@lannguyensi/harness 0.63.0 → 1.0.0
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/CHANGELOG.md +90 -0
- package/README.md +46 -42
- package/dist/cli/add/index.js +17 -21
- package/dist/cli/add/index.js.map +1 -1
- package/dist/cli/adopt/derive.d.ts +2 -2
- package/dist/cli/adopt/derive.js +2 -19
- package/dist/cli/adopt/derive.js.map +1 -1
- package/dist/cli/adopt/index.d.ts +1 -1
- package/dist/cli/adopt/index.js +1 -12
- package/dist/cli/adopt/index.js.map +1 -1
- package/dist/cli/apply/apply.d.ts +20 -35
- package/dist/cli/apply/apply.js +61 -136
- package/dist/cli/apply/apply.js.map +1 -1
- package/dist/cli/apply/generate-codex-config.js +10 -58
- package/dist/cli/apply/generate-codex-config.js.map +1 -1
- package/dist/cli/apply/generate-memory-index.js +1 -2
- package/dist/cli/apply/generate-memory-index.js.map +1 -1
- package/dist/cli/apply/generate-opencode-config.d.ts +2 -10
- package/dist/cli/apply/generate-opencode-config.js +74 -113
- package/dist/cli/apply/generate-opencode-config.js.map +1 -1
- package/dist/cli/apply/generate-settings.d.ts +11 -64
- package/dist/cli/apply/generate-settings.js +27 -132
- package/dist/cli/apply/generate-settings.js.map +1 -1
- package/dist/cli/apply/index.d.ts +1 -1
- package/dist/cli/apply/index.js +1 -1
- package/dist/cli/apply/index.js.map +1 -1
- package/dist/cli/apply/install-codex-config.d.ts +153 -1
- package/dist/cli/apply/install-codex-config.js +445 -70
- package/dist/cli/apply/install-codex-config.js.map +1 -1
- package/dist/cli/apply/next-steps.d.ts +7 -0
- package/dist/cli/apply/next-steps.js +13 -1
- package/dist/cli/apply/next-steps.js.map +1 -1
- package/dist/cli/bounded-stdin.d.ts +0 -23
- package/dist/cli/bounded-stdin.js +2 -49
- package/dist/cli/bounded-stdin.js.map +1 -1
- package/dist/cli/describe.d.ts +1 -1
- package/dist/cli/describe.js +0 -3
- package/dist/cli/describe.js.map +1 -1
- package/dist/cli/diff/engine.d.ts +0 -11
- package/dist/cli/diff/engine.js +1 -17
- package/dist/cli/diff/engine.js.map +1 -1
- package/dist/cli/diff/index.js +14 -25
- package/dist/cli/diff/index.js.map +1 -1
- package/dist/cli/doctor/claude-mcp.d.ts +4 -19
- package/dist/cli/doctor/claude-mcp.js +11 -22
- package/dist/cli/doctor/claude-mcp.js.map +1 -1
- package/dist/cli/doctor/codex.d.ts +12 -14
- package/dist/cli/doctor/codex.js +31 -144
- package/dist/cli/doctor/codex.js.map +1 -1
- package/dist/cli/doctor/format.js +23 -338
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/hook-liveness.d.ts +56 -0
- package/dist/cli/doctor/hook-liveness.js +455 -0
- package/dist/cli/doctor/hook-liveness.js.map +1 -0
- package/dist/cli/doctor/index.d.ts +13 -87
- package/dist/cli/doctor/index.js +57 -705
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/opencode.d.ts +2 -1
- package/dist/cli/doctor/opencode.js.map +1 -1
- package/dist/cli/doctor/types.d.ts +21 -378
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/drain-stdio.d.ts +31 -0
- package/dist/cli/drain-stdio.js +76 -0
- package/dist/cli/drain-stdio.js.map +1 -0
- package/dist/cli/export.d.ts +3 -1
- package/dist/cli/export.js +7 -16
- package/dist/cli/export.js.map +1 -1
- package/dist/cli/gate/codex-disable.d.ts +29 -0
- package/dist/cli/gate/codex-disable.js +195 -0
- package/dist/cli/gate/codex-disable.js.map +1 -0
- package/dist/cli/gate/codex-enable.d.ts +41 -0
- package/dist/cli/gate/codex-enable.js +127 -0
- package/dist/cli/gate/codex-enable.js.map +1 -0
- package/dist/cli/gate/codex-snapshot.d.ts +208 -0
- package/dist/cli/gate/codex-snapshot.js +402 -0
- package/dist/cli/gate/codex-snapshot.js.map +1 -0
- package/dist/cli/gate/disable.d.ts +9 -0
- package/dist/cli/gate/disable.js +263 -28
- package/dist/cli/gate/disable.js.map +1 -1
- package/dist/cli/gate/enable.d.ts +26 -6
- package/dist/cli/gate/enable.js +152 -80
- package/dist/cli/gate/enable.js.map +1 -1
- package/dist/cli/gate/link-chain.d.ts +53 -0
- package/dist/cli/gate/link-chain.js +122 -0
- package/dist/cli/gate/link-chain.js.map +1 -0
- package/dist/cli/gate/snapshot.d.ts +289 -12
- package/dist/cli/gate/snapshot.js +481 -22
- package/dist/cli/gate/snapshot.js.map +1 -1
- package/dist/cli/index.d.ts +0 -9
- package/dist/cli/index.js +15 -2607
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/composer.d.ts +3 -6
- package/dist/cli/init/composer.js +6 -370
- package/dist/cli/init/composer.js.map +1 -1
- package/dist/cli/init/dependencies.d.ts +1 -2
- package/dist/cli/init/dependencies.js +4 -80
- package/dist/cli/init/dependencies.js.map +1 -1
- package/dist/cli/init/detect.js +5 -4
- package/dist/cli/init/detect.js.map +1 -1
- package/dist/cli/init/interactive.d.ts +1 -23
- package/dist/cli/init/interactive.js +33 -247
- package/dist/cli/init/interactive.js.map +1 -1
- package/dist/cli/init/profiles.d.ts +2 -2
- package/dist/cli/init/profiles.js +51 -243
- package/dist/cli/init/profiles.js.map +1 -1
- package/dist/cli/init/templates.d.ts +2 -37
- package/dist/cli/init/templates.js +25 -1237
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/list.d.ts +1 -1
- package/dist/cli/list.js +1 -38
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/loader.d.ts +15 -1
- package/dist/cli/loader.js +56 -39
- package/dist/cli/loader.js.map +1 -1
- package/dist/cli/main.js +7 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/migrate-home/index.js +2 -2
- package/dist/cli/migrate-home/index.js.map +1 -1
- package/dist/cli/pack/add.js +1 -1
- package/dist/cli/pack/add.js.map +1 -1
- package/dist/cli/pack/hook-bootstrap.d.ts +5 -164
- package/dist/cli/pack/hook-bootstrap.js +15 -291
- package/dist/cli/pack/hook-bootstrap.js.map +1 -1
- package/dist/cli/pack/hook-branch-protection.d.ts +28 -21
- package/dist/cli/pack/hook-branch-protection.js +365 -340
- package/dist/cli/pack/hook-branch-protection.js.map +1 -1
- package/dist/cli/pack/index.d.ts +0 -1
- package/dist/cli/pack/index.js +0 -1
- package/dist/cli/pack/index.js.map +1 -1
- package/dist/cli/pack/list.js +1 -6
- package/dist/cli/pack/list.js.map +1 -1
- package/dist/cli/pack/mutate.d.ts +7 -9
- package/dist/cli/pack/mutate.js +6 -9
- package/dist/cli/pack/mutate.js.map +1 -1
- package/dist/cli/pack/reseed.d.ts +2 -2
- package/dist/cli/pack/reseed.js +16 -22
- package/dist/cli/pack/reseed.js.map +1 -1
- package/dist/cli/register-gate-group.d.ts +5 -0
- package/dist/cli/register-gate-group.js +348 -0
- package/dist/cli/register-gate-group.js.map +1 -0
- package/dist/cli/register-inspect-group.d.ts +6 -0
- package/dist/cli/register-inspect-group.js +189 -0
- package/dist/cli/register-inspect-group.js.map +1 -0
- package/dist/cli/register-operator-lifecycle.d.ts +5 -0
- package/dist/cli/register-operator-lifecycle.js +20 -0
- package/dist/cli/register-operator-lifecycle.js.map +1 -0
- package/dist/cli/register-pack-group.d.ts +5 -0
- package/dist/cli/register-pack-group.js +134 -0
- package/dist/cli/register-pack-group.js.map +1 -0
- package/dist/cli/register-setup-group.d.ts +5 -0
- package/dist/cli/register-setup-group.js +495 -0
- package/dist/cli/register-setup-group.js.map +1 -0
- package/dist/cli/remove/index.d.ts +0 -14
- package/dist/cli/remove/index.js +2 -115
- package/dist/cli/remove/index.js.map +1 -1
- package/dist/cli/remove/mutate.d.ts +0 -2
- package/dist/cli/remove/mutate.js +1 -19
- package/dist/cli/remove/mutate.js.map +1 -1
- package/dist/cli/remove/register.d.ts +5 -0
- package/dist/cli/remove/register.js +25 -0
- package/dist/cli/remove/register.js.map +1 -0
- package/dist/cli/shell-quote.d.ts +7 -0
- package/dist/cli/shell-quote.js +17 -0
- package/dist/cli/shell-quote.js.map +1 -0
- package/dist/cli/uninstall/index.d.ts +4 -2
- package/dist/cli/uninstall/index.js +15 -7
- package/dist/cli/uninstall/index.js.map +1 -1
- package/dist/cli/uninstall/register.d.ts +5 -0
- package/dist/cli/uninstall/register.js +171 -0
- package/dist/cli/uninstall/register.js.map +1 -0
- package/dist/cli/uninstall/snapshot.d.ts +15 -0
- package/dist/cli/uninstall/snapshot.js +38 -0
- package/dist/cli/uninstall/snapshot.js.map +1 -1
- package/dist/cli/validate/checks.d.ts +0 -77
- package/dist/cli/validate/checks.js +3 -1049
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/cli/validate/index.js +19 -15
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/index.js.map +1 -1
- package/dist/io/claude-mcp.d.ts +1 -1
- package/dist/io/claude-mcp.js +27 -14
- package/dist/io/claude-mcp.js.map +1 -1
- package/dist/io/harness-lock.js +2 -2
- package/dist/io/harness-lock.js.map +1 -1
- package/dist/io/lock.d.ts +0 -26
- package/dist/io/lock.js +10 -27
- package/dist/io/lock.js.map +1 -1
- package/dist/io/merge-settings.js +6 -4
- package/dist/io/merge-settings.js.map +1 -1
- package/dist/io/project-name.d.ts +22 -39
- package/dist/io/project-name.js +25 -42
- package/dist/io/project-name.js.map +1 -1
- package/dist/io/read-regular-file.d.ts +103 -40
- package/dist/io/read-regular-file.js +196 -35
- package/dist/io/read-regular-file.js.map +1 -1
- package/dist/io/restart-hints.js +3 -6
- package/dist/io/restart-hints.js.map +1 -1
- package/dist/io/version-compare.d.ts +1 -3
- package/dist/io/version-compare.js +1 -3
- package/dist/io/version-compare.js.map +1 -1
- package/dist/io/write-regular-file.d.ts +30 -0
- package/dist/io/write-regular-file.js +85 -0
- package/dist/io/write-regular-file.js.map +1 -0
- package/dist/overrides/index.d.ts +1 -0
- package/dist/overrides/index.js +1 -0
- package/dist/overrides/index.js.map +1 -1
- package/dist/overrides/merge-layers.d.ts +43 -0
- package/dist/overrides/merge-layers.js +76 -0
- package/dist/overrides/merge-layers.js.map +1 -0
- package/dist/overrides/merge.d.ts +16 -0
- package/dist/overrides/merge.js +21 -8
- package/dist/overrides/merge.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -69
- package/dist/policy-packs/builtin/branch-protection-runtime.js +12 -84
- package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection.d.ts +7 -30
- package/dist/policy-packs/builtin/branch-protection.js +56 -89
- package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
- package/dist/policy-packs/config-check.d.ts +7 -5
- package/dist/policy-packs/config-check.js +2 -2
- package/dist/policy-packs/config-check.js.map +1 -1
- package/dist/policy-packs/expand.d.ts +1 -3
- package/dist/policy-packs/expand.js +5 -42
- package/dist/policy-packs/expand.js.map +1 -1
- package/dist/policy-packs/index.d.ts +3 -3
- package/dist/policy-packs/index.js +2 -2
- package/dist/policy-packs/index.js.map +1 -1
- package/dist/policy-packs/registry.d.ts +9 -38
- package/dist/policy-packs/registry.js +5 -65
- package/dist/policy-packs/registry.js.map +1 -1
- package/dist/policy-packs/runtime.d.ts +0 -4
- package/dist/policy-packs/runtime.js +9 -22
- package/dist/policy-packs/runtime.js.map +1 -1
- package/dist/policy-packs/types.d.ts +0 -19
- package/dist/policy-packs/ux-compare.d.ts +1 -11
- package/dist/policy-packs/ux-compare.js +6 -42
- package/dist/policy-packs/ux-compare.js.map +1 -1
- package/dist/policy-packs/ux-drift-check.d.ts +5 -5
- package/dist/policy-packs/ux-drift-check.js +17 -22
- package/dist/policy-packs/ux-drift-check.js.map +1 -1
- package/dist/policy-packs/version-check.d.ts +5 -26
- package/dist/policy-packs/version-check.js +19 -74
- package/dist/policy-packs/version-check.js.map +1 -1
- package/dist/probes/memory.d.ts +1 -1
- package/dist/probes/memory.js +1 -1
- package/dist/probes/memory.js.map +1 -1
- package/dist/runtime/agent-facing.d.ts +9 -0
- package/dist/runtime/agent-facing.js +28 -14
- package/dist/runtime/agent-facing.js.map +1 -1
- package/dist/runtime/bounded-text.d.ts +15 -0
- package/dist/runtime/bounded-text.js +27 -0
- package/dist/runtime/bounded-text.js.map +1 -0
- package/dist/runtime/git-branch.d.ts +125 -0
- package/dist/runtime/git-branch.js +381 -0
- package/dist/runtime/git-branch.js.map +1 -0
- package/dist/runtime/hermetic-spawn-guard.d.ts +2 -2
- package/dist/runtime/hermetic-spawn-guard.js +24 -34
- package/dist/runtime/hermetic-spawn-guard.js.map +1 -1
- package/dist/runtime/home-dir.js +3 -2
- package/dist/runtime/home-dir.js.map +1 -1
- package/dist/runtime/tool-name-aliases.d.ts +0 -6
- package/dist/runtime/tool-name-aliases.js +5 -18
- package/dist/runtime/tool-name-aliases.js.map +1 -1
- package/dist/schema/grounding.d.ts +7 -54
- package/dist/schema/grounding.js +10 -12
- package/dist/schema/grounding.js.map +1 -1
- package/dist/schema/hooks.d.ts +39 -136
- package/dist/schema/hooks.js +3 -6
- package/dist/schema/hooks.js.map +1 -1
- package/dist/schema/index.d.ts +114 -3828
- package/dist/schema/index.js +41 -80
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/memory.d.ts +54 -131
- package/dist/schema/memory.js +2 -2
- package/dist/schema/memory.js.map +1 -1
- package/dist/schema/policy-packs.d.ts +3 -45
- package/dist/schema/policy-packs.js +7 -13
- package/dist/schema/policy-packs.js.map +1 -1
- package/dist/schema/policy-ux.d.ts +7 -0
- package/dist/schema/policy-ux.js +18 -0
- package/dist/schema/policy-ux.js.map +1 -0
- package/dist/schema/removed-keys.d.ts +185 -0
- package/dist/schema/removed-keys.js +531 -0
- package/dist/schema/removed-keys.js.map +1 -0
- package/dist/schema/tools.d.ts +30 -268
- package/dist/schema/tools.js +4 -4
- package/dist/schema/tools.js.map +1 -1
- package/package.json +5 -16
- package/dist/cli/approve/branch-protection.d.ts +0 -69
- package/dist/cli/approve/branch-protection.js +0 -144
- package/dist/cli/approve/branch-protection.js.map +0 -1
- package/dist/cli/approve/risk.d.ts +0 -112
- package/dist/cli/approve/risk.js +0 -197
- package/dist/cli/approve/risk.js.map +0 -1
- package/dist/cli/approve/stdin-report.d.ts +0 -57
- package/dist/cli/approve/stdin-report.js +0 -145
- package/dist/cli/approve/stdin-report.js.map +0 -1
- package/dist/cli/approve/understanding.d.ts +0 -410
- package/dist/cli/approve/understanding.js +0 -996
- package/dist/cli/approve/understanding.js.map +0 -1
- package/dist/cli/audit.d.ts +0 -80
- package/dist/cli/audit.js +0 -252
- package/dist/cli/audit.js.map +0 -1
- package/dist/cli/delegate/index.d.ts +0 -76
- package/dist/cli/delegate/index.js +0 -443
- package/dist/cli/delegate/index.js.map +0 -1
- package/dist/cli/doctor/auto-approve-mode.d.ts +0 -37
- package/dist/cli/doctor/auto-approve-mode.js +0 -80
- package/dist/cli/doctor/auto-approve-mode.js.map +0 -1
- package/dist/cli/doctor/bypass-without-auto-approve.d.ts +0 -38
- package/dist/cli/doctor/bypass-without-auto-approve.js +0 -95
- package/dist/cli/doctor/bypass-without-auto-approve.js.map +0 -1
- package/dist/cli/doctor/codex-config-drift.d.ts +0 -28
- package/dist/cli/doctor/codex-config-drift.js +0 -240
- package/dist/cli/doctor/codex-config-drift.js.map +0 -1
- package/dist/cli/doctor/rogue-ledger.d.ts +0 -53
- package/dist/cli/doctor/rogue-ledger.js +0 -153
- package/dist/cli/doctor/rogue-ledger.js.map +0 -1
- package/dist/cli/doctor/session-start-preflight-setup-version.d.ts +0 -83
- package/dist/cli/doctor/session-start-preflight-setup-version.js +0 -114
- package/dist/cli/doctor/session-start-preflight-setup-version.js.map +0 -1
- package/dist/cli/doctor/settings-drift.d.ts +0 -25
- package/dist/cli/doctor/settings-drift.js +0 -213
- package/dist/cli/doctor/settings-drift.js.map +0 -1
- package/dist/cli/doctor/toolchain-parity.d.ts +0 -63
- package/dist/cli/doctor/toolchain-parity.js +0 -154
- package/dist/cli/doctor/toolchain-parity.js.map +0 -1
- package/dist/cli/doctor/ug-auto-approvals.d.ts +0 -40
- package/dist/cli/doctor/ug-auto-approvals.js +0 -91
- package/dist/cli/doctor/ug-auto-approvals.js.map +0 -1
- package/dist/cli/doctor/ug-delegations.d.ts +0 -26
- package/dist/cli/doctor/ug-delegations.js +0 -121
- package/dist/cli/doctor/ug-delegations.js.map +0 -1
- package/dist/cli/doctor/ug-inflight.d.ts +0 -35
- package/dist/cli/doctor/ug-inflight.js +0 -57
- package/dist/cli/doctor/ug-inflight.js.map +0 -1
- package/dist/cli/doctor/understanding-mode-env.d.ts +0 -51
- package/dist/cli/doctor/understanding-mode-env.js +0 -98
- package/dist/cli/doctor/understanding-mode-env.js.map +0 -1
- package/dist/cli/dry-run.d.ts +0 -46
- package/dist/cli/dry-run.js +0 -250
- package/dist/cli/dry-run.js.map +0 -1
- package/dist/cli/event-input.d.ts +0 -28
- package/dist/cli/event-input.js +0 -73
- package/dist/cli/event-input.js.map +0 -1
- package/dist/cli/explain-action.d.ts +0 -20
- package/dist/cli/explain-action.js +0 -27
- package/dist/cli/explain-action.js.map +0 -1
- package/dist/cli/explain-policy.d.ts +0 -135
- package/dist/cli/explain-policy.js +0 -266
- package/dist/cli/explain-policy.js.map +0 -1
- package/dist/cli/explain.d.ts +0 -31
- package/dist/cli/explain.js +0 -159
- package/dist/cli/explain.js.map +0 -1
- package/dist/cli/gc/index.d.ts +0 -63
- package/dist/cli/gc/index.js +0 -566
- package/dist/cli/gc/index.js.map +0 -1
- package/dist/cli/pack/approve-escape.d.ts +0 -19
- package/dist/cli/pack/approve-escape.js +0 -190
- package/dist/cli/pack/approve-escape.js.map +0 -1
- package/dist/cli/pack/auto-approve-path.d.ts +0 -146
- package/dist/cli/pack/auto-approve-path.js +0 -462
- package/dist/cli/pack/auto-approve-path.js.map +0 -1
- package/dist/cli/pack/hook-codex-post-tool-use.d.ts +0 -25
- package/dist/cli/pack/hook-codex-post-tool-use.js +0 -160
- package/dist/cli/pack/hook-codex-post-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +0 -48
- package/dist/cli/pack/hook-codex-pre-tool-use.js +0 -474
- package/dist/cli/pack/hook-codex-pre-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-codex-stop.d.ts +0 -35
- package/dist/cli/pack/hook-codex-stop.js +0 -329
- package/dist/cli/pack/hook-codex-stop.js.map +0 -1
- package/dist/cli/pack/hook-codex-user-prompt-submit.d.ts +0 -24
- package/dist/cli/pack/hook-codex-user-prompt-submit.js +0 -93
- package/dist/cli/pack/hook-codex-user-prompt-submit.js.map +0 -1
- package/dist/cli/pack/hook-post-merge-gate-record.d.ts +0 -37
- package/dist/cli/pack/hook-post-merge-gate-record.js +0 -190
- package/dist/cli/pack/hook-post-merge-gate-record.js.map +0 -1
- package/dist/cli/pack/hook-post-merge-gate.d.ts +0 -34
- package/dist/cli/pack/hook-post-merge-gate.js +0 -277
- package/dist/cli/pack/hook-post-merge-gate.js.map +0 -1
- package/dist/cli/pack/hook-post-tool-use.d.ts +0 -45
- package/dist/cli/pack/hook-post-tool-use.js +0 -137
- package/dist/cli/pack/hook-post-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-pre-tool-use.d.ts +0 -92
- package/dist/cli/pack/hook-pre-tool-use.js +0 -1328
- package/dist/cli/pack/hook-pre-tool-use.js.map +0 -1
- package/dist/cli/pack/hook-runtime-reality.d.ts +0 -63
- package/dist/cli/pack/hook-runtime-reality.js +0 -210
- package/dist/cli/pack/hook-runtime-reality.js.map +0 -1
- package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +0 -32
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js +0 -337
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +0 -1
- package/dist/cli/pack/hook-solution-acceptance.d.ts +0 -157
- package/dist/cli/pack/hook-solution-acceptance.js +0 -530
- package/dist/cli/pack/hook-solution-acceptance.js.map +0 -1
- package/dist/cli/pack/hook-stay-in-scope.d.ts +0 -37
- package/dist/cli/pack/hook-stay-in-scope.js +0 -128
- package/dist/cli/pack/hook-stay-in-scope.js.map +0 -1
- package/dist/cli/pack/hook-subagent-start.d.ts +0 -23
- package/dist/cli/pack/hook-subagent-start.js +0 -88
- package/dist/cli/pack/hook-subagent-start.js.map +0 -1
- package/dist/cli/pack/hook-subagent-stop.d.ts +0 -19
- package/dist/cli/pack/hook-subagent-stop.js +0 -41
- package/dist/cli/pack/hook-subagent-stop.js.map +0 -1
- package/dist/cli/pack/hook-track-active-claim.d.ts +0 -27
- package/dist/cli/pack/hook-track-active-claim.js +0 -275
- package/dist/cli/pack/hook-track-active-claim.js.map +0 -1
- package/dist/cli/pack/transcript-report-scan.d.ts +0 -71
- package/dist/cli/pack/transcript-report-scan.js +0 -359
- package/dist/cli/pack/transcript-report-scan.js.map +0 -1
- package/dist/cli/pack/understanding-report-schema-hint.d.ts +0 -26
- package/dist/cli/pack/understanding-report-schema-hint.js +0 -120
- package/dist/cli/pack/understanding-report-schema-hint.js.map +0 -1
- package/dist/cli/pack/upgrade.d.ts +0 -32
- package/dist/cli/pack/upgrade.js +0 -273
- package/dist/cli/pack/upgrade.js.map +0 -1
- package/dist/cli/pause/index.d.ts +0 -113
- package/dist/cli/pause/index.js +0 -251
- package/dist/cli/pause/index.js.map +0 -1
- package/dist/cli/pause-check.d.ts +0 -22
- package/dist/cli/pause-check.js +0 -54
- package/dist/cli/pause-check.js.map +0 -1
- package/dist/cli/policy/intercept.d.ts +0 -233
- package/dist/cli/policy/intercept.js +0 -1020
- package/dist/cli/policy/intercept.js.map +0 -1
- package/dist/cli/policy/risk-envelope-enrichment.d.ts +0 -40
- package/dist/cli/policy/risk-envelope-enrichment.js +0 -108
- package/dist/cli/policy/risk-envelope-enrichment.js.map +0 -1
- package/dist/cli/record/index.d.ts +0 -81
- package/dist/cli/record/index.js +0 -348
- package/dist/cli/record/index.js.map +0 -1
- package/dist/cli/resolve-env.d.ts +0 -32
- package/dist/cli/resolve-env.js +0 -47
- package/dist/cli/resolve-env.js.map +0 -1
- package/dist/cli/session-export/index.d.ts +0 -46
- package/dist/cli/session-export/index.js +0 -169
- package/dist/cli/session-export/index.js.map +0 -1
- package/dist/cli/session-export/redact.d.ts +0 -22
- package/dist/cli/session-export/redact.js +0 -47
- package/dist/cli/session-export/redact.js.map +0 -1
- package/dist/cli/session-export/transcript.d.ts +0 -24
- package/dist/cli/session-export/transcript.js +0 -164
- package/dist/cli/session-export/transcript.js.map +0 -1
- package/dist/cli/session-start/branch-check.d.ts +0 -18
- package/dist/cli/session-start/branch-check.js +0 -140
- package/dist/cli/session-start/branch-check.js.map +0 -1
- package/dist/cli/session-start/index.d.ts +0 -121
- package/dist/cli/session-start/index.js +0 -591
- package/dist/cli/session-start/index.js.map +0 -1
- package/dist/cli/session-start/shared-options.d.ts +0 -103
- package/dist/cli/session-start/shared-options.js +0 -107
- package/dist/cli/session-start/shared-options.js.map +0 -1
- package/dist/cli/session-start/stale-base-check.d.ts +0 -46
- package/dist/cli/session-start/stale-base-check.js +0 -352
- package/dist/cli/session-start/stale-base-check.js.map +0 -1
- package/dist/cli/session-start/toolchain-parity.d.ts +0 -267
- package/dist/cli/session-start/toolchain-parity.js +0 -797
- package/dist/cli/session-start/toolchain-parity.js.map +0 -1
- package/dist/cli/smoke/assertions.d.ts +0 -46
- package/dist/cli/smoke/assertions.js +0 -170
- package/dist/cli/smoke/assertions.js.map +0 -1
- package/dist/cli/smoke/index.d.ts +0 -76
- package/dist/cli/smoke/index.js +0 -245
- package/dist/cli/smoke/index.js.map +0 -1
- package/dist/cli/smoke/runner.d.ts +0 -55
- package/dist/cli/smoke/runner.js +0 -134
- package/dist/cli/smoke/runner.js.map +0 -1
- package/dist/cli/smoke/stream-parser.d.ts +0 -65
- package/dist/cli/smoke/stream-parser.js +0 -115
- package/dist/cli/smoke/stream-parser.js.map +0 -1
- package/dist/cli/test-risk.d.ts +0 -26
- package/dist/cli/test-risk.js +0 -34
- package/dist/cli/test-risk.js.map +0 -1
- package/dist/io/display-path.d.ts +0 -11
- package/dist/io/display-path.js +0 -29
- package/dist/io/display-path.js.map +0 -1
- package/dist/io/duration.d.ts +0 -5
- package/dist/io/duration.js +0 -50
- package/dist/io/duration.js.map +0 -1
- package/dist/io/extract.d.ts +0 -79
- package/dist/io/extract.js +0 -226
- package/dist/io/extract.js.map +0 -1
- package/dist/io/ledger-record.d.ts +0 -83
- package/dist/io/ledger-record.js +0 -301
- package/dist/io/ledger-record.js.map +0 -1
- package/dist/io/read-json-dir-entries.d.ts +0 -36
- package/dist/io/read-json-dir-entries.js +0 -48
- package/dist/io/read-json-dir-entries.js.map +0 -1
- package/dist/io/safe-json-parse.d.ts +0 -5
- package/dist/io/safe-json-parse.js +0 -21
- package/dist/io/safe-json-parse.js.map +0 -1
- package/dist/policies/index.d.ts +0 -5
- package/dist/policies/index.js +0 -6
- package/dist/policies/index.js.map +0 -1
- package/dist/policies/ledger-client.d.ts +0 -113
- package/dist/policies/ledger-client.js +0 -500
- package/dist/policies/ledger-client.js.map +0 -1
- package/dist/policies/producers.d.ts +0 -12
- package/dist/policies/producers.js +0 -61
- package/dist/policies/producers.js.map +0 -1
- package/dist/policies/requires.d.ts +0 -75
- package/dist/policies/requires.js +0 -240
- package/dist/policies/requires.js.map +0 -1
- package/dist/policies/timestamp.d.ts +0 -14
- package/dist/policies/timestamp.js +0 -36
- package/dist/policies/timestamp.js.map +0 -1
- package/dist/policy-packs/builtin/permission-profiles.d.ts +0 -11
- package/dist/policy-packs/builtin/permission-profiles.js +0 -74
- package/dist/policy-packs/builtin/permission-profiles.js.map +0 -1
- package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +0 -286
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js +0 -397
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/post-merge-gate.d.ts +0 -56
- package/dist/policy-packs/builtin/post-merge-gate.js +0 -347
- package/dist/policy-packs/builtin/post-merge-gate.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.d.ts +0 -50
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js +0 -151
- package/dist/policy-packs/builtin/solution-acceptance-reconnect.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +0 -323
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +0 -672
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/solution-acceptance.d.ts +0 -45
- package/dist/policy-packs/builtin/solution-acceptance.js +0 -226
- package/dist/policy-packs/builtin/solution-acceptance.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.d.ts +0 -25
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js +0 -94
- package/dist/policy-packs/builtin/understanding-before-execution/active-claim.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +0 -35
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +0 -86
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +0 -210
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +0 -361
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +0 -304
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +0 -734
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.d.ts +0 -36
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js +0 -73
- package/dist/policy-packs/builtin/understanding-before-execution/expiry-reason.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +0 -19
- package/dist/policy-packs/builtin/understanding-before-execution/index.js +0 -83
- package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.d.ts +0 -135
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js +0 -618
- package/dist/policy-packs/builtin/understanding-before-execution/inflight-records.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.d.ts +0 -25
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.js +0 -56
- package/dist/policy-packs/builtin/understanding-before-execution/ledger.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.d.ts +0 -20
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js +0 -93
- package/dist/policy-packs/builtin/understanding-before-execution/lifecycle.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/markers.d.ts +0 -126
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js +0 -245
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +0 -29
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +0 -82
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +0 -71
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +0 -175
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +0 -620
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +0 -1047
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.d.ts +0 -128
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +0 -213
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.d.ts +0 -129
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js +0 -166
- package/dist/policy-packs/builtin/understanding-before-execution/stay-in-scope-config.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.d.ts +0 -164
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js +0 -275
- package/dist/policy-packs/builtin/understanding-before-execution/task-markers.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +0 -10
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +0 -1
- package/dist/policy-packs/builtin/understanding-before-execution.d.ts +0 -526
- package/dist/policy-packs/builtin/understanding-before-execution.js +0 -1074
- package/dist/policy-packs/builtin/understanding-before-execution.js.map +0 -1
- package/dist/policy-packs/permission-translator.d.ts +0 -9
- package/dist/policy-packs/permission-translator.js +0 -76
- package/dist/policy-packs/permission-translator.js.map +0 -1
- package/dist/runtime/action-envelope.d.ts +0 -64
- package/dist/runtime/action-envelope.js +0 -46
- package/dist/runtime/action-envelope.js.map +0 -1
- package/dist/runtime/approval-signing.d.ts +0 -111
- package/dist/runtime/approval-signing.js +0 -384
- package/dist/runtime/approval-signing.js.map +0 -1
- package/dist/runtime/bash-match-facts.d.ts +0 -60
- package/dist/runtime/bash-match-facts.js +0 -196
- package/dist/runtime/bash-match-facts.js.map +0 -1
- package/dist/runtime/bash-match-registry.d.ts +0 -112
- package/dist/runtime/bash-match-registry.js +0 -406
- package/dist/runtime/bash-match-registry.js.map +0 -1
- package/dist/runtime/bash-prefix-parse.d.ts +0 -31
- package/dist/runtime/bash-prefix-parse.js +0 -576
- package/dist/runtime/bash-prefix-parse.js.map +0 -1
- package/dist/runtime/command-normalize.d.ts +0 -658
- package/dist/runtime/command-normalize.js +0 -2410
- package/dist/runtime/command-normalize.js.map +0 -1
- package/dist/runtime/deletion-target-resolve.d.ts +0 -28
- package/dist/runtime/deletion-target-resolve.js +0 -1078
- package/dist/runtime/deletion-target-resolve.js.map +0 -1
- package/dist/runtime/destructive-shell-floor.d.ts +0 -19
- package/dist/runtime/destructive-shell-floor.js +0 -611
- package/dist/runtime/destructive-shell-floor.js.map +0 -1
- package/dist/runtime/environment-resolver.d.ts +0 -36
- package/dist/runtime/environment-resolver.js +0 -138
- package/dist/runtime/environment-resolver.js.map +0 -1
- package/dist/runtime/git-context.d.ts +0 -201
- package/dist/runtime/git-context.js +0 -422
- package/dist/runtime/git-context.js.map +0 -1
- package/dist/runtime/index.d.ts +0 -12
- package/dist/runtime/index.js +0 -13
- package/dist/runtime/index.js.map +0 -1
- package/dist/runtime/intercept.d.ts +0 -494
- package/dist/runtime/intercept.js +0 -1313
- package/dist/runtime/intercept.js.map +0 -1
- package/dist/runtime/kube-context.d.ts +0 -16
- package/dist/runtime/kube-context.js +0 -63
- package/dist/runtime/kube-context.js.map +0 -1
- package/dist/runtime/kubectl-target-parse.d.ts +0 -31
- package/dist/runtime/kubectl-target-parse.js +0 -249
- package/dist/runtime/kubectl-target-parse.js.map +0 -1
- package/dist/runtime/ledger-add.d.ts +0 -16
- package/dist/runtime/ledger-add.js +0 -150
- package/dist/runtime/ledger-add.js.map +0 -1
- package/dist/runtime/ledger-writer.d.ts +0 -27
- package/dist/runtime/ledger-writer.js +0 -46
- package/dist/runtime/ledger-writer.js.map +0 -1
- package/dist/runtime/pause-sentinel.d.ts +0 -60
- package/dist/runtime/pause-sentinel.js +0 -156
- package/dist/runtime/pause-sentinel.js.map +0 -1
- package/dist/runtime/pending-approval.d.ts +0 -23
- package/dist/runtime/pending-approval.js +0 -67
- package/dist/runtime/pending-approval.js.map +0 -1
- package/dist/runtime/read-only-bash.d.ts +0 -141
- package/dist/runtime/read-only-bash.js +0 -2204
- package/dist/runtime/read-only-bash.js.map +0 -1
- package/dist/runtime/recovery-git-commit.d.ts +0 -22
- package/dist/runtime/recovery-git-commit.js +0 -284
- package/dist/runtime/recovery-git-commit.js.map +0 -1
- package/dist/runtime/reject-malformed-session-id.d.ts +0 -8
- package/dist/runtime/reject-malformed-session-id.js +0 -16
- package/dist/runtime/reject-malformed-session-id.js.map +0 -1
- package/dist/runtime/risk-classifier.d.ts +0 -38
- package/dist/runtime/risk-classifier.js +0 -311
- package/dist/runtime/risk-classifier.js.map +0 -1
- package/dist/runtime/session-id.d.ts +0 -113
- package/dist/runtime/session-id.js +0 -193
- package/dist/runtime/session-id.js.map +0 -1
- package/dist/runtime/shell-word.d.ts +0 -62
- package/dist/runtime/shell-word.js +0 -410
- package/dist/runtime/shell-word.js.map +0 -1
- package/dist/runtime/task-providers/agent-tasks.d.ts +0 -103
- package/dist/runtime/task-providers/agent-tasks.js +0 -245
- package/dist/runtime/task-providers/agent-tasks.js.map +0 -1
- package/dist/runtime/when-eval.d.ts +0 -62
- package/dist/runtime/when-eval.js +0 -212
- package/dist/runtime/when-eval.js.map +0 -1
- package/dist/runtime/workflow-policies.d.ts +0 -207
- package/dist/runtime/workflow-policies.js +0 -596
- package/dist/runtime/workflow-policies.js.map +0 -1
- package/dist/schema/audit.d.ts +0 -71
- package/dist/schema/audit.js +0 -32
- package/dist/schema/audit.js.map +0 -1
- package/dist/schema/doctor.d.ts +0 -25
- package/dist/schema/doctor.js +0 -23
- package/dist/schema/doctor.js.map +0 -1
- package/dist/schema/environments.d.ts +0 -215
- package/dist/schema/environments.js +0 -101
- package/dist/schema/environments.js.map +0 -1
- package/dist/schema/extract.d.ts +0 -9
- package/dist/schema/extract.js +0 -86
- package/dist/schema/extract.js.map +0 -1
- package/dist/schema/permission-profiles.d.ts +0 -2292
- package/dist/schema/permission-profiles.js +0 -60
- package/dist/schema/permission-profiles.js.map +0 -1
- package/dist/schema/policies.d.ts +0 -974
- package/dist/schema/policies.js +0 -298
- package/dist/schema/policies.js.map +0 -1
- package/dist/schema/requires.d.ts +0 -131
- package/dist/schema/requires.js +0 -88
- package/dist/schema/requires.js.map +0 -1
- package/dist/schema/risk.d.ts +0 -144
- package/dist/schema/risk.js +0 -194
- package/dist/schema/risk.js.map +0 -1
- package/dist/schema/session-start-preflight.d.ts +0 -10
- package/dist/schema/session-start-preflight.js +0 -106
- package/dist/schema/session-start-preflight.js.map +0 -1
- package/dist/schema/stale-base-check.d.ts +0 -18
- package/dist/schema/stale-base-check.js +0 -37
- package/dist/schema/stale-base-check.js.map +0 -1
- package/dist/schema/toolchain-parity.d.ts +0 -21
- package/dist/schema/toolchain-parity.js +0 -48
- package/dist/schema/toolchain-parity.js.map +0 -1
- package/dist/schema/workflows.d.ts +0 -519
- package/dist/schema/workflows.js +0 -81
- package/dist/schema/workflows.js.map +0 -1
- package/scripts/runtime-reality-docker-probe.mjs +0 -71
|
@@ -1,797 +0,0 @@
|
|
|
1
|
-
// `harness session-start toolchain-parity` — SessionStart hook entrypoint,
|
|
2
|
-
// third sibling of `harness session-start preflight` / `branch-check`.
|
|
3
|
-
//
|
|
4
|
-
// Anlass: the 2026-07-22 PATH-shim incident, where a machine ran an entire
|
|
5
|
-
// session unnoticed on Node 22 + understanding-gate 0.4.6 instead of the
|
|
6
|
-
// intended Node 26 + 0.4.9 — nothing on that machine ever compared its own
|
|
7
|
-
// toolchain against any other machine's. This producer closes that gap,
|
|
8
|
-
// purely advisorily:
|
|
9
|
-
//
|
|
10
|
-
// (a) writes a toolchain snapshot of THIS machine to
|
|
11
|
-
// `<machineStateDir>/<ownProfile>.json` (owner-writes-only — every
|
|
12
|
-
// OTHER `*.json` in that directory is read-only input, never
|
|
13
|
-
// touched);
|
|
14
|
-
// (b) compares the local LIVE toolchain state against every peer
|
|
15
|
-
// snapshot file already in that directory;
|
|
16
|
-
// (c) reports drift as stderr warning lines plus a single
|
|
17
|
-
// `toolchain-parity:ok` / `toolchain-parity:drift:<n>` ledger fact,
|
|
18
|
-
// with a `:unparseable-peer:<n>` suffix appended whenever one or more
|
|
19
|
-
// peer files failed to parse as JSON (task 690fba7c, follow-up from
|
|
20
|
-
// the agent-memory 06d09cde incident: an unparseable peer snapshot is
|
|
21
|
-
// a real corruption/drift signal and must not vanish from `drift:N`
|
|
22
|
-
// as if it had been a complete comparison).
|
|
23
|
-
//
|
|
24
|
-
// Transport of the snapshot files BETWEEN machines is entirely
|
|
25
|
-
// agent-memory-sync's job (agent-memory PR #64, already shipped) — this
|
|
26
|
-
// module only ever reads/writes the local directory.
|
|
27
|
-
//
|
|
28
|
-
// SessionStart contract, same as the two siblings: `blocking:false`. Every
|
|
29
|
-
// failure path (not configured, mkdir/write/read failure, a broken peer
|
|
30
|
-
// file, a spawn timeout, a ledger-write failure) logs one line to stderr
|
|
31
|
-
// and exits 0. There is no "gate" this producer can leave closed — it is
|
|
32
|
-
// purely advisory, so degrading silently (well, LOUDLY on stderr, just
|
|
33
|
-
// never blocking) is always the right move.
|
|
34
|
-
import { execFile } from "node:child_process";
|
|
35
|
-
import * as fs from "node:fs";
|
|
36
|
-
import * as os from "node:os";
|
|
37
|
-
import * as path from "node:path";
|
|
38
|
-
import { readTopLevelMcpServers, resolveClaudeUserRegistryPath, } from "../../io/claude-mcp.js";
|
|
39
|
-
import { assertNoRealSpawnInTests } from "../../runtime/hermetic-spawn-guard.js";
|
|
40
|
-
import { resolveManifestLedgerWriter } from "../../runtime/ledger-writer.js";
|
|
41
|
-
import { resolveReadSessionId, } from "../../runtime/session-id.js";
|
|
42
|
-
import { loadManifest } from "../loader.js";
|
|
43
|
-
import { classifySessionSource, explicitSessionId, FALLBACK_SESSION, malformedEventReason, readSessionStartEvent, resolveEventCwd, } from "./shared-options.js";
|
|
44
|
-
const LEDGER_SOURCE = "harness-session-start-toolchain-parity";
|
|
45
|
-
const SNAPSHOT_SCHEMA_VERSION = 1;
|
|
46
|
-
// Individual spawn ceilings, not the expected duration: `node --version`
|
|
47
|
-
// and `npm ls -g --depth=0 --json` run IN PARALLEL (Promise.all in
|
|
48
|
-
// collectLocalSnapshot below), so the wall-time contribution of the two
|
|
49
|
-
// spawns together is max(nodeTimeoutMs, npmTimeoutMs), not their sum.
|
|
50
|
-
// Combined with two near-instant fs reads (OW-Kit version, MCP registry)
|
|
51
|
-
// and a SEQUENTIAL ledger write afterwards, the worst-case wall-time this
|
|
52
|
-
// hook needs against its configured `budget_ms` (and how much headroom
|
|
53
|
-
// that leaves) is analyzed once, at the hook's own `budget_ms`
|
|
54
|
-
// declaration in src/cli/init/templates.ts — search "toolchain-parity"
|
|
55
|
-
// there. That comment is the single place the number lives; this one
|
|
56
|
-
// deliberately does not restate it (task c1b5ade5 R2, closing a drift
|
|
57
|
-
// between the two comments a prior round introduced).
|
|
58
|
-
const DEFAULT_NODE_TIMEOUT_MS = 2_000;
|
|
59
|
-
const DEFAULT_NPM_GLOBALS_TIMEOUT_MS = 4_000;
|
|
60
|
-
/**
|
|
61
|
-
* Profile names land in a filename; strip anything not filename-safe.
|
|
62
|
-
* Exported (task 13919613) so `harness doctor`'s toolchain-parity section
|
|
63
|
-
* can resolve the SAME own-profile filename this producer would, without
|
|
64
|
-
* re-implementing the sanitization rule. Pure export, no behaviour change
|
|
65
|
-
* to any call site in this module.
|
|
66
|
-
*/
|
|
67
|
-
export function sanitizeProfileName(value) {
|
|
68
|
-
const cleaned = value.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
69
|
-
return cleaned.length > 0 ? cleaned : "profile";
|
|
70
|
-
}
|
|
71
|
-
function isRecordOfStrings(x) {
|
|
72
|
-
return (typeof x === "object" &&
|
|
73
|
-
x !== null &&
|
|
74
|
-
!Array.isArray(x) &&
|
|
75
|
-
Object.values(x).every((v) => typeof v === "string"));
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Parse a stored snapshot JSON. Rejects (`ok:false`) only on the shapes
|
|
79
|
-
* that make comparison meaningless — not valid JSON, not an object,
|
|
80
|
-
* missing/invalid `profile` or `timestamp`. Every other field degrades
|
|
81
|
-
* leniently (missing/malformed -> empty/absent) rather than rejecting the
|
|
82
|
-
* whole file, since a peer snapshot written by a future schema version
|
|
83
|
-
* should still compare on the fields this version understands.
|
|
84
|
-
*/
|
|
85
|
-
export function parseSnapshotJson(raw) {
|
|
86
|
-
let parsed;
|
|
87
|
-
try {
|
|
88
|
-
parsed = JSON.parse(raw);
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
return { ok: false, reason: `not valid JSON: ${err.message}` };
|
|
92
|
-
}
|
|
93
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
94
|
-
return { ok: false, reason: "not a JSON object" };
|
|
95
|
-
}
|
|
96
|
-
const p = parsed;
|
|
97
|
-
if (typeof p["profile"] !== "string" || p["profile"].length === 0) {
|
|
98
|
-
return { ok: false, reason: "missing or invalid `profile` field" };
|
|
99
|
-
}
|
|
100
|
-
if (typeof p["timestamp"] !== "string" || Number.isNaN(Date.parse(p["timestamp"]))) {
|
|
101
|
-
return { ok: false, reason: "missing or invalid `timestamp` field" };
|
|
102
|
-
}
|
|
103
|
-
const snapshot = {
|
|
104
|
-
schemaVersion: SNAPSHOT_SCHEMA_VERSION,
|
|
105
|
-
profile: p["profile"],
|
|
106
|
-
timestamp: p["timestamp"],
|
|
107
|
-
npmGlobals: isRecordOfStrings(p["npmGlobals"]) ? p["npmGlobals"] : {},
|
|
108
|
-
mcpServers: Array.isArray(p["mcpServers"]) && p["mcpServers"].every((v) => typeof v === "string")
|
|
109
|
-
? p["mcpServers"]
|
|
110
|
-
: [],
|
|
111
|
-
};
|
|
112
|
-
if (typeof p["node"] === "string")
|
|
113
|
-
snapshot.node = p["node"];
|
|
114
|
-
if (typeof p["nodeError"] === "string")
|
|
115
|
-
snapshot.nodeError = p["nodeError"];
|
|
116
|
-
if (typeof p["npmGlobalsError"] === "string")
|
|
117
|
-
snapshot.npmGlobalsError = p["npmGlobalsError"];
|
|
118
|
-
if (typeof p["owKitVersion"] === "string")
|
|
119
|
-
snapshot.owKitVersion = p["owKitVersion"];
|
|
120
|
-
if (typeof p["owKitError"] === "string")
|
|
121
|
-
snapshot.owKitError = p["owKitError"];
|
|
122
|
-
if (typeof p["mcpServersError"] === "string")
|
|
123
|
-
snapshot.mcpServersError = p["mcpServersError"];
|
|
124
|
-
return { ok: true, snapshot };
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Hermetic guard (mirrors `realNpmExec` in src/cli/doctor/npm-bin-path.ts):
|
|
128
|
-
* asserts BEFORE touching `child_process` that we are not running under
|
|
129
|
-
* vitest without a test having injected `runNodeVersion`. This function has
|
|
130
|
-
* no try/catch around the assertion, and its only caller,
|
|
131
|
-
* `collectLocalSnapshot`, calls it (via the `runNodeVersion` param, defaulted
|
|
132
|
-
* to this function in `runSessionStartToolchainParity`) with no surrounding
|
|
133
|
-
* try/catch either — see src/runtime/hermetic-spawn-guard.ts for why that
|
|
134
|
-
* matters (a thrown `HermeticSpawnViolationError` must propagate, not be
|
|
135
|
-
* folded into an ordinary "collection failed" outcome).
|
|
136
|
-
*
|
|
137
|
-
* PATH-resolved deliberately: `execFile("node", ...)` does a PATH lookup for
|
|
138
|
-
* the literal string "node", NOT `process.execPath` — the entire point of
|
|
139
|
-
* this collector is capturing the PATH state of the *shell* the session
|
|
140
|
-
* runs in (the PATH-shim incident this task follows up on was exactly a
|
|
141
|
-
* PATH pointing at the wrong node), which `process.version` (the node
|
|
142
|
-
* running THIS harness process) would silently paper over.
|
|
143
|
-
*
|
|
144
|
-
* Exported (task 13919613) so `harness doctor`'s toolchain-parity section
|
|
145
|
-
* can default its own `runNodeVersion` injection knob to the SAME real
|
|
146
|
-
* collector this producer uses — the whole point of the reuse is that
|
|
147
|
-
* doctor never re-implements this spawn/parse logic. No behaviour change:
|
|
148
|
-
* this is the exact function every existing call site already used.
|
|
149
|
-
*/
|
|
150
|
-
export function realNodeVersionSpawn(timeoutMs) {
|
|
151
|
-
assertNoRealSpawnInTests("node --version", "Inject a fake `runNodeVersion` (SessionStartToolchainParityOptions.runNodeVersion) instead of exercising the real spawn path.");
|
|
152
|
-
return new Promise((resolve) => {
|
|
153
|
-
execFile("node", ["--version"], { timeout: timeoutMs, encoding: "utf8" }, (err, stdout) => {
|
|
154
|
-
const text = (stdout ?? "").trim();
|
|
155
|
-
if (text.length > 0) {
|
|
156
|
-
resolve({ ok: true, version: text });
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (err) {
|
|
160
|
-
const e = err;
|
|
161
|
-
if (e.code === "ENOENT") {
|
|
162
|
-
resolve({ ok: false, reason: "`node` not on PATH" });
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
if (e.killed) {
|
|
166
|
-
resolve({ ok: false, reason: `\`node --version\` timed out after ${timeoutMs}ms` });
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
resolve({ ok: false, reason: `\`node --version\` failed: ${e.message}` });
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
resolve({ ok: false, reason: "`node --version` produced no output" });
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Hermetic guard, same shape/rationale as {@link realNodeVersionSpawn} —
|
|
178
|
-
* see that function's doc. Tolerant of a non-zero exit the same way
|
|
179
|
-
* `spawnPreflight` (session-start/index.ts) is tolerant of `preflight run`'s
|
|
180
|
-
* exit code: `npm ls -g` can exit non-zero on an unrelated extraneous/
|
|
181
|
-
* invalid global entry while still emitting a perfectly parseable
|
|
182
|
-
* `dependencies` JSON block, so a parseable stdout wins over the exit code.
|
|
183
|
-
*
|
|
184
|
-
* Exported (task 13919613) for the same reuse reason as
|
|
185
|
-
* {@link realNodeVersionSpawn} — `harness doctor`'s toolchain-parity
|
|
186
|
-
* section defaults to this real collector rather than duplicating it.
|
|
187
|
-
*/
|
|
188
|
-
export function realNpmGlobalsSpawn(timeoutMs) {
|
|
189
|
-
assertNoRealSpawnInTests("npm ls -g --depth=0 --json", "Inject a fake `runNpmGlobals` (SessionStartToolchainParityOptions.runNpmGlobals) instead of exercising the real spawn path.");
|
|
190
|
-
return new Promise((resolve) => {
|
|
191
|
-
execFile("npm", ["ls", "-g", "--depth=0", "--json"], { timeout: timeoutMs, maxBuffer: 8 * 1024 * 1024, encoding: "utf8" }, (err, stdout) => {
|
|
192
|
-
const text = (stdout ?? "").trim();
|
|
193
|
-
if (text.length > 0) {
|
|
194
|
-
try {
|
|
195
|
-
const parsed = JSON.parse(text);
|
|
196
|
-
const packages = {};
|
|
197
|
-
for (const [name, entry] of Object.entries(parsed.dependencies ?? {})) {
|
|
198
|
-
if (typeof entry?.version === "string")
|
|
199
|
-
packages[name] = entry.version;
|
|
200
|
-
}
|
|
201
|
-
resolve({ ok: true, packages });
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
catch {
|
|
205
|
-
/* fall through to the error path */
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (err) {
|
|
209
|
-
const e = err;
|
|
210
|
-
if (e.code === "ENOENT") {
|
|
211
|
-
resolve({ ok: false, reason: "`npm` not on PATH" });
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
if (e.killed) {
|
|
215
|
-
resolve({
|
|
216
|
-
ok: false,
|
|
217
|
-
reason: `\`npm ls -g --depth=0 --json\` timed out after ${timeoutMs}ms`,
|
|
218
|
-
});
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
resolve({ ok: false, reason: `\`npm ls -g\` failed: ${e.message}` });
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
resolve({ ok: false, reason: "`npm ls -g --depth=0 --json` produced no parseable JSON" });
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Read `<workspaceRoot>/.ai/workflow/manifest.json`'s `version` field
|
|
230
|
-
* (the orchestrator-workflow kit's own version marker). A missing file is
|
|
231
|
-
* the expected common case (most repos are not OW-kit-managed) and is
|
|
232
|
-
* NOT an error — it degrades silently to `{}`. Malformed JSON or a
|
|
233
|
-
* non-string `version` field on a manifest that DOES exist is noteworthy
|
|
234
|
-
* (something is there but broken), so that degrades to `{ error }`.
|
|
235
|
-
*
|
|
236
|
-
* Exported (task 13919613) for the same reuse reason as
|
|
237
|
-
* {@link realNodeVersionSpawn}.
|
|
238
|
-
*/
|
|
239
|
-
export function realReadOwKitVersion(workspaceRoot) {
|
|
240
|
-
const manifestPath = path.join(workspaceRoot, ".ai", "workflow", "manifest.json");
|
|
241
|
-
let raw;
|
|
242
|
-
try {
|
|
243
|
-
raw = fs.readFileSync(manifestPath, "utf8");
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
const e = err;
|
|
247
|
-
if (e.code === "ENOENT")
|
|
248
|
-
return {};
|
|
249
|
-
return { error: `cannot read ${manifestPath}: ${e.message}` };
|
|
250
|
-
}
|
|
251
|
-
let parsed;
|
|
252
|
-
try {
|
|
253
|
-
parsed = JSON.parse(raw);
|
|
254
|
-
}
|
|
255
|
-
catch (err) {
|
|
256
|
-
return { error: `${manifestPath} is not valid JSON: ${err.message}` };
|
|
257
|
-
}
|
|
258
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
259
|
-
return { error: `${manifestPath} is not a JSON object` };
|
|
260
|
-
}
|
|
261
|
-
const version = parsed["version"];
|
|
262
|
-
if (typeof version !== "string" || version.length === 0) {
|
|
263
|
-
return { error: `${manifestPath} has no string \`version\` field` };
|
|
264
|
-
}
|
|
265
|
-
return { version };
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* MCP server names from Claude Code's user-scope registry — a pure FILE
|
|
269
|
-
* READ (never a spawn), reusing the exact primitive `harness doctor`'s
|
|
270
|
-
* claude-mcp check ultimately compares against
|
|
271
|
-
* (`resolveClaudeUserRegistryPath` + `readTopLevelMcpServers` in
|
|
272
|
-
* src/io/claude-mcp.ts — the same functions `adopt`/`detect` use for the
|
|
273
|
-
* same "read the effective registration from outside io/claude-mcp.ts"
|
|
274
|
-
* purpose). Deliberately NOT `claude mcp list` (a spawn): the brief calls
|
|
275
|
-
* for a file-read source for the NAMES here, and this is it.
|
|
276
|
-
*
|
|
277
|
-
* Exported (task 13919613) for the same reuse reason as
|
|
278
|
-
* {@link realNodeVersionSpawn}.
|
|
279
|
-
*/
|
|
280
|
-
export function realReadMcpServerNames() {
|
|
281
|
-
const registryPath = resolveClaudeUserRegistryPath();
|
|
282
|
-
const { servers, error } = readTopLevelMcpServers(registryPath);
|
|
283
|
-
if (error !== null)
|
|
284
|
-
return { names: [], error };
|
|
285
|
-
return { names: Object.keys(servers).sort() };
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Collect the local, LIVE toolchain snapshot. Never throws (every
|
|
289
|
-
* collector above degrades to `{ok:false,reason}` / `{error}` instead of
|
|
290
|
-
* rejecting/throwing) — a collection failure is reported both inline on
|
|
291
|
-
* the returned snapshot (the matching `*Error` field) AND as a `notes`
|
|
292
|
-
* line for the caller to log, but never stops the other collectors from
|
|
293
|
-
* running. node/npm run in PARALLEL (see the timeout constants' comment
|
|
294
|
-
* above for why).
|
|
295
|
-
*
|
|
296
|
-
* Exported (task 13919613): `harness doctor`'s toolchain-parity section
|
|
297
|
-
* imports this directly as its Collector core — see that module's header
|
|
298
|
-
* for the reuse rationale. No behaviour change to this function or any
|
|
299
|
-
* existing call site.
|
|
300
|
-
*/
|
|
301
|
-
export async function collectLocalSnapshot(opts) {
|
|
302
|
-
const notes = [];
|
|
303
|
-
const [nodeResult, npmResult] = await Promise.all([
|
|
304
|
-
opts.runNodeVersion(opts.nodeTimeoutMs),
|
|
305
|
-
opts.runNpmGlobals(opts.npmTimeoutMs),
|
|
306
|
-
]);
|
|
307
|
-
const owKit = opts.readOwKitVersion(opts.workspaceRoot);
|
|
308
|
-
const mcp = opts.readMcpServerNames();
|
|
309
|
-
const snapshot = {
|
|
310
|
-
schemaVersion: SNAPSHOT_SCHEMA_VERSION,
|
|
311
|
-
profile: opts.profile,
|
|
312
|
-
timestamp: opts.now.toISOString(),
|
|
313
|
-
npmGlobals: {},
|
|
314
|
-
mcpServers: [],
|
|
315
|
-
};
|
|
316
|
-
if (nodeResult.ok) {
|
|
317
|
-
snapshot.node = nodeResult.version;
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
snapshot.nodeError = nodeResult.reason;
|
|
321
|
-
notes.push(`node --version: ${nodeResult.reason}`);
|
|
322
|
-
}
|
|
323
|
-
if (npmResult.ok) {
|
|
324
|
-
snapshot.npmGlobals = npmResult.packages;
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
snapshot.npmGlobalsError = npmResult.reason;
|
|
328
|
-
notes.push(`npm ls -g: ${npmResult.reason}`);
|
|
329
|
-
}
|
|
330
|
-
if (owKit.version !== undefined)
|
|
331
|
-
snapshot.owKitVersion = owKit.version;
|
|
332
|
-
if (owKit.error !== undefined) {
|
|
333
|
-
snapshot.owKitError = owKit.error;
|
|
334
|
-
notes.push(`OW-Kit version: ${owKit.error}`);
|
|
335
|
-
}
|
|
336
|
-
if (mcp.error !== undefined) {
|
|
337
|
-
snapshot.mcpServersError = mcp.error;
|
|
338
|
-
notes.push(`MCP server names: ${mcp.error}`);
|
|
339
|
-
}
|
|
340
|
-
else {
|
|
341
|
-
snapshot.mcpServers = mcp.names;
|
|
342
|
-
}
|
|
343
|
-
return { snapshot, notes };
|
|
344
|
-
}
|
|
345
|
-
// ---------------------------------------------------------------------
|
|
346
|
-
// Snapshot write (own profile only) + peer comparison
|
|
347
|
-
// ---------------------------------------------------------------------
|
|
348
|
-
/**
|
|
349
|
-
* Write ONLY `<machineStateDir>/<ownFileName>` (mkdir -p first). Never
|
|
350
|
-
* touches any other file in the directory — the caller passes exactly
|
|
351
|
-
* `sanitizeProfileName(profile) + ".json"`, so there is no path this
|
|
352
|
-
* function could take that reaches a peer's file.
|
|
353
|
-
*/
|
|
354
|
-
function writeOwnSnapshot(machineStateDir, ownFileName, snapshot) {
|
|
355
|
-
const filePath = path.join(machineStateDir, ownFileName);
|
|
356
|
-
try {
|
|
357
|
-
fs.writeFileSync(filePath, `${JSON.stringify(snapshot, null, 2)}\n`, "utf8");
|
|
358
|
-
return { ok: true, path: filePath };
|
|
359
|
-
}
|
|
360
|
-
catch (err) {
|
|
361
|
-
return { ok: false, reason: err.message };
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
/** `"just now"` / `"<n>m"` / `"<n>h"` / `"<n>d"` — coarse, human-scannable. */
|
|
365
|
-
export function formatSnapshotAge(ageMs) {
|
|
366
|
-
if (ageMs < 60_000)
|
|
367
|
-
return "just now";
|
|
368
|
-
const minutes = Math.floor(ageMs / 60_000);
|
|
369
|
-
if (minutes < 60)
|
|
370
|
-
return `${minutes}m`;
|
|
371
|
-
const hours = Math.floor(minutes / 60);
|
|
372
|
-
if (hours < 48)
|
|
373
|
-
return `${hours}h`;
|
|
374
|
-
return `${Math.floor(hours / 24)}d`;
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* Compare the local LIVE snapshot against one peer's stored snapshot.
|
|
378
|
-
* Node / OW-Kit drift only fires when BOTH sides collected that field
|
|
379
|
-
* successfully (an unavailable field reads as "unknown", not "match" or
|
|
380
|
-
* "drift"). The npm-globals and MCP-name comparisons additionally gate on
|
|
381
|
-
* the WHOLE field having collected without error on both sides — an
|
|
382
|
-
* `npmGlobalsError`/`mcpServersError` on either side means that side's map
|
|
383
|
-
* is "unknown", not "empty", and treating it as empty would fabricate a
|
|
384
|
-
* wall of "missing on N packages" drift instead of the real gap (which the
|
|
385
|
-
* caller's own note()s already surface separately, from collectLocalSnapshot's
|
|
386
|
-
* `notes` and the peer-unreadable path).
|
|
387
|
-
*/
|
|
388
|
-
export function compareToPeer(local, peer, now) {
|
|
389
|
-
const drift = [];
|
|
390
|
-
const peerProfile = peer.profile;
|
|
391
|
-
if (local.node !== undefined && peer.node !== undefined && local.node !== peer.node) {
|
|
392
|
-
drift.push({
|
|
393
|
-
kind: "node",
|
|
394
|
-
message: `node version: local ${local.node} vs peer ${peerProfile} ${peer.node}`,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
if (local.owKitVersion !== undefined &&
|
|
398
|
-
peer.owKitVersion !== undefined &&
|
|
399
|
-
local.owKitVersion !== peer.owKitVersion) {
|
|
400
|
-
drift.push({
|
|
401
|
-
kind: "ow_kit",
|
|
402
|
-
message: `orchestrator-workflow kit version: local ${local.owKitVersion} vs peer ${peerProfile} ${peer.owKitVersion}`,
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
if (local.npmGlobalsError === undefined && peer.npmGlobalsError === undefined) {
|
|
406
|
-
const names = [...new Set([...Object.keys(local.npmGlobals), ...Object.keys(peer.npmGlobals)])].sort();
|
|
407
|
-
for (const name of names) {
|
|
408
|
-
const lv = local.npmGlobals[name];
|
|
409
|
-
const pv = peer.npmGlobals[name];
|
|
410
|
-
if (lv !== undefined && pv !== undefined) {
|
|
411
|
-
if (lv !== pv) {
|
|
412
|
-
drift.push({
|
|
413
|
-
kind: "npm_package_version",
|
|
414
|
-
message: `npm global \`${name}\`: local ${lv} vs peer ${peerProfile} ${pv}`,
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
else if (lv !== undefined) {
|
|
419
|
-
drift.push({
|
|
420
|
-
kind: "npm_package_missing_peer",
|
|
421
|
-
message: `npm global \`${name}\`: local ${lv}, missing on peer ${peerProfile}`,
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
else if (pv !== undefined) {
|
|
425
|
-
drift.push({
|
|
426
|
-
kind: "npm_package_missing_local",
|
|
427
|
-
message: `npm global \`${name}\`: missing locally, peer ${peerProfile} has ${pv}`,
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
if (local.mcpServersError === undefined && peer.mcpServersError === undefined) {
|
|
433
|
-
const localSet = new Set(local.mcpServers);
|
|
434
|
-
const peerSet = new Set(peer.mcpServers);
|
|
435
|
-
const names = [...new Set([...localSet, ...peerSet])].sort();
|
|
436
|
-
for (const name of names) {
|
|
437
|
-
if (localSet.has(name) && !peerSet.has(name)) {
|
|
438
|
-
drift.push({
|
|
439
|
-
kind: "mcp_missing_peer",
|
|
440
|
-
message: `mcp server \`${name}\`: registered locally, missing on peer ${peerProfile}`,
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
else if (!localSet.has(name) && peerSet.has(name)) {
|
|
444
|
-
drift.push({
|
|
445
|
-
kind: "mcp_missing_local",
|
|
446
|
-
message: `mcp server \`${name}\`: missing locally, registered on peer ${peerProfile}`,
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
const peerTimeMs = Date.parse(peer.timestamp);
|
|
452
|
-
const ageMs = Number.isFinite(peerTimeMs) ? Math.max(0, now.getTime() - peerTimeMs) : 0;
|
|
453
|
-
return { peerProfile, ageMs, drift };
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Exported (task 13919613) so `harness doctor`'s toolchain-parity section
|
|
457
|
-
* resolves the SAME default machine-state directory this producer writes
|
|
458
|
-
* to when `toolchain_parity.machine_state_dir` is omitted from the
|
|
459
|
-
* manifest — reusing the constant instead of re-deriving it.
|
|
460
|
-
*/
|
|
461
|
-
export function defaultMachineStateDir() {
|
|
462
|
-
return path.join(os.homedir(), ".harness", "machine-state");
|
|
463
|
-
}
|
|
464
|
-
export async function runSessionStartToolchainParity(opts = {}) {
|
|
465
|
-
const stdin = opts.stdin ?? process.stdin;
|
|
466
|
-
const stderr = opts.stderr ?? process.stderr;
|
|
467
|
-
const now = opts.now ?? new Date();
|
|
468
|
-
const nodeTimeoutMs = opts.nodeTimeoutMs ?? DEFAULT_NODE_TIMEOUT_MS;
|
|
469
|
-
const npmTimeoutMs = opts.npmTimeoutMs ?? DEFAULT_NPM_GLOBALS_TIMEOUT_MS;
|
|
470
|
-
const note = (msg) => {
|
|
471
|
-
// CR/LF strip, ONCE, at this choke point (task c1b5ade5 R2b, closing
|
|
472
|
-
// what R2's per-site sanitizeProfileName wraps left open): every
|
|
473
|
-
// note() call writes exactly one stderr line prefixed with
|
|
474
|
-
// "harness session-start toolchain-parity: ". Untrusted, cross-machine-
|
|
475
|
-
// synced content reaches a note() argument through roughly ten call
|
|
476
|
-
// sites below — a peer's `profile` field, a peer filename, and an
|
|
477
|
-
// npm/mcp/node/owKitVersion value embedded in a compareToPeer drift
|
|
478
|
-
// message — and R2 sanitized only 2 of them (the collision and stale
|
|
479
|
-
// notes), leaving the rest (the "ok against"/"drift:N against" lines,
|
|
480
|
-
// every individual drift message, and two of the three peer-file-read
|
|
481
|
-
// notes) able to have a crafted `\n` forge a standalone fake parity
|
|
482
|
-
// line. Stripping CR/LF here closes the whole class by construction,
|
|
483
|
-
// regardless of which site the untrusted string flows through or
|
|
484
|
-
// whether a future site remembers to sanitize its own argument.
|
|
485
|
-
stderr.write(`harness session-start toolchain-parity: ${msg.replace(/[\r\n]/g, " ")}\n`);
|
|
486
|
-
};
|
|
487
|
-
const done = (wrote, profile, peersCompared, driftCount, sessionId, sessionSource, reason, unparseablePeerCount = 0) => ({
|
|
488
|
-
exitCode: 0,
|
|
489
|
-
wrote,
|
|
490
|
-
profile,
|
|
491
|
-
peersCompared,
|
|
492
|
-
driftCount,
|
|
493
|
-
unparseablePeerCount,
|
|
494
|
-
sessionId,
|
|
495
|
-
sessionSource,
|
|
496
|
-
...(reason !== undefined && { reason }),
|
|
497
|
-
});
|
|
498
|
-
let event;
|
|
499
|
-
try {
|
|
500
|
-
event = await readSessionStartEvent(stdin, {
|
|
501
|
-
onTimeout: note,
|
|
502
|
-
...(opts.stdinIdleTimeoutMs !== undefined && { idleTimeoutMs: opts.stdinIdleTimeoutMs }),
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
catch (err) {
|
|
506
|
-
const reason = malformedEventReason(err);
|
|
507
|
-
note(reason);
|
|
508
|
-
return done(false, "", 0, 0, FALLBACK_SESSION, "default", reason);
|
|
509
|
-
}
|
|
510
|
-
const cwd = resolveEventCwd(opts.cwd, event);
|
|
511
|
-
// Session id resolution: same precedence chain as the two siblings, so
|
|
512
|
-
// all three producers stay symmetric.
|
|
513
|
-
const explicit = explicitSessionId(opts.session, event);
|
|
514
|
-
const resolveSession = opts.resolveSession ?? resolveReadSessionId;
|
|
515
|
-
// Defensive (task c1b5ade5): a session resolver that throws (real or
|
|
516
|
-
// injected) must degrade to the same FALLBACK_SESSION every OTHER "no
|
|
517
|
-
// session known" path already uses, not crash a producer whose whole
|
|
518
|
-
// contract is "never break the session loop". Unlike collectLocalSnapshot
|
|
519
|
-
// below, this call is NOT part of the hermetic-spawn-guard contract, so
|
|
520
|
-
// wrapping it here does not swallow a HermeticSpawnViolationError.
|
|
521
|
-
let sessionId;
|
|
522
|
-
// Task c1b5ade5 R2 (finding 3): a throw here always degrades sessionId to
|
|
523
|
-
// FALLBACK_SESSION below, but sessionSource's ternary was computed purely
|
|
524
|
-
// from `opts.session`/`event.session_id`/`sessionId` — so a stdin event
|
|
525
|
-
// that DID carry a `session_id` still reported sessionSource "stdin" even
|
|
526
|
-
// though the id actually recorded was "default" (the resolver never ran
|
|
527
|
-
// to completion). That both misrepresents the ledger fact's provenance
|
|
528
|
-
// and suppresses the AC5 "resolved to default" warning below, which only
|
|
529
|
-
// fires when sessionSource === "default". `resolverThrew` short-circuits
|
|
530
|
-
// sessionSource to "default" whenever the catch below fired, regardless
|
|
531
|
-
// of what `explicit`/`event.session_id` looked like.
|
|
532
|
-
let resolverThrew = false;
|
|
533
|
-
try {
|
|
534
|
-
sessionId = resolveSession(explicit, {});
|
|
535
|
-
}
|
|
536
|
-
catch (err) {
|
|
537
|
-
note(`session id resolution failed: ${err.message}; falling back to session "${FALLBACK_SESSION}"`);
|
|
538
|
-
sessionId = FALLBACK_SESSION;
|
|
539
|
-
resolverThrew = true;
|
|
540
|
-
}
|
|
541
|
-
const sessionSource = classifySessionSource(opts.session, event, sessionId, resolverThrew);
|
|
542
|
-
let manifest;
|
|
543
|
-
if (opts.manifest) {
|
|
544
|
-
manifest = opts.manifest;
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
try {
|
|
548
|
-
manifest = loadManifest(opts).manifest;
|
|
549
|
-
}
|
|
550
|
-
catch (err) {
|
|
551
|
-
const reason = `manifest load failed: ${err.message}`;
|
|
552
|
-
note(reason);
|
|
553
|
-
return done(false, "", 0, 0, sessionId, sessionSource, reason);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
const config = manifest.toolchain_parity;
|
|
557
|
-
if (!config.enabled) {
|
|
558
|
-
const reason = "not configured (add `toolchain_parity: { enabled: true }` to harness.yaml); skipping";
|
|
559
|
-
note(reason);
|
|
560
|
-
return done(false, "", 0, 0, sessionId, sessionSource, reason);
|
|
561
|
-
}
|
|
562
|
-
const machineStateDir = config.machine_state_dir ?? defaultMachineStateDir();
|
|
563
|
-
const profile = config.profile ?? sanitizeProfileName(os.hostname());
|
|
564
|
-
const workspaceRoot = config.workspace_root ?? cwd;
|
|
565
|
-
const sanitizedProfile = sanitizeProfileName(profile);
|
|
566
|
-
const ownFileName = `${sanitizedProfile}.json`;
|
|
567
|
-
// Advisory staleness threshold (AC3, task c1b5ade5): undefined disables
|
|
568
|
-
// the check entirely, matching the schema's default-off comment.
|
|
569
|
-
const staleAfterMs = config.stale_after_days !== undefined ? config.stale_after_days * 24 * 60 * 60 * 1000 : undefined;
|
|
570
|
-
try {
|
|
571
|
-
fs.mkdirSync(machineStateDir, { recursive: true });
|
|
572
|
-
}
|
|
573
|
-
catch (err) {
|
|
574
|
-
const reason = `cannot create/access machine-state dir ${machineStateDir}: ${err.message}`;
|
|
575
|
-
note(reason);
|
|
576
|
-
return done(false, profile, 0, 0, sessionId, sessionSource, reason);
|
|
577
|
-
}
|
|
578
|
-
// Lossy-sanitization advisory (task c1b5ade5): a `profile` configured
|
|
579
|
-
// with characters that are not filename-safe silently loses information
|
|
580
|
-
// when sanitizeProfileName strips/replaces them. That is invisible to an
|
|
581
|
-
// operator unless flagged — worse, two DIFFERENT configured profiles can
|
|
582
|
-
// sanitize to the SAME filename (e.g. "mac/mini" and "mac-mini" both land
|
|
583
|
-
// on "mac-mini.json"), in which case this run's write is about to
|
|
584
|
-
// silently overwrite what looked like a peer's snapshot. Both cases are
|
|
585
|
-
// advisory-only: this producer still writes its own snapshot and
|
|
586
|
-
// continues normally either way.
|
|
587
|
-
if (sanitizedProfile !== profile) {
|
|
588
|
-
note(`configured profile "${profile}" is not filename-safe; using sanitized "${sanitizedProfile}" for the snapshot file (${ownFileName})`);
|
|
589
|
-
}
|
|
590
|
-
// Collision check (task c1b5ade5 R2, finding 2): this must run on EVERY
|
|
591
|
-
// invocation, not only when THIS machine's own profile happens to be
|
|
592
|
-
// lossy — the collision is equally caused by a DIFFERENT (peer)
|
|
593
|
-
// machine's lossy profile landing on the SAME sanitized filename as
|
|
594
|
-
// this machine's own, already filename-safe, profile. Gating this read
|
|
595
|
-
// on `sanitizedProfile !== profile` meant only the lossy side of such a
|
|
596
|
-
// pair ever warned; the filename-safe side silently overwrote the lossy
|
|
597
|
-
// peer's snapshot with no signal at all (and that peer would then never
|
|
598
|
-
// show up in `peersCompared`). Only the "not filename-safe" note above
|
|
599
|
-
// stays scoped to the lossy case — it is about THIS profile, not about
|
|
600
|
-
// a collision.
|
|
601
|
-
try {
|
|
602
|
-
const existingRaw = fs.readFileSync(path.join(machineStateDir, ownFileName), "utf8");
|
|
603
|
-
const existingParsed = parseSnapshotJson(existingRaw);
|
|
604
|
-
if (existingParsed.ok && existingParsed.snapshot.profile !== profile) {
|
|
605
|
-
// The existing snapshot's `profile` field is untrusted, cross-machine
|
|
606
|
-
// synced content, shown RAW here (task c1b5ade5 R2b, reverting R2's
|
|
607
|
-
// sanitizeProfileName wrap at this site): note() now strips CR/LF at
|
|
608
|
-
// the choke point above, so a per-site sanitize is redundant AND
|
|
609
|
-
// would mangle a legitimate non-ASCII profile name into a label that
|
|
610
|
-
// no longer matches what actually collided. sanitizeProfileName
|
|
611
|
-
// stays reserved for the FILENAME path (ownFileName, writeOwnSnapshot
|
|
612
|
-
// below) — never for this stderr-display path.
|
|
613
|
-
note(`WARNING: sanitized filename "${ownFileName}" collides with an existing snapshot for a DIFFERENT profile ("${existingParsed.snapshot.profile}"); this run's write is about to overwrite it — set a distinct \`toolchain_parity.profile\` on one of the machines`);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
catch (err) {
|
|
617
|
-
// No existing file for this sanitized name yet (first run for this
|
|
618
|
-
// profile/filename) is the expected common case — ENOENT stays a
|
|
619
|
-
// silent skip; writeOwnSnapshot below reports its own write failures
|
|
620
|
-
// separately. Anything else (EACCES, EISDIR, ...) means the collision
|
|
621
|
-
// check silently did NOT run, which is a different, noteworthy outcome
|
|
622
|
-
// from "no collision found" (task c1b5ade5 R2b, narrowing the
|
|
623
|
-
// previously-bare catch): re-noted as one line rather than swallowed.
|
|
624
|
-
const e = err;
|
|
625
|
-
if (e.code !== "ENOENT") {
|
|
626
|
-
note(`could not check for a profile-name collision on ${ownFileName}: ${e.message}`);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
const runNodeVersion = opts.runNodeVersion ?? realNodeVersionSpawn;
|
|
630
|
-
const runNpmGlobals = opts.runNpmGlobals ?? realNpmGlobalsSpawn;
|
|
631
|
-
const readOwKitVersion = opts.readOwKitVersion ?? realReadOwKitVersion;
|
|
632
|
-
const readMcpServerNames = opts.readMcpServerNames ?? realReadMcpServerNames;
|
|
633
|
-
const { snapshot: localSnapshot, notes } = await collectLocalSnapshot({
|
|
634
|
-
profile,
|
|
635
|
-
now,
|
|
636
|
-
workspaceRoot,
|
|
637
|
-
nodeTimeoutMs,
|
|
638
|
-
npmTimeoutMs,
|
|
639
|
-
runNodeVersion,
|
|
640
|
-
runNpmGlobals,
|
|
641
|
-
readOwKitVersion,
|
|
642
|
-
readMcpServerNames,
|
|
643
|
-
});
|
|
644
|
-
for (const n of notes)
|
|
645
|
-
note(n);
|
|
646
|
-
const written = writeOwnSnapshot(machineStateDir, ownFileName, localSnapshot);
|
|
647
|
-
if (!written.ok) {
|
|
648
|
-
note(`could not write own snapshot: ${written.reason}`);
|
|
649
|
-
}
|
|
650
|
-
let entries;
|
|
651
|
-
try {
|
|
652
|
-
entries = fs.readdirSync(machineStateDir);
|
|
653
|
-
}
|
|
654
|
-
catch (err) {
|
|
655
|
-
const reason = `cannot list machine-state dir ${machineStateDir}: ${err.message}`;
|
|
656
|
-
note(reason);
|
|
657
|
-
return done(false, profile, 0, 0, sessionId, sessionSource, reason);
|
|
658
|
-
}
|
|
659
|
-
const peerFiles = entries.filter((name) => name.endsWith(".json") && name !== ownFileName).sort();
|
|
660
|
-
if (peerFiles.length === 0) {
|
|
661
|
-
const reason = `no peer snapshots found in ${machineStateDir}; nothing to compare (normal for the first machine, or before any peer has run this companion)`;
|
|
662
|
-
note(reason);
|
|
663
|
-
return done(false, profile, 0, 0, sessionId, sessionSource, reason);
|
|
664
|
-
}
|
|
665
|
-
let peersCompared = 0;
|
|
666
|
-
let driftTotal = 0;
|
|
667
|
-
// Peer files that were present but failed to parse as valid JSON —
|
|
668
|
-
// AC2 (task 690fba7c): these must not vanish silently from `drift:N`, so
|
|
669
|
-
// their (file-derived) labels are surfaced both as a distinct stderr tag
|
|
670
|
-
// and as a `:unparseable-peer:<n>` suffix on the ledger fact below.
|
|
671
|
-
const unparseablePeers = [];
|
|
672
|
-
for (const fileName of peerFiles) {
|
|
673
|
-
const filePath = path.join(machineStateDir, fileName);
|
|
674
|
-
let raw;
|
|
675
|
-
try {
|
|
676
|
-
raw = fs.readFileSync(filePath, "utf8");
|
|
677
|
-
}
|
|
678
|
-
catch (err) {
|
|
679
|
-
note(`peer snapshot ${fileName} unreadable: ${err.message}`);
|
|
680
|
-
continue;
|
|
681
|
-
}
|
|
682
|
-
const parsed = parseSnapshotJson(raw);
|
|
683
|
-
if (!parsed.ok) {
|
|
684
|
-
// The profile field itself failed to parse, so the filename (minus
|
|
685
|
-
// its `.json` suffix) is the best available peer identifier. Files
|
|
686
|
-
// this producer did NOT write are untrusted input (the machine-state
|
|
687
|
-
// dir is populated cross-machine by sync), but note() strips CR/LF
|
|
688
|
-
// at the choke point above (task c1b5ade5 R2b, reverting R2's
|
|
689
|
-
// sanitizeProfileName wrap at this site), so the label is shown RAW
|
|
690
|
-
// here — a crafted filename still cannot forge a standalone parity
|
|
691
|
-
// line, and sanitizeProfileName stays reserved for the FILENAME
|
|
692
|
-
// path, not this stderr-display one. The `|| fileName` keeps a
|
|
693
|
-
// degenerate name like a literal `.json` from producing an empty
|
|
694
|
-
// label.
|
|
695
|
-
const peerLabel = fileName.replace(/\.json$/, "") || fileName;
|
|
696
|
-
note(`peer snapshot ${fileName} is corrupt: ${parsed.reason}`);
|
|
697
|
-
note(`parity:unparseable-peer:${peerLabel}`);
|
|
698
|
-
unparseablePeers.push(peerLabel);
|
|
699
|
-
continue;
|
|
700
|
-
}
|
|
701
|
-
const comparison = compareToPeer(localSnapshot, parsed.snapshot, now);
|
|
702
|
-
peersCompared += 1;
|
|
703
|
-
driftTotal += comparison.drift.length;
|
|
704
|
-
const age = formatSnapshotAge(comparison.ageMs);
|
|
705
|
-
if (comparison.drift.length === 0) {
|
|
706
|
-
note(`ok against ${comparison.peerProfile} (snapshot age ${age})`);
|
|
707
|
-
}
|
|
708
|
-
else {
|
|
709
|
-
note(`drift:${comparison.drift.length} against ${comparison.peerProfile} (snapshot age ${age})`);
|
|
710
|
-
for (const item of comparison.drift)
|
|
711
|
-
note(`drift — ${item.message}`);
|
|
712
|
-
}
|
|
713
|
-
// AC3 (task c1b5ade5): a stale peer is a trustworthiness CAVEAT on the
|
|
714
|
-
// comparison above, not a drift finding — it never touches driftTotal.
|
|
715
|
-
// Only fires when `stale_after_days` is explicitly configured.
|
|
716
|
-
if (staleAfterMs !== undefined && comparison.ageMs > staleAfterMs) {
|
|
717
|
-
// comparison.peerProfile is untrusted, cross-machine synced content,
|
|
718
|
-
// shown RAW here for the same reason as the collision-warning note
|
|
719
|
-
// above (task c1b5ade5 R2b, reverting R2's sanitizeProfileName wrap
|
|
720
|
-
// at this site): note() strips CR/LF at the choke point, and this
|
|
721
|
-
// also keeps the label identical to the "ok against"/"drift:N
|
|
722
|
-
// against" line for the SAME peer just above, instead of showing two
|
|
723
|
-
// different sanitized-vs-raw spellings of one peer's name in the
|
|
724
|
-
// same run.
|
|
725
|
-
note(`peer ${comparison.peerProfile} snapshot is stale (age ${age}, exceeds the configured ${config.stale_after_days}d threshold); its comparison may not reflect that machine's CURRENT toolchain`);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
if (peersCompared === 0) {
|
|
729
|
-
const reason = `no comparable peer snapshots (all ${peerFiles.length} peer file(s) in ${machineStateDir} were unreadable/corrupt)`;
|
|
730
|
-
note(reason);
|
|
731
|
-
return done(false, profile, 0, 0, sessionId, sessionSource, reason, unparseablePeers.length);
|
|
732
|
-
}
|
|
733
|
-
// AC2 (task 690fba7c): a non-zero `unparseablePeers` count means the
|
|
734
|
-
// comparison below is PARTIAL, so it is appended to the ledger fact
|
|
735
|
-
// itself — the artifact an operator is most likely to read after the
|
|
736
|
-
// fact via `harness audit` — not just to the stderr notes above. Absent
|
|
737
|
-
// any unparseable peer, `content` is byte-identical to the pre-existing
|
|
738
|
-
// format (AC3: no behaviour change for the all-valid-peers case).
|
|
739
|
-
const unparseableSuffix = unparseablePeers.length > 0 ? `:unparseable-peer:${unparseablePeers.length}` : "";
|
|
740
|
-
const content = (driftTotal === 0 ? "toolchain-parity:ok" : `toolchain-parity:drift:${driftTotal}`) + unparseableSuffix;
|
|
741
|
-
let writeLedger = opts.writeLedger;
|
|
742
|
-
if (!writeLedger) {
|
|
743
|
-
// No try/catch here (task c1b5ade5 R2, finding 4 — orchestrator
|
|
744
|
-
// decision): resolveManifestLedgerWriter is a pure function over an
|
|
745
|
-
// already-validated `manifest` with no throw path (findGroundingMcp is
|
|
746
|
-
// a plain array `.find`, mcpCommandList a plain string split) and no
|
|
747
|
-
// I/O seam to fail — unlike `resolveSession` above and `writeLedger`
|
|
748
|
-
// below, which DO wrap real I/O/spawn boundaries and stay caught. A
|
|
749
|
-
// try/catch here had no exercisable throw path and was dead,
|
|
750
|
-
// untested code (round-1 review finding); removed rather than built
|
|
751
|
-
// out into a fake seam.
|
|
752
|
-
const resolved = resolveManifestLedgerWriter(manifest, {
|
|
753
|
-
...(opts.ledgerTimeoutMs !== undefined ? { ledgerTimeoutMs: opts.ledgerTimeoutMs } : {}),
|
|
754
|
-
});
|
|
755
|
-
if (!resolved.ok) {
|
|
756
|
-
const reason = `${resolved.reason}; cannot record ${content}`;
|
|
757
|
-
note(reason);
|
|
758
|
-
return done(false, profile, peersCompared, driftTotal, sessionId, sessionSource, reason, unparseablePeers.length);
|
|
759
|
-
}
|
|
760
|
-
writeLedger = resolved.write;
|
|
761
|
-
}
|
|
762
|
-
// Defensive (task c1b5ade5): an injected or real writeLedger that REJECTS
|
|
763
|
-
// instead of resolving to `{ ok: false, reason }` must degrade the same
|
|
764
|
-
// way the `!result.ok` branch below already does, not propagate as an
|
|
765
|
-
// unhandled rejection out of a SessionStart hook.
|
|
766
|
-
let result;
|
|
767
|
-
try {
|
|
768
|
-
result = await writeLedger({ sessionId, content, source: LEDGER_SOURCE });
|
|
769
|
-
}
|
|
770
|
-
catch (err) {
|
|
771
|
-
const reason = `ledger write threw: ${err.message}`;
|
|
772
|
-
note(reason);
|
|
773
|
-
return done(false, profile, peersCompared, driftTotal, sessionId, sessionSource, reason, unparseablePeers.length);
|
|
774
|
-
}
|
|
775
|
-
if (!result.ok) {
|
|
776
|
-
// `?? "unknown error"` is unreachable through any type-checked caller
|
|
777
|
-
// (`AddLedgerFactResult`'s `!ok` arm types `reason` as a non-optional
|
|
778
|
-
// string) — but unlike the try/catch removed around
|
|
779
|
-
// resolveManifestLedgerWriter above (a private, non-injectable pure
|
|
780
|
-
// function only ever called from this same typed module, so genuinely
|
|
781
|
-
// dead), `writeLedger` IS an injectable public seam
|
|
782
|
-
// (SessionStartToolchainParityOptions.writeLedger): a JS-level or
|
|
783
|
-
// otherwise untyped caller can hand back `{ ok: false }` with no
|
|
784
|
-
// `reason` at runtime, so this fallback stays (task c1b5ade5 R2b).
|
|
785
|
-
const reason = `ledger write failed: ${result.reason ?? "unknown error"}`;
|
|
786
|
-
note(reason);
|
|
787
|
-
return done(false, profile, peersCompared, driftTotal, sessionId, sessionSource, reason, unparseablePeers.length);
|
|
788
|
-
}
|
|
789
|
-
note(`recorded ${content} for session ${sessionId}`);
|
|
790
|
-
if (sessionSource === "default") {
|
|
791
|
-
note("WARNING: session resolved to the literal \"default\". This tag is audit-only (no gate " +
|
|
792
|
-
"consumes toolchain-parity: yet), but pipe SessionStart event JSON on stdin, export " +
|
|
793
|
-
"$CLAUDE_SESSION_ID, or pass --session <id> for manual / scripted use to keep the audit trail useful.");
|
|
794
|
-
}
|
|
795
|
-
return done(true, profile, peersCompared, driftTotal, sessionId, sessionSource, undefined, unparseablePeers.length);
|
|
796
|
-
}
|
|
797
|
-
//# sourceMappingURL=toolchain-parity.js.map
|