dsh-plugin-dev-kb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/cordis.patch.yml +12 -0
  4. package/kb/INDEX.md +210 -0
  5. package/kb/README.md +69 -0
  6. package/kb/extra/AGENTS.md +75 -0
  7. package/kb/extra/api-gateway.md +164 -0
  8. package/kb/extra/api-gateway.zh.md +164 -0
  9. package/kb/extra/cookbook/adding-a-vendored-package.md +59 -0
  10. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +59 -0
  11. package/kb/extra/cookbook/maintaining-dsh-code-review.md +64 -0
  12. package/kb/extra/cookbook/maintaining-dsh-code-review.zh.md +64 -0
  13. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +32 -0
  14. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +32 -0
  15. package/kb/extra/defensive-patterns.md +33 -0
  16. package/kb/extra/defensive-patterns.zh.md +33 -0
  17. package/kb/extra/development.md +171 -0
  18. package/kb/extra/development.zh.md +171 -0
  19. package/kb/extra/event-producer-consumer.md +76 -0
  20. package/kb/extra/event-producer-consumer.zh.md +78 -0
  21. package/kb/extra/glossary.md +45 -0
  22. package/kb/extra/glossary.zh.md +45 -0
  23. package/kb/extra/graph-atlas.md +24 -0
  24. package/kb/extra/graph-atlas.zh.md +26 -0
  25. package/kb/extra/i18n/README.md +60 -0
  26. package/kb/extra/i18n/README.zh.md +60 -0
  27. package/kb/extra/i18n/style-samples.md +87 -0
  28. package/kb/extra/i18n/terminology.md +214 -0
  29. package/kb/extra/i18n/translation-prompt.md +263 -0
  30. package/kb/extra/i18n/translation-rules.md +69 -0
  31. package/kb/extra/i18n/translation-rules.zh.md +69 -0
  32. package/kb/extra/module-graph.md +1641 -0
  33. package/kb/extra/module-graph.zh.md +1643 -0
  34. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +113 -0
  35. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +113 -0
  36. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +47 -0
  37. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +47 -0
  38. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +53 -0
  39. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +53 -0
  40. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +55 -0
  41. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +55 -0
  42. package/kb/extra/postmortem/README.md +18 -0
  43. package/kb/extra/postmortem/README.zh.md +18 -0
  44. package/kb/extra/rescope.md +53 -0
  45. package/kb/extra/rescope.zh.md +53 -0
  46. package/kb/extra/subsystems/attachment.md +125 -0
  47. package/kb/extra/subsystems/attachment.zh.md +125 -0
  48. package/kb/extra/subsystems/extensions.md +364 -0
  49. package/kb/extra/subsystems/extensions.zh.md +364 -0
  50. package/kb/extra/subsystems/feedback.md +266 -0
  51. package/kb/extra/subsystems/feedback.zh.md +266 -0
  52. package/kb/extra/testing.md +49 -0
  53. package/kb/extra/testing.zh.md +49 -0
  54. package/kb/extra/web-styling.md +25 -0
  55. package/kb/extra/web-styling.zh.md +25 -0
  56. package/kb/meta/search-index.json +1328 -0
  57. package/kb/meta/site-pages.txt +168 -0
  58. package/kb/meta/source.json +13 -0
  59. package/kb/meta/topics.md +75 -0
  60. package/kb/site/develop/basic/config.md +108 -0
  61. package/kb/site/develop/basic/index.md +146 -0
  62. package/kb/site/develop/basic/publish.md +185 -0
  63. package/kb/site/develop/basic/tool.md +54 -0
  64. package/kb/site/develop/cordis-tutorial/01-first-plugin.md +95 -0
  65. package/kb/site/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
  66. package/kb/site/develop/cordis-tutorial/03-services.md +98 -0
  67. package/kb/site/develop/cordis-tutorial/04-events.md +144 -0
  68. package/kb/site/develop/cordis-tutorial/05-config.md +84 -0
  69. package/kb/site/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
  70. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +107 -0
  71. package/kb/site/develop/cordis-tutorial/index.md +62 -0
  72. package/kb/site/develop/framework/events.md +145 -0
  73. package/kb/site/develop/framework/index.md +139 -0
  74. package/kb/site/develop/framework/service.md +152 -0
  75. package/kb/site/develop/practice/index.md +157 -0
  76. package/kb/site/develop/practice/llm-adapter.md +190 -0
  77. package/kb/site/en/develop/basic/config.md +108 -0
  78. package/kb/site/en/develop/basic/index.md +146 -0
  79. package/kb/site/en/develop/basic/publish.md +185 -0
  80. package/kb/site/en/develop/basic/tool.md +54 -0
  81. package/kb/site/en/develop/cordis-tutorial/01-first-plugin.md +95 -0
  82. package/kb/site/en/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
  83. package/kb/site/en/develop/cordis-tutorial/03-services.md +98 -0
  84. package/kb/site/en/develop/cordis-tutorial/04-events.md +144 -0
  85. package/kb/site/en/develop/cordis-tutorial/05-config.md +84 -0
  86. package/kb/site/en/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
  87. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +107 -0
  88. package/kb/site/en/develop/cordis-tutorial/index.md +60 -0
  89. package/kb/site/en/develop/framework/events.md +145 -0
  90. package/kb/site/en/develop/framework/index.md +139 -0
  91. package/kb/site/en/develop/framework/service.md +150 -0
  92. package/kb/site/en/develop/practice/index.md +157 -0
  93. package/kb/site/en/develop/practice/llm-adapter.md +190 -0
  94. package/kb/site/en/guide/providers-custom-form.png +0 -0
  95. package/kb/site/en/guide/providers-models-page.png +0 -0
  96. package/kb/site/en/guide/providers.md +100 -0
  97. package/kb/site/en/guide/python-sdk.md +106 -0
  98. package/kb/site/en/guide/quickstart.md +32 -0
  99. package/kb/site/en/index.md +8 -0
  100. package/kb/site/en/reference/agent-lifecycle.md +86 -0
  101. package/kb/site/en/reference/capability-seams.md +475 -0
  102. package/kb/site/en/reference/config-catalog.md +3155 -0
  103. package/kb/site/en/reference/cookbook/adding-a-conversation-node.md +235 -0
  104. package/kb/site/en/reference/cookbook/adding-a-package.md +120 -0
  105. package/kb/site/en/reference/cookbook/adding-a-settings-card.md +102 -0
  106. package/kb/site/en/reference/cookbook/adding-a-tool.md +96 -0
  107. package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +45 -0
  108. package/kb/site/en/reference/cookbook/extension-cookbook.md +131 -0
  109. package/kb/site/en/reference/cordis-api/context.md +368 -0
  110. package/kb/site/en/reference/cordis-api/events.md +211 -0
  111. package/kb/site/en/reference/cordis-api/fiber.md +379 -0
  112. package/kb/site/en/reference/cordis-api/inherited.md +43 -0
  113. package/kb/site/en/reference/cordis-api/registry.md +156 -0
  114. package/kb/site/en/reference/cordis-api/service.md +106 -0
  115. package/kb/site/en/reference/cordis-primer.md +46 -0
  116. package/kb/site/en/reference/index.md +131 -0
  117. package/kb/site/en/reference/persistence-catalog.md +949 -0
  118. package/kb/site/en/reference/subsystems/approval.md +173 -0
  119. package/kb/site/en/reference/subsystems/client-modules.md +121 -0
  120. package/kb/site/en/reference/subsystems/code-runtime.md +194 -0
  121. package/kb/site/en/reference/subsystems/commands.md +190 -0
  122. package/kb/site/en/reference/subsystems/compaction.md +241 -0
  123. package/kb/site/en/reference/subsystems/core.md +1073 -0
  124. package/kb/site/en/reference/subsystems/credentials.md +136 -0
  125. package/kb/site/en/reference/subsystems/filesystem.md +498 -0
  126. package/kb/site/en/reference/subsystems/goal.md +280 -0
  127. package/kb/site/en/reference/subsystems/index.md +58 -0
  128. package/kb/site/en/reference/subsystems/invariants.md +91 -0
  129. package/kb/site/en/reference/subsystems/jobs.md +293 -0
  130. package/kb/site/en/reference/subsystems/llm-streaming.md +920 -0
  131. package/kb/site/en/reference/subsystems/lsp.md +205 -0
  132. package/kb/site/en/reference/subsystems/permission-presets.md +134 -0
  133. package/kb/site/en/reference/subsystems/persistence.md +388 -0
  134. package/kb/site/en/reference/subsystems/plan.md +90 -0
  135. package/kb/site/en/reference/subsystems/sandbox.md +221 -0
  136. package/kb/site/en/reference/subsystems/schedule.md +189 -0
  137. package/kb/site/en/reference/subsystems/scope.md +62 -0
  138. package/kb/site/en/reference/subsystems/session-projection.md +265 -0
  139. package/kb/site/en/reference/subsystems/session-query.md +498 -0
  140. package/kb/site/en/reference/subsystems/session-reference.md +111 -0
  141. package/kb/site/en/reference/subsystems/session-telemetry.md +197 -0
  142. package/kb/site/en/reference/subsystems/session-title.md +207 -0
  143. package/kb/site/en/reference/subsystems/session.md +852 -0
  144. package/kb/site/en/reference/subsystems/settings.md +313 -0
  145. package/kb/site/en/reference/subsystems/shell.md +306 -0
  146. package/kb/site/en/reference/subsystems/skills.md +334 -0
  147. package/kb/site/en/reference/subsystems/spill.md +120 -0
  148. package/kb/site/en/reference/subsystems/storage.md +232 -0
  149. package/kb/site/en/reference/subsystems/subagent.md +737 -0
  150. package/kb/site/en/reference/subsystems/subprocess.md +327 -0
  151. package/kb/site/en/reference/subsystems/system-prompt.md +210 -0
  152. package/kb/site/en/reference/subsystems/terminal.md +187 -0
  153. package/kb/site/en/reference/subsystems/token-meter.md +93 -0
  154. package/kb/site/en/reference/subsystems/tools.md +723 -0
  155. package/kb/site/en/reference/subsystems/typert.md +339 -0
  156. package/kb/site/en/reference/subsystems/user-questions.md +181 -0
  157. package/kb/site/en/reference/subsystems/web-server.md +111 -0
  158. package/kb/site/en/reference/subsystems/web.md +202 -0
  159. package/kb/site/en/reference/subsystems/workflow.md +281 -0
  160. package/kb/site/en/reference/subsystems/workspace.md +231 -0
  161. package/kb/site/en/reference/tool-catalog.md +1877 -0
  162. package/kb/site/en/reference/tool-execution-pipeline.md +66 -0
  163. package/kb/site/guide/providers-custom-form.zh.png +0 -0
  164. package/kb/site/guide/providers-models-page.zh.png +0 -0
  165. package/kb/site/guide/providers.md +100 -0
  166. package/kb/site/guide/python-sdk.md +106 -0
  167. package/kb/site/guide/quickstart.md +32 -0
  168. package/kb/site/index.md +8 -0
  169. package/kb/site/reference/agent-lifecycle.md +86 -0
  170. package/kb/site/reference/capability-seams.md +475 -0
  171. package/kb/site/reference/config-catalog.md +3154 -0
  172. package/kb/site/reference/cookbook/adding-a-conversation-node.md +235 -0
  173. package/kb/site/reference/cookbook/adding-a-package.md +120 -0
  174. package/kb/site/reference/cookbook/adding-a-settings-card.md +102 -0
  175. package/kb/site/reference/cookbook/adding-a-tool.md +98 -0
  176. package/kb/site/reference/cookbook/adding-an-llm-adapter.md +45 -0
  177. package/kb/site/reference/cookbook/extension-cookbook.md +133 -0
  178. package/kb/site/reference/cordis-api/context.md +368 -0
  179. package/kb/site/reference/cordis-api/events.md +211 -0
  180. package/kb/site/reference/cordis-api/fiber.md +379 -0
  181. package/kb/site/reference/cordis-api/inherited.md +43 -0
  182. package/kb/site/reference/cordis-api/registry.md +156 -0
  183. package/kb/site/reference/cordis-api/service.md +106 -0
  184. package/kb/site/reference/cordis-primer.md +52 -0
  185. package/kb/site/reference/index.md +135 -0
  186. package/kb/site/reference/persistence-catalog.md +949 -0
  187. package/kb/site/reference/subsystems/approval.md +173 -0
  188. package/kb/site/reference/subsystems/client-modules.md +121 -0
  189. package/kb/site/reference/subsystems/code-runtime.md +194 -0
  190. package/kb/site/reference/subsystems/commands.md +190 -0
  191. package/kb/site/reference/subsystems/compaction.md +241 -0
  192. package/kb/site/reference/subsystems/core.md +1081 -0
  193. package/kb/site/reference/subsystems/credentials.md +136 -0
  194. package/kb/site/reference/subsystems/filesystem.md +498 -0
  195. package/kb/site/reference/subsystems/goal.md +280 -0
  196. package/kb/site/reference/subsystems/index.md +58 -0
  197. package/kb/site/reference/subsystems/invariants.md +91 -0
  198. package/kb/site/reference/subsystems/jobs.md +293 -0
  199. package/kb/site/reference/subsystems/llm-streaming.md +926 -0
  200. package/kb/site/reference/subsystems/lsp.md +205 -0
  201. package/kb/site/reference/subsystems/permission-presets.md +134 -0
  202. package/kb/site/reference/subsystems/persistence.md +388 -0
  203. package/kb/site/reference/subsystems/plan.md +90 -0
  204. package/kb/site/reference/subsystems/sandbox.md +221 -0
  205. package/kb/site/reference/subsystems/schedule.md +189 -0
  206. package/kb/site/reference/subsystems/scope.md +62 -0
  207. package/kb/site/reference/subsystems/session-projection.md +265 -0
  208. package/kb/site/reference/subsystems/session-query.md +498 -0
  209. package/kb/site/reference/subsystems/session-reference.md +111 -0
  210. package/kb/site/reference/subsystems/session-telemetry.md +197 -0
  211. package/kb/site/reference/subsystems/session-title.md +207 -0
  212. package/kb/site/reference/subsystems/session.md +854 -0
  213. package/kb/site/reference/subsystems/settings.md +313 -0
  214. package/kb/site/reference/subsystems/shell.md +306 -0
  215. package/kb/site/reference/subsystems/skills.md +334 -0
  216. package/kb/site/reference/subsystems/spill.md +120 -0
  217. package/kb/site/reference/subsystems/storage.md +232 -0
  218. package/kb/site/reference/subsystems/subagent.md +739 -0
  219. package/kb/site/reference/subsystems/subprocess.md +327 -0
  220. package/kb/site/reference/subsystems/system-prompt.md +210 -0
  221. package/kb/site/reference/subsystems/terminal.md +187 -0
  222. package/kb/site/reference/subsystems/token-meter.md +93 -0
  223. package/kb/site/reference/subsystems/tools.md +723 -0
  224. package/kb/site/reference/subsystems/typert.md +339 -0
  225. package/kb/site/reference/subsystems/user-questions.md +181 -0
  226. package/kb/site/reference/subsystems/web-server.md +111 -0
  227. package/kb/site/reference/subsystems/web.md +202 -0
  228. package/kb/site/reference/subsystems/workflow.md +281 -0
  229. package/kb/site/reference/subsystems/workspace.md +231 -0
  230. package/kb/site/reference/tool-catalog.md +1880 -0
  231. package/kb/site/reference/tool-execution-pipeline.md +66 -0
  232. package/package.json +40 -0
  233. package/scripts/rebuild-index.mjs +88 -0
  234. package/skills/dsh-plugin-dev-kb.md +66 -0
@@ -0,0 +1,84 @@
1
+ ---
2
+ editSource: "docs/cordis-tutorial/05-config.zh.md"
3
+ ---
4
+
5
+ # 5. 配置
6
+
7
+ `cordis.yml` 中的每个 Cordis 配置项都可以携带 `config` 块,插件则声明一个 schema,在运行 `apply` 前验证该块。错误配置会导致加载失败,并给出准确的错误:插件绝不会在配置不完整时启动。
8
+
9
+ ## 可配置插件
10
+
11
+ 创建 `config-demo.ts`,并将其放在 `tmp/cordis-tutorial` 中:
12
+
13
+ ```ts
14
+ import type { Context } from '@deepseek-ai/cordis'
15
+ import Schema from '@deepseek-ai/schemastery'
16
+
17
+ export const name = 'config-demo'
18
+
19
+ export interface Config {
20
+ greeting: string
21
+ targets: string[]
22
+ }
23
+
24
+ export const Config: Schema<Config> = Schema.object({
25
+ greeting: Schema.string().default('Hello'),
26
+ targets: Schema.array(String).default(['world']),
27
+ })
28
+
29
+ export function apply(ctx: Context, config: Config) {
30
+ for (const target of config.targets) {
31
+ console.log(`${config.greeting}, ${target}!`)
32
+ }
33
+ }
34
+ ```
35
+
36
+ 导出的 `Config` 既是 TypeScript 接口,也是同名的运行时 schema:消费方获得类型,Cordis 获得验证器。本仓库使用 [Schemastery](https://github.com/shigma/schemastery) 定义 schema;Cordis 本身接受任意 [Standard Schema](https://standardschema.dev/) 验证器,因此将普通对象导出为 `Config` 无法工作。
37
+
38
+ 对其进行配置:
39
+
40
+ ```yaml
41
+ - name: './config-demo.ts'
42
+ config:
43
+ targets: ['alpha', 'beta']
44
+ ```
45
+
46
+ 运行:
47
+
48
+ ```
49
+ Hello, alpha!
50
+ Hello, beta!
51
+ ```
52
+
53
+ 未提供 `greeting`,因此 schema 默认值会将其补齐:`apply` 始终会收到完整且经过验证的配置。
54
+
55
+ ## 明确报错
56
+
57
+ 现在向它传入无效内容:
58
+
59
+ ```yaml
60
+ - name: './config-demo.ts'
61
+ config:
62
+ targets: 'not-an-array'
63
+ ```
64
+
65
+ ```
66
+ ValidationError: invalid config:
67
+ - $.targets expected array but got not-an-array (at targets)
68
+ ```
69
+
70
+ 插件的 fiber 进入 FAILED 状态,本教程的启动器打印错误后以状态码 1 退出。如果某个插件的配置通过了 schema 验证,但其中指定的资源或提供方不可用,该插件也应当在能解析该引用时立即拒绝。
71
+
72
+ ## 计算得到的配置值
73
+
74
+ 本仓库使用的 loader 支持 `!!js` 标签,用于必须在加载时计算的配置值:
75
+
76
+ ```yaml
77
+ - name: './config-demo.ts'
78
+ config:
79
+ greeting: !!js process.env.DEMO_GREETING ?? 'Hello'
80
+ ```
81
+
82
+ `!!js` 仅在 `config` 与条目 `disabled` 字段内有效。`disabled: !!js ...` 在每次挂载决策时基于 loader 上下文求值(本仓库的扩展),可以按平台或环境门控一行;其余元数据(`name`、`id`、`inject` 等)保持静态,其中的表达式是普通真值数据。详见 [loader 配置](../../reference/cordis-primer.md#loader-configuration)。
83
+
84
+ 下一章:[组合与 HMR(热模块替换)](./06-composition-and-hmr.md):将 `cordis.yml` 视为应用。
@@ -0,0 +1,113 @@
1
+ ---
2
+ editSource: "docs/cordis-tutorial/06-composition-and-hmr.zh.md"
3
+ ---
4
+
5
+ # 6. 组合与 HMR(热模块替换)
6
+
7
+ 到目前为止构建的每项能力都是插件,`cordis.yml` 则选择应用的插件树。本章会改变这种组合、热重载一个插件,并诊断始终无法加载的插件。
8
+
9
+ ## Cordis 配置项不只有名称
10
+
11
+ Cordis 配置项除了 `name` 和 `config`,还接受其他元数据:
12
+
13
+ ```yaml
14
+ - id: greeter # stable identity for this entry
15
+ name: './greeter.ts'
16
+ - id: consumer
17
+ name: './consumer.ts'
18
+ disabled: true # keep the entry, skip mounting it
19
+ ```
20
+
21
+ `id` 为 Cordis 配置项提供稳定标识,使 loader 能区分修改现有 Cordis 配置项与先删除再添加。`disabled: true` 会卸载插件而不删除其 Cordis 配置项;改回原值后,插件以及所有因依赖其服务而处于 PENDING 的插件都会再次加载。
22
+
23
+ 组可以嵌套一份 Cordis 配置项子列表,并将其作为一个单元加载和卸载;`isolate` 则为一个组提供某项服务名称的独立实例,因此两个组可以各自看到配置不同的 `shell` 提供方,互不影响。[Cordis 入门](../../reference/cordis-primer.md)和[服务隔离示例](../framework/service.md#service-isolation)介绍了详细内容。
24
+
25
+ ## 热模块替换
26
+
27
+ 卸载会释放 effect([第 2 章](./02-lifecycle-and-effects.md)),加载则遵循依赖关系([第 3 章](./03-services.md)),因此 HMR 可以先卸载、再加载,以替换正在运行的插件。`@deepseek-ai/cordis-plugin-hmr` 插件会监视文件,并在保存时执行这一过程。
28
+
29
+ 在 `tmp/cordis-tutorial` 中编写 `cordis.yml`:
30
+
31
+ ```yaml
32
+ - id: logger
33
+ name: '@deepseek-ai/cordis-plugin-logger-console'
34
+ - id: timer
35
+ name: '@deepseek-ai/cordis-plugin-timer'
36
+ - id: hmr
37
+ name: '@deepseek-ai/cordis-plugin-hmr'
38
+ config:
39
+ root: ['.']
40
+ - id: hello
41
+ name: './hello.ts'
42
+ ```
43
+
44
+ 列表中增加了两个辅助插件:HMR 通过 Cordis logger 服务记录日志,因此没有控制台导出器时看不到其消息;它还会 `inject` `timer` 服务来实现去抖,如果没有 `@deepseek-ai/cordis-plugin-timer`,它就会永远停在 PENDING,而且不发出任何提示。下一节就讨论这种静默状态。
45
+
46
+ HMR 通过 Loader 的原生辅助工具读取 Node 的 loader 内部结构。请在 tsx 下运行 Cordis:
47
+
48
+ ```sh
49
+ node --import tsx ../../vendor/cordis/bin.js
50
+ ```
51
+
52
+ 现在编辑 `hello.ts`,修改日志消息并保存:
53
+
54
+ ```
55
+ hello from my first plugin
56
+ 2026-07-22 15:44:36 [I] hmr watching [ '.' ]
57
+ 2026-07-22 15:44:39 [I] hmr reload plugin at hello.ts
58
+ hello from my EDITED plugin
59
+ ```
60
+
61
+ 旧实例先卸载(其所有 effect 都会回卷),新代码随后加载,`apply` 再次运行。按 Ctrl-C 停止进程。编辑 `cordis.yml` 本身也会触发更新:loader 按 `id` 比较 Cordis 配置项,只挂载、卸载或重新配置发生变化的部分。这就是上述 Cordis 配置项显式携带 `id` 的原因:不带该字段的 Cordis 配置项在每次读取时都会获得一个新生成的 id,所以只要配置文件发生任何编辑,即使自身文本未变,它也会被视为先删除再添加并重新挂载。
62
+
63
+ ## 诊断始终无法加载的插件
64
+
65
+ 依赖驱动加载也有另一面:如果插件的 `inject` 指定了无人提供的服务,它就会一直等待,不输出任何内容。这不是错误,因为 PENDING 是合法状态,提供方可能稍后才挂载。
66
+
67
+ 你可以直接查看这些状态。每个上下文都能枚举插件注册表;创建 `diagnose.ts`:
68
+
69
+ ```ts
70
+ import { FiberState, type Context } from '@deepseek-ai/cordis'
71
+
72
+ export const name = 'diagnose'
73
+
74
+ export function apply(ctx: Context) {
75
+ setTimeout(() => {
76
+ for (const runtime of ctx.registry.values()) {
77
+ for (const fiber of runtime.fibers) {
78
+ if (fiber.state === FiberState.PENDING) {
79
+ console.log(`${fiber.name} is PENDING — a required service is missing`)
80
+ }
81
+ }
82
+ }
83
+ }, 500)
84
+ }
85
+ ```
86
+
87
+ 再创建一个依赖无法满足的插件 `needs-timer.ts`:
88
+
89
+ ```ts
90
+ import type { Context } from '@deepseek-ai/cordis'
91
+
92
+ export const name = 'needs-timer'
93
+ export const inject = ['timer']
94
+
95
+ export function apply(ctx: Context) {
96
+ console.log('needs-timer loaded')
97
+ }
98
+ ```
99
+
100
+ ```yaml
101
+ - name: './needs-timer.ts'
102
+ - name: './diagnose.ts'
103
+ ```
104
+
105
+ 运行它(直接执行 `node --import tsx ../../vendor/cordis/bin.js`,按 Ctrl-C 停止):
106
+
107
+ ```
108
+ needs-timer is PENDING — a required service is missing
109
+ ```
110
+
111
+ `inject: ['timer']` 没有提供方。向列表添加 `- name: '@deepseek-ai/cordis-plugin-timer'` 后,插件就会加载。如果插件既不执行任何操作,也不报告任何内容,请检查其 fiber 状态。不加 PENDING 过滤条件进行迭代时,还会看到 loader 自身的插件(Loader、Include)处于 ACTIVE,因为配置文件本身也是通过插件挂载的。
112
+
113
+ 下一章:[进入 harness](./07-into-the-harness.md):把相同模式用于真实的 harness 服务。
@@ -0,0 +1,107 @@
1
+ ---
2
+ editSource: "docs/cordis-tutorial/07-into-the-harness.zh.md"
3
+ ---
4
+
5
+ # 7. 进入 harness
6
+
7
+ 本章会向 harness 的 `tools` 服务注册一个可由模型调用的工具,通过 harness 工具流水线执行它,并观察结果事件。整个示例无需密钥,也不会调用模型。
8
+
9
+ ## 工具插件
10
+
11
+ 创建 `greet-tool.ts`,将它放在 `tmp/cordis-tutorial` 中:
12
+
13
+ ```ts
14
+ import type { Context } from '@deepseek-ai/cordis'
15
+ import { defineTool } from '@deepseek-ai/dsh-tools'
16
+ import { CallId } from '@deepseek-ai/dsh-llm'
17
+
18
+ export const name = 'greet-tool'
19
+ export const inject = ['tools']
20
+
21
+ export function apply(ctx: Context) {
22
+ ctx.tools.register(defineTool({
23
+ name: 'greet',
24
+ description: 'Greet the named person.',
25
+ parameters: {
26
+ name: { type: 'string', required: true, description: 'Who to greet' },
27
+ },
28
+ output: {
29
+ schema: { type: 'string' },
30
+ render: (_args, value) => [{ type: 'text', text: value }],
31
+ },
32
+ async execute(args) {
33
+ return `Hello, ${args.name}!`
34
+ },
35
+ }))
36
+
37
+ // Drive one call through the real execution pipeline, standing in for
38
+ // the model. CallId brands the correlation id a provider would issue.
39
+ void (async () => {
40
+ const result = await ctx.tools.execute({
41
+ callId: CallId('demo-1'),
42
+ name: 'greet',
43
+ arguments: { name: 'Cordis' },
44
+ signal: new AbortController().signal,
45
+ })
46
+ console.log('tool replied:', JSON.stringify(result.content))
47
+ })()
48
+ }
49
+ ```
50
+
51
+ 这里的每个模式都来自前几章:`inject: ['tools']`([第 3 章](./03-services.md))会让插件等待工具注册表就绪;`ctx.tools.register(...)` 会把注册 disposer 附着到插件([第 2 章](./02-lifecycle-and-effects.md)),因此卸载时会注销工具。`defineTool` 将 `parameters` 规约转换为向模型展示的 JSON Schema,推导 `args` 的类型,并在 `execute` 运行前校验模型提供的参数。工具返回由 `output.schema` 声明的规范值;`output.render` 则作为 Native renderer(原生渲染器),另行生成可持久化的结果内容。
52
+
53
+ ## 观察插件
54
+
55
+ 创建 `tool-logger.ts`。这是一个独立插件,通过 harness 的 `tools/result` 事件观察应用中的每次工具调用:
56
+
57
+ ```ts
58
+ import type { Context } from '@deepseek-ai/cordis'
59
+ import type {} from '@deepseek-ai/dsh-tools'
60
+
61
+ export const name = 'tool-logger'
62
+ export const inject = ['tools']
63
+
64
+ export function apply(ctx: Context) {
65
+ ctx.on('tools/result', (exec, result) => {
66
+ const text = result.content
67
+ .map(block => (block.type === 'text' ? block.text : ''))
68
+ .join('')
69
+ console.log(`[tool-logger] ${exec.name} -> ${text}`)
70
+ })
71
+ }
72
+ ```
73
+
74
+ `import type {} from '@deepseek-ai/dsh-tools'` 行会引入该包的声明合并,使 `'tools/result'` 及其 payload 具有类型。这与第 4 章导入 `stats.ts` 的做法相同,只是扩展到了包级别。
75
+
76
+ ## 组合并运行
77
+
78
+ ```yaml
79
+ - name: '@deepseek-ai/dsh-system-prompt'
80
+ - name: '@deepseek-ai/dsh-tools'
81
+ - name: './tool-logger.ts'
82
+ - name: './greet-tool.ts'
83
+ ```
84
+
85
+ `@deepseek-ai/dsh-tools` 会注入 `systemPrompt` 服务,因为工具需要向系统提示词贡献 schema,所以组合中也要列出该服务的提供方。缺少提供方时,工具插件会像[第 6 章](./06-composition-and-hmr.md)所述那样保持 PENDING。
86
+
87
+ ```sh
88
+ node --import tsx ../../vendor/cordis/bin.js
89
+ ```
90
+
91
+ ```
92
+ [tool-logger] greet -> Hello, Cordis!
93
+ tool replied: [{"type":"text","text":"Hello, Cordis!"}]
94
+ ```
95
+
96
+ logger 会先触发:`tools/result` 在结果物化过程中发出,发生在 `execute` 向调用方返回的 promise 兑现之前。两个插件都不知道另一个插件存在,它们由注册表服务和事件连接。
97
+
98
+ ## 从这里走向完整 agent(智能体)
99
+
100
+ 真实 agent 就是这套组合再加上更多插件:LLM(大语言模型)适配器、agent loop(智能体循环)、持久化和运行入口。对照 [examples/headless-agent/cordis.yml](https://github.com/deepseek-ai/deepseek-harness/blob/master/examples/headless-agent/cordis.yml),你现在已经可以读懂其中每个配置项。将 `greet-tool.ts` 加入该文件的副本即可。
101
+
102
+ 后续可以阅读:
103
+
104
+ - [构建工具](../basic/tool.md):深入了解 `defineTool`,包括呈现和更丰富的 schema。
105
+ - [三层能力设计](../practice/index.md):harness 如何组织可替换能力。
106
+ - [子系统页面](../../reference/subsystems/core.md)上生成的 `cordis-surface` 区块:可以注入和监听的所有内容,各在其所属页面上。
107
+ - [架构](../../reference/index.md):这些插件所处的系统地图。
@@ -0,0 +1,62 @@
1
+ ---
2
+ editSource: "docs/cordis-tutorial/index.zh.md"
3
+ ---
4
+
5
+ # Cordis 教程
6
+
7
+ Cordis 是 DeepSeek Harness 底层的插件框架:它是一个小型运行时,其中的每项能力,包括工具、LLM(大语言模型)适配器、文件访问乃至 agent loop(智能体循环)本身,都是挂载到共享上下文中的插件。本教程通过动手实践讲解 Cordis:每一章都是一个可以运行的示例,你将在本仓库内的临时目录中逐步构建它,最后把一个插件接入真实的 harness 服务。
8
+
9
+ 本教程面向 agent 开发者。你不需要深入掌握 TypeScript;下文的 [TypeScript 说明](#typescript-notes)会解释可能陌生的语法,并且每一章都会给出确切命令和预期输出。
10
+
11
+ 如果你想阅读精简的概念参考,而不是逐步实践,请参阅 [Cordis 入门](../../reference/cordis-primer.md)。详尽的 API 参考见[子系统页面](../../reference/subsystems/core.md)上生成的 `cordis-surface` 区块,以及 [Cordis 核心 API](../../reference/cordis-api/context.md) 页面。
12
+
13
+ 如果你要为 harness 本身编写插件——由 `cordis.yml` 加载、在 Web UI 中驱动,而不是下面这个启动器——请从[第一个 Harness 插件](../basic/index.md)开始。
14
+
15
+ <a id="setup"></a>
16
+
17
+ ## 准备工作
18
+
19
+ 你需要克隆本仓库并安装依赖;[开发指南](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/development.md#setup-tutorial)列出了前置条件。本教程不需要 API 密钥;所有示例均可在无密钥环境中运行。
20
+
21
+ ```sh
22
+ git clone https://github.com/deepseek-ai/deepseek-harness.git
23
+ cd deepseek-harness
24
+ pnpm install
25
+ ```
26
+
27
+ 创建各章使用的临时目录。`tmp/` 已被 git 忽略,因此你在其中写入的任何内容都不会进入版本控制:
28
+
29
+ ```sh
30
+ mkdir -p tmp/cordis-tutorial
31
+ cd tmp/cordis-tutorial
32
+ ```
33
+
34
+ 每一章都从该目录运行同一条命令:
35
+
36
+ ```sh
37
+ node --import tsx ../../vendor/cordis/bin.js
38
+ ```
39
+
40
+ 这个单文件启动器(见 [vendor/cordis/bin.js](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/bin.js))会创建根 `Context`、挂载 Loader 插件,并让它从当前目录加载 `./cordis.yml`。其余所有内容,包括有哪些插件以及如何配置它们,都来自你稍后将编写的 YAML 文件。`--import tsx` 标志让 Node 无需构建步骤即可运行配置所指向的 TypeScript 文件。
41
+
42
+ ## 章节
43
+
44
+ 1. [你的第一个插件](./01-first-plugin.md):插件是函数,由 loader 挂载。
45
+ 2. [生命周期与 effect](./02-lifecycle-and-effects.md):由 Cordis 管理的注册会在所属插件卸载时撤销。
46
+ 3. [服务](./03-services.md):在 `ctx` 上公开一项能力,并通过 `inject` 依赖它。
47
+ 4. [事件](./04-events.md):类型化事件、广播分发和 waterfall(瀑布式事件)的短路行为。
48
+ 5. [配置](./05-config.md):读取 `cordis.yml` 中经过校验的配置,并在输入错误时明确报错。
49
+ 6. [组合与 HMR(热模块替换)](./06-composition-and-hmr.md):把配置文件作为插件树,使用热重载,并诊断始终无法加载的插件。
50
+ 7. [进入 harness](./07-into-the-harness.md):基于真实的 harness 服务注册一个可由模型调用的工具。
51
+
52
+ <a id="typescript-notes"></a>
53
+
54
+ ## TypeScript 说明
55
+
56
+ 这些示例使用了普通现代 JavaScript 之外的三项 TypeScript 功能:
57
+
58
+ - **类型注解**描述值,但不会改变运行时行为:`ctx: Context` 表示 `ctx` 具备 Cordis 上下文 API,`who: string` 接受文本,而 `string[]` 表示字符串数组。
59
+ - **`import type { Context } from '@deepseek-ai/cordis'`** 只导入类型信息。它在运行时会消失,因此仅为类型注解使用 `Context` 的插件文件不会增加运行时依赖。
60
+ - **声明合并**(`declare module '@deepseek-ai/cordis' { ... }`)会为 Cordis 已经声明的接口添加你的条目,例如新 `ctx.greeter` 属性的类型或事件名称。它不会生成任何运行时接线;插件必须另行提供服务或发出事件。第 3 章会完整展示该模式。
61
+
62
+ 第 5 章还会使用 `interface` 描述配置对象的字段,并使用 `Schema<Config>` 这类泛型表示 schema 校验哪些对象字段。你可以直接照写这些声明;周围的正文会解释每项声明连接了什么。
@@ -0,0 +1,145 @@
1
+ ---
2
+ editSource: "docs/user/develop/framework/events.zh.md"
3
+ ---
4
+
5
+ # 事件系统
6
+
7
+ 事件是 Cordis 插件间通信的核心机制。Harness 大量使用事件来实现松耦合的扩展点。
8
+
9
+ ## 基本用法
10
+
11
+ ### 监听事件
12
+
13
+ ```ts ignore-check
14
+ ctx.on('event-name', (payload) => {
15
+ // Handle the event.
16
+ })
17
+ ```
18
+
19
+ ### 触发事件
20
+
21
+ ```ts ignore-check
22
+ ctx.emit('event-name', payload)
23
+ ```
24
+
25
+ ## 事件模式
26
+
27
+ Cordis 提供多种事件模式,适用于不同的交互契约:
28
+
29
+ ### emit — 广播
30
+
31
+ 所有监听器同步执行,返回值会被忽略:
32
+
33
+ ```ts ignore-check
34
+ // Emit
35
+ ctx.emit('my-plugin/ready', { id: 'worker-1' })
36
+
37
+ // Listen
38
+ ctx.on('my-plugin/ready', ({ id }) => {
39
+ console.log(`${id} is ready`)
40
+ })
41
+ ```
42
+
43
+ ### bail — 短路
44
+
45
+ 监听器按顺序运行,第一个不是 `null`、`false` 或 `undefined` 的返回值会成为最终结果:
46
+
47
+ ```ts ignore-check
48
+ // Dispatch
49
+ const result = ctx.bail('some-check', input)
50
+
51
+ // Listen: a returned value stops later listeners.
52
+ ctx.on('some-check', (input) => {
53
+ if (shouldBlock(input)) return 'blocked'
54
+ // Return null, false, or undefined to continue to the next listener.
55
+ })
56
+ ```
57
+
58
+ ### serial — 顺序执行
59
+
60
+ 监听器按注册顺序依次执行,并等待异步结果;第一个不是 `null`、`false` 或 `undefined` 的返回值会终止后续执行:
61
+
62
+ ```ts ignore-check
63
+ await ctx.serial('setup-phase', context)
64
+ ```
65
+
66
+ ### waterfall(瀑布式事件)— 流水线
67
+
68
+ 每个监听器可以包装下游返回值,形成处理链。**必须调用 `next()` 传递给下游**,不调用即会短路流水线:
69
+
70
+ ```ts ignore-check
71
+ // Dispatch
72
+ const output = await ctx.waterfall('my-plugin/transform', input, async () => input)
73
+
74
+ // Listen: next() is mandatory.
75
+ ctx.on('my-plugin/transform', async (_input, next) => {
76
+ const downstream = await next()
77
+ return downstream.trim()
78
+ })
79
+ ```
80
+
81
+ ::: warning
82
+ waterfall 监听器**必须调用 `next()`**。不调用 `next` 会短路整个流水线,这是故意为之的设计——用于实现拦截/网关逻辑。
83
+ :::
84
+
85
+ ## 类型安全的事件
86
+
87
+ Harness 使用 TypeScript 声明合并来为事件提供类型安全:
88
+
89
+ ```ts
90
+ import '@deepseek-ai/cordis'
91
+
92
+ declare module '@deepseek-ai/cordis' {
93
+ interface Events {
94
+ 'my-plugin/ready': (payload: { id: string }) => void
95
+ 'my-plugin/check': (input: string) => boolean | undefined
96
+ 'my-plugin/transform': (input: string, next: () => Promise<string>) => Promise<string>
97
+ }
98
+ }
99
+
100
+ // ctx.on('my-plugin/ready', ...) and ctx.emit('my-plugin/ready', ...)
101
+ // are now inferred correctly.
102
+ ```
103
+
104
+ ## Cordis 事件与会话记录
105
+
106
+ Harness 的 Cordis 事件遵循 `namespace/action` 命名,例如 `agent/step`、`agent/request`、`agent/request-error`、`tools/result` 和 `session/event`。完整签名与触发模式见[子系统页面](../../reference/subsystems/core.md)上生成的 `cordis-surface` 区块。
107
+
108
+ `turn/*`、`step/*`、`tool/call`、`tool/result` 和 `compaction/*` 是持久化的会话事件类型,不是同名 Cordis 事件。需要观察它们时,监听 `session/event` 并检查 `event.type`。
109
+
110
+ ## 事件监听器也是效果
111
+
112
+ 通过 `ctx.on()` 注册的监听器会在插件卸载时自动移除:
113
+
114
+ ```ts ignore-check
115
+ export function apply(ctx: Context) {
116
+ // This listener is removed when the plugin disposes.
117
+ ctx.on('tools/result', handler)
118
+ }
119
+ ```
120
+
121
+ ## 示例:日志插件
122
+
123
+ 这个插件记录工具调用和工具结果:
124
+
125
+ ```ts
126
+ import type { Context } from '@deepseek-ai/cordis'
127
+ import '@deepseek-ai/dsh-tools'
128
+
129
+ export const name = 'tool-logger'
130
+
131
+ export function apply(ctx: Context) {
132
+ ctx.on('tools/result', (exec, result) => {
133
+ console.log(`[tool] ${exec.name}(${JSON.stringify(exec.arguments)})`)
134
+ const text = result.content
135
+ .map(block => block.type === 'text' ? block.text : '')
136
+ .join('')
137
+ console.log(`[tool result] ${text.slice(0, 100)}`)
138
+ })
139
+ }
140
+ ```
141
+
142
+ ## 下一步
143
+
144
+ - [能力分层](../practice/index.md) — 了解能力接口中的事件
145
+ - [LLM(大语言模型)适配器](../practice/llm-adapter.md) — 实现一个完整的 LLM 后端
@@ -0,0 +1,139 @@
1
+ ---
2
+ editSource: "docs/user/develop/framework/index.zh.md"
3
+ ---
4
+
5
+ # 插件与生命周期
6
+
7
+ 本页介绍 Cordis 插件模型和生命周期状态机。
8
+
9
+ ## Fiber 状态机
10
+
11
+ 每个被加载的插件都拥有一个 **Fiber** 作用域,其状态如下:
12
+
13
+ ```
14
+ PENDING → LOADING → ACTIVE
15
+ ↘ FAILED
16
+ ACTIVE → UNLOADING → DISPOSED
17
+ ```
18
+
19
+ | 状态 | 含义 |
20
+ |------|------|
21
+ | PENDING | 已声明,但所需依赖未就绪 |
22
+ | LOADING | 依赖就绪,正在执行 `apply` |
23
+ | ACTIVE | 插件运行中 |
24
+ | FAILED | `apply` 抛出异常 |
25
+ | UNLOADING | 插件正在卸载并释放资源 |
26
+ | DISPOSED | 已完全卸载 |
27
+
28
+ ## 依赖驱动的加载
29
+
30
+ 声明了 `inject` 的插件会等待所有必需服务就绪:
31
+
32
+ ```ts ignore-check
33
+ export const inject = ['tools', 'llm']
34
+
35
+ export function apply(ctx: Context) {
36
+ // ctx.tools and ctx.llm are ready here.
37
+ }
38
+ ```
39
+
40
+ 如果依赖的服务消失(例如提供方被替换时),插件会被自动卸载(ACTIVE → DISPOSED),待服务恢复后重新加载。
41
+
42
+ ## 自动清理机制
43
+
44
+ 通过 `ctx` 做的任何注册,在插件卸载时都会自动撤销:
45
+
46
+ ```ts ignore-check
47
+ export function apply(ctx: Context) {
48
+ // Event listener: removed automatically on unload.
49
+ ctx.on('some-event', handler)
50
+
51
+ // Custom resource: the returned disposer runs on unload.
52
+ ctx.effect(() => {
53
+ const connection = createConnection()
54
+ return () => connection.close()
55
+ })
56
+ }
57
+ ```
58
+
59
+ 以下操作都会被自动追踪和清理:
60
+ - `ctx.on(event, handler)` — 事件监听
61
+ - `ctx.tools.register(tool)` — 工具注册
62
+ - `ctx.llm.registerAdapter(names, adapter)` — LLM(大语言模型)适配器注册
63
+ - `ctx.effect(() => cleanup)` — 自定义资源
64
+
65
+ 插件卸载时,处置器按注册顺序的逆序开始调用,但多个异步处置器会并发执行,不保证逐个完成。存在顺序依赖的清理步骤必须放进同一个 `ctx.effect()` 返回的处置器中,由该处置器负责串行等待。
66
+
67
+ ## 嵌套上下文
68
+
69
+ `ctx.plugin()` 创建子 Fiber,它继承父上下文但有独立的生命周期:
70
+
71
+ ```ts ignore-check
72
+ export function apply(ctx: Context) {
73
+ // Register a child plugin.
74
+ ctx.plugin(childPlugin)
75
+
76
+ // The child has its own Fiber and unloads with its parent.
77
+ }
78
+ ```
79
+
80
+ ## dispose(资源释放)语义
81
+
82
+ 当你需要提前终止一个插件实例:
83
+
84
+ ```ts
85
+ import type { Context } from '@deepseek-ai/cordis'
86
+
87
+ declare const ctx: Context
88
+ declare function myPlugin(ctx: Context): void
89
+
90
+ const fiber = ctx.plugin(myPlugin)
91
+
92
+ // Dispose it manually later.
93
+ await fiber.dispose()
94
+ ```
95
+
96
+ `dispose` 保证:
97
+ 1. 该插件拥有的所有注册均被移除
98
+ 2. 它的子插件也被递归卸载
99
+ 3. 返回的 Promise 会在所有异步清理完成后兑现
100
+
101
+ ## HMR(热模块替换)
102
+
103
+ 通过 `cordis.yml` 加载 `@deepseek-ai/cordis-plugin-hmr` 后,修改插件源文件会触发:
104
+
105
+ 1. 卸载旧插件(清理所有注册)
106
+ 2. 重新加载新代码
107
+ 3. 执行新的 `apply`
108
+
109
+ 因为插件注册会被自动清理,所以热替换不会保留旧实例的注册。
110
+
111
+ ## 生命周期示例
112
+
113
+ ```ts ignore-check
114
+ export function apply(ctx: Context) {
115
+ console.log('plugin loading')
116
+
117
+ ctx.effect(() => {
118
+ console.log('effect registered')
119
+ return () => console.log('effect cleaned up')
120
+ })
121
+ }
122
+ ```
123
+
124
+ 加载时输出:
125
+ ```
126
+ plugin loading
127
+ effect registered
128
+ ```
129
+
130
+ 卸载时输出:
131
+ ```
132
+ effect cleaned up
133
+ ```
134
+
135
+ ## 下一步
136
+
137
+ - [服务与依赖](./service.md) — 让插件向其他插件提供能力
138
+ - [事件系统](./events.md) — 在插件之间通信
139
+ - [Cordis 框架教程](../cordis-tutorial/index.md) — 在 Cordis 运行时上逐步搭出同一套生命周期、服务与事件