@deepseek-harness-tui/dsh-tui 0.8.1 → 0.8.2

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 (240) hide show
  1. package/README.md +22 -13
  2. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -0
  3. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -0
  4. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -0
  5. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -0
  6. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -0
  7. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -0
  8. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -0
  9. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -0
  10. package/dsh-ecosystem-spec/registry/README.md +14 -0
  11. package/dsh-ecosystem-spec/registry/contracts/scene-v1alpha1.json +13 -0
  12. package/dsh-ecosystem-spec/registry/contracts/settings-section-v1alpha1.json +13 -0
  13. package/dsh-ecosystem-spec/registry/contracts/tui-channel-v1alpha1.json +30 -0
  14. package/dsh-ecosystem-spec/registry/contracts/workspace-provider-v1alpha1.json +6 -0
  15. package/{ecosystem-spec → dsh-ecosystem-spec}/registry/permissions-0.1.json +1 -1
  16. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -0
  17. package/lib/types/command-trees.d.ts +2 -1
  18. package/lib/types/command-trees.d.ts.map +1 -1
  19. package/lib/types/command-trees.js +1 -1
  20. package/lib/types/components/LoadedContextPanel.d.ts +10 -5
  21. package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
  22. package/lib/types/components/LoadedContextPanel.js +18 -7
  23. package/lib/types/components/LogoV2.d.ts.map +1 -1
  24. package/lib/types/components/LogoV2.js +16 -7
  25. package/lib/types/components/Markdown.d.ts +13 -1
  26. package/lib/types/components/Markdown.d.ts.map +1 -1
  27. package/lib/types/components/Markdown.js +15 -1
  28. package/lib/types/components/MessageList.d.ts +3 -1
  29. package/lib/types/components/MessageList.d.ts.map +1 -1
  30. package/lib/types/components/MessageList.js +90 -9
  31. package/lib/types/components/PromptInput.d.ts.map +1 -1
  32. package/lib/types/components/PromptInput.js +26 -12
  33. package/lib/types/components/StreamingMarkdown.d.ts +2 -8
  34. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  35. package/lib/types/components/StreamingMarkdown.js +51 -9
  36. package/lib/types/components/activityFrames.d.ts +1 -1
  37. package/lib/types/components/activityFrames.d.ts.map +1 -1
  38. package/lib/types/components/activityFrames.js +4 -1
  39. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +5 -1
  40. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  41. package/lib/types/components/messages/AssistantThinkingMessage.js +26 -3
  42. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  43. package/lib/types/components/messages/AssistantToolUseMessage.js +12 -1
  44. package/lib/types/dsh-adapter/channel.d.ts +31 -4
  45. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  46. package/lib/types/dsh-adapter/channel.js +267 -102
  47. package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -1
  48. package/lib/types/dsh-adapter/childStderr.js +10 -0
  49. package/lib/types/dsh-adapter/command-attribution.d.ts.map +1 -1
  50. package/lib/types/dsh-adapter/command-attribution.js +2 -2
  51. package/lib/types/dsh-adapter/command-trees.d.ts +7 -1
  52. package/lib/types/dsh-adapter/command-trees.d.ts.map +1 -1
  53. package/lib/types/dsh-adapter/command-trees.js +70 -20
  54. package/lib/types/dsh-adapter/component-identity.d.ts +5 -0
  55. package/lib/types/dsh-adapter/component-identity.d.ts.map +1 -1
  56. package/lib/types/dsh-adapter/component-identity.js +14 -14
  57. package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -1
  58. package/lib/types/dsh-adapter/decision-guard.js +10 -16
  59. package/lib/types/dsh-adapter/dialogs.d.ts +2 -3
  60. package/lib/types/dsh-adapter/dialogs.d.ts.map +1 -1
  61. package/lib/types/dsh-adapter/dialogs.js +114 -60
  62. package/lib/types/dsh-adapter/effect-ledger.d.ts +0 -8
  63. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  64. package/lib/types/dsh-adapter/effect-ledger.js +73 -53
  65. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  66. package/lib/types/dsh-adapter/extension-events.js +39 -1
  67. package/lib/types/dsh-adapter/grants.d.ts.map +1 -1
  68. package/lib/types/dsh-adapter/grants.js +43 -14
  69. package/lib/types/dsh-adapter/host-access.d.ts +37 -0
  70. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -0
  71. package/lib/types/dsh-adapter/host-access.js +652 -0
  72. package/lib/types/dsh-adapter/host-descriptor.d.ts +2 -2
  73. package/lib/types/dsh-adapter/host-descriptor.d.ts.map +1 -1
  74. package/lib/types/dsh-adapter/host-descriptor.js +31 -8
  75. package/lib/types/dsh-adapter/index.d.ts +4 -0
  76. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  77. package/lib/types/dsh-adapter/index.js +1 -0
  78. package/lib/types/dsh-adapter/message-observer.d.ts +10 -15
  79. package/lib/types/dsh-adapter/message-observer.d.ts.map +1 -1
  80. package/lib/types/dsh-adapter/message-observer.js +114 -70
  81. package/lib/types/dsh-adapter/plugin-host.d.ts +39 -6
  82. package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -1
  83. package/lib/types/dsh-adapter/plugin-host.js +139 -44
  84. package/lib/types/dsh-adapter/plugin-storage.d.ts +0 -5
  85. package/lib/types/dsh-adapter/plugin-storage.d.ts.map +1 -1
  86. package/lib/types/dsh-adapter/plugin-storage.js +48 -36
  87. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  88. package/lib/types/dsh-adapter/plugin.js +80 -16
  89. package/lib/types/dsh-adapter/promptDebug.d.ts +0 -6
  90. package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/promptDebug.js +13 -4
  92. package/lib/types/dsh-adapter/renderers.d.ts +6 -14
  93. package/lib/types/dsh-adapter/renderers.d.ts.map +1 -1
  94. package/lib/types/dsh-adapter/renderers.js +81 -46
  95. package/lib/types/dsh-adapter/scenes.d.ts +8 -4
  96. package/lib/types/dsh-adapter/scenes.d.ts.map +1 -1
  97. package/lib/types/dsh-adapter/scenes.js +136 -37
  98. package/lib/types/dsh-adapter/settings-sections.d.ts +7 -3
  99. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  100. package/lib/types/dsh-adapter/settings-sections.js +106 -26
  101. package/lib/types/dsh-adapter/shortcuts.d.ts +8 -10
  102. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  103. package/lib/types/dsh-adapter/shortcuts.js +108 -36
  104. package/lib/types/dsh-adapter/status.d.ts +6 -7
  105. package/lib/types/dsh-adapter/status.d.ts.map +1 -1
  106. package/lib/types/dsh-adapter/status.js +88 -22
  107. package/lib/types/dsh-adapter/workspaces.d.ts +16 -5
  108. package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
  109. package/lib/types/dsh-adapter/workspaces.js +287 -170
  110. package/lib/types/extensions.d.ts +10 -5
  111. package/lib/types/extensions.d.ts.map +1 -1
  112. package/lib/types/extensions.js +11 -5
  113. package/lib/types/force-production-react.d.ts +1 -0
  114. package/lib/types/force-production-react.d.ts.map +1 -0
  115. package/lib/types/force-production-react.js +12 -0
  116. package/lib/types/i18n.d.ts +14 -6
  117. package/lib/types/i18n.d.ts.map +1 -1
  118. package/lib/types/i18n.js +4 -2
  119. package/lib/types/index.d.ts +1 -0
  120. package/lib/types/index.d.ts.map +1 -1
  121. package/lib/types/index.js +1 -0
  122. package/lib/types/ink/components/App.d.ts +2 -0
  123. package/lib/types/ink/components/App.d.ts.map +1 -1
  124. package/lib/types/ink/components/App.js +4 -0
  125. package/lib/types/ink/ink.d.ts +20 -3
  126. package/lib/types/ink/ink.d.ts.map +1 -1
  127. package/lib/types/ink/ink.js +57 -5
  128. package/lib/types/ink/log-update.d.ts.map +1 -1
  129. package/lib/types/ink/log-update.js +128 -9
  130. package/lib/types/ink/output.d.ts +28 -2
  131. package/lib/types/ink/output.d.ts.map +1 -1
  132. package/lib/types/ink/output.js +158 -12
  133. package/lib/types/ink/screen.d.ts +39 -0
  134. package/lib/types/ink/screen.d.ts.map +1 -1
  135. package/lib/types/ink/screen.js +117 -0
  136. package/lib/types/ink/terminal.d.ts.map +1 -1
  137. package/lib/types/ink/terminal.js +10 -2
  138. package/lib/types/ink/wrapAnsi.d.ts +1 -1
  139. package/lib/types/ink/wrapAnsi.d.ts.map +1 -1
  140. package/lib/types/ink/wrapAnsi.js +29 -2
  141. package/lib/types/plugin-host.d.ts +13 -11
  142. package/lib/types/plugin-host.d.ts.map +1 -1
  143. package/lib/types/plugin-host.js +16 -16
  144. package/lib/types/plugin-spec/registry.d.ts +2 -2
  145. package/lib/types/plugin-spec/registry.d.ts.map +1 -1
  146. package/lib/types/plugin-spec/registry.js +113 -18
  147. package/lib/types/plugin-spec/tui-extension.d.ts.map +1 -1
  148. package/lib/types/plugin-spec/tui-extension.js +2 -0
  149. package/lib/types/plugin-spec/validate.d.ts.map +1 -1
  150. package/lib/types/plugin-spec/validate.js +20 -1
  151. package/lib/types/scenes.d.ts +2 -1
  152. package/lib/types/scenes.d.ts.map +1 -1
  153. package/lib/types/scenes.js +1 -1
  154. package/lib/types/screens/Chat.d.ts +3 -3
  155. package/lib/types/screens/Chat.d.ts.map +1 -1
  156. package/lib/types/screens/Chat.js +38 -17
  157. package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
  158. package/lib/types/screens/SessionBrowser.js +10 -3
  159. package/lib/types/sessions/view.d.ts +3 -2
  160. package/lib/types/sessions/view.d.ts.map +1 -1
  161. package/lib/types/sessions/view.js +18 -0
  162. package/lib/types/settings-sections.d.ts +2 -1
  163. package/lib/types/settings-sections.d.ts.map +1 -1
  164. package/lib/types/settings-sections.js +1 -1
  165. package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
  166. package/lib/types/utils/execFileNoThrow.js +3 -0
  167. package/lib/types/workspaces.d.ts +2 -1
  168. package/lib/types/workspaces.d.ts.map +1 -1
  169. package/lib/types/workspaces.js +1 -1
  170. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -0
  171. package/node_modules/@dsh-std/command/package.json +1 -1
  172. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
  173. package/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
  174. package/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
  175. package/node_modules/@dsh-std/connection/lib/memory.js +1 -0
  176. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  177. package/node_modules/@dsh-std/connection/package.json +1 -1
  178. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  179. package/node_modules/@dsh-std/core/package.json +1 -1
  180. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
  181. package/node_modules/@dsh-std/manifest/package.json +1 -1
  182. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -0
  183. package/node_modules/@dsh-std/messages/package.json +1 -1
  184. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
  185. package/node_modules/@dsh-std/presentation/README.md +2 -1
  186. package/node_modules/@dsh-std/presentation/README.zh.md +2 -1
  187. package/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
  188. package/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
  189. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
  190. package/node_modules/@dsh-std/presentation/lib/index.d.ts +44 -1
  191. package/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -1
  192. package/node_modules/@dsh-std/presentation/lib/index.js +6 -3
  193. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  194. package/node_modules/@dsh-std/presentation/package.json +7 -3
  195. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -0
  196. package/node_modules/@dsh-std/storage/package.json +1 -1
  197. package/package.json +10 -5
  198. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
  199. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
  200. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
  201. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js +1 -0
  202. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  203. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +1 -1
  204. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  205. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +1 -1
  206. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
  207. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +1 -1
  208. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
  209. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +2 -1
  210. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +2 -1
  211. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
  212. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
  213. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
  214. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts +44 -1
  215. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -1
  216. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js +6 -3
  217. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  218. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +7 -3
  219. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  220. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +1 -1
  221. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  222. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +1 -1
  223. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  224. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +1 -1
  225. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
  226. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
  227. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
  228. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js +1 -0
  229. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  230. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +1 -1
  231. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  232. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +1 -1
  233. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
  234. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +1 -1
  235. package/ecosystem-spec/registry/registry-0.15.json +0 -57
  236. /package/{ecosystem-spec → dsh-ecosystem-spec}/registry/contracts/decision-events-v1alpha1.json +0 -0
  237. /package/{ecosystem-spec → dsh-ecosystem-spec}/registry/host-descriptor.tui.example.json +0 -0
  238. /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/conformance-claim.schema.json +0 -0
  239. /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/effect-ledger-record.schema.json +0 -0
  240. /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/host-descriptor.schema.json +0 -0
@@ -1,17 +1,17 @@
1
- // Re-export shim: the Cordis-backed implementation lives behind the adapter
2
- // boundary so UI consumers never import official @deepseek-ai/* packages.
3
- // Plugin authors import the plugin-host types from here
4
- // (`@deepseek-harness-tui/dsh-tui/plugin-host`); importing the module also
5
- // applies the `declare module '@deepseek-ai/cordis'` augmentation for the
6
- // `tuiPluginHost` property on Context.
7
- export * from './dsh-adapter/plugin-host.js';
8
- export * from './dsh-adapter/grants.js';
9
- export * from './dsh-adapter/host-descriptor.js';
10
- export * from './dsh-adapter/plugin-storage.js';
11
- export * from './dsh-adapter/message-observer.js';
12
- export * from './dsh-adapter/effect-ledger.js';
13
- export * from './dsh-adapter/command-errors.js';
14
- export { commandOwner, fiberNameOf, stampCommandOwner, unstampCommandOwner } from './dsh-adapter/command-attribution.js';
15
- export { DECISION_EVENT_PERMISSIONS, decisionHandlersOf, registerDecisionHandler, withDecisionRegistration, } from './dsh-adapter/decision-guard.js';
16
- export { DECISION_HANDLER_TIMEOUT_MS, DECISION_TOTAL_TIMEOUT_MS, dispatchTuiNotification, } from './dsh-adapter/extension-events.js';
1
+ // Public plugin-host shim. Keep the Cordis-backed implementation behind the
2
+ // adapter boundary: plugin authors receive protocol types and mediated service
3
+ // contracts, while loader-only admission, host ingress, mutable stores and
4
+ // attribution registries remain adapter-internal. Type-only runtime exports
5
+ // still load the adapter declarations so Context augmentation is available.
6
+ export { name, apply } from './dsh-adapter/plugin-host.js';
7
+ export { PluginStorageError, STORAGE_KEY_MAX_LENGTH, STORAGE_MAX_BYTES, STORAGE_MAX_KEYS } from './dsh-adapter/plugin-storage.js';
8
+ // The host-only message ingress accessor stays in the adapter module. Plugin
9
+ // authors receive the broker's subscribe surface and envelope vocabulary only.
10
+ export { OBSERVE_CALLBACK_QUEUE_LIMIT, OBSERVE_CALLBACK_TIMEOUT_MS, OBSERVE_CONTENT_MAX_CHARS, OBSERVE_ID_MAX_CHARS, OBSERVE_IMAGE_BASE64_MAX_CHARS, OBSERVE_IMAGE_MAX_BYTES, OBSERVE_SCOPE_MAX_CHARS, OBSERVE_SUMMARY_CELLS, } from './dsh-adapter/message-observer.js';
11
+ export { COMMAND_ERROR_CODES, hasCommandErrorCode, mapCommandError, withCommandErrorMapping, } from './dsh-adapter/command-errors.js';
12
+ // Command attribution and decision registration are host-internal. Exposing
13
+ // these functions would let a plugin inspect or rewrite another plugin's
14
+ // checkpoint, or install an unmediated handler.
15
+ export { DECISION_EVENT_PERMISSIONS, } from './dsh-adapter/decision-guard.js';
16
+ export { DECISION_HANDLER_TIMEOUT_MS, DECISION_TOTAL_TIMEOUT_MS, } from './dsh-adapter/extension-events.js';
17
17
  export { DECISION_EVENTS_COORDINATE, TUI_EXTENSION_API_VERSION, TUI_DECISION_EVENT_NAMES, TUI_EXTENSION_PERMISSION_NAMES, createAdmissionCatalog, } from './plugin-spec/tui-extension.js';
@@ -1,7 +1,7 @@
1
1
  /** Load and verify the pinned dsh-TUI admission profile. */
2
2
  import type { ContractRegistry, PermissionRegistry, RegistryEntry } from './types.js';
3
- export declare const DSH_STD_REVISION = "a2faa86243a5693ee4970e3d8b3aaf361edea298";
4
- export declare const ECOSYSTEM_SPEC_REVISION = "be1e9a219bd01decf79d825e0c3ac1685bde2be4";
3
+ export declare const DSH_STD_REVISION = "614dfa1ac168db79fcf4577cf0ebb34e2e3b944b";
4
+ export declare const ECOSYSTEM_SPEC_REVISION = "e1b902b0f95f4280a8e68d414ec7a4d25d6ce106";
5
5
  export interface SpecData {
6
6
  dir: string;
7
7
  registry: ContractRegistry;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/plugin-spec/registry.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAO5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAErF,eAAO,MAAM,gBAAgB,6CAA6C,CAAA;AAC1E,eAAO,MAAM,uBAAuB,6CAA6C,CAAA;AAEjF,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAC/B,CAAA;CACF;AAID,wBAAgB,aAAa,CAAC,KAAK,GAAE,MAAgD,GAAG,MAAM,GAAG,SAAS,CASzG;AA0CD,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,GAAG,SAA2B,GAAG,QAAQ,GAAG,SAAS,CAiB5F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAI3E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,MAAM,EAAE,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAsBvD;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAiC/D"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/plugin-spec/registry.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAO5D,OAAO,KAAK,EAAE,gBAAgB,EAAmB,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEtG,eAAO,MAAM,gBAAgB,6CAA6C,CAAA;AAC1E,eAAO,MAAM,uBAAuB,6CAA6C,CAAA;AAEjF,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAC/B,CAAA;CACF;AAuBD,wBAAgB,aAAa,CAAC,KAAK,GAAE,MAAgD,GAAG,MAAM,GAAG,SAAS,CASzG;AAiFD,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,GAAG,SAA2B,GAAG,QAAQ,GAAG,SAAS,CAiB5F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAI3E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,MAAM,EAAE,CAE5E;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAuCvD;AAED,4EAA4E;AAC5E,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CA2C/D"}
@@ -4,14 +4,32 @@ import { existsSync, readFileSync } from 'node:fs';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { createAdmissionCatalog } from './tui-extension.js';
7
- export const DSH_STD_REVISION = 'a2faa86243a5693ee4970e3d8b3aaf361edea298';
8
- export const ECOSYSTEM_SPEC_REVISION = 'be1e9a219bd01decf79d825e0c3ac1685bde2be4';
7
+ export const DSH_STD_REVISION = '614dfa1ac168db79fcf4577cf0ebb34e2e3b944b';
8
+ export const ECOSYSTEM_SPEC_REVISION = 'e1b902b0f95f4280a8e68d414ec7a4d25d6ce106';
9
9
  const REGISTRY_FILE = join('registry', 'registry-0.15.json');
10
+ const EXPECTED_PROFILE_VERSION = 'tui-admission/0.15';
11
+ const EXPECTED_STD_REPOSITORY = 'https://github.com/Yan-Zero/dsh-std';
12
+ const EXPECTED_STD_SUBMODULE = 'vendor/dsh-std';
13
+ const EXPECTED_STD_MANIFEST_VERSION = '0.15';
14
+ const EXPECTED_PERMISSION_REGISTRY_VERSION = '0.1';
15
+ // The permission registry is policy, not merely input data. Keep the
16
+ // admission defaults and scopes pinned to the reviewed dsh-ecosystem-spec
17
+ // revision so a locally modified copy cannot silently widen a capability.
18
+ const EXPECTED_PERMISSIONS = Object.freeze([
19
+ { name: 'storage.local.read', default: 'deny', revocable: true, scope: 'plugin namespace' },
20
+ { name: 'storage.local.write', default: 'deny', revocable: true, scope: 'plugin namespace' },
21
+ { name: 'commands.invoke', default: 'allow', revocable: true, scope: 'declared command id' },
22
+ { name: 'messages.observe.read', default: 'deny', revocable: true, scope: 'message observation scope' },
23
+ { name: 'session.input.intercept', default: 'deny', revocable: true, scope: 'decision event subscription' },
24
+ { name: 'session.rewind.intercept', default: 'deny', revocable: true, scope: 'decision event subscription' },
25
+ { name: 'session.switch.intercept', default: 'deny', revocable: true, scope: 'decision event subscription' },
26
+ { name: 'session.compact.intercept', default: 'deny', revocable: true, scope: 'decision event subscription' },
27
+ ]);
10
28
  export function locateSpecDir(start = dirname(fileURLToPath(import.meta.url))) {
11
29
  let dir = start;
12
30
  for (let index = 0; index < 8; index++) {
13
- if (existsSync(join(dir, 'ecosystem-spec', REGISTRY_FILE)))
14
- return join(dir, 'ecosystem-spec');
31
+ if (existsSync(join(dir, 'dsh-ecosystem-spec', REGISTRY_FILE)))
32
+ return join(dir, 'dsh-ecosystem-spec');
15
33
  const parent = dirname(dir);
16
34
  if (parent === dir)
17
35
  return undefined;
@@ -26,41 +44,89 @@ function isRecord(value) {
26
44
  return value !== null && typeof value === 'object' && !Array.isArray(value);
27
45
  }
28
46
  function soundEntry(value, privateDefinition) {
29
- if (!isRecord(value) || typeof value.name !== 'string' || typeof value.kind !== 'string')
47
+ if (!isRecord(value) || typeof value.name !== 'string' || value.name === ''
48
+ || (value.kind !== 'capability' && value.kind !== 'event'))
30
49
  return false;
31
50
  if (!isRecord(value.coordinates)
32
- || typeof value.coordinates.apiVersion !== 'string'
33
- || typeof value.coordinates.kind !== 'string')
51
+ || typeof value.coordinates.apiVersion !== 'string' || value.coordinates.apiVersion === ''
52
+ || typeof value.coordinates.kind !== 'string' || value.coordinates.kind === '')
34
53
  return false;
35
54
  if (!Array.isArray(value.permissions) || !value.permissions.every(permission => typeof permission === 'string'))
36
55
  return false;
37
56
  if (privateDefinition) {
38
57
  return value.authority === 'dsh-tui'
39
58
  && typeof value.profile === 'string'
40
- && typeof value.profileHash === 'string';
59
+ && value.profile.length > 0
60
+ && typeof value.profileHash === 'string'
61
+ && /^sha256:[0-9a-f]{64}$/u.test(value.profileHash);
41
62
  }
42
- return typeof value.package === 'string' && value.package.startsWith('@dsh-std/');
63
+ return typeof value.package === 'string' && /^@dsh-std\/[a-z0-9][a-z0-9-]*$/u.test(value.package);
43
64
  }
44
65
  function structurallySound(data) {
45
66
  if (!isRecord(data.registry)
46
- || typeof data.registry.profileVersion !== 'string'
67
+ || data.registry.profileVersion !== EXPECTED_PROFILE_VERSION
47
68
  || !isRecord(data.registry.std)
69
+ || data.registry.std.repository !== EXPECTED_STD_REPOSITORY
70
+ || data.registry.std.submodule !== EXPECTED_STD_SUBMODULE
71
+ || data.registry.std.manifestVersion !== EXPECTED_STD_MANIFEST_VERSION
48
72
  || !Array.isArray(data.registry.imports)
49
73
  || !Array.isArray(data.registry.definitions)
50
74
  || !Array.isArray(data.registry.facetApiVersions)
51
- || !data.registry.facetApiVersions.every(version => typeof version === 'string'))
75
+ || data.registry.facetApiVersions.length === 0
76
+ || !data.registry.facetApiVersions.every(version => typeof version === 'string'
77
+ && /^v[0-9]+(?:alpha[0-9]+|beta[0-9]+)?$/u.test(version)))
78
+ return false;
79
+ if (new Set(data.registry.facetApiVersions).size !== data.registry.facetApiVersions.length)
52
80
  return false;
53
81
  if (!data.registry.imports.every(entry => soundEntry(entry, false)))
54
82
  return false;
55
83
  if (!data.registry.definitions.every(entry => soundEntry(entry, true)))
56
84
  return false;
57
- if (!isRecord(data.permissions) || !Array.isArray(data.permissions.permissions))
85
+ const entries = [...data.registry.imports, ...data.registry.definitions];
86
+ const names = new Set();
87
+ const coordinates = new Set();
88
+ for (const entry of entries) {
89
+ if (names.has(entry.name))
90
+ return false;
91
+ names.add(entry.name);
92
+ const key = `${entry.coordinates.apiVersion}#${entry.coordinates.kind}`;
93
+ if (coordinates.has(key))
94
+ return false;
95
+ coordinates.add(key);
96
+ if ('authority' in entry && !entry.coordinates.apiVersion.startsWith('tui.dsh/'))
97
+ return false;
98
+ }
99
+ if (!isRecord(data.permissions)
100
+ || data.permissions.registryVersion !== EXPECTED_PERMISSION_REGISTRY_VERSION
101
+ || !Array.isArray(data.permissions.permissions)
102
+ || data.permissions.permissions.length !== EXPECTED_PERMISSIONS.length)
58
103
  return false;
104
+ const expectedPermissions = new Map(EXPECTED_PERMISSIONS.map(permission => [permission.name, permission]));
105
+ const permissionNames = new Set();
59
106
  for (const permission of data.permissions.permissions) {
60
107
  if (!isRecord(permission) || typeof permission.name !== 'string'
61
- || (permission.default !== 'allow' && permission.default !== 'deny'))
108
+ || (permission.default !== 'allow' && permission.default !== 'deny')
109
+ || typeof permission.revocable !== 'boolean'
110
+ || typeof permission.scope !== 'string'
111
+ || permission.scope.trim() === '')
112
+ return false;
113
+ if (permissionNames.has(permission.name))
114
+ return false;
115
+ permissionNames.add(permission.name);
116
+ const expected = expectedPermissions.get(permission.name);
117
+ if (expected === undefined
118
+ || permission.default !== expected.default
119
+ || permission.revocable !== expected.revocable
120
+ || permission.scope !== expected.scope)
121
+ return false;
122
+ if ('rationale' in permission && permission.rationale !== undefined && typeof permission.rationale !== 'string')
62
123
  return false;
63
124
  }
125
+ if (permissionNames.size !== expectedPermissions.size)
126
+ return false;
127
+ const knownPermissions = new Set(expectedPermissions.keys());
128
+ if (!entries.every(entry => entry.permissions.every(permission => knownPermissions.has(permission))))
129
+ return false;
64
130
  return Object.values(data.schemas).every(isRecord);
65
131
  }
66
132
  export function loadSpecData(dir = locateSpecDir()) {
@@ -94,13 +160,32 @@ export function digestFile(dir, relative) {
94
160
  /** Verify definition availability and private profile digest pins. */
95
161
  export function verifyRegistry(data) {
96
162
  const failures = [];
97
- if (!Array.isArray(data.registry.imports)
98
- || !Array.isArray(data.registry.definitions)) {
163
+ const registry = data?.registry;
164
+ if (!isRecord(registry)
165
+ || !Array.isArray(registry.imports)
166
+ || !Array.isArray(registry.definitions)) {
99
167
  return ['registry imports/definitions are malformed'];
100
168
  }
169
+ const names = new Set();
170
+ const coordinates = new Set();
101
171
  const { protocols } = createAdmissionCatalog();
102
- for (const entry of registryEntries(data.registry)) {
172
+ for (const raw of [...registry.imports, ...registry.definitions]) {
173
+ const privateDefinition = registry.definitions.includes(raw);
174
+ if (!soundEntry(raw, privateDefinition)) {
175
+ failures.push('registry entry is malformed');
176
+ continue;
177
+ }
178
+ const entry = raw;
103
179
  const key = `${entry.coordinates.apiVersion}#${entry.coordinates.kind}`;
180
+ if (names.has(entry.name))
181
+ failures.push(`${entry.name}: duplicate registry name`);
182
+ names.add(entry.name);
183
+ if (coordinates.has(key))
184
+ failures.push(`${key}: duplicate registry coordinate`);
185
+ coordinates.add(key);
186
+ if ('authority' in entry && !entry.coordinates.apiVersion.startsWith('tui.dsh/')) {
187
+ failures.push(`${key}: dsh-tui definition must use the private protocol group`);
188
+ }
104
189
  if (!protocols.understands(entry.coordinates))
105
190
  failures.push(`${key}: ProtocolCatalog definition unavailable`);
106
191
  if ('profile' in entry) {
@@ -125,13 +210,23 @@ export function verifyContractProfiles(data) {
125
210
  'errors', 'concurrency', 'timeout', 'cleanup', 'privacyClass', 'securityBoundary',
126
211
  ];
127
212
  const failures = [];
128
- if (!Array.isArray(data.registry.definitions)) {
213
+ if (!isRecord(data?.registry)
214
+ || !Array.isArray(data.registry.definitions)) {
129
215
  return ['registry definitions are malformed'];
130
216
  }
131
217
  for (const entry of data.registry.definitions) {
218
+ if (!soundEntry(entry, true)) {
219
+ failures.push('registry definition is malformed');
220
+ continue;
221
+ }
132
222
  let profile;
133
223
  try {
134
- profile = loadJson(data.dir, entry.profile);
224
+ const loaded = loadJson(data.dir, entry.profile);
225
+ if (!isRecord(loaded)) {
226
+ failures.push(`${entry.name}: private profile is not an object (${entry.profile})`);
227
+ continue;
228
+ }
229
+ profile = loaded;
135
230
  }
136
231
  catch {
137
232
  failures.push(`${entry.name}: private profile unreadable (${entry.profile})`);
@@ -1 +1 @@
1
- {"version":3,"file":"tui-extension.d.ts","sourceRoot":"","sources":["../../../src/plugin-spec/tui-extension.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,OAAO,EAAE,eAAe,EAAE,KAAK,kBAAkB,EAAsB,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAK7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,eAAO,MAAM,yBAAyB,qBAAqB,CAAA;AAE3D,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,kBAAkB,CAGlE,CAAA;AAEF,eAAO,MAAM,wBAAwB,6HAO1B,CAAA;AAEX,eAAO,MAAM,8BAA8B,2HAKhC,CAAA;AAiBX,eAAO,MAAM,wBAAwB,EAAE,kBAsBrC,CAAA;AAEF,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,eAAe,CAAA;IAC1B,SAAS,EAAE,yBAAyB,CAAA;CACrC;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,IAAI,gBAAgB,CASzD"}
1
+ {"version":3,"file":"tui-extension.d.ts","sourceRoot":"","sources":["../../../src/plugin-spec/tui-extension.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,OAAO,EAAE,eAAe,EAAE,KAAK,kBAAkB,EAAsB,MAAM,eAAe,CAAA;AAC5F,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAA;AAM7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpD,eAAO,MAAM,yBAAyB,qBAAqB,CAAA;AAE3D,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,kBAAkB,CAGlE,CAAA;AAEF,eAAO,MAAM,wBAAwB,6HAO1B,CAAA;AAEX,eAAO,MAAM,8BAA8B,2HAKhC,CAAA;AAiBX,eAAO,MAAM,wBAAwB,EAAE,kBAsBrC,CAAA;AAEF,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,eAAe,CAAA;IAC1B,SAAS,EAAE,yBAAyB,CAAA;CACrC;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,IAAI,gBAAgB,CAUzD"}
@@ -5,6 +5,7 @@ import { register as registerCommand } from '@dsh-std/command';
5
5
  import { register as registerMessages } from '@dsh-std/messages';
6
6
  import { register as registerPresentation } from '@dsh-std/presentation';
7
7
  import { register as registerStorage } from '@dsh-std/storage';
8
+ import { tuiChannelDefinition } from '#dsh-ecosystem-spec/tui-channel';
8
9
  export const TUI_EXTENSION_API_VERSION = 'tui.dsh/v1alpha1';
9
10
  export const DECISION_EVENTS_COORDINATE = Object.freeze({
10
11
  apiVersion: TUI_EXTENSION_API_VERSION,
@@ -73,5 +74,6 @@ export function createAdmissionCatalog() {
73
74
  registerMessages(protocols);
74
75
  registerPresentation(protocols);
75
76
  protocols.register(decisionEventsDefinition);
77
+ protocols.register(tuiChannelDefinition);
76
78
  return { protocols, manifests };
77
79
  }
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/plugin-spec/validate.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,SAAS,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,WAAW,CAAC,CAAA;IACjE,SAAS,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,WAAW,CAAC,CAAA;IACjE,cAAc,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAAA;IACzE,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG;QAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;QAAC,mBAAmB,EAAE,OAAO,CAAA;KAAE,CAAA;IAC1G,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,CAAA;CACzD;AAGD,eAAO,MAAM,OAAO,GAAI,YAAY,MAAM,KAAG,MAAwC,CAAA;AAErF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,GAAG,aAAa,CAsC9G;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAwCnF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CA4B7E"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/plugin-spec/validate.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,gBAAgB,CAAA;IAC1B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,SAAS,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,WAAW,CAAC,CAAA;IACjE,SAAS,EAAE,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC,WAAW,CAAC,CAAA;IACjE,cAAc,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,GAAG,SAAS,CAAA;IACzE,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG;QAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;QAAC,mBAAmB,EAAE,OAAO,CAAA;KAAE,CAAA;IAC1G,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,CAAA;CACzD;AAGD,eAAO,MAAM,OAAO,GAAI,YAAY,MAAM,KAAG,MAAwC,CAAA;AAErF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,kBAAkB,GAAG,aAAa,CAsC9G;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CA4DnF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CA4B7E"}
@@ -58,7 +58,18 @@ export function validatePlugin(index, manifest) {
58
58
  index.resolveSubscription(subscription);
59
59
  const knownPermissions = new Set(index.permissions.permissions.map(permission => permission.name));
60
60
  const commandIds = new Set(manifest.contributes.commands.map(command => command.id));
61
- const requiresDecisionEvents = manifest.requires.contracts.some(requirement => requirement.apiVersion === 'tui.dsh/v1alpha1' && requirement.kind === 'DecisionEvents');
61
+ const requiresDecisionEvents = manifest.requires.contracts.some(requirement => requirement.kind === 'DecisionEvents'
62
+ && groupOf(requirement.apiVersion) === groupOf('tui.dsh/v1alpha1'));
63
+ const capabilityForPermission = {
64
+ 'commands.invoke': { apiVersion: 'commands.dsh/v1alpha1', kind: 'Command' },
65
+ 'storage.local.read': { apiVersion: 'storage.dsh/v1alpha1', kind: 'LocalStorage' },
66
+ 'storage.local.write': { apiVersion: 'storage.dsh/v1alpha1', kind: 'LocalStorage' },
67
+ 'messages.observe.read': { apiVersion: 'messages.dsh/v1alpha1', kind: 'MessageObserver' },
68
+ 'session.input.intercept': { apiVersion: 'tui.dsh/v1alpha1', kind: 'DecisionEvents' },
69
+ 'session.rewind.intercept': { apiVersion: 'tui.dsh/v1alpha1', kind: 'DecisionEvents' },
70
+ 'session.switch.intercept': { apiVersion: 'tui.dsh/v1alpha1', kind: 'DecisionEvents' },
71
+ 'session.compact.intercept': { apiVersion: 'tui.dsh/v1alpha1', kind: 'DecisionEvents' },
72
+ };
62
73
  for (const permission of manifest.permissions) {
63
74
  if (!knownPermissions.has(permission.name)) {
64
75
  throw new Error(`permission is not admitted by the TUI profile: ${permission.name}`);
@@ -72,6 +83,14 @@ export function validatePlugin(index, manifest) {
72
83
  if (INTERCEPT_PERMISSIONS.has(permission.name) && !requiresDecisionEvents) {
73
84
  throw new Error(`${permission.name} requires tui.dsh/v1alpha1#DecisionEvents`);
74
85
  }
86
+ const capability = capabilityForPermission[permission.name];
87
+ // An otherwise valid contract reference may use an unregistered version
88
+ // from the same protocol group. Keep that manifest structurally valid so
89
+ // negotiation can return UNKNOWN_PROTOCOL_VERSION rather than letting the
90
+ // permission/capability cross-check mask the version-drift decision.
91
+ if (capability !== undefined && !manifest.requires.contracts.some(requirement => requirement.kind === capability.kind && groupOf(requirement.apiVersion) === groupOf(capability.apiVersion))) {
92
+ throw new Error(`${permission.name} requires ${capability.apiVersion}#${capability.kind}`);
93
+ }
75
94
  }
76
95
  for (const commandId of commandIds) {
77
96
  if (!manifest.permissions.some(permission => permission.name === 'commands.invoke' && permission.scope === commandId)) {
@@ -1,3 +1,4 @@
1
- export * from './dsh-adapter/scenes.js';
1
+ export { name, TuiSceneRuntime } from './dsh-adapter/scenes.js';
2
+ export type { TuiSceneProps, TuiSceneDescriptor } from './dsh-adapter/scenes.js';
2
3
  export { default } from './dsh-adapter/scenes.js';
3
4
  //# sourceMappingURL=scenes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scenes.d.ts","sourceRoot":"","sources":["../../src/scenes.ts"],"names":[],"mappings":"AAEA,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"scenes.d.ts","sourceRoot":"","sources":["../../src/scenes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC/D,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA"}
@@ -1,4 +1,4 @@
1
1
  // Re-export shim: the Cordis-backed implementation lives behind the adapter
2
2
  // boundary so UI consumers never import official @deepseek-ai/* packages.
3
- export * from './dsh-adapter/scenes.js';
3
+ export { name, TuiSceneRuntime } from './dsh-adapter/scenes.js';
4
4
  export { default } from './dsh-adapter/scenes.js';
@@ -3,7 +3,7 @@ import { type Channel } from '../dsh-adapter/channel.js';
3
3
  import type { QuestionStore } from '../dsh-adapter/questions.js';
4
4
  import { TuiDialogStore } from '../dsh-adapter/dialogs.js';
5
5
  import { TuiStatusStore } from '../dsh-adapter/status.js';
6
- import type { TuiShortcutRuntime } from '../dsh-adapter/shortcuts.js';
6
+ import type { TuiShortcutHost } from '../dsh-adapter/shortcuts.js';
7
7
  import { ApprovalStore } from '../dsh-adapter/approvals.js';
8
8
  export declare function Chat({ channel, questionStore, approvalStore, extensionDialogs, extensionStatus, extensionShortcuts, onExit, onUpdate, fullscreen, trajectorySeen: trajectorySeenProp, }: {
9
9
  channel: Channel;
@@ -22,8 +22,8 @@ export declare function Chat({ channel, questionStore, approvalStore, extensionD
22
22
  extensionDialogs?: TuiDialogStore;
23
23
  /** Plugin status-line contributions (tuiStatus service's store). */
24
24
  extensionStatus?: TuiStatusStore;
25
- /** Plugin keyboard shortcut registry (tuiShortcuts service). */
26
- extensionShortcuts?: TuiShortcutRuntime;
25
+ /** Host-only keyboard shortcut dispatch path. */
26
+ extensionShortcuts?: TuiShortcutHost;
27
27
  onExit: () => void;
28
28
  /** Update the installed package and restart the current TUI process. */
29
29
  onUpdate?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/screens/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,OAAO,EAAqB,KAAK,OAAO,EAAsE,MAAM,2BAA2B,CAAA;AAC/I,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAA;AAGrE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAwI3D,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,UAAkB,EAClB,cAAc,EAAE,kBAAkB,GACnC,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,aAAa,CAAA;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAA;IACjC,oEAAoE;IACpE,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,gEAAgE;IAChE,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,qBA6jEA"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/screens/Chat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AASzB,OAAO,EAAqB,KAAK,OAAO,EAAsE,MAAM,2BAA2B,CAAA;AAC/I,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAGlE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAwI3D,wBAAgB,IAAI,CAAC,EACnB,OAAO,EACP,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,QAAQ,EACR,UAAkB,EAClB,cAAc,EAAE,kBAAkB,GACnC,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,EAAE,aAAa,CAAA;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAA;IACjC,oEAAoE;IACpE,eAAe,CAAC,EAAE,cAAc,CAAA;IAChC,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,qBAwlEA"}
@@ -164,12 +164,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
164
164
  React.useEffect(() => {
165
165
  if (extensionShortcuts === undefined)
166
166
  return;
167
- extensionShortcuts.onError = combo => {
167
+ return extensionShortcuts.setErrorHandler(combo => {
168
168
  channel.notify(t('ext-shortcut-failed', { combo }), { color: 'error', timeoutMs: 4000 });
169
- };
170
- return () => {
171
- extensionShortcuts.onError = undefined;
172
- };
169
+ });
173
170
  }, [extensionShortcuts, channel]);
174
171
  // When a questionnaire batch completes, fold a Q&A summary into the
175
172
  // transcript (the tool card itself is hidden from the message list).
@@ -277,15 +274,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
277
274
  /**
278
275
  * Close the scene.
279
276
  *
280
- * Leaving the alternate screen makes the terminal restore the main buffer
281
- * itself; Ink then repaints once, because `setAltScreenActive(false)` blanks
282
- * its front frame. In inline mode that costs one frame of scrollback per
283
- * round trip — the same, already-accepted cost as the Ctrl+X external-editor
284
- * handoff, and bounded per OPEN rather than per keystroke. Making it zero
285
- * needs the render core to save and restore the pre-alt front frame, which
286
- * is a separate change to `setAltScreenActive` and deliberately not made
287
- * here. `verify-trace-scene` pins the property that matters meanwhile:
288
- * navigating inside the scene adds nothing at all.
277
+ * Leaving the alternate screen makes the terminal restore the main buffer;
278
+ * Ink restores the matching saved frame and diffs any conversation changes
279
+ * that happened while the scene was open.
289
280
  */
290
281
  const closeScene = React.useCallback(() => {
291
282
  setSceneOpen(false);
@@ -302,6 +293,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
302
293
  }, []);
303
294
  /** The startup summary gives way to transcript rows after the first local command or message. */
304
295
  const loadedContextVisible = channel.rows.length === 0 && channel.loadedContext !== undefined;
296
+ /** Startup context panel: collapsed by default, toggled with Ctrl+P. */
297
+ const [loadedContextOpen, setLoadedContextOpen] = React.useState(false);
305
298
  /** `/` transcript search (less-style incsearch, ported from CC's REPL). */
306
299
  const [searchOpen, setSearchOpen] = React.useState(false);
307
300
  const [searchQuery, setSearchQuery] = React.useState('');
@@ -581,7 +574,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
581
574
  case 'lang': {
582
575
  // `/lang` shows the current UI language, `/lang en|zh` switches
583
576
  // (hot-swap, persisted to ~/.dsh-tui/lang.json). Precedence on next
584
- // launch: DSH_TUI_LANG > cordis.yml `lang` > the persisted choice.
577
+ // launch: DSH_TUI_LANG > settings.yaml `dsh-tui.lang` > cordis.yml
578
+ // `lang` > the persisted choice.
585
579
  const parts = rawInput.trim().split(/\s+/).filter(Boolean);
586
580
  if (parts[0] === 'status') {
587
581
  setHelpOpen(false);
@@ -597,6 +591,16 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
597
591
  if (isLang(parts[0])) {
598
592
  const ok = writeLangPref(parts[0]);
599
593
  setLang(parts[0]);
594
+ // Mirror into the dsh-tui settings namespace when it is served,
595
+ // so /settings and the next boot see the same last-write-wins
596
+ // choice (best effort; lang.json stays the fallback).
597
+ const settingsHost = channel.settingsHost();
598
+ const tuiView = settingsHost?.listNamespaces().find(entry => entry.ns === 'dsh-tui');
599
+ if (settingsHost !== undefined && tuiView !== undefined) {
600
+ void settingsHost
601
+ .write('dsh-tui', [{ op: 'set', path: ['lang'], value: parts[0] }], tuiView.revision)
602
+ .catch(() => { });
603
+ }
600
604
  channel.notify(ok ? t('lang-switched', { lang: parts[0] }) : t('lang-switch-failed', { lang: parts[0] }), { color: ok ? 'success' : 'error' });
601
605
  }
602
606
  else {
@@ -1805,10 +1809,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1805
1809
  return;
1806
1810
  }
1807
1811
  if (isMod(key) && input === 't') {
1808
- // Ctrl+T has one stable meaning; loaded-context details live at /context.
1812
+ // Ctrl+T opens the trajectory scene at any point in the session.
1809
1813
  openScene();
1810
1814
  return;
1811
1815
  }
1816
+ if (isMod(key) && input === 'p' && loadedContextVisible) {
1817
+ // Ctrl+P toggles the startup loaded-context panel while it is on
1818
+ // screen (transcript still empty); once rows take over and the
1819
+ // panel disappears the key has nothing left to do.
1820
+ setLoadedContextOpen(previous => !previous);
1821
+ return;
1822
+ }
1812
1823
  if (isMod(key) && input === 'r' && !helpOpen) {
1813
1824
  setHistoryQuery('');
1814
1825
  setHistoryCursor(0);
@@ -1854,6 +1865,16 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1854
1865
  else if (isMod(key) && input === 'o') {
1855
1866
  // Leaving transcript mode (Ctrl+O) — search was already handled above.
1856
1867
  setExpanded(previous => !previous);
1868
+ // The toggle rewrites every thinking row's layout at once. The
1869
+ // ordinary scroll-based diff pushes rows into terminal scrollback on
1870
+ // each expand and nothing removes them on collapse — rapid toggling
1871
+ // drifts the virtual↔scrollback mapping until writes misland
1872
+ // (garbled transcript, duplicated rows). Re-anchor the next frame:
1873
+ // in-place viewport repaint, nothing added to scrollback. Lookup
1874
+ // falls back to the only live instance for embedders whose stdout
1875
+ // isn't process.stdout (test harnesses).
1876
+ const ink = instances.get(process.stdout) ?? instances.values().next().value;
1877
+ ink?.reanchorViewport();
1857
1878
  }
1858
1879
  else if (input === '/' && !key.ctrl && !key.meta && !key.super) {
1859
1880
  // `/` in transcript mode (Ctrl+O expanded, CC's REPL semantics:
@@ -1986,7 +2007,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1986
2007
  seekRow(lastUser.id);
1987
2008
  else
1988
2009
  handle?.scrollToBottom();
1989
- } })), _jsxs(ScrollBox, { ref: setHandle, flexDirection: "column", flexGrow: 1, flexShrink: 1, stickyScroll: true, children: [_jsx(LogoHeader, { model: channel.model, effort: channel.reasoningEffort, cwd: channel.displayCwd }), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: `${modLabel}t` }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, model: channel.model, diffLayout: channel.diffLayout, showAll: showAllMessages, thinkingVisible: thinkingVisible, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount })] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [showPill && (_jsx(NewMessagesPill, { count: unseenCount, onClick: () => handle?.scrollToBottom() })), channel.working &&
2010
+ } })), _jsxs(ScrollBox, { ref: setHandle, flexDirection: "column", flexGrow: 1, flexShrink: 1, stickyScroll: true, children: [_jsx(LogoHeader, { model: channel.model, effort: channel.reasoningEffort, cwd: channel.displayCwd }), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext, open: loadedContextOpen, onToggle: () => { setLoadedContextOpen(previous => !previous); } })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: `${modLabel}t` }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, model: channel.model, diffLayout: channel.diffLayout, thinkingFold: channel.thinkingFold, showAll: showAllMessages, thinkingVisible: thinkingVisible, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount })] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [showPill && (_jsx(NewMessagesPill, { count: unseenCount, onClick: () => handle?.scrollToBottom() })), channel.working &&
1990
2011
  (channel.activityEnabled &&
1991
2012
  channel.workingActivity !== undefined &&
1992
2013
  channel.workingActivity.line !== '' &&
@@ -1 +1 @@
1
- {"version":3,"file":"SessionBrowser.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAsBzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAoDxD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,WAAW,EACX,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAC9C,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CAselB"}
1
+ {"version":3,"file":"SessionBrowser.d.ts","sourceRoot":"","sources":["../../../src/screens/SessionBrowser.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAsBzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAoDxD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,WAAW,EACX,OAAO,GACR,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAC9C,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,KAAK,CAAC,SAAS,CA4elB"}
@@ -354,13 +354,20 @@ export function SessionBrowser({ channel, home, sameProject, onClose, }) {
354
354
  // did. `resumeTo` reports its own reasons; this only has to stay put.
355
355
  runAction(async () => {
356
356
  try {
357
- const ok = await channel.resumeTo(target.id);
358
- if (ok) {
357
+ const result = await channel.resumeTo(target.id);
358
+ if (result.ok) {
359
359
  channel.notify(t('resume-resumed'));
360
360
  onClose();
361
361
  }
362
362
  else {
363
- setNotice({ text: t('session-resume-refused'), tone: 'error' });
363
+ if (result.reason === 'cancelled')
364
+ return;
365
+ const text = result.reason === 'working'
366
+ ? t('resume-while-working')
367
+ : result.reason === 'unavailable'
368
+ ? t('resume-unavailable')
369
+ : t('session-resume-failed', { err: result.error });
370
+ setNotice({ text, tone: 'error' });
364
371
  }
365
372
  }
366
373
  catch (error) {
@@ -6,8 +6,9 @@
6
6
  * flat list of rows. Two reasons it is shaped that way:
7
7
  *
8
8
  * - Filtering is where this feature's bugs were. Keeping it pure means the
9
- * truth table — a sub-agent run is hidden, a rewind fork is not, a boot
10
- * artifact is hidden but counted — is checkable without rendering anything.
9
+ * truth table — a sub-agent run is hidden, an unrelated rewind fork is not,
10
+ * a boot artifact is hidden but counted — is checkable without rendering
11
+ * anything.
11
12
  * - Rows are flattened rather than nested. A windowed list of variable-height
12
13
  * groups has to guess how much room each group needs; a flat list of
13
14
  * single-line rows is windowed by arithmetic, and the group headers simply
@@ -1 +1 @@
1
- {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/sessions/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAEtE,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAChC;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,EAAE,cAK7B,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAA;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GACtH,WAAW,CAmGb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAK9F;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAKhG;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAGhG;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEjD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,MAAM,CAoBR;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAU1F"}
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../src/sessions/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAEtE,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,wEAAwE;IACxE,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;CAChC;AAED,oEAAoE;AACpE,eAAO,MAAM,eAAe,EAAE,cAK7B,CAAA;AAED,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAA;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;CAAE,GACtH,WAAW,CAqHb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAK9F;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAKhG;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAGhG;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAEjD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,UAAU,EAAE,EAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,MAAM,CAoBR;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAU1F"}
@@ -32,7 +32,25 @@ function matches(session, needle) {
32
32
  */
33
33
  export function buildView(sessions, filters, context) {
34
34
  const needle = filters.query.trim().toLowerCase();
35
+ // `/model` and `/rewind` continue the live conversation in a fork. Offering
36
+ // that fork's ancestors in `/resume` makes one conversation look like many,
37
+ // and selecting one silently jumps back before the fork. Only the live
38
+ // lineage is excluded: unrelated forks remain recoverable. Treat malformed
39
+ // cycles as a closed chain rather than looping forever over foreign data.
40
+ const byId = new Map(sessions.map(session => [session.id, session]));
41
+ const currentAncestors = new Set();
42
+ const seen = new Set([context.currentId]);
43
+ let cursor = byId.get(context.currentId);
44
+ while (cursor?.kind.kind === 'fork') {
45
+ const parent = cursor.kind.parent;
46
+ if (seen.has(parent))
47
+ break;
48
+ seen.add(parent);
49
+ currentAncestors.add(parent);
50
+ cursor = byId.get(parent);
51
+ }
35
52
  const inScope = (session) => session.id !== context.currentId &&
53
+ !currentAncestors.has(session.id) &&
36
54
  (filters.allProjects || context.sameProject(context.cwd, session.cwd));
37
55
  // Empty sessions never reach a view, but they are counted — and the count
38
56
  // feeds a DESTRUCTIVE action, so it is scoped exactly as the list is.
@@ -1,3 +1,4 @@
1
- export * from './dsh-adapter/settings-sections.js';
1
+ export { name, TuiSettingsSectionsRuntime } from './dsh-adapter/settings-sections.js';
2
+ export type { TuiSettingsFieldKind, TuiSettingsFieldOption, TuiSettingsFieldWrite, TuiSettingsField, TuiSettingsSection, } from './dsh-adapter/settings-sections.js';
2
3
  export { default } from './dsh-adapter/settings-sections.js';
3
4
  //# sourceMappingURL=settings-sections.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings-sections.d.ts","sourceRoot":"","sources":["../../src/settings-sections.ts"],"names":[],"mappings":"AAEA,cAAc,oCAAoC,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAA"}
1
+ {"version":3,"file":"settings-sections.d.ts","sourceRoot":"","sources":["../../src/settings-sections.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AACrF,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAA"}
@@ -1,4 +1,4 @@
1
1
  // Re-export shim: the Cordis-backed implementation lives behind the adapter
2
2
  // boundary so UI consumers never import official @deepseek-ai/* packages.
3
- export * from './dsh-adapter/settings-sections.js';
3
+ export { name, TuiSettingsSectionsRuntime } from './dsh-adapter/settings-sections.js';
4
4
  export { default } from './dsh-adapter/settings-sections.js';
@@ -1 +1 @@
1
- {"version":3,"file":"execFileNoThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/execFileNoThrow.ts"],"names":[],"mappings":"AAEA,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CA8BhC"}
1
+ {"version":3,"file":"execFileNoThrow.d.ts","sourceRoot":"","sources":["../../../src/utils/execFileNoThrow.ts"],"names":[],"mappings":"AAEA,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,qBAAqB,CAAC,CAiChC"}
@@ -20,6 +20,9 @@ export function execFileNoThrow(file, args, options) {
20
20
  child.stderr.on('data', (chunk) => {
21
21
  stderrChunks.push(chunk);
22
22
  });
23
+ // A child may exit before consuming the supplied input. The resulting
24
+ // EPIPE/EOF belongs to that child outcome and must not crash the caller.
25
+ child.stdin.on('error', () => { });
23
26
  child.on('error', () => {
24
27
  resolve({
25
28
  code: 1,