@adhdev/daemon-core 0.9.82-rc.48 → 0.9.82-rc.480
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 +126 -64
- package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
- package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +69 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
- package/dist/cli-adapters/terminal-screen.d.ts +4 -11
- package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
- package/dist/commands/chat-commands-read.d.ts +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 +51 -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 +137 -0
- package/dist/commands/router-worktree-cleanup.d.ts +133 -0
- package/dist/commands/router.d.ts +204 -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 +136 -1
- package/dist/config/mesh-json-config.d.ts +199 -0
- package/dist/config/registry-resolver.d.ts +54 -0
- package/dist/config/repo-settings.d.ts +77 -0
- package/dist/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 +57 -0
- package/dist/git/git-types.d.ts +2 -50
- package/dist/git/git-worktree.d.ts +71 -1
- package/dist/git/index.d.ts +3 -1
- package/dist/index.d.ts +73 -17
- package/dist/index.js +52979 -18657
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59496 -25355
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/ipc/local-ipc-server.d.ts +91 -0
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/logging/debug-config.d.ts +16 -0
- package/dist/logging/log-redactor.d.ts +24 -0
- package/dist/logging/log-tail-reader.d.ts +81 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/contracts.d.ts +230 -0
- package/dist/mesh/coordinator-prompt.d.ts +76 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +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 +49 -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 +246 -0
- package/dist/mesh/mesh-events-stale.d.ts +61 -0
- package/dist/mesh/mesh-events-utils.d.ts +75 -0
- package/dist/mesh/mesh-events.d.ts +6 -49
- package/dist/mesh/mesh-fast-forward.d.ts +81 -0
- package/dist/mesh/mesh-host-ownership.d.ts +29 -0
- package/dist/mesh/mesh-init.d.ts +128 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
- package/dist/mesh/mesh-ledger.d.ts +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 +158 -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 +80 -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 +428 -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 +508 -0
- package/dist/mesh/mesh-scheduling-runtime.d.ts +78 -0
- package/dist/mesh/mesh-task-inflight.d.ts +46 -0
- package/dist/mesh/mesh-task-stats.d.ts +49 -0
- package/dist/mesh/mesh-unresolved-forward-outbox.d.ts +30 -0
- package/dist/mesh/mesh-warmup-deadline.d.ts +68 -0
- package/dist/mesh/mesh-work-queue.d.ts +363 -5
- package/dist/mesh/preview-freshness.d.ts +28 -0
- package/dist/mesh/refine-config.d.ts +216 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +219 -0
- package/dist/providers/acp-provider-instance.d.ts +5 -0
- package/dist/providers/approval-utils.d.ts +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 +406 -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 +149 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/manual-attendance.d.ts +79 -0
- package/dist/providers/native-history/antigravity-claim-registry.d.ts +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 +29 -0
- package/dist/providers/provider-instance.d.ts +30 -1
- package/dist/providers/provider-loader.d.ts +42 -5
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +98 -0
- package/dist/providers/spec/cli-adapter.d.ts +223 -0
- package/dist/providers/spec/evaluator.d.ts +45 -0
- package/dist/providers/spec/fsm-driver.d.ts +449 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +93 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +202 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +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 +629 -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 +98 -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 +26 -0
- package/dist/system/hash.d.ts +8 -0
- package/dist/system/load-better-sqlite3.d.ts +21 -0
- package/dist/types.d.ts +5 -0
- package/package.json +11 -4
- package/src/agent-stream/poller.ts +2 -3
- package/src/agent-stream/provider-adapter.ts +1 -1
- package/src/boot/daemon-lifecycle.ts +80 -14
- package/src/boot/process-hardening.ts +89 -0
- package/src/build-info.ts +73 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +3 -1
- package/src/cli-adapter-types.ts +68 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1282 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +954 -1144
- package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
- package/src/cli-adapters/provider-cli-parse.ts +19 -0
- package/src/cli-adapters/provider-cli-runtime.ts +56 -7
- package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
- package/src/cli-adapters/provider-cli-shared.ts +121 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/pty-write-chunking.ts +106 -0
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +204 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
- package/src/cli-adapters/terminal-backends/types.ts +10 -3
- package/src/cli-adapters/terminal-screen.ts +16 -81
- package/src/commands/chat-commands-debug-bundle.ts +398 -0
- package/src/commands/chat-commands-read.ts +2767 -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 +659 -27
- package/src/commands/handler.ts +845 -2
- package/src/commands/high-family/index.ts +28 -0
- package/src/commands/high-family/mesh-coordinator-launch.ts +680 -0
- package/src/commands/high-family/mesh-events.ts +102 -0
- package/src/commands/high-family/mesh-status.ts +849 -0
- package/src/commands/high-family/types.ts +80 -0
- package/src/commands/low-family/coordinator-prompt.ts +72 -0
- package/src/commands/low-family/daemon-lifecycle.ts +120 -0
- package/src/commands/low-family/diagnostics.ts +57 -0
- package/src/commands/low-family/index.ts +37 -0
- package/src/commands/low-family/mesh-ledger.ts +62 -0
- package/src/commands/low-family/mesh-node-logs.ts +87 -0
- package/src/commands/low-family/notification.ts +116 -0
- package/src/commands/low-family/refine-config.ts +106 -0
- package/src/commands/low-family/session-host.ts +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 +241 -0
- package/src/commands/med-family/fast-forward.ts +230 -0
- package/src/commands/med-family/ide.ts +163 -0
- package/src/commands/med-family/index.ts +37 -0
- package/src/commands/med-family/mesh-crud.ts +1287 -0
- package/src/commands/med-family/mesh-host-pairing.ts +234 -0
- package/src/commands/med-family/mesh-queue.ts +167 -0
- package/src/commands/med-family/mesh-restart.ts +92 -0
- package/src/commands/med-family/types.ts +153 -0
- package/src/commands/mesh-coordinator.ts +334 -124
- package/src/commands/router-aggregate-status.ts +209 -0
- package/src/commands/router-mesh-session-owner.ts +114 -0
- package/src/commands/router-refine.ts +1711 -0
- package/src/commands/router-worktree-cleanup.ts +870 -0
- package/src/commands/router.ts +795 -4143
- 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 +632 -23
- package/src/config/mesh-json-config.ts +376 -0
- package/src/config/recent-activity.ts +8 -2
- package/src/config/registry-resolver.ts +100 -0
- package/src/config/repo-settings.ts +111 -0
- package/src/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 +767 -48
- package/src/git/git-types.ts +14 -62
- package/src/git/git-worktree.ts +261 -4
- package/src/git/index.ts +17 -0
- package/src/index.ts +213 -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 +469 -0
- package/src/mesh/coordinator-prompt.ts +572 -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 +2002 -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 +1494 -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 +111 -0
- package/src/mesh/mesh-init.ts +350 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
- package/src/mesh/mesh-ledger.ts +898 -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 +2263 -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 +1473 -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 +1686 -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 +2150 -0
- package/src/mesh/mesh-scheduling-runtime.ts +198 -0
- package/src/mesh/mesh-task-inflight.ts +70 -0
- package/src/mesh/mesh-task-stats.ts +161 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
- package/src/mesh/mesh-warmup-deadline.ts +152 -0
- package/src/mesh/mesh-work-queue.ts +1437 -147
- package/src/mesh/preview-freshness.ts +163 -0
- package/src/mesh/refine-config.ts +423 -0
- package/src/mesh/worktree-bootstrap-config.ts +599 -0
- package/src/providers/acp-provider-instance.ts +43 -10
- package/src/providers/approval-utils.d.ts +5 -0
- package/src/providers/approval-utils.ts +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 +2709 -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 +160 -6
- package/src/providers/extension-provider-instance.ts +12 -7
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +35 -12
- package/src/providers/manual-attendance.ts +105 -0
- package/src/providers/native-history/antigravity-claim-registry.ts +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 +87 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +261 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +509 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +246 -0
- package/src/providers/spec/cli-adapter.ts +1064 -0
- package/src/providers/spec/evaluator.ts +407 -0
- package/src/providers/spec/fsm-driver.ts +1528 -0
- package/src/providers/spec/fsm-evaluator.ts +290 -0
- package/src/providers/spec/fsm-loader.ts +128 -0
- package/src/providers/spec/fsm-types.ts +301 -0
- package/src/providers/spec/native-history-executor.ts +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 +868 -13
- package/src/runtime-defaults.ts +39 -0
- package/src/session-host/managed-host.ts +218 -0
- package/src/session-host/runtime-surface.ts +20 -80
- package/src/sessions/registry.ts +44 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.d.ts +8 -0
- package/src/shared-types.ts +136 -55
- package/src/status/builders.ts +26 -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 +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
|
@@ -18,13 +18,15 @@ import { loadConfig } from '../config/config.js';
|
|
|
18
18
|
import { loadState, saveState } from '../config/state-store.js';
|
|
19
19
|
import { getWorkspaceState, resolveLaunchDirectory } from '../config/workspaces.js';
|
|
20
20
|
import { appendRecentActivity } from '../config/recent-activity.js';
|
|
21
|
+
import { shortHash } from '../system/hash.js';
|
|
22
|
+
import { unregisterMeshCoordinator, getCoordinatorForSession, listCoordinatorsForWorkspace } from '../mesh/coordinator-registry.js';
|
|
21
23
|
import { upsertSavedProviderSession } from '../config/saved-sessions.js';
|
|
22
24
|
import { buildLegacyModelModeSummaryMetadata, normalizeProviderSummaryMetadata } from '../providers/summary-metadata.js';
|
|
23
25
|
import { CliProviderInstance } from '../providers/cli-provider-instance.js';
|
|
24
26
|
import { AcpProviderInstance } from '../providers/acp-provider-instance.js';
|
|
25
27
|
import type { ProviderInstanceManager } from '../providers/provider-instance-manager.js';
|
|
26
28
|
import { ProviderLoader } from '../providers/provider-loader.js';
|
|
27
|
-
import { normalizeInputEnvelope, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
|
|
29
|
+
import { normalizeInputEnvelope, type MeshCoordinatorDelegatedWorkerIsolation, type ProviderModule, type ProviderResumeCapability } from '../providers/contracts.js';
|
|
28
30
|
import { assertProviderSupportsDeclaredInput, assertTextOnlyInput } from '../providers/provider-input-support.js';
|
|
29
31
|
import type { CliAdapter } from '../cli-adapter-types.js';
|
|
30
32
|
import type { PtyTransportFactory } from '../cli-adapters/pty-transport.js';
|
|
@@ -80,6 +82,126 @@ export interface CliManagerDeps {
|
|
|
80
82
|
|
|
81
83
|
type CommandResult = { success: boolean;[key: string]: unknown };
|
|
82
84
|
|
|
85
|
+
const BUSY_AGENT_STATUSES = new Set(['generating', 'running', 'streaming', 'starting', 'busy', 'waiting', 'waiting_approval', 'no_progress', 'long_generating']);
|
|
86
|
+
const ZERO_MESSAGE_STARTING_SEND_WAIT_MS = 2_000;
|
|
87
|
+
|
|
88
|
+
function normalizeAgentStatus(value: unknown): string {
|
|
89
|
+
return typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function hasNonEmptyModalButtons(activeModal: unknown): boolean {
|
|
93
|
+
const buttons = (activeModal as any)?.buttons;
|
|
94
|
+
return Array.isArray(buttons) && buttons.some((button) => String(button || '').trim().length > 0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function hasAdapterPendingResponse(adapter: any): boolean {
|
|
98
|
+
if (adapter?.isWaitingForResponse === true) return true;
|
|
99
|
+
if (adapter?.currentTurnScope) return true;
|
|
100
|
+
try {
|
|
101
|
+
if (typeof adapter?.isProcessing === 'function' && adapter.isProcessing()) return true;
|
|
102
|
+
} catch { /* defensive: send guard should not fail on diagnostics */ }
|
|
103
|
+
try {
|
|
104
|
+
const partial = typeof adapter?.getPartialResponse === 'function' ? adapter.getPartialResponse() : '';
|
|
105
|
+
if (typeof partial === 'string' && partial.trim()) return true;
|
|
106
|
+
} catch { /* defensive: missing partial means no pending evidence */ }
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function countMessages(value: unknown): number {
|
|
111
|
+
return Array.isArray(value) ? value.length : 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function hasFinalAssistantMessage(value: unknown): boolean {
|
|
115
|
+
const messages = Array.isArray(value) ? value : [];
|
|
116
|
+
const last = messages[messages.length - 1] as any;
|
|
117
|
+
if (!last || last.role !== 'assistant') return false;
|
|
118
|
+
if (last.bubbleState === 'streaming') return false;
|
|
119
|
+
if (last.meta?.streaming === true) return false;
|
|
120
|
+
return typeof last.content === 'string' && last.content.trim().length > 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function hasZeroMessageStartingLaunch(adapter: any): boolean {
|
|
124
|
+
const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
|
|
125
|
+
const parsedStatus = typeof adapter?.getScriptParsedStatus === 'function'
|
|
126
|
+
? adapter.getScriptParsedStatus()
|
|
127
|
+
: {};
|
|
128
|
+
const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
|
|
129
|
+
const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
|
|
130
|
+
if (adapterRawStatus !== 'starting') return false;
|
|
131
|
+
if (parsedRawStatus && parsedRawStatus !== 'starting' && parsedRawStatus !== 'generating') return false;
|
|
132
|
+
if (hasNonEmptyModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
|
|
133
|
+
if (countMessages(adapterStatus?.messages) > 0 || countMessages(parsedStatus?.messages) > 0) return false;
|
|
134
|
+
return !hasAdapterPendingResponse(adapter);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function hasCompletedStartingLaunch(adapter: any): boolean {
|
|
138
|
+
const adapterStatus = adapter?.getStatus?.({ allowParse: false }) ?? adapter?.getStatus?.() ?? {};
|
|
139
|
+
const adapterRawStatus = normalizeAgentStatus(adapterStatus?.status);
|
|
140
|
+
if (adapterRawStatus !== 'starting') return false;
|
|
141
|
+
if (hasAdapterPendingResponse(adapter)) return false;
|
|
142
|
+
|
|
143
|
+
const parsedStatus = typeof adapter?.getScriptParsedStatus === 'function'
|
|
144
|
+
? adapter.getScriptParsedStatus()
|
|
145
|
+
: {};
|
|
146
|
+
const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
|
|
147
|
+
if (parsedRawStatus !== 'idle') return false;
|
|
148
|
+
if (hasNonEmptyModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal ?? parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
|
|
149
|
+
return hasFinalAssistantMessage(parsedStatus?.messages);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* WTCLAIM (B): compare two workspace paths for node scoping. Normalizes separator
|
|
154
|
+
* style, trailing slashes, and case (Windows paths are case-insensitive; the
|
|
155
|
+
* coordinator-supplied node.workspace and the adapter's launch workingDir can
|
|
156
|
+
* differ only in those) so a base node and a worktree clone are still told apart
|
|
157
|
+
* by their distinct workspace roots.
|
|
158
|
+
*/
|
|
159
|
+
function normalizeDirForCompare(dir?: string): string {
|
|
160
|
+
if (typeof dir !== 'string') return '';
|
|
161
|
+
return dir.trim().replace(/[\\/]+/g, '/').replace(/\/+$/, '').toLowerCase();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function shouldSuppressStaleParsedBusyStatus(adapterStatus: string, parsedStatus: any, adapter: any): boolean {
|
|
165
|
+
const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
|
|
166
|
+
if (!BUSY_AGENT_STATUSES.has(parsedRawStatus)) return false;
|
|
167
|
+
if (adapterStatus !== 'idle') return false;
|
|
168
|
+
if (hasNonEmptyModalButtons(parsedStatus?.activeModal ?? parsedStatus?.modal)) return false;
|
|
169
|
+
return !hasAdapterPendingResponse(adapter);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function getEffectiveAgentSendStatus(adapter: any): string {
|
|
173
|
+
const adapterStatus = normalizeAgentStatus(adapter?.getStatus?.({ allowParse: false })?.status ?? adapter?.getStatus?.()?.status);
|
|
174
|
+
if (adapterStatus === 'starting' && hasCompletedStartingLaunch(adapter)) return 'idle';
|
|
175
|
+
if (adapterStatus && adapterStatus !== 'idle') return adapterStatus;
|
|
176
|
+
if (adapterStatus !== 'idle') return adapterStatus;
|
|
177
|
+
|
|
178
|
+
if (typeof adapter?.getScriptParsedStatus !== 'function') return adapterStatus;
|
|
179
|
+
try {
|
|
180
|
+
const parsedStatus = adapter.getScriptParsedStatus();
|
|
181
|
+
const parsedRawStatus = normalizeAgentStatus(parsedStatus?.status);
|
|
182
|
+
if (BUSY_AGENT_STATUSES.has(parsedRawStatus) && !shouldSuppressStaleParsedBusyStatus(adapterStatus, parsedStatus, adapter)) {
|
|
183
|
+
return parsedRawStatus;
|
|
184
|
+
}
|
|
185
|
+
} catch {
|
|
186
|
+
return adapterStatus;
|
|
187
|
+
}
|
|
188
|
+
return adapterStatus;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function waitForZeroMessageStartingLaunch(adapter: any): Promise<boolean> {
|
|
192
|
+
try {
|
|
193
|
+
if (!hasZeroMessageStartingLaunch(adapter)) return false;
|
|
194
|
+
} catch {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
await new Promise(resolve => setTimeout(resolve, ZERO_MESSAGE_STARTING_SEND_WAIT_MS));
|
|
198
|
+
try {
|
|
199
|
+
return hasZeroMessageStartingLaunch(adapter);
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
83
205
|
export interface CliTransportFactoryParams {
|
|
84
206
|
runtimeId: string;
|
|
85
207
|
providerType: string;
|
|
@@ -87,6 +209,16 @@ export interface CliTransportFactoryParams {
|
|
|
87
209
|
cliArgs?: string[];
|
|
88
210
|
providerSessionId?: string;
|
|
89
211
|
attachExisting?: boolean;
|
|
212
|
+
/**
|
|
213
|
+
* Launch-time record meta (meshNodeId / meshNodeFor / launchedByCoordinator /
|
|
214
|
+
* autoLaunchedForQueueTaskId). Defense-in-depth for SESSION-ACCUMULATION-LEAK:
|
|
215
|
+
* a session-host factory impl SHOULD seed the create_session record with this
|
|
216
|
+
* so the node binding is present the instant the record exists, rather than
|
|
217
|
+
* relying solely on the post-spawn updateRuntimeMeta round-trip. Optional and
|
|
218
|
+
* additive — factory impls that ignore it keep the prior behavior; the
|
|
219
|
+
* post-spawn WTDISPATCH stamp in register() still runs as the primary path.
|
|
220
|
+
*/
|
|
221
|
+
initialMeta?: Record<string, unknown>;
|
|
90
222
|
}
|
|
91
223
|
|
|
92
224
|
export interface HostedCliRuntimeDescriptor {
|
|
@@ -101,6 +233,14 @@ export interface HostedCliRuntimeDescriptor {
|
|
|
101
233
|
cliArgs?: string[];
|
|
102
234
|
providerSessionId?: string;
|
|
103
235
|
managedBy?: string;
|
|
236
|
+
/**
|
|
237
|
+
* Real spawn time (ms epoch) of the underlying session-host runtime — a PAST
|
|
238
|
+
* timestamp recorded when the runtime first started. Threaded through so an
|
|
239
|
+
* attach can restore the native-history session-floor to the runtime's actual
|
|
240
|
+
* birth instead of collapsing spawnedAtMs to 0. Undefined when unrecoverable
|
|
241
|
+
* (genuine post-restart-unknown), in which case the caller keeps the 0 fallback.
|
|
242
|
+
*/
|
|
243
|
+
startedAtMs?: number;
|
|
104
244
|
}
|
|
105
245
|
|
|
106
246
|
type CliPresentationInstance = ProviderInstance & {
|
|
@@ -138,18 +278,19 @@ type CliStartOptions = {
|
|
|
138
278
|
extraEnv?: Record<string, string>;
|
|
139
279
|
};
|
|
140
280
|
|
|
141
|
-
const
|
|
142
|
-
ADHDEV_INLINE_MESH
|
|
143
|
-
ADHDEV_MCP_TRANSPORT
|
|
144
|
-
ADHDEV_MESH_ID
|
|
145
|
-
HERMES_EPHEMERAL_SYSTEM_PROMPT
|
|
146
|
-
|
|
281
|
+
const DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS = [
|
|
282
|
+
'ADHDEV_INLINE_MESH',
|
|
283
|
+
'ADHDEV_MCP_TRANSPORT',
|
|
284
|
+
'ADHDEV_MESH_ID',
|
|
285
|
+
'HERMES_EPHEMERAL_SYSTEM_PROMPT',
|
|
286
|
+
] as const;
|
|
147
287
|
|
|
148
288
|
export interface CoordinatorDelegatedCliLaunchOptionsInput {
|
|
149
289
|
cliType: string;
|
|
150
290
|
workspace: string;
|
|
151
291
|
cliArgs?: string[];
|
|
152
292
|
env?: Record<string, string>;
|
|
293
|
+
isolation?: MeshCoordinatorDelegatedWorkerIsolation;
|
|
153
294
|
}
|
|
154
295
|
|
|
155
296
|
export interface CoordinatorDelegatedCliLaunchOptions {
|
|
@@ -161,10 +302,52 @@ function hasCliArg(args: string[], flag: string): boolean {
|
|
|
161
302
|
return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
162
303
|
}
|
|
163
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Decide the session-registry spawnedAtMs (the native-history session-floor) for a
|
|
307
|
+
* newly registered CLI instance.
|
|
308
|
+
*
|
|
309
|
+
* - Fresh launch (attachExisting=false): now (nowMs). A real live spawn floor
|
|
310
|
+
* isolates a fresh session's own store and holds prior-session leak protection.
|
|
311
|
+
* - Attach WITH a recoverable record startedAt (a PAST timestamp): that startedAt.
|
|
312
|
+
* Restoring a hosted runtime (coordinator / MAGI replica / hermes / claude /
|
|
313
|
+
* codex) after a daemon restart, the real spawn time is in the past. Using it
|
|
314
|
+
* restores each session's per-session birth-floor so co-located antigravity
|
|
315
|
+
* runtimes resolve their OWN conversation (ownerConfirmed) instead of the
|
|
316
|
+
* floor-less newest-by-mtime path that let a replica claim the coordinator's conv.
|
|
317
|
+
* - Attach with NO recoverable startedAt: 0 — disables the floor for this session
|
|
318
|
+
* (recent_window_ms still bounds the look-back). NEVER use nowMs here: nowMs is in
|
|
319
|
+
* the FUTURE relative to existing transcripts and would push the floor past every
|
|
320
|
+
* transcript file, losing them (the ANTIGRAVITY-FINAL-MESSAGE-TAIL-GAP regression).
|
|
321
|
+
*/
|
|
322
|
+
export function resolveHostedSpawnedAtMs(
|
|
323
|
+
attachExisting: boolean,
|
|
324
|
+
attachStartedAtMs: number | undefined,
|
|
325
|
+
nowMs: number,
|
|
326
|
+
): number {
|
|
327
|
+
if (!attachExisting) return nowMs;
|
|
328
|
+
if (typeof attachStartedAtMs === 'number' && attachStartedAtMs > 0) return attachStartedAtMs;
|
|
329
|
+
return 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function hasConfigOverride(args: string[], key: string): boolean {
|
|
333
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
334
|
+
const arg = args[index];
|
|
335
|
+
const next = args[index + 1];
|
|
336
|
+
if ((arg === '-c' || arg === '--config') && typeof next === 'string') {
|
|
337
|
+
if (next === key || next.startsWith(`${key}=`) || next.startsWith(`${key}.`)) return true;
|
|
338
|
+
}
|
|
339
|
+
if (arg.startsWith('--config=')) {
|
|
340
|
+
const value = arg.slice('--config='.length);
|
|
341
|
+
if (value === key || value.startsWith(`${key}=`) || value.startsWith(`${key}.`)) return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
|
|
164
347
|
function ensureEmptyDelegatedMcpConfig(workspace: string): string {
|
|
165
348
|
const baseDir = path.join(os.tmpdir(), 'adhdev-delegated-agent-empty-mcp');
|
|
166
349
|
mkdirSync(baseDir, { recursive: true });
|
|
167
|
-
const workspaceHash =
|
|
350
|
+
const workspaceHash = shortHash(path.resolve(workspace || os.tmpdir()));
|
|
168
351
|
const filePath = path.join(baseDir, `${workspaceHash}.json`);
|
|
169
352
|
writeFileSync(filePath, JSON.stringify({ mcpServers: {} }, null, 2), 'utf-8');
|
|
170
353
|
return filePath;
|
|
@@ -173,12 +356,31 @@ function ensureEmptyDelegatedMcpConfig(workspace: string): string {
|
|
|
173
356
|
export function buildCoordinatorDelegatedCliLaunchOptions(
|
|
174
357
|
input: CoordinatorDelegatedCliLaunchOptionsInput,
|
|
175
358
|
): CoordinatorDelegatedCliLaunchOptions {
|
|
176
|
-
const cliType = String(input.cliType || '').trim();
|
|
177
359
|
const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
|
|
178
|
-
const env: Record<string, string> = { ...(input.env || {})
|
|
360
|
+
const env: Record<string, string> = { ...(input.env || {}) };
|
|
361
|
+
const envUnsets = new Set<string>(DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS);
|
|
362
|
+
for (const key of input.isolation?.env?.unset || []) {
|
|
363
|
+
if (typeof key === 'string' && key.trim()) envUnsets.add(key.trim());
|
|
364
|
+
}
|
|
365
|
+
for (const key of envUnsets) env[key] = '';
|
|
179
366
|
|
|
180
|
-
|
|
181
|
-
|
|
367
|
+
for (const rule of input.isolation?.args || []) {
|
|
368
|
+
if (!rule || typeof rule !== 'object') continue;
|
|
369
|
+
if (rule.mode === 'empty_mcp_config') {
|
|
370
|
+
if (rule.flag && !hasCliArg(cliArgs, rule.flag)) {
|
|
371
|
+
cliArgs.unshift(rule.flag, ensureEmptyDelegatedMcpConfig(input.workspace));
|
|
372
|
+
}
|
|
373
|
+
if (rule.strictFlag && !hasCliArg(cliArgs, rule.strictFlag)) {
|
|
374
|
+
cliArgs.unshift(rule.strictFlag);
|
|
375
|
+
}
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (rule.mode === 'config_override') {
|
|
379
|
+
const key = String(rule.dedupeKey || rule.key || '').trim();
|
|
380
|
+
const flag = String(rule.flag || '').trim();
|
|
381
|
+
if (!key || !flag || hasConfigOverride(cliArgs, key)) continue;
|
|
382
|
+
cliArgs.unshift(flag, `${rule.key}=${rule.value}`);
|
|
383
|
+
}
|
|
182
384
|
}
|
|
183
385
|
|
|
184
386
|
return { cliArgs, env };
|
|
@@ -212,6 +414,18 @@ function expandResumeArgs(template: string[] | undefined, sessionId: string): st
|
|
|
212
414
|
return template.map((part) => part === '{{id}}' ? sessionId : part);
|
|
213
415
|
}
|
|
214
416
|
|
|
417
|
+
/**
|
|
418
|
+
* Expand a provider's `modelLaunchArgs` template with the requested model, mirroring
|
|
419
|
+
* expandResumeArgs. `{{model}}` → the trimmed model string. Returns undefined when
|
|
420
|
+
* there is no template or no model (a model request without a template is a no-op —
|
|
421
|
+
* see startSession, where the caller logs the skip). MAGI kind-panel model axis.
|
|
422
|
+
*/
|
|
423
|
+
function expandModelLaunchArgs(template: string[] | undefined, model: string | undefined): string[] | undefined {
|
|
424
|
+
const m = typeof model === 'string' ? model.trim() : '';
|
|
425
|
+
if (!m || !Array.isArray(template) || template.length === 0) return undefined;
|
|
426
|
+
return template.map((part) => part === '{{model}}' ? m : part);
|
|
427
|
+
}
|
|
428
|
+
|
|
215
429
|
function readSubcommandSessionId(args: string[], subcommands: string[]): string | undefined {
|
|
216
430
|
const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
|
|
217
431
|
if (resumeIndex < 0) return undefined;
|
|
@@ -255,10 +469,14 @@ function detectExplicitProviderSessionId(
|
|
|
255
469
|
|
|
256
470
|
const subcommands = resume?.sessionIdFromSubcommand;
|
|
257
471
|
if (Array.isArray(subcommands) && subcommands.length > 0) {
|
|
472
|
+
const hasResumeSubcommand = args.some((arg) => subcommands.includes(arg));
|
|
258
473
|
const subcommandSessionId = readSubcommandSessionId(args, subcommands);
|
|
259
474
|
if (subcommandSessionId) {
|
|
260
475
|
return { providerSessionId: subcommandSessionId, launchMode: 'resume' };
|
|
261
476
|
}
|
|
477
|
+
if (hasResumeSubcommand) {
|
|
478
|
+
return { launchMode: 'resume' };
|
|
479
|
+
}
|
|
262
480
|
}
|
|
263
481
|
|
|
264
482
|
return { launchMode: 'manual' };
|
|
@@ -292,6 +510,12 @@ export function resolveCliSessionBinding(
|
|
|
292
510
|
launchMode: explicit.launchMode,
|
|
293
511
|
};
|
|
294
512
|
}
|
|
513
|
+
if (explicit.launchMode === 'resume') {
|
|
514
|
+
return {
|
|
515
|
+
cliArgs: baseArgs,
|
|
516
|
+
launchMode: 'resume',
|
|
517
|
+
};
|
|
518
|
+
}
|
|
295
519
|
if (explicit.launchMode === 'manual' && hasArg(baseArgs || [], ['--session-id'])) {
|
|
296
520
|
return {
|
|
297
521
|
cliArgs: baseArgs,
|
|
@@ -399,6 +623,7 @@ export class DaemonCliManager {
|
|
|
399
623
|
cliArgs?: string[],
|
|
400
624
|
providerSessionId?: string,
|
|
401
625
|
attachExisting = false,
|
|
626
|
+
initialMeta?: Record<string, unknown>,
|
|
402
627
|
): PtyTransportFactory | undefined {
|
|
403
628
|
return this.deps.createPtyTransportFactory?.({
|
|
404
629
|
runtimeId,
|
|
@@ -407,6 +632,7 @@ export class DaemonCliManager {
|
|
|
407
632
|
cliArgs,
|
|
408
633
|
providerSessionId,
|
|
409
634
|
attachExisting,
|
|
635
|
+
...(initialMeta && Object.keys(initialMeta).length ? { initialMeta } : {}),
|
|
410
636
|
}) || undefined;
|
|
411
637
|
}
|
|
412
638
|
|
|
@@ -435,7 +661,9 @@ export class DaemonCliManager {
|
|
|
435
661
|
providerSessionId,
|
|
436
662
|
attachExisting,
|
|
437
663
|
);
|
|
438
|
-
|
|
664
|
+
const adapter = new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
665
|
+
if (providerSessionId) adapter.updateRuntimeMeta({ providerSessionId });
|
|
666
|
+
return adapter;
|
|
439
667
|
}
|
|
440
668
|
|
|
441
669
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
@@ -457,6 +685,7 @@ export class DaemonCliManager {
|
|
|
457
685
|
this.deps.removeAgentTracking(key);
|
|
458
686
|
sessionRegistry?.unregisterByInstanceKey(key);
|
|
459
687
|
instanceManager?.removeInstance(key);
|
|
688
|
+
unregisterMeshCoordinator(key);
|
|
460
689
|
LOG.info('CLI', `🧹 Auto-cleaned ${status.status} CLI: ${cliType}`);
|
|
461
690
|
this.deps.onStatusChange();
|
|
462
691
|
}
|
|
@@ -479,6 +708,13 @@ export class DaemonCliManager {
|
|
|
479
708
|
providerSessionId?: string;
|
|
480
709
|
launchMode?: CliLaunchMode;
|
|
481
710
|
extraEnv?: Record<string, string>;
|
|
711
|
+
/**
|
|
712
|
+
* On an attach (attachExisting=true), the real spawn time (ms epoch) of the
|
|
713
|
+
* session-host runtime being restored — a PAST timestamp. Used to restore the
|
|
714
|
+
* native-history session-floor to the runtime's actual birth instead of 0.
|
|
715
|
+
* See the spawnedAtMs computation below. Ignored for fresh launches.
|
|
716
|
+
*/
|
|
717
|
+
attachStartedAtMs?: number;
|
|
482
718
|
onProviderSessionResolved?: (info: {
|
|
483
719
|
instanceId: string;
|
|
484
720
|
providerType: string;
|
|
@@ -492,6 +728,24 @@ export class DaemonCliManager {
|
|
|
492
728
|
const instanceManager = this.deps.getInstanceManager();
|
|
493
729
|
const sessionRegistry = this.deps.getSessionRegistry?.() || null;
|
|
494
730
|
if (!instanceManager) throw new Error('InstanceManager not available');
|
|
731
|
+
|
|
732
|
+
// Launch-time record meta (mesh node binding) — computed BEFORE the
|
|
733
|
+
// transport factory so the session-host record can be seeded with the
|
|
734
|
+
// binding at create_session time (Fix ②, defense-in-depth for
|
|
735
|
+
// SESSION-ACCUMULATION-LEAK), not only via the post-spawn WTDISPATCH
|
|
736
|
+
// updateRuntimeMeta round-trip below. See CliTransportFactoryParams.initialMeta.
|
|
737
|
+
const launchMeshNodeId = typeof settings?.meshNodeId === 'string' ? settings.meshNodeId.trim() : '';
|
|
738
|
+
const launchMeshNodeFor = typeof settings?.meshNodeFor === 'string' ? settings.meshNodeFor.trim() : '';
|
|
739
|
+
const launchAutoLaunchedForQueueTaskId = typeof settings?.autoLaunchedForQueueTaskId === 'string'
|
|
740
|
+
? settings.autoLaunchedForQueueTaskId.trim()
|
|
741
|
+
: '';
|
|
742
|
+
const launchRecordMeta: Record<string, unknown> = {
|
|
743
|
+
...(launchMeshNodeId ? { meshNodeId: launchMeshNodeId } : {}),
|
|
744
|
+
...(launchMeshNodeFor ? { meshNodeFor: launchMeshNodeFor } : {}),
|
|
745
|
+
...(settings?.launchedByCoordinator === true ? { launchedByCoordinator: true } : {}),
|
|
746
|
+
...(launchAutoLaunchedForQueueTaskId ? { autoLaunchedForQueueTaskId: launchAutoLaunchedForQueueTaskId } : {}),
|
|
747
|
+
};
|
|
748
|
+
|
|
495
749
|
const transportFactory = this.getTransportFactory(
|
|
496
750
|
key,
|
|
497
751
|
normalizedType,
|
|
@@ -499,6 +753,9 @@ export class DaemonCliManager {
|
|
|
499
753
|
cliArgs,
|
|
500
754
|
options?.providerSessionId,
|
|
501
755
|
attachExisting,
|
|
756
|
+
// Only seed at create time for fresh launches — an attach restores an
|
|
757
|
+
// existing record whose meta is already stamped; re-seeding could clobber.
|
|
758
|
+
attachExisting ? undefined : launchRecordMeta,
|
|
502
759
|
);
|
|
503
760
|
const cliInstance = new CliProviderInstance(provider, resolvedDir, cliArgs, key, transportFactory, options);
|
|
504
761
|
try {
|
|
@@ -516,6 +773,33 @@ export class DaemonCliManager {
|
|
|
516
773
|
transport: 'pty',
|
|
517
774
|
adapterKey: key,
|
|
518
775
|
instanceKey: key,
|
|
776
|
+
workspace: resolvedDir,
|
|
777
|
+
// attachExisting === true means we're restoring an already-spawned
|
|
778
|
+
// hosted runtime after a daemon restart, not starting a fresh PTY.
|
|
779
|
+
//
|
|
780
|
+
// NEVER use Date.now() for the attach case: the real spawn time is in
|
|
781
|
+
// the PAST, and pinning the floor to now would push the native-history
|
|
782
|
+
// session-floor cutoff past every existing transcript file, so the
|
|
783
|
+
// agy/hermes/claude reader would return null even though the transcript
|
|
784
|
+
// on disk is fresh (the ANTIGRAVITY-FINAL-MESSAGE-TAIL-GAP regression).
|
|
785
|
+
//
|
|
786
|
+
// But collapsing to 0 for EVERY attach is also wrong: with the mesh
|
|
787
|
+
// coordinator + MAGI replicas all running as hosted runtimes sharing one
|
|
788
|
+
// workspace and attached with attachExisting=true, spawnedAtMs=0 disables
|
|
789
|
+
// the per-session native-history birth-floor for all of them. Without a
|
|
790
|
+
// floor, resolveAntigravityPath takes the floor-less newest-by-mtime
|
|
791
|
+
// branch (ownerConfirmed:false) and a replica's read can claim the
|
|
792
|
+
// coordinator's OWN conversation, which then reads as claimedByOther —
|
|
793
|
+
// regressing the coordinator chat to the pty-parser (user-only) path.
|
|
794
|
+
//
|
|
795
|
+
// So when the session-host record's REAL startedAt (a PAST timestamp) is
|
|
796
|
+
// recoverable, use it: the floor lands at the runtime's actual birth, the
|
|
797
|
+
// transcript is still found, AND each session's floor isolates its own
|
|
798
|
+
// conversation. Fall back to 0 ONLY when startedAt is unrecoverable (the
|
|
799
|
+
// genuine post-restart-unknown case) — that preserves the tail-gap
|
|
800
|
+
// protection. Fresh launches still get Date.now() so prior-session leak
|
|
801
|
+
// protection holds.
|
|
802
|
+
spawnedAtMs: resolveHostedSpawnedAtMs(attachExisting, options?.attachStartedAtMs, Date.now()),
|
|
519
803
|
});
|
|
520
804
|
} catch (spawnErr: any) {
|
|
521
805
|
LOG.error('CLI', `[${cliType}] Spawn failed: ${spawnErr?.message}`);
|
|
@@ -524,6 +808,28 @@ export class DaemonCliManager {
|
|
|
524
808
|
}
|
|
525
809
|
|
|
526
810
|
this.adapters.set(key, cliInstance.getAdapter());
|
|
811
|
+
|
|
812
|
+
// WTDISPATCH (no_node_binding): a coordinator-launched worker carries its mesh node
|
|
813
|
+
// binding on the CLI-instance settings, but the session-host RECORD meta was never
|
|
814
|
+
// stamped with it — `updateRuntimeSettings` only mutates in-memory runtime settings and
|
|
815
|
+
// `updateRuntimeMeta` was only ever called with providerSessionId. So mesh_cleanup_sessions
|
|
816
|
+
// matched these worker sessions to a node by workspace ALONE
|
|
817
|
+
// (`live_session_matched_by_workspace_only_no_node_binding`), which on a daemon hosting
|
|
818
|
+
// sibling worktree nodes cannot tell two co-located clones apart. Push the launch-time node
|
|
819
|
+
// binding to the record meta so the record is 1:1 bound to its node (the spawned pty exists
|
|
820
|
+
// by now, so updateMeta reaches the session-host store). Best-effort; guarded.
|
|
821
|
+
//
|
|
822
|
+
// With the spec-CLI updateRuntimeMeta fix (SpecCliAdapter now forwards the FULL
|
|
823
|
+
// meta down to the transport, not just providerSessionId), this stamp finally
|
|
824
|
+
// reaches the session-host record for spec-backed providers too — previously it
|
|
825
|
+
// was silently dropped, which is what let orphans accumulate. launchRecordMeta
|
|
826
|
+
// is hoisted above and also seeds the create_session record via initialMeta.
|
|
827
|
+
if (Object.keys(launchRecordMeta).length) {
|
|
828
|
+
try {
|
|
829
|
+
cliInstance.getAdapter().updateRuntimeMeta?.({ ...launchRecordMeta });
|
|
830
|
+
} catch { /* best-effort — record-meta stamp is cleanup hygiene, not on the dispatch path */ }
|
|
831
|
+
}
|
|
832
|
+
|
|
527
833
|
this.startCliExitMonitor(key, cliType);
|
|
528
834
|
}
|
|
529
835
|
|
|
@@ -556,6 +862,24 @@ export class DaemonCliManager {
|
|
|
556
862
|
|
|
557
863
|
// Create UUID-based key (allows separate instances even for same type+dir)
|
|
558
864
|
const key = crypto.randomUUID();
|
|
865
|
+
|
|
866
|
+
// (3) Session-anchored mesh routing: when launching a mesh COORDINATOR session
|
|
867
|
+
// (settings.meshCoordinatorFor set), expose this session's OWN runtime id to its MCP
|
|
868
|
+
// server via env. The MCP server is spawned by the CLI as a child and inherits this
|
|
869
|
+
// env, so the MCP layer can stamp ADHDEV_COORDINATOR_SESSION_ID as the originating
|
|
870
|
+
// coordinator on every dispatch (→ MeshContext.coordinatorSessionId → worker
|
|
871
|
+
// meshCoordinatorSessionId → completion targetCoordinatorSessionId → strict route).
|
|
872
|
+
// `key` IS the instance id findLiveCoordinators matches on, so the stamp and the live
|
|
873
|
+
// session agree. Re-applied on every (re)launch, so it always reflects the current id;
|
|
874
|
+
// a stale value only survives if the CLI process outlives a daemon restart, in which
|
|
875
|
+
// case routing falls back to the daemon level (no wedge — see mesh-reconcile-loop).
|
|
876
|
+
{
|
|
877
|
+
const coordinatorMeshId = (options?.settingsOverride as Record<string, unknown> | undefined)?.meshCoordinatorFor;
|
|
878
|
+
if (typeof coordinatorMeshId === 'string' && coordinatorMeshId.trim()) {
|
|
879
|
+
options = { ...options, extraEnv: { ...(options?.extraEnv || {}), ADHDEV_COORDINATOR_SESSION_ID: key } };
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
559
883
|
const sessionRegistry = this.deps.getSessionRegistry?.() || null;
|
|
560
884
|
|
|
561
885
|
// ─── ACP category handle ───
|
|
@@ -589,6 +913,7 @@ export class DaemonCliManager {
|
|
|
589
913
|
transport: 'acp',
|
|
590
914
|
adapterKey: key,
|
|
591
915
|
instanceKey: key,
|
|
916
|
+
workspace: resolvedDir,
|
|
592
917
|
});
|
|
593
918
|
|
|
594
919
|
// Register ACP entry in adapter map (getStatus queries from acpInstance in real-time)
|
|
@@ -663,8 +988,23 @@ export class DaemonCliManager {
|
|
|
663
988
|
console.log(colorize('cyan', ` 📦 Using provider: ${provider.name} (${provider.type})`));
|
|
664
989
|
}
|
|
665
990
|
|
|
991
|
+
// ─── Model axis (MAGI kind-panel): expand initialModel → launch args ───
|
|
992
|
+
// For a plain CLI provider the model is selected at spawn time via the manifest's
|
|
993
|
+
// modelLaunchArgs template ('{{model}}' → the requested model). ACP providers took
|
|
994
|
+
// the setConfigOption path above and never reach here. A provider with no template,
|
|
995
|
+
// or no requested model, is a no-op — model selection is best-effort and must never
|
|
996
|
+
// fail a launch. The model args are prepended so a caller's explicit cliArgs (e.g. a
|
|
997
|
+
// resume flag) still win positionally where order matters.
|
|
998
|
+
const modelLaunchArgs = expandModelLaunchArgs(provider?.modelLaunchArgs, initialModel);
|
|
999
|
+
const cliArgsWithModel = modelLaunchArgs
|
|
1000
|
+
? [...modelLaunchArgs, ...(cliArgs || [])]
|
|
1001
|
+
: cliArgs;
|
|
1002
|
+
if (initialModel && !modelLaunchArgs) {
|
|
1003
|
+
LOG.warn('CLI', `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template — launching without model selection.`);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
666
1006
|
// ─── Resolve launch options → provider session binding ───
|
|
667
|
-
const sessionBinding = resolveCliSessionBinding(provider, normalizedType,
|
|
1007
|
+
const sessionBinding = resolveCliSessionBinding(provider, normalizedType, cliArgsWithModel, options?.resumeSessionId);
|
|
668
1008
|
const resolvedCliArgs = sessionBinding.cliArgs;
|
|
669
1009
|
|
|
670
1010
|
// If InstanceManager exists, manage as CliProviderInstance unified
|
|
@@ -783,6 +1123,7 @@ export class DaemonCliManager {
|
|
|
783
1123
|
this.deps.removeAgentTracking(key);
|
|
784
1124
|
this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
|
|
785
1125
|
this.deps.getInstanceManager()?.removeInstance(key);
|
|
1126
|
+
unregisterMeshCoordinator(key);
|
|
786
1127
|
LOG.info('CLI', `🛑 Agent stopped: ${adapter.cliType} in ${adapter.workingDir}`);
|
|
787
1128
|
this.deps.onStatusChange();
|
|
788
1129
|
} else {
|
|
@@ -792,6 +1133,7 @@ export class DaemonCliManager {
|
|
|
792
1133
|
this.deps.getSessionRegistry?.()?.unregisterByInstanceKey(key);
|
|
793
1134
|
im.removeInstance(key);
|
|
794
1135
|
this.deps.removeAgentTracking(key);
|
|
1136
|
+
unregisterMeshCoordinator(key);
|
|
795
1137
|
LOG.warn('CLI', `🧹 Force-removed orphan entry: ${key}`);
|
|
796
1138
|
this.deps.onStatusChange();
|
|
797
1139
|
}
|
|
@@ -819,6 +1161,29 @@ export class DaemonCliManager {
|
|
|
819
1161
|
const restoredBindings = new Set<string>();
|
|
820
1162
|
const managerTag = this.deps.hostedRuntimeManagerTag;
|
|
821
1163
|
|
|
1164
|
+
// CORDBADGE worker-overbind guard pre-pass: the workspace-scoped coordinator
|
|
1165
|
+
// rebind fallback (below) recovers a coordinator's mark when its runtimeId
|
|
1166
|
+
// changed across restart. But a delegated WORKER session that shares the
|
|
1167
|
+
// coordinator's workspace+cliType ALSO misses the exact by-id lookup, so the
|
|
1168
|
+
// fallback would wrongly stamp it with the lone registered coordinator's mesh
|
|
1169
|
+
// mark (the reported bug: a worker shown with role:coordinator after restart).
|
|
1170
|
+
// Two batch-level signals let the fallback refuse to mark a worker:
|
|
1171
|
+
// - restoredRuntimeIds: every runtimeId in this restore batch. If a
|
|
1172
|
+
// registered coordinator's own sessionId appears here, that coordinator is
|
|
1173
|
+
// being restored under its known id (the exact match binds it), so ANY
|
|
1174
|
+
// other same-workspace session is a worker — not the renamed coordinator.
|
|
1175
|
+
// - workspaceTypeCounts: how many sessions in the batch share a
|
|
1176
|
+
// workspace+cliType. >1 means we cannot tell the coordinator from a worker
|
|
1177
|
+
// even if the coordinator's id changed, so we stay unbound (ambiguous).
|
|
1178
|
+
const restoredRuntimeIds = new Set<string>();
|
|
1179
|
+
const workspaceTypeCounts = new Map<string, number>();
|
|
1180
|
+
for (const r of sessions) {
|
|
1181
|
+
if (!r?.runtimeId || !r?.cliType || !r?.workspace) continue;
|
|
1182
|
+
restoredRuntimeIds.add(r.runtimeId);
|
|
1183
|
+
const key = `${r.workspace}::${r.cliType}`;
|
|
1184
|
+
workspaceTypeCounts.set(key, (workspaceTypeCounts.get(key) || 0) + 1);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
822
1187
|
for (const record of sessions) {
|
|
823
1188
|
if (!record?.runtimeId || !record?.cliType || !record?.workspace) continue;
|
|
824
1189
|
if (!shouldRestoreHostedRuntime(record, managerTag)) {
|
|
@@ -852,6 +1217,74 @@ export class DaemonCliManager {
|
|
|
852
1217
|
);
|
|
853
1218
|
continue;
|
|
854
1219
|
}
|
|
1220
|
+
// Re-establish the launch-time settings a fresh launch applies. startSession
|
|
1221
|
+
// seeds every new instance with { ...providerLoader.getSettings(type), ...override };
|
|
1222
|
+
// passing a bare {} here on restart silently dropped TWO launch settings, so a
|
|
1223
|
+
// restored session diverged from a freshly-launched one:
|
|
1224
|
+
// - autoApprove (a provider/machine setting from getSettings) → a restored
|
|
1225
|
+
// coordinator self-session lost auto-approve and re-prompted on every tool call.
|
|
1226
|
+
// - meshCoordinatorFor (the coordinator launch's settingsOverride) → the restored
|
|
1227
|
+
// session was no longer recognized as this daemon's live CLI coordinator by
|
|
1228
|
+
// findLiveCoordinators (so pending mesh events stopped draining into its PTY) nor
|
|
1229
|
+
// surfaced with the coordinator badge via settings. The persisted coordinator
|
|
1230
|
+
// registry (loaded on boot) is the source of truth to rebuild that mark.
|
|
1231
|
+
// Both restores are provider-agnostic — getSettings is keyed by provider type and the
|
|
1232
|
+
// registry mark is type-independent.
|
|
1233
|
+
const restoredSettings: Record<string, any> = { ...this.providerLoader.getSettings(normalizedType) };
|
|
1234
|
+
// Primary rebind: exact persisted-registry match by runtimeId (stable across
|
|
1235
|
+
// restart, see session-host runtimeId = runtimeRecord.sessionId).
|
|
1236
|
+
let coordinatorEntry = getCoordinatorForSession(record.runtimeId);
|
|
1237
|
+
// CORDBADGE fallback: the by-id match misses when a coordinator's runtime
|
|
1238
|
+
// re-attaches under a different runtimeId than the one it was registered with
|
|
1239
|
+
// (the registry survived, but its key no longer lines up). Without a rebind the
|
|
1240
|
+
// restored session silently loses meshCoordinatorFor → the coordinator badge and
|
|
1241
|
+
// selfIdentification block vanish and pending mesh events stop draining into its
|
|
1242
|
+
// PTY, and the only recovery is a manual coordinator restart. Recover the mark
|
|
1243
|
+
// from the persisted registry scoped to this exact workspace, but ONLY when it is
|
|
1244
|
+
// UNAMBIGUOUS: exactly one registered coordinator for this workspace AND its
|
|
1245
|
+
// cliType matches the restored session's type.
|
|
1246
|
+
//
|
|
1247
|
+
// WORKER-OVERBIND guard: "exactly one registered coordinator" is NOT enough —
|
|
1248
|
+
// a delegated worker session sharing the coordinator's workspace+cliType also
|
|
1249
|
+
// misses the by-id lookup, and the registry holding only the (single) real
|
|
1250
|
+
// coordinator does NOT stop the fallback from projecting that coordinator's
|
|
1251
|
+
// mark onto the worker record. So before adopting the mark we positively rule
|
|
1252
|
+
// the worker out:
|
|
1253
|
+
// (a) coordinatorPresentById — the registered coordinator's own sessionId is
|
|
1254
|
+
// in this restore batch, i.e. it is being restored under its known id and
|
|
1255
|
+
// the exact match already binds it. Then THIS record (which missed) is a
|
|
1256
|
+
// worker, not the renamed coordinator → do not rebind.
|
|
1257
|
+
// (b) siblingCount > 1 — more than one session shares this workspace+cliType,
|
|
1258
|
+
// so even if the coordinator's id changed we cannot tell it from a worker
|
|
1259
|
+
// → stay unbound (ambiguous).
|
|
1260
|
+
// Anything ambiguous stays unbound (we would rather miss a badge than
|
|
1261
|
+
// mis-attribute one).
|
|
1262
|
+
if (!coordinatorEntry?.meshId && record.workspace) {
|
|
1263
|
+
const workspaceCoordinators = listCoordinatorsForWorkspace(record.workspace)
|
|
1264
|
+
.filter(e => e.meshId && (!e.cliType || e.cliType === record.cliType));
|
|
1265
|
+
if (workspaceCoordinators.length === 1) {
|
|
1266
|
+
const candidate = workspaceCoordinators[0];
|
|
1267
|
+
const coordinatorPresentById = !!candidate.sessionId && restoredRuntimeIds.has(candidate.sessionId);
|
|
1268
|
+
const siblingCount = workspaceTypeCounts.get(`${record.workspace}::${record.cliType}`) || 1;
|
|
1269
|
+
if (!coordinatorPresentById && siblingCount === 1) {
|
|
1270
|
+
coordinatorEntry = candidate;
|
|
1271
|
+
LOG.info(
|
|
1272
|
+
'CLI',
|
|
1273
|
+
`↻ Rebound coordinator mark by workspace for ${record.runtimeKey || record.runtimeId} (mesh ${candidate.meshId} @ ${record.workspace}); registry key did not match runtimeId`
|
|
1274
|
+
);
|
|
1275
|
+
} else {
|
|
1276
|
+
LOG.info(
|
|
1277
|
+
'CLI',
|
|
1278
|
+
`↷ Skipping workspace coordinator rebind for ${record.runtimeKey || record.runtimeId} (${record.cliType} @ ${record.workspace}): ${coordinatorPresentById
|
|
1279
|
+
? 'registered coordinator is restoring under its own id — this is a delegated worker'
|
|
1280
|
+
: `ambiguous (${siblingCount} sessions share this workspace+cliType)`}`
|
|
1281
|
+
);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
if (coordinatorEntry?.meshId) {
|
|
1286
|
+
restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
|
|
1287
|
+
}
|
|
855
1288
|
try {
|
|
856
1289
|
await this.registerCliInstance(
|
|
857
1290
|
record.runtimeId,
|
|
@@ -860,11 +1293,17 @@ export class DaemonCliManager {
|
|
|
860
1293
|
record.workspace,
|
|
861
1294
|
record.cliArgs,
|
|
862
1295
|
resolvedProvider,
|
|
863
|
-
|
|
1296
|
+
restoredSettings,
|
|
864
1297
|
true,
|
|
865
1298
|
{
|
|
866
1299
|
providerSessionId: sessionBinding.providerSessionId,
|
|
867
1300
|
launchMode: 'manual',
|
|
1301
|
+
// Thread the runtime's REAL past spawn time so the attach restores
|
|
1302
|
+
// the per-session native-history birth-floor instead of collapsing
|
|
1303
|
+
// to spawnedAtMs:0 (which disabled the antigravity per-session floor
|
|
1304
|
+
// and let MAGI replicas claim the coordinator's own conversation).
|
|
1305
|
+
// Undefined → registerCliInstance keeps the 0 fallback.
|
|
1306
|
+
attachStartedAtMs: record.startedAtMs,
|
|
868
1307
|
},
|
|
869
1308
|
);
|
|
870
1309
|
restoredBindings.add(bindingKey);
|
|
@@ -899,18 +1338,36 @@ export class DaemonCliManager {
|
|
|
899
1338
|
const adapter = this.adapters.get(ik);
|
|
900
1339
|
if (adapter) return { adapter, key: ik };
|
|
901
1340
|
}
|
|
902
|
-
// 1. agentType + dir match
|
|
903
|
-
|
|
1341
|
+
// 1. agentType + dir match.
|
|
1342
|
+
// FAIL-CLOSED when an explicit instanceKey/targetSessionId was named (step 0) but
|
|
1343
|
+
// did not resolve: the caller pinned a SPECIFIC session, so healing by workspace must
|
|
1344
|
+
// not silently redirect the command into a co-located SIBLING worktree session. The
|
|
1345
|
+
// remote mesh relay (ipcDispatchToRemoteAgent) carries `dir: node.workspace` alongside
|
|
1346
|
+
// targetSessionId for the sessionless-scope case; when a session WAS named, that dir
|
|
1347
|
+
// fallback is the WTDISPATCH-FANOUT (a) leak — a stale/relaunched session_id would
|
|
1348
|
+
// dir-match whatever session lives in that workspace instead of failing. The sessionless
|
|
1349
|
+
// node-scoped path uses findMeshNodeAdapter, not this fallback, so gating dir on
|
|
1350
|
+
// !instanceKey loses no legitimate routing. Mirror step 2's fail-closed rule.
|
|
1351
|
+
if (opts?.dir && !opts?.instanceKey) {
|
|
904
1352
|
for (const [k, a] of this.adapters) {
|
|
905
1353
|
if (a.cliType === agentType && a.workingDir === opts.dir) {
|
|
906
1354
|
return { adapter: a, key: k };
|
|
907
1355
|
}
|
|
908
1356
|
}
|
|
909
1357
|
}
|
|
910
|
-
// 2. Fuzzy match (returns first of multiple sessions — may be inaccurate)
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1358
|
+
// 2. Fuzzy match (returns first of multiple sessions — may be inaccurate).
|
|
1359
|
+
// FAIL-CLOSED: only when NO explicit instanceKey/targetSessionId was requested.
|
|
1360
|
+
// When a specific session WAS named (step 0) but is not hosted on this daemon,
|
|
1361
|
+
// falling back to the first same-cliType adapter silently redirects the command
|
|
1362
|
+
// into an UNRELATED session — e.g. a relayed/misrouted mesh send_chat lands in the
|
|
1363
|
+
// coordinator's own CLI session, echoing the dispatched task body back to the
|
|
1364
|
+
// coordinator (TASKECHO self-inject). Returning null instead makes the caller
|
|
1365
|
+
// surface an explicit "not running" error rather than mis-delivering the message.
|
|
1366
|
+
if (!opts?.instanceKey) {
|
|
1367
|
+
for (const [k, a] of this.adapters) {
|
|
1368
|
+
if (a.cliType === agentType) {
|
|
1369
|
+
return { adapter: a, key: k };
|
|
1370
|
+
}
|
|
914
1371
|
}
|
|
915
1372
|
}
|
|
916
1373
|
return null;
|
|
@@ -925,6 +1382,40 @@ export class DaemonCliManager {
|
|
|
925
1382
|
return adapter ? { adapter, key: ik } : null;
|
|
926
1383
|
}
|
|
927
1384
|
|
|
1385
|
+
/**
|
|
1386
|
+
* WTCLAIM (B): resolve the adapter for a mesh dispatch that named a node
|
|
1387
|
+
* (meshContext.nodeId) but carried no explicit session. Matches by the
|
|
1388
|
+
* instance's bound mesh node id (settings.meshNodeId, falling back to the
|
|
1389
|
+
* sticky meshLastNodeId) first, then by the node workspace (workingDir).
|
|
1390
|
+
*
|
|
1391
|
+
* Unlike findAdapter's step-2 fuzzy fallback, this NEVER degrades to a
|
|
1392
|
+
* provider-only first-match: on a daemon hosting BOTH a base node and a
|
|
1393
|
+
* cloned worktree node (same daemonId), that fuzzy match could land a
|
|
1394
|
+
* worktree-targeted task on the base session. Returns null when no session
|
|
1395
|
+
* is bound to this node so the caller fails closed.
|
|
1396
|
+
*/
|
|
1397
|
+
private findMeshNodeAdapter(agentType: string, nodeId: string, dir?: string): { adapter: CliAdapter; key: string } | null {
|
|
1398
|
+
const instanceManager = this.deps.getInstanceManager();
|
|
1399
|
+
const targetDir = normalizeDirForCompare(dir);
|
|
1400
|
+
let workspaceMatch: { adapter: CliAdapter; key: string } | null = null;
|
|
1401
|
+
for (const [k, a] of this.adapters) {
|
|
1402
|
+
if (a.cliType !== agentType) continue;
|
|
1403
|
+
const settings = (instanceManager?.getInstance(k) as any)?.getState?.()?.settings as Record<string, unknown> | undefined;
|
|
1404
|
+
const boundNodeId = (typeof settings?.meshNodeId === 'string' && settings.meshNodeId.trim())
|
|
1405
|
+
? settings.meshNodeId.trim()
|
|
1406
|
+
: (typeof settings?.meshLastNodeId === 'string' ? settings.meshLastNodeId.trim() : '');
|
|
1407
|
+
// Exact node binding wins immediately (most precise).
|
|
1408
|
+
if (boundNodeId && boundNodeId === nodeId) return { adapter: a, key: k };
|
|
1409
|
+
// Workspace identity is the secondary signal for a session not (yet)
|
|
1410
|
+
// stamped with a node id — a base node and a worktree clone always have
|
|
1411
|
+
// distinct workspaces, so this still separates them.
|
|
1412
|
+
if (!workspaceMatch && targetDir && normalizeDirForCompare(a.workingDir) === targetDir) {
|
|
1413
|
+
workspaceMatch = { adapter: a, key: k };
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return workspaceMatch;
|
|
1417
|
+
}
|
|
1418
|
+
|
|
928
1419
|
// ─── CLI command handling ────────────────────────────
|
|
929
1420
|
|
|
930
1421
|
async handleCliCommand(cmd: string, args: any): Promise<CommandResult | null> {
|
|
@@ -955,6 +1446,8 @@ export class DaemonCliManager {
|
|
|
955
1446
|
const launchSource = resolved.source;
|
|
956
1447
|
if (!cliType) throw new Error('cliType required');
|
|
957
1448
|
|
|
1449
|
+
const providerType = this.providerLoader.resolveAlias(cliType);
|
|
1450
|
+
const provLookup = this.providerLoader.getMeta(providerType) as ProviderModule | undefined;
|
|
958
1451
|
const settingsOverride = args?.settings && typeof args.settings === 'object' ? args.settings : undefined;
|
|
959
1452
|
const delegatedLaunch = settingsOverride?.launchedByCoordinator === true
|
|
960
1453
|
? buildCoordinatorDelegatedCliLaunchOptions({
|
|
@@ -962,8 +1455,28 @@ export class DaemonCliManager {
|
|
|
962
1455
|
workspace: dir,
|
|
963
1456
|
cliArgs: args?.cliArgs,
|
|
964
1457
|
env: args?.env,
|
|
1458
|
+
isolation: provLookup?.meshCoordinator?.delegatedWorkerIsolation,
|
|
965
1459
|
})
|
|
966
1460
|
: null;
|
|
1461
|
+
// Untrusted-provider gate: an external source that ships JS
|
|
1462
|
+
// hooks needs explicit user confirmation before its first
|
|
1463
|
+
// launch. Dashboards add `confirmExternalUntrusted: true` to
|
|
1464
|
+
// the launch args after showing the trust modal. Without
|
|
1465
|
+
// that ack we refuse to spawn and tell the caller why.
|
|
1466
|
+
const provMeta = provLookup as any;
|
|
1467
|
+
const provTrust = provMeta?._sourceTrust;
|
|
1468
|
+
if (provTrust === 'external-untrusted' && args?.confirmExternalUntrusted !== true) {
|
|
1469
|
+
return {
|
|
1470
|
+
success: false,
|
|
1471
|
+
error: 'untrusted_external_provider',
|
|
1472
|
+
provider: {
|
|
1473
|
+
type: provLookup?.type ?? cliType,
|
|
1474
|
+
sourceName: provMeta?._sourceName ?? null,
|
|
1475
|
+
trust: provTrust,
|
|
1476
|
+
},
|
|
1477
|
+
hint: 'Resend launch_cli with confirmExternalUntrusted=true after the user explicitly approves running JavaScript from this 3rd-party source.',
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
967
1480
|
const started = await this.startSession(
|
|
968
1481
|
cliType,
|
|
969
1482
|
dir,
|
|
@@ -1030,6 +1543,45 @@ export class DaemonCliManager {
|
|
|
1030
1543
|
this.deps.onStatusChange();
|
|
1031
1544
|
return { success: true, id: found.key, mode };
|
|
1032
1545
|
}
|
|
1546
|
+
case 'record_provider_pty': {
|
|
1547
|
+
const cliType = args?.type || args?.cliType;
|
|
1548
|
+
if (!cliType) {
|
|
1549
|
+
return { success: false, error: '`type` (provider type) is required', code: 'MISSING_TYPE' };
|
|
1550
|
+
}
|
|
1551
|
+
const targetSessionId = typeof args?.targetSessionId === 'string' ? args.targetSessionId : '';
|
|
1552
|
+
const dir = args?.dir || '';
|
|
1553
|
+
const found = (targetSessionId ? this.findAdapterBySessionId(targetSessionId) : null)
|
|
1554
|
+
|| this.findAdapter(cliType, { instanceKey: targetSessionId, dir });
|
|
1555
|
+
if (!found) {
|
|
1556
|
+
return {
|
|
1557
|
+
success: false,
|
|
1558
|
+
error: `No running ${cliType} session. Launch one first (adhdev launch ${cliType}) or pass --target-session-id.`,
|
|
1559
|
+
code: 'NO_RUNNING_SESSION',
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
const instance = this.deps.getInstanceManager()?.getInstance(found.key);
|
|
1563
|
+
if (!(instance instanceof CliProviderInstance)) {
|
|
1564
|
+
return { success: false, error: 'CLI instance not available', code: 'CLI_INSTANCE_NOT_FOUND' };
|
|
1565
|
+
}
|
|
1566
|
+
const adapter = instance.getAdapter();
|
|
1567
|
+
if (!adapter || typeof (adapter as any).getAccumulatedRawBuffer !== 'function') {
|
|
1568
|
+
return { success: false, error: 'Adapter does not expose PTY buffer', code: 'ADAPTER_NOT_RECORDABLE' };
|
|
1569
|
+
}
|
|
1570
|
+
const buffer = (adapter as any).getAccumulatedRawBuffer() as { text: string; droppedChars: number };
|
|
1571
|
+
const maxBytes = Number(args?.maxBytes) > 0 ? Number(args.maxBytes) : 262144;
|
|
1572
|
+
const truncated = buffer.text.length > maxBytes;
|
|
1573
|
+
const ptyBytes = truncated ? buffer.text.slice(-maxBytes) : buffer.text;
|
|
1574
|
+
return {
|
|
1575
|
+
success: true,
|
|
1576
|
+
cliType,
|
|
1577
|
+
sessionId: found.key,
|
|
1578
|
+
ptyBytes,
|
|
1579
|
+
bytes: ptyBytes.length,
|
|
1580
|
+
truncated,
|
|
1581
|
+
droppedChars: buffer.droppedChars,
|
|
1582
|
+
capturedAt: Date.now(),
|
|
1583
|
+
};
|
|
1584
|
+
}
|
|
1033
1585
|
case 'restart_session': {
|
|
1034
1586
|
const cliType = args?.cliType || args?.agentType || args?.ideType;
|
|
1035
1587
|
const cfg = loadConfig();
|
|
@@ -1065,14 +1617,64 @@ export class DaemonCliManager {
|
|
|
1065
1617
|
const action = args?.action;
|
|
1066
1618
|
if (!agentType || !action) throw new Error('agentType and action required');
|
|
1067
1619
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1620
|
+
// WTCLAIM (B): a mesh dispatch that named a node (meshContext.nodeId)
|
|
1621
|
+
// but resolved no explicit session must be scoped to THAT node's
|
|
1622
|
+
// session — never routed by findAdapter's provider-only fuzzy fallback,
|
|
1623
|
+
// which on a daemon hosting both a base node and a cloned worktree node
|
|
1624
|
+
// (same daemonId) could land a worktree task on the base session. Fail
|
|
1625
|
+
// closed when no session is bound to the node so the coordinator
|
|
1626
|
+
// launches/retries instead of mis-landing the work.
|
|
1627
|
+
const meshScopeNodeId = (() => {
|
|
1628
|
+
const mc = (args as any)?.meshContext;
|
|
1629
|
+
return mc && typeof mc === 'object' && typeof mc.nodeId === 'string' ? mc.nodeId.trim() : '';
|
|
1630
|
+
})();
|
|
1631
|
+
let found: { adapter: CliAdapter; key: string } | null;
|
|
1632
|
+
if (meshScopeNodeId && !args?.targetSessionId) {
|
|
1633
|
+
found = this.findMeshNodeAdapter(agentType, meshScopeNodeId, args?.dir);
|
|
1634
|
+
if (!found) {
|
|
1635
|
+
throw new Error(`No mesh worker session bound to node '${meshScopeNodeId}' for agent '${agentType}' on this daemon; refusing provider-only fuzzy match to avoid cross-node dispatch`);
|
|
1636
|
+
}
|
|
1637
|
+
} else {
|
|
1638
|
+
found = this.findAdapter(agentType, {
|
|
1639
|
+
dir: args?.dir,
|
|
1640
|
+
instanceKey: args?.targetSessionId,
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1072
1643
|
if (!found) throw new Error(`CLI agent not running: ${agentType}`);
|
|
1073
1644
|
const { adapter, key } = found;
|
|
1074
1645
|
|
|
1075
1646
|
if (action === 'send_chat') {
|
|
1647
|
+
let currentStatus = getEffectiveAgentSendStatus(adapter);
|
|
1648
|
+
if (currentStatus === 'starting' && await waitForZeroMessageStartingLaunch(adapter)) {
|
|
1649
|
+
currentStatus = 'idle';
|
|
1650
|
+
} else if (currentStatus === 'starting') {
|
|
1651
|
+
currentStatus = getEffectiveAgentSendStatus(adapter);
|
|
1652
|
+
}
|
|
1653
|
+
// Stamp mesh direct-dispatch assignment on the target
|
|
1654
|
+
// instance BEFORE sending the prompt so the completion
|
|
1655
|
+
// event has a routing marker by the time it fires.
|
|
1656
|
+
// mesh_send_task --direct ships meshContext for plain CLI
|
|
1657
|
+
// sessions that were never launched as mesh delegates.
|
|
1658
|
+
const meshContext = (args as any)?.meshContext;
|
|
1659
|
+
if (meshContext && typeof meshContext === 'object' && typeof meshContext.meshId === 'string' && meshContext.meshId) {
|
|
1660
|
+
const targetInstanceId = key;
|
|
1661
|
+
let stampResult: { stamped: boolean; reason?: string } | undefined;
|
|
1662
|
+
try {
|
|
1663
|
+
stampResult = this.deps.getInstanceManager()?.attachMeshAssignmentToInstance(targetInstanceId, {
|
|
1664
|
+
meshId: meshContext.meshId,
|
|
1665
|
+
...(typeof meshContext.nodeId === 'string' && meshContext.nodeId ? { nodeId: meshContext.nodeId } : {}),
|
|
1666
|
+
...(typeof meshContext.taskId === 'string' && meshContext.taskId ? { taskId: meshContext.taskId } : {}),
|
|
1667
|
+
...(typeof meshContext.coordinatorDaemonId === 'string' && meshContext.coordinatorDaemonId ? { coordinatorDaemonId: meshContext.coordinatorDaemonId } : {}),
|
|
1668
|
+
});
|
|
1669
|
+
} catch { /* best-effort — stamping is a routing aid, not a hard requirement */ }
|
|
1670
|
+
// DOUBLE-DISPATCH stamp guard: the instance manager refused this stamp because
|
|
1671
|
+
// the SAME task is already running on another live session on this daemon.
|
|
1672
|
+
// Sending the prompt anyway would double-execute the task — fail closed so the
|
|
1673
|
+
// coordinator does not duplicate the work onto a second session.
|
|
1674
|
+
if (stampResult && stampResult.stamped === false && stampResult.reason === 'task_already_stamped_on_live_instance') {
|
|
1675
|
+
throw new Error(`Refusing duplicate mesh dispatch: task ${meshContext.taskId} is already being worked by a live session on this daemon`);
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1076
1678
|
const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
|
|
1077
1679
|
const provider = this.providerLoader.resolve(agentType) || this.providerLoader.getMeta(agentType);
|
|
1078
1680
|
if (provider?.category === 'acp') {
|
|
@@ -1082,8 +1684,38 @@ export class DaemonCliManager {
|
|
|
1082
1684
|
}
|
|
1083
1685
|
const message = input.textFallback;
|
|
1084
1686
|
if (!message) throw new Error('message required for send_chat');
|
|
1085
|
-
|
|
1086
|
-
|
|
1687
|
+
// ARCH-REFACTOR R1: thread the dispatched task's id into the turn so the
|
|
1688
|
+
// worker's completion event is bound to THIS task (per-turn identity),
|
|
1689
|
+
// not the last-write-wins session scalar. Carried for both local and
|
|
1690
|
+
// remote (P2P-echoed meshContext) dispatch; absent for plain ad-hoc chat.
|
|
1691
|
+
const meshTaskId = (meshContext && typeof meshContext === 'object'
|
|
1692
|
+
&& typeof (meshContext as any).taskId === 'string' && (meshContext as any).taskId.trim())
|
|
1693
|
+
? (meshContext as any).taskId as string
|
|
1694
|
+
: undefined;
|
|
1695
|
+
const forceSend = args?.force === true || args?.forceSend === true;
|
|
1696
|
+
// Preserve the exact prior call shape when there is no taskId (plain
|
|
1697
|
+
// ad-hoc chat / non-mesh dispatch); only thread the per-turn taskId when
|
|
1698
|
+
// present, so existing non-mesh callers and their contracts are unchanged.
|
|
1699
|
+
if (forceSend && typeof (adapter as any).forceSendMessage === 'function') {
|
|
1700
|
+
if (meshTaskId) await (adapter as any).forceSendMessage(message, meshTaskId);
|
|
1701
|
+
else await (adapter as any).forceSendMessage(message);
|
|
1702
|
+
} else if (forceSend) {
|
|
1703
|
+
await adapter.sendMessage(message, meshTaskId ? { force: true, meshTaskId } : { force: true });
|
|
1704
|
+
} else if (meshTaskId) {
|
|
1705
|
+
await adapter.sendMessage(message, { meshTaskId });
|
|
1706
|
+
} else {
|
|
1707
|
+
await adapter.sendMessage(message);
|
|
1708
|
+
}
|
|
1709
|
+
const targetInstance = this.deps.getInstanceManager()?.getInstance(key) as
|
|
1710
|
+
| { recordAcknowledgedUserInput?: (input: unknown) => void }
|
|
1711
|
+
| undefined;
|
|
1712
|
+
targetInstance?.recordAcknowledgedUserInput?.(input);
|
|
1713
|
+
return {
|
|
1714
|
+
success: true,
|
|
1715
|
+
status: BUSY_AGENT_STATUSES.has(currentStatus) ? currentStatus : 'generating',
|
|
1716
|
+
...(BUSY_AGENT_STATUSES.has(currentStatus) ? { queued: true, queuedReason: 'agent_runtime_busy' } : {}),
|
|
1717
|
+
...(forceSend ? { forceSent: true, queued: false } : {}),
|
|
1718
|
+
};
|
|
1087
1719
|
} else if (action === 'clear_history') {
|
|
1088
1720
|
if (typeof adapter.clearHistory === 'function') adapter.clearHistory();
|
|
1089
1721
|
return { success: true, cleared: true };
|