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,327 @@
1
+ ---
2
+ editSource: "docs/subsystems/subprocess.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # Subprocess
7
+
8
+ The subprocess seam is split across a Service Definition ([dsh-subprocess](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subprocess/subprocess), `ctx.subprocess`) and Service Provider ([dsh-subprocess-local](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/subprocess/subprocess-local)); its Consumers are other capability seams and out-of-process backends: the [bash executor family](./shell.md) uses collected batch output, LSP uses raw protocol pipes, the PTY backend uses the terminal primitive, and the ACP subagent backend uses piped ndjson plus inherited stderr. This seam owns the managed `DSH_*` environment namespace, the shared credential scrub (`scrubbedParentEnv`), and the `CollectedOutput` shape; [dsh-shell](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/shell) re-exports the vocabulary so bash consumers keep one import root.
9
+
10
+ Source: [`packages/subprocess/subprocess/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/src/types.ts) and [`packages/subprocess/subprocess/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/src/index.ts)
11
+
12
+ ## Executable lookup
13
+
14
+ One provider's spawn working directories, executable paths, ordinary processes, and terminal sessions inhabit the same path and process namespace as the mounted filesystem provider. `resolveExecutable(command, env?, signal?)` verifies absolute executable paths or resolves bare names through the provider's scrubbed `PATH` plus deliberate overrides.
15
+
16
+ ## Managed environment namespace and captured output
17
+
18
+ `DSH_*` variables are Harness-owned child-process facts; implementations discard ambient `DSH_*` names before the caller's explicit `env` merges, so a current fact arrives only as a deliberate string entry, while an explicit `undefined` tombstone removes an ordinary ambient value. Each collected stream reports its truncation and spill-recovery state through `CollectedOutput`.
19
+
20
+ ```ts type-equiv
21
+ /** One environment key inside the managed {@link DSH_ENV_PREFIX} namespace. */
22
+ type DshEnvironmentKey = `${typeof DSH_ENV_PREFIX}${string}`
23
+ ```
24
+
25
+ ```ts type-equiv
26
+ /** Trusted DeepSeek Harness variables for one child-process execution. */
27
+ type DshEnvironment = Readonly<Record<DshEnvironmentKey, string>>
28
+ ```
29
+
30
+ ```ts type-equiv
31
+ /** One captured stream: the (possibly truncated) text plus recovery info. */
32
+ interface CollectedOutput {
33
+ /** Collected text — the TAIL of the stream when truncated. */
34
+ text: string
35
+ /** True when bytes were dropped from `text`. */
36
+ truncated: boolean
37
+ /** Path to a file holding the COMPLETE stream, when truncated and available. */
38
+ spillPath?: string
39
+ }
40
+ ```
41
+
42
+ ## Node-shaped stdio dispositions
43
+
44
+ Each stream's disposition is explicit, chosen per consumer: raw pipes for protocol framing (LSP JSON-RPC, ACP ndjson), inherit for pass-through diagnostics, and collect mode for bounded batch output — with the spill file optional, so a diagnostic tail (a language server's stderr) buffers without leaving files behind.
45
+
46
+ ```ts type-equiv
47
+ /**
48
+ * stdin disposition. `'ignore'` leaves fd 0 on `/dev/null`; `'pipe'` exposes
49
+ * {@link SubprocessHandle.stdin} for the caller's ongoing protocol writes;
50
+ * `{ data }` writes the bytes and closes (the batch shape).
51
+ */
52
+ type SubprocessStdinMode = 'ignore' | 'pipe' | { readonly data: string }
53
+ ```
54
+
55
+ ```ts type-equiv
56
+ /**
57
+ * Bounded in-memory collection for one output stream, with an optional
58
+ * full-stream spill file. Omitting `spill` keeps only the in-memory tail —
59
+ * the diagnostic-tail shape (a language server's stderr); including it makes
60
+ * the complete stream recoverable up to its cap (the bash tool shape).
61
+ */
62
+ interface SubprocessCollect {
63
+ /** In-memory cap in bytes; overflow keeps the TAIL. */
64
+ maxBytes: number
65
+ /** Full-stream spill file; absent disables spilling entirely. */
66
+ spill?: {
67
+ /** Whole-stream byte cap; a larger stream discards its now-incomplete spill. */
68
+ maxBytes: number
69
+ }
70
+ }
71
+ ```
72
+
73
+ ```ts type-equiv
74
+ /**
75
+ * stdout/stderr disposition. `'pipe'` exposes the raw `Readable` for the
76
+ * caller's protocol decoding; `'inherit'` passes the parent's descriptor
77
+ * through (child diagnostics land on the harness's own stream); a
78
+ * {@link SubprocessCollect} object buffers boundedly with offset-based reads.
79
+ */
80
+ type SubprocessOutputMode = 'pipe' | 'inherit' | SubprocessCollect
81
+ ```
82
+
83
+ ```ts type-equiv
84
+ /** Per-stream stdio dispositions, all explicit — this seam applies no defaults. */
85
+ interface SubprocessStdio {
86
+ stdin: SubprocessStdinMode
87
+ stdout: SubprocessOutputMode
88
+ stderr: SubprocessOutputMode
89
+ }
90
+ ```
91
+
92
+ ## The fully-explicit spawn spec
93
+
94
+ The seam applies no defaults: every disposition, limit, and directory is explicit on the spec, so the caller's own config — not a hidden subprocess-service default — decides them. `argv` is never shell-interpreted.
95
+
96
+ ```ts type-equiv
97
+ /**
98
+ * A fully-specified spawn request. This seam applies no defaults: every
99
+ * disposition, limit, and directory is explicit, so the caller's own config —
100
+ * not a hidden subprocess-service default — decides them (the `dsh-shell`
101
+ * request/spec split is the owning template).
102
+ */
103
+ interface SubprocessSpawnSpec {
104
+ /** Executable and arguments; `argv[0]` is the program. Never shell-interpreted here. */
105
+ argv: readonly string[]
106
+ /** Working directory for the child. */
107
+ cwd: string
108
+ /** Per-stream stdio dispositions. */
109
+ stdio: SubprocessStdio
110
+ /**
111
+ * Positive finite grace period in milliseconds, no greater than
112
+ * `MAX_TIMER_DELAY_MS`, for the {@link SubprocessHandle.terminate} escalation
113
+ * and for draining still-open collected pipes after the process exits (an
114
+ * inherited descriptor held by a surviving descendant cannot hold the
115
+ * outcome open indefinitely).
116
+ */
117
+ graceMs: number
118
+ /**
119
+ * Abort signal — starts the terminate escalation on the process tree when
120
+ * it fires. The caller owns deadlines and cause classification; this seam
121
+ * only reacts to the abort.
122
+ */
123
+ signal?: AbortSignal | undefined
124
+ /**
125
+ * Explicit environment entries merged onto the implementation's scrubbed
126
+ * parent base (see `scrubbedParentEnv`), with no namespace validation. A
127
+ * string is a deliberate caller opt-in, so a forwarded credential-shaped
128
+ * entry or current `DSH_*` fact survives the scrub; `undefined` is a
129
+ * tombstone that removes an ordinary ambient entry from the child.
130
+ */
131
+ env?: NodeJS.ProcessEnv | undefined
132
+ }
133
+ ```
134
+
135
+ ## Handles: streams, readers, and tree-scoped termination
136
+
137
+ A spawn returns a live handle immediately. Collect-mode readers take whole-stream byte offsets and never consume, so independent readers cannot steal one another's deltas; piped streams belong to the caller. Termination is tree-scoped on every platform: `terminate()` — the only termination verb — escalates SIGTERM→grace→SIGKILL, and `waitForExit()` observes the whole tree — enough for a consumer to build its own teardown ladder (the ACP backend's stdin-EOF-first `disposeAcpChild` is the template).
138
+
139
+ ```ts type-equiv
140
+ /**
141
+ * A live child process rooted in its own process tree. Collected output
142
+ * remains readable after exit; piped streams belong to the caller.
143
+ *
144
+ * Termination is tree-scoped everywhere: POSIX signals the detached process
145
+ * group (falling back to the direct child when the group is gone), Windows
146
+ * terminates the tree via `taskkill /T`, so helper processes cannot outlive
147
+ * the handle unnoticed.
148
+ */
149
+ interface SubprocessHandle {
150
+ /** Process id (tree root); -1 when the spawn itself failed. */
151
+ readonly pid: number
152
+ /** The child's stdin, present iff spawned with `stdin: 'pipe'`. */
153
+ readonly stdin: Writable | undefined
154
+ /** The child's raw stdout, present iff spawned with `stdout: 'pipe'`. */
155
+ readonly stdout: Readable | undefined
156
+ /** The child's raw stderr, present iff spawned with `stderr: 'pipe'`. */
157
+ readonly stderr: Readable | undefined
158
+ /** Offset-based readers for collect-mode streams (also readable after exit). */
159
+ readonly collected: SubprocessCollectedOutputs
160
+ /** Resolves at process close with exit facts; rejects only for spawn-level failures. */
161
+ readonly done: Promise<SubprocessOutcome>
162
+ /**
163
+ * Begin the SIGTERM → `graceMs` → SIGKILL escalation on the process tree
164
+ * (Windows force-terminates immediately) — the seam's only termination
165
+ * verb. Idempotent, a no-op once the tree is gone (the pid may be reused),
166
+ * and also triggered by the spec's abort signal.
167
+ */
168
+ terminate(): void
169
+ /**
170
+ * Wait until the process tree has exited — the tree, not just the direct
171
+ * child, so a still-running helper is observable before teardown returns.
172
+ * @param signal - optional bound for the wait.
173
+ * @returns `true` when the tree exited, `false` when the signal aborted first.
174
+ */
175
+ waitForExit(signal?: AbortSignal): Promise<boolean>
176
+ }
177
+ ```
178
+
179
+ ```ts type-equiv
180
+ /**
181
+ * Cursor-free incremental access to one collected output stream. Offsets are
182
+ * whole-stream byte coordinates owned by the caller, so independent readers
183
+ * cannot consume one another's output; `readFrom(0)` after settlement is the
184
+ * batch result (`lossy` then means the in-memory tail lost its head — the
185
+ * {@link CollectedOutput.truncated} fact).
186
+ */
187
+ interface SubprocessOutputReader {
188
+ /**
189
+ * Read everything captured since `fromByte`. When that offset has slid out
190
+ * of the in-memory tail window the read is `lossy` — it returns the whole
191
+ * retained tail and the gap is only recoverable from the spill file.
192
+ * @param fromByte - whole-stream offset to resume from (a prior read's `nextOffset`; 0 for the first read).
193
+ * @returns the delta text, the next offset, the `lossy` flag, and the spill path when one exists.
194
+ */
195
+ readFrom(fromByte: number): SubprocessOutputRead
196
+ }
197
+ ```
198
+
199
+ ```ts type-equiv
200
+ /** One incremental {@link SubprocessOutputReader.readFrom} read. */
201
+ interface SubprocessOutputRead {
202
+ /** Stream text from the requested offset (the whole retained tail when lossy). */
203
+ text: string
204
+ /** Whole-stream offset to resume from on the next read. */
205
+ nextOffset: number
206
+ /** True when the requested offset slid out of the in-memory tail window. */
207
+ lossy: boolean
208
+ /** Path to the full-stream spill file, when one was created and remains intact. */
209
+ spillPath?: string
210
+ }
211
+ ```
212
+
213
+ ```ts type-equiv
214
+ /** Offset-based readers for the streams spawned in collect mode. */
215
+ interface SubprocessCollectedOutputs {
216
+ /** Present iff stdout is a {@link SubprocessCollect}. */
217
+ readonly stdout?: SubprocessOutputReader
218
+ /** Present iff stderr is a {@link SubprocessCollect}. */
219
+ readonly stderr?: SubprocessOutputReader
220
+ }
221
+ ```
222
+
223
+
224
+ ## Outcomes carry exit facts only
225
+
226
+ `done` reports Node's close-event vocabulary and no cause classification — the service kills on abort but never decides why (the caller reads the deadline signal it owns, e.g. the bash executor's `timedOut`/`aborted` split). Collected output stays readable through `handle.collected` after settlement, so batch and streaming callers share one access path.
227
+
228
+ ```ts type-equiv
229
+ /**
230
+ * Exit facts of one closed process — Node's `close`-event vocabulary.
231
+ * Deliberately carries NO timeout or cancellation classification (the caller
232
+ * reads the signal it owns to classify causes) and NO output: collected
233
+ * streams stay readable through {@link SubprocessHandle.collected} after
234
+ * settlement, so batch and streaming callers share one access path.
235
+ */
236
+ interface SubprocessOutcome {
237
+ /** Exit code; null when the process died from a signal. */
238
+ exitCode: number | null
239
+ /** Terminating signal (e.g. 'SIGTERM'); null on normal exit. */
240
+ signal: NodeJS.Signals | null
241
+ }
242
+ ```
243
+
244
+ ## Terminal-process primitive
245
+
246
+ `spawnTerminal(spec)` is the non-pipe process primitive. The provider allocates the controlling terminal and owns UTF-8 text transport, foreground-process-group inspection and signalling, and one awaited TERM-to-KILL operation that reaches quiescence for every session member the provider can still observe; providers document substrate-specific observability limits. The PTY backend remains responsible for prompt detection, readiness inference, scrollback, sandbox policy, and persistent-session ownership; ordinary `spawn()` cannot reconstruct controlling-terminal semantics.
247
+
248
+ The terminal spec fully specifies argv, cwd, environment overrides, dimensions, cleanup grace, and optional allocation cancellation. Its handle exposes `pid`, ordered output, `done`, `write`, `inspectForeground`, `signalForeground`, and awaited `terminate`; the exact public shapes are generated into the [`ctx.subprocess` service catalog](#ctxsubprocess--subprocessruntime-abstract-seam).
249
+
250
+ ## Service behavior
251
+
252
+ The abstract [`SubprocessRuntime`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/src/index.ts) Service Definition specifies execution-world coordinates, executable lookup, ordinary `spawn`, and `spawnTerminal`. [`LocalSubprocessRuntime`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess-local/src/index.ts) provides them with detached process trees, per-disposition wiring, credential scrubbing, `node-pty`, platform process inspection, and terminate-and-join disposal. See [`dsh-subprocess`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/README.md) for the Service Definition contract and [`dsh-subprocess-local`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess-local/README.md) for local mechanics.
253
+
254
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
255
+
256
+ <a id="cordis-surface"></a>
257
+
258
+ ## Cordis API
259
+
260
+ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
261
+
262
+ <a id="ctxe2b--e2bruntime"></a>
263
+
264
+ ### `ctx.e2b` — `E2BRuntime`
265
+
266
+ Creates one lazily consumable E2B SDK handle and deletes the sandbox at timeout or disposal. Creation begins at plugin construction; adapters await getSandbox before their first operation.
267
+
268
+ ```ts cordis-catalog
269
+ /**
270
+ * Return the shared live SDK handle.
271
+ * @returns the created sandbox after the configured cwd exists.
272
+ * @throws when E2B rejects creation or the service is disposing.
273
+ */
274
+ async getSandbox(): Promise<Sandbox>
275
+ ```
276
+
277
+ Source: [`packages/e2b/e2b/src/index.ts:74`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/e2b/e2b/src/index.ts)
278
+
279
+ <a id="ctxsubprocess--subprocessruntime-abstract-seam"></a>
280
+
281
+ ### `ctx.subprocess` — `SubprocessRuntime` (abstract seam)
282
+
283
+ Abstract subprocess service. Subclass, implement spawn, and load the subclass as a plugin — it registers as `ctx.subprocess` (one implementation per context; loading a second throws, which is cordis' standard duplicate-service behavior).
284
+
285
+ Implementations must honor these semantics:
286
+
287
+ - Executable paths belong to one execution world shared with the mounted filesystem provider.
288
+ - spawn returns immediately with a live handle; `done` resolves at process close with exit facts and rejects only for spawn-level failures.
289
+ - Collect-mode readers are offset-based and non-consuming, so independent readers never consume one another's output; lossy reads report truncation and the spill file holding the complete stream when one exists. Piped streams are handed to the caller raw and never buffered here.
290
+ - SubprocessHandle.terminate (and the spec's abort signal) escalates SIGTERM→grace→SIGKILL — the only termination verb — tree-scoped on every platform. SubprocessHandle.waitForExit observes whole-tree liveness, so a consumer-owned teardown ladder can hold each tier on real quiescence.
291
+ - Disposal of the service terminates all still-running managed processes and awaits their exit.
292
+ - spawnTerminal owns terminal allocation, text transport, foreground groups, signalling, and whole-session quiescence behind one awaited termination method; readiness and persistent-shell policy stay in the PTY consumer. Its output stream ends after queued terminal output when the top-level process exits.
293
+
294
+ ```ts cordis-catalog
295
+ /**
296
+ * Resolve one configured executable in this provider's execution world.
297
+ * Absolute paths are verified; bare names use the provider's scrubbed PATH
298
+ * plus explicit environment overrides. Relative paths containing separators
299
+ * are rejected: the resolution base is undefined, so providers fail loud
300
+ * instead of guessing.
301
+ * @param command - absolute executable path or bare PATH name.
302
+ * @param env - explicit environment entries used for lookup.
303
+ * @param signal - aborts remote or local lookup.
304
+ * @returns a canonical executable path.
305
+ */
306
+ abstract resolveExecutable( command: string, env?: Readonly<Record<string, string>>, signal?: AbortSignal, ): Promise<string>
307
+
308
+ /**
309
+ * Start one managed child process from a fully-specified spec; this seam
310
+ * applies no defaults.
311
+ * @param spec - argv, directory, stdio dispositions, grace, cancellation, and environment.
312
+ * @returns the live process handle (streams/readers, signalling, outcome promise).
313
+ */
314
+ abstract spawn(spec: SubprocessSpawnSpec): SubprocessHandle
315
+
316
+ /**
317
+ * Allocate a real terminal and start one owned process session. This is the
318
+ * only non-pipe process primitive: implementations own terminal byte I/O,
319
+ * foreground groups, signals, and complete session-tree cleanup.
320
+ * @param spec - fully specified argv, cwd, environment, dimensions, grace, and allocation cancellation.
321
+ * @returns the live terminal handle after allocation succeeds.
322
+ */
323
+ abstract spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle>
324
+ ```
325
+
326
+ Source: [`packages/subprocess/subprocess/src/index.ts:102`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subprocess/subprocess/src/index.ts)
327
+ <!-- END GENERATED cordis-surface -->
@@ -0,0 +1,210 @@
1
+ ---
2
+ editSource: "docs/subsystems/system-prompt.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # System Prompt Assembly
7
+
8
+ The [system-prompt package](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/system-prompt) owns the data exchanged between prompt contributors and one assembly call. The package [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/system-prompt/README.md) documents registration, ordering, scoping, and rendering behavior; this page records the exact cross-package types that plugins implement or pass.
9
+
10
+ Source: [`packages/core/system-prompt/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/system-prompt/src/index.ts).
11
+
12
+ ## Assembly context
13
+
14
+ `AssembleContext` identifies the scope layer one assembly resolves and may carry the explicit control signal for that request. It is merge-extensible: `dsh-agent` adds the optional live `agent` field, and `assembleContextFor(agent, signal)` sets the explicit fields together. A bare assembly has neither scope nor signal.
15
+
16
+ ```ts type-equiv
17
+ /** Merge-extensible context for one prompt assembly. */
18
+ interface AssembleContext {
19
+ /**
20
+ * Scope whose providers and waterfall listeners participate. When absent,
21
+ * only global providers and subject-less listeners participate.
22
+ */
23
+ scope?: ScopeKey
24
+ /** Explicit control signal for the turn that requested this assembly, when any. */
25
+ signal?: AbortSignal
26
+ }
27
+ ```
28
+
29
+ ## Tool-provider result
30
+
31
+ `ToolProviderResult.schemas` is the model-visible set for the current assembly. `knownNames` is the provider's pre-restriction name universe used to distinguish a configured-name typo from a known tool that is deliberately hidden in this scope.
32
+
33
+ ```ts type-equiv
34
+ /** Tool schemas visible in one assembly and their pre-restriction name set. */
35
+ interface ToolProviderResult {
36
+ /** The schemas this provider contributes to THIS assembly. */
37
+ readonly schemas: readonly ToolSchema[]
38
+ /** The pre-restriction name universe for config validation (defaults to `schemas`' names). */
39
+ readonly knownNames?: readonly string[]
40
+ }
41
+ ```
42
+
43
+ ## Prompt sections
44
+
45
+ `PromptSection` is a readonly same-process registration contract. Its text may be static or resolved from the current assembly context. One effective `complete` section becomes the sole prompt section after cooperative assembly.
46
+
47
+ ```ts type-equiv
48
+ /** One contributed section of the system prompt (registry input). */
49
+ interface PromptSection {
50
+ /** Unique name — a duplicate registration throws (see {@link SystemPrompt.section}). */
51
+ readonly name: string
52
+ /**
53
+ * Sections are concatenated in ascending order. Convention: `-100` is the
54
+ * harness identity, `0` the deployment persona, tool guidance uses 100–199;
55
+ * other negative orders also render before the persona.
56
+ */
57
+ readonly order: number
58
+ /**
59
+ * Static text or a provider evaluated at each assembly with that assembly's
60
+ * {@link AssembleContext}. The text may reference `{{variable}}`s — they are
61
+ * interpolated later, by {@link renderPrompt}.
62
+ */
63
+ readonly text: string | ((context: AssembleContext) => string)
64
+ /**
65
+ * Treat this contribution as the complete system prompt. Assembly still
66
+ * runs the cooperative waterfall so tools, contexts, and variables can be
67
+ * resolved, then restores this exact section as the sole prompt section.
68
+ * More than one effective complete section makes assembly fail.
69
+ */
70
+ readonly complete?: boolean
71
+ }
72
+ ```
73
+
74
+ ## Dynamic prompt context
75
+
76
+ `PromptContext` is the cache-safe counterpart to `PromptSection`. The assembly resolves and orders these contributions, while agent-loop logs their complete current snapshot after retained model history only when it changed or compaction removed it.
77
+
78
+ ```ts type-equiv
79
+ /** Dynamic model context materialized as a durable user-role snapshot. */
80
+ interface PromptContext {
81
+ /** Unique name — a duplicate registration throws (see {@link SystemPrompt.context}). */
82
+ readonly name: string
83
+ /** Contexts are joined in ascending order. */
84
+ readonly order: number
85
+ /** Static text or a provider evaluated for each assembly. Empty text contributes nothing. */
86
+ readonly text: string | ((context: AssembleContext) => string)
87
+ }
88
+ ```
89
+
90
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
91
+
92
+ <a id="cordis-surface"></a>
93
+
94
+ ## Cordis API
95
+
96
+ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
97
+
98
+ <a id="ctxsystemprompt--systemprompt"></a>
99
+
100
+ ### `ctx.systemPrompt` — `SystemPrompt`
101
+
102
+ Registry service for the prompt inputs assembled before each model step.
103
+
104
+ ```ts cordis-catalog
105
+ /**
106
+ * Register an ordered prompt section in the calling context's scope. A scoped
107
+ * section shadows a global section with the same name; duplicates within one
108
+ * layer and non-finite orders throw. Registration and disposal emit
109
+ * `system-prompt/change`.
110
+ * @param section - the section to register.
111
+ * @returns the exact Cordis effect disposer.
112
+ */
113
+ section(section: PromptSection): () => void
114
+
115
+ /**
116
+ * Register ordered dynamic context in the calling context's scope. Scoped
117
+ * entries shadow global entries with the same name.
118
+ * @param context - the context contribution to register.
119
+ * @returns the exact Cordis effect disposer.
120
+ */
121
+ context(context: PromptContext): () => void
122
+
123
+ /**
124
+ * Suppress every dynamic runtime-context contribution in the calling
125
+ * context's scope without changing the services that own or enforce those
126
+ * facts. Multiple suppressors remain independently disposable.
127
+ * @returns the exact Cordis effect disposer.
128
+ */
129
+ suppressRuntimeContext(): () => void
130
+
131
+ /**
132
+ * Register a tool-schema provider in the calling context's scope. Global and
133
+ * matching scoped providers both contribute; returning the reserved
134
+ * {@link TOOL_ORDER_REST} name makes assembly fail.
135
+ * @param provider - evaluated for each assembly with its context.
136
+ * @returns the exact Cordis effect disposer.
137
+ */
138
+ tools(provider: (context: AssembleContext) => ToolProviderResult): () => void
139
+
140
+ /**
141
+ * Register a prompt variable in the calling context's scope. Scoped values
142
+ * shadow globals; invalid or duplicate names throw. A provider may return
143
+ * `undefined`, but rendering a section that references that value then fails.
144
+ * @param name - the `[a-z][a-z0-9_]*` reference name.
145
+ * @param provider - evaluated for each assembly.
146
+ * @returns the exact Cordis effect disposer.
147
+ */
148
+ variable(name: string, provider: (context: AssembleContext) => string | undefined): () => void
149
+
150
+ /**
151
+ * Assemble global and scoped providers, detach tool parameters, apply
152
+ * canonical ordering, then run the assembly waterfall. Scoped sections and
153
+ * variables shadow globals. The returned waterfall value is authoritative
154
+ * except that an effective complete section is restored afterwards as the
155
+ * sole prompt section.
156
+ * @param context - the optional scope and plugin-defined assembly fields.
157
+ * @returns the post-waterfall assembly with any complete prompt enforced.
158
+ */
159
+ async assemble(context: AssembleContext = {}): Promise<PromptAssembly>
160
+ ```
161
+
162
+ Source: [`packages/core/system-prompt/src/index.ts:338`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/system-prompt/src/index.ts)
163
+
164
+ <a id="system-prompt-events"></a>
165
+
166
+ ### `system-prompt/*` events
167
+
168
+ <a id="system-promptassemble--waterfall"></a>
169
+
170
+ #### `system-prompt/assemble` — waterfall
171
+
172
+ Expert waterfall over the assembled sections, contexts, tools, and variables. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners receive only that scope's assemblies. The returned value is authoritative. A supplied signal controls only this explicit assembly request and must not be retained to control later turns. A registered complete section is restored after this waterfall, so listeners cannot add to or replace that scope's system prompt.
173
+
174
+ ```ts cordis-catalog
175
+ /**
176
+ * Expert waterfall over the assembled sections, contexts, tools, and variables.
177
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): scoped listeners
178
+ * receive only that scope's assemblies. The returned value is authoritative.
179
+ * A supplied signal controls only this explicit assembly request and must not
180
+ * be retained to control later turns. A registered complete section is
181
+ * restored after this waterfall, so listeners cannot add to or replace
182
+ * that scope's system prompt.
183
+ * @param assembly - the mutable assembly built from registered providers.
184
+ * @param context - the caller's per-assembly context.
185
+ * @mode waterfall
186
+ */
187
+ 'system-prompt/assemble'(this: Scoped<SystemPrompt>, assembly: PromptAssembly, context: AssembleContext, next: () => Promise<PromptAssembly>): Promise<PromptAssembly>
188
+ ```
189
+
190
+ Types: [Scoped](./scope.md)
191
+
192
+ Source: [`packages/core/system-prompt/src/index.ts:31`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/system-prompt/src/index.ts)
193
+
194
+ <a id="system-promptchange--emit"></a>
195
+
196
+ #### `system-prompt/change` — emit
197
+
198
+ Emitted when any prompt provider changes. This registry notification is unfiltered because a global change affects every scope.
199
+
200
+ ```ts cordis-catalog
201
+ /**
202
+ * Emitted when any prompt provider changes. This registry notification is
203
+ * unfiltered because a global change affects every scope.
204
+ * @mode emit
205
+ */
206
+ 'system-prompt/change'(): void
207
+ ```
208
+
209
+ Source: [`packages/core/system-prompt/src/index.ts:37`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/system-prompt/src/index.ts)
210
+ <!-- END GENERATED cordis-surface -->