@adhdev/daemon-core 0.9.82-rc.36 → 0.9.82-rc.361
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 +8 -0
- package/dist/boot/process-hardening.d.ts +50 -0
- package/dist/build-info.d.ts +37 -0
- package/dist/chat/source-machine.d.ts +166 -0
- package/dist/chat/source-resolver.d.ts +104 -0
- package/dist/chat/subscription-updates.d.ts +1 -0
- package/dist/cli-adapter-types.d.ts +55 -2
- package/dist/cli-adapters/cli-script-runner.d.ts +117 -0
- package/dist/cli-adapters/cli-state-engine.d.ts +198 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +116 -64
- package/dist/cli-adapters/provider-cli-parse.d.ts +4 -0
- package/dist/cli-adapters/provider-cli-runtime.d.ts +34 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +53 -0
- package/dist/cli-adapters/raw-terminal-io.d.ts +37 -0
- package/dist/cli-adapters/resolve-executable.d.ts +14 -0
- package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +6 -3
- package/dist/cli-adapters/terminal-backends/types.d.ts +10 -2
- package/dist/cli-adapters/terminal-screen.d.ts +4 -11
- package/dist/commands/cli-manager.d.ts +15 -1
- package/dist/commands/handler.d.ts +125 -0
- package/dist/commands/low-family/index.d.ts +3 -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/types.d.ts +16 -0
- package/dist/commands/mesh-coordinator.d.ts +85 -1
- package/dist/commands/router.d.ts +336 -2
- package/dist/commands/upgrade-helper.d.ts +41 -1
- package/dist/config/chat-history.d.ts +9 -0
- package/dist/config/config.d.ts +5 -0
- package/dist/config/mesh-config.d.ts +77 -1
- package/dist/detection/ide-detector.d.ts +13 -0
- package/dist/detection/win32-ide-version.d.ts +37 -0
- package/dist/git/change-impact-config.d.ts +159 -0
- package/dist/git/git-commands.d.ts +11 -1
- package/dist/git/git-diff.d.ts +6 -0
- package/dist/git/git-executor.d.ts +11 -0
- package/dist/git/git-status.d.ts +23 -0
- package/dist/git/git-types.d.ts +2 -50
- package/dist/git/index.d.ts +2 -0
- package/dist/index.d.ts +54 -13
- package/dist/index.js +41337 -14723
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44100 -17614
- 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 +46 -0
- package/dist/logging/logger.d.ts +1 -1
- package/dist/mesh/contracts.d.ts +164 -0
- package/dist/mesh/coordinator-prompt.d.ts +36 -0
- package/dist/mesh/coordinator-registry.d.ts +59 -0
- package/dist/mesh/mesh-active-work.d.ts +174 -0
- package/dist/mesh/mesh-delivery-policy.d.ts +131 -0
- package/dist/mesh/mesh-event-trace.d.ts +21 -0
- package/dist/mesh/mesh-events-coordinator.d.ts +170 -0
- package/dist/mesh/mesh-events-pending.d.ts +55 -0
- package/dist/mesh/mesh-events-stale.d.ts +40 -0
- package/dist/mesh/mesh-events-utils.d.ts +60 -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 -3
- package/dist/mesh/mesh-ledger.d.ts +77 -1
- package/dist/mesh/mesh-missions.d.ts +164 -0
- package/dist/mesh/mesh-reconcile-loop.d.ts +7 -0
- package/dist/mesh/mesh-refine-batch.d.ts +68 -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 +429 -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-work-queue.d.ts +246 -5
- package/dist/mesh/preview-freshness.d.ts +18 -0
- package/dist/mesh/refine-config.d.ts +216 -0
- package/dist/mesh/worktree-bootstrap-config.d.ts +135 -0
- package/dist/providers/acp-provider-instance.d.ts +5 -0
- package/dist/providers/approval-utils.d.ts +20 -0
- package/dist/providers/chat-message-normalization.d.ts +12 -0
- package/dist/providers/cli-provider-instance.d.ts +106 -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/dispatcher.d.ts +27 -0
- package/dist/providers/native-history/hermes-cli-transcript.d.ts +30 -0
- package/dist/providers/native-history/index.d.ts +13 -0
- package/dist/providers/provider-instance-manager.d.ts +14 -0
- package/dist/providers/provider-instance.d.ts +23 -1
- package/dist/providers/provider-loader.d.ts +26 -4
- package/dist/providers/provider-trust.d.ts +31 -0
- package/dist/providers/read-chat-contract.d.ts +29 -0
- package/dist/providers/sdk/v1/builders/acp/detect-status.d.ts +68 -0
- package/dist/providers/sdk/v1/builders/cli/detect-status.d.ts +86 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval-squash.d.ts +59 -0
- package/dist/providers/sdk/v1/builders/cli/parse-approval.d.ts +65 -0
- package/dist/providers/sdk/v1/builders/cli/parse-session.d.ts +91 -0
- package/dist/providers/sdk/v1/builders/cli/visible-region.d.ts +42 -0
- package/dist/providers/sdk/v1/fixture-tooling/format.d.ts +126 -0
- package/dist/providers/sdk/v1/fixture-tooling/index.d.ts +8 -0
- package/dist/providers/sdk/v1/fixture-tooling/replay.d.ts +38 -0
- package/dist/providers/sdk/v1/index.d.ts +30 -0
- package/dist/providers/sdk/v1/sandbox/README-design.d.ts +193 -0
- package/dist/providers/sdk/v1/sandbox/require-whitelist.d.ts +74 -0
- package/dist/providers/sdk/v1/sandbox/script-runner.d.ts +98 -0
- package/dist/providers/sdk/v1/types/cli/index.d.ts +277 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +203 -0
- package/dist/providers/sdk/v1/validators/index.d.ts +5 -0
- package/dist/providers/sdk/v1/validators/manifest.d.ts +40 -0
- package/dist/providers/sdk/v1/validators/taint.d.ts +52 -0
- package/dist/providers/spec/adapter.d.ts +91 -0
- package/dist/providers/spec/cli-adapter.d.ts +223 -0
- package/dist/providers/spec/evaluator.d.ts +45 -0
- package/dist/providers/spec/fsm-driver.d.ts +368 -0
- package/dist/providers/spec/fsm-evaluator.d.ts +76 -0
- package/dist/providers/spec/fsm-loader.d.ts +14 -0
- package/dist/providers/spec/fsm-types.d.ts +174 -0
- package/dist/providers/spec/native-history-executor.d.ts +41 -0
- package/dist/providers/spec/pre-launch-trust.d.ts +16 -0
- package/dist/providers/spec/route.d.ts +4 -0
- package/dist/providers/spec/types.d.ts +222 -0
- package/dist/providers/status-monitor.d.ts +7 -7
- package/dist/providers/transcript-v2.d.ts +176 -0
- package/dist/providers/types/interactive-prompt.d.ts +84 -0
- package/dist/providers/working-dir.d.ts +17 -0
- package/dist/repo-mesh-types.d.ts +295 -13
- package/dist/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/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 +55 -12
- package/src/boot/process-hardening.ts +89 -0
- package/src/build-info.ts +73 -0
- package/src/chat/source-machine.ts +534 -0
- package/src/chat/source-resolver.ts +0 -0
- package/src/chat/subscription-updates.ts +20 -1
- package/src/cli-adapter-types.d.ts +1 -0
- package/src/cli-adapter-types.ts +56 -2
- package/src/cli-adapters/cli-script-runner.ts +421 -0
- package/src/cli-adapters/cli-state-engine.ts +1215 -0
- package/src/cli-adapters/provider-cli-adapter.d.ts +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +774 -1141
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +13 -0
- package/src/cli-adapters/provider-cli-runtime.ts +56 -7
- package/src/cli-adapters/provider-cli-shared.d.ts +4 -0
- package/src/cli-adapters/provider-cli-shared.ts +100 -11
- package/src/cli-adapters/pty-transport.ts +2 -1
- package/src/cli-adapters/raw-terminal-io.ts +252 -0
- package/src/cli-adapters/resolve-executable.ts +90 -0
- package/src/cli-adapters/session-host-transport.ts +2 -1
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +53 -29
- package/src/cli-adapters/terminal-backends/types.ts +10 -3
- package/src/cli-adapters/terminal-screen.ts +16 -81
- package/src/commands/WINDOWS-UPGRADE-LOCK-FAILURE.md +198 -0
- package/src/commands/chat-commands.ts +1823 -62
- package/src/commands/cli-manager.ts +405 -23
- package/src/commands/handler.ts +841 -2
- package/src/commands/low-family/index.ts +23 -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/types.ts +19 -0
- package/src/commands/mesh-coordinator.ts +332 -122
- package/src/commands/router.ts +7195 -1423
- 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 +388 -6
- package/src/config/recent-activity.ts +8 -2
- package/src/daemon/dev-auto-implement.ts +3 -2
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/cli-detector.ts +28 -9
- package/src/detection/ide-detector.ts +55 -16
- package/src/detection/win32-ide-version.ts +106 -0
- package/src/git/change-impact-config.ts +354 -0
- package/src/git/git-commands.ts +55 -14
- package/src/git/git-diff.ts +81 -11
- package/src/git/git-executor.ts +12 -0
- package/src/git/git-status.ts +574 -43
- package/src/git/git-types.ts +14 -62
- package/src/git/git-worktree.ts +8 -1
- package/src/git/index.ts +16 -0
- package/src/index.ts +156 -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 +220 -0
- package/src/logging/logger.ts +14 -7
- package/src/mesh/contracts.ts +338 -0
- package/src/mesh/coordinator-prompt.ts +234 -31
- package/src/mesh/coordinator-registry.ts +121 -0
- package/src/mesh/mesh-active-work.ts +667 -0
- package/src/mesh/mesh-delivery-policy.ts +315 -0
- package/src/mesh/mesh-event-trace.ts +67 -0
- package/src/mesh/mesh-events-coordinator.ts +2572 -0
- package/src/mesh/mesh-events-pending.ts +599 -0
- package/src/mesh/mesh-events-stale.ts +309 -0
- package/src/mesh/mesh-events-utils.ts +361 -0
- package/src/mesh/mesh-events.ts +30 -1035
- package/src/mesh/mesh-fast-forward.ts +839 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-init.ts +260 -0
- package/src/mesh/mesh-ledger-reconciliation.ts +12 -5
- package/src/mesh/mesh-ledger.ts +591 -102
- package/src/mesh/mesh-missions.ts +322 -0
- package/src/mesh/mesh-reconcile-loop.ts +1096 -0
- package/src/mesh/mesh-refine-batch.ts +197 -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 +1697 -0
- package/src/mesh/mesh-task-stats.ts +161 -0
- package/src/mesh/mesh-unresolved-forward-outbox.ts +185 -0
- package/src/mesh/mesh-work-queue.ts +997 -141
- package/src/mesh/preview-freshness.ts +118 -0
- package/src/mesh/refine-config.ts +423 -0
- package/src/mesh/worktree-bootstrap-config.ts +331 -0
- package/src/providers/acp-provider-instance.ts +43 -10
- package/src/providers/approval-utils.d.ts +5 -0
- package/src/providers/approval-utils.ts +57 -5
- package/src/providers/chat-message-normalization.ts +45 -5
- package/src/providers/cli-provider-instance.ts +1267 -101
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +150 -6
- package/src/providers/extension-provider-instance.ts +12 -7
- package/src/providers/external-sources.ts +218 -0
- package/src/providers/ide-provider-instance.ts +35 -12
- package/src/providers/manual-attendance.ts +85 -0
- package/src/providers/native-history/antigravity-cli-transcript.ts +643 -0
- package/src/providers/native-history/claude-cli-transcript.ts +396 -0
- package/src/providers/native-history/codex-cli-transcript.ts +479 -0
- package/src/providers/native-history/dispatcher.ts +340 -0
- package/src/providers/native-history/hermes-cli-transcript.ts +230 -0
- package/src/providers/native-history/index.ts +30 -0
- package/src/providers/provider-instance-manager.ts +30 -0
- package/src/providers/provider-instance.ts +19 -1
- package/src/providers/provider-loader.ts +670 -50
- package/src/providers/provider-schema.ts +87 -14
- package/src/providers/provider-trust.ts +114 -0
- package/src/providers/read-chat-contract.ts +76 -16
- package/src/providers/sdk/README.md +49 -0
- package/src/providers/sdk/v1/builders/acp/detect-status.ts +144 -0
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +313 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval-squash.ts +158 -0
- package/src/providers/sdk/v1/builders/cli/parse-approval.ts +250 -0
- package/src/providers/sdk/v1/builders/cli/parse-session.ts +276 -0
- package/src/providers/sdk/v1/builders/cli/visible-region.ts +143 -0
- package/src/providers/sdk/v1/fixture-tooling/format.ts +130 -0
- package/src/providers/sdk/v1/fixture-tooling/index.ts +22 -0
- package/src/providers/sdk/v1/fixture-tooling/replay.ts +352 -0
- package/src/providers/sdk/v1/index.ts +152 -0
- package/src/providers/sdk/v1/sandbox/README-design.ts +195 -0
- package/src/providers/sdk/v1/sandbox/require-whitelist.ts +472 -0
- package/src/providers/sdk/v1/sandbox/script-runner.ts +150 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +504 -0
- package/src/providers/sdk/v1/schemas/primitives/acp-session-protocol-v1.json +131 -0
- package/src/providers/sdk/v1/schemas/primitives/native-history-codex-rollout-v1.json +66 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-approval-squash-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-assistant-block-v1.json +91 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-cue-ordering-v1.json +47 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-dispatch-order-v1.json +32 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-footer-chrome-v1.json +42 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-index-finder-v1.json +27 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-modal-v1.json +125 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-prompt-marker-v1.json +45 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-session-id-extraction-v1.json +46 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-settled-prompt-v1.json +71 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-spinner-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-transcript-pty-v1.json +83 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-visible-region-v1.json +57 -0
- package/src/providers/sdk/v1/schemas/primitives/tui-welcome-screen-v1.json +35 -0
- package/src/providers/sdk/v1/types/cli/index.ts +365 -0
- package/src/providers/sdk/v1/types/common/index.ts +229 -0
- package/src/providers/sdk/v1/validators/index.ts +19 -0
- package/src/providers/sdk/v1/validators/manifest.ts +110 -0
- package/src/providers/sdk/v1/validators/taint.ts +309 -0
- package/src/providers/spec/adapter.ts +235 -0
- package/src/providers/spec/cli-adapter.ts +1051 -0
- package/src/providers/spec/evaluator.ts +407 -0
- package/src/providers/spec/fsm-driver.ts +1251 -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 +1136 -0
- package/src/providers/spec/pre-launch-trust.ts +104 -0
- package/src/providers/spec/route.ts +51 -0
- package/src/providers/spec/types.ts +262 -0
- package/src/providers/status-monitor.d.ts +7 -7
- package/src/providers/status-monitor.ts +37 -22
- package/src/providers/transcript-v2.ts +567 -0
- package/src/providers/types/interactive-prompt.ts +536 -0
- package/src/providers/version-archive.ts +64 -24
- package/src/providers/working-dir.ts +23 -0
- package/src/repo-mesh-types.ts +378 -14
- package/src/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/host-memory.ts +29 -12
- package/src/system/load-better-sqlite3.ts +68 -0
- package/src/types.ts +5 -0
- package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
- package/dist/mesh/mesh-sync.d.ts +0 -53
- package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
- package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -97
- package/src/mesh/mesh-sync.ts +0 -111
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M7: Operational stats (time/attempts) derived from existing truth.
|
|
3
|
+
*
|
|
4
|
+
* No cost/token accounting — ADHDev observes PTY/CDP and cannot see API
|
|
5
|
+
* tokens (explicit non-goal). Everything here is derived at query time from
|
|
6
|
+
* the SQLite ledger and queue rows; there is no separate aggregate table.
|
|
7
|
+
* Tasks with missing ledger evidence report incompleteEvidence instead of
|
|
8
|
+
* estimated numbers.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readLedgerEntries } from './mesh-ledger.js';
|
|
12
|
+
import type { MeshLedgerEntry } from './mesh-ledger.js';
|
|
13
|
+
import { getQueue } from './mesh-work-queue.js';
|
|
14
|
+
|
|
15
|
+
export interface MeshTaskStats {
|
|
16
|
+
taskId: string;
|
|
17
|
+
status: string;
|
|
18
|
+
dispatchedAt: string | null;
|
|
19
|
+
terminalAt: string | null;
|
|
20
|
+
terminalKind: 'task_completed' | 'task_failed' | null;
|
|
21
|
+
/** dispatched → terminal wall clock; null when evidence is incomplete. */
|
|
22
|
+
durationMs: number | null;
|
|
23
|
+
/** Number of task_dispatched ledger entries observed for this task. */
|
|
24
|
+
dispatchCount: number;
|
|
25
|
+
/** Queue requeueCount (0 when the row is gone or never requeued). */
|
|
26
|
+
requeueCount: number;
|
|
27
|
+
/** True when dispatch or terminal ledger evidence is missing — numbers are withheld, never estimated. */
|
|
28
|
+
incompleteEvidence?: true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface MeshMissionStats {
|
|
32
|
+
missionId: string;
|
|
33
|
+
taskCount: number;
|
|
34
|
+
completed: number;
|
|
35
|
+
failed: number;
|
|
36
|
+
/** Sum of per-task durations with complete evidence. */
|
|
37
|
+
totalDurationMs: number;
|
|
38
|
+
/** First dispatch → last terminal across the mission's tasks; null without complete endpoints. */
|
|
39
|
+
wallClockMs: number | null;
|
|
40
|
+
/** Total requeue attempts across the mission's tasks. */
|
|
41
|
+
retries: number;
|
|
42
|
+
/** Task ids whose ledger evidence was incomplete (excluded from sums). */
|
|
43
|
+
incompleteTaskIds: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readPayloadTaskId(entry: MeshLedgerEntry): string {
|
|
47
|
+
const value = entry.payload?.taskId;
|
|
48
|
+
return typeof value === 'string' && value.trim() ? value.trim() : '';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function parseTime(value: string | null | undefined): number | null {
|
|
52
|
+
if (!value) return null;
|
|
53
|
+
const parsed = new Date(value).getTime();
|
|
54
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Compute per-task stats from ledger entries. Scans a bounded tail window —
|
|
59
|
+
* stats are an operational view of recent work, not a full historical report.
|
|
60
|
+
*/
|
|
61
|
+
export function computeMeshTaskStats(meshId: string, opts?: { taskIds?: string[]; missionId?: string; tail?: number }): MeshTaskStats[] {
|
|
62
|
+
const queue = getQueue(meshId);
|
|
63
|
+
const queueById = new Map(queue.map(task => [task.id, task]));
|
|
64
|
+
|
|
65
|
+
let targetIds: string[];
|
|
66
|
+
if (opts?.taskIds?.length) {
|
|
67
|
+
targetIds = [...new Set(opts.taskIds)];
|
|
68
|
+
} else if (opts?.missionId) {
|
|
69
|
+
targetIds = queue.filter(task => task.missionId === opts.missionId).map(task => task.id);
|
|
70
|
+
} else {
|
|
71
|
+
targetIds = queue.map(task => task.id);
|
|
72
|
+
}
|
|
73
|
+
if (targetIds.length === 0) return [];
|
|
74
|
+
const targetSet = new Set(targetIds);
|
|
75
|
+
|
|
76
|
+
const entries = readLedgerEntries(meshId, { tail: opts?.tail ?? 1000 });
|
|
77
|
+
const dispatches = new Map<string, { first: string; count: number }>();
|
|
78
|
+
const terminals = new Map<string, { at: string; kind: 'task_completed' | 'task_failed' }>();
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const taskId = readPayloadTaskId(entry);
|
|
81
|
+
if (!taskId || !targetSet.has(taskId)) continue;
|
|
82
|
+
if (entry.kind === 'task_dispatched') {
|
|
83
|
+
const existing = dispatches.get(taskId);
|
|
84
|
+
if (existing) existing.count += 1;
|
|
85
|
+
else dispatches.set(taskId, { first: entry.timestamp, count: 1 });
|
|
86
|
+
} else if (entry.kind === 'task_completed' || entry.kind === 'task_failed') {
|
|
87
|
+
// Last terminal wins (requeued tasks can have multiple terminals).
|
|
88
|
+
terminals.set(taskId, { at: entry.timestamp, kind: entry.kind });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return targetIds.map(taskId => {
|
|
93
|
+
const queueEntry = queueById.get(taskId);
|
|
94
|
+
const dispatch = dispatches.get(taskId);
|
|
95
|
+
const terminal = terminals.get(taskId);
|
|
96
|
+
// Direct dispatches (mesh_send_task) have no work-queue row, so queueEntry is undefined.
|
|
97
|
+
// Derive a terminal status from the attributed terminal ledger entry instead of reporting
|
|
98
|
+
// status='unknown' — without this a completed direct task showed unknown + terminalKind=null
|
|
99
|
+
// even though its task_completed event fired (see mesh-events-coordinator Fix B attribution).
|
|
100
|
+
const status = queueEntry?.status
|
|
101
|
+
?? (terminal
|
|
102
|
+
? (terminal.kind === 'task_completed' ? 'completed' : 'failed')
|
|
103
|
+
: 'unknown');
|
|
104
|
+
const isTerminalStatus = status === 'completed' || status === 'failed' || status === 'cancelled';
|
|
105
|
+
const dispatchTime = parseTime(dispatch?.first ?? queueEntry?.dispatchTimestamp);
|
|
106
|
+
const terminalTime = parseTime(terminal?.at);
|
|
107
|
+
const stats: MeshTaskStats = {
|
|
108
|
+
taskId,
|
|
109
|
+
status,
|
|
110
|
+
dispatchedAt: dispatch?.first ?? queueEntry?.dispatchTimestamp ?? null,
|
|
111
|
+
terminalAt: terminal?.at ?? null,
|
|
112
|
+
terminalKind: terminal?.kind ?? null,
|
|
113
|
+
durationMs: null,
|
|
114
|
+
dispatchCount: dispatch?.count ?? 0,
|
|
115
|
+
requeueCount: queueEntry?.requeueCount ?? 0,
|
|
116
|
+
};
|
|
117
|
+
if (dispatchTime !== null && terminalTime !== null && terminalTime >= dispatchTime) {
|
|
118
|
+
stats.durationMs = terminalTime - dispatchTime;
|
|
119
|
+
} else if (isTerminalStatus) {
|
|
120
|
+
// Terminal task without complete dispatch+terminal ledger evidence:
|
|
121
|
+
// withhold numbers rather than estimate (M7 rule).
|
|
122
|
+
stats.incompleteEvidence = true;
|
|
123
|
+
}
|
|
124
|
+
return stats;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Mission rollup — derived from per-task stats, no stored aggregates. */
|
|
129
|
+
export function computeMeshMissionStats(meshId: string, missionId: string): MeshMissionStats {
|
|
130
|
+
const tasks = computeMeshTaskStats(meshId, { missionId });
|
|
131
|
+
const stats: MeshMissionStats = {
|
|
132
|
+
missionId,
|
|
133
|
+
taskCount: tasks.length,
|
|
134
|
+
completed: 0,
|
|
135
|
+
failed: 0,
|
|
136
|
+
totalDurationMs: 0,
|
|
137
|
+
wallClockMs: null,
|
|
138
|
+
retries: 0,
|
|
139
|
+
incompleteTaskIds: [],
|
|
140
|
+
};
|
|
141
|
+
let firstDispatch: number | null = null;
|
|
142
|
+
let lastTerminal: number | null = null;
|
|
143
|
+
for (const task of tasks) {
|
|
144
|
+
if (task.status === 'completed') stats.completed += 1;
|
|
145
|
+
else if (task.status === 'failed') stats.failed += 1;
|
|
146
|
+
stats.retries += task.requeueCount;
|
|
147
|
+
if (task.incompleteEvidence) {
|
|
148
|
+
stats.incompleteTaskIds.push(task.taskId);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (task.durationMs !== null) stats.totalDurationMs += task.durationMs;
|
|
152
|
+
const dispatchTime = parseTime(task.dispatchedAt);
|
|
153
|
+
const terminalTime = parseTime(task.terminalAt);
|
|
154
|
+
if (dispatchTime !== null && (firstDispatch === null || dispatchTime < firstDispatch)) firstDispatch = dispatchTime;
|
|
155
|
+
if (terminalTime !== null && (lastTerminal === null || terminalTime > lastTerminal)) lastTerminal = terminalTime;
|
|
156
|
+
}
|
|
157
|
+
if (firstDispatch !== null && lastTerminal !== null && lastTerminal >= firstDispatch) {
|
|
158
|
+
stats.wallClockMs = lastTerminal - firstDispatch;
|
|
159
|
+
}
|
|
160
|
+
return stats;
|
|
161
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// mesh-unresolved-forward-outbox — durable retry for unresolved-delegate forwards
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// A REMOTE worker daemon that is P2P-remote-controlled by a coordinator is NOT a
|
|
5
|
+
// member of the coordinator's mesh — it has no local mesh record. So when its
|
|
6
|
+
// completion event reaches setupMeshEventForwarding, resolveWorkerDelegateRouting
|
|
7
|
+
// returns mesh_unresolved: the worker carries the coordinator daemon anchor but no
|
|
8
|
+
// resolvable mesh id, so the normal queue-then-coordinator-pull path can't be used
|
|
9
|
+
// (the coordinator's reconcile PHASE 1 only pulls mesh.nodes, and this worker is in
|
|
10
|
+
// none of them — see docs/refactoring/2026-06-16-mesh-completion-polling-single-model.md).
|
|
11
|
+
//
|
|
12
|
+
// The ONLY delivery route for this case is a directed push to the coordinator
|
|
13
|
+
// daemon (mesh_forward_event over P2P). Previously that push was fire-and-forget:
|
|
14
|
+
// a single dispatchMeshCommand whose rejection was only logged, so one transient
|
|
15
|
+
// P2P failure dropped the completion forever (delivery_unroutable).
|
|
16
|
+
//
|
|
17
|
+
// This outbox makes that push DURABLE without inventing a new persistence layer:
|
|
18
|
+
// it reuses the existing mesh_pending_events SQLite table (the same store every
|
|
19
|
+
// other mesh coordinator event is persisted to), under a synthetic, reserved
|
|
20
|
+
// "mesh id" namespace so it never collides with a real mesh's queue. The worker's
|
|
21
|
+
// reconcile tick (PHASE 0) peeks the outbox, pushes each entry to its coordinator,
|
|
22
|
+
// and marks it drained (acked) ONLY on a successful push — a failed push leaves the
|
|
23
|
+
// row undrained for the next tick. Entries that exceed a max age are expired so the
|
|
24
|
+
// outbox can't grow unbounded when a coordinator stays permanently unreachable.
|
|
25
|
+
//
|
|
26
|
+
// Idempotency:
|
|
27
|
+
// - Enqueue is idempotent on the event fingerprint (mesh_pending_events has a
|
|
28
|
+
// UNIQUE (mesh_id, fingerprint) index + INSERT OR IGNORE), so the same
|
|
29
|
+
// completion fired twice on the worker queues once.
|
|
30
|
+
// - The receiver dedups independently: handleMeshForwardEvent → injectMeshSystemMessage
|
|
31
|
+
// → queuePendingMeshCoordinatorEvent recomputes the fingerprint and suppresses a
|
|
32
|
+
// duplicate, so an at-least-once retry that double-delivers is harmless.
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
import { randomUUID } from 'crypto';
|
|
36
|
+
import { LOG } from '../logging/logger.js';
|
|
37
|
+
import { MeshRuntimeStore } from './mesh-runtime-store.js';
|
|
38
|
+
import { buildPendingEventFingerprint, type PendingMeshCoordinatorEvent } from './mesh-events-pending.js';
|
|
39
|
+
import { readNonEmptyString } from './mesh-events-utils.js';
|
|
40
|
+
|
|
41
|
+
// Reserved synthetic mesh id for the worker-side unresolved-forward outbox. The `::`
|
|
42
|
+
// and leading `__` make it impossible to collide with a real mesh id (which are
|
|
43
|
+
// `mesh_*` / `mreg_*` slugs). Scoping rows by coordinator_daemon_id inside this one
|
|
44
|
+
// namespace lets a single worker forward to multiple coordinators.
|
|
45
|
+
export const UNRESOLVED_FORWARD_OUTBOX_MESH_ID = '__unresolved_forward_outbox__';
|
|
46
|
+
|
|
47
|
+
// Entries older than this are expired (dropped) rather than retried forever — a
|
|
48
|
+
// coordinator that has been unreachable this long is treated as gone. Generous
|
|
49
|
+
// enough to ride out a long coordinator outage / restart, bounded enough that a
|
|
50
|
+
// permanently-dead coordinator can't accumulate outbox rows indefinitely.
|
|
51
|
+
const UNRESOLVED_FORWARD_MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes
|
|
52
|
+
|
|
53
|
+
export interface UnresolvedForwardEntry {
|
|
54
|
+
/** Row id in mesh_pending_events; pass back to ack/expire after a push attempt. */
|
|
55
|
+
id: string;
|
|
56
|
+
/** The coordinator daemon to push this event to (mesh_forward_event target). */
|
|
57
|
+
coordinatorDaemonId: string;
|
|
58
|
+
/** The flat payload to forward (already shaped for handleMeshForwardEvent). */
|
|
59
|
+
payload: Record<string, unknown>;
|
|
60
|
+
/** When the entry was first enqueued (epoch ms) — used for age-based expiry. */
|
|
61
|
+
queuedAt: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function getStore(): MeshRuntimeStore | undefined {
|
|
65
|
+
try { return MeshRuntimeStore.getInstance(); } catch { return undefined; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Durably enqueue an unresolved-delegate forward for a coordinator daemon. The
|
|
70
|
+
* `forwardPayload` is the flat shape handleMeshForwardEvent reads on the coordinator.
|
|
71
|
+
* Idempotent on the event fingerprint. Returns true when a new row was written (or a
|
|
72
|
+
* duplicate was harmlessly ignored), false on a hard persistence failure.
|
|
73
|
+
*/
|
|
74
|
+
export function enqueueUnresolvedDelegateForward(
|
|
75
|
+
coordinatorDaemonId: string,
|
|
76
|
+
eventName: string,
|
|
77
|
+
forwardPayload: Record<string, unknown>,
|
|
78
|
+
): boolean {
|
|
79
|
+
const target = readNonEmptyString(coordinatorDaemonId);
|
|
80
|
+
const event = readNonEmptyString(eventName);
|
|
81
|
+
if (!target || !event) return false;
|
|
82
|
+
const store = getStore();
|
|
83
|
+
if (!store) return false;
|
|
84
|
+
|
|
85
|
+
const queuedAt = Date.now();
|
|
86
|
+
// Reuse the standard pending-event fingerprint so enqueue is idempotent AND the
|
|
87
|
+
// receiver's own dedup keys on a comparable identity. We synthesise the minimal
|
|
88
|
+
// PendingMeshCoordinatorEvent shape buildPendingEventFingerprint needs.
|
|
89
|
+
const fingerprintSource: PendingMeshCoordinatorEvent = {
|
|
90
|
+
event,
|
|
91
|
+
meshId: UNRESOLVED_FORWARD_OUTBOX_MESH_ID,
|
|
92
|
+
nodeLabel: readNonEmptyString(forwardPayload.nodeId) || readNonEmptyString(forwardPayload.workspace) || 'unresolved-delegate',
|
|
93
|
+
nodeId: readNonEmptyString(forwardPayload.nodeId) || undefined,
|
|
94
|
+
workspace: readNonEmptyString(forwardPayload.workspace) || undefined,
|
|
95
|
+
metadataEvent: forwardPayload,
|
|
96
|
+
queuedAt,
|
|
97
|
+
targetCoordinatorDaemonId: target,
|
|
98
|
+
};
|
|
99
|
+
// Scope the fingerprint to the coordinator so two coordinators awaiting the same
|
|
100
|
+
// worker session don't collapse into one outbox row.
|
|
101
|
+
const fingerprint = `${target}::${buildPendingEventFingerprint(fingerprintSource)}`;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const inserted = store.insertPendingEvent({
|
|
105
|
+
id: randomUUID(),
|
|
106
|
+
meshId: UNRESOLVED_FORWARD_OUTBOX_MESH_ID,
|
|
107
|
+
coordinatorDaemonId: target,
|
|
108
|
+
event,
|
|
109
|
+
// Store the flat forward payload + the queue timestamp so the retry tick can
|
|
110
|
+
// rebuild the push args and apply age-based expiry without a schema change.
|
|
111
|
+
payload: { forwardPayload, coordinatorDaemonId: target, queuedAt },
|
|
112
|
+
fingerprint,
|
|
113
|
+
queuedAt,
|
|
114
|
+
});
|
|
115
|
+
if (inserted) {
|
|
116
|
+
LOG.info('MeshEvents', `Durably queued unresolved-delegate ${event} for coordinator ${target} (outbox)`);
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
} catch (e: any) {
|
|
120
|
+
LOG.warn('MeshEvents', `Failed to persist unresolved-delegate forward to outbox: ${e?.message || e}`);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Peek (non-destructive) every undrained outbox entry across all coordinators. */
|
|
126
|
+
export function peekUnresolvedDelegateForwards(): UnresolvedForwardEntry[] {
|
|
127
|
+
const store = getStore();
|
|
128
|
+
if (!store) return [];
|
|
129
|
+
let rows: Array<{ id: string; event: string; payload: unknown }>;
|
|
130
|
+
try {
|
|
131
|
+
rows = store.peekPendingEvents(UNRESOLVED_FORWARD_OUTBOX_MESH_ID);
|
|
132
|
+
} catch {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
const out: UnresolvedForwardEntry[] = [];
|
|
136
|
+
for (const row of rows) {
|
|
137
|
+
const stored = row.payload && typeof row.payload === 'object' ? row.payload as Record<string, unknown> : {};
|
|
138
|
+
const coordinatorDaemonId = readNonEmptyString(stored.coordinatorDaemonId);
|
|
139
|
+
const forwardPayload = stored.forwardPayload && typeof stored.forwardPayload === 'object'
|
|
140
|
+
? stored.forwardPayload as Record<string, unknown>
|
|
141
|
+
: undefined;
|
|
142
|
+
if (!coordinatorDaemonId || !forwardPayload) continue;
|
|
143
|
+
const queuedAt = typeof stored.queuedAt === 'number' ? stored.queuedAt : 0;
|
|
144
|
+
out.push({ id: row.id, coordinatorDaemonId, payload: forwardPayload, queuedAt });
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Mark an outbox entry delivered (acked) after a successful push. */
|
|
150
|
+
export function ackUnresolvedDelegateForward(id: string): void {
|
|
151
|
+
const store = getStore();
|
|
152
|
+
if (!store) return;
|
|
153
|
+
try { store.markPendingEventsDrainedById([id]); } catch { /* best-effort */ }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Drop outbox entries that have exceeded the max retry age. Returns the count
|
|
158
|
+
* expired so the caller can log a fail-loud trace (a dropped completion is a real
|
|
159
|
+
* loss; it must be visible, not silent).
|
|
160
|
+
*/
|
|
161
|
+
export function expireStaleUnresolvedDelegateForwards(nowMs: number = Date.now()): number {
|
|
162
|
+
const entries = peekUnresolvedDelegateForwards();
|
|
163
|
+
const staleIds = entries
|
|
164
|
+
.filter(e => e.queuedAt > 0 && nowMs - e.queuedAt >= UNRESOLVED_FORWARD_MAX_AGE_MS)
|
|
165
|
+
.map(e => e.id);
|
|
166
|
+
if (staleIds.length === 0) return 0;
|
|
167
|
+
const store = getStore();
|
|
168
|
+
if (!store) return 0;
|
|
169
|
+
try {
|
|
170
|
+
const removed = store.deletePendingEventsById(staleIds);
|
|
171
|
+
if (removed > 0) {
|
|
172
|
+
LOG.warn('MeshEvents', `Expired ${removed} unresolved-delegate forward(s) after ${Math.round(UNRESOLVED_FORWARD_MAX_AGE_MS / 60000)}m of failed retries — coordinator unreachable, completion dropped`);
|
|
173
|
+
}
|
|
174
|
+
return removed;
|
|
175
|
+
} catch {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Test helper: purge the entire outbox. */
|
|
181
|
+
export function __clearUnresolvedDelegateForwardOutboxForTests(): void {
|
|
182
|
+
const store = getStore();
|
|
183
|
+
if (!store) return;
|
|
184
|
+
try { store.clearPendingEventsForMesh(UNRESOLVED_FORWARD_OUTBOX_MESH_ID); } catch { /* nothing to clear */ }
|
|
185
|
+
}
|