@adhdev/daemon-core 0.9.82-rc.49 → 0.9.82-rc.491
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 +220 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +137 -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 +23 -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 +71 -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-aggregate-status.d.ts +24 -0
- package/dist/commands/router-mesh-session-owner.d.ts +59 -0
- package/dist/commands/router-refine.d.ts +151 -0
- package/dist/commands/router-worktree-cleanup.d.ts +133 -0
- package/dist/commands/router.d.ts +203 -15
- package/dist/commands/upgrade-helper.d.ts +41 -1
- package/dist/config/chat-history.d.ts +11 -0
- package/dist/config/config.d.ts +19 -0
- package/dist/config/mesh-config.d.ts +66 -0
- 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/config/state-store.d.ts +30 -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 +80 -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 +70 -17
- package/dist/index.js +53556 -19074
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +53380 -19063
- 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 +256 -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 +203 -0
- package/dist/mesh/mesh-clone-grace.d.ts +8 -0
- package/dist/mesh/mesh-completion-synthesis.d.ts +4 -0
- package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +104 -0
- package/dist/mesh/mesh-event-classify.d.ts +7 -0
- package/dist/mesh/mesh-event-forwarding.d.ts +58 -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 +258 -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 +21 -1
- 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 +139 -1
- package/dist/mesh/mesh-magi-status.d.ts +63 -0
- package/dist/mesh/mesh-missions.d.ts +281 -0
- package/dist/mesh/mesh-node-identity.d.ts +310 -0
- package/dist/mesh/mesh-queue-assignment.d.ts +162 -0
- package/dist/mesh/mesh-reconcile-acked-hold.d.ts +17 -0
- package/dist/mesh/mesh-reconcile-config.d.ts +6 -0
- package/dist/mesh/mesh-reconcile-identity.d.ts +6 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +84 -0
- package/dist/mesh/mesh-reconcile-v2-backstop.d.ts +16 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -0
- package/dist/mesh/mesh-refine-gates.d.ts +457 -0
- package/dist/mesh/mesh-refine-status.d.ts +62 -0
- package/dist/mesh/mesh-remote-event-pull.d.ts +15 -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 +567 -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 +34 -0
- package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
- package/dist/mesh/mesh-work-queue.d.ts +392 -1
- package/dist/mesh/preview-freshness.d.ts +28 -0
- package/dist/mesh/refine-config.d.ts +97 -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 +46 -0
- package/dist/providers/chat-message-normalization.d.ts +58 -1
- package/dist/providers/cli-provider-effect-format.d.ts +30 -0
- package/dist/providers/cli-provider-history-dedup.d.ts +17 -0
- package/dist/providers/cli-provider-input-prompt.d.ts +12 -0
- package/dist/providers/cli-provider-instance-types.d.ts +45 -0
- package/dist/providers/cli-provider-instance.d.ts +426 -30
- package/dist/providers/cli-provider-status-helpers.d.ts +46 -0
- package/dist/providers/cli-provider-transcript-merge.d.ts +7 -0
- package/dist/providers/contracts.d.ts +196 -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 +39 -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 +44 -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 +30 -0
- package/dist/providers/provider-instance.d.ts +31 -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 +244 -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 +616 -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 +26 -0
- package/dist/shared-types-extra.d.ts +2 -4
- package/dist/shared-types.d.ts +110 -55
- package/dist/status/chat-tail-hot-sessions.d.ts +40 -0
- 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 +27 -0
- package/dist/system/hash.d.ts +8 -0
- package/dist/system/load-better-sqlite3.d.ts +21 -0
- package/dist/types.d.ts +20 -6
- 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 +1282 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +1048 -1143
- 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 +2788 -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.d.ts +2 -0
- package/src/commands/cli-manager.ts +724 -27
- package/src/commands/handler.ts +865 -2
- package/src/commands/high-family/index.ts +28 -0
- package/src/commands/high-family/mesh-coordinator-launch.ts +696 -0
- package/src/commands/high-family/mesh-events.ts +102 -0
- package/src/commands/high-family/mesh-status.ts +857 -0
- package/src/commands/high-family/types.ts +80 -0
- package/src/commands/low-family/coordinator-prompt.ts +125 -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 +282 -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 +270 -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 +1309 -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-aggregate-status.ts +209 -0
- package/src/commands/router-mesh-session-owner.ts +114 -0
- package/src/commands/router-refine.ts +1794 -0
- package/src/commands/router-worktree-cleanup.ts +870 -0
- package/src/commands/router.ts +567 -4149
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +310 -45
- package/src/config/chat-history.ts +517 -24
- package/src/config/config.ts +30 -0
- package/src/config/mesh-config.ts +300 -24
- 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/config/state-store.ts +55 -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 +822 -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 +190 -13
- 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 +510 -0
- package/src/mesh/coordinator-prompt.ts +627 -34
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +706 -0
- package/src/mesh/mesh-clone-grace.ts +68 -0
- package/src/mesh/mesh-completion-synthesis.ts +416 -0
- package/src/mesh/mesh-coordinator-config.ts +97 -0
- package/src/mesh/mesh-delivery-policy.ts +284 -0
- package/src/mesh/mesh-event-classify.ts +78 -0
- package/src/mesh/mesh-event-forwarding.ts +2030 -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 +1548 -0
- package/src/mesh/mesh-events-stale.ts +452 -0
- package/src/mesh/mesh-events-utils.ts +443 -0
- package/src/mesh/mesh-events.ts +43 -1035
- package/src/mesh/mesh-fast-forward.ts +856 -0
- package/src/mesh/mesh-host-ownership.ts +41 -3
- package/src/mesh/mesh-init.ts +350 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
- package/src/mesh/mesh-ledger.ts +897 -102
- package/src/mesh/mesh-magi-status.ts +223 -0
- package/src/mesh/mesh-missions.ts +695 -0
- package/src/mesh/mesh-node-identity.ts +2065 -0
- package/src/mesh/mesh-queue-assignment.ts +2498 -0
- package/src/mesh/mesh-reconcile-acked-hold.ts +230 -0
- package/src/mesh/mesh-reconcile-config.ts +66 -0
- package/src/mesh/mesh-reconcile-identity.ts +103 -0
- package/src/mesh/mesh-reconcile-loop.ts +1696 -0
- package/src/mesh/mesh-reconcile-v2-backstop.ts +62 -0
- package/src/mesh/mesh-refine-batch.ts +205 -0
- package/src/mesh/mesh-refine-gates.ts +1792 -0
- package/src/mesh/mesh-refine-status.ts +231 -0
- package/src/mesh/mesh-remote-event-pull.ts +279 -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 +2292 -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 +215 -0
- package/src/mesh/mesh-warmup-deadline.ts +152 -0
- package/src/mesh/mesh-work-queue.ts +1489 -145
- package/src/mesh/preview-freshness.ts +163 -0
- package/src/mesh/refine-config.ts +129 -12
- 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 +100 -6
- package/src/providers/chat-message-normalization.ts +126 -4
- package/src/providers/cli-provider-effect-format.ts +53 -0
- package/src/providers/cli-provider-history-dedup.ts +75 -0
- package/src/providers/cli-provider-input-prompt.ts +133 -0
- package/src/providers/cli-provider-instance-types.ts +131 -0
- package/src/providers/cli-provider-instance.ts +2771 -499
- package/src/providers/cli-provider-status-helpers.ts +123 -0
- package/src/providers/cli-provider-transcript-merge.ts +114 -0
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +207 -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 +138 -0
- package/src/providers/native-history/antigravity-cli-transcript.ts +1275 -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 +617 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +312 -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 +93 -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 +538 -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 +1241 -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 +284 -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 +861 -14
- 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 +44 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.d.ts +8 -0
- package/src/shared-types.ts +148 -55
- package/src/status/builders.ts +69 -6
- package/src/status/chat-tail-hot-sessions.ts +117 -2
- package/src/status/normalize.ts +2 -0
- package/src/status/reporter.ts +19 -1
- package/src/status/snapshot.ts +100 -27
- 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 +26 -6
- 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,68 @@
|
|
|
1
|
+
import { normalizeMeshNodeId, type MeshNodeIdentified } from '@adhdev/mesh-shared';
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Recently-cloned worktree node grace window
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// FALSE-BLOCKER-CLONE-QUEUE: right after mesh_clone_node registers a worktree node, a
|
|
7
|
+
// queue task pinned to that node id (target_node pin) can transiently find NO matching
|
|
8
|
+
// node in the coordinator-owning daemon's mesh view, because:
|
|
9
|
+
// - the clone wrote the node ONLY into the inline mesh cache (med-family clone branch),
|
|
10
|
+
// and that inline entry has not yet PROPAGATED to the coordinator daemon (the clone
|
|
11
|
+
// may have run on the source node's machine and forwarded), and/or
|
|
12
|
+
// - the node's worktree bootstrap (npm install / native-addon repair) is still running,
|
|
13
|
+
// so the claim gate defers anyway.
|
|
14
|
+
// In BOTH cases the unmatch SELF-RESOLVES within ~seconds (observed bootstrap ~2m8s) — it
|
|
15
|
+
// is NOT the permanent `target_node_id_unmatched` routing miss (a removed/dead node) that
|
|
16
|
+
// the actionable-blocker coordinator notification exists for. This registry lets the skip
|
|
17
|
+
// classifier tell the transient case apart from the permanent one: a node id recorded here
|
|
18
|
+
// (within the grace TTL) is a freshly cloned worktree whose unmatch should be reported as a
|
|
19
|
+
// transient, NON-actionable skip rather than paging the coordinator with a false
|
|
20
|
+
// "will NOT clear on its own" blocker.
|
|
21
|
+
//
|
|
22
|
+
// The window is floored well above the observed clone + bootstrap + inline-cache
|
|
23
|
+
// propagation latency so a slow-but-live clone is never misclassified as a permanent
|
|
24
|
+
// unmatch. A genuinely dead/removed node is never recorded here (or its entry has long
|
|
25
|
+
// expired), so its `target_node_id_unmatched` stays correctly actionable.
|
|
26
|
+
export const CLONE_BOOTSTRAP_GRACE_MS = 10 * 60 * 1000;
|
|
27
|
+
|
|
28
|
+
const recentlyClonedNodeExpiry = new Map<string, number>(); // normalized nodeId -> expiry epoch ms
|
|
29
|
+
const MAX_TRACKED_CLONED_NODES = 512;
|
|
30
|
+
|
|
31
|
+
function normalizeNodeIdKey(nodeId: string | undefined | null): string {
|
|
32
|
+
return normalizeMeshNodeId({ id: nodeId ?? undefined } as MeshNodeIdentified) ?? '';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Record that a worktree node id was just cloned, opening its transient grace window. */
|
|
36
|
+
export function noteRecentlyClonedNode(nodeId: string | undefined | null, nowMs: number = Date.now()): void {
|
|
37
|
+
const key = normalizeNodeIdKey(nodeId);
|
|
38
|
+
if (!key) return;
|
|
39
|
+
recentlyClonedNodeExpiry.set(key, nowMs + CLONE_BOOTSTRAP_GRACE_MS);
|
|
40
|
+
if (recentlyClonedNodeExpiry.size > MAX_TRACKED_CLONED_NODES) {
|
|
41
|
+
// Map iteration is insertion-ordered; the first key is the oldest-inserted entry.
|
|
42
|
+
const oldest = recentlyClonedNodeExpiry.keys().next().value;
|
|
43
|
+
if (oldest !== undefined) recentlyClonedNodeExpiry.delete(oldest);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** True when nodeId was cloned within the grace window (and the entry has not expired). */
|
|
48
|
+
export function isWithinCloneBootstrapGrace(nodeId: string | undefined | null, nowMs: number = Date.now()): boolean {
|
|
49
|
+
const key = normalizeNodeIdKey(nodeId);
|
|
50
|
+
if (!key) return false;
|
|
51
|
+
const expiry = recentlyClonedNodeExpiry.get(key);
|
|
52
|
+
if (expiry === undefined) return false;
|
|
53
|
+
if (nowMs >= expiry) {
|
|
54
|
+
recentlyClonedNodeExpiry.delete(key);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Drop a node's grace entry (e.g. once it has fully resolved into the mesh view). */
|
|
61
|
+
export function clearCloneBootstrapGrace(nodeId: string | undefined | null): void {
|
|
62
|
+
const key = normalizeNodeIdKey(nodeId);
|
|
63
|
+
if (key) recentlyClonedNodeExpiry.delete(key);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function __resetCloneBootstrapGraceForTests(): void {
|
|
67
|
+
recentlyClonedNodeExpiry.clear();
|
|
68
|
+
}
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// mesh-completion-synthesis — PHASE-4 transcript completion synth + PHASE-5 auto-prune
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Extracted from mesh-reconcile-loop.ts (A-3 god-module decomposition, pure move,
|
|
5
|
+
// no behavior change). This is the reconcile loop's completion-synthesis core:
|
|
6
|
+
// for every active (non-terminal) direct dispatch this daemon hosts, confirm the
|
|
7
|
+
// worker session is idle and — when a final assistant summary exists but no
|
|
8
|
+
// terminal ledger does — synthesize the missing completion (the acked-hold /
|
|
9
|
+
// death-backstop / fast-track machinery lives here). PHASE-5 auto-prune of orphaned
|
|
10
|
+
// dispatch records rides along, sharing the same live-session probe transports.
|
|
11
|
+
//
|
|
12
|
+
// Depends on mesh-remote-event-pull.ts for the P2P read/probe helpers
|
|
13
|
+
// (unwrapReadChatPayload, readChatPayloadStatus, reprobeWorkerStatus,
|
|
14
|
+
// realTerminalEmitPendingForTask, collectLiveNodesWithSessions). The reconcile
|
|
15
|
+
// loop imports reconcileUnterminatedDirectDispatches + autoPruneStaleDirectDispatches.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
import type { DaemonComponents } from '../boot/daemon-lifecycle.js';
|
|
19
|
+
import type { LocalMeshEntry } from '../repo-mesh-types.js';
|
|
20
|
+
import { LOG } from '../logging/logger.js';
|
|
21
|
+
import { readNonEmptyString } from './mesh-events-utils.js';
|
|
22
|
+
import { traceMeshEventDrop } from './mesh-event-trace.js';
|
|
23
|
+
import { daemonIdsEquivalent } from '@adhdev/mesh-shared';
|
|
24
|
+
import { daemonIdListIncludes } from './mesh-reconcile-identity.js';
|
|
25
|
+
import { getActiveDirectDispatches, getQueue } from './mesh-work-queue.js';
|
|
26
|
+
import { readLedgerEntries } from './mesh-ledger.js';
|
|
27
|
+
import { pruneStaleDirectDispatches } from './mesh-active-work.js';
|
|
28
|
+
import { reconcileDirectDispatchCompletionFromTranscript } from './mesh-events-stale.js';
|
|
29
|
+
import { extractFinalAssistantSummaryEvidence } from '../providers/chat-message-normalization.js';
|
|
30
|
+
import type { ChatMessage } from '../types.js';
|
|
31
|
+
import {
|
|
32
|
+
getMeshV2BackstopCounters,
|
|
33
|
+
recordBackstopFire,
|
|
34
|
+
} from './mesh-reconcile-v2-backstop.js';
|
|
35
|
+
import {
|
|
36
|
+
ACKED_DEATH_CONSECUTIVE_READ_FAILURES,
|
|
37
|
+
resolveAckedDeathDeadlineMs,
|
|
38
|
+
resolveAckedTranscriptFastTrackGraceMs,
|
|
39
|
+
inFlightSynthKey,
|
|
40
|
+
getHoldState,
|
|
41
|
+
setHoldState,
|
|
42
|
+
deleteHoldState,
|
|
43
|
+
rehydrateAckedHoldsForMesh,
|
|
44
|
+
collectHeldSynthKeysForMesh,
|
|
45
|
+
} from './mesh-reconcile-acked-hold.js';
|
|
46
|
+
import {
|
|
47
|
+
unwrapReadChatPayload,
|
|
48
|
+
readChatPayloadStatus,
|
|
49
|
+
reprobeWorkerStatus,
|
|
50
|
+
realTerminalEmitPendingForTask,
|
|
51
|
+
collectLiveNodesWithSessions,
|
|
52
|
+
} from './mesh-remote-event-pull.js';
|
|
53
|
+
|
|
54
|
+
// PHASE 4 helper. For every active (non-terminal) direct dispatch this daemon
|
|
55
|
+
// hosts, confirm the worker session is idle via a read_chat and — if a final
|
|
56
|
+
// assistant summary is present but no terminal ledger exists for that dispatch —
|
|
57
|
+
// synthesize the missing completion through reconcileDirectDispatchCompletionFromTranscript.
|
|
58
|
+
//
|
|
59
|
+
// read_chat is resolved against the target node: a node on THIS daemon is read
|
|
60
|
+
// through the local commandHandler; a remote node is read over P2P via
|
|
61
|
+
// dispatchMeshCommand. Both yield the same { messages, status, providerSessionId }
|
|
62
|
+
// shape. We only synthesize when the session reports idle AND a final assistant
|
|
63
|
+
// message exists — the same evidence bar the MCP poll path uses — so an actively
|
|
64
|
+
// generating worker is never falsely completed. The reconcile itself is idempotent.
|
|
65
|
+
export async function reconcileUnterminatedDirectDispatches(
|
|
66
|
+
components: DaemonComponents,
|
|
67
|
+
mesh: LocalMeshEntry,
|
|
68
|
+
selfIds: string[],
|
|
69
|
+
localDaemonId: string | undefined,
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
const dispatches = getActiveDirectDispatches(mesh.id);
|
|
72
|
+
|
|
73
|
+
// T2 (B2b): restart rehydration. Reload this mesh's persisted acked-hold rows into
|
|
74
|
+
// the Map cache the first time this process touches the mesh — a hold established
|
|
75
|
+
// before a daemon restart is honored again. Must run BEFORE the prune below so a
|
|
76
|
+
// rehydrated hold for a still-active task is not seen as absent-from-cache and lost.
|
|
77
|
+
rehydrateAckedHoldsForMesh(mesh.id);
|
|
78
|
+
|
|
79
|
+
// Prune the in-flight acked-hold state to the tasks still active in THIS mesh, so a
|
|
80
|
+
// completed/pruned task's state is dropped (both the Map cache AND the store row —
|
|
81
|
+
// the persisted table never grows without bound). Runs even when there are zero
|
|
82
|
+
// active dispatches so a restart that landed after every task terminated still
|
|
83
|
+
// reaps orphaned store rows. Iterate the union of Map keys and store rows so a row
|
|
84
|
+
// that exists ONLY on disk (not yet cached) is pruned too.
|
|
85
|
+
const activeTaskKeys = new Set(
|
|
86
|
+
dispatches
|
|
87
|
+
.map(d => readNonEmptyString(d.taskId))
|
|
88
|
+
.filter(Boolean)
|
|
89
|
+
.map(taskId => inFlightSynthKey(mesh.id, taskId)),
|
|
90
|
+
);
|
|
91
|
+
const heldKeys = collectHeldSynthKeysForMesh(mesh.id);
|
|
92
|
+
for (const key of heldKeys) {
|
|
93
|
+
if (!activeTaskKeys.has(key)) deleteHoldState(key, mesh.id);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (dispatches.length === 0) return; // nothing left to reconcile after the prune
|
|
97
|
+
|
|
98
|
+
const dispatchMeshCommand = components.dispatchMeshCommand;
|
|
99
|
+
const nodeById = new Map(mesh.nodes.map(n => [n.id, n] as const));
|
|
100
|
+
|
|
101
|
+
for (const dispatch of dispatches) {
|
|
102
|
+
const sessionId = readNonEmptyString(dispatch.sessionId);
|
|
103
|
+
const nodeId = readNonEmptyString(dispatch.nodeId);
|
|
104
|
+
const taskId = readNonEmptyString(dispatch.taskId);
|
|
105
|
+
if (!sessionId || !nodeId || !taskId) continue;
|
|
106
|
+
|
|
107
|
+
const node = nodeById.get(nodeId);
|
|
108
|
+
const nodeDaemonId = readNonEmptyString(node?.daemonId);
|
|
109
|
+
// A node is local when it has no daemonId, names this daemon, or actually
|
|
110
|
+
// has a live instance here. Anything else is reached over P2P.
|
|
111
|
+
const isLocalNode = !nodeDaemonId
|
|
112
|
+
|| daemonIdListIncludes(selfIds, nodeDaemonId)
|
|
113
|
+
|| daemonIdsEquivalent(nodeDaemonId, localDaemonId)
|
|
114
|
+
|| !!components.instanceManager.getInstance(sessionId);
|
|
115
|
+
|
|
116
|
+
const providerType = readNonEmptyString(dispatch.providerType);
|
|
117
|
+
const readArgs: Record<string, unknown> = {
|
|
118
|
+
sessionId,
|
|
119
|
+
targetSessionId: sessionId,
|
|
120
|
+
tailLimit: 10,
|
|
121
|
+
...(node?.workspace ? { workspace: node.workspace } : {}),
|
|
122
|
+
...(providerType ? { agentType: providerType, providerType } : {}),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const synthKey = inFlightSynthKey(mesh.id, taskId);
|
|
126
|
+
const isAcked = dispatch.status === 'acked';
|
|
127
|
+
// T6: which last-resort backstop (if any) drove this synth. Set when the
|
|
128
|
+
// acked-hold fast-track / death-deadline promotes the synth; the counter is
|
|
129
|
+
// bumped only if the synth actually COMMITS (result.reconciled), so a
|
|
130
|
+
// deferred/re-probed-away synth is not miscounted. A never-acked dispatch
|
|
131
|
+
// that reaches the commit is a plain PHASE-4 transcript synthesis.
|
|
132
|
+
let backstopKind: keyof ReturnType<typeof getMeshV2BackstopCounters> | undefined;
|
|
133
|
+
|
|
134
|
+
// R4f: read the worker session. A FAILED read (transport error / success:false / no payload)
|
|
135
|
+
// is no longer silently swallowed for an acked task — it is the liveness side of the
|
|
136
|
+
// death backstop (a). We classify the read result and route an acked failure into the
|
|
137
|
+
// failure counter; a never-acked (or non-acked) failure keeps the old best-effort `continue`.
|
|
138
|
+
let payload: Record<string, unknown> | null = null;
|
|
139
|
+
let readFailed = false;
|
|
140
|
+
try {
|
|
141
|
+
if (isLocalNode) {
|
|
142
|
+
const result = await components.commandHandler.handle('read_chat', readArgs);
|
|
143
|
+
if (result && (result as { success?: boolean }).success === false) {
|
|
144
|
+
readFailed = true;
|
|
145
|
+
} else {
|
|
146
|
+
payload = unwrapReadChatPayload(result);
|
|
147
|
+
}
|
|
148
|
+
} else if (dispatchMeshCommand) {
|
|
149
|
+
const result = await dispatchMeshCommand(nodeDaemonId, 'read_chat', readArgs);
|
|
150
|
+
payload = unwrapReadChatPayload(result);
|
|
151
|
+
if (payload && (payload as { success?: boolean }).success === false) { payload = null; readFailed = true; }
|
|
152
|
+
} else {
|
|
153
|
+
continue; // remote node but no P2P transport — can't read; retry next tick (not a death signal)
|
|
154
|
+
}
|
|
155
|
+
} catch {
|
|
156
|
+
readFailed = true; // session may be gone or node offline
|
|
157
|
+
}
|
|
158
|
+
if (!payload && !readFailed) continue; // null payload that wasn't a hard failure — retry next tick
|
|
159
|
+
|
|
160
|
+
if (readFailed || !payload) {
|
|
161
|
+
// R4f backstop (a) — liveness failure. For a never-acked dispatch there is no in-flight
|
|
162
|
+
// turn to protect, so a read failure is a transient probe blip → retry next tick (old
|
|
163
|
+
// behavior). For an ACKED dispatch that we had previously confirmed live, a streak of
|
|
164
|
+
// consecutive read failures means the worker session genuinely went away mid-turn and
|
|
165
|
+
// will never emit its real completion — count it. The actual terminal cleanup of a
|
|
166
|
+
// gone session is owned by PHASE 2.5 (stranded reclaim) / PHASE 5 (orphan prune); here
|
|
167
|
+
// we only record the death observation and STOP holding so those nets can take over,
|
|
168
|
+
// rather than pinning the row on an indefinite hold for a session that is already gone.
|
|
169
|
+
if (isAcked) {
|
|
170
|
+
const prior = getHoldState(synthKey, mesh.id);
|
|
171
|
+
const failures = (prior?.consecutiveReadFailures ?? 0) + 1;
|
|
172
|
+
const liveConfirmedSinceAck = prior?.liveConfirmedSinceAck ?? false;
|
|
173
|
+
// A read failure breaks the idle-with-final-assistant run → reset the fast-track streak
|
|
174
|
+
// (transcriptIdleSinceMs cleared by omission) so it must re-accumulate from scratch.
|
|
175
|
+
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck, consecutiveReadFailures: failures });
|
|
176
|
+
if (liveConfirmedSinceAck && failures >= ACKED_DEATH_CONSECUTIVE_READ_FAILURES) {
|
|
177
|
+
LOG.warn('MeshReconcile', `Acked-hold death signal: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read_chat failed ${failures}x consecutively after a live-confirmed ack — worker session presumed gone mid-turn; releasing the indefinite synth hold to the stranded-reclaim / orphan-prune nets`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
continue; // no readable transcript this tick → cannot synth here; retry / let backstops act
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Read succeeded (a conclusive idle/generating status) → the session is reachable: reset the
|
|
184
|
+
// failure streak and mark it live-confirmed-since-ack, so a LATER read failure is recognized
|
|
185
|
+
// as a genuine liveness loss (backstop a) rather than a node that was never reachable. The
|
|
186
|
+
// fast-track idle streak (transcriptIdleSinceMs) is PRESERVED across this reset — it is
|
|
187
|
+
// managed below where the idle + final-assistant signal is actually evaluated.
|
|
188
|
+
const priorHoldState = getHoldState(synthKey, mesh.id);
|
|
189
|
+
setHoldState(synthKey, mesh.id, {
|
|
190
|
+
liveConfirmedSinceAck: true,
|
|
191
|
+
consecutiveReadFailures: 0,
|
|
192
|
+
...(priorHoldState?.transcriptIdleSinceMs !== undefined ? { transcriptIdleSinceMs: priorHoldState.transcriptIdleSinceMs } : {}),
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Only act on a session that has actually settled to idle. A generating /
|
|
196
|
+
// waiting_approval session is mid-turn — synthesizing a completion now would
|
|
197
|
+
// be wrong. (idle is the only status the MCP poll path reconciles too.)
|
|
198
|
+
const nowMs = Date.now();
|
|
199
|
+
if (readChatPayloadStatus(payload) !== 'idle') {
|
|
200
|
+
// Not idle → the worker is genuinely mid-turn (a clear live signal). Keep the
|
|
201
|
+
// live-confirmed flag set (above) but RESET the fast-track idle streak: a turn that
|
|
202
|
+
// resumed generating proves the prior idle was a mid-turn blip, not a settled turn-end.
|
|
203
|
+
setHoldState(synthKey, mesh.id, { liveConfirmedSinceAck: true, consecutiveReadFailures: 0 });
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// R4f GENERATING-BOUNDARY (acked-hold): a dispatch whose worker was OBSERVED to start
|
|
208
|
+
// generating (the agent:generating_started ack flipped the row to 'acked') is ALIVE and
|
|
209
|
+
// mid-turn — it WILL eventually emit a real terminal. An `idle` read here is therefore
|
|
210
|
+
// presumed a TRANSIENT mid-turn window (a PTY inter-tool-call settle, or final text already
|
|
211
|
+
// rendered while the lifecycle close lags), NOT a settled completion. We HOLD the synth
|
|
212
|
+
// INDEFINITELY rather than racing the worker's (variable, unbounded) emit latency with a
|
|
213
|
+
// finite timer — the failure mode of R4..R4e. This is safe: when the worker's real emit
|
|
214
|
+
// lands it writes a terminal ledger, and reconcileDirectDispatchCompletionFromTranscript's
|
|
215
|
+
// hasTerminalLedgerAfterDispatch makes any later synth an idempotent no-op, so the real emit
|
|
216
|
+
// always wins no matter how late. The hold is released ONLY by the death backstops:
|
|
217
|
+
// (a) consecutive read failures after a live-confirmed ack (handled above), or
|
|
218
|
+
// (b) the absolute ACKED_DEATH_DEADLINE_MS since the ack — a notification-loss net set FAR
|
|
219
|
+
// above any observed emit latency, so it catches a genuinely-wedged worker / lost emit
|
|
220
|
+
// without racing a normal slow turn.
|
|
221
|
+
// A never-acked dispatch (worker never started) is exempt — no in-flight generation to
|
|
222
|
+
// pre-empt; it keeps the first-idle-tick synth, with the downstream grace + stale-summary
|
|
223
|
+
// guards as its backstops.
|
|
224
|
+
//
|
|
225
|
+
// ACKED-HOLD-IDLE-OVERTRUST: the read is idle. Extract the final-assistant evidence NOW (the
|
|
226
|
+
// same signal the synth below requires) so the fast-track can gate on idle-WITH-final-assistant
|
|
227
|
+
// rather than bare idle. Only when a final visible assistant message is present do we treat
|
|
228
|
+
// this tick as a candidate turn-end and accumulate the fast-track grace streak; a bare idle
|
|
229
|
+
// with no assistant result is the worker still warming up and resets the streak.
|
|
230
|
+
const messages = Array.isArray(payload.messages) ? payload.messages as ChatMessage[] : [];
|
|
231
|
+
const evidence = extractFinalAssistantSummaryEvidence(messages);
|
|
232
|
+
|
|
233
|
+
if (isAcked) {
|
|
234
|
+
const ackedAtMs = Date.parse(readNonEmptyString(dispatch.updatedAt));
|
|
235
|
+
const sinceAckMs = Number.isFinite(ackedAtMs) ? nowMs - ackedAtMs : Number.POSITIVE_INFINITY;
|
|
236
|
+
const deathDeadlineMs = resolveAckedDeathDeadlineMs();
|
|
237
|
+
|
|
238
|
+
// ACKED-HOLD-IDLE-OVERTRUST fast-track. Maintain the continuous idle-with-final-assistant
|
|
239
|
+
// streak. The streak starts (or continues) only while a final visible assistant message is
|
|
240
|
+
// present; a tick with idle-but-no-assistant breaks it (the answer is not yet rendered).
|
|
241
|
+
const holdState = getHoldState(synthKey, mesh.id);
|
|
242
|
+
let fastTrackReady = false;
|
|
243
|
+
if (evidence.finalSummary) {
|
|
244
|
+
const idleSinceMs = holdState?.transcriptIdleSinceMs ?? nowMs;
|
|
245
|
+
if (holdState && holdState.transcriptIdleSinceMs === undefined) {
|
|
246
|
+
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: idleSinceMs });
|
|
247
|
+
}
|
|
248
|
+
const fastTrackGraceMs = resolveAckedTranscriptFastTrackGraceMs();
|
|
249
|
+
const idleHeldMs = nowMs - idleSinceMs;
|
|
250
|
+
if (idleHeldMs >= fastTrackGraceMs) {
|
|
251
|
+
fastTrackReady = true;
|
|
252
|
+
backstopKind = 'ackedHoldFastTrackFired';
|
|
253
|
+
LOG.info('MeshReconcile', `Acked-hold transcript fast-track: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle WITH a final assistant message for ${Math.round(idleHeldMs / 1000)}s continuous (grace ${Math.round(fastTrackGraceMs / 1000)}s) — promoting the synth ahead of the ${Math.round(deathDeadlineMs / 1000)}s death backstop; the worker's real emit was lost/late and a later one no-ops idempotently.`);
|
|
254
|
+
}
|
|
255
|
+
} else if (holdState?.transcriptIdleSinceMs !== undefined) {
|
|
256
|
+
// Idle but no final assistant yet → not a turn-end; reset the streak.
|
|
257
|
+
setHoldState(synthKey, mesh.id, { ...holdState, transcriptIdleSinceMs: undefined });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Hold indefinitely UNLESS the fast-track grace was met OR the absolute death deadline is
|
|
261
|
+
// reached. The fast-track is the new fast path in front of the (preserved) 8-min backstop.
|
|
262
|
+
if (!fastTrackReady && sinceAckMs < deathDeadlineMs) {
|
|
263
|
+
LOG.info('MeshReconcile', `Acked-hold: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read idle ${Number.isFinite(sinceAckMs) ? Math.round(sinceAckMs / 1000) + 's' : '∞'} since the generating_started ack — HOLDING synth (worker presumed alive; a later real emit is idempotent). Transcript fast-track promotes at ${Math.round(resolveAckedTranscriptFastTrackGraceMs() / 1000)}s continuous idle-with-final-assistant; death backstop at ${Math.round(deathDeadlineMs / 1000)}s or on consecutive read failures.`);
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (!fastTrackReady) {
|
|
267
|
+
backstopKind = 'ackedHoldDeathDeadlineFired';
|
|
268
|
+
LOG.warn('MeshReconcile', `Acked-hold death deadline reached: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) still idle ${Math.round(sinceAckMs / 1000)}s after the ack (deadline ${Math.round(deathDeadlineMs / 1000)}s) — synthesizing the missing completion as a notification-loss net (a real emit, if it ever lands, no-ops idempotently).`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// R4f (auxiliary, was R4e fix 3) — worker-emit priority. Secondary check: if the worker's
|
|
273
|
+
// REAL terminal emit for this task has already arrived in the pending-events queue (queued
|
|
274
|
+
// for delivery to the coordinator) but not yet written a terminal ledger, YIELD — let the
|
|
275
|
+
// genuine emit surface rather than racing it with a synth that would win the taskId-anchored
|
|
276
|
+
// fingerprint dedup and mask it. Under the R4f acked-hold this is now an auxiliary belt-and-
|
|
277
|
+
// suspenders check (the indefinite hold already defers an acked synth); it still guards the
|
|
278
|
+
// never-acked path and the post-death-deadline acked synth from racing an emit caught in
|
|
279
|
+
// flight at synth-commit time.
|
|
280
|
+
if (realTerminalEmitPendingForTask(mesh.id, taskId)) {
|
|
281
|
+
deleteHoldState(synthKey, mesh.id);
|
|
282
|
+
LOG.info('MeshReconcile', `Worker-emit priority: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) has a real terminal completion already queued — yielding synth to the worker's own emit`);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!evidence.finalSummary) continue; // no assistant result yet — nothing to attribute
|
|
287
|
+
|
|
288
|
+
// STALE-SUMMARY guard (modal-parked / reused-session misattribution): a direct
|
|
289
|
+
// dispatch frequently reuses a session that already ran a PRIOR task. read_chat
|
|
290
|
+
// returns the tail of the WHOLE session, so extractFinalAssistantSummaryEvidence
|
|
291
|
+
// picks the latest user-facing assistant message — which, for a task that has
|
|
292
|
+
// barely started (the session momentarily reads idle between turns), is the prior
|
|
293
|
+
// task's final summary. The downstream reconcile proves the summary is after the
|
|
294
|
+
// LEDGER task_dispatched entry; here we additionally have the AUTHORITATIVE per-task
|
|
295
|
+
// dispatchedAt (the dispatch-store row, immune to ledger-ordering quirks), so when
|
|
296
|
+
// the selected transcript message is provably BEFORE this task's own dispatch we
|
|
297
|
+
// refuse it outright — it is a prior task's summary, not this task's output (the
|
|
298
|
+
// 2843ms-duration stale-summary bug where task 2e3f501e copy-pasted 4eca2d9d's
|
|
299
|
+
// summary). When the message carries no usable timestamp we do NOT block here: the
|
|
300
|
+
// downstream reconcile already rejects a non-JSON summary it cannot prove is
|
|
301
|
+
// post-dispatch (transcript_not_proven_after_dispatch), and a structured
|
|
302
|
+
// final_summary_json is self-attributing — so a timeless provider is not
|
|
303
|
+
// over-blocked while the provable-stale case is still caught.
|
|
304
|
+
const dispatchedAtMs = Date.parse(readNonEmptyString(dispatch.dispatchedAt));
|
|
305
|
+
const transcriptAtMs = Date.parse(evidence.transcriptMessageAt ?? '');
|
|
306
|
+
if (Number.isFinite(dispatchedAtMs) && Number.isFinite(transcriptAtMs) && transcriptAtMs < dispatchedAtMs) {
|
|
307
|
+
LOG.info('MeshReconcile', `Stale-summary guard: skipping transcript reconcile for task ${taskId} on node ${nodeId} (mesh ${mesh.id}) — final assistant message (${evidence.transcriptMessageAt}) predates this task's dispatch (${dispatch.dispatchedAt}); it is a prior task's summary`);
|
|
308
|
+
traceMeshEventDrop('reconcile_stale_summary_before_dispatch', {
|
|
309
|
+
taskId, sessionId, nodeId, meshId: mesh.id, event: 'agent:generating_completed',
|
|
310
|
+
}, `transcriptAt=${evidence.transcriptMessageAt} < dispatchedAt=${dispatch.dispatchedAt}`);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// R4f (auxiliary, was R4e fix 2) — live re-probe immediately before committing the synth. A
|
|
315
|
+
// fresh read right now catches a worker that resumed generating since this tick's first read
|
|
316
|
+
// so it is never falsely completed off a stale snapshot. Best-effort: an inconclusive
|
|
317
|
+
// re-probe (transport error/null) falls through to the synth — we already hold a valid idle
|
|
318
|
+
// read from the top of THIS tick, so a re-probe failure must not re-introduce a
|
|
319
|
+
// notification-miss. Under the R4f acked-hold this matters mainly for the never-acked path
|
|
320
|
+
// and the post-death-deadline acked synth (the indefinite hold already deferred a live acked
|
|
321
|
+
// turn); it stays as a final live-state guard at synth-commit time.
|
|
322
|
+
const reprobeStatus = await reprobeWorkerStatus(components, { isLocalNode, nodeDaemonId, readArgs });
|
|
323
|
+
if (reprobeStatus && reprobeStatus !== 'idle') {
|
|
324
|
+
deleteHoldState(synthKey, mesh.id);
|
|
325
|
+
LOG.info('MeshReconcile', `Live re-probe defer: task ${taskId} on node ${nodeId} (mesh ${mesh.id}) read '${reprobeStatus}' at synth-commit time — worker resumed generating; deferring synth to a later tick`);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const providerSessionId = readNonEmptyString(payload.providerSessionId);
|
|
330
|
+
// COORD-EVENT-MISROUTE (anchor preservation): the coordinator DAEMON anchor for the
|
|
331
|
+
// synthesized completion is the daemon that DISPATCHED the task, NOT this reconcile
|
|
332
|
+
// runner's own daemon. On a REMOTE worker the reconcile loop runs on the WORKER's daemon,
|
|
333
|
+
// so `selfIds` is the worker daemon — stamping it as targetCoordinatorDaemonId corrupts the
|
|
334
|
+
// anchor and (when the real coordinator is on another machine) downgrades the completion to
|
|
335
|
+
// a cross-machine broadcast deliverable to any coordinator. Recover the true anchor:
|
|
336
|
+
// 1. the live worker session's meshCoordinatorDaemonId relay stamp (set at dispatch,
|
|
337
|
+
// the same anchor the worker's own real-emit path reads in mesh-event-forwarding); then
|
|
338
|
+
// 2. leave it to reconcileDirectDispatchCompletionFromTranscript, which recovers the
|
|
339
|
+
// DISPATCHING coordinator daemon from the task_dispatched ledger (authoritative).
|
|
340
|
+
// Only when NEITHER is available do we fall back to selfIds — a genuinely local,
|
|
341
|
+
// single-daemon dispatch where self IS the coordinator daemon (unchanged behaviour).
|
|
342
|
+
const workerSession = components.instanceManager.getInstance(sessionId);
|
|
343
|
+
const workerCoordinatorDaemonId = readNonEmptyString(
|
|
344
|
+
(workerSession?.getState()?.settings as Record<string, unknown> | undefined)?.meshCoordinatorDaemonId,
|
|
345
|
+
);
|
|
346
|
+
const coordinatorDaemonId = workerCoordinatorDaemonId || selfIds.find(id => !!id);
|
|
347
|
+
try {
|
|
348
|
+
const result = reconcileDirectDispatchCompletionFromTranscript({
|
|
349
|
+
meshId: mesh.id,
|
|
350
|
+
nodeId,
|
|
351
|
+
sessionId,
|
|
352
|
+
providerType: providerType || undefined,
|
|
353
|
+
providerSessionId: providerSessionId || undefined,
|
|
354
|
+
taskId,
|
|
355
|
+
finalSummary: evidence.finalSummary,
|
|
356
|
+
...(evidence.transcriptMessageAt ? { transcriptMessageAt: evidence.transcriptMessageAt } : {}),
|
|
357
|
+
// The ledger-recovered dispatching-coordinator daemon (inside the reconcile fn)
|
|
358
|
+
// takes PRIORITY over this arg; this remains the best-available fallback.
|
|
359
|
+
...(coordinatorDaemonId ? { targetCoordinatorDaemonId: coordinatorDaemonId } : {}),
|
|
360
|
+
source: 'daemon_reconcile_transcript_completion',
|
|
361
|
+
});
|
|
362
|
+
if (result.reconciled) {
|
|
363
|
+
// T6: this synth actually committed → count the last-resort backstop fire.
|
|
364
|
+
// An acked hold routes to the fast-track / death-deadline kind captured
|
|
365
|
+
// above; a never-acked dispatch is a plain PHASE-4 transcript synthesis.
|
|
366
|
+
// Under enforce, recordBackstopFire additionally WARNs (target = 0 fires).
|
|
367
|
+
recordBackstopFire(backstopKind ?? 'phase4SynthesisFired', `task ${taskId} on node ${nodeId} (mesh ${mesh.id}), kind=${result.kind}`);
|
|
368
|
+
LOG.info('MeshReconcile', `Synthesized missing completion (${result.kind}) for task ${taskId} on node ${nodeId} (mesh ${mesh.id})`);
|
|
369
|
+
}
|
|
370
|
+
} catch (e: any) {
|
|
371
|
+
LOG.warn('MeshReconcile', `Transcript completion reconcile threw for task ${taskId}: ${e?.message || e}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// PHASE 5 helper. Build the live-node view (mesh.nodes decorated with each node's live
|
|
377
|
+
// session list) and run the shared prune core in execute mode with the conservative age gate.
|
|
378
|
+
//
|
|
379
|
+
// Orphan detection needs the SAME live-session evidence the manual MCP prune uses: a node still
|
|
380
|
+
// in mesh.nodes whose session list no longer contains the dispatched sessionId is "session not
|
|
381
|
+
// present" (prunable); a node missing from mesh.nodes entirely is "node no longer in live mesh"
|
|
382
|
+
// (prunable). We obtain live sessions per node via get_status_metadata — local nodes through the
|
|
383
|
+
// local commandHandler, remote nodes over P2P (dispatchMeshCommand) — exactly the transports
|
|
384
|
+
// PHASE 4 already uses. A node we cannot probe (offline) keeps an empty session list; combined
|
|
385
|
+
// with the age gate that only matters once the orphan is genuinely old.
|
|
386
|
+
//
|
|
387
|
+
// O(1) fast exit: when there are no active direct dispatches at all there is nothing to prune,
|
|
388
|
+
// so we skip the (per-node) status probes entirely — an idle mesh costs one indexed query.
|
|
389
|
+
export async function autoPruneStaleDirectDispatches(
|
|
390
|
+
components: DaemonComponents,
|
|
391
|
+
mesh: LocalMeshEntry,
|
|
392
|
+
selfIds: string[],
|
|
393
|
+
localDaemonId: string | undefined,
|
|
394
|
+
minAgeMs: number,
|
|
395
|
+
): Promise<void> {
|
|
396
|
+
const directDispatches = getActiveDirectDispatches(mesh.id);
|
|
397
|
+
if (directDispatches.length === 0) return; // nothing dispatched → nothing to prune
|
|
398
|
+
|
|
399
|
+
const liveNodes = await collectLiveNodesWithSessions(components, mesh, selfIds, localDaemonId);
|
|
400
|
+
|
|
401
|
+
const result = pruneStaleDirectDispatches({
|
|
402
|
+
meshId: mesh.id,
|
|
403
|
+
queue: getQueue(mesh.id),
|
|
404
|
+
ledgerEntries: readLedgerEntries(mesh.id, { tail: 500 }),
|
|
405
|
+
directDispatches,
|
|
406
|
+
nodes: liveNodes,
|
|
407
|
+
execute: true,
|
|
408
|
+
minAgeMs,
|
|
409
|
+
source: 'daemon_reconcile_auto_prune',
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Log only when something was actually pruned — silence on the common no-op tick.
|
|
413
|
+
if (result.prunedCount > 0) {
|
|
414
|
+
LOG.info('MeshReconcile', `Auto-pruned ${result.prunedCount} orphaned direct dispatch record(s) for mesh ${mesh.id}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermes / MCP coordinator config helpers
|
|
3
|
+
*
|
|
4
|
+
* Extracted from commands/router.ts (behavior-preserving move). Contains the
|
|
5
|
+
* MCP-server config parse/serialize helpers and the Hermes coordinator base
|
|
6
|
+
* config loading / temp-override stripping / credential-copy helpers.
|
|
7
|
+
*
|
|
8
|
+
* router.ts re-exports every public symbol from here so existing import paths
|
|
9
|
+
* keep working.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { LOG } from '../logging/logger.js';
|
|
13
|
+
import * as yaml from 'js-yaml';
|
|
14
|
+
import { homedir } from 'os';
|
|
15
|
+
import { join as pathJoin, resolve as pathResolve } from 'path';
|
|
16
|
+
import * as fs from 'fs';
|
|
17
|
+
import type { MeshCoordinatorConfigFormat } from './mesh-refine-gates.js';
|
|
18
|
+
|
|
19
|
+
function loadYamlModule(): { load: (input: string) => any; dump: (input: any, options?: Record<string, any>) => string } {
|
|
20
|
+
return yaml as { load: (input: string) => any; dump: (input: any, options?: Record<string, any>) => string };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getMcpServersKey(format: MeshCoordinatorConfigFormat): 'mcpServers' | 'mcp_servers' {
|
|
24
|
+
return format === 'hermes_config_yaml' ? 'mcp_servers' : 'mcpServers';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function parseMeshCoordinatorMcpConfig(text: string, format: MeshCoordinatorConfigFormat): Record<string, any> {
|
|
28
|
+
if (!text.trim()) return {};
|
|
29
|
+
if (format === 'claude_mcp_json') return JSON.parse(text);
|
|
30
|
+
const parsed = loadYamlModule().load(text);
|
|
31
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function serializeMeshCoordinatorMcpConfig(config: Record<string, any>, format: MeshCoordinatorConfigFormat): string {
|
|
35
|
+
if (format === 'claude_mcp_json') return JSON.stringify(config, null, 2);
|
|
36
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveHermesUserHome(): string {
|
|
40
|
+
const explicitHome = process.env.HERMES_HOME?.trim();
|
|
41
|
+
return explicitHome || pathJoin(homedir(), '.hermes');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function loadHermesCoordinatorBaseConfig(targetConfigPath: string): { config: Record<string, any>; sourceHome: string; sourceConfigPath: string } {
|
|
45
|
+
const sourceHome = resolveHermesUserHome();
|
|
46
|
+
const sourceConfigPath = pathJoin(sourceHome, 'config.yaml');
|
|
47
|
+
if (!fs.existsSync(sourceConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
48
|
+
if (pathResolve(sourceConfigPath) === pathResolve(targetConfigPath)) return { config: {}, sourceHome, sourceConfigPath };
|
|
49
|
+
|
|
50
|
+
const parsed = parseMeshCoordinatorMcpConfig(fs.readFileSync(sourceConfigPath, 'utf-8'), 'hermes_config_yaml');
|
|
51
|
+
const { mcp_servers: _mcpServers, ...baseConfig } = parsed;
|
|
52
|
+
return { config: baseConfig, sourceHome, sourceConfigPath };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function stripHermesCoordinatorTempModelProviderOverrides(config: Record<string, any>): Record<string, any> {
|
|
56
|
+
const {
|
|
57
|
+
model: _model,
|
|
58
|
+
provider: _provider,
|
|
59
|
+
default_model: _defaultModel,
|
|
60
|
+
defaultProvider: _defaultProvider,
|
|
61
|
+
default_provider: _defaultProviderSnake,
|
|
62
|
+
modelProvider: _modelProvider,
|
|
63
|
+
model_provider: _modelProviderSnake,
|
|
64
|
+
...sanitized
|
|
65
|
+
} = config;
|
|
66
|
+
const delegation = sanitized.delegation;
|
|
67
|
+
if (delegation && typeof delegation === 'object' && !Array.isArray(delegation)) {
|
|
68
|
+
const {
|
|
69
|
+
model: _delegationModel,
|
|
70
|
+
provider: _delegationProvider,
|
|
71
|
+
modelProvider: _delegationModelProvider,
|
|
72
|
+
model_provider: _delegationModelProviderSnake,
|
|
73
|
+
...delegationRest
|
|
74
|
+
} = delegation;
|
|
75
|
+
if (Object.keys(delegationRest).length > 0) {
|
|
76
|
+
sanitized.delegation = delegationRest;
|
|
77
|
+
} else {
|
|
78
|
+
delete sanitized.delegation;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return sanitized;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function copyHermesCoordinatorCredentialFiles(sourceHome: string, targetHome: string) {
|
|
85
|
+
if (pathResolve(sourceHome) === pathResolve(targetHome)) return;
|
|
86
|
+
for (const fileName of ['.env', 'auth.json']) {
|
|
87
|
+
const sourcePath = pathJoin(sourceHome, fileName);
|
|
88
|
+
const targetPath = pathJoin(targetHome, fileName);
|
|
89
|
+
if (!fs.existsSync(sourcePath)) continue;
|
|
90
|
+
try {
|
|
91
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
92
|
+
} catch (error: any) {
|
|
93
|
+
LOG.warn('MeshCoordinator', `Could not copy Hermes ${fileName} into isolated coordinator home: ${error?.message || error}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|