harnery 0.36.0 → 0.38.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/dist/commander.d.ts +9 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +10 -1
- package/dist/commands/admission.d.ts +21 -0
- package/dist/commands/admission.d.ts.map +1 -0
- package/dist/commands/admission.js +565 -0
- package/dist/commands/agents.d.ts +7 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +148 -47
- package/dist/commands/artifacts.d.ts.map +1 -1
- package/dist/commands/artifacts.js +73 -2
- package/dist/commands/browse-ai.d.ts +2 -2
- package/dist/commands/browse-ai.d.ts.map +1 -1
- package/dist/commands/browse-ai.js +6 -4
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +360 -21
- package/dist/commands/diagnostics.d.ts +4 -0
- package/dist/commands/diagnostics.d.ts.map +1 -0
- package/dist/commands/diagnostics.js +229 -0
- package/dist/commands/fetch.js +1 -0
- package/dist/commands/files.d.ts +12 -0
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +54 -1
- package/dist/commands/governor.d.ts.map +1 -1
- package/dist/commands/governor.js +4 -0
- package/dist/commands/ledger-v3.d.ts.map +1 -1
- package/dist/commands/ledger-v3.js +71 -2
- package/dist/commands/qa-record.d.ts +144 -0
- package/dist/commands/qa-record.d.ts.map +1 -0
- package/dist/commands/qa-record.js +0 -0
- package/dist/commands/qa-run.d.ts +8 -0
- package/dist/commands/qa-run.d.ts.map +1 -0
- package/dist/commands/qa-run.js +396 -0
- package/dist/commands/qa-status.d.ts +71 -0
- package/dist/commands/qa-status.d.ts.map +1 -0
- package/dist/commands/qa-status.js +490 -0
- package/dist/commands/qa-verify.d.ts +40 -0
- package/dist/commands/qa-verify.d.ts.map +1 -0
- package/dist/commands/qa-verify.js +180 -0
- package/dist/commands/resources.d.ts +4 -0
- package/dist/commands/resources.d.ts.map +1 -0
- package/dist/commands/resources.js +29 -0
- package/dist/commands/review-pack.d.ts +4 -0
- package/dist/commands/review-pack.d.ts.map +1 -0
- package/dist/commands/review-pack.js +1001 -0
- package/dist/commands/supervisor.d.ts +4 -0
- package/dist/commands/supervisor.d.ts.map +1 -0
- package/dist/commands/supervisor.js +101 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +17 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +4 -0
- package/dist/core/agents/cli.js +7 -3
- package/dist/core/agents/health.d.ts +17 -0
- package/dist/core/agents/health.d.ts.map +1 -0
- package/dist/core/agents/health.js +109 -0
- package/dist/core/agents/mailbox.d.ts +92 -0
- package/dist/core/agents/mailbox.d.ts.map +1 -0
- package/dist/core/agents/mailbox.js +325 -0
- package/dist/core/agents/qa-signal.d.ts +111 -0
- package/dist/core/agents/qa-signal.d.ts.map +1 -0
- package/dist/core/agents/qa-signal.js +231 -0
- package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
- package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
- package/dist/core/agents/reconcile-coordination-v3.js +58 -0
- package/dist/core/agents/render/prompt-context.d.ts +5 -0
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +34 -13
- package/dist/core/agents/render/session-context.d.ts +8 -0
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +34 -3
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +50 -1
- package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
- package/dist/core/agents/rules/stop-hook.js +6 -10
- package/dist/core/agents/session-finalizer-v3.js +4 -1
- package/dist/core/agents/session-name-display.d.ts +20 -5
- package/dist/core/agents/session-name-display.d.ts.map +1 -1
- package/dist/core/agents/session-name-display.js +67 -7
- package/dist/core/agents/state/heartbeat-reader.d.ts +7 -0
- package/dist/core/agents/state/heartbeat-reader.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.d.ts +11 -0
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +17 -0
- package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
- package/dist/core/agents/state/live-coordination-view.js +1 -0
- package/dist/core/agents/state/live-coordination-writer.js +5 -0
- package/dist/core/artifacts/constants.d.ts +1 -1
- package/dist/core/artifacts/constants.js +1 -1
- package/dist/core/artifacts/index.d.ts +82 -6
- package/dist/core/artifacts/index.d.ts.map +1 -1
- package/dist/core/artifacts/index.js +410 -15
- package/dist/core/config.d.ts +20 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +59 -0
- package/dist/core/diagnostics/advice.d.ts +9 -0
- package/dist/core/diagnostics/advice.d.ts.map +1 -0
- package/dist/core/diagnostics/advice.js +112 -0
- package/dist/core/diagnostics/bundle.d.ts +51 -0
- package/dist/core/diagnostics/bundle.d.ts.map +1 -0
- package/dist/core/diagnostics/bundle.js +968 -0
- package/dist/core/diagnostics/comparison.d.ts +5 -0
- package/dist/core/diagnostics/comparison.d.ts.map +1 -0
- package/dist/core/diagnostics/comparison.js +444 -0
- package/dist/core/diagnostics/contract.d.ts +245 -0
- package/dist/core/diagnostics/contract.d.ts.map +1 -0
- package/dist/core/diagnostics/contract.js +18 -0
- package/dist/core/diagnostics/identity.d.ts +3 -0
- package/dist/core/diagnostics/identity.d.ts.map +1 -0
- package/dist/core/diagnostics/identity.js +10 -0
- package/dist/core/diagnostics/index.d.ts +8 -0
- package/dist/core/diagnostics/index.d.ts.map +1 -0
- package/dist/core/diagnostics/index.js +7 -0
- package/dist/core/diagnostics/replay.d.ts +8 -0
- package/dist/core/diagnostics/replay.d.ts.map +1 -0
- package/dist/core/diagnostics/replay.js +213 -0
- package/dist/core/diagnostics/sanitize.d.ts +9 -0
- package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
- package/dist/core/diagnostics/sanitize.js +84 -0
- package/dist/core/events/legacy-storage/compression.d.ts +13 -0
- package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
- package/dist/core/events/legacy-storage/compression.js +107 -0
- package/dist/core/events/legacy-storage/index.d.ts +1 -0
- package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
- package/dist/core/events/legacy-storage/index.js +1 -0
- package/dist/core/events/v3/archive-retention.d.ts +33 -0
- package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
- package/dist/core/events/v3/archive-retention.js +195 -0
- package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
- package/dist/core/events/v3/bootstrap.js +10 -0
- package/dist/core/events/v3/capabilities.d.ts +1 -1
- package/dist/core/events/v3/capabilities.d.ts.map +1 -1
- package/dist/core/events/v3/capabilities.js +1 -0
- package/dist/core/events/v3/coordination-view.d.ts +3 -0
- package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
- package/dist/core/events/v3/coordination-view.js +69 -8
- package/dist/core/events/v3/index.d.ts +1 -0
- package/dist/core/events/v3/index.d.ts.map +1 -1
- package/dist/core/events/v3/index.js +1 -0
- package/dist/core/events/v3/live-routing.d.ts.map +1 -1
- package/dist/core/events/v3/live-routing.js +1 -0
- package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
- package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
- package/dist/core/events/v3/producers/hook-base.js +13 -2
- package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
- package/dist/core/events/v3/producers/intake.js +10 -2
- package/dist/core/events/v3/producers/recorder.d.ts +39 -0
- package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
- package/dist/core/events/v3/producers/recorder.js +350 -17
- package/dist/core/hooks/adapter/output.d.ts +8 -0
- package/dist/core/hooks/adapter/output.d.ts.map +1 -1
- package/dist/core/hooks/adapter/output.js +11 -1
- package/dist/core/hooks/cli.js +303 -219
- package/dist/core/hooks/health.d.ts +59 -0
- package/dist/core/hooks/health.d.ts.map +1 -0
- package/dist/core/hooks/health.js +84 -0
- package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
- package/dist/core/hooks/resolve/transcript.js +10 -3
- package/dist/core/hooks/session-name-presence.d.ts.map +1 -1
- package/dist/core/hooks/session-name-presence.js +4 -1
- package/dist/core/qa-artifacts.d.ts +20 -0
- package/dist/core/qa-artifacts.d.ts.map +1 -0
- package/dist/core/qa-artifacts.js +110 -0
- package/dist/core/resources/contract.d.ts +96 -0
- package/dist/core/resources/contract.d.ts.map +1 -0
- package/dist/core/resources/contract.js +2 -0
- package/dist/core/resources/index.d.ts +6 -0
- package/dist/core/resources/index.d.ts.map +1 -0
- package/dist/core/resources/index.js +5 -0
- package/dist/core/resources/sampler.d.ts +34 -0
- package/dist/core/resources/sampler.d.ts.map +1 -0
- package/dist/core/resources/sampler.js +458 -0
- package/dist/core/resources/service-status.d.ts +3 -0
- package/dist/core/resources/service-status.d.ts.map +1 -0
- package/dist/core/resources/service-status.js +48 -0
- package/dist/core/resources/service.d.ts +26 -0
- package/dist/core/resources/service.d.ts.map +1 -0
- package/dist/core/resources/service.js +292 -0
- package/dist/core/resources/storage.d.ts +13 -0
- package/dist/core/resources/storage.d.ts.map +1 -0
- package/dist/core/resources/storage.js +30 -0
- package/dist/core/storage/atomic-json.d.ts +3 -0
- package/dist/core/storage/atomic-json.d.ts.map +1 -0
- package/dist/core/storage/atomic-json.js +15 -0
- package/dist/core/storage/builtins.d.ts.map +1 -1
- package/dist/core/storage/builtins.js +45 -6
- package/dist/core/storage/logger.d.ts +2 -0
- package/dist/core/storage/logger.d.ts.map +1 -1
- package/dist/core/storage/logger.js +2 -0
- package/dist/core/storage/query.d.ts +14 -0
- package/dist/core/storage/query.d.ts.map +1 -1
- package/dist/core/storage/query.js +51 -0
- package/dist/core/supervisor/activity.d.ts +4 -0
- package/dist/core/supervisor/activity.d.ts.map +1 -0
- package/dist/core/supervisor/activity.js +141 -0
- package/dist/core/supervisor/contract.d.ts +268 -0
- package/dist/core/supervisor/contract.d.ts.map +1 -0
- package/dist/core/supervisor/contract.js +35 -0
- package/dist/core/supervisor/explanations.d.ts +4 -0
- package/dist/core/supervisor/explanations.d.ts.map +1 -0
- package/dist/core/supervisor/explanations.js +71 -0
- package/dist/core/supervisor/findings.d.ts +20 -0
- package/dist/core/supervisor/findings.d.ts.map +1 -0
- package/dist/core/supervisor/findings.js +399 -0
- package/dist/core/supervisor/history.d.ts +9 -0
- package/dist/core/supervisor/history.d.ts.map +1 -0
- package/dist/core/supervisor/history.js +46 -0
- package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
- package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health-alerts.js +70 -0
- package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
- package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health-storage.js +24 -0
- package/dist/core/supervisor/hook-health.d.ts +72 -0
- package/dist/core/supervisor/hook-health.d.ts.map +1 -0
- package/dist/core/supervisor/hook-health.js +203 -0
- package/dist/core/supervisor/hooks.d.ts +10 -0
- package/dist/core/supervisor/hooks.d.ts.map +1 -0
- package/dist/core/supervisor/hooks.js +28 -0
- package/dist/core/supervisor/index.d.ts +15 -0
- package/dist/core/supervisor/index.d.ts.map +1 -0
- package/dist/core/supervisor/index.js +14 -0
- package/dist/core/supervisor/log-feed.d.ts +9 -0
- package/dist/core/supervisor/log-feed.d.ts.map +1 -0
- package/dist/core/supervisor/log-feed.js +103 -0
- package/dist/core/supervisor/service.d.ts +29 -0
- package/dist/core/supervisor/service.d.ts.map +1 -0
- package/dist/core/supervisor/service.js +450 -0
- package/dist/core/supervisor/services.d.ts +11 -0
- package/dist/core/supervisor/services.d.ts.map +1 -0
- package/dist/core/supervisor/services.js +155 -0
- package/dist/core/supervisor/status.d.ts +3 -0
- package/dist/core/supervisor/status.d.ts.map +1 -0
- package/dist/core/supervisor/status.js +48 -0
- package/dist/core/supervisor/storage.d.ts +30 -0
- package/dist/core/supervisor/storage.d.ts.map +1 -0
- package/dist/core/supervisor/storage.js +73 -0
- package/dist/core/supervisor/timeline.d.ts +3 -0
- package/dist/core/supervisor/timeline.d.ts.map +1 -0
- package/dist/core/supervisor/timeline.js +87 -0
- package/dist/core/workflow/admission.d.ts +23 -0
- package/dist/core/workflow/admission.d.ts.map +1 -0
- package/dist/core/workflow/admission.js +136 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +77 -2
- package/dist/core/workflow/index.d.ts +3 -2
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +2 -1
- package/dist/core/workflow/proof.d.ts +2 -1
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +39 -1
- package/dist/core/workflow/run-state.d.ts +3 -2
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +8 -1
- package/dist/core/workflow/types.d.ts +33 -1
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +2 -1
- package/dist/lib/admission.d.ts +71 -0
- package/dist/lib/admission.d.ts.map +1 -0
- package/dist/lib/admission.js +264 -0
- package/dist/lib/agent-browser/client.d.ts +1 -1
- package/dist/lib/agent-browser/client.d.ts.map +1 -1
- package/dist/lib/agent-browser/client.js +1 -5
- package/dist/lib/browser/capture-fidelity.d.ts +39 -0
- package/dist/lib/browser/capture-fidelity.d.ts.map +1 -0
- package/dist/lib/browser/capture-fidelity.js +84 -0
- package/dist/lib/browser/client.d.ts +46 -1
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +168 -9
- package/dist/lib/browser/critique.d.ts +38 -1
- package/dist/lib/browser/critique.d.ts.map +1 -1
- package/dist/lib/browser/critique.js +34 -6
- package/dist/lib/browser/index.d.ts +5 -1
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +4 -0
- package/dist/lib/browser/page-review-judge.d.ts +64 -0
- package/dist/lib/browser/page-review-judge.d.ts.map +1 -0
- package/dist/lib/browser/page-review-judge.js +270 -0
- package/dist/lib/browser/page-review-pack.d.ts +613 -0
- package/dist/lib/browser/page-review-pack.d.ts.map +1 -0
- package/dist/lib/browser/page-review-pack.js +1751 -0
- package/dist/lib/browser/qa-run-contracts.d.ts +377 -0
- package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
- package/dist/lib/browser/qa-run-contracts.js +361 -0
- package/dist/lib/browser/qa-run.d.ts +141 -0
- package/dist/lib/browser/qa-run.d.ts.map +1 -0
- package/dist/lib/browser/qa-run.js +1283 -0
- package/dist/lib/browser/request-diagnostics.d.ts +13 -0
- package/dist/lib/browser/request-diagnostics.d.ts.map +1 -0
- package/dist/lib/browser/request-diagnostics.js +18 -0
- package/dist/lib/browser/tiling.d.ts +19 -0
- package/dist/lib/browser/tiling.d.ts.map +1 -1
- package/dist/lib/browser/tiling.js +28 -0
- package/dist/lib/cookies/client.d.ts +9 -0
- package/dist/lib/cookies/client.d.ts.map +1 -1
- package/dist/lib/cookies/client.js +197 -44
- package/dist/lib/cookies/extra.d.ts +18 -0
- package/dist/lib/cookies/extra.d.ts.map +1 -0
- package/dist/lib/cookies/extra.js +14 -0
- package/dist/lib/cookies/index.d.ts +2 -1
- package/dist/lib/cookies/index.d.ts.map +1 -1
- package/dist/lib/cookies/index.js +2 -1
- package/dist/lib/coord-root-id.d.ts +9 -0
- package/dist/lib/coord-root-id.d.ts.map +1 -0
- package/dist/lib/coord-root-id.js +17 -0
- package/dist/lib/durable-job.d.ts +124 -0
- package/dist/lib/durable-job.d.ts.map +1 -0
- package/dist/lib/durable-job.js +296 -0
- package/dist/lib/http/client.d.ts +7 -1
- package/dist/lib/http/client.d.ts.map +1 -1
- package/dist/lib/http/client.js +2 -0
- package/dist/lib/instructions/apply.d.ts +3 -1
- package/dist/lib/instructions/apply.d.ts.map +1 -1
- package/dist/lib/instructions/apply.js +74 -3
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +11 -2
- package/package.json +19 -2
- package/src/commander.ts +75 -1
- package/src/commands/admission.ts +699 -0
- package/src/commands/agents.ts +189 -50
- package/src/commands/artifacts.ts +132 -18
- package/src/commands/browse-ai.ts +10 -5
- package/src/commands/browse.ts +496 -20
- package/src/commands/diagnostics.ts +271 -0
- package/src/commands/fetch.ts +1 -0
- package/src/commands/files.ts +102 -2
- package/src/commands/governor.ts +8 -0
- package/src/commands/ledger-v3.ts +82 -0
- package/src/commands/qa-record.ts +682 -0
- package/src/commands/qa-run.ts +503 -0
- package/src/commands/qa-status.ts +608 -0
- package/src/commands/qa-verify.ts +238 -0
- package/src/commands/resources.ts +38 -0
- package/src/commands/review-pack.ts +1281 -0
- package/src/commands/supervisor.ts +141 -0
- package/src/commands/web.ts +19 -0
- package/src/commands/workflow.ts +8 -0
- package/src/core/agents/cli.ts +7 -3
- package/src/core/agents/health.ts +142 -0
- package/src/core/agents/mailbox.ts +373 -0
- package/src/core/agents/qa-signal.ts +261 -0
- package/src/core/agents/reconcile-coordination-v3.ts +77 -0
- package/src/core/agents/render/prompt-context.ts +42 -12
- package/src/core/agents/render/session-context.ts +37 -3
- package/src/core/agents/rules/commit-conflict.ts +58 -1
- package/src/core/agents/rules/stop-hook.ts +6 -12
- package/src/core/agents/session-finalizer-v3.ts +4 -1
- package/src/core/agents/session-name-display.ts +78 -7
- package/src/core/agents/state/heartbeat-reader.ts +7 -0
- package/src/core/agents/state/heartbeat-writer.ts +23 -0
- package/src/core/agents/state/live-coordination-view.ts +1 -0
- package/src/core/agents/state/live-coordination-writer.ts +5 -0
- package/src/core/artifacts/constants.ts +1 -1
- package/src/core/artifacts/index.ts +565 -30
- package/src/core/config.ts +134 -2
- package/src/core/diagnostics/advice.ts +147 -0
- package/src/core/diagnostics/bundle.ts +1250 -0
- package/src/core/diagnostics/comparison.ts +565 -0
- package/src/core/diagnostics/contract.ts +311 -0
- package/src/core/diagnostics/identity.ts +11 -0
- package/src/core/diagnostics/index.ts +7 -0
- package/src/core/diagnostics/replay.ts +314 -0
- package/src/core/diagnostics/sanitize.ts +97 -0
- package/src/core/events/legacy-storage/compression.ts +130 -0
- package/src/core/events/legacy-storage/index.ts +1 -0
- package/src/core/events/v3/archive-retention.ts +251 -0
- package/src/core/events/v3/bootstrap.ts +10 -0
- package/src/core/events/v3/capabilities.ts +2 -0
- package/src/core/events/v3/coordination-view.ts +100 -11
- package/src/core/events/v3/index.ts +9 -0
- package/src/core/events/v3/live-routing.ts +1 -0
- package/src/core/events/v3/producers/hook-base.ts +14 -2
- package/src/core/events/v3/producers/intake.ts +10 -2
- package/src/core/events/v3/producers/recorder.ts +420 -17
- package/src/core/hooks/adapter/output.ts +12 -1
- package/src/core/hooks/cli.ts +332 -247
- package/src/core/hooks/health.ts +146 -0
- package/src/core/hooks/resolve/transcript.ts +10 -3
- package/src/core/hooks/session-name-presence.ts +6 -1
- package/src/core/qa-artifacts.ts +126 -0
- package/src/core/resources/contract.ts +105 -0
- package/src/core/resources/index.ts +5 -0
- package/src/core/resources/sampler.ts +590 -0
- package/src/core/resources/service-status.ts +62 -0
- package/src/core/resources/service.ts +337 -0
- package/src/core/resources/storage.ts +44 -0
- package/src/core/storage/atomic-json.ts +15 -0
- package/src/core/storage/builtins.ts +62 -6
- package/src/core/storage/logger.ts +2 -0
- package/src/core/storage/query.ts +58 -0
- package/src/core/supervisor/activity.ts +193 -0
- package/src/core/supervisor/contract.ts +312 -0
- package/src/core/supervisor/explanations.ts +104 -0
- package/src/core/supervisor/findings.ts +788 -0
- package/src/core/supervisor/history.ts +61 -0
- package/src/core/supervisor/hook-health-alerts.ts +108 -0
- package/src/core/supervisor/hook-health-storage.ts +25 -0
- package/src/core/supervisor/hook-health.ts +301 -0
- package/src/core/supervisor/hooks.ts +35 -0
- package/src/core/supervisor/index.ts +14 -0
- package/src/core/supervisor/log-feed.ts +131 -0
- package/src/core/supervisor/service.ts +511 -0
- package/src/core/supervisor/services.ts +203 -0
- package/src/core/supervisor/status.ts +59 -0
- package/src/core/supervisor/storage.ts +126 -0
- package/src/core/supervisor/timeline.ts +133 -0
- package/src/core/workflow/admission.ts +215 -0
- package/src/core/workflow/engine.ts +93 -1
- package/src/core/workflow/index.ts +10 -0
- package/src/core/workflow/proof.ts +54 -1
- package/src/core/workflow/run-state.ts +13 -1
- package/src/core/workflow/types.ts +39 -1
- package/src/lib/admission.ts +347 -0
- package/src/lib/agent-browser/client.ts +2 -10
- package/src/lib/browser/capture-fidelity.ts +98 -0
- package/src/lib/browser/client.ts +212 -10
- package/src/lib/browser/critique.ts +62 -7
- package/src/lib/browser/index.ts +65 -0
- package/src/lib/browser/page-review-judge.ts +360 -0
- package/src/lib/browser/page-review-pack.ts +2384 -0
- package/src/lib/browser/qa-run-contracts.ts +743 -0
- package/src/lib/browser/qa-run.ts +1462 -0
- package/src/lib/browser/request-diagnostics.ts +27 -0
- package/src/lib/browser/tiling.ts +32 -0
- package/src/lib/cookies/client.ts +228 -42
- package/src/lib/cookies/extra.ts +28 -0
- package/src/lib/cookies/index.ts +2 -0
- package/src/lib/coord-root-id.ts +23 -0
- package/src/lib/durable-job.ts +407 -0
- package/src/lib/http/client.ts +13 -1
- package/src/lib/instructions/apply.ts +81 -2
- package/src/lib/instructions/templates.ts +11 -2
package/src/core/hooks/cli.ts
CHANGED
|
@@ -23,7 +23,6 @@ import { dirname, join } from "node:path";
|
|
|
23
23
|
import { coordEnv } from "../../lib/env.ts";
|
|
24
24
|
import { buildInstructionBundle } from "../../lib/instructions/bundle.ts";
|
|
25
25
|
import type { Adapter } from "../adapter.ts";
|
|
26
|
-
import { coordBinPath } from "../agents/coord-bin.ts";
|
|
27
26
|
import { resolveCoordRoot } from "../agents/coord-client.ts";
|
|
28
27
|
import {
|
|
29
28
|
type ClaimFinalizationDecision,
|
|
@@ -31,20 +30,31 @@ import {
|
|
|
31
30
|
classifyWriteClaimFinalization,
|
|
32
31
|
formatWriteClaimFinalizationDenial,
|
|
33
32
|
} from "../agents/finalization.ts";
|
|
34
|
-
import {
|
|
33
|
+
import {
|
|
34
|
+
recordLiveClaimChangeV3,
|
|
35
|
+
restoreLiveCoordinationStateAfterEpochV3,
|
|
36
|
+
} from "../agents/live-authority-v3.ts";
|
|
35
37
|
import { evaluateStopHook, STOP_REMEDIATION_MARKER } from "../agents/rules/stop-hook.ts";
|
|
36
38
|
import {
|
|
37
39
|
assistantTextStartsWithSessionNameBlock,
|
|
38
40
|
isSessionNameRemediationCommand,
|
|
41
|
+
matchSessionNameDisplay,
|
|
42
|
+
sessionNameDisplayAcceptedNames,
|
|
39
43
|
sessionNameDisplayInstruction,
|
|
40
44
|
sessionNameDisplayPending,
|
|
41
45
|
sessionNameDisplayRecoveryInstruction,
|
|
42
46
|
toolResponseMintedSessionName,
|
|
43
47
|
} from "../agents/session-name-display.ts";
|
|
44
48
|
import type { Heartbeat } from "../agents/state/heartbeat-reader.ts";
|
|
45
|
-
import {
|
|
49
|
+
import {
|
|
50
|
+
readHeartbeat,
|
|
51
|
+
setAssignedNameCache,
|
|
52
|
+
stampSessionNameRequested,
|
|
53
|
+
stampSessionNameSeen,
|
|
54
|
+
} from "../agents/state/heartbeat-writer.ts";
|
|
46
55
|
import { readLiveCoordinationRow } from "../agents/state/live-coordination-view.ts";
|
|
47
56
|
import { ensureLiveCoordinationHeartbeat } from "../agents/state/live-coordination-writer.ts";
|
|
57
|
+
import { assignName } from "../agents/state/names.ts";
|
|
48
58
|
import { writePidmapRow } from "../agents/state/pidmap.ts";
|
|
49
59
|
import { agentsRequireGitFinalization, resolveBinName } from "../config.ts";
|
|
50
60
|
import {
|
|
@@ -100,9 +110,17 @@ import {
|
|
|
100
110
|
} from "./effects/index.ts";
|
|
101
111
|
import { toolInputHash, toolTargetHash } from "./events/input-hash.ts";
|
|
102
112
|
import { canonicalize } from "./guard-path.ts";
|
|
113
|
+
import {
|
|
114
|
+
beginHookHealth,
|
|
115
|
+
type HookHealthState,
|
|
116
|
+
observeHookDebug,
|
|
117
|
+
observeHookError,
|
|
118
|
+
writeHookHealthCompletion,
|
|
119
|
+
} from "./health.ts";
|
|
103
120
|
import { adapterPidFromEnv, parsePsChainLine, selectAnchorPid } from "./resolve/anchor.ts";
|
|
104
121
|
import { extractIntentComment, resolveIntent } from "./resolve/intent.ts";
|
|
105
122
|
import { resolveOwner } from "./resolve/owner.ts";
|
|
123
|
+
import type { SessionNameDisplayInspection } from "./resolve/transcript.ts";
|
|
106
124
|
import {
|
|
107
125
|
inspectSessionNameDisplayImmediately,
|
|
108
126
|
scanAssistantStatusBoxPresent,
|
|
@@ -118,6 +136,8 @@ interface Argv {
|
|
|
118
136
|
extra: string[];
|
|
119
137
|
}
|
|
120
138
|
|
|
139
|
+
let hookHealthState: HookHealthState | undefined;
|
|
140
|
+
|
|
121
141
|
function parseArgv(argv: string[]): Argv {
|
|
122
142
|
const out: Argv = { eventName: null, extra: [] };
|
|
123
143
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -155,17 +175,16 @@ async function readStdin(): Promise<string> {
|
|
|
155
175
|
}
|
|
156
176
|
|
|
157
177
|
/**
|
|
158
|
-
* Env for
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* without the pin a child could write state to a different .harnery than the
|
|
162
|
-
* one this hook resolved.
|
|
178
|
+
* Env for a detached hook retry worker, with the coord root pinned. The hook
|
|
179
|
+
* may run with the session shell's cwd (inside a submodule or journal dir), so
|
|
180
|
+
* the worker must retain the root this process already resolved.
|
|
163
181
|
*/
|
|
164
182
|
function childEnv(coordRoot: string): NodeJS.ProcessEnv {
|
|
165
183
|
return { ...process.env, HARNERY_COORD_ROOT_OVERRIDE: coordRoot };
|
|
166
184
|
}
|
|
167
185
|
|
|
168
186
|
function appendDebug(coordRoot: string, entry: Record<string, unknown>): void {
|
|
187
|
+
observeHookDebug(hookHealthState, entry);
|
|
169
188
|
if (coordEnv("SHARED_LOGS") !== "0") {
|
|
170
189
|
try {
|
|
171
190
|
processLogger(coordRoot, "agent-hook").debug("agent_hook.diagnostic", legacyLogFields(entry));
|
|
@@ -184,6 +203,7 @@ function appendDebug(coordRoot: string, entry: Record<string, unknown>): void {
|
|
|
184
203
|
}
|
|
185
204
|
|
|
186
205
|
function logError(coordRoot: string | null, err: unknown, context: Record<string, unknown>): void {
|
|
206
|
+
observeHookError(hookHealthState, context.phase);
|
|
187
207
|
if (!coordRoot) return;
|
|
188
208
|
if (coordEnv("SHARED_LOGS") !== "0") {
|
|
189
209
|
try {
|
|
@@ -216,43 +236,48 @@ function logError(coordRoot: string | null, err: unknown, context: Record<string
|
|
|
216
236
|
}
|
|
217
237
|
|
|
218
238
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* session.started emission never breaks the adapter flow.
|
|
222
|
-
*
|
|
223
|
-
* Lives at agent-hooks side (not agent-coord) to keep emitter/consumer
|
|
224
|
-
* separation: we spawn rather than import.
|
|
239
|
+
* Mint or recover the hurricane-style name for this owner in-process. Returns
|
|
240
|
+
* null on any failure so session.started emission never breaks adapter flow.
|
|
225
241
|
*/
|
|
226
|
-
function
|
|
242
|
+
function assignNameInProcess(
|
|
227
243
|
coordRoot: string,
|
|
228
244
|
instanceId: string,
|
|
229
245
|
kind: "session" | "subagent" | "transient",
|
|
230
246
|
forkedFrom?: string,
|
|
231
247
|
): { name: string; kind: string } | null {
|
|
232
|
-
const binary = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
233
|
-
if (!existsSync(binary)) return null;
|
|
234
248
|
try {
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
const result = spawnSync(binary, args, {
|
|
238
|
-
encoding: "utf8",
|
|
239
|
-
timeout: 2000,
|
|
240
|
-
env: childEnv(coordRoot),
|
|
241
|
-
});
|
|
242
|
-
if (result.status !== 0 || !result.stdout) return null;
|
|
243
|
-
const parsed = JSON.parse(result.stdout.trim()) as {
|
|
244
|
-
name?: string;
|
|
245
|
-
kind?: string;
|
|
246
|
-
};
|
|
247
|
-
if (parsed.name && parsed.kind) {
|
|
248
|
-
return { name: parsed.name, kind: parsed.kind };
|
|
249
|
-
}
|
|
250
|
-
return null;
|
|
249
|
+
const name = assignName(coordRoot, instanceId, kind, forkedFrom ? { forkedFrom } : undefined);
|
|
250
|
+
return { name, kind };
|
|
251
251
|
} catch {
|
|
252
252
|
return null;
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
+
/** Mid-flight sessions can emit tools before SessionStart assigns a pool name.
|
|
257
|
+
* Stamp the disposable cache so Codec does not render the 8-character id. */
|
|
258
|
+
function ensureSessionDisplayName(
|
|
259
|
+
coordRoot: string,
|
|
260
|
+
instanceId: string,
|
|
261
|
+
sessionId: string,
|
|
262
|
+
adapter: Adapter,
|
|
263
|
+
): void {
|
|
264
|
+
if (coordEnv("WORKFLOW_CHILD") === "1") return;
|
|
265
|
+
const row =
|
|
266
|
+
readLiveCoordinationRow(coordRoot, instanceId) ?? readHeartbeat(coordRoot, instanceId);
|
|
267
|
+
if (row?.kind === "subagent" || row?.kind === "transient" || row?.workflow_run_id) return;
|
|
268
|
+
if (row?.name?.trim()) return;
|
|
269
|
+
const assigned = assignNameInProcess(coordRoot, instanceId, "session");
|
|
270
|
+
if (!assigned?.name) return;
|
|
271
|
+
if (!readHeartbeat(coordRoot, instanceId)) {
|
|
272
|
+
try {
|
|
273
|
+
ensureLiveCoordinationHeartbeat(coordRoot, instanceId, sessionId, adapter);
|
|
274
|
+
} catch {
|
|
275
|
+
/* cache materialization is best-effort; history still holds the name */
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
setAssignedNameCache(coordRoot, instanceId, assigned.name, "session");
|
|
279
|
+
}
|
|
280
|
+
|
|
256
281
|
/**
|
|
257
282
|
* Direct (in-process) pidmap write, avoiding the spawn overhead of going via
|
|
258
283
|
* the agent-coord CLI for every session.started signal. Pid-map rows
|
|
@@ -321,14 +346,9 @@ function buildEventData(
|
|
|
321
346
|
// tool.requested heal path instead. The forkedFrom plumbing below stays
|
|
322
347
|
// for adapters that DO report a parent at session start.
|
|
323
348
|
const forkedFrom: string | undefined = undefined;
|
|
324
|
-
// Assign (or recover) name + kind
|
|
349
|
+
// Assign (or recover) name + kind in-process. Idempotent: resume
|
|
325
350
|
// returns the original name; new owner consumes a counter slot.
|
|
326
|
-
const assigned =
|
|
327
|
-
ctx.coordRoot,
|
|
328
|
-
ctx.instanceId,
|
|
329
|
-
"session",
|
|
330
|
-
forkedFrom,
|
|
331
|
-
);
|
|
351
|
+
const assigned = assignNameInProcess(ctx.coordRoot, ctx.instanceId, "session", forkedFrom);
|
|
332
352
|
// Write the adapter pid-map row so `harn agents whoami` ppid-walks find
|
|
333
353
|
// this owner. Prefer the payload pid (the actual claude binary), then the
|
|
334
354
|
// anchor walk (the `node` ancestor for Cursor, which has no payload pid),
|
|
@@ -389,14 +409,12 @@ function buildEventData(
|
|
|
389
409
|
};
|
|
390
410
|
|
|
391
411
|
case "turn.started": {
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
) {
|
|
399
|
-
assignNameViaAgentCoord(ctx.coordRoot, ctx.instanceId, "session");
|
|
412
|
+
// Mid-flight onboarding (any adapter) can observe a turn before
|
|
413
|
+
// SessionStart. Mint durable display identity here so a later
|
|
414
|
+
// SessionStart remains idempotent and Codec is not stuck on the
|
|
415
|
+
// 8-character native id.
|
|
416
|
+
if (!readLiveCoordinationRow(ctx.coordRoot, ctx.instanceId)?.name) {
|
|
417
|
+
assignNameInProcess(ctx.coordRoot, ctx.instanceId, "session");
|
|
400
418
|
}
|
|
401
419
|
const prompt = p?.prompt ?? "";
|
|
402
420
|
const { value, truncated } = clampString(prompt, 4000);
|
|
@@ -467,7 +485,7 @@ function buildEventData(
|
|
|
467
485
|
// (agent-coord/state/names.ts → kind=transient). Use the call ID as the
|
|
468
486
|
// instance_id input; assignName falls through to transient.
|
|
469
487
|
const childInstanceId = subagentCallId ?? ctx.instanceId;
|
|
470
|
-
const assigned =
|
|
488
|
+
const assigned = assignNameInProcess(ctx.coordRoot, childInstanceId, "subagent");
|
|
471
489
|
return {
|
|
472
490
|
agent_type:
|
|
473
491
|
(p?.raw.agent_type as string | undefined) ??
|
|
@@ -597,10 +615,18 @@ function numberField(value: unknown): number | undefined {
|
|
|
597
615
|
|
|
598
616
|
async function main(): Promise<number> {
|
|
599
617
|
const hookStartedAt = performance.now();
|
|
618
|
+
const hookStartedRss = process.memoryUsage().rss;
|
|
600
619
|
const hookClock = captureSpanClockV3();
|
|
601
620
|
const { eventName, extra } = parseArgv(process.argv.slice(2));
|
|
602
621
|
const adapter = detectAdapter(process.argv.slice(2));
|
|
603
622
|
const raw = await readStdin();
|
|
623
|
+
hookHealthState = beginHookHealth({
|
|
624
|
+
started_at_ms: hookStartedAt,
|
|
625
|
+
started_rss_bytes: hookStartedRss,
|
|
626
|
+
event_name: eventName,
|
|
627
|
+
adapter,
|
|
628
|
+
payload_bytes: raw.length,
|
|
629
|
+
});
|
|
604
630
|
|
|
605
631
|
// Cursor executes the Claude Code project hooks too on hosts wired for both
|
|
606
632
|
// adapters, piping them its own payload (identifiable by the top-level
|
|
@@ -612,6 +638,7 @@ async function main(): Promise<number> {
|
|
|
612
638
|
if (coordEnv("AGENT_COORD_OFF") !== "1") {
|
|
613
639
|
const coordRoot = resolveCoordRoot(process.cwd());
|
|
614
640
|
if (coordRoot) {
|
|
641
|
+
hookHealthState.coord_root = coordRoot;
|
|
615
642
|
appendDebug(coordRoot, {
|
|
616
643
|
ts: new Date().toISOString(),
|
|
617
644
|
event_name: eventName,
|
|
@@ -668,6 +695,7 @@ async function main(): Promise<number> {
|
|
|
668
695
|
|
|
669
696
|
const coordRoot = resolveCoordRoot(process.cwd());
|
|
670
697
|
if (!coordRoot) return 0;
|
|
698
|
+
hookHealthState.coord_root = coordRoot;
|
|
671
699
|
if (eventName === "runtime-context-retry") {
|
|
672
700
|
return runRuntimeContextRetryWorker(coordRoot, adapter, extra);
|
|
673
701
|
}
|
|
@@ -696,8 +724,9 @@ async function main(): Promise<number> {
|
|
|
696
724
|
// that tool. It is not a transcript and therefore cannot prove that an
|
|
697
725
|
// earlier assistant response omitted the required session-name block.
|
|
698
726
|
// afterAgentResponse is the one native boundary that carries the completed
|
|
699
|
-
// assistant text
|
|
700
|
-
//
|
|
727
|
+
// assistant text. Preserve only privacy-safe ritual booleans in the V3
|
|
728
|
+
// producer's open-turn state; Stop consumes them into the authoritative
|
|
729
|
+
// turn.completed event. The response body never enters V3 or heartbeat.
|
|
701
730
|
if (adapter === "cursor" && eventName === "after-agent-response") {
|
|
702
731
|
const payload = parsePayload(raw, adapter);
|
|
703
732
|
const owner = resolveOwner({ payload: payload?.raw ?? null, coordRoot });
|
|
@@ -705,14 +734,80 @@ async function main(): Promise<number> {
|
|
|
705
734
|
appendDebug(coordRoot, { ...debugBase, skipped: "no-owner-resolved" });
|
|
706
735
|
return 0;
|
|
707
736
|
}
|
|
708
|
-
const
|
|
737
|
+
const row = readLiveCoordinationRow(coordRoot, owner.instance_id);
|
|
738
|
+
const name = sessionNameDisplayPending(row);
|
|
709
739
|
const text = typeof payload?.raw.text === "string" ? payload.raw.text : "";
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
740
|
+
const sighting = matchSessionNameDisplay(row, text);
|
|
741
|
+
if (sighting) {
|
|
742
|
+
stampSessionNameSeen(coordRoot, owner.instance_id, sighting.pending);
|
|
743
|
+
appendDebug(coordRoot, {
|
|
744
|
+
...debugBase,
|
|
745
|
+
effect: "session-name-display-stamped",
|
|
746
|
+
session_name_pending: sighting.pending,
|
|
747
|
+
...(sighting.displayed === sighting.pending
|
|
748
|
+
? {}
|
|
749
|
+
: { session_name_displayed: sighting.displayed, session_name_drift: true }),
|
|
750
|
+
});
|
|
751
|
+
} else if (!name) {
|
|
752
|
+
// Nothing was owed. Distinct from a miss: conflating the two is what made
|
|
753
|
+
// a latched Cursor session undiagnosable from this log.
|
|
754
|
+
appendDebug(coordRoot, { ...debugBase, skipped: "no-pending-session-name" });
|
|
713
755
|
} else {
|
|
714
|
-
appendDebug(coordRoot, {
|
|
756
|
+
appendDebug(coordRoot, {
|
|
757
|
+
...debugBase,
|
|
758
|
+
skipped: "session-name-block-absent",
|
|
759
|
+
session_name_pending: name,
|
|
760
|
+
reply_bytes: text.length,
|
|
761
|
+
reply_leads_with_fence: /^\s*`{3,}/.test(text),
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (ledgerRoute.state === "blocked") {
|
|
765
|
+
appendDebug(coordRoot, {
|
|
766
|
+
...debugBase,
|
|
767
|
+
skipped: "v3-control-blocked",
|
|
768
|
+
reason: ledgerRoute.reason,
|
|
769
|
+
owner_source: owner.source,
|
|
770
|
+
});
|
|
771
|
+
return 0;
|
|
715
772
|
}
|
|
773
|
+
const statusBoxPresentStrict = scanAssistantStatusBoxPresent(undefined, text);
|
|
774
|
+
// The hook parser needs the completed reply long enough to scan it, but
|
|
775
|
+
// durable hook intake must never retain that body. Keep every other native
|
|
776
|
+
// field so turn correlation remains available to the producer.
|
|
777
|
+
const { text: _completedReply, ...privacySafeRaw } = payload?.raw ?? {};
|
|
778
|
+
const privacySafePayload = payload ? { ...payload, raw: privacySafeRaw } : null;
|
|
779
|
+
const v3Result = recordLiveHookSignalV3({
|
|
780
|
+
coordRoot,
|
|
781
|
+
route: ledgerRoute,
|
|
782
|
+
eventName,
|
|
783
|
+
payload: privacySafePayload,
|
|
784
|
+
adapter,
|
|
785
|
+
instanceId: owner.instance_id,
|
|
786
|
+
hook_name: eventName,
|
|
787
|
+
hook_duration_ms: Math.max(0, Math.floor(performance.now() - hookStartedAt)),
|
|
788
|
+
monotonic_ns: hookClock.monotonic_ns,
|
|
789
|
+
turn_ritual: {
|
|
790
|
+
status_box_present: statusBoxPresentStrict,
|
|
791
|
+
status_box_present_strict: statusBoxPresentStrict,
|
|
792
|
+
session_name_required: name !== undefined,
|
|
793
|
+
session_name_present: name ? assistantTextStartsWithSessionNameBlock(text, name) : false,
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
observeHookDebug(hookHealthState, { event_v3_state: v3Result.state });
|
|
797
|
+
appendDebug(coordRoot, {
|
|
798
|
+
...debugBase,
|
|
799
|
+
effect: "cursor-response-ritual-observed",
|
|
800
|
+
owner_source: owner.source,
|
|
801
|
+
event_v3_state: v3Result.state,
|
|
802
|
+
...(v3Result.state === "observed"
|
|
803
|
+
? {
|
|
804
|
+
generation_id: v3Result.generation_id,
|
|
805
|
+
turn_id: v3Result.turn_id,
|
|
806
|
+
response_observed_at: v3Result.observed_at,
|
|
807
|
+
status_box_present_strict: statusBoxPresentStrict,
|
|
808
|
+
}
|
|
809
|
+
: {}),
|
|
810
|
+
});
|
|
716
811
|
return 0;
|
|
717
812
|
}
|
|
718
813
|
|
|
@@ -735,9 +830,20 @@ async function main(): Promise<number> {
|
|
|
735
830
|
});
|
|
736
831
|
return 0;
|
|
737
832
|
}
|
|
833
|
+
hookHealthState.owner_id = owner.instance_id;
|
|
738
834
|
|
|
739
835
|
const sessionId = payload?.session_id ?? payload?.conversation_id ?? owner.instance_id;
|
|
740
836
|
const priorCoordination = readHeartbeat(coordRoot, owner.instance_id);
|
|
837
|
+
if (
|
|
838
|
+
norm.event_type !== "session.ended" &&
|
|
839
|
+
coordEnv("WORKFLOW_CHILD") !== "1" &&
|
|
840
|
+
priorCoordination?.kind !== "subagent" &&
|
|
841
|
+
priorCoordination?.kind !== "transient" &&
|
|
842
|
+
!priorCoordination?.workflow_run_id &&
|
|
843
|
+
!priorCoordination?.name?.trim()
|
|
844
|
+
) {
|
|
845
|
+
assignNameInProcess(coordRoot, owner.instance_id, "session");
|
|
846
|
+
}
|
|
741
847
|
|
|
742
848
|
const data = buildEventData(norm.event_type, {
|
|
743
849
|
coordRoot,
|
|
@@ -812,6 +918,9 @@ async function main(): Promise<number> {
|
|
|
812
918
|
...(turnRitual ? { turn_ritual: turnRitual } : {}),
|
|
813
919
|
...(deferV3Drain ? { defer_drain: true } : {}),
|
|
814
920
|
});
|
|
921
|
+
observeHookDebug(hookHealthState, {
|
|
922
|
+
...(v3Result ? { event_v3_state: v3Result.state } : {}),
|
|
923
|
+
});
|
|
815
924
|
const recordedGenerationId =
|
|
816
925
|
v3Result && "event" in v3Result && "generation_id" in v3Result.event.scope
|
|
817
926
|
? (v3Result.event.scope.generation_id as `gen_${string}`)
|
|
@@ -830,6 +939,13 @@ async function main(): Promise<number> {
|
|
|
830
939
|
logError(coordRoot, error, { phase: "epoch-coordination-restore" });
|
|
831
940
|
}
|
|
832
941
|
}
|
|
942
|
+
if (norm.event_type !== "session.ended") {
|
|
943
|
+
try {
|
|
944
|
+
ensureSessionDisplayName(coordRoot, owner.instance_id, sessionId, adapter);
|
|
945
|
+
} catch (error) {
|
|
946
|
+
logError(coordRoot, error, { phase: "session-display-name" });
|
|
947
|
+
}
|
|
948
|
+
}
|
|
833
949
|
const v3EventId =
|
|
834
950
|
v3Result && "event" in v3Result
|
|
835
951
|
? v3Result.event.event_id
|
|
@@ -966,6 +1082,7 @@ async function main(): Promise<number> {
|
|
|
966
1082
|
// Session start is the only caller of the artifact janitor and the storage
|
|
967
1083
|
// maintenance pass, so both load here instead of on every tool call.
|
|
968
1084
|
const { autoCleanArtifacts } = await import("../artifacts/index.ts");
|
|
1085
|
+
const { autoCleanEventV3Archives } = await import("../events/v3/archive-retention.ts");
|
|
969
1086
|
const { createAutomaticMaintenanceComposition, runAutomaticMaintenancePass } = await import(
|
|
970
1087
|
"../storage/maintenance-providers.ts"
|
|
971
1088
|
);
|
|
@@ -977,6 +1094,13 @@ async function main(): Promise<number> {
|
|
|
977
1094
|
} catch (err) {
|
|
978
1095
|
logError(coordRoot, err, { phase: "artifact-auto-clean" });
|
|
979
1096
|
}
|
|
1097
|
+
// Effect: apply the same daily throttle to closed V3 epochs. The newest
|
|
1098
|
+
// recovery epochs remain protected by the archive retention policy.
|
|
1099
|
+
try {
|
|
1100
|
+
autoCleanEventV3Archives(coordRoot);
|
|
1101
|
+
} catch (err) {
|
|
1102
|
+
logError(coordRoot, err, { phase: "event-v3-archive-auto-clean" });
|
|
1103
|
+
}
|
|
980
1104
|
// Plan one bounded, claim-first global slice from cached pressure only.
|
|
981
1105
|
// Existing owner janitors above remain the only active executors until
|
|
982
1106
|
// each provider receives a separate production activation.
|
|
@@ -1040,7 +1164,7 @@ async function main(): Promise<number> {
|
|
|
1040
1164
|
// agnostic since v0.5.0.
|
|
1041
1165
|
if (norm.event_type === "session.ended") {
|
|
1042
1166
|
try {
|
|
1043
|
-
cleanupSessionEnd(coordRoot, owner.instance_id
|
|
1167
|
+
cleanupSessionEnd(coordRoot, owner.instance_id);
|
|
1044
1168
|
} catch (err) {
|
|
1045
1169
|
logError(coordRoot, err, { phase: "session-end-cleanup" });
|
|
1046
1170
|
}
|
|
@@ -1065,27 +1189,9 @@ async function main(): Promise<number> {
|
|
|
1065
1189
|
if (norm.event_type === "agent.started") {
|
|
1066
1190
|
try {
|
|
1067
1191
|
const childInstanceId = (data.agent_id as string | undefined) ?? owner.instance_id;
|
|
1068
|
-
|
|
1069
|
-
if (existsSync(agentCoordBin)) {
|
|
1070
|
-
spawnSync(agentCoordBin, ["project"], {
|
|
1071
|
-
encoding: "utf8",
|
|
1072
|
-
timeout: 3000,
|
|
1073
|
-
env: childEnv(coordRoot),
|
|
1074
|
-
});
|
|
1075
|
-
spawnSync(
|
|
1076
|
-
agentCoordBin,
|
|
1077
|
-
[
|
|
1078
|
-
"log",
|
|
1079
|
-
`SUBAGENT_START agent_type=${(data.agent_type as string) ?? "unknown"} agent_id=${childInstanceId.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
|
|
1080
|
-
"--instance",
|
|
1081
|
-
childInstanceId,
|
|
1082
|
-
],
|
|
1083
|
-
{ encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
|
|
1084
|
-
);
|
|
1085
|
-
}
|
|
1086
|
-
emitSubagentStartContext(coordRoot, childInstanceId, sessionId, data, adapter);
|
|
1192
|
+
await emitSubagentStartContext(coordRoot, childInstanceId, sessionId, data, adapter);
|
|
1087
1193
|
} catch (err) {
|
|
1088
|
-
logError(coordRoot, err, { phase: "subagent-start-
|
|
1194
|
+
logError(coordRoot, err, { phase: "subagent-start-context" });
|
|
1089
1195
|
}
|
|
1090
1196
|
}
|
|
1091
1197
|
|
|
@@ -1093,20 +1199,7 @@ async function main(): Promise<number> {
|
|
|
1093
1199
|
if (norm.event_type === "agent.completed") {
|
|
1094
1200
|
try {
|
|
1095
1201
|
const childInstanceId = payload?.subagent_id ?? payload?.agent_id ?? owner.instance_id;
|
|
1096
|
-
cleanupSessionEnd(coordRoot, childInstanceId
|
|
1097
|
-
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1098
|
-
if (existsSync(agentCoordBin)) {
|
|
1099
|
-
spawnSync(
|
|
1100
|
-
agentCoordBin,
|
|
1101
|
-
[
|
|
1102
|
-
"log",
|
|
1103
|
-
`SUBAGENT_STOP agent_id=${childInstanceId.slice(0, 8)} platform=${adapterPlatform(adapter)}`,
|
|
1104
|
-
"--instance",
|
|
1105
|
-
childInstanceId,
|
|
1106
|
-
],
|
|
1107
|
-
{ encoding: "utf8", timeout: 2000, env: childEnv(coordRoot) },
|
|
1108
|
-
);
|
|
1109
|
-
}
|
|
1202
|
+
cleanupSessionEnd(coordRoot, childInstanceId);
|
|
1110
1203
|
const { reconcileSessionFinalizationV3 } = await import("../agents/session-finalizer-v3.ts");
|
|
1111
1204
|
reconcileSessionFinalizationV3(coordRoot, { archive_observations: [] });
|
|
1112
1205
|
} catch (err) {
|
|
@@ -1338,6 +1431,11 @@ async function main(): Promise<number> {
|
|
|
1338
1431
|
try {
|
|
1339
1432
|
const name = sessionNameDisplayPending(readLiveCoordinationRow(coordRoot, owner.instance_id));
|
|
1340
1433
|
if (name && toolResponseMintedSessionName(payload?.tool_response, name)) {
|
|
1434
|
+
// Record the title before asking for it. The suggestion can still
|
|
1435
|
+
// change afterwards (an assigned-name rewrite, a lifecycle re-mint, a
|
|
1436
|
+
// rebuilt cache), and the agent must not be stranded for displaying
|
|
1437
|
+
// exactly what it was handed.
|
|
1438
|
+
stampSessionNameRequested(coordRoot, owner.instance_id, name);
|
|
1341
1439
|
const { emitContext } = await import("./adapter/output.ts");
|
|
1342
1440
|
emitContext(adapter, "PostToolUse", sessionNameDisplayInstruction(name));
|
|
1343
1441
|
}
|
|
@@ -1414,25 +1512,7 @@ async function enforcePendingSessionNameDisplay(
|
|
|
1414
1512
|
const command = extractBashCommand(payload?.tool_name, payload?.tool_input);
|
|
1415
1513
|
if (isSessionNameRemediationCommand(command, resolveBinName(coordRoot))) return true;
|
|
1416
1514
|
|
|
1417
|
-
const inspection =
|
|
1418
|
-
adapter === "cursor" && payload?.agent_message !== undefined
|
|
1419
|
-
? {
|
|
1420
|
-
state: assistantTextStartsWithSessionNameBlock(payload.agent_message, name)
|
|
1421
|
-
? ("present" as const)
|
|
1422
|
-
: ("unavailable" as const),
|
|
1423
|
-
}
|
|
1424
|
-
: inspectSessionNameDisplayImmediately(
|
|
1425
|
-
// Codex hook payloads omit transcript_path on every event, which
|
|
1426
|
-
// left this inspection permanently unavailable and the latch never
|
|
1427
|
-
// stamped. Discover the rollout by session id; the scan only runs
|
|
1428
|
-
// while a name is pending, so the latch closes after one success.
|
|
1429
|
-
payload?.transcript_path ??
|
|
1430
|
-
(adapter === "codex"
|
|
1431
|
-
? discoverCodexSessionTranscript(payload?.session_id ?? instanceId)
|
|
1432
|
-
: undefined),
|
|
1433
|
-
name,
|
|
1434
|
-
assistantTextStartsWithSessionNameBlock,
|
|
1435
|
-
);
|
|
1515
|
+
const inspection = inspectDisplayEvidence(instanceId, adapter, payload, coordination);
|
|
1436
1516
|
if (inspection.state === "present") {
|
|
1437
1517
|
stampSessionNameSeen(coordRoot, instanceId, name);
|
|
1438
1518
|
return true;
|
|
@@ -1447,11 +1527,65 @@ async function enforcePendingSessionNameDisplay(
|
|
|
1447
1527
|
return true;
|
|
1448
1528
|
}
|
|
1449
1529
|
|
|
1530
|
+
// Record the refusal. Without this the gate was the one enforcement path
|
|
1531
|
+
// that left no trace, so a session reporting "the gate keeps denying me"
|
|
1532
|
+
// could not be confirmed or refuted from the hook log.
|
|
1533
|
+
appendDebug(coordRoot, {
|
|
1534
|
+
ts: new Date().toISOString(),
|
|
1535
|
+
event_name: "pre-tool-use",
|
|
1536
|
+
adapter,
|
|
1537
|
+
effect: "session-name-display-denied",
|
|
1538
|
+
session_name_pending: name,
|
|
1539
|
+
tool_name: payload?.tool_name,
|
|
1540
|
+
});
|
|
1450
1541
|
const { emitDeny } = await import("./adapter/output.ts");
|
|
1451
1542
|
emitDeny(adapter, sessionNameDisplayRecoveryInstruction(name, resolveBinName(coordRoot)));
|
|
1452
1543
|
return false;
|
|
1453
1544
|
}
|
|
1454
1545
|
|
|
1546
|
+
/**
|
|
1547
|
+
* Evidence for the pending display, over every title whose display counts.
|
|
1548
|
+
*
|
|
1549
|
+
* Cursor supplies the current narration directly; Claude Code and Codex are
|
|
1550
|
+
* resolved from their JSONL transcripts. Absent is the only state that denies,
|
|
1551
|
+
* so a title is refused only when a readable surface positively shows some
|
|
1552
|
+
* other opening text for every accepted title.
|
|
1553
|
+
*/
|
|
1554
|
+
function inspectDisplayEvidence(
|
|
1555
|
+
instanceId: string,
|
|
1556
|
+
adapter: Adapter,
|
|
1557
|
+
payload: ParsedPayload | null,
|
|
1558
|
+
coordination: Heartbeat | null,
|
|
1559
|
+
): SessionNameDisplayInspection {
|
|
1560
|
+
if (adapter === "cursor" && payload?.agent_message !== undefined) {
|
|
1561
|
+
return matchSessionNameDisplay(coordination, payload.agent_message)
|
|
1562
|
+
? { state: "present" }
|
|
1563
|
+
: { state: "unavailable", reason: "transcript_not_ready" };
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
// Codex hook payloads omit transcript_path on every event, which left this
|
|
1567
|
+
// inspection permanently unavailable and the latch never stamped. Discover
|
|
1568
|
+
// the rollout by session id; the scan only runs while a name is pending, so
|
|
1569
|
+
// the latch closes after one success.
|
|
1570
|
+
const transcriptPath =
|
|
1571
|
+
payload?.transcript_path ??
|
|
1572
|
+
(adapter === "codex"
|
|
1573
|
+
? discoverCodexSessionTranscript(payload?.session_id ?? instanceId)
|
|
1574
|
+
: undefined);
|
|
1575
|
+
|
|
1576
|
+
let verdict: SessionNameDisplayInspection = { state: "absent" };
|
|
1577
|
+
for (const candidate of sessionNameDisplayAcceptedNames(coordination)) {
|
|
1578
|
+
const inspection = inspectSessionNameDisplayImmediately(
|
|
1579
|
+
transcriptPath,
|
|
1580
|
+
candidate,
|
|
1581
|
+
assistantTextStartsWithSessionNameBlock,
|
|
1582
|
+
);
|
|
1583
|
+
if (inspection.state === "present") return inspection;
|
|
1584
|
+
if (inspection.state === "unavailable") verdict = inspection;
|
|
1585
|
+
}
|
|
1586
|
+
return verdict;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1455
1589
|
function generationBoundHeartbeat(
|
|
1456
1590
|
heartbeat: Heartbeat | null,
|
|
1457
1591
|
generationId: `gen_${string}` | undefined,
|
|
@@ -1494,42 +1628,19 @@ async function runPreToolUseGuard(
|
|
|
1494
1628
|
}
|
|
1495
1629
|
if (targets.length === 0) return true;
|
|
1496
1630
|
|
|
1497
|
-
const
|
|
1498
|
-
if (!existsSync(agentCoordBin)) {
|
|
1499
|
-
if (agentsRequireGitFinalization(coordRoot)) {
|
|
1500
|
-
const { emitDeny } = await import("./adapter/output.ts");
|
|
1501
|
-
emitDeny(
|
|
1502
|
-
adapter,
|
|
1503
|
-
"Harnery denied the write before mutation because the claim coordinator is unavailable; repair the project's Harnery installation and retry.",
|
|
1504
|
-
);
|
|
1505
|
-
return false;
|
|
1506
|
-
}
|
|
1507
|
-
return true;
|
|
1508
|
-
}
|
|
1631
|
+
const { evaluateClaim } = await import("../agents/rules/claim-conflict.ts");
|
|
1509
1632
|
|
|
1510
1633
|
// For apply_patch (multi-file), collect siblings so the deny reason names
|
|
1511
1634
|
// them. For single-file tools the array has one entry.
|
|
1512
1635
|
for (const target of targets) {
|
|
1513
|
-
const verdictReq = JSON.stringify({
|
|
1514
|
-
rule: "claim",
|
|
1515
|
-
instance_id: instanceId,
|
|
1516
|
-
session_id: sessionId,
|
|
1517
|
-
path: target.path,
|
|
1518
|
-
});
|
|
1519
|
-
const result = spawnSync(agentCoordBin, ["verdict"], {
|
|
1520
|
-
input: verdictReq,
|
|
1521
|
-
encoding: "utf8",
|
|
1522
|
-
timeout: 3000,
|
|
1523
|
-
env: childEnv(coordRoot),
|
|
1524
|
-
});
|
|
1525
|
-
if (result.status !== 0 || !result.stdout) continue;
|
|
1526
|
-
let parsed: { allow?: boolean; reason?: string } = {};
|
|
1527
1636
|
try {
|
|
1528
|
-
parsed =
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1637
|
+
const parsed = evaluateClaim(coordRoot, {
|
|
1638
|
+
rule: "claim",
|
|
1639
|
+
instance_id: instanceId,
|
|
1640
|
+
session_id: sessionId,
|
|
1641
|
+
path: target.path,
|
|
1642
|
+
});
|
|
1643
|
+
if (parsed.allow !== false) continue;
|
|
1533
1644
|
let reason =
|
|
1534
1645
|
parsed.reason ?? `Path ${target.path} is currently being edited by another agent.`;
|
|
1535
1646
|
if (targets.length > 1) {
|
|
@@ -1545,7 +1656,7 @@ async function runPreToolUseGuard(
|
|
|
1545
1656
|
const { emitDeny } = await import("./adapter/output.ts");
|
|
1546
1657
|
emitDeny(adapter, reason);
|
|
1547
1658
|
return false;
|
|
1548
|
-
}
|
|
1659
|
+
} catch {}
|
|
1549
1660
|
}
|
|
1550
1661
|
return true;
|
|
1551
1662
|
}
|
|
@@ -1748,16 +1859,23 @@ function releaseClaimOnFailure(
|
|
|
1748
1859
|
const row = readLiveCoordinationRow(coordRoot, instanceId);
|
|
1749
1860
|
if (!row?.files_touched?.includes(canonical)) return;
|
|
1750
1861
|
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1862
|
+
const before = readHeartbeat(coordRoot, instanceId);
|
|
1863
|
+
try {
|
|
1864
|
+
recordLiveClaimChangeV3({
|
|
1865
|
+
coordRoot,
|
|
1866
|
+
owner: instanceId,
|
|
1867
|
+
nativeSessionId: before?.session_id ?? instanceId,
|
|
1868
|
+
adapter: adapterFromPlatform(before?.platform),
|
|
1869
|
+
operation: "released",
|
|
1870
|
+
path: canonical,
|
|
1871
|
+
access: "write",
|
|
1872
|
+
});
|
|
1873
|
+
} catch {
|
|
1874
|
+
/* best-effort release must not break adapter flow */
|
|
1875
|
+
}
|
|
1758
1876
|
}
|
|
1759
1877
|
|
|
1760
|
-
function cleanupSessionEnd(coordRoot: string, instanceId: string
|
|
1878
|
+
function cleanupSessionEnd(coordRoot: string, instanceId: string): void {
|
|
1761
1879
|
// Sweep pid-map entries pointing to this instance
|
|
1762
1880
|
const pidmapDir = join(coordRoot, ".harnery", "pid-map");
|
|
1763
1881
|
if (existsSync(pidmapDir)) {
|
|
@@ -1779,15 +1897,6 @@ function cleanupSessionEnd(coordRoot: string, instanceId: string, reason: string
|
|
|
1779
1897
|
/* swallow */
|
|
1780
1898
|
}
|
|
1781
1899
|
}
|
|
1782
|
-
// Activity log
|
|
1783
|
-
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1784
|
-
if (existsSync(agentCoordBin)) {
|
|
1785
|
-
spawnSync(
|
|
1786
|
-
agentCoordBin,
|
|
1787
|
-
["log", `SESSION_END reason=${reason}`, "--instance", instanceId],
|
|
1788
|
-
{ encoding: "utf8", timeout: 2000 },
|
|
1789
|
-
);
|
|
1790
|
-
}
|
|
1791
1900
|
}
|
|
1792
1901
|
|
|
1793
1902
|
async function emitUserPromptSubmitSystemMessage(
|
|
@@ -1798,33 +1907,18 @@ async function emitUserPromptSubmitSystemMessage(
|
|
|
1798
1907
|
workspaceCwd?: string,
|
|
1799
1908
|
recoveryBriefing = "",
|
|
1800
1909
|
): Promise<boolean> {
|
|
1801
|
-
const
|
|
1802
|
-
let additionalContext =
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
// Only the boolean route travels through argv, never the host's text.
|
|
1814
|
-
if (adapter === "codex") args.push("--host-prompt-reminder");
|
|
1815
|
-
// Codex gets a fresh status-footer reminder on every prompt. Its Stop hook
|
|
1816
|
-
// stays observe-only, so missing the footer never replaces the answer.
|
|
1817
|
-
// Claude Code gets a fresh per-turn ritual reminder: satisfying the
|
|
1818
|
-
// contract up front is far cheaper than the bounce-and-retry the Stop hook
|
|
1819
|
-
// otherwise forces. Cursor's beforeSubmitPrompt cannot inject context, so
|
|
1820
|
-
// its Stop follow-up remains the supported enforcement channel.
|
|
1821
|
-
args.push("--session-name-nudge");
|
|
1822
|
-
if (adapter === "cursor" || adapter === "codex") args.push("--task-nudge");
|
|
1823
|
-
if (adapter === "codex") args.push("--status-footer-nudge");
|
|
1824
|
-
if (adapter === "claude-code") args.push("--turn-ritual-nudge", adapter);
|
|
1825
|
-
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1826
|
-
if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
|
|
1827
|
-
}
|
|
1910
|
+
const { renderPromptContext } = await import("../agents/render/prompt-context.ts");
|
|
1911
|
+
let additionalContext = renderPromptContext({
|
|
1912
|
+
coordRoot,
|
|
1913
|
+
instanceId,
|
|
1914
|
+
sessionId,
|
|
1915
|
+
adapter,
|
|
1916
|
+
sessionNameNudge: true,
|
|
1917
|
+
taskNudge: adapter === "cursor" || adapter === "codex",
|
|
1918
|
+
hostPromptReminder: adapter === "codex",
|
|
1919
|
+
statusFooterNudge: adapter === "codex",
|
|
1920
|
+
turnRitualNudge: adapter === "claude-code" ? adapter : undefined,
|
|
1921
|
+
}).trim();
|
|
1828
1922
|
if (adapter === "codex") {
|
|
1829
1923
|
const fileLinkContext = renderCodexWslFileLinkContext(coordRoot, workspaceCwd);
|
|
1830
1924
|
if (fileLinkContext) {
|
|
@@ -1841,14 +1935,14 @@ async function emitUserPromptSubmitSystemMessage(
|
|
|
1841
1935
|
return true;
|
|
1842
1936
|
}
|
|
1843
1937
|
|
|
1844
|
-
function emitSubagentStartContext(
|
|
1938
|
+
async function emitSubagentStartContext(
|
|
1845
1939
|
coordRoot: string,
|
|
1846
1940
|
instanceId: string,
|
|
1847
1941
|
sessionId: string,
|
|
1848
1942
|
data: Record<string, unknown>,
|
|
1849
1943
|
adapter: Adapter,
|
|
1850
|
-
): void {
|
|
1851
|
-
// Look up the subagent's assigned name (just-written by
|
|
1944
|
+
): Promise<void> {
|
|
1945
|
+
// Look up the subagent's assigned name (just-written by the in-process name
|
|
1852
1946
|
// in session.started data) + the parent's short id for the "you are a subagent
|
|
1853
1947
|
// of X" framing.
|
|
1854
1948
|
const subagentName = (data.name as string | undefined) ?? "";
|
|
@@ -1861,23 +1955,20 @@ function emitSubagentStartContext(
|
|
|
1861
1955
|
// Render peer table inline since the subagent might want to know who else
|
|
1862
1956
|
// is around. Reuse prompt-context (which dedups against the per-owner hash);
|
|
1863
1957
|
// first call will always emit.
|
|
1864
|
-
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1865
1958
|
let combined = message;
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
}
|
|
1959
|
+
const { renderPromptContext } = await import("../agents/render/prompt-context.ts");
|
|
1960
|
+
const context = renderPromptContext({
|
|
1961
|
+
coordRoot,
|
|
1962
|
+
instanceId,
|
|
1963
|
+
sessionId,
|
|
1964
|
+
agentName: subagentName,
|
|
1965
|
+
}).trim();
|
|
1966
|
+
if (context) combined = `${message}\n\n${context}`;
|
|
1875
1967
|
|
|
1876
1968
|
// Use SubagentStart event-name in CC's hookSpecificOutput shape; cursor's
|
|
1877
1969
|
// flat `additional_context` works the same way.
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
});
|
|
1970
|
+
const { emitContext } = await import("./adapter/output.ts");
|
|
1971
|
+
emitContext(adapter, "SubagentStart", combined);
|
|
1881
1972
|
}
|
|
1882
1973
|
|
|
1883
1974
|
function adapterPlatform(adapter: Adapter): string {
|
|
@@ -1885,6 +1976,12 @@ function adapterPlatform(adapter: Adapter): string {
|
|
|
1885
1976
|
return adapter;
|
|
1886
1977
|
}
|
|
1887
1978
|
|
|
1979
|
+
function adapterFromPlatform(platform: unknown): Adapter {
|
|
1980
|
+
if (platform === "cursor") return "cursor";
|
|
1981
|
+
if (platform === "codex") return "codex";
|
|
1982
|
+
return "claude-code";
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1888
1985
|
async function emitSessionStartSystemMessage(
|
|
1889
1986
|
coordRoot: string,
|
|
1890
1987
|
instanceId: string,
|
|
@@ -1893,53 +1990,29 @@ async function emitSessionStartSystemMessage(
|
|
|
1893
1990
|
adapter: Adapter,
|
|
1894
1991
|
recoveryBriefing = "",
|
|
1895
1992
|
): Promise<boolean> {
|
|
1896
|
-
const agentCoordBin = coordBinPath("agent-coord", coordRoot) ?? "";
|
|
1897
1993
|
const workflowChild = coordEnv("WORKFLOW_CHILD") === "1";
|
|
1898
1994
|
let additionalContext = "";
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
"
|
|
1919
|
-
|
|
1920
|
-
"--instance",
|
|
1921
|
-
instanceId,
|
|
1922
|
-
],
|
|
1923
|
-
{ encoding: "utf8", timeout: 2000 },
|
|
1924
|
-
);
|
|
1925
|
-
|
|
1926
|
-
// Workflow children retain lifecycle/event capture but do not receive
|
|
1927
|
-
// operator-facing peer, council, or init-remediation context. Injecting
|
|
1928
|
-
// that context can make a bounded child follow housekeeping instructions
|
|
1929
|
-
// instead of its assigned prompt.
|
|
1930
|
-
if (!workflowChild) {
|
|
1931
|
-
const agentName = (emittedData.name as string | undefined) ?? "";
|
|
1932
|
-
const args = ["session-context", "--instance", instanceId, "--session", sessionId];
|
|
1933
|
-
if (agentName) args.push("--name", agentName);
|
|
1934
|
-
// The "You are agent-X." prefix in session-context renders unqualified by
|
|
1935
|
-
// default (claude-code-style). For cursor/codex the bash dispatchers add
|
|
1936
|
-
// a "(Cursor)" / "(Codex)" suffix; pass it through as --platform-label.
|
|
1937
|
-
if (adapter !== "claude-code") {
|
|
1938
|
-
args.push("--platform-label", platform === "cursor" ? "Cursor" : "Codex");
|
|
1939
|
-
}
|
|
1940
|
-
const result = spawnSync(agentCoordBin, args, { encoding: "utf8", timeout: 3000 });
|
|
1941
|
-
if (result.status === 0 && result.stdout) additionalContext = result.stdout.trim();
|
|
1942
|
-
}
|
|
1995
|
+
// Opportunistic reconciliation makes normal session starts a failsafe for
|
|
1996
|
+
// archive, idle, cascade, and host lifecycle observations. It also runs the
|
|
1997
|
+
// stale cache sweep through the shared ADR 0077 composition.
|
|
1998
|
+
const { reconcileCoordinationV3 } = await import("../agents/reconcile-coordination-v3.ts");
|
|
1999
|
+
reconcileCoordinationV3(coordRoot);
|
|
2000
|
+
|
|
2001
|
+
// Workflow children retain lifecycle/event capture but do not receive
|
|
2002
|
+
// operator-facing peer, council, or init-remediation context. Injecting
|
|
2003
|
+
// that context can make a bounded child follow housekeeping instructions
|
|
2004
|
+
// instead of its assigned prompt.
|
|
2005
|
+
if (!workflowChild) {
|
|
2006
|
+
const agentName = (emittedData.name as string | undefined) ?? "";
|
|
2007
|
+
const { renderSessionContext } = await import("../agents/render/session-context.ts");
|
|
2008
|
+
additionalContext = renderSessionContext({
|
|
2009
|
+
coordRoot,
|
|
2010
|
+
instanceId,
|
|
2011
|
+
sessionId,
|
|
2012
|
+
agentName: agentName || undefined,
|
|
2013
|
+
platformLabel:
|
|
2014
|
+
adapter === "claude-code" ? undefined : adapter === "cursor" ? "Cursor" : "Codex",
|
|
2015
|
+
}).trim();
|
|
1943
2016
|
}
|
|
1944
2017
|
|
|
1945
2018
|
// Effect (claude-code): merge the journal recovery cue into the session-start
|
|
@@ -1987,6 +2060,11 @@ function completeRecoveryInjection(
|
|
|
1987
2060
|
|
|
1988
2061
|
main()
|
|
1989
2062
|
.then(async (code) => {
|
|
2063
|
+
writeHookHealthCompletion(hookHealthState, {
|
|
2064
|
+
finished_at_ms: performance.now(),
|
|
2065
|
+
finished_rss_bytes: process.memoryUsage().rss,
|
|
2066
|
+
pid: process.pid,
|
|
2067
|
+
});
|
|
1990
2068
|
await closeProcessLoggers();
|
|
1991
2069
|
process.exit(code);
|
|
1992
2070
|
})
|
|
@@ -1994,6 +2072,13 @@ main()
|
|
|
1994
2072
|
logError(resolveCoordRoot(process.cwd()), err, {
|
|
1995
2073
|
argv: process.argv.slice(2),
|
|
1996
2074
|
pid: process.pid,
|
|
2075
|
+
phase: "top-level",
|
|
2076
|
+
});
|
|
2077
|
+
writeHookHealthCompletion(hookHealthState, {
|
|
2078
|
+
finished_at_ms: performance.now(),
|
|
2079
|
+
finished_rss_bytes: process.memoryUsage().rss,
|
|
2080
|
+
pid: process.pid,
|
|
2081
|
+
faulted: true,
|
|
1997
2082
|
});
|
|
1998
2083
|
await closeProcessLoggers();
|
|
1999
2084
|
process.exit(0);
|