@adhdev/daemon-core 0.9.82-rc.46 → 0.9.82-rc.461
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 +9 -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 +68 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +200 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +126 -64
- package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
- package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +69 -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/chat-commands-debug-bundle.d.ts +14 -0
- package/dist/commands/chat-commands-read.d.ts +7 -0
- package/dist/commands/chat-commands-scope.d.ts +39 -0
- package/dist/commands/chat-commands-shared.d.ts +33 -0
- package/dist/commands/chat-commands-write.d.ts +14 -0
- package/dist/commands/chat-commands.d.ts +10 -23
- package/dist/commands/cli-manager.d.ts +25 -1
- package/dist/commands/handler.d.ts +125 -0
- package/dist/commands/high-family/index.d.ts +3 -0
- package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
- package/dist/commands/high-family/mesh-events.d.ts +2 -0
- package/dist/commands/high-family/mesh-status.d.ts +2 -0
- package/dist/commands/high-family/types.d.ts +64 -0
- package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
- package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
- package/dist/commands/low-family/diagnostics.d.ts +2 -0
- package/dist/commands/low-family/index.d.ts +3 -0
- package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
- package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
- package/dist/commands/low-family/notification.d.ts +2 -0
- package/dist/commands/low-family/refine-config.d.ts +2 -0
- package/dist/commands/low-family/session-host.d.ts +2 -0
- package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
- package/dist/commands/low-family/status-meta.d.ts +2 -0
- package/dist/commands/low-family/types.d.ts +33 -0
- package/dist/commands/med-family/cli-agent.d.ts +2 -0
- package/dist/commands/med-family/fast-forward.d.ts +2 -0
- package/dist/commands/med-family/ide.d.ts +10 -0
- package/dist/commands/med-family/index.d.ts +3 -0
- package/dist/commands/med-family/mesh-crud.d.ts +48 -0
- package/dist/commands/med-family/mesh-host-pairing.d.ts +2 -0
- package/dist/commands/med-family/mesh-queue.d.ts +2 -0
- package/dist/commands/med-family/mesh-restart.d.ts +2 -0
- package/dist/commands/med-family/types.d.ts +152 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router-refine.d.ts +137 -0
- package/dist/commands/router-worktree-cleanup.d.ts +133 -0
- package/dist/commands/router.d.ts +241 -12
- package/dist/commands/upgrade-helper.d.ts +41 -1
- package/dist/config/chat-history.d.ts +9 -0
- package/dist/config/config.d.ts +19 -0
- package/dist/config/mesh-config.d.ts +136 -1
- package/dist/config/mesh-json-config.d.ts +199 -0
- package/dist/config/registry-resolver.d.ts +54 -0
- package/dist/config/repo-settings.d.ts +77 -0
- package/dist/daemon/dev-server.d.ts +0 -2
- package/dist/detection/cli-detector.d.ts +17 -0
- 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 +26 -2
- 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 +57 -0
- package/dist/git/git-types.d.ts +2 -50
- package/dist/git/git-worktree.d.ts +71 -1
- package/dist/git/index.d.ts +3 -1
- package/dist/index.d.ts +67 -15
- package/dist/index.js +58583 -25541
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +58207 -25332
- 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/debug-config.d.ts +16 -0
- package/dist/logging/log-redactor.d.ts +24 -0
- package/dist/logging/log-tail-reader.d.ts +81 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/contracts.d.ts +230 -0
- package/dist/mesh/coordinator-prompt.d.ts +76 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +174 -0
- package/dist/mesh/mesh-clone-grace.d.ts +8 -0
- package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-event-classify.d.ts +7 -0
- package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
- package/dist/mesh/mesh-event-trace.d.ts +21 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
- package/dist/mesh/mesh-events-pending.d.ts +155 -0
- package/dist/mesh/mesh-events-stale.d.ts +61 -0
- package/dist/mesh/mesh-events-utils.d.ts +75 -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 +29 -0
- package/dist/mesh/mesh-init.d.ts +128 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
- package/dist/mesh/mesh-ledger.d.ts +133 -1
- package/dist/mesh/mesh-magi-status.d.ts +63 -0
- package/dist/mesh/mesh-missions.d.ts +189 -0
- package/dist/mesh/mesh-node-identity.d.ts +310 -0
- package/dist/mesh/mesh-queue-assignment.d.ts +158 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +80 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -0
- package/dist/mesh/mesh-refine-gates.d.ts +428 -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 +493 -0
- package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
- package/dist/mesh/mesh-task-inflight.d.ts +46 -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-warmup-deadline.d.ts +68 -0
- package/dist/mesh/mesh-work-queue.d.ts +318 -5
- package/dist/mesh/preview-freshness.d.ts +28 -0
- package/dist/mesh/refine-config.d.ts +216 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
- package/dist/providers/acp-provider-instance.d.ts +5 -0
- package/dist/providers/approval-utils.d.ts +45 -0
- package/dist/providers/chat-message-normalization.d.ts +58 -1
- package/dist/providers/cli-provider-instance.d.ts +290 -3
- package/dist/providers/contracts.d.ts +149 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/manual-attendance.d.ts +79 -0
- package/dist/providers/native-history/antigravity-claim-registry.d.ts +28 -0
- package/dist/providers/native-history/antigravity-cli-transcript.d.ts +137 -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/constants.d.ts +12 -0
- package/dist/providers/native-history/dispatcher.d.ts +31 -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 +29 -0
- package/dist/providers/provider-instance.d.ts +30 -1
- package/dist/providers/provider-loader.d.ts +42 -5
- 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 +86 -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 +98 -0
- package/dist/providers/spec/cli-adapter.d.ts +223 -0
- package/dist/providers/spec/evaluator.d.ts +45 -0
- package/dist/providers/spec/fsm-driver.d.ts +449 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +202 -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 +222 -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 +598 -12
- package/dist/runtime-defaults.d.ts +2 -0
- package/dist/session-host/managed-host.d.ts +64 -0
- package/dist/session-host/runtime-surface.d.ts +10 -16
- package/dist/sessions/registry.d.ts +6 -0
- package/dist/shared-types-extra.d.ts +2 -4
- package/dist/shared-types.d.ts +86 -55
- 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/hash.d.ts +8 -0
- package/dist/system/load-better-sqlite3.d.ts +21 -0
- package/dist/types.d.ts +5 -0
- package/package.json +11 -4
- package/src/agent-stream/poller.ts +2 -3
- package/src/agent-stream/provider-adapter.ts +1 -1
- package/src/boot/daemon-lifecycle.ts +80 -14
- 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 +3 -1
- package/src/cli-adapter-types.ts +68 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1246 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
- package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
- package/src/cli-adapters/provider-cli-parse.ts +19 -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 +121 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/pty-write-chunking.ts +106 -0
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +204 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -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-debug-bundle.ts +398 -0
- package/src/commands/chat-commands-read.ts +2488 -0
- package/src/commands/chat-commands-scope.ts +54 -0
- package/src/commands/chat-commands-shared.ts +114 -0
- package/src/commands/chat-commands-write.ts +891 -0
- package/src/commands/chat-commands.ts +19 -1841
- package/src/commands/cli-manager.ts +596 -27
- package/src/commands/handler.ts +845 -2
- package/src/commands/high-family/index.ts +28 -0
- package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
- package/src/commands/high-family/mesh-events.ts +89 -0
- package/src/commands/high-family/mesh-status.ts +832 -0
- package/src/commands/high-family/types.ts +80 -0
- package/src/commands/low-family/coordinator-prompt.ts +72 -0
- package/src/commands/low-family/daemon-lifecycle.ts +120 -0
- package/src/commands/low-family/diagnostics.ts +57 -0
- package/src/commands/low-family/index.ts +37 -0
- package/src/commands/low-family/mesh-ledger.ts +62 -0
- package/src/commands/low-family/mesh-node-logs.ts +87 -0
- package/src/commands/low-family/notification.ts +116 -0
- package/src/commands/low-family/refine-config.ts +106 -0
- package/src/commands/low-family/session-host.ts +274 -0
- package/src/commands/low-family/spec-providerdev.ts +217 -0
- package/src/commands/low-family/status-meta.ts +112 -0
- package/src/commands/low-family/types.ts +39 -0
- package/src/commands/med-family/cli-agent.ts +241 -0
- package/src/commands/med-family/fast-forward.ts +230 -0
- package/src/commands/med-family/ide.ts +163 -0
- package/src/commands/med-family/index.ts +37 -0
- package/src/commands/med-family/mesh-crud.ts +1287 -0
- package/src/commands/med-family/mesh-host-pairing.ts +234 -0
- package/src/commands/med-family/mesh-queue.ts +167 -0
- package/src/commands/med-family/mesh-restart.ts +92 -0
- package/src/commands/med-family/types.ts +153 -0
- package/src/commands/mesh-coordinator.ts +334 -124
- package/src/commands/router-refine.ts +1711 -0
- package/src/commands/router-worktree-cleanup.ts +870 -0
- package/src/commands/router.ts +1025 -4070
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +310 -45
- package/src/config/chat-history.ts +493 -24
- package/src/config/config.ts +30 -0
- package/src/config/mesh-config.ts +632 -23
- package/src/config/mesh-json-config.ts +376 -0
- package/src/config/recent-activity.ts +8 -2
- package/src/config/registry-resolver.ts +100 -0
- package/src/config/repo-settings.ts +111 -0
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/daemon/dev-server.ts +0 -541
- package/src/detection/cli-detector.ts +94 -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 +112 -16
- package/src/git/git-diff.ts +81 -11
- package/src/git/git-executor.ts +12 -0
- package/src/git/git-status.ts +767 -48
- package/src/git/git-types.ts +14 -62
- package/src/git/git-worktree.ts +261 -4
- package/src/git/index.ts +17 -0
- package/src/index.ts +200 -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/command-log.ts +7 -5
- package/src/logging/debug-config.ts +25 -0
- package/src/logging/debug-trace.ts +7 -2
- package/src/logging/log-redactor.ts +100 -0
- package/src/logging/log-tail-reader.ts +341 -0
- package/src/logging/logger.ts +14 -7
- package/src/mesh/contracts.ts +469 -0
- package/src/mesh/coordinator-prompt.ts +554 -34
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +656 -0
- package/src/mesh/mesh-clone-grace.ts +68 -0
- package/src/mesh/mesh-coordinator-config.ts +97 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-event-classify.ts +73 -0
- package/src/mesh/mesh-event-forwarding.ts +1950 -0
- package/src/mesh/mesh-event-trace.ts +67 -0
- package/src/mesh/mesh-events-coordinator.ts +32 -0
- package/src/mesh/mesh-events-pending.ts +1132 -0
- package/src/mesh/mesh-events-stale.ts +440 -0
- package/src/mesh/mesh-events-utils.ts +443 -0
- package/src/mesh/mesh-events.ts +35 -1035
- package/src/mesh/mesh-fast-forward.ts +856 -0
- package/src/mesh/mesh-host-ownership.ts +111 -0
- package/src/mesh/mesh-init.ts +350 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
- package/src/mesh/mesh-ledger.ts +873 -102
- package/src/mesh/mesh-magi-status.ts +223 -0
- package/src/mesh/mesh-missions.ts +449 -0
- package/src/mesh/mesh-node-identity.ts +2065 -0
- package/src/mesh/mesh-queue-assignment.ts +2233 -0
- package/src/mesh/mesh-reconcile-loop.ts +2397 -0
- package/src/mesh/mesh-refine-batch.ts +205 -0
- package/src/mesh/mesh-refine-gates.ts +1686 -0
- package/src/mesh/mesh-refine-status.ts +231 -0
- package/src/mesh/mesh-review-inbox.ts +308 -0
- package/src/mesh/mesh-routing.ts +291 -0
- package/src/mesh/mesh-runtime-store.ts +2056 -0
- package/src/mesh/mesh-scheduling-runtime.ts +198 -0
- package/src/mesh/mesh-task-inflight.ts +70 -0
- package/src/mesh/mesh-task-stats.ts +161 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
- package/src/mesh/mesh-warmup-deadline.ts +152 -0
- package/src/mesh/mesh-work-queue.ts +1281 -141
- package/src/mesh/preview-freshness.ts +163 -0
- package/src/mesh/refine-config.ts +423 -0
- package/src/mesh/worktree-bootstrap-config.ts +599 -0
- package/src/providers/acp-provider-instance.ts +43 -10
- package/src/providers/approval-utils.d.ts +5 -0
- package/src/providers/approval-utils.ts +99 -5
- package/src/providers/chat-message-normalization.ts +126 -4
- package/src/providers/cli-provider-instance.ts +2456 -107
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +160 -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/manual-attendance.ts +105 -0
- package/src/providers/native-history/antigravity-claim-registry.ts +131 -0
- package/src/providers/native-history/antigravity-cli-transcript.ts +1193 -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/constants.ts +19 -0
- package/src/providers/native-history/dispatcher.ts +503 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +260 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +71 -0
- package/src/providers/provider-instance.ts +24 -1
- package/src/providers/provider-loader.ts +700 -55
- 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 +313 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -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 +509 -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 +246 -0
- package/src/providers/spec/cli-adapter.ts +1064 -0
- package/src/providers/spec/evaluator.ts +407 -0
- package/src/providers/spec/fsm-driver.ts +1528 -0
- package/src/providers/spec/fsm-evaluator.ts +290 -0
- package/src/providers/spec/fsm-loader.ts +128 -0
- package/src/providers/spec/fsm-types.ts +301 -0
- package/src/providers/spec/native-history-executor.ts +1174 -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 +262 -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 +836 -13
- package/src/runtime-defaults.ts +39 -0
- package/src/session-host/managed-host.ts +218 -0
- package/src/session-host/runtime-surface.ts +20 -80
- 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 +124 -55
- 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/hash.ts +23 -0
- 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,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 {};
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider script require() whitelist.
|
|
3
|
+
*
|
|
4
|
+
* Provider scripts (detect_status.js, parse_session.js, the override layer
|
|
5
|
+
* the v1 contract exposes, plus their _shared helpers) execute in the
|
|
6
|
+
* daemon process with full Node access — see sandbox/README-design.ts for
|
|
7
|
+
* the long story. Full isolation via isolated-vm has a real perf cost and
|
|
8
|
+
* a real marshalling-complexity cost, so we instead constrain the most
|
|
9
|
+
* dangerous attack surface: what a provider script can `require()`.
|
|
10
|
+
*
|
|
11
|
+
* The hook wraps Node's CJS `Module._load` and, when the calling file is
|
|
12
|
+
* inside a directory that this loader has registered as a provider script
|
|
13
|
+
* root, blocks every module that isn't on the allowlist below. Relative
|
|
14
|
+
* paths are allowed but only when they resolve back inside the same
|
|
15
|
+
* provider root — providers can require their sibling helpers but they
|
|
16
|
+
* can't reach `../../../../etc/passwd` through a clever segment.
|
|
17
|
+
*
|
|
18
|
+
* The hook installs exactly once per process; subsequent `register()` /
|
|
19
|
+
* `unregister()` calls just adjust the set of roots that are gated.
|
|
20
|
+
*
|
|
21
|
+
* Performance: the hook adds one `path.normalize` + one Set lookup to
|
|
22
|
+
* every require call coming from a registered root. At the measured
|
|
23
|
+
* baseline (~6 script invocations / second / session, each making
|
|
24
|
+
* ≤1 require during initial module evaluation, zero during steady-state
|
|
25
|
+
* calls), this is unmeasurable.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import * as path from 'node:path';
|
|
29
|
+
import { createRequire } from 'node:module';
|
|
30
|
+
import * as nodeFs from 'node:fs';
|
|
31
|
+
import * as nodeChildProcess from 'node:child_process';
|
|
32
|
+
import { LOG } from '../../../../logging/logger.js';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Standard library modules a provider script may import unchanged.
|
|
36
|
+
* Each entry is bare ("crypto") and node-prefixed ("node:crypto") so
|
|
37
|
+
* both spellings work; production scripts use a mix of the two.
|
|
38
|
+
*
|
|
39
|
+
* Anything that touches the network, the process tree, or the V8 isolate
|
|
40
|
+
* is intentionally absent. fs and child_process are NOT here; they're
|
|
41
|
+
* exposed via the shims further down with a reduced surface.
|
|
42
|
+
*/
|
|
43
|
+
const SAFE_STDLIB = new Set<string>([
|
|
44
|
+
'path', 'os', 'util', 'url', 'querystring', 'buffer',
|
|
45
|
+
'events', 'stream', 'string_decoder', 'assert',
|
|
46
|
+
'crypto', 'timers', 'punycode', 'zlib',
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Standard library modules that need a shim — we expose a deliberately
|
|
51
|
+
* narrowed surface and trap everything else.
|
|
52
|
+
*/
|
|
53
|
+
const SHIMMED_STDLIB = new Set<string>(['fs', 'child_process', 'process']);
|
|
54
|
+
|
|
55
|
+
const ALL_GATED_STDLIB = new Set<string>([
|
|
56
|
+
...SAFE_STDLIB,
|
|
57
|
+
...SHIMMED_STDLIB,
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
/** Strip an optional `node:` prefix for bookkeeping. */
|
|
61
|
+
function normalizeModuleName(request: string): string {
|
|
62
|
+
return request.startsWith('node:') ? request.slice(5) : request;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ─── fs shim — read-only surface ────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The set of `fs` members provider scripts are allowed to call. Each is
|
|
69
|
+
* a read-only operation on the local filesystem. Anything that writes,
|
|
70
|
+
* deletes, opens for write, or alters file metadata is omitted.
|
|
71
|
+
*
|
|
72
|
+
* We expose the *real* function reference so behavior is identical to
|
|
73
|
+
* `require('fs')` for the operations that do pass — including streaming
|
|
74
|
+
* iterators, error semantics, and {withFileTypes}-style overloads.
|
|
75
|
+
*/
|
|
76
|
+
const FS_READ_ONLY_MEMBERS = [
|
|
77
|
+
'existsSync', 'statSync', 'lstatSync', 'realpathSync',
|
|
78
|
+
'readFileSync', 'readdirSync', 'readlinkSync',
|
|
79
|
+
'accessSync', 'constants',
|
|
80
|
+
// Async equivalents — same read-only set.
|
|
81
|
+
'exists', 'stat', 'lstat', 'realpath',
|
|
82
|
+
'readFile', 'readdir', 'readlink', 'access',
|
|
83
|
+
// Allow `fs.promises.{readFile,...}` for the modern async style.
|
|
84
|
+
'promises',
|
|
85
|
+
] as const;
|
|
86
|
+
|
|
87
|
+
const FS_PROMISES_READ_ONLY_MEMBERS = [
|
|
88
|
+
'stat', 'lstat', 'realpath', 'readFile', 'readdir', 'readlink', 'access',
|
|
89
|
+
] as const;
|
|
90
|
+
|
|
91
|
+
function buildFsShim(): typeof nodeFs {
|
|
92
|
+
const shim: any = {};
|
|
93
|
+
for (const key of FS_READ_ONLY_MEMBERS) {
|
|
94
|
+
if (key === 'promises') continue; // handled below
|
|
95
|
+
const real = (nodeFs as any)[key];
|
|
96
|
+
if (real !== undefined) shim[key] = real;
|
|
97
|
+
}
|
|
98
|
+
// Re-build a minimal `promises` namespace so destructuring works.
|
|
99
|
+
const realPromises = (nodeFs as any).promises || {};
|
|
100
|
+
const promisesShim: any = {};
|
|
101
|
+
for (const key of FS_PROMISES_READ_ONLY_MEMBERS) {
|
|
102
|
+
const real = realPromises[key];
|
|
103
|
+
if (real !== undefined) promisesShim[key] = real;
|
|
104
|
+
}
|
|
105
|
+
shim.promises = promisesShim;
|
|
106
|
+
return shim as typeof nodeFs;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const FS_SHIM = Object.freeze(buildFsShim());
|
|
110
|
+
|
|
111
|
+
// ─── child_process shim — execFileSync only ─────────────────────────────────
|
|
112
|
+
|
|
113
|
+
interface NarrowedExecFileSyncOptions {
|
|
114
|
+
cwd?: string;
|
|
115
|
+
timeout?: number;
|
|
116
|
+
encoding?: BufferEncoding | 'buffer';
|
|
117
|
+
maxBuffer?: number;
|
|
118
|
+
input?: string | Buffer | NodeJS.ArrayBufferView;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* `child_process.execFileSync(file, args, opts)` wrapper that strips
|
|
123
|
+
* every option a provider script has no business setting — most
|
|
124
|
+
* importantly `shell`, which would otherwise re-introduce arbitrary
|
|
125
|
+
* command injection. `args` must be a string array; `file` is a
|
|
126
|
+
* single binary name or absolute path; `opts` is narrowed to the
|
|
127
|
+
* fields below.
|
|
128
|
+
*
|
|
129
|
+
* `spawn`, `exec`, `execSync`, `fork` are intentionally absent from
|
|
130
|
+
* the shim. Providers that need them should ship a daemon-side
|
|
131
|
+
* capability instead of running raw subprocesses out of their script.
|
|
132
|
+
*/
|
|
133
|
+
function shimmedExecFileSync(
|
|
134
|
+
file: unknown,
|
|
135
|
+
args?: unknown,
|
|
136
|
+
options?: unknown,
|
|
137
|
+
): Buffer | string {
|
|
138
|
+
if (typeof file !== 'string' || file.length === 0) {
|
|
139
|
+
throw new TypeError('execFileSync: `file` must be a non-empty string');
|
|
140
|
+
}
|
|
141
|
+
let safeArgs: string[] = [];
|
|
142
|
+
if (args !== undefined && args !== null) {
|
|
143
|
+
if (!Array.isArray(args) || !args.every((a) => typeof a === 'string')) {
|
|
144
|
+
throw new TypeError('execFileSync: `args` must be a string[] (no shell expansion).');
|
|
145
|
+
}
|
|
146
|
+
safeArgs = args as string[];
|
|
147
|
+
}
|
|
148
|
+
const safeOpts: NarrowedExecFileSyncOptions = {};
|
|
149
|
+
if (options && typeof options === 'object') {
|
|
150
|
+
const o = options as Record<string, unknown>;
|
|
151
|
+
if (typeof o.cwd === 'string') safeOpts.cwd = o.cwd;
|
|
152
|
+
if (typeof o.timeout === 'number') safeOpts.timeout = o.timeout;
|
|
153
|
+
if (typeof o.encoding === 'string') safeOpts.encoding = o.encoding as BufferEncoding;
|
|
154
|
+
if (typeof o.maxBuffer === 'number') safeOpts.maxBuffer = o.maxBuffer;
|
|
155
|
+
if (typeof o.input === 'string' || o.input instanceof Buffer) {
|
|
156
|
+
safeOpts.input = o.input as any;
|
|
157
|
+
}
|
|
158
|
+
// shell / env / uid / gid / detached / windowsHide / killSignal — all dropped.
|
|
159
|
+
}
|
|
160
|
+
return nodeChildProcess.execFileSync(file, safeArgs, safeOpts as any);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const CHILD_PROCESS_SHIM = Object.freeze({
|
|
164
|
+
execFileSync: shimmedExecFileSync,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// ─── process shim — block lifecycle/abort/native bridges ────────────────────
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* The methods on `globalThis.process` that a provider script must NEVER be
|
|
171
|
+
* able to call. `exit`/`kill`/`abort` would terminate the daemon; `binding`
|
|
172
|
+
* and `dlopen` are escape hatches that re-introduce arbitrary native code
|
|
173
|
+
* (the whole reason the require() whitelist exists in the first place).
|
|
174
|
+
*/
|
|
175
|
+
const DANGEROUS_PROCESS_METHODS = new Set<string>([
|
|
176
|
+
'exit', 'kill', 'abort', 'binding', 'dlopen', '_kill', '_exit',
|
|
177
|
+
'reallyExit', '_fatalException',
|
|
178
|
+
]);
|
|
179
|
+
|
|
180
|
+
let _processGloballyHardened = false;
|
|
181
|
+
let _originalProcessMethods: Map<string, unknown> | null = null;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Decide whether the current call stack passes through a registered provider
|
|
185
|
+
* script root. We use `new Error().stack` (cheaper than `Error.captureStackTrace`
|
|
186
|
+
* for hot paths because we never need a frame object). The stack string format
|
|
187
|
+
* is `at <fn> (<filename>:line:col)` per frame; we scan for any registered
|
|
188
|
+
* provider root substring. This is best-effort: a determined attacker who
|
|
189
|
+
* controls a non-provider module loaded BY a provider could escape this, but
|
|
190
|
+
* the require() whitelist already prevents loading such modules.
|
|
191
|
+
*/
|
|
192
|
+
function callStackTouchesProviderRoot(): boolean {
|
|
193
|
+
if (_gatedRoots.length === 0) return false;
|
|
194
|
+
const stack = new Error().stack || '';
|
|
195
|
+
for (const root of _gatedRoots) {
|
|
196
|
+
if (stack.includes(root.rootPath)) return true;
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Wrap `globalThis.process` methods so calls from provider script stacks
|
|
203
|
+
* throw, while every other caller (daemon-core itself, npm deps, the test
|
|
204
|
+
* harness) goes through untouched.
|
|
205
|
+
*
|
|
206
|
+
* Trade-off: this is a stack-introspection check on every call to the
|
|
207
|
+
* affected methods. The methods in question (exit/kill/abort/binding/dlopen)
|
|
208
|
+
* are not hot paths — they're either never called or called once at
|
|
209
|
+
* shutdown. The cost is negligible.
|
|
210
|
+
*
|
|
211
|
+
* Alternative considered: wrap only the module-scope `process` binding via
|
|
212
|
+
* Module._extensions. Node's ESM/CJS semantics make this unreliable across
|
|
213
|
+
* dynamic-require paths. Stack introspection is uglier but correct.
|
|
214
|
+
*
|
|
215
|
+
* Caveat: a provider script that grabs `globalThis.process.exit` once and
|
|
216
|
+
* passes the reference to a non-provider callback can still escape — the
|
|
217
|
+
* stack at the actual call site no longer goes through provider code. We
|
|
218
|
+
* accept this gap; the threat model assumes scripts are not actively
|
|
219
|
+
* trying to launder calls through arbitrary daemon callbacks, just that
|
|
220
|
+
* a naive `process.exit(0)` should not silently terminate the daemon.
|
|
221
|
+
*/
|
|
222
|
+
export function installProviderProcessShim(): void {
|
|
223
|
+
if (_processGloballyHardened) return;
|
|
224
|
+
_processGloballyHardened = true;
|
|
225
|
+
const proc = globalThis.process as unknown as Record<string, unknown>;
|
|
226
|
+
if (!proc) return;
|
|
227
|
+
_originalProcessMethods = new Map();
|
|
228
|
+
for (const name of DANGEROUS_PROCESS_METHODS) {
|
|
229
|
+
const original = proc[name];
|
|
230
|
+
if (typeof original !== 'function') continue;
|
|
231
|
+
_originalProcessMethods.set(name, original);
|
|
232
|
+
const wrapped = function gatedProcessMethod(this: unknown, ...args: unknown[]): unknown {
|
|
233
|
+
if (callStackTouchesProviderRoot()) {
|
|
234
|
+
const err: any = new Error(
|
|
235
|
+
`process.${name}() denied: provider scripts cannot terminate, signal, or extend the daemon process.`,
|
|
236
|
+
);
|
|
237
|
+
err.code = 'PROVIDER_PROCESS_DENIED';
|
|
238
|
+
err.method = name;
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
return (original as (...a: unknown[]) => unknown).apply(this, args);
|
|
242
|
+
};
|
|
243
|
+
try {
|
|
244
|
+
// Preserve `.name` for stack traces / debugging tools.
|
|
245
|
+
Object.defineProperty(wrapped, 'name', { value: name, configurable: true });
|
|
246
|
+
proc[name] = wrapped;
|
|
247
|
+
} catch {
|
|
248
|
+
// Some Node builds mark certain process.* members non-writable.
|
|
249
|
+
// Skip silently; the require('process') gate still applies.
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** For tests — restore the original process.* methods. */
|
|
255
|
+
export function _uninstallProviderProcessShimForTest(): void {
|
|
256
|
+
if (!_originalProcessMethods) {
|
|
257
|
+
_processGloballyHardened = false;
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const proc = globalThis.process as unknown as Record<string, unknown>;
|
|
261
|
+
for (const [name, original] of _originalProcessMethods) {
|
|
262
|
+
try { proc[name] = original; } catch { /* noop */ }
|
|
263
|
+
}
|
|
264
|
+
_originalProcessMethods = null;
|
|
265
|
+
_processGloballyHardened = false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Build the `process` shim returned to provider scripts that do
|
|
270
|
+
* `require('process')`. Same surface as `globalThis.process` minus the
|
|
271
|
+
* dangerous methods, which are replaced with throwers regardless of caller
|
|
272
|
+
* (because they got here via the whitelist — caller is definitively a
|
|
273
|
+
* provider script).
|
|
274
|
+
*/
|
|
275
|
+
function buildProcessShim(): NodeJS.Process {
|
|
276
|
+
const real = globalThis.process;
|
|
277
|
+
const shim: Record<string, unknown> = Object.create(null);
|
|
278
|
+
for (const key of Object.keys(real) as Array<keyof NodeJS.Process>) {
|
|
279
|
+
if (DANGEROUS_PROCESS_METHODS.has(String(key))) continue;
|
|
280
|
+
try { shim[key as string] = (real as any)[key]; } catch { /* noop */ }
|
|
281
|
+
}
|
|
282
|
+
for (const name of DANGEROUS_PROCESS_METHODS) {
|
|
283
|
+
shim[name] = function blockedProcessMethod(): never {
|
|
284
|
+
const err: any = new Error(
|
|
285
|
+
`process.${name}() denied via require('process'): provider scripts cannot terminate, signal, or extend the daemon.`,
|
|
286
|
+
);
|
|
287
|
+
err.code = 'PROVIDER_PROCESS_DENIED';
|
|
288
|
+
err.method = name;
|
|
289
|
+
throw err;
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return Object.freeze(shim) as unknown as NodeJS.Process;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const PROCESS_SHIM = buildProcessShim();
|
|
296
|
+
|
|
297
|
+
// ─── Hook installation ─────────────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
interface GatedRoot {
|
|
300
|
+
/** Normalized, realpath-resolved absolute path. */
|
|
301
|
+
rootPath: string;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const _gatedRoots: GatedRoot[] = [];
|
|
305
|
+
let _installed = false;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Register a directory whose `.js` files should be subject to the
|
|
309
|
+
* whitelist when they call require(). Idempotent — repeated registration
|
|
310
|
+
* of the same root is a no-op. Pass the same string back to
|
|
311
|
+
* `unregisterProviderScriptRoot` to remove it.
|
|
312
|
+
*/
|
|
313
|
+
export function registerProviderScriptRoot(absRoot: string): void {
|
|
314
|
+
const normalized = canonicalize(absRoot);
|
|
315
|
+
if (!normalized) return;
|
|
316
|
+
if (_gatedRoots.some((g) => g.rootPath === normalized)) return;
|
|
317
|
+
_gatedRoots.push({ rootPath: normalized });
|
|
318
|
+
ensureInstalled();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** Inverse of registerProviderScriptRoot. */
|
|
322
|
+
export function unregisterProviderScriptRoot(absRoot: string): void {
|
|
323
|
+
const normalized = canonicalize(absRoot);
|
|
324
|
+
if (!normalized) return;
|
|
325
|
+
const idx = _gatedRoots.findIndex((g) => g.rootPath === normalized);
|
|
326
|
+
if (idx >= 0) _gatedRoots.splice(idx, 1);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** For tests — drop every registration and reset internal state. */
|
|
330
|
+
export function _resetProviderScriptRoots(): void {
|
|
331
|
+
_gatedRoots.length = 0;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** For tests — peek at the gated root list. */
|
|
335
|
+
export function _getRegisteredRoots(): readonly string[] {
|
|
336
|
+
return _gatedRoots.map((g) => g.rootPath);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function canonicalize(p: string): string | null {
|
|
340
|
+
try {
|
|
341
|
+
const resolved = path.resolve(p);
|
|
342
|
+
try {
|
|
343
|
+
return nodeFs.realpathSync.native
|
|
344
|
+
? nodeFs.realpathSync.native(resolved)
|
|
345
|
+
: nodeFs.realpathSync(resolved);
|
|
346
|
+
} catch {
|
|
347
|
+
// Root may not exist yet (e.g. external dir created lazily);
|
|
348
|
+
// we still register the resolved path so future requires from
|
|
349
|
+
// inside are gated once the directory shows up.
|
|
350
|
+
return resolved;
|
|
351
|
+
}
|
|
352
|
+
} catch {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function isCallerInsideGatedRoot(callerFilename: string): GatedRoot | null {
|
|
358
|
+
if (!callerFilename) return null;
|
|
359
|
+
let normalized: string;
|
|
360
|
+
try { normalized = canonicalize(callerFilename) || callerFilename; } catch { normalized = callerFilename; }
|
|
361
|
+
for (const root of _gatedRoots) {
|
|
362
|
+
if (normalized === root.rootPath) return root;
|
|
363
|
+
if (normalized.startsWith(root.rootPath + path.sep)) return root;
|
|
364
|
+
}
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Wrap Module._load exactly once. Subsequent calls to register/unregister
|
|
370
|
+
* just adjust the set of roots — the hook itself stays installed.
|
|
371
|
+
*/
|
|
372
|
+
function ensureInstalled(): void {
|
|
373
|
+
if (_installed) return;
|
|
374
|
+
_installed = true;
|
|
375
|
+
|
|
376
|
+
// CJS-only hook. ESM provider scripts are not currently supported
|
|
377
|
+
// (everything in adhdev-providers/ is CJS), so we don't need a
|
|
378
|
+
// matching `module.register()` ESM loader. If/when we accept ESM
|
|
379
|
+
// provider scripts, this hook becomes a no-op for them and we'll
|
|
380
|
+
// need to extend it.
|
|
381
|
+
const Module = require('module') as any;
|
|
382
|
+
const originalLoad = Module._load as (
|
|
383
|
+
request: string,
|
|
384
|
+
parent: NodeJS.Module | null,
|
|
385
|
+
isMain: boolean,
|
|
386
|
+
) => unknown;
|
|
387
|
+
|
|
388
|
+
Module._load = function gatedLoad(
|
|
389
|
+
this: unknown,
|
|
390
|
+
request: string,
|
|
391
|
+
parent: NodeJS.Module | null,
|
|
392
|
+
isMain: boolean,
|
|
393
|
+
): unknown {
|
|
394
|
+
const callerFilename = parent?.filename || '';
|
|
395
|
+
const gated = isCallerInsideGatedRoot(callerFilename);
|
|
396
|
+
if (!gated) {
|
|
397
|
+
// Caller is not provider code — bypass the gate entirely so
|
|
398
|
+
// daemon-core, vendored npm modules, etc. work as before.
|
|
399
|
+
return originalLoad.call(this, request, parent, isMain);
|
|
400
|
+
}
|
|
401
|
+
return gatedRequire.call(this, request, parent, isMain, gated, originalLoad);
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* The actual gate. Runs only when the caller lives inside a registered
|
|
407
|
+
* provider script root. `this` is forwarded from Module._load so
|
|
408
|
+
* delegating to originalLoad mirrors Node's own semantics.
|
|
409
|
+
*/
|
|
410
|
+
function gatedRequire(
|
|
411
|
+
this: unknown,
|
|
412
|
+
request: string,
|
|
413
|
+
parent: NodeJS.Module | null,
|
|
414
|
+
isMain: boolean,
|
|
415
|
+
gated: GatedRoot,
|
|
416
|
+
originalLoad: (this: unknown, request: string, parent: NodeJS.Module | null, isMain: boolean) => unknown,
|
|
417
|
+
): unknown {
|
|
418
|
+
// 1. Relative imports — must stay inside the same provider root.
|
|
419
|
+
if (request.startsWith('./') || request.startsWith('../') || path.isAbsolute(request)) {
|
|
420
|
+
let resolved: string;
|
|
421
|
+
try {
|
|
422
|
+
// Reuse the caller's require to mirror Node's resolution rules.
|
|
423
|
+
const callerRequire = parent?.filename ? createRequire(parent.filename) : createRequire(path.join(gated.rootPath, '__entry__.js'));
|
|
424
|
+
resolved = callerRequire.resolve(request);
|
|
425
|
+
} catch {
|
|
426
|
+
// Fall through to the regular loader; it will throw the
|
|
427
|
+
// standard MODULE_NOT_FOUND with the same path Node would.
|
|
428
|
+
return originalLoad.call(this, request, parent, isMain);
|
|
429
|
+
}
|
|
430
|
+
const resolvedCanon = canonicalize(resolved) || resolved;
|
|
431
|
+
if (!(resolvedCanon === gated.rootPath || resolvedCanon.startsWith(gated.rootPath + path.sep))) {
|
|
432
|
+
denyRequire(request, parent, `relative path escapes provider root (resolved to ${resolvedCanon})`);
|
|
433
|
+
}
|
|
434
|
+
// Inside the root — let it through. The hook will gate any
|
|
435
|
+
// subsequent require() calls made by the loaded file too.
|
|
436
|
+
return originalLoad.call(this, request, parent, isMain);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// 2. Bare specifier — only the stdlib subset is allowed.
|
|
440
|
+
const normalized = normalizeModuleName(request);
|
|
441
|
+
if (!ALL_GATED_STDLIB.has(normalized)) {
|
|
442
|
+
denyRequire(request, parent, 'module not on the provider script whitelist');
|
|
443
|
+
}
|
|
444
|
+
if (normalized === 'fs') return FS_SHIM;
|
|
445
|
+
if (normalized === 'child_process') return CHILD_PROCESS_SHIM;
|
|
446
|
+
if (normalized === 'process') return PROCESS_SHIM;
|
|
447
|
+
// SAFE_STDLIB — pass through.
|
|
448
|
+
return originalLoad.call(this, request, parent, isMain);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function denyRequire(request: string, parent: NodeJS.Module | null, reason: string): never {
|
|
452
|
+
const caller = parent?.filename || '<unknown>';
|
|
453
|
+
const message = `Provider script require('${request}') denied: ${reason}. Caller: ${caller}`;
|
|
454
|
+
LOG.warn('ProviderScript', `[require-whitelist] ${message}`);
|
|
455
|
+
const err: any = new Error(message);
|
|
456
|
+
err.code = 'PROVIDER_REQUIRE_DENIED';
|
|
457
|
+
err.deniedModule = request;
|
|
458
|
+
err.callerFilename = caller;
|
|
459
|
+
throw err;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Public re-exports — registry consumers want to know what's on the
|
|
464
|
+
* allowlist without parsing this file.
|
|
465
|
+
*/
|
|
466
|
+
export const PROVIDER_REQUIRE_POLICY = Object.freeze({
|
|
467
|
+
safeStdlib: Array.from(SAFE_STDLIB).sort(),
|
|
468
|
+
shimmedStdlib: Array.from(SHIMMED_STDLIB).sort(),
|
|
469
|
+
fsAllowedMembers: Array.from(FS_READ_ONLY_MEMBERS),
|
|
470
|
+
childProcessAllowedMembers: ['execFileSync'],
|
|
471
|
+
processDeniedMembers: Array.from(DANGEROUS_PROCESS_METHODS).sort(),
|
|
472
|
+
});
|