feat: rename dsh to dsh-sdk
This commit is contained in:
@@ -7,9 +7,9 @@ The [feature RFC](../../docs/rfc/proposed/feature/2026-07-14-sdk-developer-proje
|
||||
| Package | Role |
|
||||
|---|---|
|
||||
| [`helper`](helper/README.md) | Project aggregate, edit session, builtin features, project documents, templates, package managers, and prompt abstraction |
|
||||
| [`scripts`](scripts/README.md) | The `dsh` launcher: `start`, `dev`, `build`, and interactive `config` |
|
||||
| [`scripts`](scripts/README.md) | The `dsh-sdk` launcher: `start`, `dev`, `build`, and interactive `config` |
|
||||
| [`create-sdk`](create-sdk/README.md) | The `npm create @deepseek-ai/sdk` initializer |
|
||||
|
||||
`@deepseek-ai/create-sdk` is the one package-name exception to the repository's `@deepseek-ai/dsh-*` rule: npm's scoped initializer convention requires that name for `npm create @deepseek-ai/sdk`.
|
||||
|
||||
Generated projects keep `cordis.yml` as the only runtime plugin tree. `dsh dev` adds TypeScript and local-workspace resolution around that same file; it does not create a development-only config.
|
||||
Generated projects keep `cordis.yml` as the only runtime plugin tree. `dsh-sdk dev` adds TypeScript and local-workspace resolution around that same file; it does not create a development-only config.
|
||||
|
||||
@@ -13,9 +13,9 @@ const scriptsBin = join(repoRoot, 'packages/sdk/scripts/lib/bin.js')
|
||||
describe.skipIf(!existsSync(createBin) || !existsSync(scriptsBin))(
|
||||
'SDK built artifacts',
|
||||
() => {
|
||||
it('runs the published dsh bin help path under plain Node', async () => {
|
||||
it('runs the published dsh-sdk bin help path under plain Node', async () => {
|
||||
const result = await execFileAsync(process.execPath, [scriptsBin, '--help'], { encoding: 'utf8' })
|
||||
expect(result.stdout).toContain('Usage: dsh <command>')
|
||||
expect(result.stdout).toContain('Usage: dsh-sdk <command>')
|
||||
expect(result.stderr).toBe('')
|
||||
})
|
||||
|
||||
|
||||
@@ -261,11 +261,11 @@ describe('CreateWizard and scaffolder', () => {
|
||||
const manifest = parseGeneratedPackageManifest(await readFile(join(target, 'package.json'), 'utf8'))
|
||||
expect(tsconfig.compilerOptions.types).toEqual(['node'])
|
||||
expect(manifest.scripts).toEqual({
|
||||
dev: 'dsh dev index.ts',
|
||||
build: 'dsh build',
|
||||
dev: 'dsh-sdk dev index.ts',
|
||||
build: 'dsh-sdk build',
|
||||
typecheck: 'tsc -b',
|
||||
start: 'dsh start index.js',
|
||||
config: 'dsh config',
|
||||
start: 'dsh-sdk start index.js',
|
||||
config: 'dsh-sdk config',
|
||||
})
|
||||
expect(manifest.dependencies).not.toHaveProperty('node-addon-require-builtin')
|
||||
expect(manifest.devDependencies?.['@types/node']).toBe('^22.20.0')
|
||||
|
||||
@@ -93,8 +93,8 @@ describe.skipIf(!existsSync(builtScripts))('live-linked generated projects', ()
|
||||
})
|
||||
expect(existsSync(join(root, 'index.js'))).toBe(true)
|
||||
expect(existsSync(join(root, 'plugins/probe/lib/index.js'))).toBe(true)
|
||||
const dsh = join(root, 'node_modules/@deepseek-ai/dsh-scripts/lib/bin.js')
|
||||
const run = await execFileAsync(process.execPath, [dsh, 'dev', 'index.ts'], {
|
||||
const dshSdk = join(root, 'node_modules/@deepseek-ai/dsh-scripts/lib/bin.js')
|
||||
const run = await execFileAsync(process.execPath, [dshSdk, 'dev', 'index.ts'], {
|
||||
cwd: root,
|
||||
env: { ...commandEnvironment, DEEPSEEK_API_KEY: 'test-key' },
|
||||
encoding: 'utf8',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# `@deepseek-ai/dsh-helper`
|
||||
|
||||
Shared project domain and infrastructure for `create-sdk` and `dsh config`. `SdkProject` is a read-only snapshot; `ProjectEditSession` is the only mutation and commit boundary. The [SDK architecture RFC](../../../docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.md) owns the rationale.
|
||||
Shared project domain and infrastructure for `create-sdk` and `dsh-sdk config`. `SdkProject` is a read-only snapshot; `ProjectEditSession` is the only mutation and commit boundary. The [SDK architecture RFC](../../../docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.md) owns the rationale.
|
||||
|
||||
The package owns the builtin typed-spec catalog, provider/app behavior entities, structured project file objects, helper-owned project templates, the shared typed `TextTemplate` renderer, package-manager strategies, local-plugin blueprints, typed questions, and the clack prompt adapter. It never boots a Cordis application.
|
||||
|
||||
|
||||
@@ -30,4 +30,4 @@ Install NPM dependencies with `{{packageManager}} {{installArgs}}`, then use:
|
||||
- `start`: `{{packageManager}} start`
|
||||
- `config`: `{{packageManager}} run config`
|
||||
|
||||
Edit `cordis.yml` to change the runtime plugin tree. Add or remove builtin features with `{{packageManager}} exec dsh config`.
|
||||
Edit `cordis.yml` to change the runtime plugin tree. Add or remove builtin features with `{{packageManager}} exec dsh-sdk config`.
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"description": {{description}},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "dsh build",
|
||||
"build": "dsh-sdk build",
|
||||
"typecheck": "tsc -b",
|
||||
"config": "dsh config"
|
||||
"config": "dsh-sdk config"
|
||||
},
|
||||
"dependencies": {{dependencies}},
|
||||
"devDependencies": {{devDependencies}}
|
||||
|
||||
@@ -107,7 +107,7 @@ export function createAppProjectArtifacts(
|
||||
export function createAppPackageScripts(context: ProjectTemplateContext): Readonly<Record<'dev' | 'start', string>> {
|
||||
const modelArg = context.isStdio ? ` -- --model=${JSON.stringify(context.model)}` : ''
|
||||
return {
|
||||
dev: `dsh dev index.ts${modelArg}`,
|
||||
start: `dsh start index.js${modelArg}`,
|
||||
dev: `dsh-sdk dev index.ts${modelArg}`,
|
||||
start: `dsh-sdk start index.js${modelArg}`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,11 +167,11 @@ describe('SdkProject and ProjectEditSession', () => {
|
||||
expect(index).toContain('agents.create')
|
||||
expect(index).toContain('boot.args.resume')
|
||||
expect(project.packageManifest().scripts).toEqual({
|
||||
dev: 'dsh dev index.ts -- --model="deepseek-v4-flash"',
|
||||
build: 'dsh build',
|
||||
dev: 'dsh-sdk dev index.ts -- --model="deepseek-v4-flash"',
|
||||
build: 'dsh-sdk build',
|
||||
typecheck: 'tsc -b',
|
||||
start: 'dsh start index.js -- --model="deepseek-v4-flash"',
|
||||
config: 'dsh config',
|
||||
start: 'dsh-sdk start index.js -- --model="deepseek-v4-flash"',
|
||||
config: 'dsh-sdk config',
|
||||
})
|
||||
expect(await readFile(join(project.root, '.env.example'), 'utf8')).toContain('EXA_API_KEY=')
|
||||
expect(project.cordis.entry('stdio')?.config).toMatchObject({ agent: 'main' })
|
||||
@@ -255,8 +255,8 @@ describe('SdkProject and ProjectEditSession', () => {
|
||||
const acp = (await edit.commit()).project
|
||||
expect(acp.profile.runInterface).toBe('acp')
|
||||
expect(acp.packageManifest().scripts).toMatchObject({
|
||||
dev: 'dsh dev index.ts',
|
||||
start: 'dsh start index.js',
|
||||
dev: 'dsh-sdk dev index.ts',
|
||||
start: 'dsh-sdk start index.js',
|
||||
})
|
||||
expect(await readFile(join(acp.root, 'README.md'), 'utf8')).toContain('Run as an ACP server')
|
||||
expect(await readFile(join(acp.root, 'index.ts'), 'utf8')).not.toContain('agents.create')
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# `@deepseek-ai/dsh-scripts`
|
||||
|
||||
The `dsh` launcher owns SDK project startup and configuration.
|
||||
The `dsh-sdk` launcher owns SDK project startup and configuration.
|
||||
|
||||
| Command | Behavior |
|
||||
|---|---|
|
||||
| `dsh start [target] [-- args…]` | Import a module target and invoke `main(bootContext)`, or boot `cordis.yml` when omitted; arguments after `--` are forwarded |
|
||||
| `dsh dev [target] [-- args…]` | Register TypeScript and local-workspace source resolution, then use the start path |
|
||||
| `dsh build [args…]` | Invoke the project's installed tsdown with the project arguments |
|
||||
| `dsh config` | Open one interactive edit session, review accumulated changes, commit once, and install once when NPM dependencies changed |
|
||||
| `dsh-sdk start [target] [-- args…]` | Import a module target and invoke `main(bootContext)`, or boot `cordis.yml` when omitted; arguments after `--` are forwarded |
|
||||
| `dsh-sdk dev [target] [-- args…]` | Register TypeScript and local-workspace source resolution, then use the start path |
|
||||
| `dsh-sdk build [args…]` | Invoke the project's installed tsdown with the project arguments |
|
||||
| `dsh-sdk config` | Open one interactive edit session, review accumulated changes, commit once, and install once when NPM dependencies changed |
|
||||
|
||||
`ProjectBuild(tsdownConfig)` and `PluginBuild(tsdownConfig)` are exported only from `@deepseek-ai/dsh-scripts/dev/tsdown-config`. Development and production read the same `cordis.yml`.
|
||||
|
||||
Generated project scripts invoke `dsh` for dev, build, start, and config; typecheck runs `tsc -b` directly. HMR remains an explicit `cordis.yml` feature loaded by both dev and start.
|
||||
Generated project scripts invoke `dsh-sdk` for dev, build, start, and config; typecheck runs `tsc -b` directly. HMR remains an explicit `cordis.yml` feature loaded by both dev and start.
|
||||
|
||||
The runtime library exports `startSDK(source)` to load `.env` and `cordis.yml` and return the live context, and `runSDK(target)` to import a project module and invoke its `main(bootContext)` (`runSDK()` without a target delegates to `startSDK('./cordis.yml')`). `SdkBootContext` carries the raw forwarded `argv`, generic `args`, the absolute launcher `cwd`, and the `start`/`dev` mode. The launcher declares no project options: Node `parseArgs()` runs with zero schema, so valued flags use `--key=value`, bare flags become booleans, `--no-cache` becomes `args.cache = false`, and option names retain Node's spelling (`--max-depth=3` → `args['max-depth']`).
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"bin": {
|
||||
"dsh": "lib/bin.js"
|
||||
"dsh-sdk": "lib/bin.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Commander adapter for the dsh subcommand surface.
|
||||
* Commander adapter for the dsh-sdk subcommand surface.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-scripts/args
|
||||
*/
|
||||
@@ -7,12 +7,12 @@
|
||||
import { parseArgs as parseNodeArgs } from 'node:util'
|
||||
import { Command } from 'commander'
|
||||
|
||||
/** Commands implemented by the dsh launcher. */
|
||||
type DshCommand = 'start' | 'dev' | 'build' | 'config'
|
||||
/** Commands implemented by the dsh-sdk launcher. */
|
||||
type DshSdkCommand = 'start' | 'dev' | 'build' | 'config'
|
||||
|
||||
/** Parsed dsh invocation. */
|
||||
export interface DshArgs {
|
||||
command?: DshCommand
|
||||
/** Parsed dsh-sdk invocation. */
|
||||
export interface DshSdkArgs {
|
||||
command?: DshSdkCommand
|
||||
target?: string
|
||||
forwarded: readonly string[]
|
||||
help: boolean
|
||||
@@ -29,16 +29,16 @@ export function parseSdkBootArgs(argv: readonly string[]): Record<string, string
|
||||
}
|
||||
|
||||
/** Parse one launcher invocation through real Commander subcommands. */
|
||||
export function parseDshArgs(argv: readonly string[]): DshArgs {
|
||||
export function parseDshSdkArgs(argv: readonly string[]): DshSdkArgs {
|
||||
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
||||
return { forwarded: [], help: true }
|
||||
}
|
||||
const separator = argv.indexOf('--')
|
||||
const launcherArgv = separator === -1 ? argv : argv.slice(0, separator)
|
||||
const passthrough = separator === -1 ? [] : argv.slice(separator + 1)
|
||||
let parsed: DshArgs | undefined
|
||||
let parsed: DshSdkArgs | undefined
|
||||
const program = new Command()
|
||||
.name('dsh')
|
||||
.name('dsh-sdk')
|
||||
.helpOption(false)
|
||||
.showHelpAfterError(false)
|
||||
.exitOverride()
|
||||
@@ -62,9 +62,9 @@ export function parseDshArgs(argv: readonly string[]): DshArgs {
|
||||
})
|
||||
program.parse([...launcherArgv], { from: 'user' })
|
||||
/* v8 ignore next -- every registered Commander action above assigns parsed or Commander throws */
|
||||
if (!parsed) throw new Error('dsh command did not resolve')
|
||||
if (!parsed) throw new Error('dsh-sdk command did not resolve')
|
||||
if (parsed.command === 'config' && passthrough.length > 0) {
|
||||
throw new Error('dsh config does not accept forwarded arguments')
|
||||
throw new Error('dsh-sdk config does not accept forwarded arguments')
|
||||
}
|
||||
return { ...parsed, forwarded: [...parsed.forwarded, ...passthrough] }
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Self-executing dsh launcher.
|
||||
* Self-executing dsh-sdk launcher.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-scripts/bin
|
||||
*/
|
||||
|
||||
import { runDshCommand } from './command.ts'
|
||||
import { runDshSdkCommand } from './command.ts'
|
||||
|
||||
process.exitCode = await runDshCommand()
|
||||
process.exitCode = await runDshSdkCommand()
|
||||
|
||||
@@ -54,7 +54,7 @@ function resolveTsdownBin(cwd: string): string {
|
||||
try {
|
||||
manifestPath = require.resolve('tsdown/package.json')
|
||||
} catch (error) {
|
||||
throw new Error(`dsh build requires tsdown in this project: ${String(error)}`)
|
||||
throw new Error(`dsh-sdk build requires tsdown in this project: ${String(error)}`)
|
||||
}
|
||||
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as { bin?: unknown }
|
||||
const bin = typeof manifest.bin === 'string'
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* Internal dsh command composition used by the package bin.
|
||||
* Internal dsh-sdk command composition used by the package bin.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-scripts/command
|
||||
*/
|
||||
|
||||
import { parseDshArgs } from './args.ts'
|
||||
import { parseDshSdkArgs } from './args.ts'
|
||||
import { runProjectBuild } from './build.ts'
|
||||
import { runConfigCommand, type ConfigCommandContext } from './config.ts'
|
||||
import { runSDK } from './runtime.ts'
|
||||
import { DSH_TEMPLATES } from './templates/dsh-templates.ts'
|
||||
import { DSH_SDK_TEMPLATES } from './templates/dsh-sdk-templates.ts'
|
||||
|
||||
/** Injectable process and command boundaries used by the dsh bin. */
|
||||
export interface DshCommandContext extends ConfigCommandContext {
|
||||
/** Injectable process and command boundaries used by the dsh-sdk bin. */
|
||||
export interface DshSdkCommandContext extends ConfigCommandContext {
|
||||
cwd: string
|
||||
stdin: NodeJS.ReadStream
|
||||
stdout: NodeJS.WriteStream
|
||||
@@ -21,10 +21,10 @@ export interface DshCommandContext extends ConfigCommandContext {
|
||||
config?: typeof runConfigCommand
|
||||
}
|
||||
|
||||
/** Run one parsed dsh command and return its process exit code. */
|
||||
export async function runDshCommand(
|
||||
/** Run one parsed dsh-sdk command and return its process exit code. */
|
||||
export async function runDshSdkCommand(
|
||||
argv: readonly string[] = process.argv.slice(2),
|
||||
context: DshCommandContext = {
|
||||
context: DshSdkCommandContext = {
|
||||
cwd: process.cwd(),
|
||||
stdin: process.stdin,
|
||||
stdout: process.stdout,
|
||||
@@ -32,9 +32,9 @@ export async function runDshCommand(
|
||||
},
|
||||
): Promise<number> {
|
||||
try {
|
||||
const args = parseDshArgs(argv)
|
||||
const args = parseDshSdkArgs(argv)
|
||||
if (args.help || !args.command) {
|
||||
context.stdout.write(DSH_TEMPLATES.usage.render({}))
|
||||
context.stdout.write(DSH_SDK_TEMPLATES.usage.render({}))
|
||||
return 0
|
||||
}
|
||||
const run = context.run ?? runSDK
|
||||
@@ -52,7 +52,7 @@ export async function runDshCommand(
|
||||
}
|
||||
return 0
|
||||
} catch (error) {
|
||||
context.stderr.write(`dsh: ${error instanceof Error ? error.message : String(error)}\n`)
|
||||
context.stderr.write(`dsh-sdk: ${error instanceof Error ? error.message : String(error)}\n`)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* dsh config command composition.
|
||||
* dsh-sdk config command composition.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-scripts/config
|
||||
*/
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from '@deepseek-ai/dsh-helper'
|
||||
import { ConfigWorkflow, type ConfigWorkflowResult } from './config/config-workflow.ts'
|
||||
|
||||
/** Process stream slice required by dsh config. */
|
||||
/** Process stream slice required by dsh-sdk config. */
|
||||
export interface ConfigCommandContext {
|
||||
cwd: string
|
||||
stdin: NodeJS.ReadStream
|
||||
@@ -24,7 +24,7 @@ export interface ConfigCommandContext {
|
||||
/** Open and interactively edit one existing SDK project. */
|
||||
export async function runConfigCommand(context: ConfigCommandContext): Promise<ConfigWorkflowResult> {
|
||||
if (!context.port && (!context.stdin.isTTY || !context.stdout.isTTY)) {
|
||||
throw new Error('dsh config requires an interactive TTY')
|
||||
throw new Error('dsh-sdk config requires an interactive TTY')
|
||||
}
|
||||
const project = await SdkProject.open(context.cwd)
|
||||
const registry = createBuiltinRegistry(project.profile)
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
type PromptPort,
|
||||
type SdkProject,
|
||||
} from '@deepseek-ai/dsh-helper'
|
||||
import { DSH_TEMPLATES } from '../templates/dsh-templates.ts'
|
||||
import { DSH_SDK_TEMPLATES } from '../templates/dsh-sdk-templates.ts'
|
||||
|
||||
/** Config result, including an install failure that happened after commit. */
|
||||
export interface ConfigWorkflowResult {
|
||||
@@ -144,7 +144,7 @@ export class ConfigWorkflow {
|
||||
} catch (error) {
|
||||
const installError = error instanceof Error ? error : new Error(String(error))
|
||||
const manager = project.profile.packageManager
|
||||
this.output.write(DSH_TEMPLATES.configInstallFailure.render({
|
||||
this.output.write(DSH_SDK_TEMPLATES.configInstallFailure.render({
|
||||
error: installError.message,
|
||||
packageManager: manager.name,
|
||||
installArgs: manager.installCommand().join(' '),
|
||||
|
||||
@@ -68,7 +68,7 @@ async function registerDevRuntime(cwd: string = process.cwd()): Promise<void> {
|
||||
({ register: registerTsx } = await import('tsx/esm/api'))
|
||||
} catch (error) {
|
||||
/* v8 ignore next -- tsx is a declared project NPM dependency; missing-package behavior is defensive */
|
||||
throw new Error(`dsh dev requires the project's tsx NPM dependency: ${String(error)}`)
|
||||
throw new Error(`dsh-sdk dev requires the project's tsx NPM dependency: ${String(error)}`)
|
||||
}
|
||||
registerTsx()
|
||||
const mappings = await localPluginMappings(resolve(cwd))
|
||||
@@ -97,9 +97,9 @@ export async function startSDK(
|
||||
}
|
||||
const requested = source instanceof URL ? fileURLToPath(source) : source
|
||||
const absolute = resolveConfigPath(requested, undefined, cwd)
|
||||
loadEnv('dsh', dirname(absolute))
|
||||
installFailLoud('dsh')
|
||||
return boot('dsh', absolute)
|
||||
loadEnv('dsh-sdk', dirname(absolute))
|
||||
installFailLoud('dsh-sdk')
|
||||
return boot('dsh-sdk', absolute)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,12 +120,12 @@ export async function runSDK(
|
||||
try {
|
||||
await access(absolute)
|
||||
} catch (error) {
|
||||
const hint = options.dev ? '' : ' Run dsh build first if this is a TypeScript project.'
|
||||
const hint = options.dev ? '' : ' Run dsh-sdk build first if this is a TypeScript project.'
|
||||
throw new Error(`cannot start missing target ${target}.${hint} ${String(error)}`)
|
||||
}
|
||||
const module = await import(pathToFileURL(absolute).href) as { main?: (context: SdkBootContext) => unknown }
|
||||
if (typeof module.main !== 'function') {
|
||||
throw new Error(`dsh target ${target} must export function main()`)
|
||||
throw new Error(`dsh-sdk target ${target} must export function main()`)
|
||||
}
|
||||
const argv = [...options.argv ?? []]
|
||||
return module.main({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Usage: dsh <command> [options]
|
||||
Usage: dsh-sdk <command> [options]
|
||||
|
||||
Commands:
|
||||
start [target] [-- args...] Import a built module, or boot cordis.yml
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Package-owned terminal templates for the dsh launcher.
|
||||
* Package-owned terminal templates for the dsh-sdk launcher.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-scripts/templates/dsh-templates
|
||||
* @module @deepseek-ai/dsh-scripts/templates/dsh-sdk-templates
|
||||
*/
|
||||
|
||||
import { TextTemplate, type PackageManagerName } from '@deepseek-ai/dsh-helper'
|
||||
@@ -12,8 +12,8 @@ interface ConfigInstallFailureTemplateModel {
|
||||
installArgs: string
|
||||
}
|
||||
|
||||
/** Compiled dsh terminal templates. */
|
||||
export const DSH_TEMPLATES = {
|
||||
/** Compiled dsh-sdk terminal templates. */
|
||||
export const DSH_SDK_TEMPLATES = {
|
||||
usage: TextTemplate.fromFile<Record<string, never>>(new URL('./assets/usage.txt.tpl', import.meta.url)),
|
||||
configInstallFailure: TextTemplate.fromFile<ConfigInstallFailureTemplateModel>(
|
||||
new URL('./assets/config-install-failure.txt.tpl', import.meta.url),
|
||||
@@ -1,6 +1,6 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`dsh config terminal contract > pins the feature tree and Review & Apply output 1`] = `
|
||||
exports[`dsh-sdk config terminal contract > pins the feature tree and Review & Apply output 1`] = `
|
||||
{
|
||||
"committed": {
|
||||
"addedFeatures": [
|
||||
|
||||
@@ -106,7 +106,7 @@ async function baseProject(): Promise<SdkProject> {
|
||||
return (await edit.commit()).project
|
||||
}
|
||||
|
||||
describe('dsh config terminal contract', () => {
|
||||
describe('dsh-sdk config terminal contract', () => {
|
||||
it('pins the feature tree and Review & Apply output', async () => {
|
||||
const project = await baseProject()
|
||||
const registry = createBuiltinRegistry(project.profile)
|
||||
|
||||
@@ -25,9 +25,9 @@ import type {
|
||||
TextPromptRequest,
|
||||
} from '../../helper/src/questions/prompt-port.ts'
|
||||
import { runSDK, startSDK } from '@deepseek-ai/dsh-scripts'
|
||||
import { parseDshArgs, parseSdkBootArgs } from '../src/args.ts'
|
||||
import { parseDshSdkArgs, parseSdkBootArgs } from '../src/args.ts'
|
||||
import { PluginBuild, ProjectBuild, runProjectBuild } from '../src/build.ts'
|
||||
import { runDshCommand, type DshCommandContext } from '../src/command.ts'
|
||||
import { runDshSdkCommand, type DshSdkCommandContext } from '../src/command.ts'
|
||||
import { runConfigCommand } from '../src/config.ts'
|
||||
import { ConfigWorkflow } from '../src/config/config-workflow.ts'
|
||||
import { initialize, resolve as resolveLocalPlugin } from '../src/local-plugin-loader-hooks.ts'
|
||||
@@ -62,7 +62,7 @@ function outputBuffer(): { stream: Writable; read: () => string } {
|
||||
}
|
||||
}
|
||||
|
||||
function commandContext(cwd: string): DshCommandContext & { readStdout: () => string; readStderr: () => string } {
|
||||
function commandContext(cwd: string): DshSdkCommandContext & { readStdout: () => string; readStderr: () => string } {
|
||||
let stdout = ''
|
||||
let stderr = ''
|
||||
const stdin = Object.assign(new PassThrough(), { isTTY: true }) as unknown as NodeJS.ReadStream
|
||||
@@ -117,22 +117,22 @@ async function committedProject(
|
||||
|
||||
describe('Commander launcher arguments', () => {
|
||||
it('parses real subcommands and forwards arbitrary build options', () => {
|
||||
expect(parseDshArgs([])).toMatchObject({ help: true })
|
||||
expect(parseDshArgs(['start', 'index.js'])).toMatchObject({ command: 'start', target: 'index.js' })
|
||||
expect(parseDshArgs(['dev'])).toEqual({ command: 'dev', forwarded: [], help: false })
|
||||
expect(parseDshArgs(['build', '--watch', '--minify'])).toMatchObject({
|
||||
expect(parseDshSdkArgs([])).toMatchObject({ help: true })
|
||||
expect(parseDshSdkArgs(['start', 'index.js'])).toMatchObject({ command: 'start', target: 'index.js' })
|
||||
expect(parseDshSdkArgs(['dev'])).toEqual({ command: 'dev', forwarded: [], help: false })
|
||||
expect(parseDshSdkArgs(['build', '--watch', '--minify'])).toMatchObject({
|
||||
command: 'build', forwarded: ['--watch', '--minify'],
|
||||
})
|
||||
expect(parseDshArgs(['start', 'index.js', '--', '--resume', 'session-1'])).toMatchObject({
|
||||
expect(parseDshSdkArgs(['start', 'index.js', '--', '--resume', 'session-1'])).toMatchObject({
|
||||
command: 'start', target: 'index.js', forwarded: ['--resume', 'session-1'],
|
||||
})
|
||||
expect(parseDshArgs(['config'])).toMatchObject({ command: 'config' })
|
||||
expect(parseDshArgs(['start'])).toEqual({ command: 'start', forwarded: [], help: false })
|
||||
expect(parseDshArgs(['dev', 'index.ts'])).toMatchObject({ command: 'dev', target: 'index.ts' })
|
||||
expect(parseDshArgs(['-h'])).toMatchObject({ help: true })
|
||||
expect(() => parseDshArgs(['unknown'])).toThrow()
|
||||
expect(() => parseDshArgs(['config', 'extra'])).toThrow()
|
||||
expect(() => parseDshArgs(['config', '--', 'extra'])).toThrow('does not accept forwarded')
|
||||
expect(parseDshSdkArgs(['config'])).toMatchObject({ command: 'config' })
|
||||
expect(parseDshSdkArgs(['start'])).toEqual({ command: 'start', forwarded: [], help: false })
|
||||
expect(parseDshSdkArgs(['dev', 'index.ts'])).toMatchObject({ command: 'dev', target: 'index.ts' })
|
||||
expect(parseDshSdkArgs(['-h'])).toMatchObject({ help: true })
|
||||
expect(() => parseDshSdkArgs(['unknown'])).toThrow()
|
||||
expect(() => parseDshSdkArgs(['config', 'extra'])).toThrow()
|
||||
expect(() => parseDshSdkArgs(['config', '--', 'extra'])).toThrow('does not accept forwarded')
|
||||
expect(parseSdkBootArgs([
|
||||
'--model=mock', '--resume=session-1', '--custom=value', '--verbose', '--no-cache', '--max-depth=-1',
|
||||
])).toEqual({
|
||||
@@ -148,28 +148,28 @@ describe('Commander launcher arguments', () => {
|
||||
context.run = async (target, options) => { calls.push(['run', target, options]); return undefined }
|
||||
context.build = async (args, cwd) => { calls.push(['build', args, cwd]) }
|
||||
context.config = async () => { calls.push(['config']); return {} }
|
||||
await expect(runDshCommand(['start', 'index.js', '--', '--resume', 'session-1'], context)).resolves.toBe(0)
|
||||
await expect(runDshCommand(['dev', 'index.ts'], context)).resolves.toBe(0)
|
||||
await expect(runDshCommand(['build', '--watch'], context)).resolves.toBe(0)
|
||||
await expect(runDshCommand(['config'], context)).resolves.toBe(0)
|
||||
await expect(runDshSdkCommand(['start', 'index.js', '--', '--resume', 'session-1'], context)).resolves.toBe(0)
|
||||
await expect(runDshSdkCommand(['dev', 'index.ts'], context)).resolves.toBe(0)
|
||||
await expect(runDshSdkCommand(['build', '--watch'], context)).resolves.toBe(0)
|
||||
await expect(runDshSdkCommand(['config'], context)).resolves.toBe(0)
|
||||
expect(calls).toHaveLength(4)
|
||||
expect(calls[0]).toEqual(['run', 'index.js', { cwd: root, argv: ['--resume', 'session-1'] }])
|
||||
expect(calls[1]).toEqual(['run', 'index.ts', { cwd: root, dev: true, argv: [] }])
|
||||
context.config = async () => ({ installError: new Error('offline') })
|
||||
await expect(runDshCommand(['config'], context)).resolves.toBe(1)
|
||||
await expect(runDshSdkCommand(['config'], context)).resolves.toBe(1)
|
||||
context.config = async () => { throw 'broken' }
|
||||
await expect(runDshCommand(['config'], context)).resolves.toBe(1)
|
||||
await expect(runDshSdkCommand(['config'], context)).resolves.toBe(1)
|
||||
expect(context.readStderr()).toContain('broken')
|
||||
await expect(runDshCommand(['unknown'], context)).resolves.toBe(1)
|
||||
await expect(runDshCommand([], context)).resolves.toBe(0)
|
||||
expect(context.readStdout()).toContain('Usage: dsh')
|
||||
await expect(runDshSdkCommand(['unknown'], context)).resolves.toBe(1)
|
||||
await expect(runDshSdkCommand([], context)).resolves.toBe(0)
|
||||
expect(context.readStdout()).toContain('Usage: dsh-sdk')
|
||||
|
||||
const defaults = commandContext(root)
|
||||
await writeFile(join(root, 'main.mjs'), 'export function main() { return "ok" }\n')
|
||||
await expect(runDshCommand(['start', 'main.mjs'], defaults)).resolves.toBe(0)
|
||||
await expect(runDshCommand(['build'], defaults)).resolves.toBe(0)
|
||||
await expect(runDshSdkCommand(['start', 'main.mjs'], defaults)).resolves.toBe(0)
|
||||
await expect(runDshSdkCommand(['build'], defaults)).resolves.toBe(0)
|
||||
defaults.port = new QueuePort([[]])
|
||||
await expect(runDshCommand(['config'], defaults)).resolves.toBe(1)
|
||||
await expect(runDshSdkCommand(['config'], defaults)).resolves.toBe(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -260,7 +260,7 @@ describe('build profiles and invocation', () => {
|
||||
let called = false
|
||||
await runProjectBuild([], root, { run: async () => { called = true; return { exitCode: 0, signal: null } } })
|
||||
expect(called).toBe(false)
|
||||
await expect(runSDK('index.js', { cwd: root })).rejects.toThrow('Run dsh build first')
|
||||
await expect(runSDK('index.js', { cwd: root })).rejects.toThrow('Run dsh-sdk build first')
|
||||
})
|
||||
|
||||
it('invokes the target module main export and rejects passive modules', async () => {
|
||||
|
||||
Reference in New Issue
Block a user