@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
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { Context, Fiber } from '@deepseek-ai/cordis';
|
|
3
|
+
/**
|
|
4
|
+
* Recover the concrete Cordis service for host-only adapters.
|
|
5
|
+
*
|
|
6
|
+
* `ctx.get()` returns a traceable proxy even to the root context. Public
|
|
7
|
+
* services deliberately do not expose their host controls on that proxy, so
|
|
8
|
+
* the host accessor functions keep their state in WeakMaps keyed by the
|
|
9
|
+
* concrete service instance and unwrap only here.
|
|
10
|
+
*/
|
|
11
|
+
const CORDIS_ORIGINAL = Symbol.for('cordis.original');
|
|
12
|
+
const compositionRoots = new WeakMap();
|
|
13
|
+
const trackedRoots = new WeakSet();
|
|
14
|
+
const trustedFibers = new WeakSet();
|
|
15
|
+
const canonicalContexts = new WeakMap();
|
|
16
|
+
const rootFibers = new WeakMap();
|
|
17
|
+
const fiberRoots = new WeakMap();
|
|
18
|
+
const fiberEffects = new WeakMap();
|
|
19
|
+
const contextFibers = new WeakMap();
|
|
20
|
+
const restartingFibers = new WeakSet();
|
|
21
|
+
const restartPendingFibers = new WeakSet();
|
|
22
|
+
const executingFibers = new WeakSet();
|
|
23
|
+
const wrappedRunners = new WeakSet();
|
|
24
|
+
const wrappedRestarts = new WeakSet();
|
|
25
|
+
const canonicalRunners = new WeakMap();
|
|
26
|
+
const activationGenerations = new WeakMap();
|
|
27
|
+
const activationTokens = new WeakMap();
|
|
28
|
+
const activationStorage = new AsyncLocalStorage();
|
|
29
|
+
const hostCapabilityStorage = new AsyncLocalStorage();
|
|
30
|
+
const guardedRootFibers = new WeakSet();
|
|
31
|
+
const guardedRootRegistries = new WeakSet();
|
|
32
|
+
const guardedRootEvents = new WeakSet();
|
|
33
|
+
const guardedRootReflects = new WeakSet();
|
|
34
|
+
installGlobalFiberInstrumentation();
|
|
35
|
+
/**
|
|
36
|
+
* Cordis contexts are prototype-scoped objects. A plugin can therefore make
|
|
37
|
+
* `ctx.extend({ fiber: fake })`, which passes a shape-only check while making
|
|
38
|
+
* cleanup land on an attacker-controlled effect object. Track the fibers
|
|
39
|
+
* Cordis actually publishes from the composition root and require callers to
|
|
40
|
+
* use one of those identities. The root listener is global so child context
|
|
41
|
+
* filters cannot hide lifecycle notifications from this guard.
|
|
42
|
+
*/
|
|
43
|
+
function rememberFiber(value, root) {
|
|
44
|
+
if (typeof value !== 'object' || value === null)
|
|
45
|
+
return;
|
|
46
|
+
try {
|
|
47
|
+
const fiber = value;
|
|
48
|
+
const owner = fiber.ctx;
|
|
49
|
+
if (!Context.is(owner))
|
|
50
|
+
return;
|
|
51
|
+
// The internal/plugin event carries Cordis's wrapper Fiber, while the
|
|
52
|
+
// context exposes the underlying instance. Normalize both to that stable
|
|
53
|
+
// instance before recording trust and lifecycle state.
|
|
54
|
+
const actual = owner.fiber;
|
|
55
|
+
if (typeof actual !== 'object' || actual === null || actual.ctx !== owner)
|
|
56
|
+
return;
|
|
57
|
+
if (root !== undefined && !fiberBelongsToComposition(actual, root))
|
|
58
|
+
return;
|
|
59
|
+
const canonical = canonicalContexts.get(actual);
|
|
60
|
+
if (canonical !== undefined && canonical !== owner)
|
|
61
|
+
return;
|
|
62
|
+
const knownRoot = fiberRoots.get(actual);
|
|
63
|
+
if (knownRoot !== undefined && root !== undefined && knownRoot !== root)
|
|
64
|
+
return;
|
|
65
|
+
if (canonical !== undefined && canonical.fiber !== actual)
|
|
66
|
+
return;
|
|
67
|
+
canonicalContexts.set(actual, canonical ?? owner);
|
|
68
|
+
contextFibers.set(owner, actual);
|
|
69
|
+
trustedFibers.add(actual);
|
|
70
|
+
if (root !== undefined)
|
|
71
|
+
fiberRoots.set(actual, root);
|
|
72
|
+
activationGenerations.set(actual, activationGenerations.get(actual) ?? 0);
|
|
73
|
+
const runner = actual._runner;
|
|
74
|
+
const knownRunner = canonicalRunners.get(actual);
|
|
75
|
+
if (knownRunner !== undefined && knownRunner !== runner)
|
|
76
|
+
return;
|
|
77
|
+
if (runner !== undefined)
|
|
78
|
+
canonicalRunners.set(actual, runner);
|
|
79
|
+
if (!fiberEffects.has(actual)) {
|
|
80
|
+
const effect = actual.effect;
|
|
81
|
+
if (typeof effect === 'function') {
|
|
82
|
+
fiberEffects.set(actual, (execute) => Reflect.apply(effect, actual, [execute]));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Cordis reuses the same activation context across a restart and emits
|
|
86
|
+
// LOADING before its private runner executes the new callback. Keep the
|
|
87
|
+
// old activation rejected through that window, but allow synchronous
|
|
88
|
+
// registrations made by the callback currently being executed.
|
|
89
|
+
if (runner !== undefined && typeof runner.execute === 'function' && !wrappedRunners.has(runner)) {
|
|
90
|
+
const execute = runner.execute;
|
|
91
|
+
wrappedRunners.add(runner);
|
|
92
|
+
Object.defineProperty(runner, 'execute', {
|
|
93
|
+
configurable: false,
|
|
94
|
+
writable: false,
|
|
95
|
+
value: function (...args) {
|
|
96
|
+
return runActivation(actual, execute, this, args);
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const restart = actual.restart;
|
|
101
|
+
if (typeof restart === 'function' && !wrappedRestarts.has(actual)) {
|
|
102
|
+
wrappedRestarts.add(actual);
|
|
103
|
+
Object.defineProperty(actual, 'restart', {
|
|
104
|
+
configurable: false,
|
|
105
|
+
writable: false,
|
|
106
|
+
value: function (...args) {
|
|
107
|
+
const root = fiberRoots.get(actual);
|
|
108
|
+
if (root !== undefined && rootFibers.get(root) === actual) {
|
|
109
|
+
rejectRootCapability(root, 'root.fiber.restart');
|
|
110
|
+
}
|
|
111
|
+
invalidateActivation(actual);
|
|
112
|
+
restartPendingFibers.add(actual);
|
|
113
|
+
restartingFibers.add(actual);
|
|
114
|
+
const clear = () => {
|
|
115
|
+
restartPendingFibers.delete(actual);
|
|
116
|
+
restartingFibers.delete(actual);
|
|
117
|
+
};
|
|
118
|
+
try {
|
|
119
|
+
const result = Reflect.apply(restart, this, args);
|
|
120
|
+
if (result !== null && typeof result === 'object' && 'then' in result) {
|
|
121
|
+
return Promise.resolve(result).finally(clear);
|
|
122
|
+
}
|
|
123
|
+
clear();
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
clear();
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return actual;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Untrusted values are simply not admitted to the identity set.
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function trackCompositionRoot(root) {
|
|
140
|
+
let rootFiber;
|
|
141
|
+
try {
|
|
142
|
+
const value = root.fiber;
|
|
143
|
+
if (typeof value === 'object' && value !== null) {
|
|
144
|
+
rootFiber = value;
|
|
145
|
+
rootFibers.set(root, value);
|
|
146
|
+
fiberRoots.set(value, root);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Fall through to the event-listener attempt below.
|
|
151
|
+
}
|
|
152
|
+
rememberFiber(rootFiber, root);
|
|
153
|
+
if (trackedRoots.has(root))
|
|
154
|
+
return;
|
|
155
|
+
trackedRoots.add(root);
|
|
156
|
+
try {
|
|
157
|
+
root.on('internal/plugin', (fiber) => rememberFiber(fiber, root), { global: true });
|
|
158
|
+
root.on('internal/status', (fiber) => {
|
|
159
|
+
const actual = rememberFiber(fiber, root);
|
|
160
|
+
if (actual === undefined)
|
|
161
|
+
return;
|
|
162
|
+
const state = actual.state;
|
|
163
|
+
// Cordis uses 5 for UNLOADING. The wrapper returned by ctx.plugin()
|
|
164
|
+
// reports this transition while the underlying context fiber may still
|
|
165
|
+
// expose ACTIVE, so track the transition explicitly. Keep the marker
|
|
166
|
+
// through LOADING: Cordis awaits a microtask before invoking the new
|
|
167
|
+
// callback, leaving a stale-context window otherwise. The runner wrapper
|
|
168
|
+
// above temporarily admits synchronous calls from that new callback.
|
|
169
|
+
if (state === 5 || state === 3 || state === 4)
|
|
170
|
+
restartingFibers.add(actual);
|
|
171
|
+
else if (state === 2 && !restartPendingFibers.has(actual))
|
|
172
|
+
restartingFibers.delete(actual);
|
|
173
|
+
}, { global: true });
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Minimal embedders may expose Context without an event helper. The
|
|
177
|
+
// shape/lifecycle checks below remain as a conservative fallback.
|
|
178
|
+
}
|
|
179
|
+
guardRootCapabilities(root);
|
|
180
|
+
}
|
|
181
|
+
function invalidateActivation(fiber) {
|
|
182
|
+
activationGenerations.set(fiber, (activationGenerations.get(fiber) ?? 0) + 1);
|
|
183
|
+
activationTokens.delete(fiber);
|
|
184
|
+
}
|
|
185
|
+
/** Carry an activation token through every async continuation created by a
|
|
186
|
+
* Cordis plugin callback. The fallback context/root walk covers compositions
|
|
187
|
+
* that do not mount a dsh-tui service and therefore have not been admitted to
|
|
188
|
+
* the host's canonical Fiber maps yet. */
|
|
189
|
+
function runActivation(fiber, execute, receiver, args) {
|
|
190
|
+
const context = canonicalContexts.get(fiber) ?? fiber.ctx;
|
|
191
|
+
const root = fiberRoots.get(fiber) ?? findFiberRoot(fiber);
|
|
192
|
+
if (!Context.is(context) || !Context.is(root)) {
|
|
193
|
+
return Reflect.apply(execute, receiver, args);
|
|
194
|
+
}
|
|
195
|
+
const generation = (activationGenerations.get(fiber) ?? 0) + 1;
|
|
196
|
+
activationGenerations.set(fiber, generation);
|
|
197
|
+
const token = { fiber, context, root, generation };
|
|
198
|
+
activationTokens.set(fiber, token);
|
|
199
|
+
// Once the new callback starts, the old generation is already invalidated.
|
|
200
|
+
// Keep the restart marker until the public restart promise settles;
|
|
201
|
+
// assertLiveContext admits only this current token while it is held.
|
|
202
|
+
executingFibers.add(fiber);
|
|
203
|
+
return activationStorage.run(token, () => {
|
|
204
|
+
try {
|
|
205
|
+
return Reflect.apply(execute, receiver, args);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
executingFibers.delete(fiber);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function findFiberRoot(value) {
|
|
213
|
+
let fiber = value;
|
|
214
|
+
const seen = new Set();
|
|
215
|
+
for (let depth = 0; depth < 64; depth += 1) {
|
|
216
|
+
if (typeof fiber !== 'object' || fiber === null || seen.has(fiber))
|
|
217
|
+
return undefined;
|
|
218
|
+
seen.add(fiber);
|
|
219
|
+
try {
|
|
220
|
+
if (fiber.runtime === null) {
|
|
221
|
+
return Context.is(fiber.ctx) ? fiber.ctx : undefined;
|
|
222
|
+
}
|
|
223
|
+
const parent = fiber.parent;
|
|
224
|
+
if (!Context.is(parent))
|
|
225
|
+
return undefined;
|
|
226
|
+
fiber = parent.fiber;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
/** Patch Cordis once so plugin callbacks in compositions outside the TUI
|
|
235
|
+
* host still carry an ALS token when they call a guarded root object. */
|
|
236
|
+
function installGlobalFiberInstrumentation() {
|
|
237
|
+
const prototype = Fiber.prototype;
|
|
238
|
+
const original = prototype._execute;
|
|
239
|
+
if (typeof original !== 'function')
|
|
240
|
+
return;
|
|
241
|
+
Object.defineProperty(prototype, '_execute', {
|
|
242
|
+
configurable: true,
|
|
243
|
+
writable: true,
|
|
244
|
+
value: function (runner) {
|
|
245
|
+
if (runner === this._runner && runner !== null && typeof runner === 'object'
|
|
246
|
+
&& typeof runner.execute === 'function' && !wrappedRunners.has(runner)) {
|
|
247
|
+
const execute = runner.execute;
|
|
248
|
+
const fiber = this;
|
|
249
|
+
wrappedRunners.add(runner);
|
|
250
|
+
Object.defineProperty(runner, 'execute', {
|
|
251
|
+
configurable: false,
|
|
252
|
+
writable: false,
|
|
253
|
+
value: function (...args) {
|
|
254
|
+
return runActivation(fiber, execute, this, args);
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return Reflect.apply(original, this, [runner]);
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/** The event bus is public and can emit `internal/plugin` manually. Admit a
|
|
263
|
+
* Fiber only when Cordis has already placed that exact identity in this
|
|
264
|
+
* composition's runtime registry (or it is the composition root itself). */
|
|
265
|
+
function fiberBelongsToComposition(fiber, root) {
|
|
266
|
+
if (rootFibers.get(root) === fiber)
|
|
267
|
+
return true;
|
|
268
|
+
try {
|
|
269
|
+
const registry = concreteService(root.registry);
|
|
270
|
+
const internal = registry._internal;
|
|
271
|
+
if (!(internal instanceof Map))
|
|
272
|
+
return false;
|
|
273
|
+
for (const runtime of internal.values()) {
|
|
274
|
+
const fibers = runtime.fibers;
|
|
275
|
+
if (fibers === null || fibers === undefined || typeof fibers[Symbol.iterator] !== 'function')
|
|
276
|
+
continue;
|
|
277
|
+
for (const candidate of fibers) {
|
|
278
|
+
if (candidate === fiber)
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
// A minimal embedder may not expose registry internals. Fail closed.
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function currentActivationIsPlugin(root) {
|
|
289
|
+
if (hostCapabilityStorage.getStore() === true)
|
|
290
|
+
return false;
|
|
291
|
+
const token = activationStorage.getStore();
|
|
292
|
+
if (token === undefined)
|
|
293
|
+
return false;
|
|
294
|
+
if (rootFibers.get(token.root) === token.fiber)
|
|
295
|
+
return false;
|
|
296
|
+
// Both active and stale plugin chains are denied. Stale chains will also be
|
|
297
|
+
// rejected by the mediated APIs through their generation check.
|
|
298
|
+
return true;
|
|
299
|
+
}
|
|
300
|
+
/** Host-only escape hatch for process teardown paths that intentionally act on
|
|
301
|
+
* the composition root while running from a host plugin callback. This module
|
|
302
|
+
* is internal and is not part of the public plugin package surface. */
|
|
303
|
+
export function withHostRootCapability(callback) {
|
|
304
|
+
return hostCapabilityStorage.run(true, callback);
|
|
305
|
+
}
|
|
306
|
+
function rejectRootCapability(root, capability) {
|
|
307
|
+
if (currentActivationIsPlugin(root)) {
|
|
308
|
+
throw new Error(`dsh-tui: ${capability} is unavailable from a plugin activation`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function callContextOf(receiver) {
|
|
312
|
+
try {
|
|
313
|
+
const context = receiver.ctx;
|
|
314
|
+
return Context.is(context) ? context : undefined;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function guardRootCapabilities(root) {
|
|
321
|
+
const rootFiber = rootFibers.get(root);
|
|
322
|
+
if (rootFiber !== undefined && !guardedRootFibers.has(rootFiber)) {
|
|
323
|
+
guardedRootFibers.add(rootFiber);
|
|
324
|
+
guardFiberMethod(rootFiber, 'effect', root, 'root.effect');
|
|
325
|
+
guardFiberMethod(rootFiber, 'restart', root, 'root.fiber.restart');
|
|
326
|
+
guardFiberMethod(rootFiber, 'dispose', root, 'root.fiber.dispose');
|
|
327
|
+
guardFiberMethod(rootFiber, 'update', root, 'root.fiber.update');
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
const registry = concreteService(root.registry);
|
|
331
|
+
if (!guardedRootRegistries.has(registry)) {
|
|
332
|
+
guardedRootRegistries.add(registry);
|
|
333
|
+
guardServiceMethod(registry, 'inject', root, 'root.inject', true);
|
|
334
|
+
guardServiceMethod(registry, 'plugin', root, 'root.plugin', true);
|
|
335
|
+
guardServiceMethod(registry, 'delete', root, 'root.registry.delete', true);
|
|
336
|
+
for (const method of ['resolve', 'get', 'has', 'keys', 'values', 'entries', 'forEach']) {
|
|
337
|
+
guardServiceMethod(registry, method, root, `root.registry.${method}`, true);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
// A minimal embedder may not expose the registry service object.
|
|
343
|
+
}
|
|
344
|
+
try {
|
|
345
|
+
const events = concreteService(root.events);
|
|
346
|
+
if (!guardedRootEvents.has(events)) {
|
|
347
|
+
guardedRootEvents.add(events);
|
|
348
|
+
for (const method of ['on', 'once', 'emit', 'parallel', 'serial', 'bail', 'waterfall', 'register', 'unregister', 'dispatch']) {
|
|
349
|
+
guardServiceMethod(events, method, root, `root.events.${method}`, true);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// Event guards are supplemental; Fiber admission remains fail-closed.
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
const reflect = concreteService(root.reflect);
|
|
358
|
+
if (!guardedRootReflects.has(reflect)) {
|
|
359
|
+
guardedRootReflects.add(reflect);
|
|
360
|
+
guardServiceMethod(reflect, 'set', root, 'root.reflect.set', true);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
// Fall through when a minimal embedder omits reflection internals.
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function guardFiberMethod(target, method, root, capability) {
|
|
368
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(target, method);
|
|
369
|
+
if (descriptor?.configurable === false)
|
|
370
|
+
return;
|
|
371
|
+
const original = Reflect.get(target, method);
|
|
372
|
+
if (typeof original !== 'function')
|
|
373
|
+
return;
|
|
374
|
+
Object.defineProperty(target, method, {
|
|
375
|
+
configurable: false,
|
|
376
|
+
writable: false,
|
|
377
|
+
value: function (...args) {
|
|
378
|
+
rejectRootCapability(root, capability);
|
|
379
|
+
return Reflect.apply(original, this, args);
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
function guardServiceMethod(target, method, root, capability, rootOnly) {
|
|
384
|
+
const original = Reflect.get(target, method);
|
|
385
|
+
if (typeof original !== 'function')
|
|
386
|
+
return;
|
|
387
|
+
Object.defineProperty(target, method, {
|
|
388
|
+
configurable: false,
|
|
389
|
+
writable: false,
|
|
390
|
+
value: function (...args) {
|
|
391
|
+
const callContext = callContextOf(this);
|
|
392
|
+
if (!rootOnly || callContext === root)
|
|
393
|
+
rejectRootCapability(root, capability);
|
|
394
|
+
return Reflect.apply(original, this, args);
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
export function concreteService(service) {
|
|
399
|
+
let current = service;
|
|
400
|
+
const seen = new WeakSet();
|
|
401
|
+
while (!seen.has(current)) {
|
|
402
|
+
seen.add(current);
|
|
403
|
+
let original;
|
|
404
|
+
try {
|
|
405
|
+
original = Reflect.get(current, CORDIS_ORIGINAL);
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
if (original === null || typeof original !== 'object' || original === current)
|
|
411
|
+
break;
|
|
412
|
+
current = original;
|
|
413
|
+
}
|
|
414
|
+
return current;
|
|
415
|
+
}
|
|
416
|
+
/** Bind a host-side disposer to the caller's authenticated Cordis activation.
|
|
417
|
+
* A failed registration immediately rolls back the owned contribution. */
|
|
418
|
+
export function bindCallerEffect(ctx, disposer, onRegistered) {
|
|
419
|
+
let effect;
|
|
420
|
+
try {
|
|
421
|
+
const fiber = assertLiveContext(ctx, 'effect');
|
|
422
|
+
effect = fiberEffects.get(fiber);
|
|
423
|
+
}
|
|
424
|
+
catch {
|
|
425
|
+
// An untrusted or inactive caller cannot use a compatibility fallback to
|
|
426
|
+
// attach cleanup to a writable context shadow.
|
|
427
|
+
disposer();
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
if (effect === undefined) {
|
|
431
|
+
disposer();
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
try {
|
|
435
|
+
const cleanup = effect(() => disposer);
|
|
436
|
+
if (typeof cleanup === 'function') {
|
|
437
|
+
onRegistered?.(cleanup);
|
|
438
|
+
}
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
catch {
|
|
442
|
+
// Registration and the mutation it owns must be atomic. If the fiber has
|
|
443
|
+
// entered teardown, immediately undo the caller's contribution.
|
|
444
|
+
disposer();
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/** Return the stable, authenticated Fiber identity for an activation. */
|
|
449
|
+
export function activationFiber(ctx) {
|
|
450
|
+
try {
|
|
451
|
+
return assertLiveContext(ctx, 'activation');
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
return undefined;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/** Return Cordis's canonical activation context, never a writable context
|
|
458
|
+
* shadow. Explicit owner arguments use this before resolving host services. */
|
|
459
|
+
export function activationContext(ctx) {
|
|
460
|
+
const fiber = activationFiber(ctx);
|
|
461
|
+
if (fiber === undefined)
|
|
462
|
+
return undefined;
|
|
463
|
+
return canonicalContexts.get(fiber);
|
|
464
|
+
}
|
|
465
|
+
/** Resolve a service's composition root once. Service methods are invoked
|
|
466
|
+
* through caller-bound Cordis proxies; keeping this root in host state avoids
|
|
467
|
+
* resolving sibling services through an attacker-provided caller shadow. */
|
|
468
|
+
export function compositionRoot(ctx) {
|
|
469
|
+
try {
|
|
470
|
+
const knownFiber = contextFibers.get(ctx);
|
|
471
|
+
const trustedRoot = knownFiber === undefined ? undefined : fiberRoots.get(knownFiber);
|
|
472
|
+
if (trustedRoot !== undefined) {
|
|
473
|
+
compositionRoots.set(ctx, trustedRoot);
|
|
474
|
+
return trustedRoot;
|
|
475
|
+
}
|
|
476
|
+
const directFiber = ctx.fiber;
|
|
477
|
+
const directRoot = typeof directFiber === 'object' && directFiber !== null
|
|
478
|
+
? fiberRoots.get(directFiber)
|
|
479
|
+
: undefined;
|
|
480
|
+
if (directRoot !== undefined) {
|
|
481
|
+
contextFibers.set(ctx, directFiber);
|
|
482
|
+
compositionRoots.set(ctx, directRoot);
|
|
483
|
+
return directRoot;
|
|
484
|
+
}
|
|
485
|
+
const cached = compositionRoots.get(ctx);
|
|
486
|
+
if (cached !== undefined) {
|
|
487
|
+
trackCompositionRoot(cached);
|
|
488
|
+
return cached;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
// Fall through to the fiber walk for degraded contexts.
|
|
493
|
+
}
|
|
494
|
+
try {
|
|
495
|
+
let current = ctx;
|
|
496
|
+
const seen = new Set();
|
|
497
|
+
for (let depth = 0; depth < 64; depth += 1) {
|
|
498
|
+
const currentFiber = current.fiber;
|
|
499
|
+
if (typeof currentFiber !== 'object' || currentFiber === null || seen.has(currentFiber))
|
|
500
|
+
break;
|
|
501
|
+
seen.add(currentFiber);
|
|
502
|
+
const cached = compositionRoots.get(current);
|
|
503
|
+
if (cached !== undefined) {
|
|
504
|
+
compositionRoots.set(ctx, cached);
|
|
505
|
+
trackCompositionRoot(cached);
|
|
506
|
+
return cached;
|
|
507
|
+
}
|
|
508
|
+
if (currentFiber.runtime === null) {
|
|
509
|
+
const root = Context.is(currentFiber.ctx) ? currentFiber.ctx : current;
|
|
510
|
+
compositionRoots.set(current, root);
|
|
511
|
+
compositionRoots.set(ctx, root);
|
|
512
|
+
compositionRoots.set(root, root);
|
|
513
|
+
trackCompositionRoot(root);
|
|
514
|
+
return root;
|
|
515
|
+
}
|
|
516
|
+
const parent = currentFiber.parent;
|
|
517
|
+
if (!Context.is(parent))
|
|
518
|
+
break;
|
|
519
|
+
current = parent;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
catch {
|
|
523
|
+
// Fall through to the conservative self-root fallback below.
|
|
524
|
+
}
|
|
525
|
+
compositionRoots.set(ctx, ctx);
|
|
526
|
+
trackCompositionRoot(ctx);
|
|
527
|
+
return ctx;
|
|
528
|
+
}
|
|
529
|
+
function assertLiveContext(ctx, capability) {
|
|
530
|
+
try {
|
|
531
|
+
const known = contextFibers.get(ctx);
|
|
532
|
+
const directFiber = ctx.fiber;
|
|
533
|
+
if (known !== undefined && directFiber !== known)
|
|
534
|
+
throw new Error('mutated context fiber');
|
|
535
|
+
const fiber = (known ?? directFiber);
|
|
536
|
+
if (fiber.uid === null)
|
|
537
|
+
throw new Error('disposed');
|
|
538
|
+
// @deepseek-ai/cordis exposes FiberState as a const enum, so it is not a
|
|
539
|
+
// runtime export. LOADING=1 and ACTIVE=2 are the only states in which a
|
|
540
|
+
// caller can still be executing/owning effects; all other states reject.
|
|
541
|
+
if (fiber.state !== 1 && fiber.state !== 2) {
|
|
542
|
+
throw new Error('inactive');
|
|
543
|
+
}
|
|
544
|
+
// `Fiber.restart()` invalidates the runner epoch before Cordis updates
|
|
545
|
+
// the public state. Read the runtime-private marker as well so a retained
|
|
546
|
+
// context cannot register an effect during that unload/reload window.
|
|
547
|
+
const runner = fiber._runner;
|
|
548
|
+
if (canonicalRunners.get(fiber) !== runner)
|
|
549
|
+
throw new Error('mutated runner');
|
|
550
|
+
if (runner?.epoch === '__INACTIVE__') {
|
|
551
|
+
throw new Error('inactive');
|
|
552
|
+
}
|
|
553
|
+
if (!trustedFibers.has(fiber))
|
|
554
|
+
throw new Error('unregistered');
|
|
555
|
+
const owner = canonicalContexts.get(fiber);
|
|
556
|
+
if (owner === undefined)
|
|
557
|
+
throw new Error('unowned');
|
|
558
|
+
if (fiber.ctx !== owner || owner.fiber !== fiber)
|
|
559
|
+
throw new Error('mutated');
|
|
560
|
+
let current = ctx;
|
|
561
|
+
let matched = false;
|
|
562
|
+
for (let depth = 0; depth < 64 && current !== null; depth += 1) {
|
|
563
|
+
if (current === owner) {
|
|
564
|
+
matched = true;
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
current = Object.getPrototypeOf(current);
|
|
568
|
+
}
|
|
569
|
+
const token = activationStorage.getStore();
|
|
570
|
+
const tokenIsCurrent = token !== undefined
|
|
571
|
+
&& token.fiber === fiber
|
|
572
|
+
&& token.context === owner
|
|
573
|
+
&& token.root === fiberRoots.get(fiber)
|
|
574
|
+
&& token.generation === activationGenerations.get(fiber)
|
|
575
|
+
&& activationTokens.get(fiber) === token;
|
|
576
|
+
if (token !== undefined && !tokenIsCurrent) {
|
|
577
|
+
throw new Error('stale activation');
|
|
578
|
+
}
|
|
579
|
+
if (!matched || (restartingFibers.has(fiber) && !tokenIsCurrent && !executingFibers.has(fiber)))
|
|
580
|
+
throw new Error('inactive');
|
|
581
|
+
contextFibers.set(ctx, fiber);
|
|
582
|
+
return fiber;
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
// Fall through to the stable public error below.
|
|
586
|
+
}
|
|
587
|
+
throw new Error(`dsh-tui: ${capability} requires a live Cordis activation context`);
|
|
588
|
+
}
|
|
589
|
+
/** Recover the composition root that owns a traceable service. Cordis stores
|
|
590
|
+
* the provider context on the concrete Service instance; callers may reach
|
|
591
|
+
* that instance through a proxy from another composition, so this must be
|
|
592
|
+
* resolved from the unwrapped service rather than from the call context. */
|
|
593
|
+
export function serviceCompositionRoot(service) {
|
|
594
|
+
try {
|
|
595
|
+
const owner = concreteService(service).ctx;
|
|
596
|
+
return Context.is(owner) ? compositionRoot(owner) : undefined;
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
return undefined;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/** Explicit context arguments on mediated APIs may be supplied by host code
|
|
603
|
+
* running from the composition root, or may be the activation making the
|
|
604
|
+
* service call. A non-root plugin cannot nominate a different activation's
|
|
605
|
+
* context and thereby borrow its verified identity/lifecycle. */
|
|
606
|
+
export function assertCallerContext(caller, target, capability, service) {
|
|
607
|
+
if (!Context.is(caller) || !Context.is(target)) {
|
|
608
|
+
throw new Error(`dsh-tui: ${capability} requires a Cordis activation context`);
|
|
609
|
+
}
|
|
610
|
+
const callerFiber = assertLiveContext(caller, capability);
|
|
611
|
+
const targetFiber = assertLiveContext(target, capability);
|
|
612
|
+
const ownerRoot = service === undefined ? undefined : serviceCompositionRoot(service);
|
|
613
|
+
if (ownerRoot !== undefined
|
|
614
|
+
&& (compositionRoot(caller) !== ownerRoot || compositionRoot(target) !== ownerRoot)) {
|
|
615
|
+
throw new Error(`dsh-tui: ${capability} context belongs to a different composition`);
|
|
616
|
+
}
|
|
617
|
+
if (caller === target || callerFiber === targetFiber)
|
|
618
|
+
return;
|
|
619
|
+
const root = compositionRoot(caller);
|
|
620
|
+
if (caller === root || callerFiber === rootFibers.get(root))
|
|
621
|
+
return;
|
|
622
|
+
throw new Error(`dsh-tui: ${capability} context must be the calling activation`);
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Resolve the caller for a plugin-owned effect. A plugin can read
|
|
626
|
+
* `ctx.root`, but using its root-bound service proxy would attach cleanup to
|
|
627
|
+
* the host fiber and leave the effect alive after the plugin unloads. Host
|
|
628
|
+
* code must use the module-local host accessor for controls it owns; the
|
|
629
|
+
* public service surface only accepts a live non-root activation.
|
|
630
|
+
*/
|
|
631
|
+
export function requirePluginCaller(caller, capability, service) {
|
|
632
|
+
if (!Context.is(caller)) {
|
|
633
|
+
throw new Error(`dsh-tui: ${capability} requires a Cordis activation context`);
|
|
634
|
+
}
|
|
635
|
+
try {
|
|
636
|
+
const callerFiber = assertLiveContext(caller, capability);
|
|
637
|
+
const root = compositionRoot(caller);
|
|
638
|
+
if (caller === root || callerFiber === rootFibers.get(root)) {
|
|
639
|
+
throw new Error(`dsh-tui: ${capability} requires a non-root calling activation`);
|
|
640
|
+
}
|
|
641
|
+
const ownerRoot = service === undefined ? undefined : serviceCompositionRoot(service);
|
|
642
|
+
if (ownerRoot !== undefined && compositionRoot(caller) !== ownerRoot) {
|
|
643
|
+
throw new Error(`dsh-tui: ${capability} context belongs to a different composition`);
|
|
644
|
+
}
|
|
645
|
+
return caller;
|
|
646
|
+
}
|
|
647
|
+
catch (error) {
|
|
648
|
+
if (error instanceof Error && error.message.startsWith('dsh-tui:'))
|
|
649
|
+
throw error;
|
|
650
|
+
throw new Error(`dsh-tui: ${capability} requires a live non-root calling activation`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
@@ -16,8 +16,8 @@ export interface HostDescriptorOptions {
|
|
|
16
16
|
}
|
|
17
17
|
export interface HostDescriptorBuild {
|
|
18
18
|
descriptor: HostDescriptor;
|
|
19
|
-
dropped: string[];
|
|
20
|
-
warnings: string[];
|
|
19
|
+
readonly dropped: readonly string[];
|
|
20
|
+
readonly warnings: readonly string[];
|
|
21
21
|
}
|
|
22
22
|
export declare function readOwnPackageVersion(): string;
|
|
23
23
|
export declare function buildHostDescriptor(options: HostDescriptorOptions): HostDescriptorBuild;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-descriptor.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/host-descriptor.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAKnF,OAAO,KAAK,EAAE,kBAAkB,EAAgB,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAM/F,eAAO,MAAM,wBAAwB,EAAE,SAAS,kBAAkB,EAKhE,CAAA;AAEF;;;mCAGmC;AACnC,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAAgC,CAAA;AAErF,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,cAAc,CAAA;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"host-descriptor.d.ts","sourceRoot":"","sources":["../../../src/dsh-adapter/host-descriptor.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAKnF,OAAO,KAAK,EAAE,kBAAkB,EAAgB,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAM/F,eAAO,MAAM,wBAAwB,EAAE,SAAS,kBAAkB,EAKhE,CAAA;AAEF;;;mCAGmC;AACnC,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAAgC,CAAA;AAErF,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,cAAc,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AASD,wBAAgB,qBAAqB,IAAI,MAAM,CAyB9C;AASD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,mBAAmB,CAuGvF"}
|