diff --git a/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.i18n.yaml b/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.i18n.yaml index 036616cddb..6e301ee06a 100644 --- a/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.i18n.yaml +++ b/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-15-sdk-project-editing-architecture.md: 0a3751d9641e6d4c56d14b8d81ed578905c48c73 -2026-07-15-sdk-project-editing-architecture.zh.md: 6f6ec656bf0734cf81d6c69d9c0e163fb78a33b5 +2026-07-15-sdk-project-editing-architecture.md: 985cc22c159c68801b78262aa96c7422bdfa1318 +2026-07-15-sdk-project-editing-architecture.zh.md: 6a194e8e5f193e62bfc283fd93a5fde0367fe196 diff --git a/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.md b/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.md index 0a3751d964..985cc22c15 100644 --- a/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.md +++ b/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.md @@ -32,12 +32,12 @@ Structured files are modified through document objects, while one-shot text arti | Package | Responsibility | Does not own | |---|---|---| | `@deepseek-ai/dsh-helper` | Edit sessions, feature configuration, project-template rendering, package-manager adaptation, and prompt interaction adaptation | Booting Cordis applications or deciding create/config terminal workflows | -| `@deepseek-ai/dsh-scripts` | `dsh start/dev/build/config`, process lifecycle, project entry loading, the config workflow, and its terminal-copy templates | Interpreting feature definitions directly or modifying YAML/JSON ASTs | +| `@deepseek-ai/dsh-scripts` | `dsh-sdk start/dev/build/config`, process lifecycle, project entry loading, the config workflow, and its terminal-copy templates | Interpreting feature definitions directly or modifying YAML/JSON ASTs | | `@deepseek-ai/create-sdk` | Arguments, question order, initial project creation, installation finish, and terminal-copy templates for `npm create @deepseek-ai/sdk` | Becoming a generated project's runtime npm dependency or providing a library API | `@deepseek-ai/create-sdk` is the only exception to the repository's `@deepseek-ai/dsh-*` naming rule. npm's scoped-initializer convention requires that package name for `npm create @deepseek-ai/sdk`. The exception is a repository architecture fact and does not add a third developer product entrypoint. -The three packages export only the narrow entrypoints consumed by adjacent layers and provide no `src/*` deep imports. The scripts library entrypoint and build-config subpath serve generated code and project build configuration, while the developer product contract remains the `dsh` commands. +The three packages export only the narrow entrypoints consumed by adjacent layers and provide no `src/*` deep imports. The scripts library entrypoint and build-config subpath serve generated code and project build configuration, while the developer product contract remains the `dsh-sdk` commands. ## Project aggregate and edit session @@ -84,7 +84,7 @@ Templates use Handlebars strict mode and `noEscape` without custom processing. F ## Command and runtime boundary -Scripts supports `dsh start/dev/build/config`. Start dynamically loads a module target and calls its named entrypoint. Dev adds TypeScript and local-workspace source resolution before following the same path. Build invokes the project's installed tsdown. Config opens one edit session and commits after Review & Apply. Generated projects run `tsc -b` directly for typechecking. +Scripts supports `dsh-sdk start/dev/build/config`. Start dynamically loads a module target and calls its named entrypoint. Dev adds TypeScript and local-workspace source resolution before following the same path. Build invokes the project's installed tsdown. Config opens one edit session and commits after Review & Apply. Generated projects run `tsc -b` directly for typechecking. HMR is an explicit Cordis config entry loaded by dev and start. Its required `node-addon-require-builtin` package is supplied transitively by the scripts package and is absent from the generated project's `package.json`. @@ -117,7 +117,7 @@ Link mode preserves the ordinary project file shape. `@deepseek-ai/*` points int - Adding an ordinary feature, feature option, or parameter extends only its typed spec or owning behavior object, without adding a central switch to create or config workflows - Helper owns the feature model, npm dependency and other resource configuration, and inconsistent-state detection - Structured files change through `*File` document objects; one-shot files and complete product copy come from package-owned Handlebars templates, and business decisions do not enter a template DSL -- `dsh start/dev/build/config` is the runtime product surface, typecheck uses `tsc -b` directly, HMR is not injected by command mode, and only the scripts package transitively supplies `node-addon-require-builtin` +- `dsh-sdk start/dev/build/config` is the runtime product surface, typecheck uses `tsc -b` directly, HMR is not injected by command mode, and only the scripts package transitively supplies `node-addon-require-builtin` - `--link-workspace` exists only as a hidden repository-development option and preserves one module identity under npm, pnpm, and Yarn ## Risks diff --git a/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.zh.md b/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.zh.md index 6f6ec656bf..6a194e8e5f 100644 --- a/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.zh.md +++ b/docs/rfc/proposed/architecture/2026-07-15-sdk-project-editing-architecture.zh.md @@ -32,12 +32,12 @@ SDK 使用一个共享的面向对象工程模型。`SdkProject` 是只读快照 | Package | 责任 | 不负责 | |---|---|---| | `@deepseek-ai/dsh-helper` | 编辑会话、功能配置、工程模板渲染、包管理适配和 prompt 交互适配 | 启动 Cordis 应用或决定 create/config 的终端流程 | -| `@deepseek-ai/dsh-scripts` | `dsh start/dev/build/config`、进程生命周期、项目入口加载、config 流程和所属终端文案模板 | 直接解释功能定义或修改 YAML/JSON AST | +| `@deepseek-ai/dsh-scripts` | `dsh-sdk start/dev/build/config`、进程生命周期、项目入口加载、config 流程和所属终端文案模板 | 直接解释功能定义或修改 YAML/JSON AST | | `@deepseek-ai/create-sdk` | `npm create @deepseek-ai/sdk` 的参数、问题顺序、首次工程创建、安装收尾和所属终端文案模板 | 成为生成工程的运行时 NPM 依赖或提供库 API | `@deepseek-ai/create-sdk` 是仓库 `@deepseek-ai/dsh-*` 命名规则的唯一例外;npm scoped initializer 约定要求 `npm create @deepseek-ai/sdk` 对应这个 package 名。该例外是仓库架构事实,不增加第三个开发者产品入口。 -三个 package 只导出相邻层实际使用的最小入口,不提供 `src/*` 深路径。scripts 的库入口与构建配置子路径服务生成代码和项目构建配置,但开发者产品合同仍由 `dsh` 命令承担。 +三个 package 只导出相邻层实际使用的最小入口,不提供 `src/*` 深路径。scripts 的库入口与构建配置子路径服务生成代码和项目构建配置,但开发者产品合同仍由 `dsh-sdk` 命令承担。 ## 工程聚合与编辑会话 @@ -84,7 +84,7 @@ helper 提供通用的数据类型化 `TextTemplate` 模板渲染器,调用 pa ## 命令与运行边界 -scripts 支持 `dsh start/dev/build/config`。start 动态加载模块 target 并调用其命名入口;dev 在同一路径前增加 TypeScript 与本地 workspace 源码解析;build 调用工程安装的 tsdown;config 打开一个编辑会话并在 Review & Apply 后提交。typecheck 由生成工程直接执行 `tsc -b`。 +scripts 支持 `dsh-sdk start/dev/build/config`。start 动态加载模块 target 并调用其命名入口;dev 在同一路径前增加 TypeScript 与本地 workspace 源码解析;build 调用工程安装的 tsdown;config 打开一个编辑会话并在 Review & Apply 后提交。typecheck 由生成工程直接执行 `tsc -b`。 HMR 作为显式 Cordis 配置项由 dev 和 start 加载;它所需的 `node-addon-require-builtin` 由 scripts package 传递提供,不写入开发者工程的 `package.json`。 @@ -117,7 +117,7 @@ create-sdk 保留隐藏的 `--link-workspace` 选项供 Harness 仓库开发和 - 新增普通功能、功能选项或参数只扩展类型化 spec 或所属行为对象,create/config 流程不增加中央 switch - 功能模型、NPM 依赖与其他资源配置、不一致检测由 helper 统一实现 - 结构化文件通过 `*File` 文档对象修改;一次性文件和完整产品文案通过所属 package 的 Handlebars 模板生成,业务决策不进入模板 DSL -- `dsh start/dev/build/config` 是运行产品面,typecheck 直接使用 `tsc -b`,HMR 不通过命令隐式注入,`node-addon-require-builtin` 只由 scripts package 传递提供 +- `dsh-sdk start/dev/build/config` 是运行产品面,typecheck 直接使用 `tsc -b`,HMR 不通过命令隐式注入,`node-addon-require-builtin` 只由 scripts package 传递提供 - `--link-workspace` 只作为隐藏的仓库开发选项存在,并对 npm、pnpm 和 Yarn 保持单一模块身份 ## 风险 diff --git a/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.i18n.yaml b/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.i18n.yaml index 7b5a289e1e..36bb26161f 100644 --- a/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.i18n.yaml +++ b/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write -2026-07-14-sdk-developer-projects.md: 4650b5df5d1dc85035d8029754ec60b7d7008d4c -2026-07-14-sdk-developer-projects.zh.md: 613da4da930591fb13516b287f408ebc3b15b2c2 +2026-07-14-sdk-developer-projects.md: 0b5fe876f92153e1ccf5bd8fe383464f5087f4b1 +2026-07-14-sdk-developer-projects.zh.md: ec08f323acba1b9dc049182937fda34bfb50d4ee diff --git a/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.md b/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.md index 4650b5df5d..0b5fe876f9 100644 --- a/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.md +++ b/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.md @@ -16,7 +16,7 @@ Initial creation and later configuration address the same builtin feature set. W The SDK creates an ordinary, explicit TypeScript/Cordis project owned by its developer. `cordis.yml` is the only runtime plugin tree; development and production read the same file. The generated `package.json`, `cordis.yml`, TypeScript entrypoint, build configuration, and `plugins/*` remain directly editable instead of being hidden behind a preset. -The only developer product entrypoints are `npm create @deepseek-ai/sdk` and the `dsh` commands. The initializer performs initial creation, `dsh config` manages SDK-recognized builtin features afterward, and `dsh dev`, `dsh build`, and `dsh start` own development, build, and startup; this phase provides no `dsh create`. Create and config consume one manually authored feature definition, so each feature has one source for its feature options, npm dependencies, Cordis config entries, related files, and inspection rules. The [SDK project editing architecture](../architecture/2026-07-15-sdk-project-editing-architecture.md) defines terms such as feature and feature option. +The only developer product entrypoints are `npm create @deepseek-ai/sdk` and the `dsh-sdk` commands. The initializer performs initial creation, `dsh-sdk config` manages SDK-recognized builtin features afterward, and `dsh-sdk dev`, `dsh-sdk build`, and `dsh-sdk start` own development, build, and startup; this phase provides no `dsh-sdk create`. Create and config consume one manually authored feature definition, so each feature has one source for its feature options, npm dependencies, Cordis config entries, related files, and inspection rules. The [SDK project editing architecture](../architecture/2026-07-15-sdk-project-editing-architecture.md) defines terms such as feature and feature option. The SDK offers interaction for feature selection and finite feature options only; it does not turn arbitrary Cordis plugin config into a generic form. A feature collects the small number of dedicated inputs required by its feature options. All other Cordis plugin config remains in `cordis.yml`, with comments documenting common edits, for direct developer control. @@ -27,10 +27,10 @@ Initial creation collects information in an order where earlier answers determin ```sh npm create @deepseek-ai/sdk my-agent cd my-agent -npm exec dsh dev index.ts -npm exec dsh config -npm exec dsh build -npm exec dsh start index.js +npm exec dsh-sdk dev index.ts +npm exec dsh-sdk config +npm exec dsh-sdk build +npm exec dsh-sdk start index.js ``` Create rejects every target path that already exists. After committing the project files, the CLI asks whether to install npm dependencies and build. An install or build failure preserves the generated project and prints commands that can retry the failed work. @@ -94,31 +94,31 @@ my-agent/ `.env.example` always exists, and the SDK keeps its placeholders aligned with the current feature set. A gitignored `.env` is also created when a secret is captured or the developer confirms an empty credential to fill later. The SDK only appends differently named variables that are not already present in `.env` and never updates or removes existing contents. Feature-option changes may remove obsolete `.env.example` placeholders, while old credentials remain in `.env` for the developer to manage. pnpm and Yarn projects add their required workspace files, but do not fork the runtime plugin tree or TypeScript entrypoint. -Generated `package.json` provides the following scripts. `dev`, `build`, `start`, and `config` invoke `dsh`, while `typecheck` invokes TypeScript directly: +Generated `package.json` provides the following scripts. `dev`, `build`, `start`, and `config` invoke `dsh-sdk`, while `typecheck` invokes TypeScript directly: | Script | Behavior | |---|---| -| `dev` | Run `dsh dev index.ts`, registering development-time resolution for TypeScript and local workspace plugins | -| `build` | Run `dsh build`, invoking the project's installed tsdown for the root entrypoint and `plugins/*` packages | +| `dev` | Run `dsh-sdk dev index.ts`, registering development-time resolution for TypeScript and local workspace plugins | +| `build` | Run `dsh-sdk build`, invoking the project's installed tsdown for the root entrypoint and `plugins/*` packages | | `typecheck` | Run `tsc -b` directly | -| `start` | Run `dsh start index.js`, starting the built entrypoint without an implicit build | -| `config` | Run `dsh config` to edit the current project's feature tree | +| `start` | Run `dsh-sdk start index.js`, starting the built entrypoint without an implicit build | +| `config` | Run `dsh-sdk config` to edit the current project's feature tree | -`dsh start` and `dsh dev` accept a module target and forward arguments after `--` unchanged to the project entrypoint. Generic argument parsing uses Node `parseArgs()` with zero schema: valued flags use `--key=value`, bare flags become `true`, and `--no-*` becomes `false`. +`dsh-sdk start` and `dsh-sdk dev` accept a module target and forward arguments after `--` unchanged to the project entrypoint. Generic argument parsing uses Node `parseArgs()` with zero schema: valued flags use `--key=value`, bare flags become `true`, and `--no-*` becomes `false`. - Stdio projects pass the selected model through `--model=` and create or resume an agent according to optional `--resume=`; - ACP uses protocol `session/load` - Embed uses the model written into the generated code. -Each feature-owned Cordis config entry keeps its developer-editable Cordis plugin config and explanatory comments in `cordis.yml`. When `dsh config` changes other features, it preserves unknown fields, formatting on untouched nodes, and comments. HMR is an ordinary leaf config entry: when the feature is selected, dev and start load the same watcher, and the command does not change the plugin tree implicitly. +Each feature-owned Cordis config entry keeps its developer-editable Cordis plugin config and explanatory comments in `cordis.yml`. When `dsh-sdk config` changes other features, it preserves unknown fields, formatting on untouched nodes, and comments. HMR is an ordinary leaf config entry: when the feature is selected, dev and start load the same watcher, and the command does not change the plugin tree implicitly. ## Post-creation configuration -`dsh config` requires only readable root `package.json` and `cordis.yml` files in the current directory. It inspects standard features and their current feature options, expresses the final desired state through one feature tree, and shows feature changes and affected files before Review & Apply. +`dsh-sdk config` requires only readable root `package.json` and `cordis.yml` files in the current directory. It inspects standard features and their current feature options, expresses the final desired state through one feature tree, and shows feature changes and affected files before Review & Apply. -`dsh config` can install missing features, enable or disable installed features, and switch finite feature options. Required features cannot be removed. An npm dependency change runs the project package manager's install once after the file commit; installation failure does not roll back committed project files. +`dsh-sdk config` can install missing features, enable or disable installed features, and switch finite feature options. Required features cannot be removed. An npm dependency change runs the project package manager's install once after the file commit; installation failure does not roll back committed project files. -The SDK modifies only Cordis config entries, config keys, npm dependencies, `.env.example` placeholders, and owned files explicitly owned by a feature. Updating the same feature option preserves unknown config keys in its Cordis config entries. Handwritten and third-party plugins support enable and disable by stable ID only. When a known feature has been edited into an incomplete, ambiguous, or otherwise unreadable shape, `dsh config` displays diagnostics and refuses automatic changes until the developer repairs it manually. +The SDK modifies only Cordis config entries, config keys, npm dependencies, `.env.example` placeholders, and owned files explicitly owned by a feature. Updating the same feature option preserves unknown config keys in its Cordis config entries. Handwritten and third-party plugins support enable and disable by stable ID only. When a known feature has been edited into an incomplete, ambiguous, or otherwise unreadable shape, `dsh-sdk config` displays diagnostics and refuses automatic changes until the developer repairs it manually. One config session accumulates every change in an in-memory working copy. Before Apply, it validates feature relationships, resource conflicts, and document shapes, then compares each affected existing file with the text read when the session opened. Validation failure or an external edit causes zero writes. Once physical writes begin, the SDK does not provide cross-file transactional rollback. @@ -128,7 +128,7 @@ The SDK curates its builtin support set instead of exposing npm packages automat ## Future work -- `dsh add [package-spec]` unifies local-plugin creation with external Cordis plugin installation: without a package or repository source it creates a local plugin/tool, while a supplied source adds the npm dependency and `cordis.yml` config entry; the source model leaves room for GitHub repositories and other extensions +- `dsh-sdk add [package-spec]` unifies local-plugin creation with external Cordis plugin installation: without a package or repository source it creates a local plugin/tool, while a supplied source adds the npm dependency and `cordis.yml` config entry; the source model leaves room for GitHub repositories and other extensions - Non-interactive create/config: both workflows require a TTY in this phase and provide no complete input contract for automation - More feature-specific inputs: this product surface exposes only finite feature options, secrets, and a few dedicated values in this phase rather than a generic parameter interface for Cordis plugin config @@ -144,7 +144,7 @@ The SDK curates its builtin support set instead of exposing npm packages automat **A private local-plugin discovery protocol.** Ordinary package-manager workspaces, root npm dependencies, TypeScript references, and Cordis config entries already express the complete relationship. Another discovery protocol would create hidden state understood only by the SDK. -**A `dsh create` command for existing projects.** Create already provides one editable local-plugin skeleton, and later plugins can use ordinary workspace and Cordis mechanisms manually. A parallel command would add a second scaffolding product surface without adding composition functionality. +**A `dsh-sdk create` command for existing projects.** Create already provides one editable local-plugin skeleton, and later plugins can use ordinary workspace and Cordis mechanisms manually. A parallel command would add a second scaffolding product surface without adding composition functionality. **Automatically expose every new Cordis plugin as a builtin.** An npm package cannot say how several plugins compose into one product feature, nor can it derive exclusivity, feature requirements, secrets, interface applicability, or security constraints. The support set requires human curation; automation is suitable only for checking whether candidates have been classified. @@ -153,8 +153,8 @@ The SDK curates its builtin support set instead of exposing npm packages automat - `npm create @deepseek-ai/sdk` collects project identity, provider, interface, features, an optional local plugin, package manager, and installation choice in the documented order, and cancellation leaves the target path absent - A default npm project has the documented tree and `dev`, `build`, `typecheck`, `start`, and `config` scripts, with dev and start sharing one `cordis.yml` - Create offers the documented features and feature options; local and sandbox bash are exclusive with local as the default, the sandbox Cordis config entry retains the editable commented config example, and HMR is selected by default and loaded by both dev and start -- Create's `plugin` or `tool` choice creates at most one fixed-name local plugin and atomically updates its files and root-project relationships; this phase provides no `dsh create` -- `dsh config` reads the same support set from an existing project, installs, enables, disables, and switches supported feature options, preserves unknown config and comments, and refuses to modify inconsistent config +- Create's `plugin` or `tool` choice creates at most one fixed-name local plugin and atomically updates its files and root-project relationships; this phase provides no `dsh-sdk create` +- `dsh-sdk config` reads the same support set from an existing project, installs, enables, disables, and switches supported feature options, preserves unknown config and comments, and refuses to modify inconsistent config - `.env.example` reflects variables required by the current features; `.env` only appends missing differently named variables and never updates or removes existing contents - npm, pnpm, and Yarn workspaces install, build, and start; local plugins resolve from source under dev and from built output under start diff --git a/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.zh.md b/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.zh.md index 613da4da93..ec08f323ac 100644 --- a/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.zh.md +++ b/docs/rfc/proposed/feature/2026-07-14-sdk-developer-projects.zh.md @@ -16,7 +16,7 @@ DeepSeek Harness 通过 Cordis 插件对功能进行组合,但从空目录开 SDK 创建一个普通、显式且归开发者所有的 TypeScript/Cordis 工程。`cordis.yml` 是唯一的运行时插件树;开发和生产读取同一份文件。工程中的 `package.json`、`cordis.yml`、TypeScript 入口、构建配置和 `plugins/*` 均可直接编辑,SDK 不把它们封装成不可见的 preset。 -开发者产品入口只有 `npm create @deepseek-ai/sdk` 和 `dsh` 命令。前者负责首次创建,`dsh config` 在创建后管理 SDK 能识别的内置功能,`dsh dev`、`dsh build` 与 `dsh start` 负责开发、构建和启动;本期不提供 `dsh create`。create 与 config 使用同一份人工编写的功能定义,因此一项功能的功能选项、NPM 依赖、Cordis 配置项、相关文件和识别规则只有一个来源。功能、功能选项等名词由 [SDK 工程编辑架构](../architecture/2026-07-15-sdk-project-editing-architecture.md) 的术语表定义。 +开发者产品入口只有 `npm create @deepseek-ai/sdk` 和 `dsh-sdk` 命令。前者负责首次创建,`dsh-sdk config` 在创建后管理 SDK 能识别的内置功能,`dsh-sdk dev`、`dsh-sdk build` 与 `dsh-sdk start` 负责开发、构建和启动;本期不提供 `dsh-sdk create`。create 与 config 使用同一份人工编写的功能定义,因此一项功能的功能选项、NPM 依赖、Cordis 配置项、相关文件和识别规则只有一个来源。功能、功能选项等名词由 [SDK 工程编辑架构](../architecture/2026-07-15-sdk-project-editing-architecture.md) 的术语表定义。 SDK 只为功能选择和有限功能选项提供交互,不尝试把任意 Cordis 插件配置变成通用表单。功能选项所需的少量专用输入由所属功能收集;其余 Cordis 插件配置留在 `cordis.yml` 中,并通过注释指明常用改法,由开发者直接修改。 @@ -27,10 +27,10 @@ SDK 只为功能选择和有限功能选项提供交互,不尝试把任意 Cor ```sh npm create @deepseek-ai/sdk my-agent cd my-agent -npm exec dsh dev index.ts -npm exec dsh config -npm exec dsh build -npm exec dsh start index.js +npm exec dsh-sdk dev index.ts +npm exec dsh-sdk config +npm exec dsh-sdk build +npm exec dsh-sdk start index.js ``` create 拒绝任何已经存在的目标路径。工程文件提交成功后,CLI 询问是否安装 NPM 依赖并构建;安装或构建失败时保留生成结果,并打印可以重新执行的命令。 @@ -94,31 +94,31 @@ my-agent/ `.env.example` 始终存在,并由 SDK 根据当前功能维护占位。收集到 secret 或开发者确认稍后填写空凭据时,同时生成 gitignored `.env`。SDK 只向 `.env` 追加尚不存在的不同名变量,绝不覆盖或删除已有内容;切换功能选项可以清理 `.env.example` 中不再需要的占位,但旧凭据仍留在 `.env` 中供开发者自行处理。pnpm 和 Yarn 工程增加各自所需的 workspace 配置文件,但运行时插件树和 TypeScript 入口不分叉。 -生成的 `package.json` 提供以下 scripts;其中 `dev`、`build`、`start` 与 `config` 调用 `dsh`,`typecheck` 直接调用 TypeScript: +生成的 `package.json` 提供以下 scripts;其中 `dev`、`build`、`start` 与 `config` 调用 `dsh-sdk`,`typecheck` 直接调用 TypeScript: | script | 行为 | |---|---| -| `dev` | 运行 `dsh dev index.ts`,为 TypeScript 和本地 workspace 插件注册开发期解析 | -| `build` | 运行 `dsh build`,调用工程安装的 tsdown 构建根入口和 `plugins/*` package | +| `dev` | 运行 `dsh-sdk dev index.ts`,为 TypeScript 和本地 workspace 插件注册开发期解析 | +| `build` | 运行 `dsh-sdk build`,调用工程安装的 tsdown 构建根入口和 `plugins/*` package | | `typecheck` | 直接运行 `tsc -b` | -| `start` | 运行 `dsh start index.js`,启动已构建入口且不隐式构建 | -| `config` | 运行 `dsh config`,修改当前工程功能树 | +| `start` | 运行 `dsh-sdk start index.js`,启动已构建入口且不隐式构建 | +| `config` | 运行 `dsh-sdk config`,修改当前工程功能树 | -`dsh start` 与 `dsh dev` 可以接收模块 target,并把 `--` 后的参数原样转发给工程入口。通用参数解析使用 Node `parseArgs()` 的零 schema 模式:带值 flag 采用 `--key=value`,bare flag 转换为 `true`,`--no-*` 转换为 `false`。 +`dsh-sdk start` 与 `dsh-sdk dev` 可以接收模块 target,并把 `--` 后的参数原样转发给工程入口。通用参数解析使用 Node `parseArgs()` 的零 schema 模式:带值 flag 采用 `--key=value`,bare flag 转换为 `true`,`--no-*` 转换为 `false`。 - stdio 工程通过 `--model=` 传入所选 model,并根据可选的 `--resume=` 创建或恢复 agent; - acp 使用协议 `session/load` - embed 使用生成代码中的 model。 -每个功能拥有的 Cordis 配置项在 `cordis.yml` 中保留自己的可编辑 Cordis 插件配置和说明注释;`dsh config` 修改其他功能时必须保留未知字段、未修改节点的格式和注释。HMR(热模块替换)是普通叶子配置项:选择该功能后,dev 和 start 加载同一个 watcher,命令不隐式改变插件树。 +每个功能拥有的 Cordis 配置项在 `cordis.yml` 中保留自己的可编辑 Cordis 插件配置和说明注释;`dsh-sdk config` 修改其他功能时必须保留未知字段、未修改节点的格式和注释。HMR(热模块替换)是普通叶子配置项:选择该功能后,dev 和 start 加载同一个 watcher,命令不隐式改变插件树。 ## 创建后的配置 -`dsh config` 只要求当前目录具有可读的根 `package.json` 与 `cordis.yml`。它检查标准功能及其当前功能选项,以一棵功能树表达最终目标状态,并在 Review & Apply 前展示功能变化和受影响文件。 +`dsh-sdk config` 只要求当前目录具有可读的根 `package.json` 与 `cordis.yml`。它检查标准功能及其当前功能选项,以一棵功能树表达最终目标状态,并在 Review & Apply 前展示功能变化和受影响文件。 -`dsh config` 可以安装缺失功能、启停已安装功能和切换有限功能选项。required 功能不能取消。改变 NPM 依赖后只运行一次项目包管理器安装;安装失败不回滚已经提交的工程文件。 +`dsh-sdk config` 可以安装缺失功能、启停已安装功能和切换有限功能选项。required 功能不能取消。改变 NPM 依赖后只运行一次项目包管理器安装;安装失败不回滚已经提交的工程文件。 -SDK 只修改功能明确拥有的 Cordis 配置项、配置键、NPM 依赖、`.env.example` 占位和独占文件。同一功能选项的更新保留 Cordis 配置项中的未知配置键;手写或第三方插件只支持按稳定 ID 启停。已知功能被手改成不完整、歧义或无法读取的形状时,`dsh config` 显示诊断并拒绝自动修改,直到开发者手工修复。 +SDK 只修改功能明确拥有的 Cordis 配置项、配置键、NPM 依赖、`.env.example` 占位和独占文件。同一功能选项的更新保留 Cordis 配置项中的未知配置键;手写或第三方插件只支持按稳定 ID 启停。已知功能被手改成不完整、歧义或无法读取的形状时,`dsh-sdk config` 显示诊断并拒绝自动修改,直到开发者手工修复。 一次 config 会话在内存工作区上累计全部修改。Apply 前完成功能关系、资源冲突和文件形状校验,并比较受影响文件与会话打开时的原文;校验失败或检测到外部修改时不写盘。实际写盘开始后不提供跨文件事务回滚。 @@ -128,7 +128,7 @@ Builtin 支持集由 SDK 人工策划,不根据 NPM 依赖名称或目录约 ## 后续工作 -- `dsh add [package-spec]`:统一本地插件创建与外部 Cordis 插件接入;未指定 package 或仓库来源时创建本地 plugin/tool,指定来源时增加 NPM 依赖和 `cordis.yml` 配置项,来源模型为 GitHub 仓库等扩展保留空间 +- `dsh-sdk add [package-spec]`:统一本地插件创建与外部 Cordis 插件接入;未指定 package 或仓库来源时创建本地 plugin/tool,指定来源时增加 NPM 依赖和 `cordis.yml` 配置项,来源模型为 GitHub 仓库等扩展保留空间 - 非交互 create/config:本期两个流程都要求 TTY,不提供供自动化调用的完整输入合同 - 更多功能专用参数输入:本期产品只展示有限功能选项、secret 和少量专用值,不为 Cordis 插件配置提供通用参数界面 @@ -144,7 +144,7 @@ Builtin 支持集由 SDK 人工策划,不根据 NPM 依赖名称或目录约 **使用私有协议发现本地插件。** 普通 package manager workspace、根 NPM 依赖、TypeScript references 和 Cordis 配置项已能表达完整关系;额外发现协议会创造只能由 SDK 理解的隐藏状态。 -**在现有工程中提供 `dsh create`。** create 已能生成一种可编辑的本地插件骨架,后续插件可以沿用普通 workspace 和 Cordis 机制手工添加;再提供同构命令会增加第二条脚手架产品面,却不增加新的组合功能。 +**在现有工程中提供 `dsh-sdk create`。** create 已能生成一种可编辑的本地插件骨架,后续插件可以沿用普通 workspace 和 Cordis 机制手工添加;再提供同构命令会增加第二条脚手架产品面,却不增加新的组合功能。 **把每个新 Cordis 插件自动暴露为 builtin。** package 无法说明多个插件如何组合成一项产品功能,也无法推导互斥关系、功能依赖、secret、接口适用性和安全限制;支持集需要人工策划,自动化只适合检查候选是否完成分类。 @@ -153,8 +153,8 @@ Builtin 支持集由 SDK 人工策划,不根据 NPM 依赖名称或目录约 - `npm create @deepseek-ai/sdk` 按本文顺序收集项目身份、provider、interface、功能、可选本地插件、包管理器和安装选择,并在取消时保持目标路径不存在 - 默认 npm 工程具有本文目录树和 `dev`、`build`、`typecheck`、`start`、`config` scripts,且 dev/start 使用同一份 `cordis.yml` - create 展示本文功能及功能选项;`bash` 的 local/sandbox 二选一且默认 local,sandbox Cordis 配置项保留可编辑的注释配置示例;HMR 默认选中并同时由 dev/start 加载 -- create 的 `plugin` 或 `tool` 选择至多生成一个固定名称的本地插件,并原子更新插件文件与根工程关系;本期不提供 `dsh create` -- `dsh config` 从现有工程读取同一支持集,能够安装、启停和切换支持的功能选项,保留未知配置与注释,并拒绝修改不一致配置 +- create 的 `plugin` 或 `tool` 选择至多生成一个固定名称的本地插件,并原子更新插件文件与根工程关系;本期不提供 `dsh-sdk create` +- `dsh-sdk config` 从现有工程读取同一支持集,能够安装、启停和切换支持的功能选项,保留未知配置与注释,并拒绝修改不一致配置 - `.env.example` 反映当前功能所需变量;`.env` 只追加缺失的不同名变量,从不覆盖或清理已有内容 - npm、pnpm 和 Yarn 生成的 workspace 能安装、构建和启动;本地插件在 dev 中使用源码,在 start 中使用构建产物 diff --git a/packages/sdk/README.md b/packages/sdk/README.md index a193206a65..953d52ea76 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -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. diff --git a/packages/sdk/create-sdk/tests/built-artifacts.e2e.ts b/packages/sdk/create-sdk/tests/built-artifacts.e2e.ts index 53a2b858ba..4b2de078c7 100644 --- a/packages/sdk/create-sdk/tests/built-artifacts.e2e.ts +++ b/packages/sdk/create-sdk/tests/built-artifacts.e2e.ts @@ -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 ') + expect(result.stdout).toContain('Usage: dsh-sdk ') expect(result.stderr).toBe('') }) diff --git a/packages/sdk/create-sdk/tests/create.spec.ts b/packages/sdk/create-sdk/tests/create.spec.ts index 8233806ac5..9d75700bb9 100644 --- a/packages/sdk/create-sdk/tests/create.spec.ts +++ b/packages/sdk/create-sdk/tests/create.spec.ts @@ -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') diff --git a/packages/sdk/create-sdk/tests/link-workspace.e2e.ts b/packages/sdk/create-sdk/tests/link-workspace.e2e.ts index d78993995d..6e0b404dc6 100644 --- a/packages/sdk/create-sdk/tests/link-workspace.e2e.ts +++ b/packages/sdk/create-sdk/tests/link-workspace.e2e.ts @@ -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', diff --git a/packages/sdk/helper/README.md b/packages/sdk/helper/README.md index 3e1148e567..5b5608cdf0 100644 --- a/packages/sdk/helper/README.md +++ b/packages/sdk/helper/README.md @@ -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. diff --git a/packages/sdk/helper/src/templates/assets/README.md.tpl b/packages/sdk/helper/src/templates/assets/README.md.tpl index 5d56d13a72..0033c8e0d4 100644 --- a/packages/sdk/helper/src/templates/assets/README.md.tpl +++ b/packages/sdk/helper/src/templates/assets/README.md.tpl @@ -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`. diff --git a/packages/sdk/helper/src/templates/assets/package.json.tpl b/packages/sdk/helper/src/templates/assets/package.json.tpl index 9884f0913f..b5aa0fde0d 100644 --- a/packages/sdk/helper/src/templates/assets/package.json.tpl +++ b/packages/sdk/helper/src/templates/assets/package.json.tpl @@ -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}} diff --git a/packages/sdk/helper/src/templates/project-template.ts b/packages/sdk/helper/src/templates/project-template.ts index 90ab46d51e..b214126b6e 100644 --- a/packages/sdk/helper/src/templates/project-template.ts +++ b/packages/sdk/helper/src/templates/project-template.ts @@ -107,7 +107,7 @@ export function createAppProjectArtifacts( export function createAppPackageScripts(context: ProjectTemplateContext): Readonly> { 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}`, } } diff --git a/packages/sdk/helper/tests/project.spec.ts b/packages/sdk/helper/tests/project.spec.ts index 37c0c2f903..e888d7854f 100644 --- a/packages/sdk/helper/tests/project.spec.ts +++ b/packages/sdk/helper/tests/project.spec.ts @@ -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') diff --git a/packages/sdk/scripts/README.md b/packages/sdk/scripts/README.md index 5b3b1908bc..e87c375a4f 100644 --- a/packages/sdk/scripts/README.md +++ b/packages/sdk/scripts/README.md @@ -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']`). diff --git a/packages/sdk/scripts/package.json b/packages/sdk/scripts/package.json index c74ab051cc..ba441a528c 100644 --- a/packages/sdk/scripts/package.json +++ b/packages/sdk/scripts/package.json @@ -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": { ".": { diff --git a/packages/sdk/scripts/src/args.ts b/packages/sdk/scripts/src/args.ts index b23fe44870..1b91269592 100644 --- a/packages/sdk/scripts/src/args.ts +++ b/packages/sdk/scripts/src/args.ts @@ -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 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] } } diff --git a/packages/sdk/scripts/src/bin.ts b/packages/sdk/scripts/src/bin.ts index d08b872818..f125f0f4ac 100644 --- a/packages/sdk/scripts/src/bin.ts +++ b/packages/sdk/scripts/src/bin.ts @@ -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() diff --git a/packages/sdk/scripts/src/build.ts b/packages/sdk/scripts/src/build.ts index f71832f75f..4b83a24b71 100644 --- a/packages/sdk/scripts/src/build.ts +++ b/packages/sdk/scripts/src/build.ts @@ -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' diff --git a/packages/sdk/scripts/src/command.ts b/packages/sdk/scripts/src/command.ts index 13eec41d87..9351cfa39c 100644 --- a/packages/sdk/scripts/src/command.ts +++ b/packages/sdk/scripts/src/command.ts @@ -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 { 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 } } diff --git a/packages/sdk/scripts/src/config.ts b/packages/sdk/scripts/src/config.ts index bb0ab464c4..88d8cc035a 100644 --- a/packages/sdk/scripts/src/config.ts +++ b/packages/sdk/scripts/src/config.ts @@ -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 { 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) diff --git a/packages/sdk/scripts/src/config/config-workflow.ts b/packages/sdk/scripts/src/config/config-workflow.ts index e4e3476c3f..318ecd4ece 100644 --- a/packages/sdk/scripts/src/config/config-workflow.ts +++ b/packages/sdk/scripts/src/config/config-workflow.ts @@ -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(' '), diff --git a/packages/sdk/scripts/src/runtime.ts b/packages/sdk/scripts/src/runtime.ts index fbd9a88726..b25563bc07 100644 --- a/packages/sdk/scripts/src/runtime.ts +++ b/packages/sdk/scripts/src/runtime.ts @@ -68,7 +68,7 @@ async function registerDevRuntime(cwd: string = process.cwd()): Promise { ({ 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({ diff --git a/packages/sdk/scripts/src/templates/assets/usage.txt.tpl b/packages/sdk/scripts/src/templates/assets/usage.txt.tpl index b9680dddcf..d4122198f5 100644 --- a/packages/sdk/scripts/src/templates/assets/usage.txt.tpl +++ b/packages/sdk/scripts/src/templates/assets/usage.txt.tpl @@ -1,4 +1,4 @@ -Usage: dsh [options] +Usage: dsh-sdk [options] Commands: start [target] [-- args...] Import a built module, or boot cordis.yml diff --git a/packages/sdk/scripts/src/templates/dsh-templates.ts b/packages/sdk/scripts/src/templates/dsh-sdk-templates.ts similarity index 70% rename from packages/sdk/scripts/src/templates/dsh-templates.ts rename to packages/sdk/scripts/src/templates/dsh-sdk-templates.ts index 136ea5940a..a7dabc3b85 100644 --- a/packages/sdk/scripts/src/templates/dsh-templates.ts +++ b/packages/sdk/scripts/src/templates/dsh-sdk-templates.ts @@ -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>(new URL('./assets/usage.txt.tpl', import.meta.url)), configInstallFailure: TextTemplate.fromFile( new URL('./assets/config-install-failure.txt.tpl', import.meta.url), diff --git a/packages/sdk/scripts/tests/__snapshots__/config.snapshot.ts.snap b/packages/sdk/scripts/tests/__snapshots__/config.snapshot.ts.snap index bab11ec455..31e21dd8a9 100644 --- a/packages/sdk/scripts/tests/__snapshots__/config.snapshot.ts.snap +++ b/packages/sdk/scripts/tests/__snapshots__/config.snapshot.ts.snap @@ -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": [ diff --git a/packages/sdk/scripts/tests/config.snapshot.ts b/packages/sdk/scripts/tests/config.snapshot.ts index c6f6c64c6c..80a79a5f20 100644 --- a/packages/sdk/scripts/tests/config.snapshot.ts +++ b/packages/sdk/scripts/tests/config.snapshot.ts @@ -106,7 +106,7 @@ async function baseProject(): Promise { 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) diff --git a/packages/sdk/scripts/tests/scripts.spec.ts b/packages/sdk/scripts/tests/scripts.spec.ts index 572705f8fd..0ed3fed411 100644 --- a/packages/sdk/scripts/tests/scripts.spec.ts +++ b/packages/sdk/scripts/tests/scripts.spec.ts @@ -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 () => {