Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
82ee4ec
feat: smart package manager selection (#1190)
sacrosanctic Jul 23, 2026
580c2f7
fix: recognize the nub package manager (#1187)
colinhacks Jul 23, 2026
ad6d098
fix: format all created project files so fresh projects pass lint (#1…
mvanhorn Jul 25, 2026
15e23c8
feat: `addOption` in setup phase (#1042)
jycouet Jul 25, 2026
063258f
Version Packages (#1191)
github-actions[bot] Jul 25, 2026
129cc63
feat: welcome `ai-tools` (#1050)
jycouet Jul 30, 2026
9b3fa17
fix: drop obsolete pnpm allowBuilds entries and surface real format e…
jycouet Jul 30, 2026
86a4cce
fix(experimental): create manages `#lib` and the rest of the SvelteKi…
jycouet Jul 30, 2026
a1aba83
fix(drizzle): `remove better-sqlite3` from `allowBuilds` (#1205)
sacrosanctic Jul 31, 2026
1a67d26
fix(better-auth): use the `auth` CLI binary in the auth:schema script…
jycouet Jul 31, 2026
78f6b7a
Version Packages (#1200)
github-actions[bot] Jul 31, 2026
fdcf48f
drop in replacement
sacrosanctic Aug 1, 2026
c791d83
add run helper that defaults cwd to testOutputPath
sacrosanctic Aug 1, 2026
2115be4
refactor out `constructCommand`
sacrosanctic Aug 1, 2026
1fc25b7
refactor to no throw
sacrosanctic Aug 1, 2026
21bef99
`tinyexec` doesn't throw by default
sacrosanctic Aug 1, 2026
d7d20f9
clean up
sacrosanctic Aug 1, 2026
696efaa
every `exec` on this page should `throw`?
sacrosanctic Aug 1, 2026
f44f36e
not sure if this is a one to one refactor
sacrosanctic Aug 1, 2026
390a6ea
lint
sacrosanctic Aug 1, 2026
78030c6
fix
sacrosanctic Aug 1, 2026
e48f361
fix
sacrosanctic Aug 1, 2026
20674ce
nit
sacrosanctic Aug 1, 2026
764cf6a
rerun test
sacrosanctic Aug 1, 2026
ea6eb58
Update packages/sv/src/core/verifiers.ts
sacrosanctic Aug 2, 2026
6901b16
adjust throws
sacrosanctic Aug 3, 2026
584df66
lint
sacrosanctic Aug 3, 2026
4b0773d
Clarify where error properties come from
sacrosanctic Aug 3, 2026
9b31da4
throw
sacrosanctic Aug 3, 2026
1ab1830
more throws
sacrosanctic Aug 3, 2026
4b83db5
no type casting
sacrosanctic Aug 5, 2026
a0c7755
add `isNodeError`
sacrosanctic Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
packages/sv/src/cli/tests/snapshots/*
packages/sv-utils/src/tests/**/output.ts
packages/sv-utils/src/tests/**/output.ts
packages/sv/src/create/shared/+skills/*
2 changes: 1 addition & 1 deletion documentation/docs/20-commands/20-sv-add.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ Do not prompt to install dependencies.

## Official add-ons

- [`ai-tools`](ai-tools)
- [`better-auth`](better-auth)
- [`drizzle`](drizzle)
- [`eslint`](eslint)
- [`mcp`](mcp)
- [`mdsvex`](mdsvex)
- [`paraglide`](paraglide)
- [`playwright`](playwright)
Expand Down
56 changes: 56 additions & 0 deletions documentation/docs/30-add-ons/01-ai-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
title: ai-tools
---

The [Svelte AI tools](/docs/ai/overview) can help your LLM write better Svelte code.

## Usage

```sh
npx sv add ai-tools
```

## What you get

You can add the tooling either through the official Svelte plugin or as individual tools.

- The Svelte plugin bundles everything (MCP server, [skills](https://svelte.dev/docs/ai/skills) and sub-agents) and keeps itself up to date. It's available for Claude Code and OpenCode. For Claude Code it's enabled through a committed `.claude/settings.json` - the first time you open the project you'll be asked to trust the workspace, then it installs automatically (no `/plugin install` needed).
- Individual tools, for clients without a plugin (or when you want to pick exactly what to add):
- An MCP configuration for [local](https://svelte.dev/docs/ai/local-setup) or [remote](https://svelte.dev/docs/ai/remote-setup) setup
- A [README for agents](https://agents.md/) to help you use the MCP server effectively
- [Skills](https://svelte.dev/docs/ai/skills) for clients that support them
- Sub-agents for clients that support them

## Options

### ide

The client(s) you want to use like `'claude-code'`, `'cursor'`, `'gemini'`, `'opencode'`, `'vscode'`, `'other'`.

```sh
npx sv add ai-tools="ide:cursor,vscode"
```

### delivery

How to add the tooling: `'plugin'` (the Svelte plugin, recommended) or `'tools'` (individual tools). Only asked when a selected client supports a plugin.

```sh
npx sv add ai-tools="ide:claude-code+delivery:plugin"
```

### tools

Which individual tools to add when not using the plugin, like `'mcp'`, `'svelte-code-writer'`, `'svelte-core-bestpractices'`, `'svelte-file-editor'`.

```sh
npx sv add ai-tools="ide:cursor+delivery:tools+tools:mcp,svelte-file-editor"
```

### mcpSetup

The MCP setup you want to use (`'local'` or `'remote'`). Only relevant when adding the MCP server as an individual tool.

```sh
npx sv add ai-tools="mcpSetup:local"
```
34 changes: 0 additions & 34 deletions documentation/docs/30-add-ons/17-mcp.md

This file was deleted.

5 changes: 4 additions & 1 deletion documentation/docs/30-add-ons/99-community.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ export default defineAddon({
})
.build(),

setup: ({ dependsOn, isKit, unsupported }) => {
setup: ({ dependsOn, isKit, unsupported, addOption }) => {
if (!isKit) unsupported('Requires SvelteKit');
dependsOn('vitest');

// dynamically add options (e.g. based on workspace state or fetched data)
// addOption('key', { question: '...', type: 'boolean', default: true });
},

run: ({ isKit, cancel, sv, options, file, language, directory }) => {
Expand Down
37 changes: 35 additions & 2 deletions documentation/docs/50-api/10-sv.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@ export default defineAddon({
id: 'my-addon',
options: defineAddonOptions().build(),

// called before run declare dependencies and environment requirements
setup: ({ dependsOn, unsupported, isKit }) => {
// called before run - declare dependencies, environment requirements, and dynamic options
setup: ({ dependsOn, unsupported, addOption, isKit }) => {
if (!isKit) unsupported('Requires SvelteKit');
dependsOn('eslint');

// dynamically add options based on workspace state or fetched data
addOption('theme', {
question: 'Which theme?',
type: 'select',
default: 'dark',
options: [{ value: 'dark' }, { value: 'light' }]
});
},

// the actual work — add files, edit files, declare dependencies
Expand Down Expand Up @@ -50,6 +58,31 @@ export default defineAddon({

The `sv` object in `run` provides `file`, `dependency`, `devDependency`, and `execute`. For file transforms (AST-based editing of scripts, Svelte components, CSS, JSON, etc.) and package manager helpers, see [`@sveltejs/sv-utils`](sv-utils).

### Typed dynamic options

If your add-on adds options dynamically in `setup` (e.g. from a fetch), you can pass a type parameter to `defineAddon` to get strong typing for those options:

```ts
import { defineAddon, defineAddonOptions } from 'sv';
// ---cut---
const addon = defineAddon<{ theme: string }>()({
id: 'my-addon',
options: defineAddonOptions().build(),
setup: ({ addOption }) => {
addOption('theme', {
question: 'Which theme?',
type: 'string',
default: 'dark'
});
},
run: ({ options }) => {
options.theme; // string
}
});
```

The type parameter maps value types (`boolean`, `string`, `number`) to question definitions. Without it, `defineAddon` stays strict and only allows statically defined options.

## `defineAddonOptions`

Builder for add-on options. Chained with `.add()` and finalized with `.build()`.
Expand Down
6 changes: 6 additions & 0 deletions packages/migrate/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# svelte-migrate

## 1.10.3
### Patch Changes


- fix: recognize the `nub` package manager ([#1187](https://github.com/sveltejs/cli/pull/1187))

## 1.10.2
### Patch Changes

Expand Down
4 changes: 2 additions & 2 deletions packages/migrate/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "svelte-migrate",
"version": "1.10.2",
"version": "1.10.3",
"type": "module",
"description": "A CLI for migrating Svelte(Kit) codebases",
"license": "MIT",
Expand Down Expand Up @@ -31,7 +31,7 @@
"@clack/prompts": "1.5.0",
"import-meta-resolve": "^4.2.0",
"magic-string": "^0.30.21",
"package-manager-detector": "^1.6.0",
"package-manager-detector": "^1.8.0",
"picocolors": "^1.1.1",
"semver": "^7.8.1",
"tiny-glob": "^0.2.9",
Expand Down
12 changes: 12 additions & 0 deletions packages/sv-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# @sveltejs/sv-utils

## 0.3.3
### Patch Changes


- feat: add SvelteKit 3 helpers - `isKit3`, `resolveLibPrefix`, `libSubpathImports` ([#1199](https://github.com/sveltejs/cli/pull/1199))

## 0.3.2
### Patch Changes


- fix: recognize the `nub` package manager ([#1187](https://github.com/sveltejs/cli/pull/1187))

## 0.3.1
### Patch Changes

Expand Down
15 changes: 15 additions & 0 deletions packages/sv-utils/api-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,16 @@ type DefineEnv = {
};

declare function defineEnv({ sv, cwd, dependencyVersion }: DefineEnvContext): DefineEnv;

declare function isKit3(kitRange: string | undefined): boolean;

declare function resolveLibPrefix(kitRange: string | undefined): '#lib' | '$lib';

declare function libSubpathImports(libDir: string): Record<string, string>;

declare const KIT3_TSCONFIG = '$app/tsconfig';

declare const KIT3_TSCONFIG_DEFAULT: Record<string, unknown>;
type ColorInput = string | string[];
declare const color: {
addon: (str: ColorInput) => string;
Expand Down Expand Up @@ -886,6 +896,8 @@ export {
COMMANDS,
type Comments,
type ConfigFileReader,
KIT3_TSCONFIG,
KIT3_TSCONFIG_DEFAULT,
type Package,
type SvelteAst,
type SvelteConfigKind,
Expand All @@ -905,16 +917,19 @@ export {
downloadJson,
fileExists,
index_d_exports$2 as html,
isKit3,
isVersionUnsupportedBelow,
index_d_exports$3 as js,
json_d_exports as json,
libSubpathImports,
loadFile,
loadPackageJson,
minVersion,
parse,
pnpm_d_exports as pnpm,
resolveCommand,
resolveCommandArray,
resolveLibPrefix,
sanitizeName,
saveFile,
splitVersion,
Expand Down
4 changes: 2 additions & 2 deletions packages/sv-utils/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sveltejs/sv-utils",
"version": "0.3.1",
"version": "0.3.3",
"type": "module",
"description": "Utility functions for sv",
"license": "MIT",
Expand Down Expand Up @@ -30,7 +30,7 @@
"decircular": "^1.0.0",
"dedent": "^1.7.2",
"esrap": "^2.2.11",
"package-manager-detector": "^1.6.0",
"package-manager-detector": "^1.8.0",
"semver": "^7.8.1",
"silver-fleece": "^1.2.1",
"smol-toml": "^1.6.1",
Expand Down
24 changes: 13 additions & 11 deletions packages/sv-utils/src/env.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fileExists } from './files.ts';
import { isKit3 } from './kit3.ts';
import { coerceVersion } from './semver.ts';
import { svelteConfig, type ConfigFileReader, type SvFileApi } from './svelte-config.ts';
import type { AstTypes } from './tooling/index.ts';
Expand All @@ -15,10 +16,8 @@ export function resolveEnvMode({
explicitEnvFlag: boolean;
}): EnvMode {
if (!kitRange) return 'legacy';
if (kitRange === 'next') return 'declared';
const { major } = coerceVersion(kitRange);
if (major !== undefined && major >= 3) return 'declared';
if (major === 2 && explicitEnvFlag) return 'declared';
if (isKit3(kitRange)) return 'declared';
if (coerceVersion(kitRange).major === 2 && explicitEnvFlag) return 'declared';
return 'legacy';
}

Expand Down Expand Up @@ -110,23 +109,23 @@ function getOrCreateVariablesObject(
* just call `define`/`reference` and never deal with the legacy-vs-declared distinction themselves.
*/
export function defineEnv({ sv, cwd, dependencyVersion }: DefineEnvContext): DefineEnv {
const mode = resolveEnvMode({
kitRange: dependencyVersion('@sveltejs/kit'),
explicitEnvFlag: readExplicitEnvFlag(cwd)
});
const kitRange = dependencyVersion('@sveltejs/kit');
const mode = resolveEnvMode({ kitRange, explicitEnvFlag: readExplicitEnvFlag(cwd) });
const language = fileExists(cwd, 'tsconfig.json') ? 'ts' : 'js';
return _bindEnv({ sv, mode, language });
return _bindEnv({ sv, mode, language, kit3: isKit3(kitRange) });
}

/** @internal The mode-resolved core, exported for filesystem-free tests. */
export function _bindEnv({
sv,
mode,
language
language,
kit3 = false
}: {
sv: SvFileApi;
mode: EnvMode;
language: 'ts' | 'js';
kit3?: boolean;
}): DefineEnv {
const declared = new Map<string, EnvVarSpec>();

Expand All @@ -138,7 +137,10 @@ export function _bindEnv({
const envPath = `src/env.${language}`;
sv.file(envPath, (content) =>
transforms.script(({ ast, js }) => {
js.imports.addNamed(ast, { from: '@sveltejs/kit/hooks', imports: ['defineEnvVars'] });
js.imports.addNamed(ast, {
from: kit3 ? '@sveltejs/kit/env' : '@sveltejs/kit/hooks',
imports: ['defineEnvVars']
});
const variables = getOrCreateVariablesObject(ast, js);
const entry = js.object.property(variables, {
name: spec.name,
Expand Down
9 changes: 9 additions & 0 deletions packages/sv-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ export {
// Env access (abstracts over legacy `$env/dynamic/*` vs declared `$app/env/*` + `src/env.ts`)
export { defineEnv } from './env.ts';

// Kit 3 specifics (version detection, `$lib` -> `#lib`, the generated tsconfig)
export {
KIT3_TSCONFIG,
KIT3_TSCONFIG_DEFAULT,
isKit3,
libSubpathImports,
resolveLibPrefix
} from './kit3.ts';

// Terminal styling
export { color } from './color.ts';

Expand Down
Loading