@deepseek-harness-tui/dsh-tui 0.8.0 → 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 +13 -5
- package/cordis.patch.yml +21 -2
- package/cordis.yml +12 -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 +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 -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.map +1 -1
- package/lib/types/components/MessageList.js +25 -1
- 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/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.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +1 -1
- package/lib/types/dsh-adapter/channel.d.ts +30 -7
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +503 -21
- 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 +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 +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/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 +47 -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/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 +7 -1
- package/lib/types/dsh-adapter/scenes.d.ts.map +1 -1
- package/lib/types/dsh-adapter/scenes.js +17 -2
- 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 +162 -16
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +53 -5
- 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/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/screens/Chat.d.ts +14 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +142 -39
- 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/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 +105 -70
- 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
|
@@ -27,6 +27,102 @@ import { modeDisplayName, resolveSessionModes } from '../sessionModes.js';
|
|
|
27
27
|
import { ActivityTracker } from 'dsh-working-activity/status';
|
|
28
28
|
import { attachSessionToWorkspace } from './workspace.js';
|
|
29
29
|
import { createLocalWorkspaceRuntime } from './workspaces.js';
|
|
30
|
+
import { dispatchTuiDecision, dispatchTuiNotification, normalizeCancelDecision } from './extension-events.js';
|
|
31
|
+
import { installDecisionGuard } from './decision-guard.js';
|
|
32
|
+
import { commandOwner } from './command-attribution.js';
|
|
33
|
+
import { readGrantStore } from './grants.js';
|
|
34
|
+
import { hasCommandErrorCode, mapCommandError } from './command-errors.js';
|
|
35
|
+
import { pluginsInfoLines } from './plugins-info.js';
|
|
36
|
+
import { cleanRenderText, cleanScalarText } from './sanitize.js';
|
|
37
|
+
/** `tui/input` return normalization: transform/handled/cancel or no opinion.
|
|
38
|
+
* A blank `{ text }` rewrite is NOT a decision — it is logged and the chain
|
|
39
|
+
* continues so a later veto listener still runs. */
|
|
40
|
+
function normalizeInputDecision(result, warn) {
|
|
41
|
+
if (result === undefined || result === null || result === false)
|
|
42
|
+
return undefined;
|
|
43
|
+
if (typeof result !== 'object') {
|
|
44
|
+
warn(`a non-object (${typeof result})`);
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const record = result;
|
|
48
|
+
if (record.cancel === true) {
|
|
49
|
+
const reason = cleanScalarText(record.reason, NOTICE_CELLS);
|
|
50
|
+
return { cancel: true, ...(reason === '' ? {} : { reason }) };
|
|
51
|
+
}
|
|
52
|
+
if (record.handled === true) {
|
|
53
|
+
const notice = cleanScalarText(record.notice, NOTICE_CELLS);
|
|
54
|
+
return { handled: true, ...(notice === '' ? {} : { notice }) };
|
|
55
|
+
}
|
|
56
|
+
if (typeof record.text === 'string') {
|
|
57
|
+
if (record.text.trim() === '') {
|
|
58
|
+
warn('a blank {text} rewrite');
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return { text: record.text };
|
|
62
|
+
}
|
|
63
|
+
warn('an unrecognized decision shape');
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
/** `tui/rewind-prompt` return normalization: cancel/modes or no opinion.
|
|
67
|
+
* Modes are COPIED with only validated, sanitized scalar fields — the raw
|
|
68
|
+
* plugin object must never reach the render path (a `description: {}` would
|
|
69
|
+
* crash ListItem's `.replace`, and control chars would corrupt the pane).
|
|
70
|
+
* Notices/reasons are toast-bound plugin text: sanitized too (see
|
|
71
|
+
* ./sanitize.js — the one implementation of the render-path contract). */
|
|
72
|
+
function normalizeRewindPromptDecision(result, warn) {
|
|
73
|
+
if (result === undefined || result === null || result === false)
|
|
74
|
+
return undefined;
|
|
75
|
+
if (typeof result !== 'object') {
|
|
76
|
+
warn(`a non-object (${typeof result})`);
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const record = result;
|
|
80
|
+
if (record.cancel === true) {
|
|
81
|
+
const reason = cleanScalarText(record.reason, NOTICE_CELLS);
|
|
82
|
+
return { cancel: true, ...(reason === '' ? {} : { reason }) };
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(record.modes)) {
|
|
85
|
+
const modes = [];
|
|
86
|
+
for (const raw of record.modes) {
|
|
87
|
+
if (modes.length >= 8)
|
|
88
|
+
break;
|
|
89
|
+
if (raw === null || typeof raw !== 'object')
|
|
90
|
+
continue;
|
|
91
|
+
const candidate = raw;
|
|
92
|
+
if (typeof candidate.id !== 'string' || candidate.id.trim() === '')
|
|
93
|
+
continue;
|
|
94
|
+
const label = typeof candidate.label === 'string' ? cleanRenderText(candidate.label, 120) : '';
|
|
95
|
+
if (label === '')
|
|
96
|
+
continue;
|
|
97
|
+
const description = typeof candidate.description === 'string' && candidate.description.trim() !== ''
|
|
98
|
+
? cleanRenderText(candidate.description, 400)
|
|
99
|
+
: undefined;
|
|
100
|
+
modes.push({ id: candidate.id, label, ...(description === undefined ? {} : { description }) });
|
|
101
|
+
}
|
|
102
|
+
if (modes.length === 0) {
|
|
103
|
+
warn('an empty or invalid {modes} list');
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
return { modes };
|
|
107
|
+
}
|
|
108
|
+
warn('an unrecognized decision shape');
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
/** Toast-bound plugin text (veto reasons, handled notices, rewind summaries)
|
|
112
|
+
* is render-path data too: same sanitization, toast-width cap. */
|
|
113
|
+
const NOTICE_CELLS = 200;
|
|
114
|
+
/** `tui/rewind-done` return normalization: the first non-empty STRING is the
|
|
115
|
+
* summary; anything else is not a decision. */
|
|
116
|
+
function normalizeRewindDoneSummary(result, warn) {
|
|
117
|
+
if (result === undefined || result === null || result === false)
|
|
118
|
+
return undefined;
|
|
119
|
+
if (typeof result === 'string') {
|
|
120
|
+
const summary = cleanRenderText(result, NOTICE_CELLS);
|
|
121
|
+
return summary === '' ? undefined : summary;
|
|
122
|
+
}
|
|
123
|
+
warn('a non-string summary');
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
30
126
|
/**
|
|
31
127
|
* Delay before re-reading a skill catalog that reported an incomplete
|
|
32
128
|
* observation (a provider whose directory watcher is still warming).
|
|
@@ -288,12 +384,29 @@ async function waitForTurnEnd(session, fromSeq, timeoutMs) {
|
|
|
288
384
|
export function createChannel(ctx, initialAgent, options) {
|
|
289
385
|
let agent = initialAgent;
|
|
290
386
|
let currentHandle = options.handle;
|
|
387
|
+
// D-7 backstop: the extensions row installs the decision-subscription
|
|
388
|
+
// gate, but the channel IS the dispatch path — a stale patch without that
|
|
389
|
+
// row (or a bare embed mounting neither) would otherwise leave tui/input
|
|
390
|
+
// & friends subscribable by default, silently voiding the default-deny
|
|
391
|
+
// posture. Idempotent per cordis root, so the full-patch path installs
|
|
392
|
+
// exactly once whichever side runs first. One store instance serves both
|
|
393
|
+
// the gate and the invoke checkpoint below.
|
|
394
|
+
// Keep a private fallback for bare embedders, but resolve the host-owned
|
|
395
|
+
// store on every operation so a plugin-host row mounted later (or a custom
|
|
396
|
+
// live GrantStore) is not shadowed by an early snapshot.
|
|
397
|
+
const fallbackGrantStore = readGrantStore();
|
|
398
|
+
const currentGrantStore = () => ctx.get('tuiPluginHost')?.grants ?? fallbackGrantStore;
|
|
399
|
+
installDecisionGuard(ctx, currentGrantStore());
|
|
291
400
|
// The DSH slash-command registry (optional service): /plan, /goal and
|
|
292
401
|
// friends register here; the TUI merges their descriptors into the slash
|
|
293
402
|
// menu and dispatches through `execute` (which logs the paired
|
|
294
403
|
// command/run + command/done records). Absent the service, only the
|
|
295
404
|
// built-in local commands exist.
|
|
296
405
|
const commandService = ctx.get('commands');
|
|
406
|
+
// messages.observe broker (optional service, C-042): mounted by the
|
|
407
|
+
// dsh-tui-plugin-host row; absent the row, publish is a no-op and nothing
|
|
408
|
+
// else changes (soft degradation, #183).
|
|
409
|
+
const messageObserver = ctx.get('tuiMessageObserver');
|
|
297
410
|
// Workspace registry runtime (optional service, issue #183): mounted by
|
|
298
411
|
// the bundle patch's dsh-tui-workspaces row; absent the row (stale patch
|
|
299
412
|
// or a bare embedder), degrade to the local-only runtime. plugin.ts owns
|
|
@@ -311,6 +424,10 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
311
424
|
// tuiWorkspaces/tuiCommandTrees): mounted by the bundle patch's
|
|
312
425
|
// dsh-tui-scenes row; absent the row, `pluginScene` simply stays undefined.
|
|
313
426
|
const sceneRuntime = ctx.get('tuiScenes');
|
|
427
|
+
// Custom-entry text renderers (optional service, dsh-tui-extensions row):
|
|
428
|
+
// absent the row, unknown plugin event types stay invisible in the
|
|
429
|
+
// transcript, exactly as before the seam existed.
|
|
430
|
+
const rendererRuntime = ctx.get('tuiRenderers');
|
|
314
431
|
// Shift+Tab session-mode cycle: cordis.yml `modes` wins; absent/empty/
|
|
315
432
|
// atom-less → the built-in default/plan/full cycle (sessionModes.ts).
|
|
316
433
|
const { modes: sessionModes, dropped: droppedModeIds } = resolveSessionModes(options.modes);
|
|
@@ -405,6 +522,142 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
405
522
|
state.notify(t('send-failed', { err: message }), { color: 'error' });
|
|
406
523
|
});
|
|
407
524
|
};
|
|
525
|
+
/**
|
|
526
|
+
* RFC 0005 D-8: a flow parked on a plugin decision must be user-observable.
|
|
527
|
+
* Decisions normally resolve in milliseconds, so the notice only fires
|
|
528
|
+
* once the wait crosses a threshold — a slow plugin (e.g. one showing a
|
|
529
|
+
* managed dialog) then explains the pause instead of looking like the TUI
|
|
530
|
+
* ate the input.
|
|
531
|
+
*/
|
|
532
|
+
const DECISION_PENDING_MS = 400;
|
|
533
|
+
const withDecisionPending = (name, pending) => {
|
|
534
|
+
let dismiss;
|
|
535
|
+
const timer = setTimeout(() => {
|
|
536
|
+
// Sticky (timeoutMs 0), D-8: the indicator must cover the WHOLE wait —
|
|
537
|
+
// an auto-expiring notice would vanish after ~4s while the decision,
|
|
538
|
+
// the delivery and every queued FIFO task behind them stay parked,
|
|
539
|
+
// leaving the user with no sign the flow is still waiting. It comes
|
|
540
|
+
// down only when the decision settles (finally below); a decision
|
|
541
|
+
// that never settles keeps its indicator up, which is the truthful
|
|
542
|
+
// state.
|
|
543
|
+
dismiss = state.notify(t('ext-decision-pending', { event: name }), { timeoutMs: 0 });
|
|
544
|
+
}, DECISION_PENDING_MS);
|
|
545
|
+
// Both exits are covered: a fast decision clears the timer before it
|
|
546
|
+
// fires; a slow one dismisses the indicator it raised.
|
|
547
|
+
return pending.finally(() => {
|
|
548
|
+
clearTimeout(timer);
|
|
549
|
+
dismiss?.();
|
|
550
|
+
});
|
|
551
|
+
};
|
|
552
|
+
/**
|
|
553
|
+
* The `tui/input` decision event (pi's `input` seam): the FIRST plugin
|
|
554
|
+
* returning a valid decision wins — transform the text, mark it handled,
|
|
555
|
+
* or cancel it. No listeners (or only crashing/malformed ones) means
|
|
556
|
+
* delivery proceeds unchanged, so a broken plugin can never wedge the
|
|
557
|
+
* input path — and can never skip a later veto listener either
|
|
558
|
+
* (dispatchTuiDecision isolates crashes and normalizes returns per
|
|
559
|
+
* listener instead of bailing on the first object).
|
|
560
|
+
*
|
|
561
|
+
* Decision AND delivery enter one FIFO chain in submission order: a slow
|
|
562
|
+
* listener on A parks A's delivery AND any later submissions behind it —
|
|
563
|
+
* without the chain, B's decision could resolve first and the model would
|
|
564
|
+
* receive B before A. Each submission binds its origin agent AT ENQUEUE,
|
|
565
|
+
* so a session switch landing before OR during its decision drops the
|
|
566
|
+
* stale text with a notice instead of sending the old conversation's
|
|
567
|
+
* words to the new session.
|
|
568
|
+
*/
|
|
569
|
+
let inputChain = Promise.resolve();
|
|
570
|
+
const runUserTextDecision = async (text, placement, originAgent, originAgentId) => {
|
|
571
|
+
// Stale detection compares the AGENT REFERENCE, not the id: session ids
|
|
572
|
+
// are reusable (A → /new → /resume A lands back on the same id with a
|
|
573
|
+
// fresh agent), so an id check has an ABA hole. Both origin values are
|
|
574
|
+
// ENQUEUE-time captures (see dispatchUserText): a decision parked behind
|
|
575
|
+
// a slow predecessor must still be judged against the session its text
|
|
576
|
+
// was typed in, not whichever session is live when it finally runs.
|
|
577
|
+
const decision = await withDecisionPending('tui/input', dispatchTuiDecision(ctx, 'tui/input', {
|
|
578
|
+
text,
|
|
579
|
+
delivery: placement === 'steer' ? 'steer' : 'followup',
|
|
580
|
+
sessionId: originAgentId,
|
|
581
|
+
cwd: state.cwd,
|
|
582
|
+
}, normalizeInputDecision));
|
|
583
|
+
if (decision !== undefined) {
|
|
584
|
+
// Both intercepts toast — a bare {cancel}/{handled} must not make the
|
|
585
|
+
// typed line vanish silently (the host-localized fallback mirrors the
|
|
586
|
+
// other decision events' ext-action-cancelled handling).
|
|
587
|
+
if ('cancel' in decision) {
|
|
588
|
+
state.notify(decision.reason ?? t('ext-action-cancelled'), { color: 'warning', timeoutMs: 4000 });
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if ('handled' in decision) {
|
|
592
|
+
state.notify(decision.notice ?? t('ext-action-handled'), { timeoutMs: 4000 });
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
text = decision.text.trim();
|
|
596
|
+
}
|
|
597
|
+
if (agent !== originAgent) {
|
|
598
|
+
state.notify(t('ext-stale-dropped'), { color: 'warning', timeoutMs: 4000 });
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
deliverUserText(text, placement);
|
|
602
|
+
};
|
|
603
|
+
const dispatchUserText = (text, placement) => {
|
|
604
|
+
// D-6: bind the submission to the session it was typed in AT ENQUEUE
|
|
605
|
+
// TIME. The FIFO chain may park this task behind a slow predecessor
|
|
606
|
+
// while the user /new's away — capturing the agent at run time would
|
|
607
|
+
// adopt the NEW session as this text's origin and deliver the old
|
|
608
|
+
// conversation's words into it.
|
|
609
|
+
const originAgent = agent;
|
|
610
|
+
const originAgentId = state.agentId;
|
|
611
|
+
inputChain = inputChain.then(() => runUserTextDecision(text, placement, originAgent, originAgentId)).catch((error) => {
|
|
612
|
+
// The chain must survive a failed decision: log, then continue with
|
|
613
|
+
// the next queued submission.
|
|
614
|
+
ctx.logger.warn('dsh-tui: tui/input dispatch failed: %o', error);
|
|
615
|
+
});
|
|
616
|
+
};
|
|
617
|
+
/**
|
|
618
|
+
* The `tui/session-switch` decision event (pi's `session_before_switch`),
|
|
619
|
+
* fired before `/new` or `/resume` replaces the live session (rewind has
|
|
620
|
+
* its own prompt event). The first answering plugin may veto the switch;
|
|
621
|
+
* the reason is toasted here so the fallback string stays host-localized.
|
|
622
|
+
*/
|
|
623
|
+
const sessionSwitchVetoed = async (kind, targetSessionId) => {
|
|
624
|
+
// D-6 stale detection captures the AGENT REFERENCE (session ids are
|
|
625
|
+
// reusable — ABA): a slow decision must not let an older /resume roll
|
|
626
|
+
// over a newer session the user already switched to mid-await.
|
|
627
|
+
const originAgent = agent;
|
|
628
|
+
const decision = await withDecisionPending('tui/session-switch', dispatchTuiDecision(ctx, 'tui/session-switch', {
|
|
629
|
+
kind,
|
|
630
|
+
...(targetSessionId === undefined ? {} : { targetSessionId }),
|
|
631
|
+
sessionId: state.agentId,
|
|
632
|
+
cwd: state.cwd,
|
|
633
|
+
}, normalizeCancelDecision));
|
|
634
|
+
if (agent !== originAgent) {
|
|
635
|
+
// The world changed while the decision parked: drop the pending
|
|
636
|
+
// switch instead of replacing the user's newer session.
|
|
637
|
+
state.notify(t('ext-stale-dropped'), { color: 'warning', timeoutMs: 4000 });
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
if (decision !== undefined) {
|
|
641
|
+
state.notify(decision.reason ?? t('ext-action-cancelled'), { color: 'warning', timeoutMs: 4000 });
|
|
642
|
+
return true;
|
|
643
|
+
}
|
|
644
|
+
return false;
|
|
645
|
+
};
|
|
646
|
+
/** Fire-and-forget `tui/session-switched` (parallel): per-session plugin
|
|
647
|
+
* state rebinds here. Listener failures are logged, never propagated —
|
|
648
|
+
* the switch itself already succeeded. */
|
|
649
|
+
const notifySessionSwitched = (kind, sessionId, previousSessionId) => {
|
|
650
|
+
try {
|
|
651
|
+
void dispatchTuiNotification(ctx, 'tui/session-switched', { kind, sessionId, previousSessionId, cwd: state.cwd }).catch((error) => {
|
|
652
|
+
ctx.logger.warn('dsh-tui: tui/session-switched listener failed: %o', error);
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
catch (error) {
|
|
656
|
+
// A bare embedder's context may lack the event bus entirely; the
|
|
657
|
+
// switch itself already succeeded, so this stays a log line.
|
|
658
|
+
ctx.logger.warn('dsh-tui: tui/session-switched dispatch failed: %o', error);
|
|
659
|
+
}
|
|
660
|
+
};
|
|
408
661
|
/** Monotonic token: only the latest `interruptAndDeliver` re-queues, so a
|
|
409
662
|
* second interrupt while the abort settles cannot double-deliver. */
|
|
410
663
|
let interruptSeq = 0;
|
|
@@ -519,6 +772,45 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
519
772
|
const executeRegistryCommand = async (name, rawInput) => {
|
|
520
773
|
if (!commandService)
|
|
521
774
|
return undefined;
|
|
775
|
+
// Resolve the exact definition that execute() will select for this agent.
|
|
776
|
+
// Same names may exist in distinct agent scopes, so a name-only lookup can
|
|
777
|
+
// apply another scope's owner policy.
|
|
778
|
+
const definition = commandService.find(agent, name);
|
|
779
|
+
const owner = commandOwner(ctx, definition);
|
|
780
|
+
// The root checkpoint covers host/direct registrations. A built-in name
|
|
781
|
+
// is not necessarily a namespaced contribution id, so use a deterministic
|
|
782
|
+
// host scope for that case; legacy unscoped denies still conservatively
|
|
783
|
+
// revoke every valid command scope.
|
|
784
|
+
const rootScope = owner?.commandId
|
|
785
|
+
?? (/^[a-z][a-z0-9]*(?:[.-][a-z0-9][a-z0-9-]*)+$/u.test(name)
|
|
786
|
+
? name
|
|
787
|
+
: `dsh-tui.${name.toLowerCase().replace(/[^a-z0-9-]+/gu, '-').replace(/^-+|-+$/gu, '') || 'command'}`);
|
|
788
|
+
if (!currentGrantStore().allows({ componentId: 'root' }, 'commands.invoke', rootScope)) {
|
|
789
|
+
ctx.logger.warn('dsh-tui: registry command invocation denied (commands.invoke revoked for "root" in the grants file)');
|
|
790
|
+
ctx.get('tuiEffectLedger')?.record({
|
|
791
|
+
operation: 'bind',
|
|
792
|
+
resource: { kind: 'permission', id: `root:commands.invoke:${rootScope}` },
|
|
793
|
+
result: 'failed',
|
|
794
|
+
errorCode: 'PERMISSION_NOT_GRANTED',
|
|
795
|
+
}, ctx);
|
|
796
|
+
return t('command-invoke-denied');
|
|
797
|
+
}
|
|
798
|
+
// Per-owner gate (C-041): a command REGISTERED BY A PLUGIN through the
|
|
799
|
+
// plugin-host row's mediated registerCommand (see command-attribution.js)
|
|
800
|
+
// is additionally gated on the OWNER's grant, so a denies entry for the
|
|
801
|
+
// plugin closes the host-mediated invocation of ITS commands.
|
|
802
|
+
// Unattributed host/direct registrations remain inside the documented
|
|
803
|
+
// trusted-in-process boundary and have no plugin grant to evaluate.
|
|
804
|
+
if (owner !== undefined && !currentGrantStore().allows({ componentId: owner.componentId, activationId: owner.activationId }, 'commands.invoke', owner.commandId)) {
|
|
805
|
+
ctx.logger.warn(`dsh-tui: registry command "/${name}" invocation denied — owner Component "${owner.componentId}" lost commands.invoke for "${owner.commandId}"`);
|
|
806
|
+
ctx.get('tuiEffectLedger')?.record({
|
|
807
|
+
operation: 'bind',
|
|
808
|
+
resource: { kind: 'permission', id: `${owner.componentId}:commands.invoke:${owner.commandId}` },
|
|
809
|
+
result: 'failed',
|
|
810
|
+
errorCode: 'PERMISSION_NOT_GRANTED',
|
|
811
|
+
}, ctx);
|
|
812
|
+
return t('command-invoke-denied-owner', { name, owner: owner.componentId });
|
|
813
|
+
}
|
|
522
814
|
try {
|
|
523
815
|
const execution = await commandService.execute(agent, `/${name}${rawInput}`, new AbortController().signal);
|
|
524
816
|
// `undefined` = not registered; a handler error surfaces as its
|
|
@@ -778,7 +1070,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
778
1070
|
// The current session is being used — move it to the MRU front
|
|
779
1071
|
// (/resume sorts by last-used).
|
|
780
1072
|
touchSession(state.agentId);
|
|
781
|
-
|
|
1073
|
+
void dispatchUserText(trimmed, 'followup');
|
|
782
1074
|
},
|
|
783
1075
|
/** Steer a message into the RUNNING turn (Codex/pi semantics): it is
|
|
784
1076
|
* injected at the next step boundary of the current turn and the agent
|
|
@@ -788,11 +1080,13 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
788
1080
|
if (!trimmed)
|
|
789
1081
|
return;
|
|
790
1082
|
touchSession(state.agentId);
|
|
791
|
-
//
|
|
792
|
-
//
|
|
793
|
-
//
|
|
794
|
-
//
|
|
795
|
-
|
|
1083
|
+
// Same tui/input decision pass as submit; the delivery re-validates
|
|
1084
|
+
// the live agent after the await. Official dsh-agent rc.6: steer() is
|
|
1085
|
+
// synchronous void — the message enters the next-step inbox; a
|
|
1086
|
+
// rejected step leaves it parked for the next wake, and the inbox
|
|
1087
|
+
// events retire the preview (claimed → turn boundary, discarded →
|
|
1088
|
+
// cancel).
|
|
1089
|
+
void dispatchUserText(trimmed, 'steer');
|
|
796
1090
|
},
|
|
797
1091
|
/** Pull a pending message back out of the inbox (Alt+Up): it returns to
|
|
798
1092
|
* the input for editing instead of being delivered. */
|
|
@@ -838,7 +1132,10 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
838
1132
|
return;
|
|
839
1133
|
for (const text of queued) {
|
|
840
1134
|
touchSession(state.agentId);
|
|
841
|
-
|
|
1135
|
+
// Same tui/input decision pass as a typed submit: Ctrl+Enter must
|
|
1136
|
+
// not bypass a plugin's cancel/transform policy, and re-queued
|
|
1137
|
+
// texts keep submission order through the one FIFO chain.
|
|
1138
|
+
dispatchUserText(text, 'followup');
|
|
842
1139
|
}
|
|
843
1140
|
};
|
|
844
1141
|
if (typeof whenIdle === 'function') {
|
|
@@ -851,7 +1148,43 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
851
1148
|
}
|
|
852
1149
|
return queued.length;
|
|
853
1150
|
},
|
|
854
|
-
|
|
1151
|
+
/**
|
|
1152
|
+
* The `tui/rewind-prompt` decision event (pi's `session_before_fork`):
|
|
1153
|
+
* fired when the rewind picker confirms a message, before any fork
|
|
1154
|
+
* work. The first answering plugin may cancel the rewind (the picker
|
|
1155
|
+
* stays open; the reason is toasted here so the UI string stays
|
|
1156
|
+
* host-localized when absent) or offer extra modes rendered in the
|
|
1157
|
+
* confirm pane. Returns 'cancel', the modes, or null for "no opinion".
|
|
1158
|
+
*/
|
|
1159
|
+
async promptRewind(row) {
|
|
1160
|
+
if (row.seq === undefined)
|
|
1161
|
+
return null;
|
|
1162
|
+
// D-6, same as the other decision points: a slow /new or /resume can
|
|
1163
|
+
// replace the agent while this decision parks. Without the identity
|
|
1164
|
+
// check the picker would go on to show the OLD session's row in the
|
|
1165
|
+
// confirm pane and rewindTo would cut the NEW session at the old
|
|
1166
|
+
// seq — a wrong rewind or a fork failure. Compare agent REFERENCES
|
|
1167
|
+
// (session ids are reusable — ABA) and stale-cancel.
|
|
1168
|
+
const originAgent = agent;
|
|
1169
|
+
const decision = await withDecisionPending('tui/rewind-prompt', dispatchTuiDecision(ctx, 'tui/rewind-prompt', {
|
|
1170
|
+
text: row.text,
|
|
1171
|
+
seq: row.seq,
|
|
1172
|
+
sessionId: state.agentId,
|
|
1173
|
+
cwd: state.cwd,
|
|
1174
|
+
}, normalizeRewindPromptDecision));
|
|
1175
|
+
if (agent !== originAgent) {
|
|
1176
|
+
state.notify(t('ext-stale-dropped'), { color: 'warning', timeoutMs: 4000 });
|
|
1177
|
+
return 'cancel';
|
|
1178
|
+
}
|
|
1179
|
+
if (decision === undefined)
|
|
1180
|
+
return null;
|
|
1181
|
+
if ('cancel' in decision) {
|
|
1182
|
+
state.notify(decision.reason ?? t('ext-action-cancelled'), { color: 'warning', timeoutMs: 4000 });
|
|
1183
|
+
return 'cancel';
|
|
1184
|
+
}
|
|
1185
|
+
return { modes: decision.modes };
|
|
1186
|
+
},
|
|
1187
|
+
async rewindTo(row, mode = null) {
|
|
855
1188
|
if (row.seq === undefined)
|
|
856
1189
|
return null;
|
|
857
1190
|
const sessions = ctx.get('sessions');
|
|
@@ -984,6 +1317,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
984
1317
|
renderEvent(event);
|
|
985
1318
|
// Rebind subscriptions to the new agent, then free the old one.
|
|
986
1319
|
const oldHandle = currentHandle;
|
|
1320
|
+
const sourceSessionId = String(agent.session.id);
|
|
987
1321
|
agent = handle.agent;
|
|
988
1322
|
currentHandle = handle;
|
|
989
1323
|
bindAgent();
|
|
@@ -994,6 +1328,43 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
994
1328
|
touchSession(childId);
|
|
995
1329
|
state.emit();
|
|
996
1330
|
void oldHandle?.dispose().catch(() => { });
|
|
1331
|
+
// Decision-event pair around the completed rewind: `tui/rewind-done`
|
|
1332
|
+
// (the first non-empty string is toasted as the post-rewind summary,
|
|
1333
|
+
// e.g. a plugin reporting restored files) and the generic
|
|
1334
|
+
// `tui/session-switched` notification. Listener failures are logged,
|
|
1335
|
+
// never surfaced — the rewind itself already succeeded.
|
|
1336
|
+
//
|
|
1337
|
+
// rewind-done is a post-hoc summary, NOT a gate, so it is dispatched
|
|
1338
|
+
// DECOUPLED from the return value: the picker is already closed and
|
|
1339
|
+
// PromptInput is live — awaiting a slow listener here would delay the
|
|
1340
|
+
// picked text's return to the draft, letting its late arrival
|
|
1341
|
+
// overwrite whatever the user typed meanwhile, and a listener that
|
|
1342
|
+
// never settles would park tui/session-switched forever. The summary
|
|
1343
|
+
// toasts whenever it lands.
|
|
1344
|
+
try {
|
|
1345
|
+
void dispatchTuiDecision(ctx, 'tui/rewind-done', {
|
|
1346
|
+
text: row.text,
|
|
1347
|
+
mode,
|
|
1348
|
+
boundarySeq: boundary,
|
|
1349
|
+
sourceSessionId,
|
|
1350
|
+
childSessionId: String(childId),
|
|
1351
|
+
sessionId: String(childId),
|
|
1352
|
+
cwd: state.cwd,
|
|
1353
|
+
}, normalizeRewindDoneSummary)
|
|
1354
|
+
.then(summary => {
|
|
1355
|
+
if (summary !== undefined)
|
|
1356
|
+
state.notify(summary, { timeoutMs: 6000 });
|
|
1357
|
+
})
|
|
1358
|
+
.catch((error) => {
|
|
1359
|
+
ctx.logger.warn('dsh-tui: tui/rewind-done dispatch failed: %o', error);
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
catch (error) {
|
|
1363
|
+
// A bare embedder's context may lack the event bus entirely; the
|
|
1364
|
+
// rewind itself already succeeded, so this stays a log line.
|
|
1365
|
+
ctx.logger.warn('dsh-tui: tui/rewind-done dispatch failed: %o', error);
|
|
1366
|
+
}
|
|
1367
|
+
notifySessionSwitched('rewind', String(childId), sourceSessionId);
|
|
997
1368
|
return row.text;
|
|
998
1369
|
},
|
|
999
1370
|
async resumeTo(sessionId) {
|
|
@@ -1009,6 +1380,11 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1009
1380
|
state.notify(t('resume-unavailable'), { color: 'error' });
|
|
1010
1381
|
return false;
|
|
1011
1382
|
}
|
|
1383
|
+
// Plugin veto point (tui/session-switch): before any read of the
|
|
1384
|
+
// target — a veto leaves the live session and its transcript
|
|
1385
|
+
// untouched.
|
|
1386
|
+
if (await sessionSwitchVetoed('resume', sessionId))
|
|
1387
|
+
return false;
|
|
1012
1388
|
let handle;
|
|
1013
1389
|
// Compat boundary: register vouched-for legacy event types (e.g.
|
|
1014
1390
|
// activity/status from pre-#143 logs) in every reachable dsh-session
|
|
@@ -1111,6 +1487,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1111
1487
|
settleStreaming();
|
|
1112
1488
|
// Rebind subscriptions to the resumed agent, then free the old one.
|
|
1113
1489
|
const oldHandle = currentHandle;
|
|
1490
|
+
const previousSessionId = String(agent.session.id);
|
|
1114
1491
|
agent = handle.agent;
|
|
1115
1492
|
currentHandle = handle;
|
|
1116
1493
|
bindAgent();
|
|
@@ -1124,6 +1501,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1124
1501
|
state.emit();
|
|
1125
1502
|
void oldHandle?.dispose().catch(() => { });
|
|
1126
1503
|
clearStagedImages();
|
|
1504
|
+
notifySessionSwitched('resume', sessionId, previousSessionId);
|
|
1127
1505
|
return true;
|
|
1128
1506
|
},
|
|
1129
1507
|
async newSession() {
|
|
@@ -1143,6 +1521,10 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1143
1521
|
});
|
|
1144
1522
|
return false;
|
|
1145
1523
|
}
|
|
1524
|
+
// Plugin veto point (tui/session-switch): no side effects have
|
|
1525
|
+
// happened yet — the session id below is not even allocated.
|
|
1526
|
+
if (await sessionSwitchVetoed('new'))
|
|
1527
|
+
return false;
|
|
1146
1528
|
const sessionId = SessionId(randomUUID());
|
|
1147
1529
|
let handle;
|
|
1148
1530
|
// A fresh session composes the caller's DEFAULT preset: the cordis.yml
|
|
@@ -1234,6 +1616,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1234
1616
|
tools: 0,
|
|
1235
1617
|
};
|
|
1236
1618
|
const oldHandle = currentHandle;
|
|
1619
|
+
const previousSessionId = String(agent.session.id);
|
|
1237
1620
|
agent = handle.agent;
|
|
1238
1621
|
currentHandle = handle;
|
|
1239
1622
|
bindAgent();
|
|
@@ -1245,6 +1628,7 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1245
1628
|
touchSession(handle.agent.id);
|
|
1246
1629
|
void oldHandle?.dispose().catch(() => { });
|
|
1247
1630
|
clearStagedImages();
|
|
1631
|
+
notifySessionSwitched('new', String(handle.agent.id), previousSessionId);
|
|
1248
1632
|
return true;
|
|
1249
1633
|
},
|
|
1250
1634
|
listWorkspaces() {
|
|
@@ -1456,13 +1840,24 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1456
1840
|
};
|
|
1457
1841
|
state.notifications.push(item);
|
|
1458
1842
|
state.emit();
|
|
1459
|
-
|
|
1843
|
+
const remove = () => {
|
|
1460
1844
|
const index = state.notifications.indexOf(item);
|
|
1461
1845
|
if (index >= 0) {
|
|
1462
1846
|
state.notifications.splice(index, 1);
|
|
1463
1847
|
state.emit();
|
|
1464
1848
|
}
|
|
1465
|
-
}
|
|
1849
|
+
};
|
|
1850
|
+
// timeoutMs 0 = sticky: no expiry timer, the dismiss handle is the
|
|
1851
|
+
// only way out (a decision-parked indicator must outlive the wait it
|
|
1852
|
+
// describes — auto-expiring it would hide a still-parked flow, D-8).
|
|
1853
|
+
const expire = item.timeoutMs > 0 ? setTimeout(remove, item.timeoutMs) : undefined;
|
|
1854
|
+
// Early-dismiss handle for flows that know their notice went stale
|
|
1855
|
+
// (e.g. a decision-parked indicator whose decision just landed).
|
|
1856
|
+
return () => {
|
|
1857
|
+
if (expire !== undefined)
|
|
1858
|
+
clearTimeout(expire);
|
|
1859
|
+
remove();
|
|
1860
|
+
};
|
|
1466
1861
|
},
|
|
1467
1862
|
setDiffLayout(layout) {
|
|
1468
1863
|
if (layout === state.diffLayout)
|
|
@@ -1839,16 +2234,49 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
1839
2234
|
state.notify(t('compact-while-working'), { color: 'warning' });
|
|
1840
2235
|
return;
|
|
1841
2236
|
}
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
2237
|
+
// Plugin veto point (tui/compact): the first answering plugin may
|
|
2238
|
+
// cancel the compaction before anything runs.
|
|
2239
|
+
const originAgentId = state.agentId;
|
|
2240
|
+
// Compare the AGENT REFERENCE after the await, not the id — session
|
|
2241
|
+
// ids are reusable (A → /new → /resume A returns the same id on a new
|
|
2242
|
+
// agent), so an id comparison has an ABA hole that would hand the new
|
|
2243
|
+
// agent to the OLD scope's compaction service.
|
|
2244
|
+
const originAgent = agent;
|
|
2245
|
+
void (async () => {
|
|
2246
|
+
const decision = await withDecisionPending('tui/compact', dispatchTuiDecision(ctx, 'tui/compact', {
|
|
2247
|
+
sessionId: originAgentId,
|
|
2248
|
+
cwd: state.cwd,
|
|
2249
|
+
}, normalizeCancelDecision));
|
|
2250
|
+
if (decision !== undefined) {
|
|
2251
|
+
state.notify(decision.reason ?? t('ext-action-cancelled'), { color: 'warning', timeoutMs: 4000 });
|
|
2252
|
+
return;
|
|
2253
|
+
}
|
|
2254
|
+
// Stale-drop (same rule as tui/input): the await parked us while the
|
|
2255
|
+
// user switched sessions — `compactService` was resolved through the
|
|
2256
|
+
// OLD agent's scope chain, and the mutable `agent` now points at the
|
|
2257
|
+
// new session. Running now would hand the new agent to the old
|
|
2258
|
+
// service (or call into an unloaded one).
|
|
2259
|
+
if (agent !== originAgent) {
|
|
2260
|
+
state.notify(t('ext-compact-stale'), { color: 'warning', timeoutMs: 4000 });
|
|
2261
|
+
return;
|
|
2262
|
+
}
|
|
2263
|
+
if (state.working) {
|
|
2264
|
+
// The await above gave a queued turn time to start; compacting
|
|
2265
|
+
// mid-turn now would be the same race the check upfront avoided.
|
|
2266
|
+
state.notify(t('compact-while-working'), { color: 'warning' });
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
const signal = new AbortController().signal;
|
|
2270
|
+
state.notify(t('compact-working'));
|
|
2271
|
+
void compactService
|
|
2272
|
+
.compactNow(agent, signal)
|
|
2273
|
+
.then((result) => {
|
|
2274
|
+
state.notify(result ? t('compact-done') : t('compact-nothing'));
|
|
2275
|
+
})
|
|
2276
|
+
.catch((error) => {
|
|
2277
|
+
state.notify(t('compact-failed', { err: error instanceof Error ? error.message : String(error) }), { color: 'error', timeoutMs: 8000 });
|
|
2278
|
+
});
|
|
2279
|
+
})();
|
|
1852
2280
|
},
|
|
1853
2281
|
runExternalCommand(name, rawInput) {
|
|
1854
2282
|
return executeRegistryCommand(name, rawInput);
|
|
@@ -2017,8 +2445,23 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
2017
2445
|
if (existsSync(LEGACY_DATA_DIR)) {
|
|
2018
2446
|
lines.push(t('doctor-legacy-dir'));
|
|
2019
2447
|
}
|
|
2448
|
+
// Plugin-spec diagnostics (v0.15): the runtime generation and the
|
|
2449
|
+
// vendored registry self-check, both soft-probed (#183 discipline).
|
|
2450
|
+
const pluginHost = ctx.get('tuiPluginHost');
|
|
2451
|
+
lines.push(t('doctor-plugin-generation', { id: pluginHost?.generationId ?? t('doctor-plugin-host-missing') }));
|
|
2452
|
+
const violations = pluginHost?.selfCheck();
|
|
2453
|
+
lines.push(t('doctor-plugin-registry', {
|
|
2454
|
+
state: violations === undefined ? t('doctor-plugin-host-missing') : violations.length === 0 ? '✓' : `✗ ${violations.length}`,
|
|
2455
|
+
}));
|
|
2020
2456
|
return lines;
|
|
2021
2457
|
},
|
|
2458
|
+
pluginsInfo(args) {
|
|
2459
|
+
const host = ctx.get('tuiPluginHost');
|
|
2460
|
+
return pluginsInfoLines(args, {
|
|
2461
|
+
grants: host?.grants ?? currentGrantStore(),
|
|
2462
|
+
host: host?.describe(),
|
|
2463
|
+
});
|
|
2464
|
+
},
|
|
2022
2465
|
async listSubagents() {
|
|
2023
2466
|
const subagents = ctx.get('subagents');
|
|
2024
2467
|
if (!subagents)
|
|
@@ -2372,10 +2815,21 @@ export function createChannel(ctx, initialAgent, options) {
|
|
|
2372
2815
|
},
|
|
2373
2816
|
});
|
|
2374
2817
|
skillCommands.set(name, { dispose, description });
|
|
2818
|
+
ctx.get('tuiEffectLedger')?.record({ operation: 'create', resource: { kind: 'command', id: name }, result: 'applied' }, ctx);
|
|
2375
2819
|
}
|
|
2376
2820
|
catch (error) {
|
|
2821
|
+
// C-041: a duplicate registration arrives as a plain-message Error
|
|
2822
|
+
// from dsh-commands; map it onto the contract code before handling
|
|
2823
|
+
// (the refusal path itself is unchanged).
|
|
2824
|
+
const mapped = mapCommandError(error);
|
|
2377
2825
|
skillCommandsRefused.add(name);
|
|
2378
|
-
ctx.logger.warn(`skill commands: "${name}" not registrable: %o`,
|
|
2826
|
+
ctx.logger.warn(`skill commands: "${name}" not registrable%s: %o`, hasCommandErrorCode(mapped, 'DUPLICATE_CONTRIBUTION_ID') ? ' (DUPLICATE_CONTRIBUTION_ID)' : '', mapped);
|
|
2827
|
+
ctx.get('tuiEffectLedger')?.record({
|
|
2828
|
+
operation: 'create',
|
|
2829
|
+
resource: { kind: 'command', id: name },
|
|
2830
|
+
result: 'failed',
|
|
2831
|
+
errorCode: hasCommandErrorCode(mapped, 'DUPLICATE_CONTRIBUTION_ID') ? 'DUPLICATE_CONTRIBUTION_ID' : 'COMMAND_FAILED',
|
|
2832
|
+
}, ctx);
|
|
2379
2833
|
}
|
|
2380
2834
|
}
|
|
2381
2835
|
};
|
|
@@ -2976,6 +3430,30 @@ ${output}
|
|
|
2976
3430
|
text: t('agent-preset-switched', { preset: data.agentPreset ?? 'unknown' }),
|
|
2977
3431
|
});
|
|
2978
3432
|
nextRowId += 1;
|
|
3433
|
+
break;
|
|
3434
|
+
}
|
|
3435
|
+
// Custom plugin events (tuiRenderers seam): a registered renderer
|
|
3436
|
+
// maps the payload to text rows — title as a local row, body as
|
|
3437
|
+
// preview-clipped local-output rows, same shape pushLocal uses.
|
|
3438
|
+
// Runs on the live stream AND on replay (resume/rewind), so the
|
|
3439
|
+
// projection must stay total; the runtime isolates renderer
|
|
3440
|
+
// crashes per type.
|
|
3441
|
+
if (rendererRuntime !== undefined) {
|
|
3442
|
+
const rendered = rendererRuntime.render(event.type, event.data);
|
|
3443
|
+
if (rendered !== undefined) {
|
|
3444
|
+
if (rendered.title !== undefined && rendered.title !== '') {
|
|
3445
|
+
state.rows.push({ id: nextRowId, kind: 'local', text: rendered.title });
|
|
3446
|
+
nextRowId += 1;
|
|
3447
|
+
}
|
|
3448
|
+
for (const line of rendered.lines) {
|
|
3449
|
+
state.rows.push({
|
|
3450
|
+
id: nextRowId,
|
|
3451
|
+
kind: 'local-output',
|
|
3452
|
+
text: preview(String(line), LOCAL_OUTPUT_LIMIT),
|
|
3453
|
+
});
|
|
3454
|
+
nextRowId += 1;
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
2979
3457
|
}
|
|
2980
3458
|
break;
|
|
2981
3459
|
}
|
|
@@ -3113,6 +3591,10 @@ ${output}
|
|
|
3113
3591
|
ctx.on('session/event', (session, event) => {
|
|
3114
3592
|
if (session !== agent.session)
|
|
3115
3593
|
return;
|
|
3594
|
+
// Observation broker (C-042): maps user/message + assistant/message
|
|
3595
|
+
// into grant-gated envelopes; every other event type is a no-op, and
|
|
3596
|
+
// publish never throws into this arm.
|
|
3597
|
+
messageObserver?.publish(session, event);
|
|
3116
3598
|
activityTracker.onSessionEvent(event);
|
|
3117
3599
|
renderWorkingActivity();
|
|
3118
3600
|
// Mode-affecting atoms fold into the Shift+Tab mode indicator the
|