@adhdev/daemon-core 0.9.82-rc.34 → 0.9.82-rc.341
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/dist/boot/daemon-lifecycle.d.ts +8 -0
- package/dist/boot/process-hardening.d.ts +50 -0
- package/dist/build-info.d.ts +37 -0
- package/dist/chat/source-machine.d.ts +166 -0
- package/dist/chat/source-resolver.d.ts +104 -0
- package/dist/chat/subscription-updates.d.ts +1 -0
- package/dist/cli-adapter-types.d.ts +46 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +198 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +116 -64
- package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +53 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +14 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
- package/dist/cli-adapters/terminal-screen.d.ts +4 -11
- package/dist/commands/cli-manager.d.ts +2 -1
- package/dist/commands/handler.d.ts +110 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router.d.ts +308 -1
- package/dist/commands/upgrade-helper.d.ts +12 -0
- package/dist/config/chat-history.d.ts +9 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/mesh-config.d.ts +77 -1
- package/dist/detection/ide-detector.d.ts +13 -0
- package/dist/detection/win32-ide-version.d.ts +37 -0
- package/dist/git/change-impact-config.d.ts +159 -0
- package/dist/git/git-commands.d.ts +11 -1
- package/dist/git/git-diff.d.ts +6 -0
- package/dist/git/git-executor.d.ts +11 -0
- package/dist/git/git-status.d.ts +23 -0
- package/dist/git/git-types.d.ts +2 -50
- package/dist/git/index.d.ts +2 -0
- package/dist/index.d.ts +52 -13
- package/dist/index.js +42012 -17098
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +41683 -16890
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/ipc/local-ipc-server.d.ts +91 -0
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/logging/log-redactor.d.ts +24 -0
- package/dist/logging/log-tail-reader.d.ts +46 -0
- package/dist/mesh/contracts.d.ts +164 -0
- package/dist/mesh/coordinator-prompt.d.ts +36 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +174 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +169 -0
- package/dist/mesh/mesh-events-pending.d.ts +45 -0
- package/dist/mesh/mesh-events-stale.d.ts +40 -0
- package/dist/mesh/mesh-events-utils.d.ts +66 -0
- package/dist/mesh/mesh-events.d.ts +6 -49
- package/dist/mesh/mesh-fast-forward.d.ts +81 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-init.d.ts +86 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -3
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-missions.d.ts +116 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +7 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -0
- package/dist/mesh/mesh-refine-status.d.ts +62 -0
- package/dist/mesh/mesh-review-inbox.d.ts +90 -0
- package/dist/mesh/mesh-routing.d.ts +70 -0
- package/dist/mesh/mesh-runtime-store.d.ts +418 -0
- package/dist/mesh/mesh-task-stats.d.ts +49 -0
- package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
- package/dist/mesh/mesh-work-queue.d.ts +208 -5
- package/dist/mesh/preview-freshness.d.ts +18 -0
- package/dist/mesh/refine-config.d.ts +216 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
- package/dist/providers/acp-provider-instance.d.ts +2 -0
- package/dist/providers/approval-utils.d.ts +13 -0
- package/dist/providers/chat-message-normalization.d.ts +12 -0
- package/dist/providers/cli-provider-instance.d.ts +76 -3
- package/dist/providers/contracts.d.ts +139 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
- package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
- package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
- package/dist/providers/native-history/dispatcher.d.ts +27 -0
- package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
- package/dist/providers/native-history/index.d.ts +13 -0
- package/dist/providers/provider-instance-manager.d.ts +13 -0
- package/dist/providers/provider-instance.d.ts +13 -1
- package/dist/providers/provider-loader.d.ts +26 -4
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +85 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +69 -0
- package/dist/providers/spec/cli-adapter.d.ts +217 -0
- package/dist/providers/spec/evaluator.d.ts +23 -0
- package/dist/providers/spec/fsm-driver.d.ts +306 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +72 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +144 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +180 -0
- package/dist/providers/status-monitor.d.ts +7 -7
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +84 -0
- package/dist/providers/working-dir.d.ts +17 -0
- package/dist/repo-mesh-types.d.ts +295 -13
- package/dist/sessions/registry.d.ts +6 -0
- package/dist/shared-types-extra.d.ts +2 -4
- package/dist/shared-types.d.ts +59 -2
- package/dist/status/normalize.d.ts +1 -1
- package/dist/status/normalize.js +1 -0
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +1 -0
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/reporter.d.ts +2 -0
- package/dist/status/snapshot.d.ts +26 -0
- package/dist/system/load-better-sqlite3.d.ts +21 -0
- package/dist/types.d.ts +5 -0
- package/package.json +7 -3
- package/src/agent-stream/poller.ts +2 -3
- package/src/agent-stream/provider-adapter.ts +1 -1
- package/src/boot/daemon-lifecycle.ts +55 -12
- package/src/boot/process-hardening.ts +89 -0
- package/src/build-info.ts +73 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +1 -0
- package/src/cli-adapter-types.ts +47 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1215 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +774 -1141
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +13 -0
- package/src/cli-adapters/provider-cli-runtime.ts +56 -7
- package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
- package/src/cli-adapters/provider-cli-shared.ts +100 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +90 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +53 -29
- package/src/cli-adapters/terminal-backends/types.ts +10 -3
- package/src/cli-adapters/terminal-screen.ts +16 -81
- package/src/commands/chat-commands.ts +1823 -62
- package/src/commands/cli-manager.ts +286 -14
- package/src/commands/handler.ts +809 -2
- package/src/commands/mesh-coordinator.ts +332 -122
- package/src/commands/router.ts +7433 -1317
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +81 -30
- package/src/config/chat-history.ts +483 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +388 -6
- package/src/config/recent-activity.ts +8 -2
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/cli-detector.ts +28 -9
- package/src/detection/ide-detector.ts +55 -16
- package/src/detection/win32-ide-version.ts +106 -0
- package/src/git/change-impact-config.ts +354 -0
- package/src/git/git-commands.ts +55 -14
- package/src/git/git-diff.ts +53 -0
- package/src/git/git-executor.ts +12 -0
- package/src/git/git-status.ts +574 -43
- package/src/git/git-types.ts +14 -62
- package/src/git/git-worktree.ts +8 -1
- package/src/git/index.ts +16 -0
- package/src/index.ts +146 -12
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/ipc/local-ipc-server.ts +278 -0
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/log-redactor.ts +100 -0
- package/src/logging/log-tail-reader.ts +220 -0
- package/src/logging/logger.ts +2 -1
- package/src/mesh/contracts.ts +329 -0
- package/src/mesh/coordinator-prompt.ts +234 -31
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +623 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-events-coordinator.ts +2144 -0
- package/src/mesh/mesh-events-pending.ts +508 -0
- package/src/mesh/mesh-events-stale.ts +290 -0
- package/src/mesh/mesh-events-utils.ts +300 -0
- package/src/mesh/mesh-events.ts +30 -1035
- package/src/mesh/mesh-fast-forward.ts +839 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-init.ts +260 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
- package/src/mesh/mesh-ledger.ts +589 -102
- package/src/mesh/mesh-missions.ts +248 -0
- package/src/mesh/mesh-reconcile-loop.ts +822 -0
- package/src/mesh/mesh-refine-batch.ts +197 -0
- package/src/mesh/mesh-refine-status.ts +231 -0
- package/src/mesh/mesh-review-inbox.ts +307 -0
- package/src/mesh/mesh-routing.ts +291 -0
- package/src/mesh/mesh-runtime-store.ts +1626 -0
- package/src/mesh/mesh-task-stats.ts +154 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
- package/src/mesh/mesh-work-queue.ts +888 -141
- package/src/mesh/preview-freshness.ts +118 -0
- package/src/mesh/refine-config.ts +423 -0
- package/src/mesh/worktree-bootstrap-config.ts +331 -0
- package/src/providers/acp-provider-instance.ts +25 -9
- package/src/providers/approval-utils.d.ts +4 -0
- package/src/providers/approval-utils.ts +47 -5
- package/src/providers/chat-message-normalization.ts +45 -5
- package/src/providers/cli-provider-instance.ts +1038 -99
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +150 -6
- package/src/providers/extension-provider-instance.ts +12 -7
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +35 -12
- package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
- package/src/providers/native-history/claude-cli-transcript.ts +396 -0
- package/src/providers/native-history/codex-cli-transcript.ts +479 -0
- package/src/providers/native-history/dispatcher.ts +340 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +30 -0
- package/src/providers/provider-instance.ts +10 -1
- package/src/providers/provider-loader.ts +670 -50
- package/src/providers/provider-schema.ts +87 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +262 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +168 -0
- package/src/providers/spec/cli-adapter.ts +986 -0
- package/src/providers/spec/evaluator.ts +345 -0
- package/src/providers/spec/fsm-driver.ts +1015 -0
- package/src/providers/spec/fsm-evaluator.ts +255 -0
- package/src/providers/spec/fsm-loader.ts +120 -0
- package/src/providers/spec/fsm-types.ts +238 -0
- package/src/providers/spec/native-history-executor.ts +1136 -0
- package/src/providers/spec/pre-launch-trust.ts +104 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/types.ts +226 -0
- package/src/providers/status-monitor.d.ts +7 -7
- package/src/providers/status-monitor.ts +37 -22
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +536 -0
- package/src/providers/version-archive.ts +64 -24
- package/src/providers/working-dir.ts +23 -0
- package/src/repo-mesh-types.ts +378 -14
- package/src/sessions/registry.ts +6 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.d.ts +8 -0
- package/src/shared-types.ts +64 -1
- package/src/status/builders.ts +26 -6
- package/src/status/normalize.ts +2 -0
- package/src/status/reporter.ts +19 -1
- package/src/status/snapshot.ts +95 -26
- package/src/system/host-memory.ts +29 -12
- package/src/system/load-better-sqlite3.ts +68 -0
- package/src/types.ts +5 -0
- package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
- package/src/mesh/mesh-sync.ts +0 -111
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fixture replay runner.
|
|
3
|
+
*
|
|
4
|
+
* Given a `.pty` byte capture and `.expected.json` declaration, replay the
|
|
5
|
+
* bytes through the daemon's TerminalTranscriptAccumulator, invoke the
|
|
6
|
+
* provider handlers at each anchor, and diff against expectations.
|
|
7
|
+
*
|
|
8
|
+
* Used by:
|
|
9
|
+
* - `adhdev provider test` (daemon-cloud CLI)
|
|
10
|
+
* - daemon-core CI suite for production-provider regression tests
|
|
11
|
+
* - external authors as `adhdev provider test ./`
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
import { dirname, resolve } from 'node:path';
|
|
16
|
+
import {
|
|
17
|
+
TerminalTranscriptAccumulator,
|
|
18
|
+
buildCliScreenSnapshot,
|
|
19
|
+
type CliScriptInput as InternalCliScriptInput,
|
|
20
|
+
type CliStatusInput as InternalCliStatusInput,
|
|
21
|
+
type CliApprovalInput as InternalCliApprovalInput,
|
|
22
|
+
type ParsedSession as InternalParsedSession,
|
|
23
|
+
} from '../../../../cli-adapters/provider-cli-shared.js';
|
|
24
|
+
import type {
|
|
25
|
+
CliApprovalModal,
|
|
26
|
+
CliChatMessage,
|
|
27
|
+
CliStatus,
|
|
28
|
+
} from '../types/cli/index.js';
|
|
29
|
+
import type {
|
|
30
|
+
FixtureExpected,
|
|
31
|
+
FixtureAnchor,
|
|
32
|
+
AnchorReplayResult,
|
|
33
|
+
FixtureReplayResult,
|
|
34
|
+
MessageShape,
|
|
35
|
+
} from './format.js';
|
|
36
|
+
|
|
37
|
+
// ─── Provider handler shape (matches the contract) ─────────────────────
|
|
38
|
+
|
|
39
|
+
export interface CliProviderHandlers {
|
|
40
|
+
createState?: () => Record<string, unknown>;
|
|
41
|
+
parseSession: (state: unknown, input: InternalCliScriptInput) => InternalParsedSession;
|
|
42
|
+
detectStatus: (input: InternalCliStatusInput) => string | null;
|
|
43
|
+
parseApproval: (input: InternalCliApprovalInput) => { message: string; buttons: string[] } | null;
|
|
44
|
+
parseOutput?: (state: unknown, input: InternalCliScriptInput) => unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ReplayOptions {
|
|
48
|
+
/** Override accumulator dimensions. Defaults to the fixture's terminal block or 80x24. */
|
|
49
|
+
cols?: number;
|
|
50
|
+
rows?: number;
|
|
51
|
+
/** Provided manually (e.g. by tests). Defaults to wall-clock at replay start. */
|
|
52
|
+
spawnAt?: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ─── Helpers — build the inputs the handlers expect ────────────────────
|
|
56
|
+
|
|
57
|
+
function makeStatusInput(buffer: string, rawBuffer: string): InternalCliStatusInput {
|
|
58
|
+
const tail = buffer.slice(-1000);
|
|
59
|
+
const screenText = buffer;
|
|
60
|
+
return {
|
|
61
|
+
tail,
|
|
62
|
+
screenText,
|
|
63
|
+
rawBuffer,
|
|
64
|
+
isWaitingForResponse: false,
|
|
65
|
+
screen: buildCliScreenSnapshot(screenText),
|
|
66
|
+
tailScreen: buildCliScreenSnapshot(tail),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function makeApprovalInput(buffer: string, rawBuffer: string): InternalCliApprovalInput {
|
|
71
|
+
const tail = buffer.slice(-1000);
|
|
72
|
+
const screenText = buffer;
|
|
73
|
+
return {
|
|
74
|
+
buffer,
|
|
75
|
+
screenText,
|
|
76
|
+
rawBuffer,
|
|
77
|
+
tail,
|
|
78
|
+
screen: buildCliScreenSnapshot(screenText),
|
|
79
|
+
bufferScreen: buildCliScreenSnapshot(buffer),
|
|
80
|
+
tailScreen: buildCliScreenSnapshot(tail),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function makeScriptInput(
|
|
85
|
+
buffer: string,
|
|
86
|
+
rawBuffer: string,
|
|
87
|
+
spawnAt: number,
|
|
88
|
+
): InternalCliScriptInput {
|
|
89
|
+
const recentBuffer = buffer.slice(-1000);
|
|
90
|
+
const screenText = buffer;
|
|
91
|
+
return {
|
|
92
|
+
buffer,
|
|
93
|
+
rawBuffer,
|
|
94
|
+
recentBuffer,
|
|
95
|
+
screenText,
|
|
96
|
+
screen: buildCliScreenSnapshot(screenText),
|
|
97
|
+
bufferScreen: buildCliScreenSnapshot(buffer),
|
|
98
|
+
recentScreen: buildCliScreenSnapshot(recentBuffer),
|
|
99
|
+
messages: [],
|
|
100
|
+
partialResponse: '',
|
|
101
|
+
isWaitingForResponse: false,
|
|
102
|
+
spawnAt,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ─── Anchor stop condition ─────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
function nextStopIndex(anchor: FixtureAnchor, startIdx: number, raw: string): number {
|
|
109
|
+
if (typeof anchor.untilByte === 'number') {
|
|
110
|
+
return Math.min(anchor.untilByte, raw.length);
|
|
111
|
+
}
|
|
112
|
+
if (anchor.untilSentinel) {
|
|
113
|
+
const idx = raw.indexOf(anchor.untilSentinel, startIdx);
|
|
114
|
+
return idx < 0 ? raw.length : idx + anchor.untilSentinel.length;
|
|
115
|
+
}
|
|
116
|
+
// Default: replay everything.
|
|
117
|
+
return raw.length;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ─── Shape matching for messages ───────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
function isShapeArray(input: unknown): input is MessageShape[] {
|
|
123
|
+
if (!Array.isArray(input) || input.length === 0) return false;
|
|
124
|
+
return input.every((m) => {
|
|
125
|
+
if (!m || typeof m !== 'object') return false;
|
|
126
|
+
const keys = Object.keys(m as object);
|
|
127
|
+
// Detect by absence of CliChatMessage-only required fields like `content` typed string.
|
|
128
|
+
return (
|
|
129
|
+
keys.some((k) => k === 'contentIncludes' || k === 'contentMatches') ||
|
|
130
|
+
(keys.includes('role') && !keys.includes('content'))
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function messageMatchesShape(actual: CliChatMessage, shape: MessageShape): string | null {
|
|
136
|
+
if (actual.role !== shape.role) {
|
|
137
|
+
return `role mismatch: expected "${shape.role}", got "${actual.role}"`;
|
|
138
|
+
}
|
|
139
|
+
if (shape.kind && actual.kind && actual.kind !== shape.kind) {
|
|
140
|
+
return `kind mismatch: expected "${shape.kind}", got "${actual.kind}"`;
|
|
141
|
+
}
|
|
142
|
+
const content = typeof actual.content === 'string'
|
|
143
|
+
? actual.content
|
|
144
|
+
: JSON.stringify(actual.content);
|
|
145
|
+
if (shape.contentIncludes && !content.includes(shape.contentIncludes)) {
|
|
146
|
+
return `content missing substring "${shape.contentIncludes.slice(0, 40)}"`;
|
|
147
|
+
}
|
|
148
|
+
if (shape.contentMatches) {
|
|
149
|
+
const re = new RegExp(shape.contentMatches.source, shape.contentMatches.flags ?? '');
|
|
150
|
+
if (!re.test(content)) {
|
|
151
|
+
return `content does not match /${shape.contentMatches.source}/${shape.contentMatches.flags ?? ''}`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ─── Diffing ───────────────────────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
function diffStatus(
|
|
160
|
+
label: string,
|
|
161
|
+
expected: unknown,
|
|
162
|
+
actual: unknown,
|
|
163
|
+
diffs: string[],
|
|
164
|
+
): void {
|
|
165
|
+
if (expected === undefined) return;
|
|
166
|
+
if (expected !== actual) {
|
|
167
|
+
diffs.push(`${label}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function diffModal(
|
|
172
|
+
label: string,
|
|
173
|
+
expected: CliApprovalModal | null | undefined,
|
|
174
|
+
actual: CliApprovalModal | null,
|
|
175
|
+
diffs: string[],
|
|
176
|
+
): void {
|
|
177
|
+
if (expected === undefined) return;
|
|
178
|
+
if (expected === null) {
|
|
179
|
+
if (actual !== null) {
|
|
180
|
+
diffs.push(`${label}: expected null modal, got ${JSON.stringify(actual)}`);
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (actual === null) {
|
|
185
|
+
diffs.push(`${label}: expected modal, got null`);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (expected.message !== actual.message) {
|
|
189
|
+
diffs.push(`${label}.message: expected "${expected.message}", got "${actual.message}"`);
|
|
190
|
+
}
|
|
191
|
+
if (expected.buttons.length !== actual.buttons.length) {
|
|
192
|
+
diffs.push(`${label}.buttons.length: expected ${expected.buttons.length}, got ${actual.buttons.length}`);
|
|
193
|
+
} else {
|
|
194
|
+
for (let i = 0; i < expected.buttons.length; i += 1) {
|
|
195
|
+
if (expected.buttons[i] !== actual.buttons[i]) {
|
|
196
|
+
diffs.push(`${label}.buttons[${i}]: expected "${expected.buttons[i]}", got "${actual.buttons[i]}"`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function diffMessages(
|
|
203
|
+
label: string,
|
|
204
|
+
expected: CliChatMessage[] | MessageShape[] | undefined,
|
|
205
|
+
actual: CliChatMessage[],
|
|
206
|
+
diffs: string[],
|
|
207
|
+
): void {
|
|
208
|
+
if (expected === undefined) return;
|
|
209
|
+
if (expected.length !== actual.length) {
|
|
210
|
+
diffs.push(`${label}.length: expected ${expected.length}, got ${actual.length}`);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (isShapeArray(expected)) {
|
|
214
|
+
for (let i = 0; i < expected.length; i += 1) {
|
|
215
|
+
const reason = messageMatchesShape(actual[i], expected[i] as MessageShape);
|
|
216
|
+
if (reason) diffs.push(`${label}[${i}]: ${reason}`);
|
|
217
|
+
}
|
|
218
|
+
} else {
|
|
219
|
+
for (let i = 0; i < expected.length; i += 1) {
|
|
220
|
+
const e = expected[i] as CliChatMessage;
|
|
221
|
+
const a = actual[i];
|
|
222
|
+
if (e.role !== a.role) diffs.push(`${label}[${i}].role: ${e.role} vs ${a.role}`);
|
|
223
|
+
const ec = typeof e.content === 'string' ? e.content : JSON.stringify(e.content);
|
|
224
|
+
const ac = typeof a.content === 'string' ? a.content : JSON.stringify(a.content);
|
|
225
|
+
if (ec !== ac) diffs.push(`${label}[${i}].content: differs`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ─── Replay one anchor ─────────────────────────────────────────────────
|
|
231
|
+
|
|
232
|
+
function replayAnchor(
|
|
233
|
+
raw: string,
|
|
234
|
+
startIdx: number,
|
|
235
|
+
acc: TerminalTranscriptAccumulator,
|
|
236
|
+
anchor: FixtureAnchor,
|
|
237
|
+
handlers: CliProviderHandlers,
|
|
238
|
+
spawnAt: number,
|
|
239
|
+
): { result: AnchorReplayResult; nextIdx: number } {
|
|
240
|
+
const stop = nextStopIndex(anchor, startIdx, raw);
|
|
241
|
+
const chunk = raw.slice(startIdx, stop);
|
|
242
|
+
const buffer = acc.append(chunk);
|
|
243
|
+
const rawBufferSnapshot = raw.slice(0, stop);
|
|
244
|
+
|
|
245
|
+
const detect = handlers.detectStatus(makeStatusInput(buffer, rawBufferSnapshot));
|
|
246
|
+
const modal = handlers.parseApproval(makeApprovalInput(buffer, rawBufferSnapshot));
|
|
247
|
+
const state = handlers.createState ? handlers.createState() : undefined;
|
|
248
|
+
const session = handlers.parseSession(state, makeScriptInput(buffer, rawBufferSnapshot, spawnAt));
|
|
249
|
+
|
|
250
|
+
const diffs: string[] = [];
|
|
251
|
+
diffStatus('detectStatus', anchor.expect.detectStatus, detect as CliStatus | null, diffs);
|
|
252
|
+
diffModal('parseApproval', anchor.expect.parseApproval, modal, diffs);
|
|
253
|
+
if (anchor.expect.parseSession) {
|
|
254
|
+
diffStatus('parseSession.status', anchor.expect.parseSession.status, session.status as CliStatus, diffs);
|
|
255
|
+
diffModal('parseSession.modal', anchor.expect.parseSession.modal, session.modal as CliApprovalModal | null, diffs);
|
|
256
|
+
if (anchor.expect.parseSession.providerSessionId !== undefined) {
|
|
257
|
+
diffStatus(
|
|
258
|
+
'parseSession.providerSessionId',
|
|
259
|
+
anchor.expect.parseSession.providerSessionId,
|
|
260
|
+
session.providerSessionId,
|
|
261
|
+
diffs,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
diffMessages(
|
|
265
|
+
'parseSession.messages',
|
|
266
|
+
anchor.expect.parseSession.messages,
|
|
267
|
+
session.messages as CliChatMessage[],
|
|
268
|
+
diffs,
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
result: {
|
|
274
|
+
anchor,
|
|
275
|
+
passes: diffs.length === 0,
|
|
276
|
+
diffs,
|
|
277
|
+
actual: {
|
|
278
|
+
detectStatus: detect as CliStatus | null,
|
|
279
|
+
parseApproval: modal,
|
|
280
|
+
parseSession: {
|
|
281
|
+
status: session.status as CliStatus,
|
|
282
|
+
modal: session.modal as CliApprovalModal | null,
|
|
283
|
+
providerSessionId: session.providerSessionId,
|
|
284
|
+
messages: session.messages as CliChatMessage[],
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
nextIdx: stop,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ─── Public API ────────────────────────────────────────────────────────
|
|
293
|
+
|
|
294
|
+
export function loadFixtureExpected(expectedPath: string): FixtureExpected {
|
|
295
|
+
const raw = readFileSync(expectedPath, 'utf-8');
|
|
296
|
+
const parsed = JSON.parse(raw) as FixtureExpected;
|
|
297
|
+
if (parsed.version !== 1) {
|
|
298
|
+
throw new Error(`Fixture format version ${parsed.version} not supported (this runner is v1).`);
|
|
299
|
+
}
|
|
300
|
+
if (!parsed.providerType) throw new Error('Fixture missing providerType');
|
|
301
|
+
if (!parsed.ptyFile) throw new Error('Fixture missing ptyFile');
|
|
302
|
+
if (!Array.isArray(parsed.anchors) || parsed.anchors.length === 0) {
|
|
303
|
+
throw new Error('Fixture must declare at least one anchor');
|
|
304
|
+
}
|
|
305
|
+
return parsed;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function replayFixture(
|
|
309
|
+
expectedPath: string,
|
|
310
|
+
handlers: CliProviderHandlers,
|
|
311
|
+
options: ReplayOptions = {},
|
|
312
|
+
): FixtureReplayResult {
|
|
313
|
+
const expected = loadFixtureExpected(expectedPath);
|
|
314
|
+
const ptyFullPath = resolve(dirname(expectedPath), expected.ptyFile);
|
|
315
|
+
const rawBytes = readFileSync(ptyFullPath, 'utf-8');
|
|
316
|
+
const acc = new TerminalTranscriptAccumulator();
|
|
317
|
+
const spawnAt = options.spawnAt ?? Date.now();
|
|
318
|
+
let idx = 0;
|
|
319
|
+
const perAnchor: AnchorReplayResult[] = [];
|
|
320
|
+
for (const anchor of expected.anchors) {
|
|
321
|
+
const { result, nextIdx } = replayAnchor(rawBytes, idx, acc, anchor, handlers, spawnAt);
|
|
322
|
+
perAnchor.push(result);
|
|
323
|
+
idx = nextIdx;
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
fixturePath: expectedPath,
|
|
327
|
+
expected,
|
|
328
|
+
perAnchor,
|
|
329
|
+
overallPasses: perAnchor.every((a) => a.passes),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Format a result as a human-readable report. Returns the multi-line string;
|
|
335
|
+
* caller decides whether to print or assert.
|
|
336
|
+
*/
|
|
337
|
+
export function formatReplayReport(result: FixtureReplayResult): string {
|
|
338
|
+
const lines: string[] = [];
|
|
339
|
+
lines.push(`Fixture: ${result.fixturePath}`);
|
|
340
|
+
lines.push(`Provider: ${result.expected.providerType}`);
|
|
341
|
+
lines.push(`Anchors: ${result.perAnchor.length}`);
|
|
342
|
+
for (const a of result.perAnchor) {
|
|
343
|
+
if (a.passes) {
|
|
344
|
+
lines.push(` ✓ ${a.anchor.name}`);
|
|
345
|
+
} else {
|
|
346
|
+
lines.push(` ✗ ${a.anchor.name}`);
|
|
347
|
+
for (const d of a.diffs) lines.push(` ${d}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
lines.push(result.overallPasses ? 'OVERALL: PASS' : 'OVERALL: FAIL');
|
|
351
|
+
return lines.join('\n');
|
|
352
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider SDK — v1 surface.
|
|
3
|
+
*
|
|
4
|
+
* Internal consumers (daemon-core) import directly from here.
|
|
5
|
+
* External consumers (provider authors) import from the npm package
|
|
6
|
+
* `@adhdev/provider-types` (Apache 2.0), which is extracted from this
|
|
7
|
+
* source at build time.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export * from './types/cli/index.js';
|
|
11
|
+
export * from './types/common/index.js';
|
|
12
|
+
|
|
13
|
+
// Builders — turn declarative manifest blocks into runtime functions.
|
|
14
|
+
export {
|
|
15
|
+
buildDetectStatusFromTui,
|
|
16
|
+
type DetectStatusTuiSpec,
|
|
17
|
+
} from './builders/cli/detect-status.js';
|
|
18
|
+
export {
|
|
19
|
+
buildParseApprovalFromTui,
|
|
20
|
+
type ModalTuiSpec,
|
|
21
|
+
} from './builders/cli/parse-approval.js';
|
|
22
|
+
export {
|
|
23
|
+
applyVisibleRegion,
|
|
24
|
+
type VisibleRegionSpec,
|
|
25
|
+
} from './builders/cli/visible-region.js';
|
|
26
|
+
export {
|
|
27
|
+
buildParseApprovalFromSquash,
|
|
28
|
+
compactText,
|
|
29
|
+
type ApprovalSquashSpec,
|
|
30
|
+
} from './builders/cli/parse-approval-squash.js';
|
|
31
|
+
export {
|
|
32
|
+
buildParseSessionFromTui,
|
|
33
|
+
normalizeMessageIdentity,
|
|
34
|
+
type ParseSessionTuiSpec,
|
|
35
|
+
type TranscriptPtySpec,
|
|
36
|
+
type SessionIdExtractionSpec,
|
|
37
|
+
type SynthesizedMessage,
|
|
38
|
+
type SynthesizedSession,
|
|
39
|
+
} from './builders/cli/parse-session.js';
|
|
40
|
+
|
|
41
|
+
// ACP builders — declarative stdio session-status detection.
|
|
42
|
+
export {
|
|
43
|
+
buildDetectStatusFromAcp,
|
|
44
|
+
type AcpSessionSpec,
|
|
45
|
+
type AcpStatusInput,
|
|
46
|
+
type AcpDetectedStatus,
|
|
47
|
+
} from './builders/acp/detect-status.js';
|
|
48
|
+
|
|
49
|
+
// Fixture tooling — record/replay for provider regression suites.
|
|
50
|
+
export {
|
|
51
|
+
loadFixtureExpected,
|
|
52
|
+
replayFixture,
|
|
53
|
+
formatReplayReport,
|
|
54
|
+
type FixtureExpected,
|
|
55
|
+
type FixtureAnchor,
|
|
56
|
+
type MessageShape,
|
|
57
|
+
type AnchorReplayResult,
|
|
58
|
+
type FixtureReplayResult,
|
|
59
|
+
type CliProviderHandlers,
|
|
60
|
+
type ReplayOptions,
|
|
61
|
+
} from './fixture-tooling/index.js';
|
|
62
|
+
|
|
63
|
+
// Static validators — used by `adhdev provider validate` + registry publish.
|
|
64
|
+
export {
|
|
65
|
+
analyzeOverrideTaint,
|
|
66
|
+
formatTaintResult,
|
|
67
|
+
type TaintLevel,
|
|
68
|
+
type TaintCategory,
|
|
69
|
+
type TaintFinding,
|
|
70
|
+
type TaintResult,
|
|
71
|
+
validateCliProviderManifest,
|
|
72
|
+
formatManifestValidationIssues,
|
|
73
|
+
type ManifestValidationIssue,
|
|
74
|
+
type ManifestValidationResult,
|
|
75
|
+
} from './validators/index.js';
|
|
76
|
+
|
|
77
|
+
// Primitive identifiers — the canonical list.
|
|
78
|
+
// Implementations live under ./primitives/ and are wired in by builders.
|
|
79
|
+
export const V1_PRIMITIVE_CATALOG = Object.freeze({
|
|
80
|
+
acp: [
|
|
81
|
+
'adhdev:acp/session-protocol@1',
|
|
82
|
+
],
|
|
83
|
+
tui: [
|
|
84
|
+
'adhdev:tui/prompt-marker@1',
|
|
85
|
+
'adhdev:tui/spinner@1',
|
|
86
|
+
'adhdev:tui/settled-prompt@1',
|
|
87
|
+
'adhdev:tui/assistant-block@1',
|
|
88
|
+
'adhdev:tui/tool-block@1',
|
|
89
|
+
'adhdev:tui/thinking-block@1',
|
|
90
|
+
'adhdev:tui/user-echo@1',
|
|
91
|
+
'adhdev:tui/modal@1',
|
|
92
|
+
'adhdev:tui/modal-as-message@1',
|
|
93
|
+
'adhdev:tui/footer-chrome@1',
|
|
94
|
+
'adhdev:tui/welcome-screen@1',
|
|
95
|
+
'adhdev:tui/visible-region@1',
|
|
96
|
+
'adhdev:tui/cue-ordering@1',
|
|
97
|
+
'adhdev:tui/dispatch-order@1',
|
|
98
|
+
'adhdev:tui/index-finder@1',
|
|
99
|
+
'adhdev:tui/status-downgrade@1',
|
|
100
|
+
'adhdev:tui/approval-stitching@1',
|
|
101
|
+
'adhdev:tui/approval-squash@1',
|
|
102
|
+
'adhdev:tui/media-input@1',
|
|
103
|
+
'adhdev:tui/session-id-extraction@1',
|
|
104
|
+
'adhdev:tui/error-detection@1',
|
|
105
|
+
],
|
|
106
|
+
nativeHistory: [
|
|
107
|
+
'adhdev:native-history/codex-rollout@1',
|
|
108
|
+
'adhdev:native-history/claude-jsonl@1',
|
|
109
|
+
'adhdev:native-history/anthropic-cli-transcript@1',
|
|
110
|
+
'adhdev:native-history/hermes-session@1',
|
|
111
|
+
],
|
|
112
|
+
cliCapability: [
|
|
113
|
+
'adhdev:cli/capability-list@1',
|
|
114
|
+
'adhdev:cli/control-state@1',
|
|
115
|
+
'adhdev:cli/capability-action@1',
|
|
116
|
+
'adhdev:cli/control-toggle@1',
|
|
117
|
+
'adhdev:cli/picker-open@1',
|
|
118
|
+
'adhdev:cli/picker-set@1',
|
|
119
|
+
],
|
|
120
|
+
common: [
|
|
121
|
+
'adhdev:common/setting-boolean@1',
|
|
122
|
+
'adhdev:common/setting-number@1',
|
|
123
|
+
'adhdev:common/setting-string@1',
|
|
124
|
+
'adhdev:common/setting-select@1',
|
|
125
|
+
'adhdev:common/capability-input@1',
|
|
126
|
+
'adhdev:common/capability-output@1',
|
|
127
|
+
'adhdev:common/capability-controls@1',
|
|
128
|
+
'adhdev:common/auth-env-var@1',
|
|
129
|
+
'adhdev:common/auth-cli-command@1',
|
|
130
|
+
'adhdev:common/spawn@1',
|
|
131
|
+
'adhdev:common/timeouts@1',
|
|
132
|
+
'adhdev:common/resume@1',
|
|
133
|
+
'adhdev:common/mesh-coordinator@1',
|
|
134
|
+
],
|
|
135
|
+
override: [
|
|
136
|
+
'adhdev:override/cli-parse-session@1',
|
|
137
|
+
'adhdev:override/cli-detect-status@1',
|
|
138
|
+
'adhdev:override/cli-parse-approval@1',
|
|
139
|
+
'adhdev:override/cli-parse-output@1',
|
|
140
|
+
'adhdev:override/cli-read-native-history@1',
|
|
141
|
+
'adhdev:override/cli-list-native-history@1',
|
|
142
|
+
'adhdev:override/cli-capability-handler@1',
|
|
143
|
+
],
|
|
144
|
+
} as const);
|
|
145
|
+
|
|
146
|
+
/** Aggregate flat list — for provider catalog endpoints. */
|
|
147
|
+
export const V1_ALL_PRIMITIVES: ReadonlyArray<string> = Object.freeze(
|
|
148
|
+
Object.values(V1_PRIMITIVE_CATALOG).flat(),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
/** Catalog version label exposed at `registry.adhf.dev/primitives`. */
|
|
152
|
+
export const V1_CONTRACT_VERSION = '1.0.0' as const;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file README-design.ts
|
|
3
|
+
* @description Phase 5 Sandbox Design Document
|
|
4
|
+
*
|
|
5
|
+
* This file is a design document written as TypeScript JSDoc/comments.
|
|
6
|
+
* It is NOT executable — it exists to communicate the sandboxing architecture
|
|
7
|
+
* to future implementors, reviewers, and delegated agents.
|
|
8
|
+
*
|
|
9
|
+
* =============================================================================
|
|
10
|
+
* CONTEXT: EXTENDED-LEGACY PROVIDER SCRIPT EXECUTION (PRE-PHASE-5)
|
|
11
|
+
* =============================================================================
|
|
12
|
+
*
|
|
13
|
+
* "Extended-legacy" providers (e.g. hermes-cli, and any provider using the
|
|
14
|
+
* `compatibility` script format) supply JavaScript override scripts that the
|
|
15
|
+
* daemon loads and calls directly via Node.js `require()`:
|
|
16
|
+
*
|
|
17
|
+
* provider-loader.ts → require(scriptsPath) // load
|
|
18
|
+
* cli-script-runner.ts → this.invoke(fn, input) // call at runtime
|
|
19
|
+
*
|
|
20
|
+
* The loaded module exports plain JS functions (detectStatus, parseApproval,
|
|
21
|
+
* parseSession, etc.). These functions run **in the daemon process with full
|
|
22
|
+
* Node.js access** — no memory cap, no CPU limit, full `require`, `fs`, `net`.
|
|
23
|
+
*
|
|
24
|
+
* The `extended-legacy` label refers to providers that still use the JS-function
|
|
25
|
+
* override layer rather than the pure-declarative `tui` manifest block. The
|
|
26
|
+
* claude-cli provider (scripts/v1/detect_status.js) is the canonical example of
|
|
27
|
+
* this pattern: it delegates to `sdk.declarativeDetectStatus` for the raw verdict
|
|
28
|
+
* but adds a stateful generating-hold on top that cannot be expressed declaratively.
|
|
29
|
+
*
|
|
30
|
+
* =============================================================================
|
|
31
|
+
* PHASE 5 GOAL: isolated-vm SANDBOXING
|
|
32
|
+
* =============================================================================
|
|
33
|
+
*
|
|
34
|
+
* Phase 5 wraps each script call in an isolated-vm context so that:
|
|
35
|
+
*
|
|
36
|
+
* 1. CPU time is capped per call (default 50 ms hard limit).
|
|
37
|
+
* 2. Memory is capped per Isolate (default 32 MB heap limit).
|
|
38
|
+
* 3. The script cannot reach back into the daemon process — no `require`,
|
|
39
|
+
* no `import`, no Node.js built-ins (fs, net, child_process, etc.).
|
|
40
|
+
* 4. Execution errors and timeouts are caught and surfaced cleanly instead
|
|
41
|
+
* of propagating exceptions that could crash the daemon parse loop.
|
|
42
|
+
*
|
|
43
|
+
* =============================================================================
|
|
44
|
+
* SANDBOX EXECUTION MODEL
|
|
45
|
+
* =============================================================================
|
|
46
|
+
*
|
|
47
|
+
* Each call to SandboxedScriptRunner.run() creates a **fresh evaluation context**
|
|
48
|
+
* inside the Isolate. Persistent state across calls (e.g. the `state` object in
|
|
49
|
+
* detectStatus) is cloned in/out of the sandbox via structured serialization.
|
|
50
|
+
*
|
|
51
|
+
* Flow per call:
|
|
52
|
+
*
|
|
53
|
+
* 1. Serialize `context` (input + state) into a plain JSON-safe value.
|
|
54
|
+
* 2. Create a new isolated-vm Context from the shared Isolate.
|
|
55
|
+
* 3. Inject allowed globals (see below) into the context.
|
|
56
|
+
* 4. Compile + run the script string with `cpuTimeLimitMs` enforced.
|
|
57
|
+
* 5. Deserialize and return the result.
|
|
58
|
+
* 6. Discard the Context (short-lived).
|
|
59
|
+
*
|
|
60
|
+
* The Isolate itself is reused across calls so that the V8 JIT and snapshot
|
|
61
|
+
* warm-up cost is paid once per runner instance, not per call.
|
|
62
|
+
*
|
|
63
|
+
* Memory limit (32 MB) applies to the Isolate heap. If a script allocates
|
|
64
|
+
* beyond the limit, isolated-vm throws RangeError: Array buffer allocation
|
|
65
|
+
* failed (or similar). The runner catches this and returns an error signal.
|
|
66
|
+
*
|
|
67
|
+
* CPU time limit (50 ms) is a wall-clock limit on the script execution tick
|
|
68
|
+
* measured by isolated-vm's internal timer. Async operations inside the script
|
|
69
|
+
* are not permitted (the context is synchronous-only).
|
|
70
|
+
*
|
|
71
|
+
* =============================================================================
|
|
72
|
+
* ALLOWED API SURFACE (what scripts CAN use)
|
|
73
|
+
* =============================================================================
|
|
74
|
+
*
|
|
75
|
+
* The following globals are explicitly injected into the sandbox context:
|
|
76
|
+
*
|
|
77
|
+
* - `input` — the calling frame's input object (CliStatusInput, etc.)
|
|
78
|
+
* - `sdk` — a controlled facade object; see sdk shape below
|
|
79
|
+
* - `console.log` — redirected to daemon LOG.debug; console.error/warn also
|
|
80
|
+
* allowed but routed to LOG.warn
|
|
81
|
+
* - `JSON` — standard JSON object (parse + stringify)
|
|
82
|
+
* - `Math` — standard Math object
|
|
83
|
+
* - `Date` — Date constructor (read-only; no timers)
|
|
84
|
+
* - `String`, `Number`, `Boolean`, `Array`, `Object`, `RegExp`
|
|
85
|
+
* — standard constructors
|
|
86
|
+
* - `undefined`, `null`, `NaN`, `Infinity`, `parseInt`, `parseFloat`,
|
|
87
|
+
* `isNaN`, `isFinite`, `encodeURIComponent`, `decodeURIComponent`
|
|
88
|
+
*
|
|
89
|
+
* sdk shape injected into the sandbox:
|
|
90
|
+
*
|
|
91
|
+
* sdk.declarativeDetectStatus(input) → string
|
|
92
|
+
* Calls the daemon-built declarative verdict function. The implementation
|
|
93
|
+
* serializes the call, executes the declarative function in daemon-land,
|
|
94
|
+
* and returns the result string into the sandbox.
|
|
95
|
+
*
|
|
96
|
+
* sdk.tailHasPrimitive(input, primitive) → boolean
|
|
97
|
+
* Returns true if the screen tail contains the named TUI primitive token.
|
|
98
|
+
*
|
|
99
|
+
* sdk.state (object | null)
|
|
100
|
+
* The per-session state object returned by createState(). Mutable inside
|
|
101
|
+
* the script; mutations are copied back after the call completes.
|
|
102
|
+
*
|
|
103
|
+
* =============================================================================
|
|
104
|
+
* FORBIDDEN API SURFACE (what scripts CANNOT use)
|
|
105
|
+
* =============================================================================
|
|
106
|
+
*
|
|
107
|
+
* The sandbox provides NO access to:
|
|
108
|
+
*
|
|
109
|
+
* - `require` / `import` / `module` / `exports` / `__dirname` / `__filename`
|
|
110
|
+
* - `process` (no env, no exit, no stdio)
|
|
111
|
+
* - `fs`, `path`, `os`, `net`, `http`, `https`, `child_process`, `worker_threads`
|
|
112
|
+
* - `setTimeout`, `setInterval`, `setImmediate`, `clearTimeout`, `clearInterval`
|
|
113
|
+
* (async scheduling is blocked; scripts must be synchronous)
|
|
114
|
+
* - `Promise`, `async/await` (not injected; async resolution is disallowed)
|
|
115
|
+
* - `WebAssembly` (not injected)
|
|
116
|
+
* - `Buffer`, `TextEncoder`, `TextDecoder` (not injected by default; can be
|
|
117
|
+
* added to allowedGlobals if a specific script family requires them)
|
|
118
|
+
* - Any daemon-internal module, class, or singleton
|
|
119
|
+
*
|
|
120
|
+
* =============================================================================
|
|
121
|
+
* MIGRATION PATH FOR HERMES-CLI (when Phase 5 lands)
|
|
122
|
+
* =============================================================================
|
|
123
|
+
*
|
|
124
|
+
* hermes-cli (adhdev-providers/cli/hermes-cli) uses the `compatibility` script
|
|
125
|
+
* format with `defaultScriptDir: "scripts/1.0"`. Its scripts are loaded via
|
|
126
|
+
* require() in provider-loader.ts → loadScriptsFromDir() and called via
|
|
127
|
+
* CliScriptRunner.invoke().
|
|
128
|
+
*
|
|
129
|
+
* Phase 5 migration steps:
|
|
130
|
+
*
|
|
131
|
+
* 1. The ProviderLoader detects at load time whether a provider's scriptDir
|
|
132
|
+
* uses the extended-legacy JS override layer (i.e. scripts.js exports
|
|
133
|
+
* function(s) rather than a pure-declarative object).
|
|
134
|
+
*
|
|
135
|
+
* 2. For extended-legacy providers, instead of storing the raw Function
|
|
136
|
+
* references in `normalizedProvider.scripts`, the loader stores the
|
|
137
|
+
* **script source strings** alongside a flag `sandboxed: true`.
|
|
138
|
+
*
|
|
139
|
+
* 3. CliScriptRunner is extended with an optional SandboxedScriptRunner
|
|
140
|
+
* member. When present, invoke() routes script calls through the sandbox
|
|
141
|
+
* instead of calling the function directly.
|
|
142
|
+
*
|
|
143
|
+
* 4. hermes-cli's scripts/1.0/scripts.js is updated (or a scripts/2.0/ dir
|
|
144
|
+
* created) with source strings compatible with the allowed API surface.
|
|
145
|
+
* In particular:
|
|
146
|
+
* - `require` calls must be removed.
|
|
147
|
+
* - Any direct Node.js module access must be replaced with sdk equivalents.
|
|
148
|
+
*
|
|
149
|
+
* 5. The daemon's dev server (port 19280) exposes a /sandbox/test endpoint
|
|
150
|
+
* that accepts a script source string + input and returns the sandboxed
|
|
151
|
+
* result — useful for provider authors to iterate without restarting.
|
|
152
|
+
*
|
|
153
|
+
* 6. Fallback: providers that have not been migrated to the sandbox API still
|
|
154
|
+
* run via DirectEvalRunner (see script-runner.ts) — unsafe but compatible,
|
|
155
|
+
* with a visible deprecation warning in the daemon log.
|
|
156
|
+
*
|
|
157
|
+
* =============================================================================
|
|
158
|
+
* SandboxedScriptRunner INTERFACE (to be satisfied by the Phase 5 implementation)
|
|
159
|
+
* =============================================================================
|
|
160
|
+
*
|
|
161
|
+
* The interface defined in script-runner.ts must be satisfied by two
|
|
162
|
+
* implementations:
|
|
163
|
+
*
|
|
164
|
+
* DirectEvalRunner — no-op stub; runs script via eval() in a try/catch.
|
|
165
|
+
* Used when isolated-vm is not installed or when
|
|
166
|
+
* sandboxing is explicitly disabled for development.
|
|
167
|
+
* Logs a warning on first use.
|
|
168
|
+
* Safe to use in tests (no native dependency).
|
|
169
|
+
*
|
|
170
|
+
* IsolatedVmRunner — full implementation using the `isolated-vm` npm package.
|
|
171
|
+
* Created by createScriptRunner() when isolated-vm is
|
|
172
|
+
* importable. Not committed to the OSS package — loaded
|
|
173
|
+
* dynamically at runtime.
|
|
174
|
+
*
|
|
175
|
+
* Factory function createScriptRunner(options?) returns:
|
|
176
|
+
* - IsolatedVmRunner if `require('isolated-vm')` succeeds
|
|
177
|
+
* - DirectEvalRunner otherwise, with a LOG.warn() deprecation notice
|
|
178
|
+
*
|
|
179
|
+
* =============================================================================
|
|
180
|
+
* FILE LAYOUT (Phase 5 deliverables under this directory)
|
|
181
|
+
* =============================================================================
|
|
182
|
+
*
|
|
183
|
+
* sandbox/
|
|
184
|
+
* README-design.ts ← this file (design document)
|
|
185
|
+
* script-runner.ts ← SandboxedScriptRunner interface + DirectEvalRunner stub
|
|
186
|
+
* isolated-vm-runner.ts ← IsolatedVmRunner (Phase 5 full impl, not yet committed)
|
|
187
|
+
*
|
|
188
|
+
* Related files that will be touched in Phase 5:
|
|
189
|
+
* cli-adapters/cli-script-runner.ts ← add optional SandboxedScriptRunner member
|
|
190
|
+
* providers/provider-loader.ts ← detect extended-legacy, store source strings
|
|
191
|
+
* providers/cli-provider-instance.ts ← TODO comment (already added in Phase 4 scaffold)
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
// This file contains no executable code.
|
|
195
|
+
export {};
|