{"_id":"@buddhilive/dsh-cmdline","name":"@buddhilive/dsh-cmdline","dist-tags":{"alpha":"0.1.2-alpha.3","latest":"0.1.2-alpha.3"},"versions":{"0.1.2-alpha.3":{"name":"@buddhilive/dsh-cmdline","description":"Immutable command-line handoff from a dsh launcher to any app plugin that injects cmdlineArgs","version":"0.1.2-alpha.3","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/boot/cmdline"},"type":"module","main":"lib/index.js","types":"lib/types/index.d.ts","exports":{".":{"types":"./lib/types/index.d.ts","default":"./lib/index.js"},"./invariant":{"types":"./lib/types/invariant.d.ts","default":"./lib/invariant.js"},"./src/*":"./src/*","./package.json":"./package.json"},"license":"MIT","peerDependencies":{"@deepseek-ai/cordis-plugin-loader":"^1.0.3","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2"},"devDependencies":{"commander":"^15.0.0","@deepseek-ai/cordis-plugin-include":"^1.0.7","@buddhilive/dsh-invariants":"^0.1.2-alpha.3","@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/cordis-plugin-loader":"^1.0.3"},"_id":"@buddhilive/dsh-cmdline@0.1.2-alpha.3","bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","_integrity":"sha512-E9hQPmGmsjjHUx7nTGIRba4DEsYwCrU2by0VGOZcalFIn+UNwlip/OWIl9SZBQTQzW0YkMys74CIjQ8pviNUxw==","_resolved":"C:\\DevDojo\\Buddhi\\buddhi-ai-harness\\dist\\npm\\buddhilive-dsh-cmdline-0.1.2-alpha.3.tgz","_from":"file:C:/DevDojo/Buddhi/buddhi-ai-harness/dist/npm/buddhilive-dsh-cmdline-0.1.2-alpha.3.tgz","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-E9hQPmGmsjjHUx7nTGIRba4DEsYwCrU2by0VGOZcalFIn+UNwlip/OWIl9SZBQTQzW0YkMys74CIjQ8pviNUxw==","shasum":"1e64ed6ae9fd9fd2754c017bb328a86c1c3ba1fb","tarball":"https://registry.npmjs.org/@buddhilive/dsh-cmdline/-/dsh-cmdline-0.1.2-alpha.3.tgz","fileCount":9,"unpackedSize":35554,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCwrnBt2vw1oJSfOhho4sA/XJZainIbLWD8CXTy9br61AIhAKMq4J2CxPhGWfWWLtW/sKXtwg0US3abSbblRQfpizVS"}]},"_npmUser":{"name":"buddhilive","email":"visitbudkavin@gmail.com"},"directories":{},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-cmdline_0.1.2-alpha.3_1788165118268_0.7979653018242423"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T08:31:58.051Z","0.1.2-alpha.3":"2026-08-31T08:31:58.407Z","modified":"2026-08-31T08:31:58.742Z"},"maintainers":[{"name":"buddhilive","email":"visitbudkavin@gmail.com"}],"description":"Immutable command-line handoff from a dsh launcher to any app plugin that injects cmdlineArgs","homepage":"https://github.com/Buddhilive/buddhi-ai-harness#readme","repository":{"type":"git","url":"git+https://github.com/Buddhilive/buddhi-ai-harness.git","directory":"packages/boot/cmdline"},"bugs":{"url":"https://github.com/Buddhilive/buddhi-ai-harness/issues"},"license":"MIT","readme":"---\ndescription: \"dsh app bin 的应用自有命令行：应用从启动器剩余参数中解析自己的 flag、--help 与退出行为。\"\nkind: \"package-library\"\n---\n\n# @buddhilive/dsh-cmdline\n\n[English](README.md) | 中文\n\n## 概述\n\n`dsh-cmdline` 让你的应用持有自己的命令行：启动器只保留属于自己的 flag（`--profile`、`--patch`、配置 dump），并把**其后的一切**原样交给你的应用，因此 flag、`--help` 文本与解析错误都由你的应用决定。你从这些参数解析出的值会胜过配置中写下的任何默认值，且无需写回任何内容。你的应用还获得一个有边界的进程退出请求，接到启动器的关停上。当你编写接受自有 flag 的应用 bin 时使用它；它本身不增加任何提示词、schema 或面向模型的表面。\n\n## 目录\n\n- [使用本包](#use-this-package)\n- [理解实现](#understand-the-implementation)\n- [进一步探索](#further-exploration)\n- [模型体验](#model-experience)\n- [已知限制与延期工作](#known-limitations-and-deferred-work)\n- [开发备注](#dev-note)\n\n-----\n\n<a id=\"use-this-package\"></a>\n## 使用本包\n\n你的应用在启动时读取本次调用的内层参数，任意数量的插件都可以使用它们。常用路径是：启动插件读取参数、解析它们，再发布解析后的值；其他行由这些值配置自身。\n\n### 启动器提供的值\n\n启动器向你的应用提供三样东西：\n\n- `ctx.cmdlineArgs`——本次调用的内层参数。读取它返回一份不可变快照，且绝不会消费或修改它们：`dsh --profile tui --resume abc` 给你的应用 `['--resume', 'abc']`。\n- `ctx.appExit`——在整棵树关闭后请求进程退出的方式，接到启动器的关停控制器上。\n- `ctx.appReady`——成功启动信号，只在 Loader 树与 launcher 自有设置成功后提交。\n\n没有参数的启动会看到空列表——这是诚实的答案，而不是缺失的值。\n\n`exitOnStdinEnd(ctx, label)` 把已成功启动的 stdio 应用 EOF 绑定到 `ctx.appExit(0)`。它绝不读取或恢复 stdin，因此协议传输会收到挂载前已缓冲的字节；启动拒绝优先于竞态 EOF，拥有它的 fiber 会移除两项待处理监听。\n\n### 解析你的 flag\n\n你自带自己的 commander program：声明你的 flag 与 action，本包会针对内层参数运行它。校验只发生在你的 action 中，并由它发布你的行所需的任何值。插件的 Loader 行不携带特殊标记：\n\n```yaml\n- id: web-startup\n  name: '@buddhilive/dsh-web-app/startup'\n```\n\n由解析值配置的行注入发布的服务，并在其配置中直接读取它：\n\n```yaml\n- id: webserver\n  name: '@buddhilive/dsh-host-webserver'\n  inject: [webStartup]\n  config:\n    host: !!js ctx.webStartup.host ?? '127.0.0.1'\n    port: !!js ctx.webStartup.port ?? 3080\n```\n\n结果：即使配置写的是 3080，`dsh --profile web --port 8080` 也会让服务器监听 8080 端口，因为 flag 优先。`--help` 打印你的应用帮助并以 0 退出、不启动任何内容；被拒绝的值（例如非数字端口）打印你的错误并以非零码退出，任何依赖解析值的行都不会启动。\n\n### flag 如何胜过配置值\n\n写在 `!!js` 表达式旁的值是后备：flag 存在时 flag 优先，否则使用写下的值。解析在启动时、你的解析器运行之后发生一次，因此 flag 绝不会被之后的配置重载悄悄重置。\n\n### 多个插件读取同一份参数\n\n任意数量的插件都可以读取同一份参数——读取绝不会消费它们——每个插件都能解析自己需要的部分并发布各自的值。启动器不会决定谁是命令行的所有者：没有读取方的应用会忽略自己的参数。\n\n本仓库之外构建的应用行为一致：即使它们自带 commander 副本，其 `--help` 也会打印并退出，而不是崩溃。\n\n-----\n\n<a id=\"understand-the-implementation\"></a>\n## 理解实现\n\n<details>\n<summary>实现细节——点击展开</summary>\n\n本节解释上述结果如何实现，并指出实现它们的代码位置；这里的内容面向开发者，使用本包并不需要。\n\n### 设计说明\n\n- **启动器事实，而非配置。** `cmdlineArgs` 与 `appExit` 在树挂载前提供到宿主上下文上；它们不是 Loader 行，因此没有任何组合持有或覆盖它们。\n- **按位置切分。** 启动器不认识任何应用行：自身 flag 之后的第一个 token 就是应用参数的起点，因此 flag 家族、`--help` 文本与解析错误都由应用自己持有。\n- **结构化错误识别。** `isCommanderError` 读取 commander 的错误码前缀，而不是用 `instanceof`，因为树外插件会带来自己的一份 commander 副本，其 `CommanderError` 身份不同；`configureExitAndOutput` 会遍历每个子命令，因为 commander 只在注册时复制退出与输出设置。\n- **可注入的输出流。** `internals` 持有输出流，使测试无需触碰进程即可捕获 commander 的文本。\n\n### 解析约定\n\n解析路径是一个只有两个所有者的小家族：`provideCmdline` 冻结宿主参数，并在任何配置树条目挂载前提供 `cmdlineArgs` 与 `appExit`；`parseCmdline` 针对不可变参数运行你的 commander program，把每个命令的 help、version 与错误输出都接到启动器上。被拒绝的值、`--help` 或 `--version` 会打印 commander 文本并请求 `ctx.appExit`，且不发布任何内容，因此依赖行绝不会激活；Loader 会把每行的 `!!js` 插值推迟到该行声明的注入全部激活之后。各导出的约定在代码中，不在本 README——见 [`src/index.ts`](src/index.ts)。\n\n### 源码地图\n\n| 文件 | 职责 |\n|---|---|\n| [`src/index.ts`](src/index.ts) | `CmdlineArgs`/`AppExit` 类型、`provideCmdline`、`parseCmdline`、commander 退出／输出路由 |\n| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件（无运行时不变式；Loader 结算会报告缺失的服务） |\n\n</details>\n\n-----\n\n<a id=\"further-exploration\"></a>\n## 进一步探索\n\n当包级约定不够用时阅读以下页面。它们从交接机制逐步进入消费它的应用及其背后的决策。\n\n- [应用持有命令行决策](../../../.agents/notes/implemented/architecture/2026-08-06-app-owned-command-line.zh.md)——为什么 flag 家族由应用持有，以及交接如何运作。\n- [命令行 seam 精简](../../../.agents/notes/implemented/architecture/2026-08-11-cmdline-seam-trim.zh.md)——缩减到既有接口的各 seam。\n- [dsh-app-boot](../app-boot/README.zh.md)——提供这些启动器值的启动序列。\n- [dsh-web-app 组合包](../../bundle/web-app/README.zh.md)——通过此包持有 Web flag 家族的应用。\n- [dsh-headless 组合包](../../bundle/headless/README.zh.md)——从命令行读取任务的一次性 runner。\n\n-----\n\n<a id=\"model-experience\"></a>\n## 模型体验\n\n无。本包在任何会话存在之前解析进程自身的命令行；配置行持有每一个模型可见的后果。\n\n#### KV Cache 影响\n\n无；本包既不组装也不发送提供方请求。\n\n## 已知限制与延期工作\n\n<a id=\"known-limitations-and-deferred-work\"></a>\n\n\n这些限制说明应用自有命令行在何时不合适，或何时需要特别注意。它们是当前包约束，不是任务积压。\n\n- **启动器的 flag 必须写在应用参数之前**——切分按位置进行：启动器不认识的第一个 token 就是内层参数的起点，因此写在某个应用 flag 之后的 `--patch` 属于应用。启动器的解析器会消耗掉一个 `--`，因此必须以字面量 `--` 存活到应用的参数需要写成 `-- --`。\n- **应用自有服务没有静态声明的提供方**——消费行通过普通注入点名它；缺少提供方的组合包会在结算时失败，由待处理条目点名该服务，而不是在加载时失败。\n- **用户 patch 若整体替换某行的 `config`，会连同其中的表达式一起丢掉**——flag 胜过的是表达式旁写着的那个值，而不是用户用字面量替换掉表达式之后的结果；保留表达式才能保留 flag 的优先级。\n\n<a id=\"dev-note\"></a>\n### 开发备注\n\n<details>\n<summary>维护者的工作上下文——点击展开</summary>\n\n本开发备注是维护者的工作上下文：开放设计问题与尚未决定的探索方向。它明确不具权威性——已交付的行为、限制与既定理由以上文、包代码和相关 Agent Note 为准。\n\n#### 待定：解析器表面\n\n`parseCmdline` 是 commander 适配器，而不是命令行框架：help、version 与错误输出遵循 commander 的格式，退出／输出路由也假定 commander 的控制流模型。改用其他解析器需要它自己的路由与错误处理；`cmdlineArgs` 服务约定中没有任何内容依赖 commander。\n\n</details>\n","readmeFilename":"README.zh.md","_rev":"1-29a0d37abb056251b7638313b5e792b8"}