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,205 @@
1
+ ---
2
+ editSource: "docs/subsystems/lsp.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # LSP navigation
7
+
8
+ The LSP seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-15-lsp-capability-seam.md) exposing semantic code navigation on one `ctx.lsp` service, split across packages: Service Definition ([dsh-lsp](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/lsp/lsp), `ctx.lsp` + the provider registry), a generic Service Provider ([dsh-lsp-stdio](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/lsp/lsp-stdio), a configured stdio language-server host), and Consumer ([dsh-tool-lsp](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/lsp/tool-lsp), the `lsp` tool schema). LSP is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](./core.md). A provider swap does not change how the model asks for navigation.
9
+
10
+ Source: [`packages/lsp/lsp/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/lsp/lsp/src/types.ts)
11
+
12
+ ## Operations and coordinates
13
+
14
+ The seam and model expose exactly four semantic queries; the union is closed, so adding one is a compile-enforced change across the seam, providers, and the tool. Positions and ranges are zero-based UTF-16, matching the protocol; the model-facing tool owns the one-based cursor convention and converts on the way in and out.
15
+
16
+ ```ts type-equiv
17
+ /**
18
+ * The four semantic queries the seam and model expose. A closed union: adding an operation is a
19
+ * compile-enforced change across the seam, providers, and the tool. Symbols and call hierarchy are
20
+ * not operations here; they need different schemas.
21
+ */
22
+ type LspOperation = 'goToDefinition' | 'findReferences' | 'goToImplementation' | 'hover'
23
+ ```
24
+
25
+ ```ts type-equiv
26
+ /** A zero-based UTF-16 cursor coordinate, matching the LSP wire convention. */
27
+ interface LspPosition {
28
+ /** Zero-based line. */
29
+ readonly line: number
30
+ /** Zero-based UTF-16 code-unit offset within the line. */
31
+ readonly character: number
32
+ }
33
+ ```
34
+
35
+ ```ts type-equiv
36
+ /** A zero-based UTF-16 half-open range `[start, end)`. */
37
+ interface LspRange {
38
+ readonly start: LspPosition
39
+ readonly end: LspPosition
40
+ }
41
+ ```
42
+
43
+ ## Request
44
+
45
+ Every field is required: `workspaceRoot` is caller-supplied, `languageId` comes from the provider's registration (not the request), and consumers own timeouts and result limits — so no field needs implementation defaulting and there is no `resolve()` step. The provider receives the caller's request plus the derived `languageId`, which only synchronizes the transient document and never participates in selection.
46
+
47
+ ```ts type-equiv
48
+ /**
49
+ * A caller's normalized query. Every field is required: `workspaceRoot` is caller-supplied,
50
+ * `languageId` comes from the provider registration (not here), and consumers own timeouts and
51
+ * result limits — so no field needs implementation defaulting and there is no `resolve()` step.
52
+ */
53
+ interface LspQueryRequest {
54
+ /** Which semantic query to run. */
55
+ readonly operation: LspOperation
56
+ /** The source file to query (relative to `workspaceRoot` or absolute; the provider canonicalizes). */
57
+ readonly filePath: string
58
+ /** The zero-based UTF-16 cursor position to query at. */
59
+ readonly position: LspPosition
60
+ /** The workspace root the provider resolves against and indexes; required, never defaulted. */
61
+ readonly workspaceRoot: string
62
+ }
63
+ ```
64
+
65
+ ```ts type-equiv
66
+ /**
67
+ * A request as a provider receives it: the caller's {@link LspQueryRequest} plus the `languageId`
68
+ * the seam derived from the provider's extension mapping. The language id only synchronizes the
69
+ * transient document; it does not participate in selection.
70
+ */
71
+ interface LspProviderQuery extends LspQueryRequest {
72
+ /** The LSP language id for `filePath`, from this provider's extension mapping. */
73
+ readonly languageId: string
74
+ }
75
+ ```
76
+
77
+ ## Result
78
+
79
+ A CLOSED discriminated union: navigation operations normalize to `locations`, `hover` to content or `null`. Consumers `switch` on `kind` to exhaustiveness so a new arm breaks compilation until handled. `findReferences` always includes declarations — the provider enforces this internally, so callers get no flag. The `locations` variant carries `resolvedWorkspaceUri`, the provider's canonical workspace `file:` URI. A caller relativizing location URIs uses that coordinate rather than applying host-platform path rules to the possibly-symlinked request root.
80
+
81
+ ```ts type-equiv
82
+ /** One resolved location: a document URI and the range within it. */
83
+ interface LspLocation {
84
+ /** The target document URI (`file:` or otherwise), verbatim from the server. */
85
+ readonly uri: string
86
+ /** The range within the target document. */
87
+ readonly range: LspRange
88
+ }
89
+ ```
90
+
91
+ ```ts type-equiv
92
+ /** Normalized hover content, or `null` for no hover at the position. */
93
+ interface LspHover {
94
+ /** The normalized hover text (markdown or plaintext, provider-joined). */
95
+ readonly contents: string
96
+ /** The range the hover applies to, when the server supplied one. */
97
+ readonly range?: LspRange
98
+ }
99
+ ```
100
+
101
+ ```ts type-equiv
102
+ /**
103
+ * The closed result union. Navigation operations (`goToDefinition`, `findReferences`,
104
+ * `goToImplementation`) normalize to `locations`; `hover` normalizes to content or `null`.
105
+ * Consumers `switch` on `kind` to exhaustiveness so a new arm breaks compilation until handled.
106
+ *
107
+ * The `locations` variant carries `resolvedWorkspaceUri`: the provider's canonical `file:` URI for
108
+ * the request's workspace root. A caller that relativizes location URIs MUST use this, not parse the
109
+ * request's possibly symlinked process path with host-platform rules; the execution platform may
110
+ * differ from the caller's.
111
+ */
112
+ type LspQueryResult =
113
+ | { readonly kind: 'locations'; readonly locations: readonly LspLocation[]; readonly resolvedWorkspaceUri: string }
114
+ | { readonly kind: 'hover'; readonly hover: LspHover | null }
115
+ ```
116
+
117
+ ## Provider and service
118
+
119
+ A provider owns a stable branded `id` and an exclusive lowercase leading-dot extension map. `registerProvider` reserves the id and every extension atomically — an invalid or conflicting registration publishes nothing — and its disposer releases all reservations. Selection is per query and order-independent; no match throws `LspError` `LSP_UNAVAILABLE`. The seam exposes no protocol types, process/document controls, or generic JSON-RPC escape hatch.
120
+
121
+ ```ts type-equiv
122
+ /**
123
+ * A language-server backend registered on `ctx.lsp`. Each provider owns a stable {@link
124
+ * LspProviderId} and an extension-to-language-id map (lowercase, leading-dot keys).
125
+ * `findReferences` always includes declarations — the provider enforces this internally; callers
126
+ * get no flag.
127
+ */
128
+ interface LspProvider {
129
+ /** Stable provider identity, reserved atomically with the extension mappings. */
130
+ readonly id: LspProviderId
131
+ /** Lowercase leading-dot extension → LSP language id (e.g. `{ '.ts': 'typescript' }`). */
132
+ readonly extensionToLanguage: Readonly<Record<string, string>>
133
+ /**
134
+ * Run one query. The seam has already selected this provider and derived `languageId`.
135
+ * @param request - the resolved provider query (caller request + derived language id).
136
+ * @param signal - optional cancellation; the provider stops its own work when it aborts.
137
+ * @returns the normalized, closed-union result.
138
+ */
139
+ query(request: LspProviderQuery, signal?: AbortSignal): Promise<LspQueryResult>
140
+ }
141
+ ```
142
+
143
+ ```ts type-equiv
144
+ /**
145
+ * The LSP capability seam (`ctx.lsp`). Owns provider registration/selection and normalized query
146
+ * execution; exposes exactly the four operations and no protocol escape hatch.
147
+ */
148
+ interface LspService {
149
+ /**
150
+ * Register a provider, atomically reserving its id and every normalized extension. Any conflict
151
+ * or invalid input publishes nothing and throws `LspError`; the returned disposer releases all
152
+ * reservations. Disposed with the calling fiber.
153
+ * @param provider - the backend to register.
154
+ * @returns a synchronous disposer releasing the id and all extension reservations.
155
+ */
156
+ registerProvider(provider: LspProvider): () => void
157
+ /**
158
+ * Select a provider by the file's extension and run one query. Selection is per-query and
159
+ * order-independent; no match throws `LspError` `LSP_UNAVAILABLE`.
160
+ * @param request - the normalized query.
161
+ * @param signal - optional cancellation forwarded to the selected provider.
162
+ * @returns the normalized, closed-union result.
163
+ */
164
+ query(request: LspQueryRequest, signal?: AbortSignal): Promise<LspQueryResult>
165
+ }
166
+ ```
167
+
168
+ `LspProviderId` is the seam's branded id (`Branded<'LspProviderId'>` from [dsh-brand](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/util/brand)); `LspError` extends `HarnessError` with stable codes such as `LSP_INVALID_PROVIDER`, `LSP_CONFLICT`, `LSP_UNAVAILABLE`, `LSP_DISPOSED`, `LSP_UNSUPPORTED_OPERATION`, and `LSP_MALFORMED_RESPONSE`, which callers route on instead of parsing `message`.
169
+
170
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
171
+
172
+ <a id="cordis-surface"></a>
173
+
174
+ ## Cordis API
175
+
176
+ 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).
177
+
178
+ <a id="ctxlsp--lspservice"></a>
179
+
180
+ ### `ctx.lsp` — `LspService`
181
+
182
+ The LSP capability seam (`ctx.lsp`). Owns provider registration/selection and normalized query execution; exposes exactly the four operations and no protocol escape hatch.
183
+
184
+ ```ts cordis-catalog
185
+ /**
186
+ * Register a provider, atomically reserving its id and every normalized extension. Any conflict
187
+ * or invalid input publishes nothing and throws `LspError`; the returned disposer releases all
188
+ * reservations. Disposed with the calling fiber.
189
+ * @param provider - the backend to register.
190
+ * @returns a synchronous disposer releasing the id and all extension reservations.
191
+ */
192
+ registerProvider(provider: LspProvider): () => void
193
+
194
+ /**
195
+ * Select a provider by the file's extension and run one query. Selection is per-query and
196
+ * order-independent; no match throws `LspError` `LSP_UNAVAILABLE`.
197
+ * @param request - the normalized query.
198
+ * @param signal - optional cancellation forwarded to the selected provider.
199
+ * @returns the normalized, closed-union result.
200
+ */
201
+ query(request: LspQueryRequest, signal?: AbortSignal): Promise<LspQueryResult>
202
+ ```
203
+
204
+ Source: [`packages/lsp/lsp/src/types.ts:113`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/lsp/lsp/src/types.ts)
205
+ <!-- END GENERATED cordis-surface -->
@@ -0,0 +1,134 @@
1
+ ---
2
+ editSource: "docs/subsystems/permission-presets.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # Permission Presets
7
+
8
+ The permission-preset layer of [dsh-permission-presets](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/permission-presets) (`ctx.permissionPresets`, `PermissionPresetService`) bundles the two independent enforcement knobs — [sandbox mode](./sandbox.md) (`sandbox/mode`) and [approval policy](./approval.md) (`approval/policy`) — into named presets a client offers as one Permissions selector. It is one optional capability, not part of the agent-loop spine, and it owns no enforcement: execution, prompt narration, and replay keep reading their knob folds, and a preset switch only records intent and writes through each knob's canonical setter. The [package README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/permission-presets/README.md) owns composition status and limitations; the [sandbox switching design](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-06-sandbox.md) owns the rationale.
9
+
10
+ Source: [`packages/interaction/permission-presets/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/permission-presets/src/index.ts)
11
+
12
+ ## The preset table
13
+
14
+ A preset is a table key mapping to one sandbox/approval bundle plus optional client presentation; the default table ships `workspace-write` (`workspace-write` + `ask`) and `danger-full-access` (`danger-full-access` + `never`).
15
+
16
+ ```ts type-equiv
17
+ /** One preset's sandbox/approval bundle and optional client presentation. */
18
+ interface PresetSpec {
19
+ /** The `sandbox/mode` value the preset writes through. */
20
+ sandbox: SandboxMode
21
+ /** The `approval/policy` value the preset writes through. */
22
+ approval: ApprovalPolicy
23
+ /** The display label a client shows for this preset; the raw table key when omitted. */
24
+ name?: string
25
+ /** One user-facing sentence on what the preset means; omitted when not configured. */
26
+ description?: string
27
+ }
28
+ ```
29
+
30
+ ```ts type-equiv
31
+ /** The {@link PermissionPresetService} config: preset table and composition default. */
32
+ interface Config {
33
+ /**
34
+ * The preset table: name → knob bundle. Defaults to `workspace-write`
35
+ * (workspace-write + ask) and `danger-full-access` (danger-full-access +
36
+ * never). The name `custom` is reserved for the derived not-a-preset state.
37
+ */
38
+ presets?: Record<string, PresetSpec>
39
+ /**
40
+ * Default for new sessions. When omitted, the preset matching the composed
41
+ * sandbox and approval defaults is used.
42
+ */
43
+ defaultPreset?: string
44
+ }
45
+ ```
46
+
47
+ The service requires a confining `ctx.shell` executor and `ctx.approval`, and misconfiguration fails at plugin load: a table entry named `custom` throws (the name is reserved for the derived not-a-preset state), and composing over a bash executor that does not confine (no `sandboxMode` capability fact) throws, because presets bundle a sandbox mode.
48
+
49
+ ## Current preset and the derived `custom`
50
+
51
+ `current(events)` derives the effective preset from the knobs, not from its own event alone: it folds the session's effective sandbox mode (falling back to the executor's configured mode) and effective approval policy (falling back to the approval service config, then `ask`), prefers a still-matching recorded selection, then the first matching table entry in declaration order, and otherwise returns `CUSTOM_PRESET` (`'custom'`). `custom` is derived-only: clients may display it as the current value, but it is never a switch target or an event payload.
52
+
53
+ `names` lists the switchable presets in table declaration order; `optionOf(name)` builds the option a client renders for a table key (label falls back to the key) or for `custom`, and throws for any other name.
54
+
55
+ ```ts type-equiv
56
+ /** The select-option shape a presentation layer advertises for one preset (or for the derived `custom` state). */
57
+ interface PresetOption {
58
+ /** Stable option value: the table key, or `custom`. */
59
+ value: string
60
+ /** The display label. */
61
+ name: string
62
+ /** One user-facing sentence on what the value means; omitted when not configured. */
63
+ description?: string
64
+ }
65
+ ```
66
+
67
+ ## Switching and the `permission/preset` event
68
+
69
+ `set(session, name)` resolves the preset (unknown names throw), appends a log-only `permission/preset` event unless `name` is already the effective preset, then writes each knob through its own setter — `setSandboxMode` from [dsh-sandbox-policy](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/sandbox/sandbox-policy) and `setApprovalPolicy` from [dsh-user-approval](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-approval) — only when that knob's effective value changes. The selection event precedes the knob events in the same turn, and re-selecting the effective preset appends nothing at all.
70
+
71
+ `permission/preset` is durable, log-only user intent: it stays out of the model transcript (the knob events own the model-visible consequences through their consumers), and it exists so `current()` can preserve WHICH preset the user chose when two presets share a bundle; `effectivePermissionPreset(events)` folds the last one, and replay needs no catch-up state. The complete event declaration is in the [persistence log event catalog](../persistence-catalog.md); the method signatures are in the generated [service catalog](#ctxpermissionpresets--permissionpresetservice).
72
+
73
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
74
+
75
+ <a id="cordis-surface"></a>
76
+
77
+ ## Cordis API
78
+
79
+ 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).
80
+
81
+ <a id="ctxpermissionpresets--permissionpresetservice"></a>
82
+
83
+ ### `ctx.permissionPresets` — `PermissionPresetService`
84
+
85
+ Owns the deployment's permission presets and their write path. Requires a confining `ctx.shell` executor and `ctx.approval`; unmatched knob values are reported as CUSTOM_PRESET, not an error.
86
+
87
+ ```ts cordis-catalog
88
+ /**
89
+ * Resolve the preset matching the effective knob values. A still-matching
90
+ * last selection wins shared-bundle ties; otherwise the first table match
91
+ * wins, or {@link CUSTOM_PRESET} when no entry matches.
92
+ * @param events - the session's events in log order.
93
+ * @returns the effective preset name, or `custom` when nothing matches.
94
+ */
95
+ current(events: readonly SessionEvent[]): string
96
+
97
+ /**
98
+ * Build the whole select value for one folded knob state: every table
99
+ * option in declaration order, `custom` appended exactly while derived.
100
+ * @param state - the folded knob overrides.
101
+ * @returns the `permissions` projection payload.
102
+ */
103
+ selectFor(state: KnobState): PermissionSelect
104
+
105
+ /**
106
+ * Resolve a preset's knob bundle.
107
+ * @param name - the preset name to resolve.
108
+ * @returns the configured bundle.
109
+ * @throws when `name` is not in the table.
110
+ */
111
+ resolve(name: string): PresetSpec
112
+
113
+ /**
114
+ * Build the client option for a table entry or {@link CUSTOM_PRESET}. A
115
+ * missing label falls back to the table key.
116
+ * @param name - a table key, or `custom`.
117
+ * @returns the option a client renders.
118
+ * @throws when `name` is neither a table key nor `custom`.
119
+ */
120
+ optionOf(name: string): PresetOption
121
+
122
+ /**
123
+ * Record a changed preset, then update each changed knob through its own
124
+ * setter. Selecting the effective preset again appends nothing.
125
+ * @param session - the session the switch belongs to.
126
+ * @param name - the preset to switch to; unknown names throw.
127
+ */
128
+ set(session: Session, name: string): void
129
+ ```
130
+
131
+ Types: [Session](./session.md) · [SessionEvent](./session.md)
132
+
133
+ Source: [`packages/interaction/permission-presets/src/index.ts:159`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/permission-presets/src/index.ts)
134
+ <!-- END GENERATED cordis-surface -->