@adhdev/daemon-core 0.9.82-rc.43 → 0.9.82-rc.430
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boot/daemon-lifecycle.d.ts +9 -0
- package/dist/boot/process-hardening.d.ts +50 -0
- package/dist/build-info.d.ts +37 -0
- package/dist/chat/source-machine.d.ts +166 -0
- package/dist/chat/source-resolver.d.ts +104 -0
- package/dist/chat/subscription-updates.d.ts +1 -0
- package/dist/cli-adapter-types.d.ts +68 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +200 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +126 -64
- package/dist/cli-adapters/provider-cli-parse.d.ts +5 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +74 -0
- package/dist/cli-adapters/pty-write-chunking.d.ts +34 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +69 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
- package/dist/cli-adapters/terminal-screen.d.ts +4 -11
- package/dist/commands/chat-commands-debug-bundle.d.ts +14 -0
- package/dist/commands/chat-commands-read.d.ts +7 -0
- package/dist/commands/chat-commands-scope.d.ts +39 -0
- package/dist/commands/chat-commands-shared.d.ts +33 -0
- package/dist/commands/chat-commands-write.d.ts +14 -0
- package/dist/commands/chat-commands.d.ts +10 -23
- package/dist/commands/cli-manager.d.ts +15 -1
- package/dist/commands/handler.d.ts +125 -0
- package/dist/commands/high-family/index.d.ts +3 -0
- package/dist/commands/high-family/mesh-coordinator-launch.d.ts +2 -0
- package/dist/commands/high-family/mesh-events.d.ts +2 -0
- package/dist/commands/high-family/mesh-status.d.ts +2 -0
- package/dist/commands/high-family/types.d.ts +60 -0
- package/dist/commands/low-family/coordinator-prompt.d.ts +9 -0
- package/dist/commands/low-family/daemon-lifecycle.d.ts +2 -0
- package/dist/commands/low-family/diagnostics.d.ts +2 -0
- package/dist/commands/low-family/index.d.ts +3 -0
- package/dist/commands/low-family/mesh-ledger.d.ts +10 -0
- package/dist/commands/low-family/mesh-node-logs.d.ts +2 -0
- package/dist/commands/low-family/notification.d.ts +2 -0
- package/dist/commands/low-family/refine-config.d.ts +2 -0
- package/dist/commands/low-family/session-host.d.ts +2 -0
- package/dist/commands/low-family/spec-providerdev.d.ts +11 -0
- package/dist/commands/low-family/status-meta.d.ts +2 -0
- package/dist/commands/low-family/types.d.ts +33 -0
- package/dist/commands/med-family/cli-agent.d.ts +2 -0
- package/dist/commands/med-family/fast-forward.d.ts +2 -0
- package/dist/commands/med-family/ide.d.ts +10 -0
- package/dist/commands/med-family/index.d.ts +3 -0
- package/dist/commands/med-family/mesh-crud.d.ts +29 -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 +142 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router.d.ts +276 -2
- package/dist/commands/upgrade-helper.d.ts +41 -1
- package/dist/config/chat-history.d.ts +9 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/mesh-config.d.ts +100 -1
- package/dist/config/mesh-json-config.d.ts +199 -0
- package/dist/config/repo-settings.d.ts +77 -0
- package/dist/daemon/dev-server.d.ts +0 -2
- package/dist/detection/ide-detector.d.ts +13 -0
- package/dist/detection/win32-ide-version.d.ts +37 -0
- package/dist/git/change-impact-config.d.ts +159 -0
- package/dist/git/git-commands.d.ts +11 -1
- package/dist/git/git-diff.d.ts +6 -0
- package/dist/git/git-executor.d.ts +11 -0
- package/dist/git/git-status.d.ts +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 +64 -14
- package/dist/index.js +49391 -19228
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48574 -18570
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/ipc/local-ipc-server.d.ts +91 -0
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/logging/log-redactor.d.ts +24 -0
- package/dist/logging/log-tail-reader.d.ts +81 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/contracts.d.ts +164 -0
- package/dist/mesh/coordinator-prompt.d.ts +89 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +174 -0
- package/dist/mesh/mesh-clone-grace.d.ts +8 -0
- package/dist/mesh/mesh-coordinator-config.d.ts +21 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-event-classify.d.ts +5 -0
- package/dist/mesh/mesh-event-forwarding.d.ts +41 -0
- package/dist/mesh/mesh-event-trace.d.ts +21 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +4 -0
- package/dist/mesh/mesh-events-pending.d.ts +69 -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 +9 -0
- package/dist/mesh/mesh-init.d.ts +86 -0
- package/dist/mesh/mesh-ledger-reconciliation.d.ts +23 -4
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-magi-status.d.ts +63 -0
- package/dist/mesh/mesh-missions.d.ts +189 -0
- package/dist/mesh/mesh-node-identity.d.ts +289 -0
- package/dist/mesh/mesh-queue-assignment.d.ts +113 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +65 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -0
- package/dist/mesh/mesh-refine-gates.d.ts +428 -0
- package/dist/mesh/mesh-refine-status.d.ts +62 -0
- package/dist/mesh/mesh-review-inbox.d.ts +90 -0
- package/dist/mesh/mesh-routing.d.ts +70 -0
- package/dist/mesh/mesh-runtime-store.d.ts +450 -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 +290 -5
- package/dist/mesh/preview-freshness.d.ts +18 -0
- package/dist/mesh/refine-config.d.ts +216 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +145 -0
- package/dist/providers/acp-provider-instance.d.ts +5 -0
- package/dist/providers/approval-utils.d.ts +20 -0
- package/dist/providers/chat-message-normalization.d.ts +31 -1
- package/dist/providers/cli-provider-instance.d.ts +221 -3
- package/dist/providers/contracts.d.ts +139 -6
- package/dist/providers/external-sources.d.ts +71 -0
- package/dist/providers/manual-attendance.d.ts +63 -0
- package/dist/providers/native-history/antigravity-cli-transcript.d.ts +100 -0
- package/dist/providers/native-history/claude-cli-transcript.d.ts +70 -0
- package/dist/providers/native-history/codex-cli-transcript.d.ts +73 -0
- package/dist/providers/native-history/constants.d.ts +12 -0
- package/dist/providers/native-history/dispatcher.d.ts +27 -0
- package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
- package/dist/providers/native-history/index.d.ts +13 -0
- package/dist/providers/provider-instance-manager.d.ts +29 -0
- package/dist/providers/provider-instance.d.ts +23 -1
- package/dist/providers/provider-loader.d.ts +26 -4
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +91 -0
- package/dist/providers/spec/cli-adapter.d.ts +223 -0
- package/dist/providers/spec/evaluator.d.ts +45 -0
- package/dist/providers/spec/fsm-driver.d.ts +422 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +174 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +222 -0
- package/dist/providers/status-monitor.d.ts +7 -7
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +84 -0
- package/dist/providers/working-dir.d.ts +17 -0
- package/dist/repo-mesh-types.d.ts +501 -13
- package/dist/runtime-defaults.d.ts +2 -0
- package/dist/sessions/registry.d.ts +6 -0
- package/dist/shared-types-extra.d.ts +2 -4
- package/dist/shared-types.d.ts +59 -2
- package/dist/status/normalize.d.ts +1 -1
- package/dist/status/normalize.js +1 -0
- package/dist/status/normalize.js.map +1 -1
- package/dist/status/normalize.mjs +1 -0
- package/dist/status/normalize.mjs.map +1 -1
- package/dist/status/reporter.d.ts +2 -0
- package/dist/status/snapshot.d.ts +26 -0
- package/dist/system/hash.d.ts +8 -0
- package/dist/system/load-better-sqlite3.d.ts +21 -0
- package/dist/types.d.ts +5 -0
- package/package.json +7 -3
- package/src/agent-stream/poller.ts +2 -3
- package/src/agent-stream/provider-adapter.ts +1 -1
- package/src/boot/daemon-lifecycle.ts +63 -12
- package/src/boot/process-hardening.ts +89 -0
- package/src/build-info.ts +73 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +3 -1
- package/src/cli-adapter-types.ts +68 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1246 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +914 -1144
- package/src/cli-adapters/provider-cli-parse.d.ts +2 -0
- package/src/cli-adapters/provider-cli-parse.ts +19 -0
- package/src/cli-adapters/provider-cli-runtime.ts +56 -7
- package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
- package/src/cli-adapters/provider-cli-shared.ts +121 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/pty-write-chunking.ts +106 -0
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +204 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +63 -29
- package/src/cli-adapters/terminal-backends/types.ts +10 -3
- package/src/cli-adapters/terminal-screen.ts +16 -81
- package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
- package/src/commands/chat-commands-debug-bundle.ts +398 -0
- package/src/commands/chat-commands-read.ts +2327 -0
- package/src/commands/chat-commands-scope.ts +54 -0
- package/src/commands/chat-commands-shared.ts +114 -0
- package/src/commands/chat-commands-write.ts +891 -0
- package/src/commands/chat-commands.ts +19 -1841
- package/src/commands/cli-manager.ts +544 -26
- package/src/commands/handler.ts +841 -2
- package/src/commands/high-family/index.ts +28 -0
- package/src/commands/high-family/mesh-coordinator-launch.ts +678 -0
- package/src/commands/high-family/mesh-events.ts +80 -0
- package/src/commands/high-family/mesh-status.ts +710 -0
- package/src/commands/high-family/types.ts +76 -0
- package/src/commands/low-family/coordinator-prompt.ts +72 -0
- package/src/commands/low-family/daemon-lifecycle.ts +107 -0
- package/src/commands/low-family/diagnostics.ts +57 -0
- package/src/commands/low-family/index.ts +37 -0
- package/src/commands/low-family/mesh-ledger.ts +62 -0
- package/src/commands/low-family/mesh-node-logs.ts +87 -0
- package/src/commands/low-family/notification.ts +116 -0
- package/src/commands/low-family/refine-config.ts +106 -0
- package/src/commands/low-family/session-host.ts +274 -0
- package/src/commands/low-family/spec-providerdev.ts +217 -0
- package/src/commands/low-family/status-meta.ts +112 -0
- package/src/commands/low-family/types.ts +39 -0
- package/src/commands/med-family/cli-agent.ts +238 -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 +1066 -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 +143 -0
- package/src/commands/mesh-coordinator.ts +334 -124
- package/src/commands/router.ts +2711 -3254
- package/src/commands/stream-commands.ts +8 -0
- package/src/commands/upgrade-helper.ts +310 -45
- package/src/config/chat-history.ts +483 -24
- package/src/config/config.ts +12 -0
- package/src/config/mesh-config.ts +495 -22
- package/src/config/mesh-json-config.ts +376 -0
- package/src/config/recent-activity.ts +8 -2
- package/src/config/repo-settings.ts +111 -0
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/daemon/dev-server.ts +0 -541
- package/src/detection/cli-detector.ts +28 -9
- package/src/detection/ide-detector.ts +55 -16
- package/src/detection/win32-ide-version.ts +106 -0
- package/src/git/change-impact-config.ts +354 -0
- package/src/git/git-commands.ts +59 -15
- 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 +194 -12
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/ipc/local-ipc-server.ts +278 -0
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/command-log.ts +7 -5
- package/src/logging/log-redactor.ts +100 -0
- package/src/logging/log-tail-reader.ts +341 -0
- package/src/logging/logger.ts +14 -7
- package/src/mesh/contracts.ts +338 -0
- package/src/mesh/coordinator-prompt.ts +381 -33
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +645 -0
- package/src/mesh/mesh-clone-grace.ts +68 -0
- package/src/mesh/mesh-coordinator-config.ts +97 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-event-classify.ts +51 -0
- package/src/mesh/mesh-event-forwarding.ts +1888 -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 +656 -0
- package/src/mesh/mesh-events-stale.ts +389 -0
- package/src/mesh/mesh-events-utils.ts +443 -0
- package/src/mesh/mesh-events.ts +33 -1035
- package/src/mesh/mesh-fast-forward.ts +843 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-init.ts +260 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -7
- package/src/mesh/mesh-ledger.ts +656 -102
- package/src/mesh/mesh-magi-status.ts +223 -0
- package/src/mesh/mesh-missions.ts +449 -0
- package/src/mesh/mesh-node-identity.ts +1887 -0
- package/src/mesh/mesh-queue-assignment.ts +1918 -0
- package/src/mesh/mesh-reconcile-loop.ts +1780 -0
- package/src/mesh/mesh-refine-batch.ts +205 -0
- package/src/mesh/mesh-refine-gates.ts +1673 -0
- package/src/mesh/mesh-refine-status.ts +231 -0
- package/src/mesh/mesh-review-inbox.ts +307 -0
- package/src/mesh/mesh-routing.ts +291 -0
- package/src/mesh/mesh-runtime-store.ts +1853 -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 +1243 -141
- package/src/mesh/preview-freshness.ts +118 -0
- package/src/mesh/refine-config.ts +423 -0
- package/src/mesh/worktree-bootstrap-config.ts +450 -0
- package/src/providers/acp-provider-instance.ts +43 -10
- package/src/providers/approval-utils.d.ts +5 -0
- package/src/providers/approval-utils.ts +57 -5
- package/src/providers/chat-message-normalization.ts +92 -4
- package/src/providers/cli-provider-instance.ts +1933 -104
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +150 -6
- package/src/providers/extension-provider-instance.ts +12 -7
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +35 -12
- package/src/providers/manual-attendance.ts +85 -0
- package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
- package/src/providers/native-history/claude-cli-transcript.ts +396 -0
- package/src/providers/native-history/codex-cli-transcript.ts +479 -0
- package/src/providers/native-history/constants.ts +19 -0
- package/src/providers/native-history/dispatcher.ts +339 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +71 -0
- package/src/providers/provider-instance.ts +19 -1
- package/src/providers/provider-loader.ts +668 -50
- package/src/providers/provider-schema.ts +87 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +235 -0
- package/src/providers/spec/cli-adapter.ts +1056 -0
- package/src/providers/spec/evaluator.ts +407 -0
- package/src/providers/spec/fsm-driver.ts +1410 -0
- package/src/providers/spec/fsm-evaluator.ts +272 -0
- package/src/providers/spec/fsm-loader.ts +120 -0
- package/src/providers/spec/fsm-types.ts +273 -0
- package/src/providers/spec/native-history-executor.ts +1128 -0
- package/src/providers/spec/pre-launch-trust.ts +104 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/types.ts +262 -0
- package/src/providers/status-monitor.d.ts +7 -7
- package/src/providers/status-monitor.ts +37 -22
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +536 -0
- package/src/providers/version-archive.ts +64 -24
- package/src/providers/working-dir.ts +23 -0
- package/src/repo-mesh-types.ts +740 -14
- package/src/runtime-defaults.ts +39 -0
- package/src/sessions/registry.ts +6 -0
- package/src/shared-types-extra.ts +2 -4
- package/src/shared-types.d.ts +8 -0
- package/src/shared-types.ts +64 -1
- package/src/status/builders.ts +26 -6
- package/src/status/normalize.ts +2 -0
- package/src/status/reporter.ts +19 -1
- package/src/status/snapshot.ts +95 -26
- package/src/system/hash.ts +23 -0
- package/src/system/host-memory.ts +29 -12
- package/src/system/load-better-sqlite3.ts +68 -0
- package/src/types.ts +5 -0
- package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
- package/src/mesh/mesh-sync.ts +0 -111
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec-aware dispatcher for native conversation history.
|
|
3
|
+
*
|
|
4
|
+
* The four existing readers (claude/codex/antigravity/hermes) already know
|
|
5
|
+
* how to parse each agent's on-disk format. This dispatcher just resolves
|
|
6
|
+
* the right file given a workspace + sessionId hint, then hands it off.
|
|
7
|
+
*
|
|
8
|
+
* Wired into ProviderModule.scripts.readNativeHistory by provider-loader
|
|
9
|
+
* when spec.json declares native_history.reader. The script signature
|
|
10
|
+
* matches what chat-history.ts expects (see callProviderNativeHistoryRead).
|
|
11
|
+
*/
|
|
12
|
+
'use strict';
|
|
13
|
+
|
|
14
|
+
import * as fs from 'node:fs';
|
|
15
|
+
import * as os from 'node:os';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { readSession as readClaudeCliSession } from './claude-cli-transcript.js';
|
|
18
|
+
import { readSession as readCodexCliSession } from './codex-cli-transcript.js';
|
|
19
|
+
import { readSession as readAntigravityCliSession } from './antigravity-cli-transcript.js';
|
|
20
|
+
import { readSession as readHermesCliSession } from './hermes-cli-transcript.js';
|
|
21
|
+
import { SPAWN_BIND_GRACE_MS } from './constants.js';
|
|
22
|
+
|
|
23
|
+
export type ReaderId = 'claude-cli' | 'codex-cli' | 'antigravity-cli' | 'hermes-cli';
|
|
24
|
+
|
|
25
|
+
export interface NativeHistoryInput {
|
|
26
|
+
agentType?: string;
|
|
27
|
+
sessionId?: string;
|
|
28
|
+
providerSessionId?: string;
|
|
29
|
+
historySessionId?: string;
|
|
30
|
+
workspace?: string;
|
|
31
|
+
sessionStartedAtMs?: number;
|
|
32
|
+
format?: string;
|
|
33
|
+
watchPath?: string;
|
|
34
|
+
forceRefresh?: boolean;
|
|
35
|
+
args?: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface NativeHistoryResult {
|
|
39
|
+
messages: Array<{ role: string; content: string; receivedAt?: number; kind?: string; workspace?: string }>;
|
|
40
|
+
providerSessionId?: string;
|
|
41
|
+
sourcePath: string;
|
|
42
|
+
sourceMtimeMs: number;
|
|
43
|
+
nativeHistoryCoverage?: 'full' | 'partial' | 'best-effort';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function createNativeHistoryDispatcher(reader: ReaderId): (input: NativeHistoryInput) => NativeHistoryResult | null {
|
|
47
|
+
return (input: NativeHistoryInput) => {
|
|
48
|
+
const workspace = input.workspace || '';
|
|
49
|
+
const sessionId = input.sessionId || input.historySessionId || '';
|
|
50
|
+
// Caller may pass a providerSessionId (the *provider's own* id, e.g.
|
|
51
|
+
// the uuid claude writes into the jsonl basename). When present, the
|
|
52
|
+
// dispatcher only returns a transcript whose file id matches —
|
|
53
|
+
// otherwise the newest_by_mtime fallback can surface a different
|
|
54
|
+
// session's chat (round 9 part b: the user reported "previous chat
|
|
55
|
+
// shows up before I type anything" on every provider).
|
|
56
|
+
const requestedProviderSid = input.providerSessionId || '';
|
|
57
|
+
|
|
58
|
+
const sessionStartedAtMs = typeof input.sessionStartedAtMs === 'number'
|
|
59
|
+
? input.sessionStartedAtMs
|
|
60
|
+
: typeof input.args?.sessionStartedAtMs === 'number'
|
|
61
|
+
? input.args.sessionStartedAtMs
|
|
62
|
+
: 0;
|
|
63
|
+
const sourcePath = resolveSourcePath(reader, workspace, sessionId, sessionStartedAtMs);
|
|
64
|
+
if (!sourcePath) return null;
|
|
65
|
+
if (input.forceRefresh === true || input.args?.forceRefresh === true) {
|
|
66
|
+
try { fs.statSync(sourcePath); } catch { /* best-effort metadata refresh */ }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const session = readByReader(reader, sourcePath, sessionId, workspace);
|
|
70
|
+
if (!session) return null;
|
|
71
|
+
|
|
72
|
+
if (requestedProviderSid && session.providerSessionId && session.providerSessionId !== requestedProviderSid) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
messages: session.messages.map((m: any) => ({
|
|
78
|
+
role: normalizeRole(m.role),
|
|
79
|
+
content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
|
|
80
|
+
receivedAt: typeof m.receivedAt === 'number' ? m.receivedAt : Date.parse(m.timestamp || '') || Date.now(),
|
|
81
|
+
kind: typeof m.kind === 'string' ? m.kind : 'standard',
|
|
82
|
+
workspace: typeof m.workspace === 'string' ? m.workspace : workspace || undefined,
|
|
83
|
+
})),
|
|
84
|
+
providerSessionId: session.providerSessionId,
|
|
85
|
+
sourcePath: session.sourcePath,
|
|
86
|
+
sourceMtimeMs: session.sourceMtimeMs,
|
|
87
|
+
nativeHistoryCoverage: (session as any).nativeHistoryCoverage || 'full',
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
93
|
+
// Per-provider path resolution
|
|
94
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
function resolveSourcePath(reader: ReaderId, workspace: string, sessionId: string, sessionStartedAtMs: number): string | null {
|
|
97
|
+
switch (reader) {
|
|
98
|
+
case 'claude-cli': return resolveClaudePath(workspace, sessionId);
|
|
99
|
+
case 'codex-cli': return resolveCodexPath(workspace, sessionId, sessionStartedAtMs);
|
|
100
|
+
case 'antigravity-cli': return resolveAntigravityPath(workspace);
|
|
101
|
+
case 'hermes-cli': return resolveHermesPath(workspace, sessionId);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function resolveClaudePath(workspace: string, sessionId: string): string | null {
|
|
106
|
+
// claude stores per-cwd: ~/.claude/projects/<cwd-as-dashes>/<uuid>.jsonl
|
|
107
|
+
const dir = path.join(os.homedir(), '.claude', 'projects', cwdAsDashes(workspace));
|
|
108
|
+
if (!fs.existsSync(dir)) return null;
|
|
109
|
+
if (sessionId) {
|
|
110
|
+
const candidate = path.join(dir, `${sessionId}.jsonl`);
|
|
111
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
112
|
+
}
|
|
113
|
+
// No exact match: return null. The newest_by_mtime fallback used to
|
|
114
|
+
// grab whichever transcript was touched most recently, but that
|
|
115
|
+
// surfaced a different (often the user's *external* claude session
|
|
116
|
+
// in the same workspace) chat in the dashboard before the user
|
|
117
|
+
// typed anything. The right answer is to show nothing until either
|
|
118
|
+
// the daemon's sessionId actually maps to a file or the caller
|
|
119
|
+
// passes the correct providerSessionId (round 9 part b).
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function resolveCodexPath(workspace: string, sessionId: string, sessionStartedAtMs: number): string | null {
|
|
124
|
+
// codex stores by UTC date: ~/.codex/sessions/<year>/<month>/<day>/<file>.jsonl
|
|
125
|
+
const root = codexSessionsRoot();
|
|
126
|
+
if (sessionId && isUuidLikeSessionId(sessionId)) {
|
|
127
|
+
return findCodexPathBySessionId(root, sessionId);
|
|
128
|
+
}
|
|
129
|
+
return findCodexPathByRuntime(root, workspace, sessionStartedAtMs);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function findCodexPathBySessionId(root: string, sessionId: string): string | null {
|
|
133
|
+
if (!fs.existsSync(root)) return null;
|
|
134
|
+
const needle = sessionId.toLowerCase();
|
|
135
|
+
const matches: Array<{ p: string; mtime: number }> = [];
|
|
136
|
+
const stack: string[] = [root];
|
|
137
|
+
while (stack.length > 0) {
|
|
138
|
+
const current = stack.pop()!;
|
|
139
|
+
let entries: fs.Dirent[] = [];
|
|
140
|
+
try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
const entryPath = path.join(current, entry.name);
|
|
143
|
+
if (entry.isDirectory()) {
|
|
144
|
+
stack.push(entryPath);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
|
|
148
|
+
if (!entry.name.toLowerCase().includes(needle)) continue;
|
|
149
|
+
if (!isSafeFilename(entry.name.replace('.jsonl', ''))) continue;
|
|
150
|
+
matches.push({ p: entryPath, mtime: safeMtime(entryPath) });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
matches.sort((a, b) => b.mtime - a.mtime);
|
|
154
|
+
return matches[0]?.p ?? null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function findCodexPathByRuntime(root: string, workspace: string, sessionStartedAtMs: number): string | null {
|
|
158
|
+
if (!fs.existsSync(root) || !workspace) return null;
|
|
159
|
+
const workspaceResolved = resolveRealPath(workspace);
|
|
160
|
+
const cutoff = Date.now() - RECENT_WINDOW_MS;
|
|
161
|
+
const matches: Array<{ p: string; mtime: number; diff: number }> = [];
|
|
162
|
+
const stack: string[] = [root];
|
|
163
|
+
|
|
164
|
+
while (stack.length > 0) {
|
|
165
|
+
const current = stack.pop()!;
|
|
166
|
+
let entries: fs.Dirent[] = [];
|
|
167
|
+
try { entries = fs.readdirSync(current, { withFileTypes: true }); } catch { continue; }
|
|
168
|
+
for (const entry of entries) {
|
|
169
|
+
const entryPath = path.join(current, entry.name);
|
|
170
|
+
if (entry.isDirectory()) {
|
|
171
|
+
stack.push(entryPath);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (!entry.isFile() || !entry.name.endsWith('.jsonl')) continue;
|
|
175
|
+
const mtime = safeMtime(entryPath);
|
|
176
|
+
if (mtime < cutoff) continue;
|
|
177
|
+
const meta = readCodexSessionMeta(entryPath);
|
|
178
|
+
if (!meta?.cwd || resolveRealPath(meta.cwd) !== workspaceResolved) continue;
|
|
179
|
+
const diff = sessionStartedAtMs > 0 && meta.timestampMs != null
|
|
180
|
+
? Math.abs(meta.timestampMs - sessionStartedAtMs)
|
|
181
|
+
: 0;
|
|
182
|
+
if (sessionStartedAtMs > 0 && (meta.timestampMs == null || diff > SPAWN_BIND_GRACE_MS)) continue;
|
|
183
|
+
matches.push({ p: entryPath, mtime, diff });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
matches.sort((a, b) => sessionStartedAtMs > 0
|
|
188
|
+
? a.diff - b.diff || b.mtime - a.mtime
|
|
189
|
+
: b.mtime - a.mtime);
|
|
190
|
+
return matches[0]?.p ?? null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function readCodexSessionMeta(filePath: string): { cwd?: string; timestampMs?: number } | null {
|
|
194
|
+
try {
|
|
195
|
+
const fd = fs.openSync(filePath, 'r');
|
|
196
|
+
try {
|
|
197
|
+
const buffer = Buffer.alloc(8192);
|
|
198
|
+
const bytes = fs.readSync(fd, buffer, 0, buffer.length, 0);
|
|
199
|
+
if (bytes <= 0) return null;
|
|
200
|
+
const text = buffer.subarray(0, bytes).toString('utf8');
|
|
201
|
+
const firstLine = text.slice(0, text.indexOf('\n') >= 0 ? text.indexOf('\n') : text.length).trim();
|
|
202
|
+
if (!firstLine) return null;
|
|
203
|
+
const record = JSON.parse(firstLine) as Record<string, unknown>;
|
|
204
|
+
if (record.type !== 'session_meta' || !record.payload || typeof record.payload !== 'object') return null;
|
|
205
|
+
const payload = record.payload as Record<string, unknown>;
|
|
206
|
+
const timestampRaw = payload.timestamp;
|
|
207
|
+
const timestampMs = typeof timestampRaw === 'string'
|
|
208
|
+
? Date.parse(timestampRaw)
|
|
209
|
+
: typeof timestampRaw === 'number'
|
|
210
|
+
? (timestampRaw < 1e12 ? timestampRaw * 1000 : timestampRaw)
|
|
211
|
+
: NaN;
|
|
212
|
+
return {
|
|
213
|
+
cwd: typeof payload.cwd === 'string' ? payload.cwd : undefined,
|
|
214
|
+
timestampMs: Number.isFinite(timestampMs) ? timestampMs : undefined,
|
|
215
|
+
};
|
|
216
|
+
} finally {
|
|
217
|
+
fs.closeSync(fd);
|
|
218
|
+
}
|
|
219
|
+
} catch {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function resolveRealPath(value: string): string {
|
|
225
|
+
try { return fs.realpathSync(value); } catch { return value; }
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function resolveAntigravityPath(workspace: string): string | null {
|
|
229
|
+
void workspace;
|
|
230
|
+
// agy brain/<uuid>/.system_generated/logs/transcript.jsonl
|
|
231
|
+
const brainRoot = path.join(os.homedir(), '.gemini', 'antigravity-cli', 'brain');
|
|
232
|
+
if (!fs.existsSync(brainRoot)) return null;
|
|
233
|
+
const cutoff = Date.now() - RECENT_WINDOW_MS;
|
|
234
|
+
const entries = fs.readdirSync(brainRoot, { withFileTypes: true })
|
|
235
|
+
.filter(e => e.isDirectory())
|
|
236
|
+
.map(e => ({ p: path.join(brainRoot, e.name), mtime: safeMtime(path.join(brainRoot, e.name)) }))
|
|
237
|
+
.filter(e => e.mtime >= cutoff)
|
|
238
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
239
|
+
for (const e of entries) {
|
|
240
|
+
const t = path.join(e.p, '.system_generated', 'logs', 'transcript.jsonl');
|
|
241
|
+
if (fs.existsSync(t)) return t;
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function resolveHermesPath(workspace: string, sessionId: string): string | null {
|
|
247
|
+
void workspace; void sessionId;
|
|
248
|
+
// Hermes ≥ 0.14 persists all chat to ~/.hermes/state.db (SQLite). The
|
|
249
|
+
// db file is the "path" we hand to the reader — it pulls the newest
|
|
250
|
+
// source='cli' session inside readSession.
|
|
251
|
+
const dbPath = path.join(os.homedir(), '.hermes', 'state.db');
|
|
252
|
+
if (fs.existsSync(dbPath)) return dbPath;
|
|
253
|
+
// Legacy fallback: pre-db hermes wrote per-session JSON dumps.
|
|
254
|
+
const dir = path.join(os.homedir(), '.hermes', 'sessions');
|
|
255
|
+
if (!fs.existsSync(dir)) return null;
|
|
256
|
+
return newestRecentFile(dir, /^session_.*\.json$/);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
260
|
+
// Reader dispatch
|
|
261
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
262
|
+
|
|
263
|
+
function readByReader(
|
|
264
|
+
reader: ReaderId,
|
|
265
|
+
sourcePath: string,
|
|
266
|
+
sessionId: string,
|
|
267
|
+
workspace: string,
|
|
268
|
+
): any | null {
|
|
269
|
+
switch (reader) {
|
|
270
|
+
case 'claude-cli': return readClaudeCliSession(sourcePath);
|
|
271
|
+
case 'codex-cli': return readCodexCliSession(sourcePath);
|
|
272
|
+
case 'antigravity-cli': return readAntigravityCliSession(sourcePath, sessionId || undefined, workspace || undefined);
|
|
273
|
+
case 'hermes-cli': return readHermesCliSession(sourcePath);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
278
|
+
// Helpers
|
|
279
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
280
|
+
|
|
281
|
+
function cwdAsDashes(cwd: string): string {
|
|
282
|
+
if (!cwd) return '';
|
|
283
|
+
return cwd.replace(/\//g, '-');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function codexSessionsRoot(): string {
|
|
287
|
+
return path.join(os.homedir(), '.codex', 'sessions');
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function isUuidLikeSessionId(sessionId: string): boolean {
|
|
291
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function isSafeFilename(name: string): boolean {
|
|
295
|
+
return /^[A-Za-z0-9._:-]+$/.test(name) && !name.includes('..');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function newestFile(dir: string, pattern: RegExp): string | null {
|
|
299
|
+
try {
|
|
300
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
301
|
+
.filter(e => e.isFile() && pattern.test(e.name))
|
|
302
|
+
.map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
|
|
303
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
304
|
+
return entries[0]?.p ?? null;
|
|
305
|
+
} catch { return null; }
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Like newestFile but only returns a candidate when its mtime is within
|
|
310
|
+
* the recent activity window. Prevents the dashboard from surfacing a
|
|
311
|
+
* prior session's transcript when the daemon's sessionId doesn't match
|
|
312
|
+
* any file on disk (e.g. claude allocates its own uuid; daemon and
|
|
313
|
+
* agent disagree about what the "current" session is).
|
|
314
|
+
*/
|
|
315
|
+
const RECENT_WINDOW_MS = 5 * 60 * 1000;
|
|
316
|
+
function newestRecentFile(dir: string, pattern: RegExp): string | null {
|
|
317
|
+
try {
|
|
318
|
+
const cutoff = Date.now() - RECENT_WINDOW_MS;
|
|
319
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true })
|
|
320
|
+
.filter(e => e.isFile() && pattern.test(e.name))
|
|
321
|
+
.map(e => ({ p: path.join(dir, e.name), mtime: safeMtime(path.join(dir, e.name)) }))
|
|
322
|
+
.filter(e => e.mtime >= cutoff)
|
|
323
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
324
|
+
return entries[0]?.p ?? null;
|
|
325
|
+
} catch { return null; }
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function safeMtime(p: string): number {
|
|
329
|
+
try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function normalizeRole(r: any): 'user' | 'assistant' | 'system' {
|
|
333
|
+
const s = String(r ?? '').toLowerCase();
|
|
334
|
+
if (s === 'user' || s === 'human') return 'user';
|
|
335
|
+
if (s === 'assistant' || s === 'ai' || s === 'model') return 'assistant';
|
|
336
|
+
// daemon's chat schema rejects 'tool'/'function' — surface as assistant.
|
|
337
|
+
if (s === 'tool' || s === 'tool_result' || s === 'function') return 'assistant';
|
|
338
|
+
return 'system';
|
|
339
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hermes Agent — native history adapter.
|
|
3
|
+
*
|
|
4
|
+
* Hermes persists state in ~/.hermes/state.db (SQLite, better-sqlite3):
|
|
5
|
+
* sessions(id, source, started_at, ended_at, message_count, ...)
|
|
6
|
+
* messages(id, session_id, role, content, timestamp, ...)
|
|
7
|
+
*
|
|
8
|
+
* Earlier releases dumped per-session JSON files under ~/.hermes/sessions/;
|
|
9
|
+
* recent hermes (≥ 0.14) writes only to state.db. We read straight from
|
|
10
|
+
* the db when available and fall back to scanning legacy JSON dumps for
|
|
11
|
+
* archived sessions.
|
|
12
|
+
*
|
|
13
|
+
* The dispatcher hands us a sourcePath (the file the resolveHermesPath
|
|
14
|
+
* function picks). For the SQLite case the "path" is the db file itself
|
|
15
|
+
* and we resolve the most recent cli-source session inside readSession.
|
|
16
|
+
*/
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
import * as fs from 'node:fs';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import * as os from 'node:os';
|
|
22
|
+
import { loadBetterSqlite3 } from '../../system/load-better-sqlite3.js';
|
|
23
|
+
|
|
24
|
+
export interface NativeHistoryMessage {
|
|
25
|
+
id: string;
|
|
26
|
+
role: 'user' | 'assistant' | 'system';
|
|
27
|
+
content: string;
|
|
28
|
+
receivedAt: number;
|
|
29
|
+
kind?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface NativeHistorySession {
|
|
33
|
+
messages: NativeHistoryMessage[];
|
|
34
|
+
providerSessionId: string;
|
|
35
|
+
source: 'provider-native';
|
|
36
|
+
sourcePath: string;
|
|
37
|
+
sourceMtimeMs: number;
|
|
38
|
+
nativeHistoryCoverage: 'full';
|
|
39
|
+
workspace?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface NativeHistorySessionMeta {
|
|
43
|
+
historySessionId: string;
|
|
44
|
+
sessionId: string;
|
|
45
|
+
sourcePath: string;
|
|
46
|
+
sourceMtimeMs: number;
|
|
47
|
+
messageCount: number;
|
|
48
|
+
firstMessageAt: number;
|
|
49
|
+
lastMessageAt: number;
|
|
50
|
+
sessionTitle?: string;
|
|
51
|
+
preview?: string;
|
|
52
|
+
workspace?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const HERMES_STATE_DB = path.join(os.homedir(), '.hermes', 'state.db');
|
|
56
|
+
const HERMES_LEGACY_SESSIONS_DIR = path.join(os.homedir(), '.hermes', 'sessions');
|
|
57
|
+
|
|
58
|
+
function statMtimeMs(p: string): number {
|
|
59
|
+
try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function openDb(): any | null {
|
|
63
|
+
if (!fs.existsSync(HERMES_STATE_DB)) return null;
|
|
64
|
+
try {
|
|
65
|
+
const Database = loadBetterSqlite3();
|
|
66
|
+
return new Database(HERMES_STATE_DB, { readonly: true, fileMustExist: true });
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function loadMessagesForSession(db: any, sessionId: string): NativeHistoryMessage[] {
|
|
73
|
+
const rows: any[] = db.prepare(
|
|
74
|
+
`SELECT id, role, content, timestamp
|
|
75
|
+
FROM messages
|
|
76
|
+
WHERE session_id = ? AND content IS NOT NULL AND content != ''
|
|
77
|
+
ORDER BY timestamp ASC, id ASC`,
|
|
78
|
+
).all(sessionId);
|
|
79
|
+
const out: NativeHistoryMessage[] = [];
|
|
80
|
+
for (const r of rows) {
|
|
81
|
+
const role = normalizeHermesRole(r.role);
|
|
82
|
+
// Hermes stores some tool/system rows under role='tool'; surface as
|
|
83
|
+
// 'assistant' so they don't get dropped on the daemon's chat schema
|
|
84
|
+
// validation (role must be user/assistant/system).
|
|
85
|
+
out.push({
|
|
86
|
+
id: String(r.id),
|
|
87
|
+
role,
|
|
88
|
+
content: String(r.content),
|
|
89
|
+
receivedAt: Math.floor(Number(r.timestamp) * 1000),
|
|
90
|
+
kind: 'standard',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function readSession(sessionPath: string): NativeHistorySession | null {
|
|
97
|
+
if (!sessionPath) return null;
|
|
98
|
+
|
|
99
|
+
// Path mode A: SQLite — sourcePath is the state.db path. Pick the
|
|
100
|
+
// newest source='cli' session that has at least one persisted message.
|
|
101
|
+
if (sessionPath === HERMES_STATE_DB) {
|
|
102
|
+
const db = openDb();
|
|
103
|
+
if (!db) return null;
|
|
104
|
+
try {
|
|
105
|
+
const row: any = db.prepare(
|
|
106
|
+
`SELECT id, started_at FROM sessions
|
|
107
|
+
WHERE source = 'cli' AND message_count > 0
|
|
108
|
+
ORDER BY started_at DESC LIMIT 1`,
|
|
109
|
+
).get();
|
|
110
|
+
if (!row) return null;
|
|
111
|
+
const messages = loadMessagesForSession(db, row.id);
|
|
112
|
+
if (messages.length === 0) return null;
|
|
113
|
+
return {
|
|
114
|
+
messages,
|
|
115
|
+
providerSessionId: String(row.id),
|
|
116
|
+
source: 'provider-native',
|
|
117
|
+
sourcePath: sessionPath,
|
|
118
|
+
sourceMtimeMs: statMtimeMs(sessionPath),
|
|
119
|
+
nativeHistoryCoverage: 'full',
|
|
120
|
+
};
|
|
121
|
+
} finally {
|
|
122
|
+
try { db.close(); } catch { /* ignore */ }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Path mode B: legacy JSON dump — keep the old reader for archived
|
|
127
|
+
// sessions that pre-date the db format.
|
|
128
|
+
if (!path.isAbsolute(sessionPath) || !fs.existsSync(sessionPath)) return null;
|
|
129
|
+
let raw: any;
|
|
130
|
+
try { raw = JSON.parse(fs.readFileSync(sessionPath, 'utf8')); } catch { return null; }
|
|
131
|
+
if (!raw || typeof raw !== 'object') return null;
|
|
132
|
+
const rawMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
133
|
+
if (rawMessages.length === 0) return null;
|
|
134
|
+
const sourceMtimeMs = statMtimeMs(sessionPath);
|
|
135
|
+
const sessionStart = Number(raw.session_start) || sourceMtimeMs - rawMessages.length * 1000;
|
|
136
|
+
const messages: NativeHistoryMessage[] = [];
|
|
137
|
+
for (let i = 0; i < rawMessages.length; i += 1) {
|
|
138
|
+
const m = rawMessages[i];
|
|
139
|
+
const content = typeof m?.content === 'string' ? m.content : '';
|
|
140
|
+
if (!content) continue;
|
|
141
|
+
messages.push({
|
|
142
|
+
id: typeof m?.id === 'string' ? m.id : `msg_${i}`,
|
|
143
|
+
role: normalizeHermesRole(m?.role),
|
|
144
|
+
content,
|
|
145
|
+
receivedAt: sessionStart + i * 1000,
|
|
146
|
+
kind: 'standard',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (messages.length === 0) return null;
|
|
150
|
+
const sessionId = typeof raw.session_id === 'string' && raw.session_id
|
|
151
|
+
? raw.session_id
|
|
152
|
+
: path.basename(sessionPath, '.json').replace(/^session_/, '');
|
|
153
|
+
return {
|
|
154
|
+
messages,
|
|
155
|
+
providerSessionId: sessionId,
|
|
156
|
+
source: 'provider-native',
|
|
157
|
+
sourcePath: sessionPath,
|
|
158
|
+
sourceMtimeMs,
|
|
159
|
+
nativeHistoryCoverage: 'full',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export async function listSessions(_watchPath: string): Promise<NativeHistorySessionMeta[]> {
|
|
164
|
+
const out: NativeHistorySessionMeta[] = [];
|
|
165
|
+
|
|
166
|
+
const db = openDb();
|
|
167
|
+
if (db) {
|
|
168
|
+
try {
|
|
169
|
+
const rows: any[] = db.prepare(
|
|
170
|
+
`SELECT id, started_at, ended_at, message_count, title
|
|
171
|
+
FROM sessions
|
|
172
|
+
WHERE source = 'cli' AND message_count > 0
|
|
173
|
+
ORDER BY started_at DESC LIMIT 100`,
|
|
174
|
+
).all();
|
|
175
|
+
const mtime = statMtimeMs(HERMES_STATE_DB);
|
|
176
|
+
for (const r of rows) {
|
|
177
|
+
out.push({
|
|
178
|
+
historySessionId: String(r.id),
|
|
179
|
+
sessionId: String(r.id),
|
|
180
|
+
sourcePath: HERMES_STATE_DB,
|
|
181
|
+
sourceMtimeMs: mtime,
|
|
182
|
+
messageCount: Number(r.message_count) || 0,
|
|
183
|
+
firstMessageAt: Math.floor(Number(r.started_at) * 1000),
|
|
184
|
+
lastMessageAt: Math.floor(Number(r.ended_at || r.started_at) * 1000),
|
|
185
|
+
sessionTitle: typeof r.title === 'string' ? r.title : undefined,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
} finally {
|
|
189
|
+
try { db.close(); } catch { /* ignore */ }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (fs.existsSync(HERMES_LEGACY_SESSIONS_DIR)) {
|
|
194
|
+
for (const name of fs.readdirSync(HERMES_LEGACY_SESSIONS_DIR)) {
|
|
195
|
+
if (!/^session_.*\.json$/.test(name)) continue;
|
|
196
|
+
const p = path.join(HERMES_LEGACY_SESSIONS_DIR, name);
|
|
197
|
+
const mtime = statMtimeMs(p);
|
|
198
|
+
if (!mtime) continue;
|
|
199
|
+
let raw: any;
|
|
200
|
+
try { raw = JSON.parse(fs.readFileSync(p, 'utf8')); } catch { continue; }
|
|
201
|
+
const msgs = Array.isArray(raw?.messages) ? raw.messages : [];
|
|
202
|
+
if (msgs.length === 0) continue;
|
|
203
|
+
const sessionId = typeof raw.session_id === 'string' && raw.session_id
|
|
204
|
+
? raw.session_id
|
|
205
|
+
: name.replace(/^session_/, '').replace(/\.json$/, '');
|
|
206
|
+
out.push({
|
|
207
|
+
historySessionId: sessionId,
|
|
208
|
+
sessionId,
|
|
209
|
+
sourcePath: p,
|
|
210
|
+
sourceMtimeMs: mtime,
|
|
211
|
+
messageCount: msgs.length,
|
|
212
|
+
firstMessageAt: Number(raw.session_start) || mtime,
|
|
213
|
+
lastMessageAt: Number(raw.last_updated) || mtime,
|
|
214
|
+
sessionTitle: typeof raw.title === 'string' ? raw.title : undefined,
|
|
215
|
+
preview: typeof msgs[0]?.content === 'string' ? String(msgs[0].content).slice(0, 80) : undefined,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
out.sort((a, b) => b.sourceMtimeMs - a.sourceMtimeMs);
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function normalizeHermesRole(r: any): 'user' | 'assistant' | 'system' {
|
|
225
|
+
const s = String(r ?? '').toLowerCase();
|
|
226
|
+
if (s === 'user' || s === 'human') return 'user';
|
|
227
|
+
if (s === 'assistant' || s === 'ai' || s === 'model') return 'assistant';
|
|
228
|
+
if (s === 'tool' || s === 'tool_result' || s === 'function') return 'assistant';
|
|
229
|
+
return 'system';
|
|
230
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* native-history — Daemon-side built-in adapters for CLI provider native history.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter reads conversation history directly from the CLI tool's on-disk
|
|
5
|
+
* storage without shelling out to a provider JS override script.
|
|
6
|
+
*
|
|
7
|
+
* OSS code (AGPL-3.0). Must not import from packages/ (proprietary).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
readSession as readClaudeCliSession,
|
|
12
|
+
listSessions as listClaudeCliSessions,
|
|
13
|
+
} from './claude-cli-transcript.js';
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
readSession as readCodexCliSession,
|
|
17
|
+
listSessions as listCodexCliSessions,
|
|
18
|
+
} from './codex-cli-transcript.js';
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
readSession as readAntigravityCliSession,
|
|
22
|
+
listSessions as listAntigravityCliSessions,
|
|
23
|
+
} from './antigravity-cli-transcript.js';
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
readSession as readHermesCliSession,
|
|
27
|
+
listSessions as listHermesCliSessions,
|
|
28
|
+
} from './hermes-cli-transcript.js';
|
|
29
|
+
|
|
30
|
+
export { createNativeHistoryDispatcher, type ReaderId } from './dispatcher.js';
|
|
@@ -306,6 +306,77 @@ export class ProviderInstanceManager {
|
|
|
306
306
|
return updated;
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
/** Stamp a mesh assignment on a single instance (used by mesh_send_task
|
|
310
|
+
* --direct so the worker's completion event has a coordinator routing
|
|
311
|
+
* marker in state.settings). Returns `{ stamped: true }` when the stamp was
|
|
312
|
+
* applied, or `{ stamped: false, reason }` when it was refused — the instance
|
|
313
|
+
* was missing / has no attach method, or the DOUBLE-DISPATCH idempotence guard
|
|
314
|
+
* fired (the same task is already running on another live session here). */
|
|
315
|
+
attachMeshAssignmentToInstance(instanceId: string, assignment: { meshId: string; nodeId?: string; taskId?: string; coordinatorDaemonId?: string; coordinatorSessionId?: string }): { stamped: boolean; reason?: string } {
|
|
316
|
+
const inst = this.instances.get(instanceId);
|
|
317
|
+
if (!inst || typeof inst.attachMeshAssignment !== 'function') {
|
|
318
|
+
LOG.warn('MeshDispatch', `attachMeshAssignment skipped: instance ${instanceId} ${inst ? 'has no attach method' : 'not found'}`);
|
|
319
|
+
return { stamped: false, reason: inst ? 'instance_has_no_attach_method' : 'instance_not_found' };
|
|
320
|
+
}
|
|
321
|
+
// DOUBLE-DISPATCH stamp idempotence guard (defense in depth): refuse to stamp this
|
|
322
|
+
// (meshId, taskId) onto a SECOND instance when a DIFFERENT, still-live and actively
|
|
323
|
+
// working instance already holds the exact same task. Two sessions carrying one taskId
|
|
324
|
+
// double-execute the work (the auto-launch race RCA: a delayed claim by the original
|
|
325
|
+
// session plus the new session's post-boot claim sequentially stamp the same task —
|
|
326
|
+
// the atomic claim only blocks SIMULTANEOUS claims). A stale/dead/idle prior holder is
|
|
327
|
+
// NOT a conflict — a legitimate re-dispatch after a dispatch failure must still stamp.
|
|
328
|
+
if (assignment.taskId) {
|
|
329
|
+
const conflict = this.findLiveWorkingTaskHolder(assignment.meshId, assignment.taskId, instanceId);
|
|
330
|
+
if (conflict) {
|
|
331
|
+
LOG.warn('MeshDispatch', `attachMeshAssignment refused: task ${assignment.taskId} (mesh ${assignment.meshId}) is already being worked by live session ${conflict} — skipping duplicate stamp on ${instanceId}`);
|
|
332
|
+
return { stamped: false, reason: 'task_already_stamped_on_live_instance' };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
inst.attachMeshAssignment(assignment);
|
|
336
|
+
LOG.info('MeshDispatch', `stamped mesh assignment on ${instanceId}: mesh=${assignment.meshId} node=${assignment.nodeId || ''} task=${assignment.taskId || ''} coordinator=${assignment.coordinatorDaemonId || ''}`);
|
|
337
|
+
return { stamped: true };
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* DOUBLE-DISPATCH support: the id of another LIVE, actively-working instance that already
|
|
342
|
+
* holds (meshId, taskId), or null. "Live working" = stamped with this exact mesh+task AND
|
|
343
|
+
* currently mid-turn / booting toward it (generating / waiting on approval-or-choice /
|
|
344
|
+
* starting) — NOT idle, stopped, or errored. A stale/dead/idle holder is deliberately
|
|
345
|
+
* ignored so a legitimate re-dispatch (e.g. after a dispatch failure) is never blocked.
|
|
346
|
+
* The instance being stamped (excludeInstanceId) is skipped so re-stamping the same
|
|
347
|
+
* session stays idempotent. O(n) over instances — the count is small.
|
|
348
|
+
*/
|
|
349
|
+
private findLiveWorkingTaskHolder(meshId: string, taskId: string, excludeInstanceId: string): string | null {
|
|
350
|
+
// Mid-turn / booting statuses (top-level or activeChat). Anything else — idle, stopped,
|
|
351
|
+
// error — is not a live worker actively holding the task.
|
|
352
|
+
const working = new Set(['generating', 'waiting_approval', 'waiting_choice', 'starting', 'streaming', 'working', 'no_progress', 'long_generating']);
|
|
353
|
+
for (const [id, inst] of this.instances) {
|
|
354
|
+
if (id === excludeInstanceId) continue;
|
|
355
|
+
let state: ProviderState;
|
|
356
|
+
try {
|
|
357
|
+
state = inst.getState();
|
|
358
|
+
} catch {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const settings = (state.settings as Record<string, unknown>) || {};
|
|
362
|
+
if (settings.meshNodeFor !== meshId) continue;
|
|
363
|
+
if (settings.meshActiveTaskId !== taskId) continue;
|
|
364
|
+
const status = (typeof state.status === 'string' ? state.status : '').toLowerCase();
|
|
365
|
+
const chatStatus = (typeof state.activeChat?.status === 'string' ? state.activeChat.status : '').toLowerCase();
|
|
366
|
+
if (working.has(status) || working.has(chatStatus)) return id;
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Clear a mesh assignment after the dispatched task reaches a terminal
|
|
372
|
+
* state (generating_completed / stopped / failed). */
|
|
373
|
+
detachMeshAssignmentFromInstance(instanceId: string): boolean {
|
|
374
|
+
const inst = this.instances.get(instanceId);
|
|
375
|
+
if (!inst || typeof inst.detachMeshAssignment !== 'function') return false;
|
|
376
|
+
inst.detachMeshAssignment();
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
|
|
309
380
|
refreshProviderDefinitions(resolveProvider: (providerType: string) => unknown): number {
|
|
310
381
|
let refreshed = 0;
|
|
311
382
|
for (const instance of this.instances.values()) {
|