@deepseek-harness-tui/dsh-tui 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -13
- package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -0
- package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -0
- package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -0
- package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -0
- package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -0
- package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -0
- package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -0
- package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -0
- package/dsh-ecosystem-spec/registry/README.md +14 -0
- package/dsh-ecosystem-spec/registry/contracts/scene-v1alpha1.json +13 -0
- package/dsh-ecosystem-spec/registry/contracts/settings-section-v1alpha1.json +13 -0
- package/dsh-ecosystem-spec/registry/contracts/tui-channel-v1alpha1.json +30 -0
- package/dsh-ecosystem-spec/registry/contracts/workspace-provider-v1alpha1.json +6 -0
- package/{ecosystem-spec → dsh-ecosystem-spec}/registry/permissions-0.1.json +1 -1
- package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -0
- package/lib/types/command-trees.d.ts +2 -1
- package/lib/types/command-trees.d.ts.map +1 -1
- package/lib/types/command-trees.js +1 -1
- package/lib/types/components/LoadedContextPanel.d.ts +10 -5
- package/lib/types/components/LoadedContextPanel.d.ts.map +1 -1
- package/lib/types/components/LoadedContextPanel.js +18 -7
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +16 -7
- package/lib/types/components/Markdown.d.ts +13 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +15 -1
- package/lib/types/components/MessageList.d.ts +3 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +90 -9
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +26 -12
- package/lib/types/components/StreamingMarkdown.d.ts +2 -8
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +51 -9
- package/lib/types/components/activityFrames.d.ts +1 -1
- package/lib/types/components/activityFrames.d.ts.map +1 -1
- package/lib/types/components/activityFrames.js +4 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +5 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +26 -3
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +12 -1
- package/lib/types/dsh-adapter/channel.d.ts +31 -4
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +267 -102
- package/lib/types/dsh-adapter/childStderr.d.ts.map +1 -1
- package/lib/types/dsh-adapter/childStderr.js +10 -0
- package/lib/types/dsh-adapter/command-attribution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/command-attribution.js +2 -2
- package/lib/types/dsh-adapter/command-trees.d.ts +7 -1
- package/lib/types/dsh-adapter/command-trees.d.ts.map +1 -1
- package/lib/types/dsh-adapter/command-trees.js +70 -20
- package/lib/types/dsh-adapter/component-identity.d.ts +5 -0
- package/lib/types/dsh-adapter/component-identity.d.ts.map +1 -1
- package/lib/types/dsh-adapter/component-identity.js +14 -14
- package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/decision-guard.js +10 -16
- package/lib/types/dsh-adapter/dialogs.d.ts +2 -3
- package/lib/types/dsh-adapter/dialogs.d.ts.map +1 -1
- package/lib/types/dsh-adapter/dialogs.js +114 -60
- package/lib/types/dsh-adapter/effect-ledger.d.ts +0 -8
- package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
- package/lib/types/dsh-adapter/effect-ledger.js +73 -53
- package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/extension-events.js +39 -1
- package/lib/types/dsh-adapter/grants.d.ts.map +1 -1
- package/lib/types/dsh-adapter/grants.js +43 -14
- package/lib/types/dsh-adapter/host-access.d.ts +37 -0
- package/lib/types/dsh-adapter/host-access.d.ts.map +1 -0
- package/lib/types/dsh-adapter/host-access.js +652 -0
- package/lib/types/dsh-adapter/host-descriptor.d.ts +2 -2
- package/lib/types/dsh-adapter/host-descriptor.d.ts.map +1 -1
- package/lib/types/dsh-adapter/host-descriptor.js +31 -8
- 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 +10 -15
- package/lib/types/dsh-adapter/message-observer.d.ts.map +1 -1
- package/lib/types/dsh-adapter/message-observer.js +114 -70
- package/lib/types/dsh-adapter/plugin-host.d.ts +39 -6
- package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin-host.js +139 -44
- package/lib/types/dsh-adapter/plugin-storage.d.ts +0 -5
- package/lib/types/dsh-adapter/plugin-storage.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin-storage.js +48 -36
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +80 -16
- package/lib/types/dsh-adapter/promptDebug.d.ts +0 -6
- package/lib/types/dsh-adapter/promptDebug.d.ts.map +1 -1
- package/lib/types/dsh-adapter/promptDebug.js +13 -4
- package/lib/types/dsh-adapter/renderers.d.ts +6 -14
- package/lib/types/dsh-adapter/renderers.d.ts.map +1 -1
- package/lib/types/dsh-adapter/renderers.js +81 -46
- package/lib/types/dsh-adapter/scenes.d.ts +8 -4
- package/lib/types/dsh-adapter/scenes.d.ts.map +1 -1
- package/lib/types/dsh-adapter/scenes.js +136 -37
- package/lib/types/dsh-adapter/settings-sections.d.ts +7 -3
- package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
- package/lib/types/dsh-adapter/settings-sections.js +106 -26
- package/lib/types/dsh-adapter/shortcuts.d.ts +8 -10
- package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
- package/lib/types/dsh-adapter/shortcuts.js +108 -36
- package/lib/types/dsh-adapter/status.d.ts +6 -7
- package/lib/types/dsh-adapter/status.d.ts.map +1 -1
- package/lib/types/dsh-adapter/status.js +88 -22
- package/lib/types/dsh-adapter/workspaces.d.ts +16 -5
- package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
- package/lib/types/dsh-adapter/workspaces.js +287 -170
- package/lib/types/extensions.d.ts +10 -5
- package/lib/types/extensions.d.ts.map +1 -1
- package/lib/types/extensions.js +11 -5
- package/lib/types/force-production-react.d.ts +1 -0
- package/lib/types/force-production-react.d.ts.map +1 -0
- package/lib/types/force-production-react.js +12 -0
- package/lib/types/i18n.d.ts +14 -6
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +4 -2
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +1 -0
- package/lib/types/ink/components/App.d.ts +2 -0
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +4 -0
- package/lib/types/ink/ink.d.ts +20 -3
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +57 -5
- package/lib/types/ink/log-update.d.ts.map +1 -1
- package/lib/types/ink/log-update.js +128 -9
- package/lib/types/ink/output.d.ts +28 -2
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +158 -12
- package/lib/types/ink/screen.d.ts +39 -0
- package/lib/types/ink/screen.d.ts.map +1 -1
- package/lib/types/ink/screen.js +117 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +10 -2
- package/lib/types/ink/wrapAnsi.d.ts +1 -1
- package/lib/types/ink/wrapAnsi.d.ts.map +1 -1
- package/lib/types/ink/wrapAnsi.js +29 -2
- package/lib/types/plugin-host.d.ts +13 -11
- package/lib/types/plugin-host.d.ts.map +1 -1
- package/lib/types/plugin-host.js +16 -16
- package/lib/types/plugin-spec/registry.d.ts +2 -2
- package/lib/types/plugin-spec/registry.d.ts.map +1 -1
- package/lib/types/plugin-spec/registry.js +113 -18
- package/lib/types/plugin-spec/tui-extension.d.ts.map +1 -1
- package/lib/types/plugin-spec/tui-extension.js +2 -0
- package/lib/types/plugin-spec/validate.d.ts.map +1 -1
- package/lib/types/plugin-spec/validate.js +20 -1
- package/lib/types/scenes.d.ts +2 -1
- package/lib/types/scenes.d.ts.map +1 -1
- package/lib/types/scenes.js +1 -1
- package/lib/types/screens/Chat.d.ts +3 -3
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +38 -17
- package/lib/types/screens/SessionBrowser.d.ts.map +1 -1
- package/lib/types/screens/SessionBrowser.js +10 -3
- package/lib/types/sessions/view.d.ts +3 -2
- package/lib/types/sessions/view.d.ts.map +1 -1
- package/lib/types/sessions/view.js +18 -0
- package/lib/types/settings-sections.d.ts +2 -1
- package/lib/types/settings-sections.d.ts.map +1 -1
- package/lib/types/settings-sections.js +1 -1
- package/lib/types/utils/execFileNoThrow.d.ts.map +1 -1
- package/lib/types/utils/execFileNoThrow.js +3 -0
- package/lib/types/workspaces.d.ts +2 -1
- package/lib/types/workspaces.d.ts.map +1 -1
- package/lib/types/workspaces.js +1 -1
- package/node_modules/@dsh-std/command/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/command/package.json +1 -1
- package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
- package/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
- package/node_modules/@dsh-std/connection/lib/memory.js +1 -0
- package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/node_modules/@dsh-std/connection/package.json +1 -1
- package/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/core/package.json +1 -1
- package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
- package/node_modules/@dsh-std/manifest/package.json +1 -1
- package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/messages/package.json +1 -1
- package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
- package/node_modules/@dsh-std/presentation/README.md +2 -1
- package/node_modules/@dsh-std/presentation/README.zh.md +2 -1
- package/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
- package/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
- package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
- package/node_modules/@dsh-std/presentation/lib/index.d.ts +44 -1
- package/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -1
- package/node_modules/@dsh-std/presentation/lib/index.js +6 -3
- package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/node_modules/@dsh-std/presentation/package.json +7 -3
- package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -0
- package/node_modules/@dsh-std/storage/package.json +1 -1
- package/package.json +10 -5
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +2 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +2 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.d.ts +2 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js +179 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -0
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts +44 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.d.ts.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js +6 -3
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
- package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +7 -3
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +1 -1
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +1 -1
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.d.ts.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js +1 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +1 -1
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +1 -1
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -0
- package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +1 -1
- package/ecosystem-spec/registry/registry-0.15.json +0 -57
- /package/{ecosystem-spec → dsh-ecosystem-spec}/registry/contracts/decision-events-v1alpha1.json +0 -0
- /package/{ecosystem-spec → dsh-ecosystem-spec}/registry/host-descriptor.tui.example.json +0 -0
- /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/conformance-claim.schema.json +0 -0
- /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/effect-ledger-record.schema.json +0 -0
- /package/{ecosystem-spec → dsh-ecosystem-spec}/schemas/host-descriptor.schema.json +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { digestFile, loadSpecData } from '../plugin-spec/registry.js';
|
|
5
|
+
import { digestFile, loadSpecData, verifyContractProfiles } from '../plugin-spec/registry.js';
|
|
6
6
|
import { TUI_DECISION_EVENT_NAMES } from '../plugin-spec/tui-extension.js';
|
|
7
7
|
import { createContractIndex, validateHost } from '../plugin-spec/validate.js';
|
|
8
8
|
import { check } from '../plugin-spec/schema-check.js';
|
|
@@ -17,6 +17,14 @@ export const HOST_SUPPORTED_CONTRACTS = Object.freeze([
|
|
|
17
17
|
* optional vendored registry is unavailable; the contract list is still
|
|
18
18
|
* empty in that degraded state. */
|
|
19
19
|
export const HOST_FACET_API_VERSIONS = Object.freeze(['v1alpha1']);
|
|
20
|
+
function freezeDeep(value, seen = new WeakSet()) {
|
|
21
|
+
if (value === null || typeof value !== 'object' || seen.has(value))
|
|
22
|
+
return value;
|
|
23
|
+
seen.add(value);
|
|
24
|
+
for (const child of Object.values(value))
|
|
25
|
+
freezeDeep(child, seen);
|
|
26
|
+
return Object.freeze(value);
|
|
27
|
+
}
|
|
20
28
|
export function readOwnPackageVersion() {
|
|
21
29
|
const candidates = [];
|
|
22
30
|
try {
|
|
@@ -58,13 +66,15 @@ export function buildHostDescriptor(options) {
|
|
|
58
66
|
const dropped = [];
|
|
59
67
|
const contracts = [];
|
|
60
68
|
const data = loadSpecData(options.specDir);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
// `loadSpecData` rejects malformed/empty facet declarations. Preserve the
|
|
70
|
+
// pinned values exactly when data is valid; use the schema-valid fallback
|
|
71
|
+
// only for the completely unavailable/degraded path.
|
|
72
|
+
const facetApiVersions = data === undefined
|
|
73
|
+
? [...HOST_FACET_API_VERSIONS]
|
|
74
|
+
: [...data.registry.facetApiVersions];
|
|
75
|
+
const profileFailures = data === undefined ? [] : verifyContractProfiles(data);
|
|
66
76
|
if (data === undefined) {
|
|
67
|
-
warnings.push('admission profile unavailable (ecosystem-spec/); advertising an empty protocol surface');
|
|
77
|
+
warnings.push('admission profile unavailable (dsh-ecosystem-spec/); advertising an empty protocol surface');
|
|
68
78
|
}
|
|
69
79
|
else {
|
|
70
80
|
const index = createContractIndex(data.registry, data.permissions);
|
|
@@ -78,6 +88,11 @@ export function buildHostDescriptor(options) {
|
|
|
78
88
|
continue;
|
|
79
89
|
}
|
|
80
90
|
if ('profile' in entry) {
|
|
91
|
+
if (profileFailures.length > 0) {
|
|
92
|
+
dropped.push(key);
|
|
93
|
+
warnings.push(`${key}: TUI contract profile self-check failed (${profileFailures.join(' | ')})`);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
81
96
|
let actual;
|
|
82
97
|
try {
|
|
83
98
|
actual = digestFile(data.dir, entry.profile);
|
|
@@ -142,5 +157,13 @@ export function buildHostDescriptor(options) {
|
|
|
142
157
|
descriptor.contracts.length = 0;
|
|
143
158
|
}
|
|
144
159
|
}
|
|
145
|
-
|
|
160
|
+
// The descriptor is handed to untrusted admission/diagnostic callers. A
|
|
161
|
+
// cached mutable object would let one caller delete contracts or forge the
|
|
162
|
+
// runtime generation for every later negotiation, so freeze the complete
|
|
163
|
+
// graph and return immutable diagnostic arrays as well.
|
|
164
|
+
return Object.freeze({
|
|
165
|
+
descriptor: freezeDeep(descriptor),
|
|
166
|
+
dropped: Object.freeze(dropped),
|
|
167
|
+
warnings: Object.freeze(warnings),
|
|
168
|
+
});
|
|
146
169
|
}
|
|
@@ -66,6 +66,10 @@ export interface Config {
|
|
|
66
66
|
* terminals (≥110 cols) and unified below; `split`/`unified` force one
|
|
67
67
|
* layout. Editable live from the `/settings` screen. */
|
|
68
68
|
diffLayout?: 'auto' | 'split' | 'unified';
|
|
69
|
+
/** Thinking-block display: `preview` (default) streams a 2-3 line live
|
|
70
|
+
* preview and folds each step when it settles; `full` keeps thinking
|
|
71
|
+
* expanded until the whole turn ends. Editable live from `/settings`. */
|
|
72
|
+
thinkingFold?: 'preview' | 'full';
|
|
69
73
|
/** Shift+Tab session-mode cycle (array order IS the cycle order; index 0
|
|
70
74
|
* is the unmarked base mode). Each entry bundles any subset of the
|
|
71
75
|
* `plan`/`sandbox`/`approval` atoms; absent → the built-in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD,eAAO,MAAM,IAAI,YAAY,CAAA;AAU7B,eAAO,MAAM,MAAM,UAAa,CAAA;AAEhC;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;yEAKqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;gDAC4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;gFAE4E;IAC5E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;oCACgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;sBAIkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;4BAGwB;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;wDAEoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;kFAC8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;gCAG4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;6DAEyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;IACzC;;8EAE0E;IAC1E,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC;;;yDAGqD;IACrD,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,CA4BhC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvE"}
|
|
@@ -28,6 +28,7 @@ export const Config = Schema.object({
|
|
|
28
28
|
lang: Schema.string().required(false),
|
|
29
29
|
preset: Schema.string().required(false),
|
|
30
30
|
diffLayout: Schema.union(['auto', 'split', 'unified']).default('auto'),
|
|
31
|
+
thinkingFold: Schema.union(['preview', 'full']).default('preview'),
|
|
31
32
|
modes: Schema.array(Schema.object({
|
|
32
33
|
id: Schema.string(),
|
|
33
34
|
label: Schema.string().required(false),
|
|
@@ -82,6 +82,11 @@ export interface MessagesObserveEnvelope {
|
|
|
82
82
|
payload: MessagesObservePayload;
|
|
83
83
|
}
|
|
84
84
|
export type MessagesObserveListener = (envelope: MessagesObserveEnvelope) => void | Promise<void>;
|
|
85
|
+
/** Host-only session-event ingress. Plugins receive only `subscribe`; the
|
|
86
|
+
* channel uses this capability to publish events after its own identity check. */
|
|
87
|
+
export interface TuiMessageObserverHost {
|
|
88
|
+
publish(session: unknown, event: unknown): void;
|
|
89
|
+
}
|
|
85
90
|
/** Summary bound (cells; schema maxLength 1024 chars — 200 cells ≤ 1024). */
|
|
86
91
|
export declare const OBSERVE_SUMMARY_CELLS = 200;
|
|
87
92
|
/** Content text bound (chars; schema maxLength 262144). */
|
|
@@ -99,6 +104,9 @@ export declare const OBSERVE_CALLBACK_TIMEOUT_MS = 1500;
|
|
|
99
104
|
/** Bound queued callbacks per subscription so a stalled listener cannot grow
|
|
100
105
|
* an unbounded Promise chain before its timeout closes the subscription. */
|
|
101
106
|
export declare const OBSERVE_CALLBACK_QUEUE_LIMIT = 32;
|
|
107
|
+
/** Attachment reads are part of the broker build chain and therefore need an
|
|
108
|
+
* independent bound; a wedged reader must not stall every later envelope. */
|
|
109
|
+
export declare const OBSERVE_IMAGE_READ_TIMEOUT_MS = 1500;
|
|
102
110
|
declare module '@deepseek-ai/cordis' {
|
|
103
111
|
interface Context {
|
|
104
112
|
tuiMessageObserver: TuiMessageObserverRuntime;
|
|
@@ -112,14 +120,7 @@ declare module '@deepseek-ai/cordis' {
|
|
|
112
120
|
* is ever delivered (a host that cannot self-check must not emit).
|
|
113
121
|
*/
|
|
114
122
|
export declare class TuiMessageObserverRuntime extends Service {
|
|
115
|
-
private
|
|
116
|
-
private readonly fallbackGrants;
|
|
117
|
-
private readonly ledgerOption;
|
|
118
|
-
private readonly subscriptions;
|
|
119
|
-
private readonly validateEnvelope;
|
|
120
|
-
private readonly validatorUnavailable;
|
|
121
|
-
private validatorWarned;
|
|
122
|
-
private buildChain;
|
|
123
|
+
#private;
|
|
123
124
|
constructor(ctx: Context, options?: {
|
|
124
125
|
grants?: GrantStore;
|
|
125
126
|
ledger?: TuiEffectLedgerRuntime;
|
|
@@ -147,13 +148,6 @@ export declare class TuiMessageObserverRuntime extends Service {
|
|
|
147
148
|
subscribe(pluginCtx: Context, listener: MessagesObserveListener, options: {
|
|
148
149
|
scope: string;
|
|
149
150
|
}): () => void;
|
|
150
|
-
/**
|
|
151
|
-
* Publish a session event (channel `session/event` arm). Non-mapped
|
|
152
|
-
* event types return immediately; everything else never throws into the
|
|
153
|
-
* caller — problems are warned, not raised.
|
|
154
|
-
*/
|
|
155
|
-
publish(session: unknown, event: unknown): void;
|
|
156
|
-
private publishGuarded;
|
|
157
151
|
private buildAndDeliver;
|
|
158
152
|
/** Release a subscription exactly once (disposer, ctx unload, revoke). */
|
|
159
153
|
private drop;
|
|
@@ -175,4 +169,5 @@ export declare class TuiMessageObserverRuntime extends Service {
|
|
|
175
169
|
* drop (unreadable, oversize, bad media type, no attachment store). */
|
|
176
170
|
private imageBlockOf;
|
|
177
171
|
}
|
|
172
|
+
export declare function getHostMessageObserver(runtime: TuiMessageObserverRuntime | undefined): TuiMessageObserverHost | undefined;
|
|
178
173
|
//# sourceMappingURL=message-observer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-observer.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/message-observer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"message-observer.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/message-observer.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,8 +55,9 @@ import { Service } from '@deepseek-ai/cordis';
|
|
|
55
55
|
import { validateMessageEvent } from '@dsh-std/messages';
|
|
56
56
|
import { check } from '../plugin-spec/schema-check.js';
|
|
57
57
|
import { cleanScalarText } from './sanitize.js';
|
|
58
|
+
import { activationContext, assertCallerContext, bindCallerEffect, compositionRoot, concreteService } from './host-access.js';
|
|
58
59
|
import { readGrantStore } from './grants.js';
|
|
59
|
-
import { declaresObserverScope, declaresPermission, requireComponentIdentity, } from './component-identity.js';
|
|
60
|
+
import { declaresObserverScope, declaresPermission, requireComponentIdentity, requiresContract, } from './component-identity.js';
|
|
60
61
|
import { normalizePermissionScope, scopeCovers, SESSION_SCOPE_MAX_CHARS, } from '../plugin-spec/permission-scope.js';
|
|
61
62
|
/** Summary bound (cells; schema maxLength 1024 chars — 200 cells ≤ 1024). */
|
|
62
63
|
export const OBSERVE_SUMMARY_CELLS = 200;
|
|
@@ -75,6 +76,9 @@ export const OBSERVE_CALLBACK_TIMEOUT_MS = 1500;
|
|
|
75
76
|
/** Bound queued callbacks per subscription so a stalled listener cannot grow
|
|
76
77
|
* an unbounded Promise chain before its timeout closes the subscription. */
|
|
77
78
|
export const OBSERVE_CALLBACK_QUEUE_LIMIT = 32;
|
|
79
|
+
/** Attachment reads are part of the broker build chain and therefore need an
|
|
80
|
+
* independent bound; a wedged reader must not stall every later envelope. */
|
|
81
|
+
export const OBSERVE_IMAGE_READ_TIMEOUT_MS = 1500;
|
|
78
82
|
/** The envelope schema's mimeType pattern (image blocks). */
|
|
79
83
|
const OBSERVE_MIME_PATTERN = /^[A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+$/;
|
|
80
84
|
function deepFreeze(value) {
|
|
@@ -145,45 +149,56 @@ function observerScopeCovers(subscriptionScope, envelopeScope) {
|
|
|
145
149
|
* is ever delivered (a host that cannot self-check must not emit).
|
|
146
150
|
*/
|
|
147
151
|
export class TuiMessageObserverRuntime extends Service {
|
|
148
|
-
grantsOption;
|
|
149
|
-
fallbackGrants;
|
|
150
|
-
ledgerOption;
|
|
151
|
-
subscriptions = new Set();
|
|
152
|
-
validateEnvelope;
|
|
153
|
-
validatorUnavailable;
|
|
154
|
-
validatorWarned = false;
|
|
155
|
-
buildChain = Promise.resolve();
|
|
156
152
|
constructor(ctx, options = {}) {
|
|
157
153
|
super(ctx, 'tuiMessageObserver');
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
const state = {
|
|
155
|
+
hostContext: compositionRoot(ctx),
|
|
156
|
+
grantsOption: options.grants,
|
|
157
|
+
fallbackGrants: readGrantStore(),
|
|
158
|
+
ledgerOption: options.ledger,
|
|
159
|
+
subscriptions: new Set(),
|
|
160
|
+
validateEnvelope: validateMessageEvent,
|
|
161
|
+
validatorUnavailable: false,
|
|
162
|
+
validatorWarned: false,
|
|
163
|
+
buildChain: Promise.resolve(),
|
|
164
|
+
};
|
|
165
|
+
const runtime = this;
|
|
166
|
+
const host = Object.freeze({
|
|
167
|
+
publish: (session, event) => {
|
|
168
|
+
try {
|
|
169
|
+
runtime.#publishGuarded(session, event);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
runtime.ctx.logger.warn('dsh-tui: messages.observe publish failed (event dropped)');
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
hostMessageObservers.set(runtime, host);
|
|
161
177
|
if (Object.hasOwn(options, 'validateEnvelope')) {
|
|
162
|
-
|
|
163
|
-
|
|
178
|
+
state.validatorUnavailable = options.validateEnvelope === undefined;
|
|
179
|
+
state.validateEnvelope = options.validateEnvelope ?? (() => { throw new Error('standard envelope validator unavailable'); });
|
|
164
180
|
}
|
|
165
181
|
else if (Object.hasOwn(options, 'envelopeSchema')) {
|
|
166
182
|
const schema = options.envelopeSchema;
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
state.validatorUnavailable = schema === undefined;
|
|
184
|
+
state.validateEnvelope = schema === undefined
|
|
169
185
|
? (() => { throw new Error('vendored envelope schema unavailable'); })
|
|
170
186
|
: (value) => check(value, schema, schema);
|
|
171
187
|
}
|
|
172
|
-
|
|
173
|
-
this.validatorUnavailable = false;
|
|
174
|
-
this.validateEnvelope = (value) => { validateMessageEvent(value); };
|
|
175
|
-
}
|
|
188
|
+
observerStates.set(this, state);
|
|
176
189
|
}
|
|
177
190
|
/** Grants: the plugin-host row's store when mounted, else a private read.
|
|
178
191
|
* Resolved PER CALL — sibling services mounted later by the same apply()
|
|
179
192
|
* are not visible to constructors (cordis), so a constructor-time probe
|
|
180
193
|
* would silently stick to the fallback. */
|
|
181
194
|
grants() {
|
|
182
|
-
|
|
195
|
+
const state = observerStateFor(this);
|
|
196
|
+
return state.grantsOption ?? state.hostContext.get('tuiPluginHost')?.grants ?? state.fallbackGrants;
|
|
183
197
|
}
|
|
184
198
|
/** Optional observability; a bare mount (tests) simply records nothing. */
|
|
185
199
|
ledger() {
|
|
186
|
-
|
|
200
|
+
const state = observerStateFor(this);
|
|
201
|
+
return state.ledgerOption ?? state.hostContext.get('tuiEffectLedger');
|
|
187
202
|
}
|
|
188
203
|
/**
|
|
189
204
|
* Subscribe to observation envelopes for ONE scope. Identity = the verified
|
|
@@ -196,11 +211,20 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
196
211
|
* unloads.
|
|
197
212
|
*/
|
|
198
213
|
subscribe(pluginCtx, listener, options) {
|
|
199
|
-
const
|
|
214
|
+
const caller = activationContext(pluginCtx);
|
|
215
|
+
if (caller === undefined)
|
|
216
|
+
throw new Error('dsh-tui: messages.observe.subscribe requires a live activation context');
|
|
217
|
+
assertCallerContext(this.ctx, caller, 'messages.observe.subscribe', this);
|
|
218
|
+
const identity = requireComponentIdentity(caller);
|
|
200
219
|
const plugin = identity.componentId;
|
|
220
|
+
if (!requiresContract(identity, 'messages.dsh/v1alpha1', 'MessageObserver')) {
|
|
221
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe subscription from Component "${plugin}" denied — ` +
|
|
222
|
+
'the messages.dsh/v1alpha1#MessageObserver contract was not required');
|
|
223
|
+
return () => false;
|
|
224
|
+
}
|
|
201
225
|
const scope = typeof options?.scope === 'string' ? options.scope : '';
|
|
202
226
|
if (scope === '' || scope.length > OBSERVE_SCOPE_MAX_CHARS) {
|
|
203
|
-
this.
|
|
227
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe subscription from plugin "${plugin}" refused — options.scope must be a ` +
|
|
204
228
|
`non-empty string of at most ${OBSERVE_SCOPE_MAX_CHARS} characters (e.g. "session:<id>")`);
|
|
205
229
|
return () => false;
|
|
206
230
|
}
|
|
@@ -208,28 +232,28 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
208
232
|
|| !declaresObserverScope(identity, scope)
|
|
209
233
|
|| !declaresPermission(identity, 'messages.observe.read', scope)
|
|
210
234
|
|| !this.grants().allows({ componentId: identity.componentId, activationId: identity.activationId }, 'messages.observe.read', scope)) {
|
|
211
|
-
this.
|
|
235
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe subscription from Component "${plugin}" denied — ` +
|
|
212
236
|
'the scope is not statically declared or the current grant does not cover it; the listener was NOT registered');
|
|
213
237
|
this.ledger()?.record({
|
|
214
238
|
operation: 'bind',
|
|
215
239
|
resource: { kind: 'permission', id: 'messages.observe.read' },
|
|
216
240
|
result: 'failed',
|
|
217
241
|
errorCode: 'PERMISSION_NOT_GRANTED',
|
|
218
|
-
},
|
|
242
|
+
}, caller);
|
|
219
243
|
return () => false;
|
|
220
244
|
}
|
|
221
245
|
const subscription = {
|
|
222
246
|
plugin,
|
|
223
247
|
identity,
|
|
224
|
-
ownerContext:
|
|
248
|
+
ownerContext: caller,
|
|
225
249
|
scope,
|
|
226
250
|
listener,
|
|
227
251
|
chain: Promise.resolve(),
|
|
228
252
|
pendingCallbacks: 0,
|
|
229
253
|
closed: false,
|
|
230
254
|
};
|
|
231
|
-
this.subscriptions.add(subscription);
|
|
232
|
-
this.ledger()?.record({ operation: 'bind', resource: { kind: 'subscription', id: plugin }, result: 'applied' },
|
|
255
|
+
observerStateFor(this).subscriptions.add(subscription);
|
|
256
|
+
this.ledger()?.record({ operation: 'bind', resource: { kind: 'subscription', id: plugin }, result: 'applied' }, caller);
|
|
233
257
|
const release = () => {
|
|
234
258
|
if (subscription.closed)
|
|
235
259
|
return false;
|
|
@@ -240,29 +264,12 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
240
264
|
if (!this.grants().allows({ componentId: identity.componentId, activationId: identity.activationId }, 'messages.observe.read', scope))
|
|
241
265
|
release();
|
|
242
266
|
});
|
|
243
|
-
|
|
244
|
-
pluginCtx.effect(() => release);
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
// Degraded context: the subscription lives until process end.
|
|
248
|
-
}
|
|
267
|
+
bindCallerEffect(caller, release);
|
|
249
268
|
return release;
|
|
250
269
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
* caller — problems are warned, not raised.
|
|
255
|
-
*/
|
|
256
|
-
publish(session, event) {
|
|
257
|
-
try {
|
|
258
|
-
this.publishGuarded(session, event);
|
|
259
|
-
}
|
|
260
|
-
catch (error) {
|
|
261
|
-
this.ctx.logger.warn(`dsh-tui: messages.observe publish failed (event dropped): ${error instanceof Error ? error.message : String(error)}`);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
publishGuarded(session, event) {
|
|
265
|
-
if (this.subscriptions.size === 0)
|
|
270
|
+
#publishGuarded(session, event) {
|
|
271
|
+
const state = observerStateFor(this);
|
|
272
|
+
if (state.subscriptions.size === 0)
|
|
266
273
|
return;
|
|
267
274
|
const record = event;
|
|
268
275
|
const kind = record.type === 'user/message'
|
|
@@ -276,7 +283,7 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
276
283
|
return;
|
|
277
284
|
const sessionId = session?.id;
|
|
278
285
|
if (typeof sessionId !== 'string' || sessionId === '') {
|
|
279
|
-
this.
|
|
286
|
+
observerStateFor(this).hostContext.logger.warn('dsh-tui: messages.observe publish skipped — the session carries no string id');
|
|
280
287
|
return;
|
|
281
288
|
}
|
|
282
289
|
const data = (record.data ?? {});
|
|
@@ -285,19 +292,20 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
285
292
|
// Never truncate a session identity into the schema's scope bound: two
|
|
286
293
|
// distinct long ids can otherwise collapse into one subscription scope.
|
|
287
294
|
if (scope.length > OBSERVE_SCOPE_MAX_CHARS) {
|
|
288
|
-
this.
|
|
295
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe publish skipped — the session scope exceeds ${OBSERVE_SCOPE_MAX_CHARS} characters`);
|
|
289
296
|
return;
|
|
290
297
|
}
|
|
291
298
|
// C-042 isolation: match subscriptions BEFORE building anything — a
|
|
292
299
|
// subscription for another scope must never see this scope's content.
|
|
293
|
-
const matched = [...
|
|
300
|
+
const matched = [...state.subscriptions].filter(subscription => !subscription.closed && observerScopeCovers(subscription.scope, scope));
|
|
294
301
|
if (matched.length === 0)
|
|
295
302
|
return;
|
|
296
303
|
// Builds serialize broker-wide so delivery order stays the publish
|
|
297
304
|
// order even though image reads are async (sequence stays monotonic).
|
|
298
|
-
|
|
305
|
+
state.buildChain = state.buildChain.then(() => this.buildAndDeliver(kind, sessionId, scope, record.seq, message, matched));
|
|
299
306
|
}
|
|
300
307
|
async buildAndDeliver(kind, sessionId, scope, sequence, message, matched) {
|
|
308
|
+
const state = observerStateFor(this);
|
|
301
309
|
try {
|
|
302
310
|
const text = this.textOf(message?.content);
|
|
303
311
|
const { blocks, truncated: contentTruncated } = await this.contentOf(message?.content);
|
|
@@ -326,18 +334,18 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
326
334
|
},
|
|
327
335
|
};
|
|
328
336
|
// Self-check EVERY envelope with the pinned @dsh-std/messages validator.
|
|
329
|
-
if (
|
|
330
|
-
if (!
|
|
331
|
-
|
|
332
|
-
this.
|
|
337
|
+
if (state.validatorUnavailable) {
|
|
338
|
+
if (!state.validatorWarned) {
|
|
339
|
+
state.validatorWarned = true;
|
|
340
|
+
observerStateFor(this).hostContext.logger.warn('dsh-tui: standard message envelope validator unavailable — delivery is fail-closed');
|
|
333
341
|
}
|
|
334
342
|
return;
|
|
335
343
|
}
|
|
336
344
|
try {
|
|
337
|
-
|
|
345
|
+
state.validateEnvelope(envelope);
|
|
338
346
|
}
|
|
339
347
|
catch (error) {
|
|
340
|
-
this.
|
|
348
|
+
observerStateFor(this).hostContext.logger.warn('dsh-tui: messages.observe envelope failed the standard validator and was dropped');
|
|
341
349
|
return;
|
|
342
350
|
}
|
|
343
351
|
for (const subscription of matched) {
|
|
@@ -346,12 +354,12 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
346
354
|
// Deliver-time grant re-check: a revoked grant RELEASES the
|
|
347
355
|
// subscription (contract cleanup rule), with one warning.
|
|
348
356
|
if (!this.grants().allows({ componentId: subscription.identity.componentId, activationId: subscription.identity.activationId }, 'messages.observe.read', scope)) {
|
|
349
|
-
this.
|
|
357
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe subscription of plugin "${subscription.plugin}" released — the grant was revoked`);
|
|
350
358
|
this.drop(subscription);
|
|
351
359
|
continue;
|
|
352
360
|
}
|
|
353
361
|
if (subscription.pendingCallbacks >= OBSERVE_CALLBACK_QUEUE_LIMIT) {
|
|
354
|
-
this.
|
|
362
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe listener of Component "${subscription.plugin}" reached its ` +
|
|
355
363
|
`${OBSERVE_CALLBACK_QUEUE_LIMIT}-callback queue limit; this envelope was skipped`);
|
|
356
364
|
continue;
|
|
357
365
|
}
|
|
@@ -359,25 +367,33 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
359
367
|
const run = subscription.chain.then(async () => {
|
|
360
368
|
if (subscription.closed)
|
|
361
369
|
return;
|
|
370
|
+
// Re-check at the actual callback boundary as well as at enqueue
|
|
371
|
+
// time. A grant may be revoked while an earlier callback is still
|
|
372
|
+
// running; queued envelopes must then be skipped rather than
|
|
373
|
+
// delivered from the stale pre-revocation snapshot.
|
|
374
|
+
if (!this.grants().allows({ componentId: subscription.identity.componentId, activationId: subscription.identity.activationId }, 'messages.observe.read', scope)) {
|
|
375
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe subscription of plugin "${subscription.plugin}" released — the grant was revoked`);
|
|
376
|
+
this.drop(subscription);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
362
379
|
const isolated = freezeEnvelope(envelope);
|
|
363
380
|
const result = await runWithBudget(() => subscription.listener(isolated), OBSERVE_CALLBACK_TIMEOUT_MS);
|
|
364
381
|
if (result.kind === 'timeout') {
|
|
365
|
-
this.
|
|
382
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe listener of Component "${subscription.plugin}" exceeded ` +
|
|
366
383
|
`${OBSERVE_CALLBACK_TIMEOUT_MS}ms and the subscription was closed`);
|
|
367
384
|
this.drop(subscription);
|
|
368
385
|
}
|
|
369
386
|
else if (result.kind === 'rejected') {
|
|
370
|
-
this.
|
|
371
|
-
`${result.error instanceof Error ? result.error.message : String(result.error)}`);
|
|
387
|
+
observerStateFor(this).hostContext.logger.warn(`dsh-tui: messages.observe listener of Component "${subscription.plugin}" failed; delivery continues`);
|
|
372
388
|
}
|
|
373
389
|
});
|
|
374
390
|
subscription.chain = run.catch(error => {
|
|
375
|
-
this.
|
|
391
|
+
observerStateFor(this).hostContext.logger.warn('dsh-tui: messages.observe delivery failed');
|
|
376
392
|
}).finally(() => { subscription.pendingCallbacks -= 1; });
|
|
377
393
|
}
|
|
378
394
|
}
|
|
379
395
|
catch (error) {
|
|
380
|
-
this.
|
|
396
|
+
observerStateFor(this).hostContext.logger.warn('dsh-tui: messages.observe publish failed (event dropped)');
|
|
381
397
|
}
|
|
382
398
|
}
|
|
383
399
|
/** Release a subscription exactly once (disposer, ctx unload, revoke). */
|
|
@@ -387,7 +403,7 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
387
403
|
subscription.closed = true;
|
|
388
404
|
subscription.stopGrantWatch?.();
|
|
389
405
|
subscription.stopGrantWatch = undefined;
|
|
390
|
-
this.subscriptions.delete(subscription);
|
|
406
|
+
observerStateFor(this).subscriptions.delete(subscription);
|
|
391
407
|
this.ledger()?.record({ operation: 'release', resource: { kind: 'subscription', id: subscription.plugin }, result: 'applied' }, subscription.ownerContext);
|
|
392
408
|
}
|
|
393
409
|
/** Join the text blocks of a session message's content (text-only view). */
|
|
@@ -486,12 +502,21 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
486
502
|
const bytes = attachment.bytes;
|
|
487
503
|
if (typeof bytes !== 'number' || !Number.isFinite(bytes) || bytes < 0 || bytes > OBSERVE_IMAGE_MAX_BYTES)
|
|
488
504
|
return undefined;
|
|
489
|
-
const reader = this.
|
|
505
|
+
const reader = observerStateFor(this).hostContext.get('attachments');
|
|
490
506
|
if (typeof reader?.readImage !== 'function')
|
|
491
507
|
return undefined;
|
|
492
508
|
// A failing read drops ONLY this image (the envelope survives with the
|
|
493
509
|
// truncation mark) — one corrupt attachment must not nuke the message.
|
|
494
|
-
|
|
510
|
+
let timer;
|
|
511
|
+
const read = Promise.resolve().then(() => reader.readImage(attachment));
|
|
512
|
+
const timeout = new Promise(resolve => {
|
|
513
|
+
timer = setTimeout(() => resolve(undefined), OBSERVE_IMAGE_READ_TIMEOUT_MS);
|
|
514
|
+
});
|
|
515
|
+
const stored = await Promise.race([read, timeout]);
|
|
516
|
+
if (timer !== undefined)
|
|
517
|
+
clearTimeout(timer);
|
|
518
|
+
// `read` has an attached rejection handler through the race's promise
|
|
519
|
+
// chain; late completion after a timeout is deliberately ignored.
|
|
495
520
|
const data = stored?.data;
|
|
496
521
|
if (!(data instanceof Uint8Array) || data.byteLength > OBSERVE_IMAGE_MAX_BYTES)
|
|
497
522
|
return undefined;
|
|
@@ -507,3 +532,22 @@ export class TuiMessageObserverRuntime extends Service {
|
|
|
507
532
|
}
|
|
508
533
|
}
|
|
509
534
|
}
|
|
535
|
+
/** Host-only ingress accessor; deliberately omitted from `./plugin-host`. */
|
|
536
|
+
const hostMessageObservers = new WeakMap();
|
|
537
|
+
export function getHostMessageObserver(runtime) {
|
|
538
|
+
if (runtime === undefined)
|
|
539
|
+
return undefined;
|
|
540
|
+
try {
|
|
541
|
+
return hostMessageObservers.get(concreteService(runtime));
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
return undefined;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const observerStates = new WeakMap();
|
|
548
|
+
function observerStateFor(runtime) {
|
|
549
|
+
const state = observerStates.get(concreteService(runtime));
|
|
550
|
+
if (state === undefined)
|
|
551
|
+
throw new Error('tuiMessageObserver host state is unavailable');
|
|
552
|
+
return state;
|
|
553
|
+
}
|
|
@@ -39,19 +39,33 @@ import { type GrantStore } from './grants.js';
|
|
|
39
39
|
import { type HostDescriptorBuild } from './host-descriptor.js';
|
|
40
40
|
import { type DecisionRegistrationOptions } from './decision-guard.js';
|
|
41
41
|
import { type VerifiedComponentIdentity } from './component-identity.js';
|
|
42
|
+
/** Public, mediated plugin-host capability. Loader-only admission remains
|
|
43
|
+
* behind getHostAdmission(), which is deliberately omitted from the package
|
|
44
|
+
* export surface. */
|
|
45
|
+
export interface TuiPluginHost {
|
|
46
|
+
readonly generationId: string;
|
|
47
|
+
readonly grants: GrantStore;
|
|
48
|
+
hostDescriptor(): HostDescriptor;
|
|
49
|
+
describe(): HostDescriptorBuild;
|
|
50
|
+
subscribeDecision(pluginCtx: Context, event: string, listener: (payload: Record<string, unknown>) => unknown, options?: {
|
|
51
|
+
scope?: string;
|
|
52
|
+
order?: string;
|
|
53
|
+
}): () => boolean;
|
|
54
|
+
registerCommand(pluginCtx: Context, definition: CommandDefinition): () => void;
|
|
55
|
+
registerCommand(pluginCtx: Context, contributionId: string, definition: CommandDefinition): () => void;
|
|
56
|
+
selfCheck(): string[];
|
|
57
|
+
}
|
|
42
58
|
declare module '@deepseek-ai/cordis' {
|
|
43
59
|
interface Context {
|
|
44
|
-
tuiPluginHost:
|
|
60
|
+
tuiPluginHost: TuiPluginHost;
|
|
45
61
|
}
|
|
46
62
|
}
|
|
47
63
|
/** `ctx.tuiPluginHost` — plugin-interop anchor (generation, grants, descriptor). */
|
|
48
|
-
export declare class TuiPluginHostRuntime extends Service {
|
|
64
|
+
export declare class TuiPluginHostRuntime extends Service implements TuiPluginHost {
|
|
49
65
|
/** Runtime generation id (C-050): fresh per activation of this row. */
|
|
50
|
-
|
|
66
|
+
get generationId(): string;
|
|
51
67
|
/** Live scoped grant store; every operation observes the current file. */
|
|
52
|
-
|
|
53
|
-
private descriptorBuild;
|
|
54
|
-
private descriptorCommandsMounted;
|
|
68
|
+
get grants(): GrantStore;
|
|
55
69
|
constructor(ctx: Context);
|
|
56
70
|
/**
|
|
57
71
|
* The C-010 Host Descriptor, built lazily and cached while the
|
|
@@ -69,6 +83,11 @@ export declare class TuiPluginHostRuntime extends Service {
|
|
|
69
83
|
source?: string;
|
|
70
84
|
activationId?: string;
|
|
71
85
|
}): VerifiedComponentIdentity;
|
|
86
|
+
/** @internal Host loader entry; the unexported token prevents proxy calls. */
|
|
87
|
+
admitInternal(pluginCtx: Context, source: string, options?: {
|
|
88
|
+
source?: string;
|
|
89
|
+
activationId?: string;
|
|
90
|
+
}, token?: symbol): VerifiedComponentIdentity;
|
|
72
91
|
/**
|
|
73
92
|
* Host-mediated DecisionEvents activation surface. A plugin cannot use a
|
|
74
93
|
* raw `ctx.on` for these points: the verified Component identity, static
|
|
@@ -98,6 +117,20 @@ export declare class TuiPluginHostRuntime extends Service {
|
|
|
98
117
|
*/
|
|
99
118
|
selfCheck(): string[];
|
|
100
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Loader-only admission capability. It is intentionally omitted from the
|
|
122
|
+
* package `plugin-host` export; tests and the in-process loader can obtain it
|
|
123
|
+
* from this adapter module, while a plugin calling the public service proxy
|
|
124
|
+
* receives a deterministic denial instead of being able to impersonate a
|
|
125
|
+
* different manifest identity.
|
|
126
|
+
*/
|
|
127
|
+
export interface HostAdmission {
|
|
128
|
+
admit(pluginCtx: Context, source: string, options?: {
|
|
129
|
+
source?: string;
|
|
130
|
+
activationId?: string;
|
|
131
|
+
}): VerifiedComponentIdentity;
|
|
132
|
+
}
|
|
133
|
+
export declare function getHostAdmission(runtime: TuiPluginHost | TuiPluginHostRuntime | undefined): HostAdmission | undefined;
|
|
101
134
|
export declare const name = "dsh-tui-plugin-host";
|
|
102
135
|
export declare function apply(ctx: Context): void;
|
|
103
136
|
//# sourceMappingURL=plugin-host.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-host.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAI7D,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAiD,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAM9G,OAAO,EAKL,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAA;AAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"plugin-host.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/plugin-host.ts"],"names":[],"mappings":"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"}
|