@deepseek-harness-tui/dsh-tui 0.7.3 → 0.8.1
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 +15 -7
- package/bin/dsh-tui.js +19 -3
- package/cordis.patch.yml +43 -11
- package/cordis.yml +20 -1
- package/ecosystem-spec/registry/contracts/decision-events-v1alpha1.json +13 -0
- package/ecosystem-spec/registry/host-descriptor.tui.example.json +56 -0
- package/ecosystem-spec/registry/permissions-0.1.json +13 -0
- package/ecosystem-spec/registry/registry-0.15.json +57 -0
- package/ecosystem-spec/schemas/conformance-claim.schema.json +15 -0
- package/ecosystem-spec/schemas/effect-ledger-record.schema.json +16 -0
- package/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/commands.d.ts.map +1 -1
- package/lib/types/commands.js +4 -1
- 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 -10
- package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
- package/lib/types/components/LoadedContextPanel.js +7 -18
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +1 -2
- 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 +29 -5
- package/lib/types/components/PluginSceneBoundary.d.ts +31 -0
- package/lib/types/components/PluginSceneBoundary.d.ts.map +1 -0
- package/lib/types/components/PluginSceneBoundary.js +29 -0
- 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/SkillsPicker.d.ts +18 -0
- package/lib/types/components/SkillsPicker.d.ts.map +1 -0
- package/lib/types/components/SkillsPicker.js +50 -0
- package/lib/types/components/SplitDiffView.d.ts +28 -0
- package/lib/types/components/SplitDiffView.d.ts.map +1 -0
- package/lib/types/components/SplitDiffView.js +417 -0
- 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/messages/AssistantToolUseMessage.d.ts +3 -1
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +17 -7
- package/lib/types/dsh-adapter/channel.d.ts +98 -7
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +623 -26
- 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/component-identity.d.ts +28 -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 +2 -2
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +3 -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 +354 -0
- package/lib/types/dsh-adapter/dialogs.d.ts +146 -0
- package/lib/types/dsh-adapter/dialogs.d.ts.map +1 -0
- package/lib/types/dsh-adapter/dialogs.js +262 -0
- package/lib/types/dsh-adapter/effect-ledger.d.ts +99 -0
- package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -0
- package/lib/types/dsh-adapter/effect-ledger.js +231 -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 +169 -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 +184 -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 +146 -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 +178 -0
- package/lib/types/dsh-adapter/message-observer.d.ts.map +1 -0
- package/lib/types/dsh-adapter/message-observer.js +509 -0
- package/lib/types/dsh-adapter/plugin-host.d.ts +103 -0
- package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-host.js +270 -0
- package/lib/types/dsh-adapter/plugin-storage.d.ts +113 -0
- package/lib/types/dsh-adapter/plugin-storage.d.ts.map +1 -0
- package/lib/types/dsh-adapter/plugin-storage.js +385 -0
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +106 -1
- 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 +10 -0
- package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -0
- package/lib/types/dsh-adapter/promptDebug.js +148 -0
- package/lib/types/dsh-adapter/renderers.d.ts +65 -0
- package/lib/types/dsh-adapter/renderers.d.ts.map +1 -0
- package/lib/types/dsh-adapter/renderers.js +138 -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 +81 -0
- package/lib/types/dsh-adapter/scenes.d.ts.map +1 -0
- package/lib/types/dsh-adapter/scenes.js +93 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts +116 -0
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -0
- package/lib/types/dsh-adapter/settings-sections.js +63 -0
- package/lib/types/dsh-adapter/settingsEditor.d.ts +128 -0
- package/lib/types/dsh-adapter/settingsEditor.d.ts.map +1 -0
- package/lib/types/dsh-adapter/settingsEditor.js +244 -0
- package/lib/types/dsh-adapter/shortcuts.d.ts +109 -0
- package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -0
- package/lib/types/dsh-adapter/shortcuts.js +268 -0
- package/lib/types/dsh-adapter/status.d.ts +75 -0
- package/lib/types/dsh-adapter/status.d.ts.map +1 -0
- package/lib/types/dsh-adapter/status.js +168 -0
- package/lib/types/extensions.d.ts +8 -0
- package/lib/types/extensions.d.ts.map +1 -0
- package/lib/types/extensions.js +15 -0
- package/lib/types/i18n.d.ts +299 -26
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +89 -8
- package/lib/types/ink/ink.d.ts +11 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +33 -0
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +101 -51
- package/lib/types/ink/output.d.ts +7 -0
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +125 -4
- 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/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +18 -6
- package/lib/types/jsx-runtime.d.ts +2 -0
- package/lib/types/jsx-runtime.d.ts.map +1 -0
- package/lib/types/jsx-runtime.js +13 -0
- package/lib/types/modelRoute.d.ts +10 -2
- package/lib/types/modelRoute.d.ts.map +1 -1
- package/lib/types/modelRoute.js +33 -4
- package/lib/types/plugin-host.d.ts +13 -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 +157 -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 +77 -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 +119 -0
- package/lib/types/scenes.d.ts +3 -0
- package/lib/types/scenes.d.ts.map +1 -0
- package/lib/types/scenes.js +4 -0
- 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 +247 -48
- package/lib/types/screens/Settings.d.ts +20 -0
- package/lib/types/screens/Settings.d.ts.map +1 -0
- package/lib/types/screens/Settings.js +333 -0
- package/lib/types/screens/StatusLine.js +1 -1
- package/lib/types/settings-sections.d.ts +3 -0
- package/lib/types/settings-sections.d.ts.map +1 -0
- package/lib/types/settings-sections.js +4 -0
- package/lib/types/theme.d.ts +17 -0
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +51 -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/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/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/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 +257 -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/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/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/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/LICENSE +21 -0
- package/node_modules/@dsh-std/presentation/README.md +26 -0
- package/node_modules/@dsh-std/presentation/README.zh.md +28 -0
- package/node_modules/@dsh-std/presentation/lib/index.d.ts +219 -0
- package/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -0
- package/node_modules/@dsh-std/presentation/lib/index.js +547 -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 +21 -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 +118 -67
- 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 +257 -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/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/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/LICENSE +21 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +26 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +28 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts +219 -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 +547 -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 +21 -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/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/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/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 +257 -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/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/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,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React-free form model behind the `/settings` screen (issue #165), mirroring
|
|
3
|
+
* the web front door's card-form.ts semantics: a section stages what the user
|
|
4
|
+
* types and writes it only on save — every settings write is a durable,
|
|
5
|
+
* revision-fenced `settings.mutate`, so a control that committed as it
|
|
6
|
+
* settled turned one edit into a write the user never asked for and could
|
|
7
|
+
* not preview; staged text makes what is on screen exactly what a save would
|
|
8
|
+
* store.
|
|
9
|
+
*
|
|
10
|
+
* A field shows its effective value — the user layer over the composition
|
|
11
|
+
* layer over the schema default — and whether the user layer carries it. That
|
|
12
|
+
* presence, not a value comparison, is what marks a field overridden: an
|
|
13
|
+
* override equal to the composition default is still an override.
|
|
14
|
+
*
|
|
15
|
+
* The kernel side (storage, schema validation, layering, revision fencing)
|
|
16
|
+
* stays with the dsh settings / credentials services; this module only
|
|
17
|
+
* translates between drafts and `mutate` path ops.
|
|
18
|
+
*/
|
|
19
|
+
/** Read a nested value by path (array indexes as strings). */
|
|
20
|
+
export function getPath(value, path) {
|
|
21
|
+
let current = value;
|
|
22
|
+
for (const key of path) {
|
|
23
|
+
if (Array.isArray(current)) {
|
|
24
|
+
current = current[Number(key)];
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (typeof current !== 'object' || current === null)
|
|
28
|
+
return undefined;
|
|
29
|
+
current = current[key];
|
|
30
|
+
}
|
|
31
|
+
return current;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether a value explicitly carries the path — its presence marks a user
|
|
35
|
+
* override, independent of the value stored there.
|
|
36
|
+
*/
|
|
37
|
+
export function hasPath(value, path) {
|
|
38
|
+
if (path.length === 0)
|
|
39
|
+
return value !== undefined;
|
|
40
|
+
const parent = getPath(value, path.slice(0, -1));
|
|
41
|
+
const key = path[path.length - 1];
|
|
42
|
+
if (Array.isArray(parent))
|
|
43
|
+
return Number(key) < parent.length;
|
|
44
|
+
if (typeof parent !== 'object' || parent === null)
|
|
45
|
+
return false;
|
|
46
|
+
return key in parent;
|
|
47
|
+
}
|
|
48
|
+
/** Default draft text for a kind; the empty string when the section carries none. */
|
|
49
|
+
function defaultFormat(field, value) {
|
|
50
|
+
if (field.format)
|
|
51
|
+
return field.format(value);
|
|
52
|
+
if (value === undefined || value === null)
|
|
53
|
+
return '';
|
|
54
|
+
switch (field.kind) {
|
|
55
|
+
case 'number':
|
|
56
|
+
return typeof value === 'number' ? String(value) : '';
|
|
57
|
+
case 'boolean':
|
|
58
|
+
return value === true ? 'true' : 'false';
|
|
59
|
+
default:
|
|
60
|
+
return typeof value === 'string' ? value : String(value);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Default write for a kind: an empty text/number draft stages a clear. */
|
|
64
|
+
function defaultParse(field, text) {
|
|
65
|
+
if (field.parse)
|
|
66
|
+
return field.parse(text);
|
|
67
|
+
const trimmed = text.trim();
|
|
68
|
+
switch (field.kind) {
|
|
69
|
+
case 'number': {
|
|
70
|
+
if (trimmed === '')
|
|
71
|
+
return { kind: 'clear' };
|
|
72
|
+
const value = Number(trimmed);
|
|
73
|
+
return Number.isFinite(value) ? { kind: 'set', value } : undefined;
|
|
74
|
+
}
|
|
75
|
+
case 'boolean':
|
|
76
|
+
return { kind: 'set', value: trimmed === 'true' };
|
|
77
|
+
case 'select':
|
|
78
|
+
return field.options?.some(option => option.value === trimmed)
|
|
79
|
+
? { kind: 'set', value: trimmed }
|
|
80
|
+
: undefined;
|
|
81
|
+
default:
|
|
82
|
+
return trimmed === '' ? { kind: 'clear' } : { kind: 'set', value: text };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Key addressing one field inside a form: its path joined. */
|
|
86
|
+
function fieldKey(field) {
|
|
87
|
+
return field.path.join('.');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The staged form over one settings namespace's declared fields. The screen
|
|
91
|
+
* re-seeds it from a fresh namespace view after every save and whenever the
|
|
92
|
+
* underlying document changes.
|
|
93
|
+
*/
|
|
94
|
+
export class SettingsForm {
|
|
95
|
+
host;
|
|
96
|
+
view;
|
|
97
|
+
fields;
|
|
98
|
+
edits = new Map();
|
|
99
|
+
saving = false;
|
|
100
|
+
failed = false;
|
|
101
|
+
constructor(host, view, fields) {
|
|
102
|
+
this.host = host;
|
|
103
|
+
this.view = view;
|
|
104
|
+
this.fields = fields;
|
|
105
|
+
}
|
|
106
|
+
get available() {
|
|
107
|
+
return this.view !== undefined;
|
|
108
|
+
}
|
|
109
|
+
/** The namespace view the form was seeded from (undefined = not served). */
|
|
110
|
+
get namespace() {
|
|
111
|
+
return this.view;
|
|
112
|
+
}
|
|
113
|
+
field(field) {
|
|
114
|
+
const key = fieldKey(field);
|
|
115
|
+
const staged = this.edits.get(key);
|
|
116
|
+
if (field.secret !== undefined) {
|
|
117
|
+
// A credential literal never seeds a draft: blank until typed, and a
|
|
118
|
+
// blank draft writes nothing.
|
|
119
|
+
return { text: staged?.text ?? '', overridden: false, invalid: false };
|
|
120
|
+
}
|
|
121
|
+
if (staged !== undefined) {
|
|
122
|
+
const write = defaultParse(field, staged.text);
|
|
123
|
+
return {
|
|
124
|
+
text: staged.text,
|
|
125
|
+
overridden: write?.kind === 'set',
|
|
126
|
+
invalid: write === undefined,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
text: defaultFormat(field, this.view ? getPath(this.view.value, field.path) : undefined),
|
|
131
|
+
overridden: this.view !== undefined && hasPath(this.view.user, field.path),
|
|
132
|
+
invalid: false,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
shell() {
|
|
136
|
+
let invalid = false;
|
|
137
|
+
for (const field of this.fields) {
|
|
138
|
+
if (this.field(field).invalid)
|
|
139
|
+
invalid = true;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
available: this.available,
|
|
143
|
+
dirty: this.edits.size > 0,
|
|
144
|
+
invalid,
|
|
145
|
+
saving: this.saving,
|
|
146
|
+
failed: this.failed,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** Whether the field holds a staged (unsaved) edit. */
|
|
150
|
+
isStaged(field) {
|
|
151
|
+
return this.edits.has(fieldKey(field));
|
|
152
|
+
}
|
|
153
|
+
/** Stage draft text for one field. */
|
|
154
|
+
edit(field, text) {
|
|
155
|
+
this.edits.set(fieldKey(field), { text, clear: false });
|
|
156
|
+
this.failed = false;
|
|
157
|
+
}
|
|
158
|
+
/** Stage a clear, so saving lets the field re-inherit the composition layer. */
|
|
159
|
+
resetField(field) {
|
|
160
|
+
this.edits.set(fieldKey(field), { text: '', clear: true });
|
|
161
|
+
this.failed = false;
|
|
162
|
+
}
|
|
163
|
+
/** Drop every staged edit. */
|
|
164
|
+
discard() {
|
|
165
|
+
this.edits.clear();
|
|
166
|
+
this.failed = false;
|
|
167
|
+
}
|
|
168
|
+
/** Whether any staged draft is invalid, which blocks the save. */
|
|
169
|
+
get invalid() {
|
|
170
|
+
return this.shell().invalid;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Write every staged edit. Settings fields land as one revision-fenced
|
|
174
|
+
* `mutate` (one retry on a stale-revision conflict); credential fields
|
|
175
|
+
* write through the credentials seam. Resolves to whether every write
|
|
176
|
+
* landed — the caller re-seeds from a fresh namespace view afterwards.
|
|
177
|
+
*
|
|
178
|
+
* Only the edits THIS save snapshotted are cleared on success, and only
|
|
179
|
+
* when they are still the same edit: a draft typed while the write was in
|
|
180
|
+
* flight is a newer object and survives — it was never written, so it must
|
|
181
|
+
* not be silently dropped.
|
|
182
|
+
*/
|
|
183
|
+
async save() {
|
|
184
|
+
if (this.view === undefined || this.invalid || this.saving)
|
|
185
|
+
return false;
|
|
186
|
+
const ns = this.view.ns;
|
|
187
|
+
const snapshot = new Map(this.edits);
|
|
188
|
+
const ops = [];
|
|
189
|
+
const secrets = [];
|
|
190
|
+
for (const field of this.fields) {
|
|
191
|
+
const staged = snapshot.get(fieldKey(field));
|
|
192
|
+
if (staged === undefined)
|
|
193
|
+
continue;
|
|
194
|
+
if (field.secret !== undefined) {
|
|
195
|
+
// Blank drafts write nothing; typed drafts replace the credential.
|
|
196
|
+
if (staged.text !== '')
|
|
197
|
+
secrets.push({ ref: field.secret.ref, text: staged.text });
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const write = staged.clear ? { kind: 'clear' } : defaultParse(field, staged.text);
|
|
201
|
+
if (write === undefined)
|
|
202
|
+
return false;
|
|
203
|
+
ops.push(write.kind === 'clear'
|
|
204
|
+
? { op: 'unset', path: field.path }
|
|
205
|
+
: { op: 'set', path: field.path, value: write.value });
|
|
206
|
+
}
|
|
207
|
+
this.saving = true;
|
|
208
|
+
try {
|
|
209
|
+
if (ops.length > 0) {
|
|
210
|
+
try {
|
|
211
|
+
await this.host.write(ns, ops, this.view.revision);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
// One retry on a stale-revision conflict (a concurrent write landed
|
|
215
|
+
// between seed and save); anything else propagates.
|
|
216
|
+
if (error?.code !== 'SETTINGS_CONFLICT')
|
|
217
|
+
throw error;
|
|
218
|
+
const fresh = this.host.listNamespaces().find(entry => entry.ns === ns);
|
|
219
|
+
await this.host.write(ns, ops, fresh?.revision);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
for (const secret of secrets) {
|
|
223
|
+
await this.host.writeCredential(secret.ref, secret.text);
|
|
224
|
+
}
|
|
225
|
+
for (const [key, edit] of snapshot) {
|
|
226
|
+
if (this.edits.get(key) === edit)
|
|
227
|
+
this.edits.delete(key);
|
|
228
|
+
}
|
|
229
|
+
this.failed = false;
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
this.failed = true;
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
finally {
|
|
237
|
+
this.saving = false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/** Whether any layer supplies the credential a secret field addresses. */
|
|
241
|
+
credentialConfigured(field) {
|
|
242
|
+
return field.secret === undefined ? Promise.resolve(false) : this.host.credentialConfigured(field.secret.ref);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
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 { Context, Service } from '@deepseek-ai/cordis';
|
|
23
|
+
/** Minimal shape of the ink Key flags the matcher reads (kept structurally
|
|
24
|
+
* compatible with `Key` from the ui kit without importing React-facing
|
|
25
|
+
* modules into the adapter). */
|
|
26
|
+
export interface TuiShortcutKey {
|
|
27
|
+
ctrl?: boolean;
|
|
28
|
+
meta?: boolean;
|
|
29
|
+
super?: boolean;
|
|
30
|
+
shift?: boolean;
|
|
31
|
+
return?: boolean;
|
|
32
|
+
escape?: boolean;
|
|
33
|
+
tab?: boolean;
|
|
34
|
+
backspace?: boolean;
|
|
35
|
+
delete?: boolean;
|
|
36
|
+
upArrow?: boolean;
|
|
37
|
+
downArrow?: boolean;
|
|
38
|
+
leftArrow?: boolean;
|
|
39
|
+
rightArrow?: boolean;
|
|
40
|
+
home?: boolean;
|
|
41
|
+
end?: boolean;
|
|
42
|
+
pageUp?: boolean;
|
|
43
|
+
pageDown?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface TuiShortcutOptions {
|
|
46
|
+
/** One-line description (shown by future /help surfaces; required so
|
|
47
|
+
* every binding is discoverable). */
|
|
48
|
+
description: string;
|
|
49
|
+
handler: () => void | Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
interface ParsedCombo {
|
|
52
|
+
readonly raw: string;
|
|
53
|
+
readonly ctrl: boolean;
|
|
54
|
+
readonly meta: boolean;
|
|
55
|
+
readonly shift: boolean;
|
|
56
|
+
/** Named key flag on the Key object, or undefined for a character key. */
|
|
57
|
+
readonly named?: keyof TuiShortcutKey;
|
|
58
|
+
/** Character to match against the ink `input` string (lowercased). */
|
|
59
|
+
readonly char?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse `ctrl+shift+p` style combos. Returns undefined on anything
|
|
63
|
+
* malformed or disallowed (no modifier, unknown key name); `allowReserved`
|
|
64
|
+
* is exposed for tests only.
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseShortcutCombo(raw: string): ParsedCombo | undefined;
|
|
67
|
+
/** Match a keypress against a parsed combo. `input` is ink's input string
|
|
68
|
+
* (already the resolved character; ctrl+space arrives as ' '). */
|
|
69
|
+
export declare function matchShortcut(combo: ParsedCombo, input: string, key: TuiShortcutKey): boolean;
|
|
70
|
+
declare module '@deepseek-ai/cordis' {
|
|
71
|
+
interface Context {
|
|
72
|
+
tuiShortcuts: TuiShortcutRuntime;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** `ctx.tuiShortcuts` — plugin keyboard shortcut registry. */
|
|
76
|
+
export declare class TuiShortcutRuntime extends Service {
|
|
77
|
+
private readonly shortcuts;
|
|
78
|
+
/** Handler invocation errors are surfaced through this hook — the chat
|
|
79
|
+
* screen wires it to its notification toast. */
|
|
80
|
+
onError: ((combo: string, error: unknown) => void) | undefined;
|
|
81
|
+
constructor(ctx: Context);
|
|
82
|
+
/**
|
|
83
|
+
* Bind `combo` to `handler`. Invalid, modifier-less, reserved, or
|
|
84
|
+
* duplicate combos are refused with a logger warning rather than a throw
|
|
85
|
+
* — a bad binding must not fail the plugin's whole boot.
|
|
86
|
+
*
|
|
87
|
+
* Returns the dispose function; the CALLER scopes it to its own fiber
|
|
88
|
+
* (`ctx.effect(() => dispose)`) — the same contract as `tuiScenes`
|
|
89
|
+
* registration. (A service method only sees the service's own ctx, so
|
|
90
|
+
* caller-fiber cleanup cannot happen here.)
|
|
91
|
+
*
|
|
92
|
+
* The optional trailing `identity` (the plugin's own ctx) only feeds the
|
|
93
|
+
* effect ledger's pluginId — omitting it records `undeclared` (C-060).
|
|
94
|
+
*/
|
|
95
|
+
register(combo: string, options: TuiShortcutOptions, identity?: Context): () => void;
|
|
96
|
+
/** Registered combos with descriptions (diagnostics / future /help). */
|
|
97
|
+
list(): readonly {
|
|
98
|
+
combo: string;
|
|
99
|
+
description: string;
|
|
100
|
+
}[];
|
|
101
|
+
/**
|
|
102
|
+
* Match a keypress; on a hit, run the handler and return true (the UI
|
|
103
|
+
* consumes the key). Handler rejections are caught and reported through
|
|
104
|
+
* {@link onError} — never propagated into the input path.
|
|
105
|
+
*/
|
|
106
|
+
dispatch(input: string, key: TuiShortcutKey): boolean;
|
|
107
|
+
}
|
|
108
|
+
export default TuiShortcutRuntime;
|
|
109
|
+
//# sourceMappingURL=shortcuts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortcuts.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/shortcuts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAGtD;;iCAEiC;AACjC,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC;0CACsC;IACtC,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACpC;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,cAAc,CAAA;IACrC,sEAAsE;IACtE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AA6DD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CA8CvE;AAkBD;mEACmE;AACnE,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAiB7F;AAED,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,YAAY,EAAE,kBAAkB,CAAA;KACjC;CACF;AAED,8DAA8D;AAC9D,qBAAa,kBAAmB,SAAQ,OAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE;qDACiD;IACjD,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;gBAElD,GAAG,EAAE,OAAO;IAIxB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,IAAI;IAoDpF,wEAAwE;IACxE,IAAI,IAAI,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;IAIzD;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;CAatD;AAED,eAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,268 @@
|
|
|
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
|
+
const NAMED_KEYS = {
|
|
25
|
+
enter: 'return',
|
|
26
|
+
return: 'return',
|
|
27
|
+
esc: 'escape',
|
|
28
|
+
escape: 'escape',
|
|
29
|
+
tab: 'tab',
|
|
30
|
+
backspace: 'backspace',
|
|
31
|
+
delete: 'delete',
|
|
32
|
+
up: 'upArrow',
|
|
33
|
+
down: 'downArrow',
|
|
34
|
+
left: 'leftArrow',
|
|
35
|
+
right: 'rightArrow',
|
|
36
|
+
home: 'home',
|
|
37
|
+
end: 'end',
|
|
38
|
+
pageup: 'pageUp',
|
|
39
|
+
pagedown: 'pageDown',
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Combos the TUI owns, globally or inside the prompt editor (the editor's
|
|
43
|
+
* bindings are checked AFTER plugin shortcuts, so refusing them here is
|
|
44
|
+
* what keeps "locals win" true). Built-in handlers match a MODIFIER SUBSET
|
|
45
|
+
* (`isMod(key) && input === 'x'` — they never exclude an extra Shift), so
|
|
46
|
+
* the reserved check below refuses a plugin combo whose SHIFTLESS form is
|
|
47
|
+
* reserved: ctrl+shift+x would shadow Ctrl+X on terminals that report both
|
|
48
|
+
* as the same keypress (ConPTY does), and would be dead weight on terminals
|
|
49
|
+
* that don't.
|
|
50
|
+
*/
|
|
51
|
+
const RESERVED_COMBOS = new Set([
|
|
52
|
+
'ctrl+c', // interrupt / clear
|
|
53
|
+
'ctrl+d', // exit on empty input
|
|
54
|
+
'ctrl+t', // startup context panel
|
|
55
|
+
'ctrl+r', // history search
|
|
56
|
+
'ctrl+x', // external editor
|
|
57
|
+
'ctrl+o', // transcript mode toggle
|
|
58
|
+
'ctrl+l', // terminal redraw
|
|
59
|
+
'ctrl+e', // show all messages / line end
|
|
60
|
+
'ctrl+v', // paste
|
|
61
|
+
'ctrl+a', // line start
|
|
62
|
+
'ctrl+u', // kill line
|
|
63
|
+
'ctrl+k', // kill to end
|
|
64
|
+
'ctrl+w', // kill word
|
|
65
|
+
'ctrl+left', // word jump
|
|
66
|
+
'ctrl+right', // word jump
|
|
67
|
+
'ctrl+return', // newline (multi-line input)
|
|
68
|
+
'ctrl+shift+return', // shift+Enter newline (CSI 13;6u) — same editor binding
|
|
69
|
+
'alt+return', // newline fallback on terminals without shift reporting
|
|
70
|
+
'alt+up', // pull the last pending message back for editing
|
|
71
|
+
'escape', // pickers / interrupt / rewind double-tap
|
|
72
|
+
'tab', // command completion
|
|
73
|
+
'shift+tab', // session-mode cycle
|
|
74
|
+
]);
|
|
75
|
+
/**
|
|
76
|
+
* Parse `ctrl+shift+p` style combos. Returns undefined on anything
|
|
77
|
+
* malformed or disallowed (no modifier, unknown key name); `allowReserved`
|
|
78
|
+
* is exposed for tests only.
|
|
79
|
+
*/
|
|
80
|
+
export function parseShortcutCombo(raw) {
|
|
81
|
+
const parts = String(raw ?? '')
|
|
82
|
+
.toLowerCase()
|
|
83
|
+
.split('+')
|
|
84
|
+
.map(part => part.trim())
|
|
85
|
+
.filter(part => part !== '');
|
|
86
|
+
if (parts.length === 0)
|
|
87
|
+
return undefined;
|
|
88
|
+
let ctrl = false;
|
|
89
|
+
let meta = false;
|
|
90
|
+
let shift = false;
|
|
91
|
+
let named;
|
|
92
|
+
let char;
|
|
93
|
+
for (const part of parts) {
|
|
94
|
+
if (part === 'ctrl' || part === 'control') {
|
|
95
|
+
if (ctrl)
|
|
96
|
+
return undefined;
|
|
97
|
+
ctrl = true;
|
|
98
|
+
}
|
|
99
|
+
else if (part === 'alt' || part === 'meta' || part === 'option') {
|
|
100
|
+
if (meta)
|
|
101
|
+
return undefined;
|
|
102
|
+
meta = true;
|
|
103
|
+
}
|
|
104
|
+
else if (part === 'shift') {
|
|
105
|
+
if (shift)
|
|
106
|
+
return undefined;
|
|
107
|
+
shift = true;
|
|
108
|
+
}
|
|
109
|
+
else if (part === 'space') {
|
|
110
|
+
if (char !== undefined || named !== undefined)
|
|
111
|
+
return undefined;
|
|
112
|
+
char = ' ';
|
|
113
|
+
}
|
|
114
|
+
else if (part in NAMED_KEYS) {
|
|
115
|
+
if (char !== undefined || named !== undefined)
|
|
116
|
+
return undefined;
|
|
117
|
+
named = NAMED_KEYS[part];
|
|
118
|
+
}
|
|
119
|
+
else if ([...part].length === 1) {
|
|
120
|
+
if (char !== undefined || named !== undefined)
|
|
121
|
+
return undefined;
|
|
122
|
+
char = part;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (char === undefined && named === undefined)
|
|
129
|
+
return undefined;
|
|
130
|
+
// Bare keys are typing/navigation; a modifier is what makes a shortcut.
|
|
131
|
+
if (!ctrl && !meta)
|
|
132
|
+
return undefined;
|
|
133
|
+
// Escape combos are refused outright: the input layer sets key.meta = true
|
|
134
|
+
// for EVERY Escape (ink/events/input-event.ts — `keypress.meta ||
|
|
135
|
+
// keypress.name === 'escape' || keypress.option`), so an alt+escape combo
|
|
136
|
+
// would match every bare Esc press and shadow clear-input / the double-Esc
|
|
137
|
+
// rewind. Esc is fully owned by the TUI; there is no unambiguous way to
|
|
138
|
+
// bind it.
|
|
139
|
+
if (named === 'escape')
|
|
140
|
+
return undefined;
|
|
141
|
+
return { raw: parts.join('+'), ctrl, meta, shift, ...(named === undefined ? {} : { named }), ...(char === undefined ? {} : { char }) };
|
|
142
|
+
}
|
|
143
|
+
/** Canonical form for dedupe/reserved checks: modifiers sorted, key last. */
|
|
144
|
+
function comboKey(combo) {
|
|
145
|
+
const mods = [combo.ctrl ? 'ctrl' : '', combo.meta ? 'alt' : '', combo.shift ? 'shift' : '']
|
|
146
|
+
.filter(part => part !== '')
|
|
147
|
+
.sort();
|
|
148
|
+
return [...mods, combo.named === undefined ? (combo.char ?? '') : String(combo.named)].join('+');
|
|
149
|
+
}
|
|
150
|
+
/** Reserved lookup accepts user-spelled combos too (`ctrl+c`). */
|
|
151
|
+
function reservedKey(raw) {
|
|
152
|
+
const combo = parseShortcutCombo(raw);
|
|
153
|
+
return combo === undefined ? raw.toLowerCase() : comboKey(combo);
|
|
154
|
+
}
|
|
155
|
+
const RESERVED_CANONICAL = new Set([...RESERVED_COMBOS].map(reservedKey));
|
|
156
|
+
/** Match a keypress against a parsed combo. `input` is ink's input string
|
|
157
|
+
* (already the resolved character; ctrl+space arrives as ' '). */
|
|
158
|
+
export function matchShortcut(combo, input, key) {
|
|
159
|
+
if (Boolean(key.ctrl) !== combo.ctrl)
|
|
160
|
+
return false;
|
|
161
|
+
// ink reports Alt as meta; Esc itself also sets meta, which is why the
|
|
162
|
+
// modifier check runs against the combo, not a bare flag read.
|
|
163
|
+
if (Boolean(key.meta) !== combo.meta)
|
|
164
|
+
return false;
|
|
165
|
+
if (key.super)
|
|
166
|
+
return false;
|
|
167
|
+
// Shift must match for NAMED keys exactly as for characters — otherwise a
|
|
168
|
+
// registered ctrl+shift+enter would also match a plain ctrl+enter press,
|
|
169
|
+
// letting a plugin shadow the editor's built-in Ctrl+Enter delivery.
|
|
170
|
+
if (Boolean(key.shift) !== combo.shift)
|
|
171
|
+
return false;
|
|
172
|
+
if (combo.named !== undefined) {
|
|
173
|
+
return key[combo.named] === true;
|
|
174
|
+
}
|
|
175
|
+
if (combo.char === undefined)
|
|
176
|
+
return false;
|
|
177
|
+
// Shift+letter arrives as the uppercase character; compare case-folded
|
|
178
|
+
// (the shift FLAG equality above already pinned the modifier state).
|
|
179
|
+
return input.toLowerCase() === combo.char;
|
|
180
|
+
}
|
|
181
|
+
/** `ctx.tuiShortcuts` — plugin keyboard shortcut registry. */
|
|
182
|
+
export class TuiShortcutRuntime extends Service {
|
|
183
|
+
shortcuts = new Map();
|
|
184
|
+
/** Handler invocation errors are surfaced through this hook — the chat
|
|
185
|
+
* screen wires it to its notification toast. */
|
|
186
|
+
onError;
|
|
187
|
+
constructor(ctx) {
|
|
188
|
+
super(ctx, 'tuiShortcuts');
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Bind `combo` to `handler`. Invalid, modifier-less, reserved, or
|
|
192
|
+
* duplicate combos are refused with a logger warning rather than a throw
|
|
193
|
+
* — a bad binding must not fail the plugin's whole boot.
|
|
194
|
+
*
|
|
195
|
+
* Returns the dispose function; the CALLER scopes it to its own fiber
|
|
196
|
+
* (`ctx.effect(() => dispose)`) — the same contract as `tuiScenes`
|
|
197
|
+
* registration. (A service method only sees the service's own ctx, so
|
|
198
|
+
* caller-fiber cleanup cannot happen here.)
|
|
199
|
+
*
|
|
200
|
+
* The optional trailing `identity` (the plugin's own ctx) only feeds the
|
|
201
|
+
* effect ledger's pluginId — omitting it records `undeclared` (C-060).
|
|
202
|
+
*/
|
|
203
|
+
register(combo, options, identity) {
|
|
204
|
+
const parsed = parseShortcutCombo(combo);
|
|
205
|
+
if (parsed === undefined) {
|
|
206
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected ${JSON.stringify(combo)} — need ctrl/alt plus one key (e.g. "ctrl+shift+p")`);
|
|
207
|
+
return () => { };
|
|
208
|
+
}
|
|
209
|
+
const key = comboKey(parsed);
|
|
210
|
+
// Built-ins match a modifier subset (see RESERVED_COMBOS): a combo whose
|
|
211
|
+
// SHIFTLESS form is reserved collides with the built-in on terminals that
|
|
212
|
+
// don't report Shift distinctly, so it is refused too. The exact form is
|
|
213
|
+
// still checked for combos reserved WITH shift (ctrl+shift+return).
|
|
214
|
+
const shiftlessKey = comboKey({ ...parsed, shift: false });
|
|
215
|
+
if (RESERVED_CANONICAL.has(key) || RESERVED_CANONICAL.has(shiftlessKey)) {
|
|
216
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${combo}" — reserved by a built-in binding`);
|
|
217
|
+
return () => { };
|
|
218
|
+
}
|
|
219
|
+
if (this.shortcuts.has(key)) {
|
|
220
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${combo}" — already registered`);
|
|
221
|
+
this.ctx.get('tuiEffectLedger')?.record({
|
|
222
|
+
operation: 'bind',
|
|
223
|
+
resource: { kind: 'shortcut', id: key },
|
|
224
|
+
result: 'failed',
|
|
225
|
+
errorCode: 'DUPLICATE_CONTRIBUTION_ID',
|
|
226
|
+
}, identity);
|
|
227
|
+
return () => { };
|
|
228
|
+
}
|
|
229
|
+
const description = cleanScalarText(options?.description, 120);
|
|
230
|
+
if (typeof options?.handler !== 'function' || description === '') {
|
|
231
|
+
this.ctx.logger.warn(`dsh-tui: tuiShortcuts.register rejected "${combo}" — needs a description and a handler`);
|
|
232
|
+
return () => { };
|
|
233
|
+
}
|
|
234
|
+
const entry = { combo: parsed, description, handler: options.handler };
|
|
235
|
+
this.shortcuts.set(key, entry);
|
|
236
|
+
this.ctx.get('tuiEffectLedger')?.record({ operation: 'bind', resource: { kind: 'shortcut', id: key }, result: 'applied' }, identity);
|
|
237
|
+
return () => {
|
|
238
|
+
if (this.shortcuts.get(key) !== entry)
|
|
239
|
+
return;
|
|
240
|
+
this.shortcuts.delete(key);
|
|
241
|
+
this.ctx.get('tuiEffectLedger')?.record({ operation: 'release', resource: { kind: 'shortcut', id: key }, result: 'applied' }, identity);
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/** Registered combos with descriptions (diagnostics / future /help). */
|
|
245
|
+
list() {
|
|
246
|
+
return [...this.shortcuts.values()].map(entry => ({ combo: entry.combo.raw, description: entry.description }));
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Match a keypress; on a hit, run the handler and return true (the UI
|
|
250
|
+
* consumes the key). Handler rejections are caught and reported through
|
|
251
|
+
* {@link onError} — never propagated into the input path.
|
|
252
|
+
*/
|
|
253
|
+
dispatch(input, key) {
|
|
254
|
+
for (const entry of this.shortcuts.values()) {
|
|
255
|
+
if (!matchShortcut(entry.combo, input, key))
|
|
256
|
+
continue;
|
|
257
|
+
Promise.resolve()
|
|
258
|
+
.then(() => entry.handler())
|
|
259
|
+
.catch((error) => {
|
|
260
|
+
this.onError?.(entry.combo.raw, error);
|
|
261
|
+
this.ctx.logger.warn(`dsh-tui: shortcut "${entry.combo.raw}" handler failed: %o`, error);
|
|
262
|
+
});
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
export default TuiShortcutRuntime;
|