dsh-plugin-dev-kb 1.0.9 → 1.3.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 (169) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.en.md +14 -8
  3. package/README.md +14 -8
  4. package/docs/banner.svg +25 -0
  5. package/kb/INDEX.md +8 -2
  6. package/kb/README.md +4 -4
  7. package/kb/extra/AGENTS.md +3 -3
  8. package/kb/extra/cookbook/adding-a-remote-api.md +197 -0
  9. package/kb/extra/cookbook/adding-a-remote-api.zh.md +197 -0
  10. package/kb/extra/cookbook/adding-a-session-format-version.md +109 -0
  11. package/kb/extra/cookbook/adding-a-session-format-version.zh.md +109 -0
  12. package/kb/extra/cookbook/adding-a-vendored-package.md +1 -1
  13. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +1 -1
  14. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +1 -1
  15. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +1 -1
  16. package/kb/extra/deepseek-llm-api-wire-extensions.md +19 -15
  17. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +19 -15
  18. package/kb/extra/development.md +13 -3
  19. package/kb/extra/development.zh.md +13 -3
  20. package/kb/extra/event-producer-consumer.md +49 -46
  21. package/kb/extra/event-producer-consumer.zh.md +52 -49
  22. package/kb/extra/i18n/README.md +2 -1
  23. package/kb/extra/i18n/README.zh.md +3 -2
  24. package/kb/extra/i18n/style-samples.md +2 -2
  25. package/kb/extra/i18n/translation-prompt.md +1 -1
  26. package/kb/extra/module-graph.md +493 -1002
  27. package/kb/extra/module-graph.zh.md +495 -1004
  28. package/kb/extra/rescope.md +1 -1
  29. package/kb/extra/rescope.zh.md +1 -1
  30. package/kb/extra/session-format-status.md +47 -0
  31. package/kb/extra/session-format-status.zh.md +47 -0
  32. package/kb/extra/subsystems/agent-team.md +3 -2
  33. package/kb/extra/subsystems/agent-team.zh.md +3 -2
  34. package/kb/extra/subsystems/attachment.md +157 -4
  35. package/kb/extra/subsystems/attachment.zh.md +157 -4
  36. package/kb/extra/subsystems/feedback.md +164 -30
  37. package/kb/extra/subsystems/feedback.zh.md +164 -30
  38. package/kb/extra/testing.md +9 -4
  39. package/kb/extra/testing.zh.md +9 -4
  40. package/kb/extra/web-styling.md +5 -0
  41. package/kb/extra/web-styling.zh.md +5 -0
  42. package/kb/meta/search-index.json +223 -151
  43. package/kb/meta/site-pages.txt +187 -181
  44. package/kb/meta/source.json +5 -5
  45. package/kb/meta/topics.md +5 -5
  46. package/kb/site/develop/basic/publish.md +1 -1
  47. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +3 -2
  48. package/kb/site/develop/practice/llm-adapter.md +4 -3
  49. package/kb/site/en/develop/basic/publish.md +1 -1
  50. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +3 -2
  51. package/kb/site/en/develop/practice/llm-adapter.md +4 -3
  52. package/kb/site/en/guide/network-proxy.md +87 -0
  53. package/kb/site/en/guide/providers.md +70 -17
  54. package/kb/site/en/guide/python-sdk.md +19 -3
  55. package/kb/site/en/guide/schedule.md +2 -0
  56. package/kb/site/en/reference/agent-lifecycle.md +17 -8
  57. package/kb/site/en/reference/api-gateway.md +2 -2
  58. package/kb/site/en/reference/capability-seams.md +24 -10
  59. package/kb/site/en/reference/config-catalog.md +322 -264
  60. package/kb/site/en/reference/cookbook/adding-a-package.md +1 -2
  61. package/kb/site/en/reference/cookbook/adding-a-settings-card.md +10 -8
  62. package/kb/site/en/reference/cookbook/adding-a-tool.md +1 -1
  63. package/kb/site/en/reference/cookbook/extension-cookbook.md +16 -13
  64. package/kb/site/en/reference/index.md +26 -9
  65. package/kb/site/en/reference/persistence-catalog.md +189 -95
  66. package/kb/site/en/reference/subsystems/approval.md +1 -1
  67. package/kb/site/en/reference/subsystems/client-modules.md +9 -0
  68. package/kb/site/en/reference/subsystems/client-resources.md +94 -0
  69. package/kb/site/en/reference/subsystems/code-runtime.md +7 -3
  70. package/kb/site/en/reference/subsystems/commands.md +25 -16
  71. package/kb/site/en/reference/subsystems/compaction.md +10 -10
  72. package/kb/site/en/reference/subsystems/conversation.md +11 -4
  73. package/kb/site/en/reference/subsystems/core.md +173 -29
  74. package/kb/site/en/reference/subsystems/credentials.md +5 -4
  75. package/kb/site/en/reference/subsystems/filesystem.md +15 -0
  76. package/kb/site/en/reference/subsystems/goal.md +38 -2
  77. package/kb/site/en/reference/subsystems/index.md +3 -1
  78. package/kb/site/en/reference/subsystems/invariants.md +1 -1
  79. package/kb/site/en/reference/subsystems/llm-streaming.md +43 -12
  80. package/kb/site/en/reference/subsystems/lsp.md +1 -1
  81. package/kb/site/en/reference/subsystems/permission-presets.md +5 -5
  82. package/kb/site/en/reference/subsystems/persistence.md +211 -199
  83. package/kb/site/en/reference/subsystems/plan.md +3 -3
  84. package/kb/site/en/reference/subsystems/sandbox.md +2 -0
  85. package/kb/site/en/reference/subsystems/schedule.md +9 -3
  86. package/kb/site/en/reference/subsystems/scope.md +1 -1
  87. package/kb/site/en/reference/subsystems/session-projection.md +50 -24
  88. package/kb/site/en/reference/subsystems/session-query.md +19 -13
  89. package/kb/site/en/reference/subsystems/session-reference.md +29 -1
  90. package/kb/site/en/reference/subsystems/session-telemetry.md +27 -10
  91. package/kb/site/en/reference/subsystems/session-title.md +6 -6
  92. package/kb/site/en/reference/subsystems/session.md +208 -103
  93. package/kb/site/en/reference/subsystems/settings.md +30 -12
  94. package/kb/site/en/reference/subsystems/shell.md +9 -6
  95. package/kb/site/en/reference/subsystems/sidebar-right.md +151 -0
  96. package/kb/site/en/reference/subsystems/skills.md +1 -1
  97. package/kb/site/en/reference/subsystems/slots.md +41 -32
  98. package/kb/site/en/reference/subsystems/spill.md +13 -6
  99. package/kb/site/en/reference/subsystems/storage.md +28 -5
  100. package/kb/site/en/reference/subsystems/subagent.md +58 -105
  101. package/kb/site/en/reference/subsystems/subprocess.md +25 -26
  102. package/kb/site/en/reference/subsystems/system-prompt.md +18 -3
  103. package/kb/site/en/reference/subsystems/token-meter.md +4 -3
  104. package/kb/site/en/reference/subsystems/tools.md +5 -5
  105. package/kb/site/en/reference/subsystems/typert.md +18 -18
  106. package/kb/site/en/reference/subsystems/web-client.md +1 -1
  107. package/kb/site/en/reference/subsystems/workspace.md +88 -9
  108. package/kb/site/en/reference/tool-catalog.md +56 -66
  109. package/kb/site/en/reference/tool-execution-pipeline.md +2 -2
  110. package/kb/site/guide/network-proxy.md +87 -0
  111. package/kb/site/guide/providers.md +70 -17
  112. package/kb/site/guide/python-sdk.md +19 -3
  113. package/kb/site/guide/schedule.md +2 -0
  114. package/kb/site/reference/agent-lifecycle.md +17 -8
  115. package/kb/site/reference/api-gateway.md +2 -2
  116. package/kb/site/reference/capability-seams.md +24 -10
  117. package/kb/site/reference/config-catalog.md +321 -263
  118. package/kb/site/reference/cookbook/adding-a-package.md +1 -2
  119. package/kb/site/reference/cookbook/adding-a-settings-card.md +10 -8
  120. package/kb/site/reference/cookbook/adding-a-tool.md +1 -1
  121. package/kb/site/reference/cookbook/extension-cookbook.md +16 -13
  122. package/kb/site/reference/index.md +26 -9
  123. package/kb/site/reference/persistence-catalog.md +190 -96
  124. package/kb/site/reference/subsystems/approval.md +1 -1
  125. package/kb/site/reference/subsystems/client-modules.md +9 -0
  126. package/kb/site/reference/subsystems/client-resources.md +94 -0
  127. package/kb/site/reference/subsystems/code-runtime.md +7 -3
  128. package/kb/site/reference/subsystems/commands.md +25 -16
  129. package/kb/site/reference/subsystems/compaction.md +10 -10
  130. package/kb/site/reference/subsystems/conversation.md +11 -4
  131. package/kb/site/reference/subsystems/core.md +173 -29
  132. package/kb/site/reference/subsystems/credentials.md +5 -4
  133. package/kb/site/reference/subsystems/filesystem.md +15 -0
  134. package/kb/site/reference/subsystems/goal.md +38 -2
  135. package/kb/site/reference/subsystems/index.md +14 -12
  136. package/kb/site/reference/subsystems/invariants.md +1 -1
  137. package/kb/site/reference/subsystems/llm-streaming.md +43 -12
  138. package/kb/site/reference/subsystems/lsp.md +1 -1
  139. package/kb/site/reference/subsystems/permission-presets.md +5 -5
  140. package/kb/site/reference/subsystems/persistence.md +210 -198
  141. package/kb/site/reference/subsystems/plan.md +3 -3
  142. package/kb/site/reference/subsystems/schedule.md +9 -3
  143. package/kb/site/reference/subsystems/scope.md +1 -1
  144. package/kb/site/reference/subsystems/session-projection.md +50 -24
  145. package/kb/site/reference/subsystems/session-query.md +19 -13
  146. package/kb/site/reference/subsystems/session-reference.md +29 -1
  147. package/kb/site/reference/subsystems/session-telemetry.md +27 -10
  148. package/kb/site/reference/subsystems/session-title.md +6 -6
  149. package/kb/site/reference/subsystems/session.md +208 -103
  150. package/kb/site/reference/subsystems/settings.md +30 -12
  151. package/kb/site/reference/subsystems/shell.md +9 -6
  152. package/kb/site/reference/subsystems/sidebar-right.md +151 -0
  153. package/kb/site/reference/subsystems/skills.md +1 -1
  154. package/kb/site/reference/subsystems/slots.md +41 -32
  155. package/kb/site/reference/subsystems/spill.md +13 -6
  156. package/kb/site/reference/subsystems/storage.md +28 -5
  157. package/kb/site/reference/subsystems/subagent.md +58 -105
  158. package/kb/site/reference/subsystems/subprocess.md +25 -26
  159. package/kb/site/reference/subsystems/system-prompt.md +18 -3
  160. package/kb/site/reference/subsystems/token-meter.md +4 -3
  161. package/kb/site/reference/subsystems/tools.md +5 -5
  162. package/kb/site/reference/subsystems/typert.md +18 -18
  163. package/kb/site/reference/subsystems/web-client.md +1 -1
  164. package/kb/site/reference/subsystems/workspace.md +88 -9
  165. package/kb/site/reference/tool-catalog.md +55 -65
  166. package/kb/site/reference/tool-execution-pipeline.md +2 -2
  167. package/lib/index.js +25 -44
  168. package/package.json +3 -2
  169. package/skills/dsh-plugin-dev-kb.md +4 -4
@@ -49,7 +49,7 @@ type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'
49
49
  type ApprovalPolicy = 'ask' | 'never'
50
50
  ```
51
51
 
52
- Both policies contribute their complete current meaning to the cache-safe runtime-context snapshot. The sourced `user/message` is the durable model-visible input; changing approval state appends a new full snapshot after retained history without rewriting the request header's system prompt.
52
+ Both policies contribute their complete current meaning to the cache-safe runtime-context snapshot. The sourced `user/message` is the durable model-visible input; changing approval state appends a new full snapshot after retained history without touching the `system/message` nodes that hold the rendered system prompt.
53
53
 
54
54
  ## Approval request
55
55
 
@@ -133,6 +133,15 @@ graph(): WebBootGraph
133
133
  */
134
134
  clientPath(id: string): string | undefined
135
135
 
136
+ /**
137
+ * Serve an advertised revisioned bundle or source map without a Web server.
138
+ * Unknown URLs return 404, unsupported methods return 405, and `HEAD`
139
+ * returns the same immutable headers without a body.
140
+ * @param request - shell-carrier request for a `/plugins` resource.
141
+ * @returns the exact response also exposed by the optional Web route.
142
+ */
143
+ fetchBundle(request: Request): Response
144
+
136
145
  /**
137
146
  * Filesystem baseline captured before an entry's current bytes were read.
138
147
  * HMR compares it with the live files when installing a watch, so a write
@@ -0,0 +1,94 @@
1
+ ---
2
+ editSource: "docs/subsystems/client-resources.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # Client Resources
7
+
8
+ The client resource model turns an address into live data for any Web Client component. [`dsh-client-resources`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/resources/README.md) provides the `ctx.resources` service and the `useResource` global standard hook; a package that owns a kind of content registers one **provider** for its **protocol**, and a component reads the content's current state by **address** without importing the owner's runtime. The right Sidebar's tabs are the model's first consumer ([Right Sidebar](./sidebar-right.md)); the decision record is the [client resource model Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-09-05-client-resource-model.md).
9
+
10
+ This page is the developer reference: how to write an address, how to register a provider, how to read a resource, what the states and failures mean, and how the model holds and releases a resource.
11
+
12
+ ## Addresses
13
+
14
+ A resource address is a `dsh-resource://<type>/…` URL. The host names the protocol and must be a key of `ResourceProtocolMap`; the path is the protocol's own, and its owner percent-encodes each segment. A protocol that needs a scope puts it in the path: the `file` protocol's addresses read `dsh-resource://file/session/<sessionId>/<path>`, where path is workspace-relative or absolute with its leading slashes preserved, built with `fileAddressFor(sessionId, cwd, path)` and read back with `parseFileAddress(address)` from [`dsh-util-workspace-path`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/util/workspace-path/README.md). The model itself reads only the scheme and the host: `protocolOf(address)` returns the lower-cased host of a `dsh-resource://` URL and `undefined` for anything else. Addresses under any other scheme — the Sidebar's `sidebar://guide` — name no resource and read as `none`.
15
+
16
+ | Address | Protocol key | Reads as |
17
+ |---|---|---|
18
+ | `dsh-resource://file/session/s1/notes/a.md` | `file` | the metadata of `notes/a.md` under session `s1`'s workspace root, when the `file` provider is registered |
19
+ | `dsh-resource://file/absolute/home/me/notes.md` | `file` | parseable but fails with `workspace-file/unknown-workspace`: no authorizing Session, and neither current nor Tab Session is borrowed |
20
+ | `DSH-RESOURCE://File/session/s1/a` | `file` | a distinct record: addresses compare as strings, and `openResource` accepts only the canonical lower-case spelling that `fileAddressFor` emits |
21
+ | `sidebar://guide` | — | `none`: a navigation address |
22
+ | `/home/me/notes.md` | — | `none`: not a URL |
23
+
24
+ ## Registering a provider
25
+
26
+ The owner of a protocol declares its value type on `ResourceProtocolMap` and registers one provider inside its own `ctx.effect`, so the protocol lives exactly as long as the plugin ([provide a protocol](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/resources/README.md#provide-a-protocol)). `open(address, { signal })` returns a stream of `RemoteResult` frames — the current state first, then one frame per change — and must stop when `signal` aborts. A failure is an `ok: false` frame carrying a `RemoteFailure`; a throw inside the stream is a programming error and is not caught.
27
+
28
+ ```ts ignore-check
29
+ import type { Context } from '@deepseek-ai/cordis'
30
+ import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'
31
+ import type {} from '@deepseek-ai/dsh-client-resources/client'
32
+
33
+ interface NoteView { readonly title: string; readonly updatedAt: string }
34
+
35
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
36
+ interface ResourceProtocolMap { note: NoteView }
37
+ }
38
+
39
+ export const inject = ['resources', 'remote']
40
+
41
+ export function apply(ctx: Context): void {
42
+ ctx.effect(() => ctx.resources.register<'note'>({
43
+ protocol: 'note',
44
+ async *open(address, { signal }): AsyncIterable<RemoteResult<NoteView>> {
45
+ const id = new URL(address).pathname.slice(1)
46
+ yield await ctx.remote.notes.read(id, signal)
47
+ for await (const change of ctx.remote.notes.follow(id, signal)) yield change
48
+ },
49
+ }), 'my-notes: note resource provider')
50
+ }
51
+ ```
52
+
53
+ A protocol has exactly one provider; a second registration throws. Registering while addresses of the protocol are already held opens their streams at once; disposing the provider ends those streams and the addresses read `none` until a provider returns.
54
+
55
+ ## Reading a resource
56
+
57
+ Every slot component receives `useResource` in its props, whatever its scope ([Slots](./slots.md)). `useResource<P>(address)` names the protocol as the type argument and returns the address's current snapshot; subscribing is what holds the resource open, and a component that mounts while another holder keeps the resource alive reads the latest value at once without reopening the stream ([read a resource](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/resources/README.md#read-a-resource)).
58
+
59
+ | `status` | Meaning | `value` | `failure` |
60
+ |---|---|---|---|
61
+ | `none` | No provider is registered for the address's protocol, or the address is not a resource address | `undefined` | `undefined` |
62
+ | `loading` | The provider's stream is open and has not yielded yet | `undefined` | `undefined` |
63
+ | `live` | The latest frame succeeded | the latest `ok` value | `undefined` |
64
+ | `failed` | The latest frame reported a failure | the last `ok` value, kept | the frame's `RemoteFailure` |
65
+
66
+ ```tsx ignore-check
67
+ import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
68
+ import type {} from '@deepseek-ai/dsh-api-workspace-files/client'
69
+
70
+ type Props = PropsRuntime<'sidebar.right.pane.tab'>
71
+
72
+ export function FileHeader({ useTabInfo, useResource, t }: Props) {
73
+ const { tab } = useTabInfo()
74
+ const meta = useResource<'file'>(tab.contentId)
75
+ if (meta.status === 'failed') return <p role="alert">{t('failed', { code: meta.failure.code })}</p>
76
+ return (
77
+ <header>
78
+ {tab.title}
79
+ </header>
80
+ )
81
+ }
82
+ ```
83
+
84
+ A consumer presents `failed` itself: the model keeps the last value beside the failure so a body can show stale content with a notice rather than a blank, and the next `ok` frame clears the failure. Nothing in the model produces user-visible text.
85
+
86
+ ## Holding and releasing
87
+
88
+ A resource is alive while it has a holder: a subscribed `useResource`, or a pin. `ctx.resources.pin(address, signal)` keeps a resource open without subscribing until `signal` aborts, and an already-aborted signal pins nothing; the right Sidebar pins every open tab record's address for the record's life, so switching tabs unmounts a body without closing its stream. The first holder opens the provider's stream; the last release aborts it, discards the value, and returns the snapshot to `loading` (provider present) or `none` (absent). A frame the provider yields after that release is dropped, and the iterator is returned. `ctx.resources.source(address)` is the bare observable behind the hook, reference-stable per address, for callers outside React; reading its snapshot does not hold the resource ([lifecycle](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/resources/README.md#lifecycle)).
89
+
90
+ Streams carry metadata, not content. The `file` provider's value is `WorkspaceFileStat { absolutePath, version, bytes? }`: the first frame comes from Host `stat`, and later observations update the version. A consumer reads content through the Workspace Files Remote namespace; Preview owns refresh independently per tab ([`dsh-api-workspace-files`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/workspace-files/README.md)).
91
+
92
+ ## Limits
93
+
94
+ Records live for the page lifetime: an address's record stays after its last holder leaves, holding no stream and no value, so memory grows with the number of distinct addresses ever read. A provider that ignores `signal` keeps running until its next frame. The failure type is the Remote face's `RemoteFailure`, so a provider whose source is not a Remote call mints one. A misspelled protocol or a malformed address reads as `none` with no other diagnostic.
@@ -55,7 +55,11 @@ interface CodeRunResult {
55
55
  * rendered string; a failed or value-less run leaves this absent.
56
56
  */
57
57
  value?: CodeJsonValue
58
- /** Text the program emitted, in order, bounded only as part of the outer result. */
58
+ /**
59
+ * Captured text. Each source channel preserves emission order; interleaving
60
+ * across independent channels is backend-dependent. Bounded only as part of
61
+ * the outer result.
62
+ */
59
63
  logs: string[]
60
64
  /** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */
61
65
  error?: CodeRunFailure
@@ -134,7 +138,7 @@ type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue>
134
138
 
135
139
  ## Captured output and the failure taxonomy
136
140
 
137
- Logs are plain strings in emission order. The runtime captures the program's console and stream output, but channel and console-method metadata are not part of the seam because consumers render only the text. Implementations cap the serialized outer log-array plus completion-value or failure-message payload; fixed result-envelope syntax and consumer presentation whitespace are not part of that variable-payload ledger. Overflow is an explicit failure rather than in-band value substitution.
141
+ Logs are plain strings. Each source channel preserves emission order, while interleaving across independent channels is backend-dependent because channel metadata is not part of the seam. The runtime captures the program's console and stream output, and consumers render only the text. Implementations cap the serialized outer log-array plus completion-value or failure-message payload; fixed result-envelope syntax and consumer presentation whitespace are not part of that variable-payload ledger. Overflow is an explicit failure rather than in-band value substitution.
138
142
 
139
143
  Failure kinds are **orthogonal outcomes reported independently** (per [defensive-patterns](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/defensive-patterns.md)): a budget expiry is not an exception, an abort is not a timeout, and a substrate death (e.g. OOM) is neither:
140
144
 
@@ -161,7 +165,7 @@ interface CodeRunFailure {
161
165
 
162
166
  ## The service
163
167
 
164
- `CodeRuntime` (`ctx.codeRuntime`, abstract — defined in [`packages/code-runtime/code-runtime/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/index.ts)) is `run(request)` plus two readonly descriptors: `language` (what the program must be written in — `'typescript'` and `'python'` are the well-known values, those `dsh-tools` presents, and only `'typescript'` has a published backend; a consumer generating language-specific presentation switches on it and fails loud on one it cannot present) and `isolation` (the execution substrate — `'worker-thread'`, `'process'`, `'container'`; a diagnostic label, **not a security claim**). Implementations must keep runs isolated from each other (no cross-run state) and dispose to quiescence: in-flight runs are terminated and awaited before teardown completes.
168
+ `CodeRuntime` (`ctx.codeRuntime`, abstract — defined in [`packages/code-runtime/code-runtime/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/index.ts)) is `run(request)` plus two readonly descriptors: `language` (what the program must be written in — `'typescript'` and `'python'` are the well-known values, those `dsh-tools` presents, the TypeScript backend released and the Python backend experimental and private (not published); a consumer generating language-specific presentation switches on it and fails loud on one it cannot present) and `isolation` (the execution substrate — `'worker-thread'`, `'process'`, `'container'`; a diagnostic label, **not a security claim**). Implementations must keep runs isolated from each other (no cross-run state) and dispose to quiescence: in-flight runs are terminated and awaited before teardown completes.
165
169
 
166
170
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
167
171
 
@@ -11,7 +11,7 @@ Source: [`packages/interaction/commands/src/index.ts`](https://github.com/deepse
11
11
 
12
12
  ## Input metadata
13
13
 
14
- The service exposes one optional unstructured-input descriptor: a hint plus an image-acceptance flag. Command availability follows plugin composition: every adapter consuming the registry sees every effective definition.
14
+ The service exposes one optional unstructured-input descriptor: a hint plus an attachment-acceptance flag. Command availability follows plugin composition: every adapter consuming the registry sees every effective definition.
15
15
 
16
16
  ```ts type-equiv
17
17
  /** Immutable metadata for a command's optional unstructured input. */
@@ -19,13 +19,13 @@ interface CommandInputDescriptor {
19
19
  /** Placeholder shown before the user supplies free-form input. */
20
20
  readonly hint: string
21
21
  /**
22
- * Whether composer image attachments may accompany an invocation. Absent or
23
- * false = the executor rejects an invocation carrying images and capable
22
+ * Whether composer attachments may accompany an invocation. Absent or
23
+ * false = the executor rejects an invocation carrying attachments and capable
24
24
  * composers refuse the submission before dispatch. A declaring command's
25
25
  * handler receives the admitted durable blocks and owns every further
26
26
  * grammar decision, including rejecting sub-commands that cannot use them.
27
27
  */
28
- readonly images?: boolean
28
+ readonly attachments?: boolean
29
29
  }
30
30
  ```
31
31
 
@@ -67,13 +67,13 @@ interface CommandInvocation {
67
67
  /** Exact text following the registered command name, including separator whitespace. */
68
68
  readonly rawInput: string
69
69
  /**
70
- * Durably admitted image blocks accompanying this invocation, in submission
71
- * order; empty unless the definition declares `input.images`. The handler
70
+ * Durably admitted image and file blocks accompanying this invocation, in submission
71
+ * order; empty unless the definition declares `input.attachments`. The handler
72
72
  * owns their model-visible use — the registry never schedules them itself —
73
73
  * and a handler whose grammar cannot use them in this invocation returns an
74
74
  * error so the dispatching composer retains the originals.
75
75
  */
76
- readonly attachments: readonly ImageBlock[]
76
+ readonly attachments: readonly (ImageBlock | FileBlock)[]
77
77
  /** Cancellation signal owned by the dispatching UI request. */
78
78
  readonly signal: AbortSignal
79
79
  }
@@ -86,7 +86,7 @@ type CommandResult =
86
86
  readonly kind: 'success'
87
87
  readonly text?: string
88
88
  /** Earlier authoritative domain event that owns a richer presentation. */
89
- readonly sourceEventSeq?: number
89
+ readonly sourceEventSeq?: SessionSeq
90
90
  }
91
91
  | { readonly kind: 'error'; readonly text: string }
92
92
  ```
@@ -141,6 +141,13 @@ Human-command registry. Plain-context definitions are global; definitions regist
141
141
  */
142
142
  register(definition: CommandDefinition): () => void
143
143
 
144
+ /**
145
+ * Register the sole authority that resolves staged file receipts for command submissions.
146
+ * @param resolver - Session-aware receipt resolver.
147
+ * @returns disposer that removes this exact resolver.
148
+ */
149
+ registerFileReceiptResolver(resolver: CommandFileReceiptResolver): () => void
150
+
144
151
  /**
145
152
  * List the effective immutable command descriptors for one agent.
146
153
  * @param agent - exact receiving agent and scoped-layer key.
@@ -169,23 +176,25 @@ find(agent: Agent, name: string): CommandDefinition | undefined
169
176
  * handler-failure path is contained so the handler's own error stays the
170
177
  * reported failure.
171
178
  *
172
- * Image admission is enforced here, not in the composer: images sent to a
173
- * command that does not declare `input.images`, an absent attachment store,
174
- * and an exceeded attachment limit each settle as an error result before
175
- * the handler runs, and a rejected batch publishes no durable object.
179
+ * Attachment admission is enforced here, not in the composer: attachments sent to a
180
+ * command that does not declare `input.attachments`, an absent attachment store,
181
+ * and an exceeded image limit each settle as an error result before
182
+ * the handler runs. Validation rejection starts no attachment writes;
183
+ * a storage failure can leave only unreachable content-addressed objects
184
+ * for deferred collection.
176
185
  *
177
186
  * @param agent - exact receiving agent.
178
187
  * @param line - complete slash-command line.
179
- * @param images - base64-encoded composer images accompanying the line, in
180
- * submission order; empty for a plain invocation.
188
+ * @param submittedAttachments - encoded images and staged file receipts accompanying the line,
189
+ * in submission order; empty for a plain invocation.
181
190
  * @param signal - cancellation signal owned by the UI request.
182
191
  * @returns the settled execution (result + lifecycle pairing id), or
183
192
  * `undefined` when syntax or name does not resolve.
184
193
  */
185
- @Remote async execute( agent: Agent, line: string, images: readonly EncodedImageAttachment[], signal: AbortSignal, ): Promise<CommandExecution | undefined>
194
+ @Remote async execute( agent: Agent, line: string, submittedAttachments: readonly CommandSubmitAttachment[], signal: AbortSignal, ): Promise<CommandExecution | undefined>
186
195
  ```
187
196
 
188
- Types: [Agent](./core.md) · [EncodedImageAttachment](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/attachment.md)
197
+ Types: [Agent](./core.md)
189
198
 
190
199
  Source: [`packages/interaction/commands/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/index.ts)
191
200
 
@@ -11,7 +11,7 @@ Source: [`packages/compaction/compaction/src/types.ts`](https://github.com/deeps
11
11
 
12
12
  ## The `compaction/*` session events
13
13
 
14
- Compaction extends [`SessionEventMap`](./session.md) with three event types via declaration merging. All three are **log-only** — they record the lock, summary, selected range, shadowed event seqs, token count, and model call without joining the surface. `SurfaceEventType` is deliberately NOT extended (only message-producing events reach the model), so the summary itself rides on a separate `user/message` with `surfaceOp: { op: 'replace', start, end }` — the only surface mutation performed by summary compaction. The [Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md) owns the rationale for reusing `user/message`.
14
+ Compaction extends [`SessionEventMap`](./session.md) with three event types via declaration merging. All three are **log-only** — they record the lock, summary, selected range, shadowed event seqs, token count, and model call without joining the surface. `SurfaceEventType` is deliberately NOT extended (only message-producing events reach the model), so the summary itself rides on a separate `user/message` with `surfaceOp: { op: 'replace', startSeq, endSeq }` — the only surface mutation performed by summary compaction. The [Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-18-compaction-capability-seam.md) owns the rationale for reusing `user/message`.
15
15
 
16
16
  | Event | Payload | Role |
17
17
  |---|---|---|
@@ -37,11 +37,11 @@ interface CompactionResult {
37
37
  /** Human command that initiated this compaction, when it was manual. */
38
38
  sourceCommandId?: CommandId
39
39
  /** The seq of the appended `compaction/start` event. */
40
- startSeq: number
40
+ startSeq: SessionSeq
41
41
  /** The seq of the appended `compaction/summary` event. */
42
- summarySeq: number
42
+ summarySeq: SessionSeq
43
43
  /** The seq of the appended `compaction/end` event. */
44
- endSeq: number
44
+ endSeq: SessionSeq
45
45
  /** The summary content blocks produced by the backend. */
46
46
  summary: ContentBlock[]
47
47
  /**
@@ -52,9 +52,9 @@ interface CompactionResult {
52
52
  * can be GREATER than `end`. {@link CompactionResult.shadowedSeqs} is the
53
53
  * authoritative set of shadowed nodes, in surface order.
54
54
  */
55
- shadowedRange: { start: number; end: number }
55
+ shadowedRange: { start: SessionSeq; end: SessionSeq }
56
56
  /** The seqs of all shadowed surface nodes, in surface order. */
57
- shadowedSeqs: number[]
57
+ shadowedSeqs: SessionSeq[]
58
58
  /** Estimated token count of the shadowed content. */
59
59
  shadowedTokenCount: number
60
60
  }
@@ -98,9 +98,9 @@ The optional tool-result pruning service reports each durable content replacemen
98
98
  /** Cited source event and size accounting for one landed surface replacement. */
99
99
  interface PrunedEntry {
100
100
  /** Full-fidelity tool-result event shadowed by the replacement. */
101
- readonly originalSeq: number
101
+ readonly originalSeq: SessionSeq
102
102
  /** Newly appended pruned tool-result event. */
103
- readonly replacementSeq: number
103
+ readonly replacementSeq: SessionSeq
104
104
  /** Tool call shared by the original and replacement. */
105
105
  readonly callId: ToolCallId
106
106
  /** Original text size in Unicode code points. */
@@ -190,10 +190,10 @@ abstract compactNow( agent: ManualCompactAgentContext, signal: AbortSignal, sour
190
190
  * @throws when compaction is active or the range is missing, reversed, or unbalanced.
191
191
  * @returns the appended event seqs, summary, replaced range, and token accounting.
192
192
  */
193
- abstract compactRegion( start: number, end: number, agent: CompactionAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>
193
+ abstract compactRegion( start: SessionSeq, end: SessionSeq, agent: CompactionAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>
194
194
  ```
195
195
 
196
- Types: [CommandId](./commands.md)
196
+ Types: [CommandId](./commands.md) · [SessionSeq](./session.md)
197
197
 
198
198
  Source: [`packages/compaction/compaction/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/compaction/compaction/src/index.ts)
199
199
 
@@ -11,18 +11,24 @@ This page defines the data model and the extension path for a business-owned Con
11
11
 
12
12
  ## Data model and ownership
13
13
 
14
- The Session Controller owns the contiguous loaded logical-event window. Each `SessionEventLikeEntry` is either `{ type: 'event', event: SessionEvent }` or `{ type: 'chunks', event: ChunkRowEvent }`; both inner events expose `type`, `seq`, `time`, and `data`. `ui-conversation` passes these entries to the assembler without opening a second history stream, converting records, or expanding packed members. One `ConversationNodeAssembler` per Session applies every registered Definition and publishes an independent source for each registered view target.
14
+ The Session Controller owns the contiguous loaded logical-event window. Each `SessionEventLikeEntry` is either `{ type: 'event', event: SessionEvent }` for one durable event or `{ type: 'transient', event: AssistantLiveChunkEvent }` for one Client-only `assistant/live-chunk` presentation. Both inner events expose `type`, `seq`, `time`, and `data`. `ui-conversation` passes these entries to the assembler without opening a second history stream. One `ConversationNodeAssembler` per Session applies every registered Definition and publishes an independent source for each registered view target.
15
15
 
16
16
  | Concept | Owner and purpose |
17
17
  |---|---|
18
- | Event Definition | A business package matches one standard event or packed Assistant run at a time, correlates it by stable `(kind, id)`, folds deterministic State, and optionally materializes one target node. |
19
- | Context | The engine-owned ordered Matches and current State for one `(kind, id)`. A packed run occupies one update Match; update-only evidence may remain pending until pagination supplies its unique scalar start. |
18
+ | Event Definition | A business package matches one durable or Client-only transient event at a time, correlates it by stable `(kind, id)`, folds deterministic State, and optionally materializes one target node. |
19
+ | Context | The engine-owned ordered Matches and current State for one `(kind, id)`. A transient event occupies one update Match; update-only evidence may remain pending until pagination supplies its unique durable start. |
20
20
  | Location | The engine-owned Session, Turn, or Step coordinates derived from durable boundary events. Definitions may publish typed data onto one Turn or Step. |
21
21
  | View Definition | A target package creates one incremental builder per Session and owns the final snapshot type for that target. |
22
22
  | View | A Slot entry such as Chat or Trajectory reads only its target snapshot and renders target-owned nodes. |
23
23
 
24
24
  Chat and Trajectory may recognize the same durable event family, but each keeps its own Definition State and final node payload. Shared target-neutral machinery is limited to identity routing, ordered replay, Location data, predecessor dependencies, and publication cadence.
25
25
 
26
+ ## Target activation
27
+
28
+ Each Session keeps a monotonic set of active targets. Creating or reading a target source does not activate it. The shell explicitly activates its persisted or newly selected View, while another consumer activates a target through its first source subscription. First activation creates that target's builder and calls `replace()` once from the current target-indexed Contexts. Later flushes call `apply()` for every active target, and unsubscription does not remove one.
29
+
30
+ The shell owns View selection and resolves the registered preferred View or Chat fallback before rendering when a binding is created or selected as current, and after View-roster changes. The assembler receives only the resolved target id and does not select Chat or another default target. A third-party View participates through the same selection and activation operations.
31
+
26
32
  ## Replayable event families
27
33
 
28
34
  Choose one stable business id before writing the Definition. Every event that contributes to the same Node must carry that id or derive it independently from its own payload; the client must never assign an update to “the latest unfinished” Context.
@@ -39,7 +45,7 @@ Use the producer-owned branded id type across the process boundary. Put the `Ses
39
45
 
40
46
  Incremental events are supported. Prefer whole-value checkpoints when the producer can emit them cheaply, because they remain useful when the start is outside the loaded window. Each delta must carry the stable id and produce deterministic State when replayed in ascending log `seq`; it must not depend on live-only memory. If the current history window contains only updates, the assembler keeps a pending Context and builds no State until an older page supplies the start. If the product must render before the start is loaded, a terminal or checkpoint event must carry enough whole fallback state for the Definition to build that result directly; do not recover it by scanning unrelated events.
41
47
 
42
- Historical runs of consecutive same-block `assistant/chunk` deltas arrive as `chunkrow/text-chunks`, `chunkrow/reasoning-chunks`, or `chunkrow/tool-call-chunks`. Their top-level `seq` and `time` identify the first logical member, and their `data` retains each fragment and timestamp gap. These Client-only events can only be updates; `start()` receives a standard `SessionEvent`. A Definition that consumes Assistant deltas handles the relevant packed tags in the same `match()` and `update()` methods, while other Definitions return `null` without expanding the run.
48
+ Live Assistant deltas arrive as Client-only `assistant/live-chunk` updates. Reconnect baselines expand the active process-local compact stream into the same transient events, while durable `assistant/message` and `assistant/attempt` events embed complete compact streams for history replay. Transient events can only be updates; `start()` receives a standard `SessionEvent`. A Definition that consumes Assistant output handles live chunks and durable settlements in the same `match()` and `update()` methods, while unrelated Definitions return `null` without expanding a stream.
43
49
 
44
50
  ## Definition and typed Chat payload
45
51
 
@@ -250,5 +256,6 @@ Add focused tests that establish these outcomes:
250
256
  5. Repeated visible deltas preserve `context.key` and publish at most once per animation frame when requested.
251
257
  6. The keyed renderer consumes `node.data` and constrained Location hooks only; it does not scan the Session event window, Contexts, or Chat Nodes.
252
258
  7. Scalar and packed Assistant history produce the same final State, timing boundaries, and target snapshot, while one packed run remains one Match through replace, prepend, Location replay, and registry rebuild.
259
+ 8. Creating a target source performs no builder work; explicit selection or the first subscription performs one complete replacement, later updates reach every active target, and repeated activation performs no replacement.
253
260
 
254
261
  Use [`packages/client/ui-chat/src/client/conversation-nodes/assistant.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/src/client/conversation-nodes/assistant.ts) for streaming and interruption, [`inbox.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/src/client/conversation-nodes/inbox.ts) plus [`message.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/src/client/conversation-nodes/message.ts) for predecessor queries, and [`packages/client/ui-deliverables`](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-deliverables) for a Definition that publishes Turn data without creating its own Node.