@adhdev/daemon-core 0.9.82-rc.38 → 0.9.82-rc.380
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 +55 -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 +121 -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 +63 -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 +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/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 +15 -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 +60 -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 +2 -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 +116 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router.d.ts +227 -2
- package/dist/commands/upgrade-helper.d.ts +41 -1
- 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/daemon/dev-server.d.ts +0 -2
- 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 +55 -13
- package/dist/index.js +47229 -19835
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45750 -18490
- 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 +81 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/contracts.d.ts +164 -0
- package/dist/mesh/coordinator-prompt.d.ts +89 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +174 -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 +5 -0
- package/dist/mesh/mesh-event-forwarding.d.ts +18 -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 +55 -0
- package/dist/mesh/mesh-events-stale.d.ts +52 -0
- package/dist/mesh/mesh-events-utils.d.ts +64 -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 -4
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-missions.d.ts +164 -0
- package/dist/mesh/mesh-node-identity.d.ts +289 -0
- package/dist/mesh/mesh-queue-assignment.d.ts +86 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +8 -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 +427 -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 +247 -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 +5 -0
- package/dist/providers/approval-utils.d.ts +20 -0
- package/dist/providers/chat-message-normalization.d.ts +13 -1
- package/dist/providers/cli-provider-instance.d.ts +111 -3
- package/dist/providers/contracts.d.ts +139 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/manual-attendance.d.ts +63 -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/constants.d.ts +12 -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 +14 -0
- package/dist/providers/provider-instance.d.ts +23 -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 +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 +91 -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 +397 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +174 -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 +295 -13
- package/dist/runtime-defaults.d.ts +2 -0
- 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/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 +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 +63 -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 +56 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1221 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +836 -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 +110 -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 +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/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
- package/src/commands/chat-commands-debug-bundle.ts +398 -0
- package/src/commands/chat-commands-read.ts +2327 -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 +880 -0
- package/src/commands/chat-commands.ts +19 -1841
- package/src/commands/cli-manager.ts +513 -26
- package/src/commands/handler.ts +841 -2
- package/src/commands/high-family/index.ts +28 -0
- package/src/commands/high-family/mesh-coordinator-launch.ts +657 -0
- package/src/commands/high-family/mesh-events.ts +47 -0
- package/src/commands/high-family/mesh-status.ts +642 -0
- package/src/commands/high-family/types.ts +76 -0
- package/src/commands/low-family/coordinator-prompt.ts +72 -0
- package/src/commands/low-family/daemon-lifecycle.ts +107 -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 +230 -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 +825 -0
- package/src/commands/med-family/mesh-host-pairing.ts +234 -0
- package/src/commands/med-family/mesh-queue.ts +131 -0
- package/src/commands/med-family/mesh-restart.ts +92 -0
- package/src/commands/med-family/types.ts +120 -0
- package/src/commands/mesh-coordinator.ts +334 -124
- package/src/commands/router.ts +2395 -3206
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +310 -45
- package/src/config/chat-history.ts +483 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +389 -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/daemon/dev-server.ts +0 -541
- 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 +81 -11
- 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 +158 -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/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 +338 -0
- package/src/mesh/coordinator-prompt.ts +379 -31
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +645 -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 +51 -0
- package/src/mesh/mesh-event-forwarding.ts +1559 -0
- package/src/mesh/mesh-event-trace.ts +67 -0
- package/src/mesh/mesh-events-coordinator.ts +30 -0
- package/src/mesh/mesh-events-pending.ts +590 -0
- package/src/mesh/mesh-events-stale.ts +363 -0
- package/src/mesh/mesh-events-utils.ts +425 -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 -7
- package/src/mesh/mesh-ledger.ts +596 -102
- package/src/mesh/mesh-missions.ts +322 -0
- package/src/mesh/mesh-node-identity.ts +1887 -0
- package/src/mesh/mesh-queue-assignment.ts +1491 -0
- package/src/mesh/mesh-reconcile-loop.ts +1332 -0
- package/src/mesh/mesh-refine-batch.ts +197 -0
- package/src/mesh/mesh-refine-gates.ts +1652 -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 +1685 -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 +997 -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 +43 -10
- package/src/providers/approval-utils.d.ts +5 -0
- package/src/providers/approval-utils.ts +57 -5
- package/src/providers/chat-message-normalization.ts +46 -6
- package/src/providers/cli-provider-instance.ts +1416 -101
- 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/manual-attendance.ts +85 -0
- 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/constants.ts +19 -0
- package/src/providers/native-history/dispatcher.ts +339 -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 +19 -1
- package/src/providers/provider-loader.ts +668 -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 +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 +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 +235 -0
- package/src/providers/spec/cli-adapter.ts +1051 -0
- package/src/providers/spec/evaluator.ts +407 -0
- package/src/providers/spec/fsm-driver.ts +1292 -0
- package/src/providers/spec/fsm-evaluator.ts +272 -0
- package/src/providers/spec/fsm-loader.ts +120 -0
- package/src/providers/spec/fsm-types.ts +273 -0
- package/src/providers/spec/native-history-executor.ts +1128 -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 +378 -14
- package/src/runtime-defaults.ts +39 -0
- 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/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,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M7: Operational stats (time/attempts) derived from existing truth.
|
|
3
|
+
*
|
|
4
|
+
* No cost/token accounting — ADHDev observes PTY/CDP and cannot see API
|
|
5
|
+
* tokens (explicit non-goal). Everything here is derived at query time from
|
|
6
|
+
* the SQLite ledger and queue rows; there is no separate aggregate table.
|
|
7
|
+
* Tasks with missing ledger evidence report incompleteEvidence instead of
|
|
8
|
+
* estimated numbers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readLedgerEntries } from './mesh-ledger.js';
|
|
12
|
+
import type { MeshLedgerEntry } from './mesh-ledger.js';
|
|
13
|
+
import { getQueue } from './mesh-work-queue.js';
|
|
14
|
+
|
|
15
|
+
export interface MeshTaskStats {
|
|
16
|
+
taskId: string;
|
|
17
|
+
status: string;
|
|
18
|
+
dispatchedAt: string | null;
|
|
19
|
+
terminalAt: string | null;
|
|
20
|
+
terminalKind: 'task_completed' | 'task_failed' | null;
|
|
21
|
+
/** dispatched → terminal wall clock; null when evidence is incomplete. */
|
|
22
|
+
durationMs: number | null;
|
|
23
|
+
/** Number of task_dispatched ledger entries observed for this task. */
|
|
24
|
+
dispatchCount: number;
|
|
25
|
+
/** Queue requeueCount (0 when the row is gone or never requeued). */
|
|
26
|
+
requeueCount: number;
|
|
27
|
+
/** True when dispatch or terminal ledger evidence is missing — numbers are withheld, never estimated. */
|
|
28
|
+
incompleteEvidence?: true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MeshMissionStats {
|
|
32
|
+
missionId: string;
|
|
33
|
+
taskCount: number;
|
|
34
|
+
completed: number;
|
|
35
|
+
failed: number;
|
|
36
|
+
/** Sum of per-task durations with complete evidence. */
|
|
37
|
+
totalDurationMs: number;
|
|
38
|
+
/** First dispatch → last terminal across the mission's tasks; null without complete endpoints. */
|
|
39
|
+
wallClockMs: number | null;
|
|
40
|
+
/** Total requeue attempts across the mission's tasks. */
|
|
41
|
+
retries: number;
|
|
42
|
+
/** Task ids whose ledger evidence was incomplete (excluded from sums). */
|
|
43
|
+
incompleteTaskIds: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readPayloadTaskId(entry: MeshLedgerEntry): string {
|
|
47
|
+
const value = entry.payload?.taskId;
|
|
48
|
+
return typeof value === 'string' && value.trim() ? value.trim() : '';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function parseTime(value: string | null | undefined): number | null {
|
|
52
|
+
if (!value) return null;
|
|
53
|
+
const parsed = new Date(value).getTime();
|
|
54
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Compute per-task stats from ledger entries. Scans a bounded tail window —
|
|
59
|
+
* stats are an operational view of recent work, not a full historical report.
|
|
60
|
+
*/
|
|
61
|
+
export function computeMeshTaskStats(meshId: string, opts?: { taskIds?: string[]; missionId?: string; tail?: number }): MeshTaskStats[] {
|
|
62
|
+
const queue = getQueue(meshId);
|
|
63
|
+
const queueById = new Map(queue.map(task => [task.id, task]));
|
|
64
|
+
|
|
65
|
+
let targetIds: string[];
|
|
66
|
+
if (opts?.taskIds?.length) {
|
|
67
|
+
targetIds = [...new Set(opts.taskIds)];
|
|
68
|
+
} else if (opts?.missionId) {
|
|
69
|
+
targetIds = queue.filter(task => task.missionId === opts.missionId).map(task => task.id);
|
|
70
|
+
} else {
|
|
71
|
+
targetIds = queue.map(task => task.id);
|
|
72
|
+
}
|
|
73
|
+
if (targetIds.length === 0) return [];
|
|
74
|
+
const targetSet = new Set(targetIds);
|
|
75
|
+
|
|
76
|
+
const entries = readLedgerEntries(meshId, { tail: opts?.tail ?? 1000 });
|
|
77
|
+
const dispatches = new Map<string, { first: string; count: number }>();
|
|
78
|
+
const terminals = new Map<string, { at: string; kind: 'task_completed' | 'task_failed' }>();
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const taskId = readPayloadTaskId(entry);
|
|
81
|
+
if (!taskId || !targetSet.has(taskId)) continue;
|
|
82
|
+
if (entry.kind === 'task_dispatched') {
|
|
83
|
+
const existing = dispatches.get(taskId);
|
|
84
|
+
if (existing) existing.count += 1;
|
|
85
|
+
else dispatches.set(taskId, { first: entry.timestamp, count: 1 });
|
|
86
|
+
} else if (entry.kind === 'task_completed' || entry.kind === 'task_failed') {
|
|
87
|
+
// Last terminal wins (requeued tasks can have multiple terminals).
|
|
88
|
+
terminals.set(taskId, { at: entry.timestamp, kind: entry.kind });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return targetIds.map(taskId => {
|
|
93
|
+
const queueEntry = queueById.get(taskId);
|
|
94
|
+
const dispatch = dispatches.get(taskId);
|
|
95
|
+
const terminal = terminals.get(taskId);
|
|
96
|
+
// Direct dispatches (mesh_send_task) have no work-queue row, so queueEntry is undefined.
|
|
97
|
+
// Derive a terminal status from the attributed terminal ledger entry instead of reporting
|
|
98
|
+
// status='unknown' — without this a completed direct task showed unknown + terminalKind=null
|
|
99
|
+
// even though its task_completed event fired (see mesh-events-coordinator Fix B attribution).
|
|
100
|
+
const status = queueEntry?.status
|
|
101
|
+
?? (terminal
|
|
102
|
+
? (terminal.kind === 'task_completed' ? 'completed' : 'failed')
|
|
103
|
+
: 'unknown');
|
|
104
|
+
const isTerminalStatus = status === 'completed' || status === 'failed' || status === 'cancelled';
|
|
105
|
+
const dispatchTime = parseTime(dispatch?.first ?? queueEntry?.dispatchTimestamp);
|
|
106
|
+
const terminalTime = parseTime(terminal?.at);
|
|
107
|
+
const stats: MeshTaskStats = {
|
|
108
|
+
taskId,
|
|
109
|
+
status,
|
|
110
|
+
dispatchedAt: dispatch?.first ?? queueEntry?.dispatchTimestamp ?? null,
|
|
111
|
+
terminalAt: terminal?.at ?? null,
|
|
112
|
+
terminalKind: terminal?.kind ?? null,
|
|
113
|
+
durationMs: null,
|
|
114
|
+
dispatchCount: dispatch?.count ?? 0,
|
|
115
|
+
requeueCount: queueEntry?.requeueCount ?? 0,
|
|
116
|
+
};
|
|
117
|
+
if (dispatchTime !== null && terminalTime !== null && terminalTime >= dispatchTime) {
|
|
118
|
+
stats.durationMs = terminalTime - dispatchTime;
|
|
119
|
+
} else if (isTerminalStatus) {
|
|
120
|
+
// Terminal task without complete dispatch+terminal ledger evidence:
|
|
121
|
+
// withhold numbers rather than estimate (M7 rule).
|
|
122
|
+
stats.incompleteEvidence = true;
|
|
123
|
+
}
|
|
124
|
+
return stats;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Mission rollup — derived from per-task stats, no stored aggregates. */
|
|
129
|
+
export function computeMeshMissionStats(meshId: string, missionId: string): MeshMissionStats {
|
|
130
|
+
const tasks = computeMeshTaskStats(meshId, { missionId });
|
|
131
|
+
const stats: MeshMissionStats = {
|
|
132
|
+
missionId,
|
|
133
|
+
taskCount: tasks.length,
|
|
134
|
+
completed: 0,
|
|
135
|
+
failed: 0,
|
|
136
|
+
totalDurationMs: 0,
|
|
137
|
+
wallClockMs: null,
|
|
138
|
+
retries: 0,
|
|
139
|
+
incompleteTaskIds: [],
|
|
140
|
+
};
|
|
141
|
+
let firstDispatch: number | null = null;
|
|
142
|
+
let lastTerminal: number | null = null;
|
|
143
|
+
for (const task of tasks) {
|
|
144
|
+
if (task.status === 'completed') stats.completed += 1;
|
|
145
|
+
else if (task.status === 'failed') stats.failed += 1;
|
|
146
|
+
stats.retries += task.requeueCount;
|
|
147
|
+
if (task.incompleteEvidence) {
|
|
148
|
+
stats.incompleteTaskIds.push(task.taskId);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (task.durationMs !== null) stats.totalDurationMs += task.durationMs;
|
|
152
|
+
const dispatchTime = parseTime(task.dispatchedAt);
|
|
153
|
+
const terminalTime = parseTime(task.terminalAt);
|
|
154
|
+
if (dispatchTime !== null && (firstDispatch === null || dispatchTime < firstDispatch)) firstDispatch = dispatchTime;
|
|
155
|
+
if (terminalTime !== null && (lastTerminal === null || terminalTime > lastTerminal)) lastTerminal = terminalTime;
|
|
156
|
+
}
|
|
157
|
+
if (firstDispatch !== null && lastTerminal !== null && lastTerminal >= firstDispatch) {
|
|
158
|
+
stats.wallClockMs = lastTerminal - firstDispatch;
|
|
159
|
+
}
|
|
160
|
+
return stats;
|
|
161
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// mesh-unresolved-forward-outbox — durable retry for unresolved-delegate forwards
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// A REMOTE worker daemon that is P2P-remote-controlled by a coordinator is NOT a
|
|
5
|
+
// member of the coordinator's mesh — it has no local mesh record. So when its
|
|
6
|
+
// completion event reaches setupMeshEventForwarding, resolveWorkerDelegateRouting
|
|
7
|
+
// returns mesh_unresolved: the worker carries the coordinator daemon anchor but no
|
|
8
|
+
// resolvable mesh id, so the normal queue-then-coordinator-pull path can't be used
|
|
9
|
+
// (the coordinator's reconcile PHASE 1 only pulls mesh.nodes, and this worker is in
|
|
10
|
+
// none of them — see docs/refactoring/2026-06-16-mesh-completion-polling-single-model.md).
|
|
11
|
+
//
|
|
12
|
+
// The ONLY delivery route for this case is a directed push to the coordinator
|
|
13
|
+
// daemon (mesh_forward_event over P2P). Previously that push was fire-and-forget:
|
|
14
|
+
// a single dispatchMeshCommand whose rejection was only logged, so one transient
|
|
15
|
+
// P2P failure dropped the completion forever (delivery_unroutable).
|
|
16
|
+
//
|
|
17
|
+
// This outbox makes that push DURABLE without inventing a new persistence layer:
|
|
18
|
+
// it reuses the existing mesh_pending_events SQLite table (the same store every
|
|
19
|
+
// other mesh coordinator event is persisted to), under a synthetic, reserved
|
|
20
|
+
// "mesh id" namespace so it never collides with a real mesh's queue. The worker's
|
|
21
|
+
// reconcile tick (PHASE 0) peeks the outbox, pushes each entry to its coordinator,
|
|
22
|
+
// and marks it drained (acked) ONLY on a successful push — a failed push leaves the
|
|
23
|
+
// row undrained for the next tick. Entries that exceed a max age are expired so the
|
|
24
|
+
// outbox can't grow unbounded when a coordinator stays permanently unreachable.
|
|
25
|
+
//
|
|
26
|
+
// Idempotency:
|
|
27
|
+
// - Enqueue is idempotent on the event fingerprint (mesh_pending_events has a
|
|
28
|
+
// UNIQUE (mesh_id, fingerprint) index + INSERT OR IGNORE), so the same
|
|
29
|
+
// completion fired twice on the worker queues once.
|
|
30
|
+
// - The receiver dedups independently: handleMeshForwardEvent → injectMeshSystemMessage
|
|
31
|
+
// → queuePendingMeshCoordinatorEvent recomputes the fingerprint and suppresses a
|
|
32
|
+
// duplicate, so an at-least-once retry that double-delivers is harmless.
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
import { randomUUID } from 'crypto';
|
|
36
|
+
import { LOG } from '../logging/logger.js';
|
|
37
|
+
import { MeshRuntimeStore } from './mesh-runtime-store.js';
|
|
38
|
+
import { buildPendingEventFingerprint, type PendingMeshCoordinatorEvent } from './mesh-events-pending.js';
|
|
39
|
+
import { readNonEmptyString } from './mesh-events-utils.js';
|
|
40
|
+
|
|
41
|
+
// Reserved synthetic mesh id for the worker-side unresolved-forward outbox. The `::`
|
|
42
|
+
// and leading `__` make it impossible to collide with a real mesh id (which are
|
|
43
|
+
// `mesh_*` / `mreg_*` slugs). Scoping rows by coordinator_daemon_id inside this one
|
|
44
|
+
// namespace lets a single worker forward to multiple coordinators.
|
|
45
|
+
export const UNRESOLVED_FORWARD_OUTBOX_MESH_ID = '__unresolved_forward_outbox__';
|
|
46
|
+
|
|
47
|
+
// Entries older than this are expired (dropped) rather than retried forever — a
|
|
48
|
+
// coordinator that has been unreachable this long is treated as gone. Generous
|
|
49
|
+
// enough to ride out a long coordinator outage / restart, bounded enough that a
|
|
50
|
+
// permanently-dead coordinator can't accumulate outbox rows indefinitely.
|
|
51
|
+
const UNRESOLVED_FORWARD_MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes
|
|
52
|
+
|
|
53
|
+
export interface UnresolvedForwardEntry {
|
|
54
|
+
/** Row id in mesh_pending_events; pass back to ack/expire after a push attempt. */
|
|
55
|
+
id: string;
|
|
56
|
+
/** The coordinator daemon to push this event to (mesh_forward_event target). */
|
|
57
|
+
coordinatorDaemonId: string;
|
|
58
|
+
/** The flat payload to forward (already shaped for handleMeshForwardEvent). */
|
|
59
|
+
payload: Record<string, unknown>;
|
|
60
|
+
/** When the entry was first enqueued (epoch ms) — used for age-based expiry. */
|
|
61
|
+
queuedAt: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getStore(): MeshRuntimeStore | undefined {
|
|
65
|
+
try { return MeshRuntimeStore.getInstance(); } catch { return undefined; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Durably enqueue an unresolved-delegate forward for a coordinator daemon. The
|
|
70
|
+
* `forwardPayload` is the flat shape handleMeshForwardEvent reads on the coordinator.
|
|
71
|
+
* Idempotent on the event fingerprint. Returns true when a new row was written (or a
|
|
72
|
+
* duplicate was harmlessly ignored), false on a hard persistence failure.
|
|
73
|
+
*/
|
|
74
|
+
export function enqueueUnresolvedDelegateForward(
|
|
75
|
+
coordinatorDaemonId: string,
|
|
76
|
+
eventName: string,
|
|
77
|
+
forwardPayload: Record<string, unknown>,
|
|
78
|
+
): boolean {
|
|
79
|
+
const target = readNonEmptyString(coordinatorDaemonId);
|
|
80
|
+
const event = readNonEmptyString(eventName);
|
|
81
|
+
if (!target || !event) return false;
|
|
82
|
+
const store = getStore();
|
|
83
|
+
if (!store) return false;
|
|
84
|
+
|
|
85
|
+
const queuedAt = Date.now();
|
|
86
|
+
// Reuse the standard pending-event fingerprint so enqueue is idempotent AND the
|
|
87
|
+
// receiver's own dedup keys on a comparable identity. We synthesise the minimal
|
|
88
|
+
// PendingMeshCoordinatorEvent shape buildPendingEventFingerprint needs.
|
|
89
|
+
const fingerprintSource: PendingMeshCoordinatorEvent = {
|
|
90
|
+
event,
|
|
91
|
+
meshId: UNRESOLVED_FORWARD_OUTBOX_MESH_ID,
|
|
92
|
+
nodeLabel: readNonEmptyString(forwardPayload.nodeId) || readNonEmptyString(forwardPayload.workspace) || 'unresolved-delegate',
|
|
93
|
+
nodeId: readNonEmptyString(forwardPayload.nodeId) || undefined,
|
|
94
|
+
workspace: readNonEmptyString(forwardPayload.workspace) || undefined,
|
|
95
|
+
metadataEvent: forwardPayload,
|
|
96
|
+
queuedAt,
|
|
97
|
+
targetCoordinatorDaemonId: target,
|
|
98
|
+
};
|
|
99
|
+
// Scope the fingerprint to the coordinator so two coordinators awaiting the same
|
|
100
|
+
// worker session don't collapse into one outbox row.
|
|
101
|
+
const fingerprint = `${target}::${buildPendingEventFingerprint(fingerprintSource)}`;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const inserted = store.insertPendingEvent({
|
|
105
|
+
id: randomUUID(),
|
|
106
|
+
meshId: UNRESOLVED_FORWARD_OUTBOX_MESH_ID,
|
|
107
|
+
coordinatorDaemonId: target,
|
|
108
|
+
event,
|
|
109
|
+
// Store the flat forward payload + the queue timestamp so the retry tick can
|
|
110
|
+
// rebuild the push args and apply age-based expiry without a schema change.
|
|
111
|
+
payload: { forwardPayload, coordinatorDaemonId: target, queuedAt },
|
|
112
|
+
fingerprint,
|
|
113
|
+
queuedAt,
|
|
114
|
+
});
|
|
115
|
+
if (inserted) {
|
|
116
|
+
LOG.info('MeshEvents', `Durably queued unresolved-delegate ${event} for coordinator ${target} (outbox)`);
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
} catch (e: any) {
|
|
120
|
+
LOG.warn('MeshEvents', `Failed to persist unresolved-delegate forward to outbox: ${e?.message || e}`);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Peek (non-destructive) every undrained outbox entry across all coordinators. */
|
|
126
|
+
export function peekUnresolvedDelegateForwards(): UnresolvedForwardEntry[] {
|
|
127
|
+
const store = getStore();
|
|
128
|
+
if (!store) return [];
|
|
129
|
+
let rows: Array<{ id: string; event: string; payload: unknown }>;
|
|
130
|
+
try {
|
|
131
|
+
rows = store.peekPendingEvents(UNRESOLVED_FORWARD_OUTBOX_MESH_ID);
|
|
132
|
+
} catch {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
const out: UnresolvedForwardEntry[] = [];
|
|
136
|
+
for (const row of rows) {
|
|
137
|
+
const stored = row.payload && typeof row.payload === 'object' ? row.payload as Record<string, unknown> : {};
|
|
138
|
+
const coordinatorDaemonId = readNonEmptyString(stored.coordinatorDaemonId);
|
|
139
|
+
const forwardPayload = stored.forwardPayload && typeof stored.forwardPayload === 'object'
|
|
140
|
+
? stored.forwardPayload as Record<string, unknown>
|
|
141
|
+
: undefined;
|
|
142
|
+
if (!coordinatorDaemonId || !forwardPayload) continue;
|
|
143
|
+
const queuedAt = typeof stored.queuedAt === 'number' ? stored.queuedAt : 0;
|
|
144
|
+
out.push({ id: row.id, coordinatorDaemonId, payload: forwardPayload, queuedAt });
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Mark an outbox entry delivered (acked) after a successful push. */
|
|
150
|
+
export function ackUnresolvedDelegateForward(id: string): void {
|
|
151
|
+
const store = getStore();
|
|
152
|
+
if (!store) return;
|
|
153
|
+
try { store.markPendingEventsDrainedById([id]); } catch { /* best-effort */ }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Drop outbox entries that have exceeded the max retry age. Returns the count
|
|
158
|
+
* expired so the caller can log a fail-loud trace (a dropped completion is a real
|
|
159
|
+
* loss; it must be visible, not silent).
|
|
160
|
+
*/
|
|
161
|
+
export function expireStaleUnresolvedDelegateForwards(nowMs: number = Date.now()): number {
|
|
162
|
+
const entries = peekUnresolvedDelegateForwards();
|
|
163
|
+
const staleIds = entries
|
|
164
|
+
.filter(e => e.queuedAt > 0 && nowMs - e.queuedAt >= UNRESOLVED_FORWARD_MAX_AGE_MS)
|
|
165
|
+
.map(e => e.id);
|
|
166
|
+
if (staleIds.length === 0) return 0;
|
|
167
|
+
const store = getStore();
|
|
168
|
+
if (!store) return 0;
|
|
169
|
+
try {
|
|
170
|
+
const removed = store.deletePendingEventsById(staleIds);
|
|
171
|
+
if (removed > 0) {
|
|
172
|
+
LOG.warn('MeshEvents', `Expired ${removed} unresolved-delegate forward(s) after ${Math.round(UNRESOLVED_FORWARD_MAX_AGE_MS / 60000)}m of failed retries — coordinator unreachable, completion dropped`);
|
|
173
|
+
}
|
|
174
|
+
return removed;
|
|
175
|
+
} catch {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Test helper: purge the entire outbox. */
|
|
181
|
+
export function __clearUnresolvedDelegateForwardOutboxForTests(): void {
|
|
182
|
+
const store = getStore();
|
|
183
|
+
if (!store) return;
|
|
184
|
+
try { store.clearPendingEventsForMesh(UNRESOLVED_FORWARD_OUTBOX_MESH_ID); } catch { /* nothing to clear */ }
|
|
185
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// mesh-warmup-deadline — cold-open-aware deadline for mesh P2P dispatches
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// A dependency-free leaf so the warmup deadline + its connection-probe resolution
|
|
5
|
+
// can be shared by BOTH the dashboard git_status probe path (commands/router.ts)
|
|
6
|
+
// and the general task-dispatch path (mesh/mesh-events-coordinator.ts) without an
|
|
7
|
+
// import cycle (router ⇄ mesh-events). Pure except for timers + the injected
|
|
8
|
+
// `isConnected` probe, so it is unit-testable under fake timers with no real WebRTC.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Await `work` under a warmup-aware deadline so a cold-open DataChannel handshake
|
|
13
|
+
* is NOT charged against the command response budget — the root cause of the
|
|
14
|
+
* "first mesh dispatch to a cold peer false-times-out, the warm retry succeeds"
|
|
15
|
+
* signature. Two budgets, switched by the live peer connection state:
|
|
16
|
+
*
|
|
17
|
+
* - While `isConnected()` returns false the peer's channel is still opening; the
|
|
18
|
+
* cold-open `connectTimeoutMs` budget applies. This phase is deliberately
|
|
19
|
+
* generous because a TURN-relayed cross-machine handshake legitimately needs
|
|
20
|
+
* many seconds — but a genuine connect *failure* is surfaced by `work`
|
|
21
|
+
* rejecting on its own (the mesh manager fails the peer the instant its
|
|
22
|
+
* PeerConnection state goes terminal), so a real failure is never masked for
|
|
23
|
+
* the whole window.
|
|
24
|
+
* - The first time `isConnected()` returns true the channel is warm; from that
|
|
25
|
+
* instant the tight `responseTimeoutMs` governs how long the handler may take.
|
|
26
|
+
* Warm-channel callers therefore see behavior identical to the old single
|
|
27
|
+
* `Promise.race(work, responseTimeoutMs)`.
|
|
28
|
+
*
|
|
29
|
+
* Rejects with `Error('timeout')` when either budget is exhausted, mirroring the
|
|
30
|
+
* previous single-race contract. When no connection getter is wired callers must
|
|
31
|
+
* NOT pass `() => true` ("always warm") — that re-introduces the cold-open
|
|
32
|
+
* false-timeout. Use {@link resolveWarmupDeadlineOpts} which degrades conservatively.
|
|
33
|
+
*/
|
|
34
|
+
export function awaitWithWarmupDeadline<T>(
|
|
35
|
+
work: Promise<T>,
|
|
36
|
+
opts: {
|
|
37
|
+
isConnected: () => boolean;
|
|
38
|
+
connectTimeoutMs: number;
|
|
39
|
+
responseTimeoutMs: number;
|
|
40
|
+
pollIntervalMs?: number;
|
|
41
|
+
},
|
|
42
|
+
): Promise<T> {
|
|
43
|
+
const pollMs = Math.max(1, Math.min(opts.pollIntervalMs ?? 200, opts.connectTimeoutMs));
|
|
44
|
+
return new Promise<T>((resolve, reject) => {
|
|
45
|
+
let done = false;
|
|
46
|
+
let poll: ReturnType<typeof setInterval> | undefined;
|
|
47
|
+
let responseTimer: ReturnType<typeof setTimeout> | undefined;
|
|
48
|
+
const startedAt = Date.now();
|
|
49
|
+
const cleanup = () => {
|
|
50
|
+
if (poll) { clearInterval(poll); poll = undefined; }
|
|
51
|
+
if (responseTimer) { clearTimeout(responseTimer); responseTimer = undefined; }
|
|
52
|
+
};
|
|
53
|
+
const settle = (fn: () => void) => {
|
|
54
|
+
if (done) return;
|
|
55
|
+
done = true;
|
|
56
|
+
cleanup();
|
|
57
|
+
fn();
|
|
58
|
+
};
|
|
59
|
+
// Arm the response deadline exactly once, the moment the channel is warm.
|
|
60
|
+
const armResponse = () => {
|
|
61
|
+
if (responseTimer || done) return;
|
|
62
|
+
responseTimer = setTimeout(
|
|
63
|
+
() => settle(() => reject(new Error('timeout'))),
|
|
64
|
+
opts.responseTimeoutMs,
|
|
65
|
+
);
|
|
66
|
+
if (typeof responseTimer.unref === 'function') responseTimer.unref();
|
|
67
|
+
};
|
|
68
|
+
const onPoll = () => {
|
|
69
|
+
if (done) return;
|
|
70
|
+
if (opts.isConnected()) {
|
|
71
|
+
if (poll) { clearInterval(poll); poll = undefined; }
|
|
72
|
+
armResponse();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (Date.now() - startedAt >= opts.connectTimeoutMs) {
|
|
76
|
+
settle(() => reject(new Error('timeout')));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
if (opts.isConnected()) {
|
|
80
|
+
// Already warm (e.g. a retry over an open channel) — skip the warmup
|
|
81
|
+
// phase entirely and let the response deadline govern from t0.
|
|
82
|
+
armResponse();
|
|
83
|
+
} else {
|
|
84
|
+
poll = setInterval(onPoll, pollMs);
|
|
85
|
+
if (typeof poll.unref === 'function') poll.unref();
|
|
86
|
+
}
|
|
87
|
+
work.then(
|
|
88
|
+
(val) => settle(() => resolve(val)),
|
|
89
|
+
(err) => settle(() => reject(err)),
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Minimal connection-state reader: a mesh peer snapshot stamps its live state on `.state`. */
|
|
95
|
+
export function readWarmupConnectionState(connection: Record<string, unknown> | null | undefined): string | undefined {
|
|
96
|
+
const state = (connection as { state?: unknown } | null | undefined)?.state;
|
|
97
|
+
return typeof state === 'string' && state.length > 0 ? state : undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface ResolvedWarmupDeadlineOpts {
|
|
101
|
+
isConnected: () => boolean;
|
|
102
|
+
connectTimeoutMs: number;
|
|
103
|
+
responseTimeoutMs: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Build {@link awaitWithWarmupDeadline} opts from an OPTIONAL live peer-connection
|
|
108
|
+
* probe, handling the missing-getter case fail-loud instead of silently degrading.
|
|
109
|
+
*
|
|
110
|
+
* When `getConnection` is wired the normal cold-open/warm split applies: the probe
|
|
111
|
+
* is consulted live and the channel is "warm" only once it reports `connected`.
|
|
112
|
+
*
|
|
113
|
+
* When `getConnection` is ABSENT the old call sites fell back to `() => true`
|
|
114
|
+
* ("always warm"), which charges a still-opening cold channel against the response
|
|
115
|
+
* budget and silently re-introduces the exact cold-open false-timeout the warmup
|
|
116
|
+
* deadline exists to prevent. Instead we degrade CONSERVATIVELY and FAIL LOUD:
|
|
117
|
+
* - `onMissingGetter` is invoked so the caller can warn (the degrade is visible,
|
|
118
|
+
* never silent) — keyed/throttled by the caller as it sees fit.
|
|
119
|
+
* - the channel is treated as NOT observably warm (`isConnected: () => false`),
|
|
120
|
+
* so the response deadline never arms early on an unobservable channel.
|
|
121
|
+
* - the cold peer is granted the COMBINED connect+response window as one deadline,
|
|
122
|
+
* so a slow-but-live cold open is never false-timed at the shorter response
|
|
123
|
+
* budget. A genuinely hung dispatch still rejects when the combined window
|
|
124
|
+
* lapses, and `work` rejecting on its own (a real transport failure) still
|
|
125
|
+
* settles immediately.
|
|
126
|
+
*
|
|
127
|
+
* Note: a present getter that returns a non-`connected` snapshot (or `null` for an
|
|
128
|
+
* unknown peer) correctly yields `isConnected() === false` — i.e. the generous
|
|
129
|
+
* connect budget, never "always warm". Only a wholly absent getter degrades.
|
|
130
|
+
*/
|
|
131
|
+
export function resolveWarmupDeadlineOpts(opts: {
|
|
132
|
+
getConnection?: ((daemonId: string) => Record<string, unknown> | null) | undefined;
|
|
133
|
+
daemonId: string;
|
|
134
|
+
connectTimeoutMs: number;
|
|
135
|
+
responseTimeoutMs: number;
|
|
136
|
+
onMissingGetter?: (daemonId: string) => void;
|
|
137
|
+
}): ResolvedWarmupDeadlineOpts {
|
|
138
|
+
const { getConnection, daemonId, connectTimeoutMs, responseTimeoutMs } = opts;
|
|
139
|
+
if (getConnection) {
|
|
140
|
+
return {
|
|
141
|
+
isConnected: () => readWarmupConnectionState(getConnection(daemonId)) === 'connected',
|
|
142
|
+
connectTimeoutMs,
|
|
143
|
+
responseTimeoutMs,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
opts.onMissingGetter?.(daemonId);
|
|
147
|
+
return {
|
|
148
|
+
isConnected: () => false,
|
|
149
|
+
connectTimeoutMs: connectTimeoutMs + responseTimeoutMs,
|
|
150
|
+
responseTimeoutMs,
|
|
151
|
+
};
|
|
152
|
+
}
|