@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,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin keyboard shortcuts — pi's `pi.registerShortcut`. A plugin binds a
|
|
3
|
+
* combo (`ctrl+shift+p`, `alt+k`, …) to a handler; the chat screen matches
|
|
4
|
+
* combos against keypresses that survived every built-in binding and runs
|
|
5
|
+
* the handler, consuming the key.
|
|
6
|
+
*
|
|
7
|
+
* Precedence rule (same philosophy as the command list: a plugin shadows
|
|
8
|
+
* nothing built in):
|
|
9
|
+
*
|
|
10
|
+
* - Combos must carry ctrl or alt (meta) — bare letters are typing, and
|
|
11
|
+
* bare Esc/arrows are navigation. Rejected at registration.
|
|
12
|
+
* - A RESERVED list (every combo the TUI itself binds globally or in the
|
|
13
|
+
* prompt editor) is refused at registration with a warning. The list is
|
|
14
|
+
* the enforcement of "locals win": collisions can never reach the matcher.
|
|
15
|
+
* - Overlays (pickers, dialogs, scenes, the session browser) own the
|
|
16
|
+
* keyboard while open; shortcuts match only in the plain chat state.
|
|
17
|
+
*
|
|
18
|
+
* Handlers are fire-and-forget from the UI's point of view: async handlers
|
|
19
|
+
* are awaited but their rejection is caught and toasted — a throwing
|
|
20
|
+
* handler must never break the keyboard for everyone else.
|
|
21
|
+
*/
|
|
22
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
23
|
+
import { cleanScalarText } from './sanitize.js';
|
|
24
|
+
import { activationFiber, bindCallerEffect, compositionRoot, concreteService, requirePluginCaller } from './host-access.js';
|
|
25
|
+
const NAMED_KEYS = {
|
|
26
|
+
enter: 'return',
|
|
27
|
+
return: 'return',
|
|
28
|
+
esc: 'escape',
|
|
29
|
+
escape: 'escape',
|
|
30
|
+
tab: 'tab',
|
|
31
|
+
backspace: 'backspace',
|
|
32
|
+
delete: 'delete',
|
|
33
|
+
up: 'upArrow',
|
|
34
|
+
down: 'downArrow',
|
|
35
|
+
left: 'leftArrow',
|
|
36
|
+
right: 'rightArrow',
|
|
37
|
+
home: 'home',
|
|
38
|
+
end: 'end',
|
|
39
|
+
pageup: 'pageUp',
|
|
40
|
+
pagedown: 'pageDown',
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Combos the TUI owns, globally or inside the prompt editor (the editor's
|
|
44
|
+
* bindings are checked AFTER plugin shortcuts, so refusing them here is
|
|
45
|
+
* what keeps "locals win" true). Built-in handlers match a MODIFIER SUBSET
|
|
46
|
+
* (`isMod(key) && input === 'x'` — they never exclude an extra Shift), so
|
|
47
|
+
* the reserved check below refuses a plugin combo whose SHIFTLESS form is
|
|
48
|
+
* reserved: ctrl+shift+x would shadow Ctrl+X on terminals that report both
|
|
49
|
+
* as the same keypress (ConPTY does), and would be dead weight on terminals
|
|
50
|
+
* that don't.
|
|
51
|
+
*/
|
|
52
|
+
const RESERVED_COMBOS = new Set([
|
|
53
|
+
'ctrl+c', // interrupt / clear
|
|
54
|
+
'ctrl+d', // exit on empty input
|
|
55
|
+
'ctrl+t', // startup context panel
|
|
56
|
+
'ctrl+r', // history search
|
|
57
|
+
'ctrl+x', // external editor
|
|
58
|
+
'ctrl+o', // transcript mode toggle
|
|
59
|
+
'ctrl+l', // terminal redraw
|
|
60
|
+
'ctrl+e', // show all messages / line end
|
|
61
|
+
'ctrl+v', // paste
|
|
62
|
+
'ctrl+a', // line start
|
|
63
|
+
'ctrl+u', // kill line
|
|
64
|
+
'ctrl+k', // kill to end
|
|
65
|
+
'ctrl+w', // kill word
|
|
66
|
+
'ctrl+left', // word jump
|
|
67
|
+
'ctrl+right', // word jump
|
|
68
|
+
'ctrl+return', // newline (multi-line input)
|
|
69
|
+
'ctrl+shift+return', // shift+Enter newline (CSI 13;6u) — same editor binding
|
|
70
|
+
'alt+return', // newline fallback on terminals without shift reporting
|
|
71
|
+
'alt+up', // pull the last pending message back for editing
|
|
72
|
+
'escape', // pickers / interrupt / rewind double-tap
|
|
73
|
+
'tab', // command completion
|
|
74
|
+
'shift+tab', // session-mode cycle
|
|
75
|
+
]);
|
|
76
|
+
/**
|
|
77
|
+
* Parse `ctrl+shift+p` style combos. Returns undefined on anything
|
|
78
|
+
* malformed or disallowed (no modifier, unknown key name); `allowReserved`
|
|
79
|
+
* is exposed for tests only.
|
|
80
|
+
*/
|
|
81
|
+
export function parseShortcutCombo(raw) {
|
|
82
|
+
const parts = String(raw ?? '')
|
|
83
|
+
.toLowerCase()
|
|
84
|
+
.split('+')
|
|
85
|
+
.map(part => part.trim())
|
|
86
|
+
.filter(part => part !== '');
|
|
87
|
+
if (parts.length === 0)
|
|
88
|
+
return undefined;
|
|
89
|
+
let ctrl = false;
|
|
90
|
+
let meta = false;
|
|
91
|
+
let shift = false;
|
|
92
|
+
let named;
|
|
93
|
+
let char;
|
|
94
|
+
for (const part of parts) {
|
|
95
|
+
if (part === 'ctrl' || part === 'control') {
|
|
96
|
+
if (ctrl)
|
|
97
|
+
return undefined;
|
|
98
|
+
ctrl = true;
|
|
99
|
+
}
|
|
100
|
+
else if (part === 'alt' || part === 'meta' || part === 'option') {
|
|
101
|
+
if (meta)
|
|
102
|
+
return undefined;
|
|
103
|
+
meta = true;
|
|
104
|
+
}
|
|
105
|
+
else if (part === 'shift') {
|
|
106
|
+
if (shift)
|
|
107
|
+
return undefined;
|
|
108
|
+
shift = true;
|
|
109
|
+
}
|
|
110
|
+
else if (part === 'space') {
|
|
111
|
+
if (char !== undefined || named !== undefined)
|
|
112
|
+
return undefined;
|
|
113
|
+
char = ' ';
|
|
114
|
+
}
|
|
115
|
+
else if (part in NAMED_KEYS) {
|
|
116
|
+
if (char !== undefined || named !== undefined)
|
|
117
|
+
return undefined;
|
|
118
|
+
named = NAMED_KEYS[part];
|
|
119
|
+
}
|
|
120
|
+
else if ([...part].length === 1) {
|
|
121
|
+
if (char !== undefined || named !== undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
char = part;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (char === undefined && named === undefined)
|
|
130
|
+
return undefined;
|
|
131
|
+
// Bare keys are typing/navigation; a modifier is what makes a shortcut.
|
|
132
|
+
if (!ctrl && !meta)
|
|
133
|
+
return undefined;
|
|
134
|
+
// Escape combos are refused outright: the input layer sets key.meta = true
|
|
135
|
+
// for EVERY Escape (ink/events/input-event.ts — `keypress.meta ||
|
|
136
|
+
// keypress.name === 'escape' || keypress.option`), so an alt+escape combo
|
|
137
|
+
// would match every bare Esc press and shadow clear-input / the double-Esc
|
|
138
|
+
// rewind. Esc is fully owned by the TUI; there is no unambiguous way to
|
|
139
|
+
// bind it.
|
|
140
|
+
if (named === 'escape')
|
|
141
|
+
return undefined;
|
|
142
|
+
return { raw: parts.join('+'), ctrl, meta, shift, ...(named === undefined ? {} : { named }), ...(char === undefined ? {} : { char }) };
|
|
143
|
+
}
|
|
144
|
+
/** Canonical form for dedupe/reserved checks: modifiers sorted, key last. */
|
|
145
|
+
function comboKey(combo) {
|
|
146
|
+
const mods = [combo.ctrl ? 'ctrl' : '', combo.meta ? 'alt' : '', combo.shift ? 'shift' : '']
|
|
147
|
+
.filter(part => part !== '')
|
|
148
|
+
.sort();
|
|
149
|
+
return [...mods, combo.named === undefined ? (combo.char ?? '') : String(combo.named)].join('+');
|
|
150
|
+
}
|
|
151
|
+
/** Reserved lookup accepts user-spelled combos too (`ctrl+c`). */
|
|
152
|
+
function reservedKey(raw) {
|
|
153
|
+
const combo = parseShortcutCombo(raw);
|
|
154
|
+
return combo === undefined ? raw.toLowerCase() : comboKey(combo);
|
|
155
|
+
}
|
|
156
|
+
const RESERVED_CANONICAL = new Set([...RESERVED_COMBOS].map(reservedKey));
|
|
157
|
+
/** Match a keypress against a parsed combo. `input` is ink's input string
|
|
158
|
+
* (already the resolved character; ctrl+space arrives as ' '). */
|
|
159
|
+
export function matchShortcut(combo, input, key) {
|
|
160
|
+
if (Boolean(key.ctrl) !== combo.ctrl)
|
|
161
|
+
return false;
|
|
162
|
+
// ink reports Alt as meta; Esc itself also sets meta, which is why the
|
|
163
|
+
// modifier check runs against the combo, not a bare flag read.
|
|
164
|
+
if (Boolean(key.meta) !== combo.meta)
|
|
165
|
+
return false;
|
|
166
|
+
if (key.super)
|
|
167
|
+
return false;
|
|
168
|
+
// Shift must match for NAMED keys exactly as for characters — otherwise a
|
|
169
|
+
// registered ctrl+shift+enter would also match a plain ctrl+enter press,
|
|
170
|
+
// letting a plugin shadow the editor's built-in Ctrl+Enter delivery.
|
|
171
|
+
if (Boolean(key.shift) !== combo.shift)
|
|
172
|
+
return false;
|
|
173
|
+
if (combo.named !== undefined) {
|
|
174
|
+
return key[combo.named] === true;
|
|
175
|
+
}
|
|
176
|
+
if (combo.char === undefined)
|
|
177
|
+
return false;
|
|
178
|
+
// Shift+letter arrives as the uppercase character; compare case-folded
|
|
179
|
+
// (the shift FLAG equality above already pinned the modifier state).
|
|
180
|
+
return input.toLowerCase() === combo.char;
|
|
181
|
+
}
|
|
182
|
+
/** `ctx.tuiShortcuts` — plugin keyboard shortcut registry. */
|
|
183
|
+
export class TuiShortcutRuntime extends Service {
|
|
184
|
+
constructor(ctx) {
|
|
185
|
+
super(ctx, 'tuiShortcuts');
|
|
186
|
+
compositionRoot(ctx);
|
|
187
|
+
const runtime = this;
|
|
188
|
+
const state = {
|
|
189
|
+
shortcuts: new Map(),
|
|
190
|
+
owners: new Map(),
|
|
191
|
+
onError: undefined,
|
|
192
|
+
host: undefined,
|
|
193
|
+
logger: ctx.logger,
|
|
194
|
+
};
|
|
195
|
+
const host = Object.freeze({
|
|
196
|
+
dispatch: (input, key) => dispatchShortcut(runtime, input, key),
|
|
197
|
+
setErrorHandler: (handler) => {
|
|
198
|
+
state.onError = handler;
|
|
199
|
+
return () => {
|
|
200
|
+
if (state.onError === handler)
|
|
201
|
+
state.onError = undefined;
|
|
202
|
+
};
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
state.host = host;
|
|
206
|
+
hostShortcuts.set(runtime, state);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Bind `combo` to `handler`. Invalid, modifier-less, reserved, or
|
|
210
|
+
* duplicate combos are refused with a logger warning rather than a throw
|
|
211
|
+
* — a bad binding must not fail the plugin's whole boot.
|
|
212
|
+
*
|
|
213
|
+
* Returns the dispose function; the CALLER scopes it to its own fiber
|
|
214
|
+
* (`ctx.effect(() => dispose)`) — the same contract as `tuiScenes`
|
|
215
|
+
* registration. (A service method only sees the service's own ctx, so
|
|
216
|
+
* caller-fiber cleanup cannot happen here.)
|
|
217
|
+
*
|
|
218
|
+
* The optional trailing `identity` (the plugin's own ctx) only feeds the
|
|
219
|
+
* effect ledger's pluginId — omitting it records `undeclared` (C-060).
|
|
220
|
+
*/
|
|
221
|
+
register(combo, options, identity) {
|
|
222
|
+
let caller;
|
|
223
|
+
try {
|
|
224
|
+
caller = requirePluginCaller(this.ctx, 'tuiShortcuts.register', this);
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
this.ctx.logger.warn('dsh-tui: tuiShortcuts.register requires a live non-root plugin activation');
|
|
228
|
+
return () => { };
|
|
229
|
+
}
|
|
230
|
+
const state = shortcutStateFor(this);
|
|
231
|
+
const owner = activationFiber(caller);
|
|
232
|
+
if (owner === undefined) {
|
|
233
|
+
this.ctx.logger.warn('dsh-tui: tuiShortcuts.register requires a live activation');
|
|
234
|
+
return () => { };
|
|
235
|
+
}
|
|
236
|
+
let parsed;
|
|
237
|
+
try {
|
|
238
|
+
parsed = parseShortcutCombo(combo);
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
this.ctx.logger.warn('dsh-tui: tuiShortcuts.register rejected an uncoercible combo');
|
|
242
|
+
return () => { };
|
|
243
|
+
}
|
|
244
|
+
if (parsed === undefined) {
|
|
245
|
+
this.ctx.logger.warn('dsh-tui: tuiShortcuts.register rejected an invalid combo — need ctrl/alt plus one key (e.g. "ctrl+shift+p")');
|
|
246
|
+
return () => { };
|
|
247
|
+
}
|
|
248
|
+
const key = comboKey(parsed);
|
|
249
|
+
// Built-ins match a modifier subset (see RESERVED_COMBOS): a combo whose
|
|
250
|
+
// SHIFTLESS form is reserved collides with the built-in on terminals that
|
|
251
|
+
// don't report Shift distinctly, so it is refused too. The exact form is
|
|
252
|
+
// still checked for combos reserved WITH shift (ctrl+shift+return).
|
|
253
|
+
const shiftlessKey = comboKey({ ...parsed, shift: false });
|
|
254
|
+
if (RESERVED_CANONICAL.has(key) || RESERVED_CANONICAL.has(shiftlessKey)) {
|
|
255
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${parsed.raw}" — reserved by a built-in binding`);
|
|
256
|
+
return () => { };
|
|
257
|
+
}
|
|
258
|
+
if (state.shortcuts.has(key)) {
|
|
259
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${parsed.raw}" — already registered`);
|
|
260
|
+
this.ctx.get('tuiEffectLedger')?.record({
|
|
261
|
+
operation: 'bind',
|
|
262
|
+
resource: { kind: 'shortcut', id: key },
|
|
263
|
+
result: 'failed',
|
|
264
|
+
errorCode: 'DUPLICATE_CONTRIBUTION_ID',
|
|
265
|
+
}, identity);
|
|
266
|
+
return () => { };
|
|
267
|
+
}
|
|
268
|
+
let description;
|
|
269
|
+
let handler;
|
|
270
|
+
try {
|
|
271
|
+
description = cleanScalarText(options?.description, 120);
|
|
272
|
+
handler = options?.handler;
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${parsed.raw}" — malformed options`);
|
|
276
|
+
return () => { };
|
|
277
|
+
}
|
|
278
|
+
if (typeof handler !== 'function' || description === '') {
|
|
279
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${parsed.raw}" — needs a description and a handler`);
|
|
280
|
+
return () => { };
|
|
281
|
+
}
|
|
282
|
+
const entry = { combo: parsed, description, handler };
|
|
283
|
+
state.shortcuts.set(key, entry);
|
|
284
|
+
state.owners.set(key, owner);
|
|
285
|
+
this.ctx.get('tuiEffectLedger')?.record({ operation: 'bind', resource: { kind: 'shortcut', id: key }, result: 'applied' }, identity);
|
|
286
|
+
const dispose = () => {
|
|
287
|
+
if (state.shortcuts.get(key) !== entry)
|
|
288
|
+
return;
|
|
289
|
+
state.shortcuts.delete(key);
|
|
290
|
+
state.owners.delete(key);
|
|
291
|
+
this.ctx.get('tuiEffectLedger')?.record({ operation: 'release', resource: { kind: 'shortcut', id: key }, result: 'applied' }, identity);
|
|
292
|
+
};
|
|
293
|
+
bindCallerEffect(caller, dispose);
|
|
294
|
+
return dispose;
|
|
295
|
+
}
|
|
296
|
+
/** Registered combos with descriptions (diagnostics / future /help). */
|
|
297
|
+
list() {
|
|
298
|
+
const caller = requirePluginCaller(this.ctx, 'tuiShortcuts.list', this);
|
|
299
|
+
const owner = activationFiber(caller);
|
|
300
|
+
if (owner === undefined)
|
|
301
|
+
return [];
|
|
302
|
+
const state = shortcutStateFor(this);
|
|
303
|
+
return [...state.shortcuts.entries()]
|
|
304
|
+
.filter(([key]) => state.owners.get(key) === owner)
|
|
305
|
+
.map(([, entry]) => ({ combo: entry.combo.raw, description: entry.description }));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const hostShortcuts = new WeakMap();
|
|
309
|
+
function shortcutStateFor(runtime) {
|
|
310
|
+
const state = hostShortcuts.get(concreteService(runtime));
|
|
311
|
+
if (state === undefined)
|
|
312
|
+
throw new Error('tuiShortcuts host state is unavailable');
|
|
313
|
+
return state;
|
|
314
|
+
}
|
|
315
|
+
function dispatchShortcut(runtime, input, key) {
|
|
316
|
+
const state = shortcutStateFor(runtime);
|
|
317
|
+
for (const entry of state.shortcuts.values()) {
|
|
318
|
+
if (!matchShortcut(entry.combo, input, key))
|
|
319
|
+
continue;
|
|
320
|
+
Promise.resolve()
|
|
321
|
+
.then(() => entry.handler())
|
|
322
|
+
.catch((error) => {
|
|
323
|
+
state.onError?.(entry.combo.raw, error);
|
|
324
|
+
state.logger.warn(`dsh-tui: shortcut "${entry.combo.raw}" handler failed: %o`, error);
|
|
325
|
+
});
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
export function getHostShortcuts(runtime) {
|
|
331
|
+
if (runtime === undefined)
|
|
332
|
+
return undefined;
|
|
333
|
+
try {
|
|
334
|
+
return hostShortcuts.get(concreteService(runtime))?.host;
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
export default TuiShortcutRuntime;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyed status-line contributions — pi's `ctx.ui.setStatus(key, text)`.
|
|
3
|
+
* Each plugin owns a key; setting text shows it, setting undefined clears
|
|
4
|
+
* it. The TUI renders all contributions as one joined line above the prompt
|
|
5
|
+
* (host-owned rendering: plugins supply text, never layout).
|
|
6
|
+
*
|
|
7
|
+
* Same split as the dialogs seam: a cordis-free store the chat screen
|
|
8
|
+
* subscribes to, and a thin cordis service validating untrusted text.
|
|
9
|
+
*/
|
|
10
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
11
|
+
/** One rendered contribution. */
|
|
12
|
+
export interface TuiStatusEntry {
|
|
13
|
+
readonly key: string;
|
|
14
|
+
readonly text: string;
|
|
15
|
+
}
|
|
16
|
+
/** Cordis-free keyed-text store. Render order is first-set order (Map
|
|
17
|
+
* insertion order), so a plugin's line never jumps around on updates. */
|
|
18
|
+
export declare class TuiStatusStore {
|
|
19
|
+
private readonly listeners;
|
|
20
|
+
private readonly entries;
|
|
21
|
+
private snapshot;
|
|
22
|
+
/** Set or clear (undefined/empty) one key. */
|
|
23
|
+
set(key: string, text: string | undefined, token?: number, owner?: object): void;
|
|
24
|
+
/** Current contributions, first-set first (stable between changes). */
|
|
25
|
+
getSnapshot(): readonly TuiStatusEntry[];
|
|
26
|
+
/** Host runtime uses this to enforce that one activation cannot rewrite or
|
|
27
|
+
* clear another activation's keyed contribution. */
|
|
28
|
+
ownerOf(key: string): object | undefined;
|
|
29
|
+
/** Clear `key` only while it still holds the write tagged `token` — a
|
|
30
|
+
* stale disposer must not wipe a newer contribution (even one with
|
|
31
|
+
* identical text). Returns true when this call actually cleared. */
|
|
32
|
+
clearIf(key: string, token: number, owner?: object): boolean;
|
|
33
|
+
/** Drop everything (teardown). */
|
|
34
|
+
clear(): void;
|
|
35
|
+
subscribe(listener: () => void): () => void;
|
|
36
|
+
private emit;
|
|
37
|
+
}
|
|
38
|
+
declare module '@deepseek-ai/cordis' {
|
|
39
|
+
interface Context {
|
|
40
|
+
tuiStatus: TuiStatusRuntime;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* `ctx.tuiStatus` — plugin-facing status contributions. Invalid keys and
|
|
45
|
+
* oversized text are rejected with a logger warning instead of throwing:
|
|
46
|
+
* a status line must never take the TUI down.
|
|
47
|
+
*/
|
|
48
|
+
export declare class TuiStatusRuntime extends Service {
|
|
49
|
+
constructor(ctx: Context);
|
|
50
|
+
/**
|
|
51
|
+
* Set (or clear with `undefined`) the contribution for `key`. Keys are
|
|
52
|
+
* plugin-namespaced by convention (`my-plugin`, `my-plugin:detail`);
|
|
53
|
+
* control chars are stripped and text is capped at 200 cells. Text is
|
|
54
|
+
* scalar-only: string/number/boolean are coerced to string, anything else
|
|
55
|
+
* is refused with a warning (never rendered as "[object Object]", never
|
|
56
|
+
* silently treated as a clear).
|
|
57
|
+
*
|
|
58
|
+
* Returns a disposer that clears the contribution IF the key still holds
|
|
59
|
+
* exactly this write (a later set — even of identical text — wins over a
|
|
60
|
+
* stale disposer). The CALLER scopes it to its own fiber
|
|
61
|
+
* (`ctx.effect(() => dispose)`) — the same contract as
|
|
62
|
+
* `tuiShortcuts`/`tuiScenes`: a service method only sees the service's own
|
|
63
|
+
* ctx, so per-plugin cleanup cannot happen here. Without that, an unloaded
|
|
64
|
+
* or hot-reloaded plugin would leave its line behind forever.
|
|
65
|
+
*
|
|
66
|
+
* The optional trailing `identity` (the plugin's own ctx) only feeds the
|
|
67
|
+
* effect ledger's pluginId — omitting it records `undeclared`, never a
|
|
68
|
+
* guess (C-060 honest identity).
|
|
69
|
+
*/
|
|
70
|
+
set(key: string, text: string | number | boolean | undefined, identity?: Context): () => void;
|
|
71
|
+
}
|
|
72
|
+
export declare function getHostStatusStore(runtime: TuiStatusRuntime | undefined): TuiStatusStore | undefined;
|
|
73
|
+
export default TuiStatusRuntime;
|
|
74
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAKtD,iCAAiC;AACjC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AASD;0EAC0E;AAC1E,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAKlD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoE;IAG5F,OAAO,CAAC,QAAQ,CAAgC;IAEhD,8CAA8C;IAC9C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,SAAI,EAAE,KAAK,GAAE,MAA0B,GAAG,IAAI;IAmB9F,uEAAuE;IACvE,WAAW,IAAI,SAAS,cAAc,EAAE;IAIxC;wDACoD;IACpD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIxC;;yEAEqE;IACrE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO;IAS5D,kCAAkC;IAClC,KAAK,IAAI,IAAI;IAOb,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAO3C,OAAO,CAAC,IAAI;CAGb;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,SAAS,EAAE,gBAAgB,CAAA;KAC5B;CACF;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,OAAO;gBAC/B,GAAG,EAAE,OAAO;IAUxB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,IAAI;CAwF9F;AAgBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAOpG;AAED,eAAe,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyed status-line contributions — pi's `ctx.ui.setStatus(key, text)`.
|
|
3
|
+
* Each plugin owns a key; setting text shows it, setting undefined clears
|
|
4
|
+
* it. The TUI renders all contributions as one joined line above the prompt
|
|
5
|
+
* (host-owned rendering: plugins supply text, never layout).
|
|
6
|
+
*
|
|
7
|
+
* Same split as the dialogs seam: a cordis-free store the chat screen
|
|
8
|
+
* subscribes to, and a thin cordis service validating untrusted text.
|
|
9
|
+
*/
|
|
10
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
11
|
+
import { cleanScalarText } from './sanitize.js';
|
|
12
|
+
import { activationFiber, assertCallerContext, bindCallerEffect, compositionRoot, concreteService, requirePluginCaller } from './host-access.js';
|
|
13
|
+
import { componentIdentityOf } from './component-identity.js';
|
|
14
|
+
// Colon-separated segments are the documented namespacing convention
|
|
15
|
+
// (`plugin:sub-item`); each segment stays a lowercase slug.
|
|
16
|
+
const KEY_PATTERN = /^[a-z][a-z0-9_-]*(:[a-z][a-z0-9_-]*)*$/u;
|
|
17
|
+
const TEXT_CELLS = 200;
|
|
18
|
+
const MAX_ENTRIES = 20;
|
|
19
|
+
const HOST_STATUS_OWNER = Object.freeze({ kind: 'host-status-owner' });
|
|
20
|
+
/** Cordis-free keyed-text store. Render order is first-set order (Map
|
|
21
|
+
* insertion order), so a plugin's line never jumps around on updates. */
|
|
22
|
+
export class TuiStatusStore {
|
|
23
|
+
listeners = new Set();
|
|
24
|
+
// Each write carries a token: a disposer compares TOKENS, not text —
|
|
25
|
+
// value comparison has an ABA hole (set 'x', set 'x' again, the first
|
|
26
|
+
// disposer would wipe the second write, e.g. a hot reload restoring the
|
|
27
|
+
// same status text).
|
|
28
|
+
entries = new Map();
|
|
29
|
+
// useSyncExternalStore requires a referentially stable snapshot between
|
|
30
|
+
// emits — a fresh array per call would re-render in an infinite loop.
|
|
31
|
+
snapshot = [];
|
|
32
|
+
/** Set or clear (undefined/empty) one key. */
|
|
33
|
+
set(key, text, token = 0, owner = HOST_STATUS_OWNER) {
|
|
34
|
+
const had = this.entries.has(key);
|
|
35
|
+
if (text === undefined || text === '') {
|
|
36
|
+
if (!had)
|
|
37
|
+
return;
|
|
38
|
+
this.entries.delete(key);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const existing = this.entries.get(key);
|
|
42
|
+
if (existing?.text === text) {
|
|
43
|
+
// Same text, new write: adopt the new token so the newest disposer
|
|
44
|
+
// is the one that owns the line (no re-emit — nothing visible changed).
|
|
45
|
+
existing.token = token;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.entries.set(key, { text, token, owner });
|
|
49
|
+
}
|
|
50
|
+
this.snapshot = [...this.entries].map(([entryKey, entry]) => ({ key: entryKey, text: entry.text }));
|
|
51
|
+
this.emit();
|
|
52
|
+
}
|
|
53
|
+
/** Current contributions, first-set first (stable between changes). */
|
|
54
|
+
getSnapshot() {
|
|
55
|
+
return this.snapshot;
|
|
56
|
+
}
|
|
57
|
+
/** Host runtime uses this to enforce that one activation cannot rewrite or
|
|
58
|
+
* clear another activation's keyed contribution. */
|
|
59
|
+
ownerOf(key) {
|
|
60
|
+
return this.entries.get(key)?.owner;
|
|
61
|
+
}
|
|
62
|
+
/** Clear `key` only while it still holds the write tagged `token` — a
|
|
63
|
+
* stale disposer must not wipe a newer contribution (even one with
|
|
64
|
+
* identical text). Returns true when this call actually cleared. */
|
|
65
|
+
clearIf(key, token, owner) {
|
|
66
|
+
if (owner !== undefined && this.entries.get(key)?.owner !== owner)
|
|
67
|
+
return false;
|
|
68
|
+
if (this.entries.get(key)?.token !== token)
|
|
69
|
+
return false;
|
|
70
|
+
this.entries.delete(key);
|
|
71
|
+
this.snapshot = [...this.entries].map(([entryKey, entry]) => ({ key: entryKey, text: entry.text }));
|
|
72
|
+
this.emit();
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/** Drop everything (teardown). */
|
|
76
|
+
clear() {
|
|
77
|
+
if (this.entries.size === 0)
|
|
78
|
+
return;
|
|
79
|
+
this.entries.clear();
|
|
80
|
+
this.snapshot = [];
|
|
81
|
+
this.emit();
|
|
82
|
+
}
|
|
83
|
+
subscribe(listener) {
|
|
84
|
+
this.listeners.add(listener);
|
|
85
|
+
return () => {
|
|
86
|
+
this.listeners.delete(listener);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
emit() {
|
|
90
|
+
for (const listener of this.listeners)
|
|
91
|
+
listener();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* `ctx.tuiStatus` — plugin-facing status contributions. Invalid keys and
|
|
96
|
+
* oversized text are rejected with a logger warning instead of throwing:
|
|
97
|
+
* a status line must never take the TUI down.
|
|
98
|
+
*/
|
|
99
|
+
export class TuiStatusRuntime extends Service {
|
|
100
|
+
constructor(ctx) {
|
|
101
|
+
super(ctx, 'tuiStatus');
|
|
102
|
+
compositionRoot(ctx);
|
|
103
|
+
// Keep host state out of the traceable service object. A WeakMap also
|
|
104
|
+
// works with Cordis's caller-bound method proxy (unlike `#private`).
|
|
105
|
+
const state = { store: new TuiStatusStore(), nextToken: 1 };
|
|
106
|
+
hostStatusStores.set(this, state);
|
|
107
|
+
ctx.effect(() => () => state.store.clear());
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Set (or clear with `undefined`) the contribution for `key`. Keys are
|
|
111
|
+
* plugin-namespaced by convention (`my-plugin`, `my-plugin:detail`);
|
|
112
|
+
* control chars are stripped and text is capped at 200 cells. Text is
|
|
113
|
+
* scalar-only: string/number/boolean are coerced to string, anything else
|
|
114
|
+
* is refused with a warning (never rendered as "[object Object]", never
|
|
115
|
+
* silently treated as a clear).
|
|
116
|
+
*
|
|
117
|
+
* Returns a disposer that clears the contribution IF the key still holds
|
|
118
|
+
* exactly this write (a later set — even of identical text — wins over a
|
|
119
|
+
* stale disposer). The CALLER scopes it to its own fiber
|
|
120
|
+
* (`ctx.effect(() => dispose)`) — the same contract as
|
|
121
|
+
* `tuiShortcuts`/`tuiScenes`: a service method only sees the service's own
|
|
122
|
+
* ctx, so per-plugin cleanup cannot happen here. Without that, an unloaded
|
|
123
|
+
* or hot-reloaded plugin would leave its line behind forever.
|
|
124
|
+
*
|
|
125
|
+
* The optional trailing `identity` (the plugin's own ctx) only feeds the
|
|
126
|
+
* effect ledger's pluginId — omitting it records `undeclared`, never a
|
|
127
|
+
* guess (C-060 honest identity).
|
|
128
|
+
*/
|
|
129
|
+
set(key, text, identity) {
|
|
130
|
+
const noop = () => { };
|
|
131
|
+
let caller;
|
|
132
|
+
try {
|
|
133
|
+
caller = requirePluginCaller(this.ctx, 'tuiStatus.set', this);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
this.ctx.logger.warn('dsh-tui: tuiStatus.set requires a live non-root plugin activation');
|
|
137
|
+
return noop;
|
|
138
|
+
}
|
|
139
|
+
const state = statusStateFor(this);
|
|
140
|
+
const store = state.store;
|
|
141
|
+
const callerIdentity = componentIdentityOf(caller);
|
|
142
|
+
const suppliedIdentity = identity === undefined ? callerIdentity : componentIdentityOf(identity);
|
|
143
|
+
if (identity !== undefined) {
|
|
144
|
+
try {
|
|
145
|
+
assertCallerContext(caller, identity, 'tuiStatus.set');
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
caller.logger.warn('dsh-tui: tuiStatus.set rejected an identity belonging to another activation');
|
|
149
|
+
return noop;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const owner = activationFiber(caller);
|
|
153
|
+
if (owner === undefined) {
|
|
154
|
+
caller.logger.warn('dsh-tui: tuiStatus.set requires a live activation owner');
|
|
155
|
+
return noop;
|
|
156
|
+
}
|
|
157
|
+
let normalized;
|
|
158
|
+
try {
|
|
159
|
+
normalized = String(key ?? '').trim().toLowerCase();
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
caller.logger.warn('dsh-tui: tuiStatus.set rejected an uncoercible key');
|
|
163
|
+
return noop;
|
|
164
|
+
}
|
|
165
|
+
if (!KEY_PATTERN.test(normalized)) {
|
|
166
|
+
caller.logger.warn('dsh-tui: tuiStatus.set rejected an invalid key');
|
|
167
|
+
return noop;
|
|
168
|
+
}
|
|
169
|
+
if (text !== undefined && !store.getSnapshot().some(e => e.key === normalized)) {
|
|
170
|
+
// New key beyond the cap: the line is one row of terminal — an
|
|
171
|
+
// unbounded count would push the prompt off screen.
|
|
172
|
+
if (store.getSnapshot().length >= MAX_ENTRIES) {
|
|
173
|
+
caller.logger.warn(`dsh-tui: tuiStatus.set rejected "${normalized}": ${MAX_ENTRIES} contributions already shown`);
|
|
174
|
+
return noop;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
let cleaned;
|
|
178
|
+
if (text !== undefined) {
|
|
179
|
+
// Scalar-only coercion (Track A contract): a non-scalar text (an
|
|
180
|
+
// object would otherwise render as "[object Object]") is REFUSED with
|
|
181
|
+
// a warning — it must not silently become a clear, either.
|
|
182
|
+
if (typeof text !== 'string' && typeof text !== 'number' && typeof text !== 'boolean') {
|
|
183
|
+
caller.logger.warn(`dsh-tui: tuiStatus.set rejected non-scalar text for "${normalized}"`);
|
|
184
|
+
return noop;
|
|
185
|
+
}
|
|
186
|
+
cleaned = cleanScalarText(text, TEXT_CELLS);
|
|
187
|
+
}
|
|
188
|
+
const token = state.nextToken++;
|
|
189
|
+
const had = store.getSnapshot().some(entry => entry.key === normalized);
|
|
190
|
+
if (store.ownerOf(normalized) !== undefined && store.ownerOf(normalized) !== owner) {
|
|
191
|
+
caller.logger.warn(`dsh-tui: tuiStatus.set rejected "${normalized}" — the contribution belongs to another activation`);
|
|
192
|
+
return noop;
|
|
193
|
+
}
|
|
194
|
+
store.set(normalized, cleaned, token, owner);
|
|
195
|
+
const ledger = caller.get('tuiEffectLedger');
|
|
196
|
+
if (cleaned === undefined) {
|
|
197
|
+
if (had)
|
|
198
|
+
ledger?.record({ operation: 'release', resource: { kind: 'status', id: normalized }, result: 'applied' }, identity);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
ledger?.record({
|
|
202
|
+
operation: had ? 'replace' : 'bind',
|
|
203
|
+
resource: { kind: 'status', id: normalized },
|
|
204
|
+
result: 'applied',
|
|
205
|
+
...(had ? { replaces: { resourceId: normalized } } : {}),
|
|
206
|
+
}, identity);
|
|
207
|
+
}
|
|
208
|
+
const dispose = () => {
|
|
209
|
+
if (store.clearIf(normalized, token, owner)) {
|
|
210
|
+
caller.get('tuiEffectLedger')?.record({ operation: 'release', resource: { kind: 'status', id: normalized }, result: 'applied' }, identity);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
bindCallerEffect(caller, dispose);
|
|
214
|
+
return dispose;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const hostStatusStores = new WeakMap();
|
|
218
|
+
function statusStateFor(runtime) {
|
|
219
|
+
const store = hostStatusStores.get(concreteService(runtime));
|
|
220
|
+
if (store === undefined)
|
|
221
|
+
throw new Error('tuiStatus host store is unavailable');
|
|
222
|
+
return store;
|
|
223
|
+
}
|
|
224
|
+
export function getHostStatusStore(runtime) {
|
|
225
|
+
if (runtime === undefined)
|
|
226
|
+
return undefined;
|
|
227
|
+
try {
|
|
228
|
+
return hostStatusStores.get(concreteService(runtime))?.store;
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export default TuiStatusRuntime;
|