@deepseek-harness-tui/dsh-tui 0.8.0 → 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.
- package/README.md +32 -15
- package/cordis.patch.yml +21 -2
- package/cordis.yml +12 -1
- package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -0
- package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -0
- package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -0
- package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -0
- package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -0
- package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -0
- package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -0
- package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -0
- package/dsh-ecosystem-spec/registry/README.md +14 -0
- package/dsh-ecosystem-spec/registry/contracts/decision-events-v1alpha1.json +13 -0
- package/dsh-ecosystem-spec/registry/contracts/scene-v1alpha1.json +13 -0
- package/dsh-ecosystem-spec/registry/contracts/settings-section-v1alpha1.json +13 -0
- package/dsh-ecosystem-spec/registry/contracts/tui-channel-v1alpha1.json +30 -0
- package/dsh-ecosystem-spec/registry/contracts/workspace-provider-v1alpha1.json +6 -0
- package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -0
- package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -0
- package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -0
- package/dsh-ecosystem-spec/schemas/conformance-claim.schema.json +15 -0
- package/dsh-ecosystem-spec/schemas/effect-ledger-record.schema.json +16 -0
- package/dsh-ecosystem-spec/schemas/host-descriptor.schema.json +26 -0
- package/lib/types/cc/figures.d.ts +4 -0
- package/lib/types/cc/figures.d.ts.map +1 -1
- package/lib/types/cc/figures.js +4 -0
- package/lib/types/command-trees.d.ts +2 -1
- package/lib/types/command-trees.d.ts.map +1 -1
- package/lib/types/command-trees.js +1 -1
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +2 -0
- package/lib/types/components/ExtensionDialog.d.ts +40 -0
- package/lib/types/components/ExtensionDialog.d.ts.map +1 -0
- package/lib/types/components/ExtensionDialog.js +210 -0
- package/lib/types/components/HelpMenu.js +1 -1
- package/lib/types/components/LoadedContextPanel.d.ts +5 -5
- package/lib/types/components/LoadedContextPanel.js +6 -6
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +16 -8
- package/lib/types/components/Markdown.d.ts +13 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +15 -1
- package/lib/types/components/MessageList.d.ts +3 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +111 -6
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +26 -12
- package/lib/types/components/RewindPicker.d.ts +13 -1
- package/lib/types/components/RewindPicker.d.ts.map +1 -1
- package/lib/types/components/RewindPicker.js +26 -2
- package/lib/types/components/StreamingMarkdown.d.ts +2 -8
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +51 -9
- package/lib/types/components/ToolUseLoader.d.ts +8 -3
- package/lib/types/components/ToolUseLoader.d.ts.map +1 -1
- package/lib/types/components/ToolUseLoader.js +43 -9
- package/lib/types/components/activityFrames.d.ts +1 -1
- package/lib/types/components/activityFrames.d.ts.map +1 -1
- package/lib/types/components/activityFrames.js +4 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +5 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +26 -3
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +13 -2
- package/lib/types/dsh-adapter/channel.d.ts +61 -11
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +767 -120
- package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -1
- package/lib/types/dsh-adapter/childStderr.js +10 -0
- package/lib/types/dsh-adapter/command-attribution.d.ts +51 -0
- package/lib/types/dsh-adapter/command-attribution.d.ts.map +1 -0
- package/lib/types/dsh-adapter/command-attribution.js +93 -0
- package/lib/types/dsh-adapter/command-errors.d.ts +42 -0
- package/lib/types/dsh-adapter/command-errors.d.ts.map +1 -0
- package/lib/types/dsh-adapter/command-errors.js +63 -0
- package/lib/types/dsh-adapter/command-trees.d.ts +7 -1
- package/lib/types/dsh-adapter/command-trees.d.ts.map +1 -1
- package/lib/types/dsh-adapter/command-trees.js +70 -20
- package/lib/types/dsh-adapter/component-identity.d.ts +33 -0
- package/lib/types/dsh-adapter/component-identity.d.ts.map +1 -0
- package/lib/types/dsh-adapter/component-identity.js +108 -0
- package/lib/types/dsh-adapter/contract.d.ts +1 -1
- package/lib/types/dsh-adapter/contract.js +2 -2
- package/lib/types/dsh-adapter/decision-guard.d.ts +84 -0
- package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -0
- package/lib/types/dsh-adapter/decision-guard.js +348 -0
- package/lib/types/dsh-adapter/dialogs.d.ts +145 -0
- package/lib/types/dsh-adapter/dialogs.d.ts.map +1 -0
- package/lib/types/dsh-adapter/dialogs.js +316 -0
- package/lib/types/dsh-adapter/effect-ledger.d.ts +91 -0
- package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -0
- package/lib/types/dsh-adapter/effect-ledger.js +251 -0
- package/lib/types/dsh-adapter/extension-events.d.ts +193 -0
- package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -0
- package/lib/types/dsh-adapter/extension-events.js +207 -0
- package/lib/types/dsh-adapter/extensions.d.ts +32 -0
- package/lib/types/dsh-adapter/extensions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/extensions.js +42 -0
- package/lib/types/dsh-adapter/grants.d.ts +25 -0
- package/lib/types/dsh-adapter/grants.d.ts.map +1 -0
- package/lib/types/dsh-adapter/grants.js +213 -0
- package/lib/types/dsh-adapter/host-access.d.ts +37 -0
- package/lib/types/dsh-adapter/host-access.d.ts.map +1 -0
- package/lib/types/dsh-adapter/host-access.js +652 -0
- package/lib/types/dsh-adapter/host-descriptor.d.ts +24 -0
- package/lib/types/dsh-adapter/host-descriptor.d.ts.map +1 -0
- package/lib/types/dsh-adapter/host-descriptor.js +169 -0
- package/lib/types/dsh-adapter/index.d.ts +4 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +1 -0
- package/lib/types/dsh-adapter/message-observer.d.ts +173 -0
- package/lib/types/dsh-adapter/message-observer.d.ts.map +1 -0
- package/lib/types/dsh-adapter/message-observer.js +553 -0
- package/lib/types/dsh-adapter/plugin-host.d.ts +136 -0
- package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-host.js +365 -0
- package/lib/types/dsh-adapter/plugin-storage.d.ts +108 -0
- package/lib/types/dsh-adapter/plugin-storage.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-storage.js +397 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +124 -14
- package/lib/types/dsh-adapter/plugins-info.d.ts +43 -0
- package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugins-info.js +276 -0
- package/lib/types/dsh-adapter/promptDebug.d.ts +0 -6
- package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -1
- package/lib/types/dsh-adapter/promptDebug.js +13 -4
- package/lib/types/dsh-adapter/renderers.d.ts +57 -0
- package/lib/types/dsh-adapter/renderers.d.ts.map +1 -0
- package/lib/types/dsh-adapter/renderers.js +173 -0
- package/lib/types/dsh-adapter/sanitize.d.ts +36 -0
- package/lib/types/dsh-adapter/sanitize.d.ts.map +1 -0
- package/lib/types/dsh-adapter/sanitize.js +65 -0
- package/lib/types/dsh-adapter/scenes.d.ts +15 -5
- package/lib/types/dsh-adapter/scenes.d.ts.map +1 -1
- package/lib/types/dsh-adapter/scenes.js +149 -35
- package/lib/types/dsh-adapter/settings-sections.d.ts +7 -3
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +106 -26
- package/lib/types/dsh-adapter/shortcuts.d.ts +107 -0
- package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -0
- package/lib/types/dsh-adapter/shortcuts.js +340 -0
- package/lib/types/dsh-adapter/status.d.ts +74 -0
- package/lib/types/dsh-adapter/status.d.ts.map +1 -0
- package/lib/types/dsh-adapter/status.js +234 -0
- package/lib/types/dsh-adapter/workspaces.d.ts +16 -5
- package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
- package/lib/types/dsh-adapter/workspaces.js +287 -170
- package/lib/types/extensions.d.ts +13 -0
- package/lib/types/extensions.d.ts.map +1 -0
- package/lib/types/extensions.js +21 -0
- package/lib/types/force-production-react.d.ts +1 -0
- package/lib/types/force-production-react.d.ts.map +1 -0
- package/lib/types/force-production-react.js +12 -0
- package/lib/types/i18n.d.ts +174 -20
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +56 -6
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +1 -0
- package/lib/types/ink/components/App.d.ts +2 -0
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +4 -0
- package/lib/types/ink/ink.d.ts +31 -3
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +90 -5
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +225 -56
- package/lib/types/ink/output.d.ts +35 -2
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +281 -14
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +14 -6
- package/lib/types/ink/screen.d.ts +39 -0
- package/lib/types/ink/screen.d.ts.map +1 -1
- package/lib/types/ink/screen.js +117 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +26 -6
- package/lib/types/ink/wrapAnsi.d.ts +1 -1
- package/lib/types/ink/wrapAnsi.d.ts.map +1 -1
- package/lib/types/ink/wrapAnsi.js +29 -2
- package/lib/types/plugin-host.d.ts +15 -0
- package/lib/types/plugin-host.d.ts.map +1 -0
- package/lib/types/plugin-host.js +17 -0
- package/lib/types/plugin-spec/negotiate.d.ts +11 -0
- package/lib/types/plugin-spec/negotiate.d.ts.map +1 -0
- package/lib/types/plugin-spec/negotiate.js +97 -0
- package/lib/types/plugin-spec/permission-scope.d.ts +32 -0
- package/lib/types/plugin-spec/permission-scope.d.ts.map +1 -0
- package/lib/types/plugin-spec/permission-scope.js +90 -0
- package/lib/types/plugin-spec/registry.d.ts +23 -0
- package/lib/types/plugin-spec/registry.d.ts.map +1 -0
- package/lib/types/plugin-spec/registry.js +252 -0
- package/lib/types/plugin-spec/schema-check.d.ts +17 -0
- package/lib/types/plugin-spec/schema-check.d.ts.map +1 -0
- package/lib/types/plugin-spec/schema-check.js +165 -0
- package/lib/types/plugin-spec/tui-extension.d.ts +16 -0
- package/lib/types/plugin-spec/tui-extension.d.ts.map +1 -0
- package/lib/types/plugin-spec/tui-extension.js +79 -0
- package/lib/types/plugin-spec/types.d.ts +114 -0
- package/lib/types/plugin-spec/types.d.ts.map +1 -0
- package/lib/types/plugin-spec/types.js +10 -0
- package/lib/types/plugin-spec/validate.d.ts +21 -0
- package/lib/types/plugin-spec/validate.d.ts.map +1 -0
- package/lib/types/plugin-spec/validate.js +138 -0
- package/lib/types/scenes.d.ts +2 -1
- package/lib/types/scenes.d.ts.map +1 -1
- package/lib/types/scenes.js +1 -1
- package/lib/types/screens/Chat.d.ts +14 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +173 -49
- package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
- package/lib/types/screens/SessionBrowser.js +10 -3
- package/lib/types/sessions/view.d.ts +3 -2
- package/lib/types/sessions/view.d.ts.map +1 -1
- package/lib/types/sessions/view.js +18 -0
- package/lib/types/settings-sections.d.ts +2 -1
- package/lib/types/settings-sections.d.ts.map +1 -1
- package/lib/types/settings-sections.js +1 -1
- package/lib/types/theme.d.ts +5 -0
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +15 -0
- package/lib/types/update.d.ts +20 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +54 -7
- package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
- package/lib/types/utils/execFileNoThrow.js +3 -0
- package/lib/types/utils/loaded-context.d.ts +8 -3
- package/lib/types/utils/loaded-context.d.ts.map +1 -1
- package/lib/types/utils/loaded-context.js +39 -3
- package/lib/types/utils/modifiers.d.ts.map +1 -1
- package/lib/types/utils/modifiers.js +3 -2
- package/lib/types/working-activity.d.ts +12 -0
- package/lib/types/working-activity.d.ts.map +1 -1
- package/lib/types/working-activity.js +13 -0
- package/lib/types/workspaces.d.ts +2 -1
- package/lib/types/workspaces.d.ts.map +1 -1
- package/lib/types/workspaces.js +1 -1
- package/node_modules/@dsh-std/command/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/command/LICENSE +21 -0
- package/node_modules/@dsh-std/command/README.md +26 -0
- package/node_modules/@dsh-std/command/README.zh.md +28 -0
- package/node_modules/@dsh-std/command/lib/index.d.ts +144 -0
- package/node_modules/@dsh-std/command/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/command/lib/index.js +252 -0
- package/node_modules/@dsh-std/command/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/command/package.json +22 -0
- package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/connection/LICENSE +21 -0
- package/node_modules/@dsh-std/connection/README.md +42 -0
- package/node_modules/@dsh-std/connection/README.zh.md +42 -0
- package/node_modules/@dsh-std/connection/lib/connection-CdGcSQnu.d.ts +125 -0
- package/node_modules/@dsh-std/connection/lib/connection-CdGcSQnu.d.ts.map +1 -0
- package/node_modules/@dsh-std/connection/lib/index.d.ts +89 -0
- package/node_modules/@dsh-std/connection/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/connection/lib/index.js +158 -0
- package/node_modules/@dsh-std/connection/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/connection/lib/memory.d.ts +24 -0
- package/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -0
- package/node_modules/@dsh-std/connection/lib/memory.js +258 -0
- package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -0
- package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js +226 -0
- package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -0
- package/node_modules/@dsh-std/connection/package.json +20 -0
- package/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/core/LICENSE +21 -0
- package/node_modules/@dsh-std/core/README.md +13 -0
- package/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/core/package.json +21 -0
- package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
- package/node_modules/@dsh-std/manifest/LICENSE +21 -0
- package/node_modules/@dsh-std/manifest/README.md +5 -0
- package/node_modules/@dsh-std/manifest/README.zh.md +5 -0
- package/node_modules/@dsh-std/manifest/lib/index.d.ts +182 -0
- package/node_modules/@dsh-std/manifest/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/manifest/lib/index.js +625 -0
- package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/manifest/package.json +20 -0
- package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -0
- package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/messages/LICENSE +21 -0
- package/node_modules/@dsh-std/messages/README.md +5 -0
- package/node_modules/@dsh-std/messages/README.zh.md +7 -0
- package/node_modules/@dsh-std/messages/lib/index.d.ts +50 -0
- package/node_modules/@dsh-std/messages/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/messages/lib/index.js +151 -0
- package/node_modules/@dsh-std/messages/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/messages/package.json +20 -0
- package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -0
- package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
- package/node_modules/@dsh-std/presentation/LICENSE +21 -0
- package/node_modules/@dsh-std/presentation/README.md +27 -0
- package/node_modules/@dsh-std/presentation/README.zh.md +29 -0
- package/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
- package/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
- package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
- package/node_modules/@dsh-std/presentation/lib/index.d.ts +262 -0
- package/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/presentation/lib/index.js +550 -0
- package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/presentation/lib/interaction.d.ts +2 -0
- package/node_modules/@dsh-std/presentation/lib/interaction.js +2 -0
- package/node_modules/@dsh-std/presentation/lib/operations.d.ts +2 -0
- package/node_modules/@dsh-std/presentation/lib/operations.js +2 -0
- package/node_modules/@dsh-std/presentation/package.json +25 -0
- package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/storage/LICENSE +21 -0
- package/node_modules/@dsh-std/storage/README.md +5 -0
- package/node_modules/@dsh-std/storage/README.zh.md +7 -0
- package/node_modules/@dsh-std/storage/lib/index.d.ts +48 -0
- package/node_modules/@dsh-std/storage/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/storage/lib/index.js +104 -0
- package/node_modules/@dsh-std/storage/lib/index.js.map +1 -0
- package/node_modules/@dsh-std/storage/package.json +20 -0
- package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -0
- package/package.json +110 -70
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/connection-CdGcSQnu.d.ts +125 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/connection-CdGcSQnu.d.ts.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.d.ts +89 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js +158 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts +24 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js +258 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js +226 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.d.ts +182 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js +625 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts +262 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js +550 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/interaction.d.ts +2 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/interaction.js +2 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/operations.d.ts +2 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/operations.js +2 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/connection-CdGcSQnu.d.ts +125 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/connection-CdGcSQnu.d.ts.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.d.ts +89 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js +158 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts +24 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js +258 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js +226 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.d.ts +112 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.d.ts.map +1 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js +424 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* storage.local contract surface (C-040, `storage.dsh/v1alpha1#LocalStorage`):
|
|
3
|
+
* per-plugin private persistence, mounted by the dsh-tui-plugin-host row as
|
|
4
|
+
* `ctx.tuiPluginStorage`.
|
|
5
|
+
*
|
|
6
|
+
* The plugin-facing API is `open(ctx)` → `{ get, set, delete }`:
|
|
7
|
+
*
|
|
8
|
+
* - VERIFIED IDENTITY: the namespace is derived from the admitted Component
|
|
9
|
+
* identity bound to the PASSED activation — there is no parameter to name
|
|
10
|
+
* another plugin, so cross-plugin access is rejected by construction.
|
|
11
|
+
* - GRANTS AT CALL TIME: `get` requires `storage.local.read`, `set`/`delete`
|
|
12
|
+
* require `storage.local.write` — checked per call against the live grant
|
|
13
|
+
* store (a revoked grant blocks the very next operation without restart).
|
|
14
|
+
* - Backend: `~/.dsh-tui/plugin-storage/<namespace>.json`, one flat JSON
|
|
15
|
+
* object per namespace. Writes go through dsh-atomic-write (`withFileLock`
|
|
16
|
+
* for the read-modify-write cycle + `writeFileAtomic` for the commit), and
|
|
17
|
+
* an in-process per-namespace promise chain serializes operations in
|
|
18
|
+
* invocation order (contract concurrency rule — the lock alone does not
|
|
19
|
+
* order contenders).
|
|
20
|
+
* - QUOTA (host-defined): 256 keys AND 256 KiB of serialized content per
|
|
21
|
+
* namespace; a `set` that would cross either fails with QUOTA_EXCEEDED and
|
|
22
|
+
* changes nothing.
|
|
23
|
+
* - Keys stay ordinary data even when they collide with Object.prototype
|
|
24
|
+
* names ("__proto__", "toString", "constructor"): namespace tables are
|
|
25
|
+
* null-prototype and membership is decided with Object.hasOwn. Values
|
|
26
|
+
* must be EXACT JSON values — inputs JSON.stringify would silently
|
|
27
|
+
* mutate (undefined, NaN/±Infinity, functions, class instances, sparse
|
|
28
|
+
* arrays, cycles) are rejected instead of round-tripping a lie.
|
|
29
|
+
* - A corrupt namespace file is NEVER overwritten silently: every operation
|
|
30
|
+
* fails with STORAGE_UNAVAILABLE and the bytes stay on disk for manual
|
|
31
|
+
* recovery. Closing a handle (plugin unload) retains data (contract
|
|
32
|
+
* cleanup rule); later calls on a closed handle fail STORAGE_UNAVAILABLE.
|
|
33
|
+
* - privacyClass: sensitive — keys AND values are never logged.
|
|
34
|
+
*/
|
|
35
|
+
import { mkdirSync, readFileSync } from 'node:fs';
|
|
36
|
+
import { join } from 'node:path';
|
|
37
|
+
import { writeFileAtomic, withFileLock } from '@deepseek-ai/dsh-atomic-write';
|
|
38
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
39
|
+
import { validateDeleteInput, validateGetInput, validateSetInput, validateGetOutput, validateSetOutput, validateDeleteOutput, } from '@dsh-std/storage';
|
|
40
|
+
import { DATA_DIR } from '../utils/paths.js';
|
|
41
|
+
import { activationContext, assertCallerContext, bindCallerEffect, compositionRoot, concreteService } from './host-access.js';
|
|
42
|
+
import { declaresPermission, requireComponentIdentity, requiresContract } from './component-identity.js';
|
|
43
|
+
import { readGrantStore } from './grants.js';
|
|
44
|
+
/** Quota: max distinct keys per namespace. */
|
|
45
|
+
export const STORAGE_MAX_KEYS = 256;
|
|
46
|
+
/** Quota: max serialized file size per namespace (bytes). */
|
|
47
|
+
export const STORAGE_MAX_BYTES = 256 * 1024;
|
|
48
|
+
/** Max key length (characters). */
|
|
49
|
+
export const STORAGE_KEY_MAX_LENGTH = 128;
|
|
50
|
+
/** Storage failure with the contract's error code on `.code`. */
|
|
51
|
+
export class PluginStorageError extends Error {
|
|
52
|
+
code;
|
|
53
|
+
constructor(code, message) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.name = 'PluginStorageError';
|
|
56
|
+
this.code = code;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const storageStates = new WeakMap();
|
|
60
|
+
function storageStateFor(runtime) {
|
|
61
|
+
const state = storageStates.get(concreteService(runtime));
|
|
62
|
+
if (state === undefined)
|
|
63
|
+
throw new Error('tuiPluginStorage host state is unavailable');
|
|
64
|
+
return state;
|
|
65
|
+
}
|
|
66
|
+
/** Namespace directory under the data dir. */
|
|
67
|
+
export const PLUGIN_STORAGE_DIR = 'plugin-storage';
|
|
68
|
+
/**
|
|
69
|
+
* Plugin name → safe, collision-free file name. encodeURIComponent keeps
|
|
70
|
+
* alphanumerics and `- _ . ! ~ * ' ( )`, so scoped names like `@foo/bar`
|
|
71
|
+
* encode reversibly; pathological results ('', '.', '..') map to '_'.
|
|
72
|
+
*/
|
|
73
|
+
export function storageFileName(plugin) {
|
|
74
|
+
const encoded = encodeURIComponent(plugin);
|
|
75
|
+
return encoded === '' || encoded === '.' || encoded === '..' ? '_' : encoded;
|
|
76
|
+
}
|
|
77
|
+
function assertKey(key) {
|
|
78
|
+
if (typeof key !== 'string' || key === '' || key.length > STORAGE_KEY_MAX_LENGTH || /[\x00-\x1f\x7f-\x9f]/.test(key)) {
|
|
79
|
+
throw new PluginStorageError('INVALID_KEY', 'storage keys are non-empty control-free strings of at most 128 characters');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function validateStorageInput(operation, input) {
|
|
83
|
+
try {
|
|
84
|
+
if (operation === 'get')
|
|
85
|
+
validateGetInput(input);
|
|
86
|
+
else if (operation === 'set')
|
|
87
|
+
validateSetInput(input);
|
|
88
|
+
else
|
|
89
|
+
validateDeleteInput(input);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
93
|
+
if (operation !== 'set')
|
|
94
|
+
throw new PluginStorageError('INVALID_KEY', message);
|
|
95
|
+
// The standard validator intentionally reports exact-record failures in a
|
|
96
|
+
// single stream. Preserve the contract's distinction: malformed/missing
|
|
97
|
+
// `key` is INVALID_KEY; once the key itself is valid, every value/shape
|
|
98
|
+
// failure (including a missing `value`) is INVALID_VALUE.
|
|
99
|
+
let keyValid = false;
|
|
100
|
+
try {
|
|
101
|
+
const candidate = input;
|
|
102
|
+
assertKey(candidate?.key);
|
|
103
|
+
keyValid = true;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
keyValid = false;
|
|
107
|
+
}
|
|
108
|
+
throw new PluginStorageError(keyValid ? 'INVALID_VALUE' : 'INVALID_KEY', message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Exact JSON values only. JSON.stringify silently MUTATES edge inputs
|
|
113
|
+
* (NaN/±Infinity → null, undefined array items → null, undefined object
|
|
114
|
+
* properties dropped, class instances reduced to own fields) — a storage
|
|
115
|
+
* contract must not round-trip a value the caller never stored, so those
|
|
116
|
+
* inputs are rejected instead. Accepts: null, boolean, string, finite
|
|
117
|
+
* number, arrays (dense), and plain objects (Object.prototype or null
|
|
118
|
+
* prototype only). Every own property is inspected because JSON.stringify
|
|
119
|
+
* ignores array side-properties, symbols, and non-enumerable fields, while
|
|
120
|
+
* accessors/toJSON can replace the value being serialized. Those inputs,
|
|
121
|
+
* cycles, and anything whose inspection throws are rejected.
|
|
122
|
+
*/
|
|
123
|
+
function assertJsonValue(value) {
|
|
124
|
+
let ok = false;
|
|
125
|
+
try {
|
|
126
|
+
ok = isJsonValue(value, new Set());
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
ok = false;
|
|
130
|
+
}
|
|
131
|
+
if (!ok) {
|
|
132
|
+
throw new PluginStorageError('INVALID_VALUE', 'storage values must be exact JSON values (no undefined, functions, symbols, BigInt, NaN/Infinity, class instances, sparse arrays, or cycles)');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function isJsonValue(value, seen) {
|
|
136
|
+
if (value === null)
|
|
137
|
+
return true;
|
|
138
|
+
switch (typeof value) {
|
|
139
|
+
case 'boolean':
|
|
140
|
+
case 'string':
|
|
141
|
+
return true;
|
|
142
|
+
case 'number':
|
|
143
|
+
return Number.isFinite(value);
|
|
144
|
+
case 'object': {
|
|
145
|
+
const object = value;
|
|
146
|
+
if (seen.has(object))
|
|
147
|
+
return false;
|
|
148
|
+
seen.add(object);
|
|
149
|
+
try {
|
|
150
|
+
if (Array.isArray(value)) {
|
|
151
|
+
// Array subclasses/custom prototypes can supply an inherited toJSON
|
|
152
|
+
// hook. JSON would serialize its replacement, not this array.
|
|
153
|
+
if (Object.getPrototypeOf(value) !== Array.prototype)
|
|
154
|
+
return false;
|
|
155
|
+
if (Object.getOwnPropertySymbols(value).length > 0)
|
|
156
|
+
return false;
|
|
157
|
+
const ownNames = Object.getOwnPropertyNames(value);
|
|
158
|
+
for (const name of ownNames) {
|
|
159
|
+
if (name === 'length')
|
|
160
|
+
continue;
|
|
161
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, name);
|
|
162
|
+
// JSON arrays serialize only their indexed elements. Any other
|
|
163
|
+
// own property (especially toJSON) would be silently lost.
|
|
164
|
+
const index = Number(name);
|
|
165
|
+
if (descriptor === undefined || !('value' in descriptor) ||
|
|
166
|
+
!Number.isSafeInteger(index) || index < 0 || String(index) !== name || index >= value.length)
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
for (let index = 0; index < value.length; index++) {
|
|
170
|
+
// A sparse hole would serialize as null — a value never stored.
|
|
171
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
172
|
+
if (descriptor === undefined || !('value' in descriptor))
|
|
173
|
+
return false;
|
|
174
|
+
if (!isJsonValue(descriptor.value, seen))
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
const proto = Object.getPrototypeOf(value);
|
|
180
|
+
if (proto !== Object.prototype && proto !== null)
|
|
181
|
+
return false;
|
|
182
|
+
// A modified Object.prototype can add an inherited toJSON hook; own
|
|
183
|
+
// non-enumerable/accessor properties are likewise not exact JSON.
|
|
184
|
+
if (typeof value.toJSON === 'function')
|
|
185
|
+
return false;
|
|
186
|
+
if (Object.getOwnPropertySymbols(value).length > 0)
|
|
187
|
+
return false;
|
|
188
|
+
for (const name of Object.getOwnPropertyNames(value)) {
|
|
189
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, name);
|
|
190
|
+
if (descriptor === undefined || !descriptor.enumerable || !('value' in descriptor))
|
|
191
|
+
return false;
|
|
192
|
+
if (!isJsonValue(descriptor.value, seen))
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
// DAGs (shared references without cycles) serialize fine — only
|
|
199
|
+
// reject a value reachable from ITSELF.
|
|
200
|
+
seen.delete(object);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
default:
|
|
204
|
+
// undefined / function / symbol / bigint
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* `ctx.tuiPluginStorage` — storage.local contract surface. Mounted by the
|
|
210
|
+
* dsh-tui-plugin-host row; grants come from that row's store when present
|
|
211
|
+
* (normal path) or a private read otherwise (bare mounts in tests).
|
|
212
|
+
*/
|
|
213
|
+
export class TuiPluginStorageRuntime extends Service {
|
|
214
|
+
constructor(ctx, options = {}) {
|
|
215
|
+
super(ctx, 'tuiPluginStorage');
|
|
216
|
+
storageStates.set(this, {
|
|
217
|
+
hostContext: compositionRoot(ctx),
|
|
218
|
+
grantsOption: options.grants,
|
|
219
|
+
fallbackGrants: readGrantStore(),
|
|
220
|
+
ledgerOption: options.ledger,
|
|
221
|
+
namespaces: new Map(),
|
|
222
|
+
dir: options.dir ?? join(DATA_DIR, PLUGIN_STORAGE_DIR),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/** Grants: the plugin-host row's store when mounted, else a private read.
|
|
226
|
+
* Resolved PER CALL — sibling services mounted later by the same apply()
|
|
227
|
+
* are not visible to constructors (cordis), so a constructor-time probe
|
|
228
|
+
* would silently stick to the fallback. */
|
|
229
|
+
grants() {
|
|
230
|
+
const state = storageStateFor(this);
|
|
231
|
+
return state.grantsOption ?? state.hostContext.get('tuiPluginHost')?.grants ?? state.fallbackGrants;
|
|
232
|
+
}
|
|
233
|
+
/** Optional observability; a bare mount (tests) simply records nothing. */
|
|
234
|
+
ledger() {
|
|
235
|
+
const state = storageStateFor(this);
|
|
236
|
+
return state.ledgerOption ?? state.hostContext.get('tuiEffectLedger');
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Open the caller's private namespace. Identity = the PASSED context's
|
|
240
|
+
* verified Component identity (no way to name another plugin). The handle
|
|
241
|
+
* closes automatically when the caller's context unloads (idempotent
|
|
242
|
+
* disposer); data is retained (contract cleanup rule).
|
|
243
|
+
*/
|
|
244
|
+
open(pluginCtx) {
|
|
245
|
+
const caller = activationContext(pluginCtx);
|
|
246
|
+
if (caller === undefined)
|
|
247
|
+
throw new PluginStorageError('STORAGE_UNAVAILABLE', 'storage.local.open requires a live activation context');
|
|
248
|
+
assertCallerContext(this.ctx, caller, 'storage.local.open', this);
|
|
249
|
+
const state = storageStateFor(this);
|
|
250
|
+
const identity = requireComponentIdentity(caller);
|
|
251
|
+
if (!requiresContract(identity, 'storage.dsh/v1alpha1', 'LocalStorage')) {
|
|
252
|
+
throw new PluginStorageError('PERMISSION_NOT_GRANTED', 'storage.local requires the storage.dsh/v1alpha1#LocalStorage contract in the admitted manifest');
|
|
253
|
+
}
|
|
254
|
+
const plugin = identity.componentId;
|
|
255
|
+
let namespace = state.namespaces.get(plugin);
|
|
256
|
+
if (namespace === undefined) {
|
|
257
|
+
namespace = { chain: Promise.resolve() };
|
|
258
|
+
state.namespaces.set(plugin, namespace);
|
|
259
|
+
}
|
|
260
|
+
this.ledger()?.record({ operation: 'create', resource: { kind: 'storage-namespace', id: plugin }, result: 'applied' }, caller);
|
|
261
|
+
// `closed` is PER HANDLE, not per namespace: unloading one fiber must not
|
|
262
|
+
// kill another handle opened on the same namespace. Close on unload;
|
|
263
|
+
// idempotent (a double-close stays harmless by design).
|
|
264
|
+
let closed = false;
|
|
265
|
+
const close = () => {
|
|
266
|
+
if (closed)
|
|
267
|
+
return;
|
|
268
|
+
closed = true;
|
|
269
|
+
this.ledger()?.record({ operation: 'release', resource: { kind: 'storage-namespace', id: plugin }, result: 'applied' }, caller);
|
|
270
|
+
};
|
|
271
|
+
bindCallerEffect(caller, close);
|
|
272
|
+
const file = join(state.dir, `${storageFileName(plugin)}.json`);
|
|
273
|
+
const grants = () => this.grants();
|
|
274
|
+
const ledger = () => this.ledger();
|
|
275
|
+
const enqueue = (operation) => {
|
|
276
|
+
if (closed) {
|
|
277
|
+
return Promise.reject(new PluginStorageError('STORAGE_UNAVAILABLE', `storage namespace "${plugin}" handle is closed`));
|
|
278
|
+
}
|
|
279
|
+
const run = namespace.chain.then(operation);
|
|
280
|
+
// Keep the chain alive after a failure without unhandled rejections.
|
|
281
|
+
namespace.chain = run.catch(() => { });
|
|
282
|
+
return run;
|
|
283
|
+
};
|
|
284
|
+
const readTable = () => {
|
|
285
|
+
let raw;
|
|
286
|
+
try {
|
|
287
|
+
raw = readFileSync(file, 'utf8');
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
if (error.code === 'ENOENT')
|
|
291
|
+
return Object.create(null);
|
|
292
|
+
throw new PluginStorageError('STORAGE_UNAVAILABLE', `storage namespace "${plugin}" is unreadable; the file was left untouched for manual recovery`);
|
|
293
|
+
}
|
|
294
|
+
let parsed;
|
|
295
|
+
try {
|
|
296
|
+
parsed = JSON.parse(raw);
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
throw new PluginStorageError('STORAGE_UNAVAILABLE', `storage namespace "${plugin}" is corrupt on disk; the file was left untouched for manual recovery`);
|
|
300
|
+
}
|
|
301
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
302
|
+
throw new PluginStorageError('STORAGE_UNAVAILABLE', `storage namespace "${plugin}" holds a non-object document; the file was left untouched for manual recovery`);
|
|
303
|
+
}
|
|
304
|
+
// Rebuild on a NULL-PROTOTYPE table: key membership is decided with
|
|
305
|
+
// Object.hasOwn, and keys like "__proto__" / "toString" must behave
|
|
306
|
+
// as ordinary data (a prototype-chain read would leak host objects
|
|
307
|
+
// into plugin results and fake membership for never-stored keys).
|
|
308
|
+
const table = Object.create(null);
|
|
309
|
+
for (const [key, value] of Object.entries(parsed))
|
|
310
|
+
table[key] = value;
|
|
311
|
+
return table;
|
|
312
|
+
};
|
|
313
|
+
const requireGrant = (permission) => {
|
|
314
|
+
if (!declaresPermission(identity, permission, plugin)
|
|
315
|
+
|| !grants().allows({ componentId: identity.componentId, activationId: identity.activationId }, permission, plugin)) {
|
|
316
|
+
ledger()?.record({
|
|
317
|
+
operation: 'bind',
|
|
318
|
+
resource: { kind: 'permission', id: permission },
|
|
319
|
+
result: 'failed',
|
|
320
|
+
errorCode: 'PERMISSION_NOT_GRANTED',
|
|
321
|
+
}, caller);
|
|
322
|
+
throw new PluginStorageError('PERMISSION_NOT_GRANTED', `storage.${permission.endsWith('.read') ? 'get' : 'set/delete'} from plugin "${plugin}" denied — grant "${permission}" ` +
|
|
323
|
+
`for "${plugin}" in ~/.dsh-tui/extension-grants.json first`);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
// withFileLock creates its lock as a SIBLING of the file and does not
|
|
327
|
+
// create parent directories — ensure the tree exists before any write
|
|
328
|
+
// path (read paths tolerate ENOENT as an empty namespace and never
|
|
329
|
+
// materialize the tree).
|
|
330
|
+
const ensureDir = () => {
|
|
331
|
+
mkdirSync(state.dir, { recursive: true, mode: 0o700 });
|
|
332
|
+
};
|
|
333
|
+
return {
|
|
334
|
+
get: (input) => enqueue(async () => {
|
|
335
|
+
validateStorageInput('get', input);
|
|
336
|
+
const key = input.key;
|
|
337
|
+
assertKey(key);
|
|
338
|
+
requireGrant('storage.local.read');
|
|
339
|
+
const table = readTable();
|
|
340
|
+
const output = { value: Object.hasOwn(table, key) ? table[key] : null };
|
|
341
|
+
try {
|
|
342
|
+
validateGetOutput(output);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
throw new PluginStorageError('STORAGE_UNAVAILABLE', `storage namespace "${plugin}" contains an invalid JSON value`);
|
|
346
|
+
}
|
|
347
|
+
return output;
|
|
348
|
+
}),
|
|
349
|
+
set: (input) => enqueue(async () => {
|
|
350
|
+
validateStorageInput('set', input);
|
|
351
|
+
const key = input.key;
|
|
352
|
+
const value = input.value;
|
|
353
|
+
assertKey(key);
|
|
354
|
+
assertJsonValue(value);
|
|
355
|
+
requireGrant('storage.local.write');
|
|
356
|
+
ensureDir();
|
|
357
|
+
return withFileLock(file, async () => {
|
|
358
|
+
const table = readTable();
|
|
359
|
+
const isNewKey = !Object.hasOwn(table, key);
|
|
360
|
+
if (isNewKey && Object.keys(table).length >= STORAGE_MAX_KEYS) {
|
|
361
|
+
throw new PluginStorageError('QUOTA_EXCEEDED', `storage namespace "${plugin}" holds ${STORAGE_MAX_KEYS} keys already`);
|
|
362
|
+
}
|
|
363
|
+
table[key] = value;
|
|
364
|
+
const content = JSON.stringify(table);
|
|
365
|
+
if (Buffer.byteLength(content, 'utf8') > STORAGE_MAX_BYTES) {
|
|
366
|
+
throw new PluginStorageError('QUOTA_EXCEEDED', `storage namespace "${plugin}" would exceed ${STORAGE_MAX_BYTES} bytes`);
|
|
367
|
+
}
|
|
368
|
+
// 0o600/0o700: the namespace is privacyClass sensitive.
|
|
369
|
+
await writeFileAtomic(file, content, { mode: 0o600, dirMode: 0o700 });
|
|
370
|
+
const output = { stored: true };
|
|
371
|
+
validateSetOutput(output);
|
|
372
|
+
return output;
|
|
373
|
+
});
|
|
374
|
+
}),
|
|
375
|
+
delete: (input) => enqueue(async () => {
|
|
376
|
+
validateStorageInput('delete', input);
|
|
377
|
+
const key = input.key;
|
|
378
|
+
assertKey(key);
|
|
379
|
+
requireGrant('storage.local.write');
|
|
380
|
+
ensureDir();
|
|
381
|
+
return withFileLock(file, async () => {
|
|
382
|
+
const table = readTable();
|
|
383
|
+
if (!Object.hasOwn(table, key)) {
|
|
384
|
+
const output = { deleted: false };
|
|
385
|
+
validateDeleteOutput(output);
|
|
386
|
+
return output;
|
|
387
|
+
}
|
|
388
|
+
delete table[key];
|
|
389
|
+
await writeFileAtomic(file, JSON.stringify(table), { mode: 0o600, dirMode: 0o700 });
|
|
390
|
+
const output = { deleted: true };
|
|
391
|
+
validateDeleteOutput(output);
|
|
392
|
+
return output;
|
|
393
|
+
});
|
|
394
|
+
}),
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAGhE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAmCnC;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmmBvE;AA6GD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CAAE,GAAG;IACjF,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,YAAY,EAAE,MAAM,IAAI,CAAA;CACzB,CAcA;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,KAAK,GAAG,SAAS,CAAA;IAC5B,YAAY,EAAE,KAAK,CAAA;CACpB,GAAG,OAAO,CAQV"}
|
|
@@ -21,12 +21,17 @@ import { ensurePackagedPresets } from './packaged-presets.js';
|
|
|
21
21
|
import { ensureLegacySessionEventTypes } from './compat/index.js';
|
|
22
22
|
import { clearResumeTarget, writeResumeTarget } from '../sessionHistory.js';
|
|
23
23
|
import { resolveSessionCwd } from '../utils/workspaceRoot.js';
|
|
24
|
-
import { checkForTuiUpdate, installedTuiVersion, isVersionNewer, resolveDshProfileName, resolveTuiUpdateTarget, updateTuiAndRestart } from '../update.js';
|
|
25
|
-
import { isLang, resolveStartupLang, setLang, t } from '../i18n.js';
|
|
24
|
+
import { checkForTuiUpdate, installedTuiVersion, isBootDeadlockTarget, isVersionNewer, resolveDshProfileName, resolveTuiUpdateTarget, updateTuiAndRestart } from '../update.js';
|
|
25
|
+
import { getLang, isLang, resolveStartupLang, setLang, t, writeLangPref } from '../i18n.js';
|
|
26
26
|
import { detectLegacyEnv, migrateLegacyDataDir, RENAMED_ENV } from '../utils/paths.js';
|
|
27
27
|
import { Chat } from '../screens/Chat.js';
|
|
28
|
+
import { getHostDialogStore } from './dialogs.js';
|
|
29
|
+
import { getHostStatusStore } from './status.js';
|
|
30
|
+
import { getHostShortcuts } from './shortcuts.js';
|
|
28
31
|
import { attachSessionToWorkspace } from './workspace.js';
|
|
29
|
-
import { createLocalWorkspaceRuntime } from './workspaces.js';
|
|
32
|
+
import { createLocalWorkspaceRuntime, getHostWorkspaceRuntime } from './workspaces.js';
|
|
33
|
+
import { getHostSettingsSections } from './settings-sections.js';
|
|
34
|
+
import { withHostRootCapability } from './host-access.js';
|
|
30
35
|
import { render, ThemeProvider, AlternateScreen } from '../ui.js';
|
|
31
36
|
import instances from '../ink/instances.js';
|
|
32
37
|
import { cursorMove, DISABLE_KITTY_KEYBOARD, DISABLE_MODIFY_OTHER_KEYS, DISABLE_WIN32_INPUT_MODE } from '../ink/termio/csi.js';
|
|
@@ -66,10 +71,11 @@ export async function apply(ctx, config) {
|
|
|
66
71
|
// already touches lang.json). Copy, not move — old launchers keep working
|
|
67
72
|
// and the user deletes the legacy directory themselves.
|
|
68
73
|
const migrated = migrateLegacyDataDir();
|
|
69
|
-
// UI language resolution: DSH_TUI_LANG env var wins, then
|
|
70
|
-
// `lang
|
|
71
|
-
//
|
|
72
|
-
//
|
|
74
|
+
// UI language resolution: DSH_TUI_LANG env var wins, then the
|
|
75
|
+
// settings.yaml `dsh-tui.lang` user layer (applied once the settings
|
|
76
|
+
// namespace registers below), then cordis.yml `lang`, then the
|
|
77
|
+
// persisted `/lang` choice, then `zh`. Must settle before the first
|
|
78
|
+
// render so every module resolves strings in the same language.
|
|
73
79
|
const envLang = process.env.DSH_TUI_LANG;
|
|
74
80
|
setLang(isLang(envLang) ? envLang : isLang(config.lang) ? config.lang : resolveStartupLang());
|
|
75
81
|
// Rename notices must land before the first render — stderr writes break
|
|
@@ -211,7 +217,7 @@ export async function apply(ctx, config) {
|
|
|
211
217
|
// without the service means the patch came from an older dsh-tui copy
|
|
212
218
|
// than the running code — warn once so the skew is diagnosable. Bare
|
|
213
219
|
// embedders (no --profile) take the same fallback by design, silently.
|
|
214
|
-
const mountedWorkspaceService = ctx.get('tuiWorkspaces');
|
|
220
|
+
const mountedWorkspaceService = getHostWorkspaceRuntime(ctx.get('tuiWorkspaces'));
|
|
215
221
|
if (mountedWorkspaceService === undefined && resolveDshProfileName() !== undefined) {
|
|
216
222
|
ctx.logger.warn('dsh-tui: tuiWorkspaces service is not mounted; /workspace runs with the local-only fallback. ' +
|
|
217
223
|
'The bundle patch is older than the installed dsh-tui package — update the globally installed dsh-tui launcher to match the profile (issue #183).');
|
|
@@ -225,6 +231,24 @@ export async function apply(ctx, config) {
|
|
|
225
231
|
ctx.logger.warn('dsh-tui: tuiScenes service is not mounted; plugin scenes will never open. ' +
|
|
226
232
|
'The bundle patch is older than the installed dsh-tui package — update the globally installed dsh-tui launcher to match the profile (issue #183).');
|
|
227
233
|
}
|
|
234
|
+
// Same skew guard for the plugin-UI services (dsh-tui-extensions row):
|
|
235
|
+
// managed dialogs park unanswered, status contributions never render,
|
|
236
|
+
// shortcuts never match, and custom-entry renderers stay invisible when
|
|
237
|
+
// the row is absent — say why on profile launches.
|
|
238
|
+
if (ctx.get('tuiDialogs') === undefined && resolveDshProfileName() !== undefined) {
|
|
239
|
+
ctx.logger.warn('dsh-tui: tuiDialogs/tuiStatus/tuiShortcuts/tuiRenderers services are not mounted; plugin dialogs, status contributions, shortcuts and custom-entry renderers are off. ' +
|
|
240
|
+
'The bundle patch is older than the installed dsh-tui package — update the globally installed dsh-tui launcher to match the profile (issue #183).');
|
|
241
|
+
}
|
|
242
|
+
// Same skew guard for the plugin-host row (dsh-tui-plugin-host): without
|
|
243
|
+
// it there is no runtime generation id, no unified grant store service,
|
|
244
|
+
// and no Host Descriptor — plugin interop surfaces degrade silently
|
|
245
|
+
// otherwise. The D-7 decision gate does NOT depend on this row (the
|
|
246
|
+
// channel installs its own), so interception gating stays intact either
|
|
247
|
+
// way — what breaks is everything that rides on tuiPluginHost.
|
|
248
|
+
if (ctx.get('tuiPluginHost') === undefined && resolveDshProfileName() !== undefined) {
|
|
249
|
+
ctx.logger.warn('dsh-tui: tuiPluginHost service is not mounted; plugin grant store, runtime generation and Host Descriptor are unavailable. ' +
|
|
250
|
+
'The bundle patch is older than the installed dsh-tui package — update the globally installed dsh-tui launcher to match the profile (issue #183).');
|
|
251
|
+
}
|
|
228
252
|
const initialWorkspace = requestedWorkspace === undefined
|
|
229
253
|
? undefined
|
|
230
254
|
: await workspaceService.resolve(requestedWorkspace);
|
|
@@ -284,6 +308,7 @@ export async function apply(ctx, config) {
|
|
|
284
308
|
// Edit/Write diff presentation (schema default 'auto'); the /settings
|
|
285
309
|
// screen edits this key live through the dsh-tui namespace.
|
|
286
310
|
diffLayout: config.diffLayout,
|
|
311
|
+
thinkingFold: config.thinkingFold,
|
|
287
312
|
handle,
|
|
288
313
|
});
|
|
289
314
|
// Register the dsh-tui settings namespace so the /settings screen can
|
|
@@ -293,24 +318,69 @@ export async function apply(ctx, config) {
|
|
|
293
318
|
ctx.inject(['settings'], (settingsCtx) => {
|
|
294
319
|
const scope = settingsCtx.settings.register(settingsNamespace('dsh-tui'), Schema.object({
|
|
295
320
|
diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
|
|
321
|
+
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
322
|
+
// No default on purpose: an unset `lang` keeps the field showing
|
|
323
|
+
// the effective language (see the section's format below) and lets
|
|
324
|
+
// cordis.yml / lang.json keep their precedence.
|
|
325
|
+
lang: Schema.union(['zh', 'en']),
|
|
296
326
|
}));
|
|
297
327
|
const applyLayout = (value) => {
|
|
298
328
|
channel.setDiffLayout(value.diffLayout ?? config.diffLayout ?? 'auto');
|
|
299
329
|
};
|
|
300
|
-
|
|
301
|
-
|
|
330
|
+
// The /settings language field writes `lang` through the settings
|
|
331
|
+
// service (user layer): apply it live and mirror it to lang.json so
|
|
332
|
+
// the /lang command and next-boot resolution agree. DSH_TUI_LANG
|
|
333
|
+
// stays the top precedence — a pinned env is never overridden by the
|
|
334
|
+
// document.
|
|
335
|
+
const applyLang = (value) => {
|
|
336
|
+
if (!isLang(process.env.DSH_TUI_LANG) && isLang(value.lang)) {
|
|
337
|
+
setLang(value.lang);
|
|
338
|
+
writeLangPref(value.lang);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
// thinkingFold rides the same namespace: /settings writes it live and
|
|
342
|
+
// the channel picks it up at the next step seal.
|
|
343
|
+
const applyThinkingFold = (value) => {
|
|
344
|
+
channel.setThinkingFold(value.thinkingFold ?? config.thinkingFold ?? 'preview');
|
|
345
|
+
};
|
|
346
|
+
const apply = (next) => {
|
|
302
347
|
applyLayout(next);
|
|
348
|
+
applyLang(next);
|
|
349
|
+
applyThinkingFold(next);
|
|
350
|
+
};
|
|
351
|
+
apply(scope.get());
|
|
352
|
+
scope.watch(next => {
|
|
353
|
+
apply(next);
|
|
303
354
|
});
|
|
304
355
|
});
|
|
305
356
|
// The /settings screen's own section: the dsh-tui namespace comes from
|
|
306
|
-
//
|
|
307
|
-
// back through the settings service's revision-fenced
|
|
308
|
-
|
|
357
|
+
// the settings registration above, and the declared selects write `lang`
|
|
358
|
+
// and `diffLayout` back through the settings service's revision-fenced
|
|
359
|
+
// mutate (the watch applies both live).
|
|
360
|
+
const settingsSections = getHostSettingsSections(ctx.get('tuiSettingsSections'));
|
|
309
361
|
if (settingsSections !== undefined) {
|
|
310
362
|
const unregister = settingsSections.register({
|
|
311
363
|
ns: 'dsh-tui',
|
|
312
364
|
title: 'dsh-tui',
|
|
313
365
|
fields: [
|
|
366
|
+
{
|
|
367
|
+
path: ['lang'],
|
|
368
|
+
label: 'Language',
|
|
369
|
+
descriptions: { zh: '界面语言' },
|
|
370
|
+
hint: 'UI language for the whole interface — applies immediately and is saved.',
|
|
371
|
+
hintDescriptions: { zh: '整个界面的显示语言——立即生效并保存。' },
|
|
372
|
+
kind: 'select',
|
|
373
|
+
options: [
|
|
374
|
+
{ value: 'zh', label: '中文', descriptions: { zh: '中文' } },
|
|
375
|
+
{ value: 'en', label: 'English', descriptions: { zh: '英文' } },
|
|
376
|
+
],
|
|
377
|
+
format(value) {
|
|
378
|
+
// Unset in settings.yaml: show the effective UI language
|
|
379
|
+
// (env / cordis.yml / lang.json resolution) instead of a
|
|
380
|
+
// blank "unset" that hides the current choice.
|
|
381
|
+
return value === undefined || value === null ? getLang() : String(value);
|
|
382
|
+
},
|
|
383
|
+
},
|
|
314
384
|
{
|
|
315
385
|
path: ['diffLayout'],
|
|
316
386
|
label: 'Diff layout',
|
|
@@ -324,6 +394,18 @@ export async function apply(ctx, config) {
|
|
|
324
394
|
{ value: 'unified', label: 'Unified', descriptions: { zh: '统一式' } },
|
|
325
395
|
],
|
|
326
396
|
},
|
|
397
|
+
{
|
|
398
|
+
path: ['thinkingFold'],
|
|
399
|
+
label: 'Thinking display',
|
|
400
|
+
descriptions: { zh: '思考块展示' },
|
|
401
|
+
hint: 'Streaming thinking shows a 2-3 line live preview and each step folds when it settles; Full keeps thinking expanded until the turn ends.',
|
|
402
|
+
hintDescriptions: { zh: '流式时思考显示 2-3 行动态预览,每步落定后折叠;展开模式保持思考展开直到整轮结束。' },
|
|
403
|
+
kind: 'select',
|
|
404
|
+
options: [
|
|
405
|
+
{ value: 'preview', label: 'Preview (2-3 lines)', descriptions: { zh: '预览(2-3 行)' } },
|
|
406
|
+
{ value: 'full', label: 'Full until turn end', descriptions: { zh: '展开至轮末' } },
|
|
407
|
+
],
|
|
408
|
+
},
|
|
327
409
|
],
|
|
328
410
|
});
|
|
329
411
|
ctx.effect(() => unregister);
|
|
@@ -428,6 +510,12 @@ export async function apply(ctx, config) {
|
|
|
428
510
|
channel,
|
|
429
511
|
questionStore,
|
|
430
512
|
approvalStore,
|
|
513
|
+
// The dsh-tui-extensions row's services (managed dialogs, status line,
|
|
514
|
+
// shortcuts). Soft-consumed: absent the row (stale patch, bare embed),
|
|
515
|
+
// Chat falls back to inert stores and no shortcut registry.
|
|
516
|
+
extensionDialogs: getHostDialogStore(ctx.get('tuiDialogs')),
|
|
517
|
+
extensionStatus: getHostStatusStore(ctx.get('tuiStatus')),
|
|
518
|
+
extensionShortcuts: getHostShortcuts(ctx.get('tuiShortcuts')),
|
|
431
519
|
// Full-screen surfaces inside Chat — the trajectory scene and the session
|
|
432
520
|
// browser — enter the alt screen themselves in inline mode; in fullscreen
|
|
433
521
|
// the tree is already wrapped below, so they must not nest.
|
|
@@ -453,6 +541,21 @@ export async function apply(ctx, config) {
|
|
|
453
541
|
channel.notify(t('update-check-failed'));
|
|
454
542
|
}
|
|
455
543
|
else {
|
|
544
|
+
// 0.7.0/0.7.1 hard-inject tuiWorkspaces at the code level; under
|
|
545
|
+
// an older global launcher patch (no service row) that is a
|
|
546
|
+
// permanent boot deadlock (issues #183/#307, the exact report
|
|
547
|
+
// "pending (waiting for service: tuiWorkspaces)"). A stale mirror
|
|
548
|
+
// pinning /update onto that range must be refused, not installed.
|
|
549
|
+
if (isBootDeadlockTarget(target.latest)) {
|
|
550
|
+
channel.notify(t('update-refused-deadlock', {
|
|
551
|
+
latest: target.latest,
|
|
552
|
+
authoritative: target.authoritative ?? target.latest,
|
|
553
|
+
}), { color: 'warning' });
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (target.authoritative !== undefined) {
|
|
557
|
+
channel.notify(t('update-mirror-lag', { latest: target.latest, authoritative: target.authoritative }));
|
|
558
|
+
}
|
|
456
559
|
updateTargetVersion = target.latest;
|
|
457
560
|
}
|
|
458
561
|
channel.notify(t('update-starting'));
|
|
@@ -644,6 +747,11 @@ async function finishExit(ctx, instance, fullscreen, notice, stderrNotice, done)
|
|
|
644
747
|
const cursor = fullscreen ? '' : cursorMoveToFrameEnd(runtime);
|
|
645
748
|
try {
|
|
646
749
|
runtime?.detachForShutdown?.();
|
|
750
|
+
// The /update continuation spawns children that inherit this stdin;
|
|
751
|
+
// strip the readable pump so the parent cannot swallow their input
|
|
752
|
+
// (issues #284/#307). Harmless on plain exits — the process exits
|
|
753
|
+
// right after this cleanup anyway.
|
|
754
|
+
runtime?.detachStdinForHandoff?.();
|
|
647
755
|
}
|
|
648
756
|
catch {
|
|
649
757
|
ctx.logger.debug('dsh-tui: Ink shutdown detach failed; continuing with generic terminal cleanup');
|
|
@@ -678,6 +786,8 @@ function readInkShutdownState(value) {
|
|
|
678
786
|
const candidate = value;
|
|
679
787
|
if (candidate.detachForShutdown !== undefined && typeof candidate.detachForShutdown !== 'function')
|
|
680
788
|
return undefined;
|
|
789
|
+
if (candidate.detachStdinForHandoff !== undefined && typeof candidate.detachStdinForHandoff !== 'function')
|
|
790
|
+
return undefined;
|
|
681
791
|
if (candidate.frontFrame !== undefined && !isFrameState(candidate.frontFrame))
|
|
682
792
|
return undefined;
|
|
683
793
|
if (candidate.displayCursor !== undefined && candidate.displayCursor !== null && !isCursorState(candidate.displayCursor))
|
|
@@ -778,7 +888,7 @@ function resumeCommand(profile, sessionId) {
|
|
|
778
888
|
function disposeRootAndThen(ctx, done, fallbackCode = 1) {
|
|
779
889
|
const timer = setTimeout(() => process.exit(fallbackCode), 5000);
|
|
780
890
|
timer.unref();
|
|
781
|
-
void ctx.root.fiber.dispose().then(() => {
|
|
891
|
+
void withHostRootCapability(() => ctx.root.fiber.dispose()).then(() => {
|
|
782
892
|
clearTimeout(timer);
|
|
783
893
|
done();
|
|
784
894
|
}, () => {
|