session-orchestrator 3.21.0 → 3.23.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.cursor/commands/autopilot-multi.md +14 -0
- package/.cursor/commands/autopilot.md +14 -0
- package/.cursor/commands/bootstrap.md +14 -0
- package/.cursor/commands/brainstorm.md +14 -0
- package/.cursor/commands/close.md +13 -0
- package/.cursor/commands/contract-version-bump.md +14 -0
- package/.cursor/commands/debug.md +14 -0
- package/.cursor/commands/discovery.md +14 -0
- package/.cursor/commands/dispatcher.md +14 -0
- package/.cursor/commands/eli5.md +14 -0
- package/.cursor/commands/eval.md +14 -0
- package/.cursor/commands/evolve.md +14 -0
- package/.cursor/commands/go.md +14 -0
- package/.cursor/commands/grill.md +14 -0
- package/.cursor/commands/harness-audit.md +13 -0
- package/.cursor/commands/journey-audit.md +14 -0
- package/.cursor/commands/memory-cleanup.md +14 -0
- package/.cursor/commands/persona-panel.md +14 -0
- package/.cursor/commands/plan.md +14 -0
- package/.cursor/commands/portfolio.md +14 -0
- package/.cursor/commands/reconcile.md +14 -0
- package/.cursor/commands/release.md +14 -0
- package/.cursor/commands/repo-audit.md +13 -0
- package/.cursor/commands/session.md +14 -0
- package/.cursor/commands/spinout.md +14 -0
- package/.cursor/commands/sunset-review.md +14 -0
- package/.cursor/commands/templates-ack.md +14 -0
- package/.cursor/commands/test.md +14 -0
- package/.cursor/hooks.json +60 -0
- package/.cursor/rules/000-session-orchestrator.mdc +11 -2
- package/.cursor/rules/010-session-workflow.mdc +9 -1
- package/.cursor/rules/020-quality-gates.mdc +1 -1
- package/.cursor/rules/030-wave-execution.mdc +1 -1
- package/.cursor/rules/040-discovery.mdc +6 -6
- package/.cursor/rules/050-plan.mdc +10 -10
- package/.cursor/rules/070-gitlab-ops.mdc +73 -57
- package/.cursor/rules/080-ecosystem-health.mdc +7 -7
- package/.cursor/skills/architecture/SKILL.md +13 -0
- package/.cursor/skills/autopilot/SKILL.md +12 -0
- package/.cursor/skills/bootstrap/SKILL.md +12 -0
- package/.cursor/skills/brainstorm/SKILL.md +13 -0
- package/.cursor/skills/claude-md-drift-check/SKILL.md +13 -0
- package/.cursor/skills/contract-version-bump/SKILL.md +12 -0
- package/.cursor/skills/convergence-monitoring/SKILL.md +12 -0
- package/.cursor/skills/daily/SKILL.md +12 -0
- package/.cursor/skills/debug/SKILL.md +13 -0
- package/.cursor/skills/discovery/SKILL.md +13 -0
- package/.cursor/skills/dispatcher/SKILL.md +13 -0
- package/.cursor/skills/docs-orchestrator/SKILL.md +13 -0
- package/.cursor/skills/domain-model/SKILL.md +13 -0
- package/.cursor/skills/ecosystem-health/SKILL.md +13 -0
- package/.cursor/skills/eli5/SKILL.md +13 -0
- package/.cursor/skills/eval/SKILL.md +12 -0
- package/.cursor/skills/evolve/SKILL.md +13 -0
- package/.cursor/skills/frontmatter-guard/SKILL.md +13 -0
- package/.cursor/skills/gitlab-ops/SKILL.md +13 -0
- package/.cursor/skills/gitlab-portfolio/SKILL.md +13 -0
- package/.cursor/skills/grill/SKILL.md +13 -0
- package/.cursor/skills/hook-development/SKILL.md +13 -0
- package/.cursor/skills/journey-audit/SKILL.md +13 -0
- package/.cursor/skills/mcp-builder/SKILL.md +13 -0
- package/.cursor/skills/memory-cleanup/SKILL.md +12 -0
- package/.cursor/skills/mode-selector/SKILL.md +13 -0
- package/.cursor/skills/npm-publish/SKILL.md +12 -0
- package/.cursor/skills/peekaboo-driver/SKILL.md +13 -0
- package/.cursor/skills/persona-panel/SKILL.md +12 -0
- package/.cursor/skills/plan/SKILL.md +13 -0
- package/.cursor/skills/playwright-driver/SKILL.md +13 -0
- package/.cursor/skills/quality-gates/SKILL.md +13 -0
- package/.cursor/skills/reconcile/SKILL.md +12 -0
- package/.cursor/skills/repo-audit/SKILL.md +13 -0
- package/.cursor/skills/session-end/SKILL.md +13 -0
- package/.cursor/skills/session-plan/SKILL.md +13 -0
- package/.cursor/skills/session-start/SKILL.md +13 -0
- package/.cursor/skills/skill-creator/SKILL.md +13 -0
- package/.cursor/skills/spinout/SKILL.md +12 -0
- package/.cursor/skills/sunset-review/SKILL.md +13 -0
- package/.cursor/skills/test-runner/SKILL.md +13 -0
- package/.cursor/skills/tmux-layout/SKILL.md +13 -0
- package/.cursor/skills/ubiquitous-language/SKILL.md +13 -0
- package/.cursor/skills/using-orchestrator/SKILL.md +13 -0
- package/.cursor/skills/vault-mirror/SKILL.md +13 -0
- package/.cursor/skills/vault-sync/SKILL.md +13 -0
- package/.cursor/skills/wave-executor/SKILL.md +13 -0
- package/.cursor/skills/write-executable-plan/SKILL.md +13 -0
- package/.mcp.json +4 -1
- package/CHANGELOG.md +269 -0
- package/README.md +18 -15
- package/agents/AGENTS.md +23 -4
- package/agents/code-implementer.md +2 -1
- package/agents/db-specialist.md +2 -1
- package/agents/docs-writer.md +3 -1
- package/agents/eval-judge.md +1 -1
- package/agents/memory-proposal-collector.md +6 -4
- package/agents/session-reviewer.md +7 -1
- package/agents/test-writer.md +2 -1
- package/agents/ui-developer.md +2 -1
- package/commands/bootstrap.md +2 -2
- package/commands/close.md +3 -1
- package/commands/eli5.md +33 -0
- package/commands/go.md +1 -1
- package/commands/journey-audit.md +43 -0
- package/commands/release.md +5 -3
- package/commands/test.md +2 -2
- package/docs/USER-GUIDE.md +2 -2
- package/docs/ci-setup.md +14 -0
- package/docs/codex-setup.md +64 -0
- package/docs/components.md +7 -6
- package/docs/cursor-setup.md +26 -47
- package/docs/events-schema.md +76 -4
- package/docs/github-mirror-protection.md +197 -0
- package/docs/pi-setup.md +2 -0
- package/docs/rule-authoring.md +3 -1
- package/docs/scope-collision-guard.md +52 -5
- package/docs/session-config-reference.md +57 -12
- package/docs/session-config-template.md +4 -3
- package/docs/telemetry.md +22 -0
- package/hooks/_lib/lock-bootstrap.mjs +26 -16
- package/hooks/_lib/vcs-create-matcher.mjs +397 -38
- package/hooks/enforce-scope.mjs +64 -0
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +201 -20
- package/hooks/hooks-pi.json +1 -1
- package/hooks/hooks.json +12 -2
- package/hooks/on-session-end.mjs +237 -104
- package/hooks/on-session-start.mjs +404 -110
- package/hooks/on-stop.mjs +48 -9
- package/hooks/post-subagent-discovery-validator.mjs +34 -3
- package/hooks/post-tool-batch-wave-signal.mjs +11 -2
- package/hooks/pre-auq-clarity.mjs +787 -0
- package/hooks/pre-bash-issue-budget.mjs +133 -21
- package/hooks/pre-bash-sessions-ledger-guard.mjs +159 -0
- package/hooks/pre-bash-staging-fence.mjs +4 -0
- package/hooks/pre-task-scope-disjoint.mjs +368 -35
- package/hooks/skill-invocation-telemetry.mjs +21 -10
- package/monitors/monitors.json +6 -0
- package/package.json +3 -1
- package/pi/prompts/eli5.md +12 -0
- package/pi/prompts/journey-audit.md +12 -0
- package/rules/_index.md +9 -1
- package/rules/always-on/ask-via-tool.md +62 -0
- package/rules/always-on/bash-harness-pitfalls.md +168 -0
- package/rules/always-on/build-value.md +47 -0
- package/rules/always-on/cross-session-messaging.md +59 -0
- package/rules/always-on/loop-and-monitor.md +221 -0
- package/rules/always-on/parallel-sessions.md +142 -12
- package/rules/always-on/receiving-review.md +108 -0
- package/rules/always-on/test-value.md +40 -0
- package/rules/always-on/verification-before-completion.md +77 -0
- package/scripts/archive-closed-prds.mjs +258 -18
- package/scripts/auq-audit.mjs +825 -0
- package/scripts/autopilot.mjs +12 -8
- package/scripts/backfill-evidence-digest.mjs +376 -0
- package/scripts/cursor-install.mjs +89 -48
- package/scripts/export-hw-learnings.mjs +143 -2
- package/scripts/express-path.mjs +299 -0
- package/scripts/generate-cursor-adapter.mjs +253 -0
- package/scripts/github-protection-audit.mjs +358 -0
- package/scripts/lib/auq/clarity.mjs +1314 -0
- package/scripts/lib/auq/parse.mjs +1006 -0
- package/scripts/lib/auq/schema.mjs +1457 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +240 -16
- package/scripts/lib/build-live-signals.mjs +24 -5
- package/scripts/lib/ci-status-banner.mjs +221 -68
- package/scripts/lib/command-blocker.mjs +70 -0
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +32 -9
- package/scripts/lib/config/reconcile.mjs +79 -4
- package/scripts/lib/config/section-extractor.mjs +235 -36
- package/scripts/lib/config/vault-integration.mjs +12 -1
- package/scripts/lib/config-schema.mjs +9 -1
- package/scripts/lib/config.mjs +57 -6
- package/scripts/lib/convergence-monitor.mjs +13 -2
- package/scripts/lib/cursor-hook-bridge.mjs +443 -0
- package/scripts/lib/dispatcher/cli.mjs +2 -2
- package/scripts/lib/dispatcher/rank.mjs +4 -7
- package/scripts/lib/express-path.mjs +327 -0
- package/scripts/lib/file-lock.mjs +22 -4
- package/scripts/lib/gates/gate-full.mjs +84 -11
- package/scripts/lib/gates/gate-helpers.mjs +93 -21
- package/scripts/lib/git-config-drift.mjs +134 -5
- package/scripts/lib/host-identity.mjs +247 -2
- package/scripts/lib/instruction-budget-guard.mjs +31 -1
- package/scripts/lib/io.mjs +239 -0
- package/scripts/lib/issue-budget.mjs +284 -31
- package/scripts/lib/learnings/io.mjs +55 -10
- package/scripts/lib/learnings/schema.mjs +95 -28
- package/scripts/lib/lock-reaper.mjs +7 -1
- package/scripts/lib/locks/staging-fence-lock.mjs +5 -1
- package/scripts/lib/locks/state-md-lock.mjs +8 -1
- package/scripts/lib/memory-banner.mjs +5 -2
- package/scripts/lib/memory-paths.mjs +15 -6
- package/scripts/lib/mode-selector/scoring.mjs +53 -6
- package/scripts/lib/owner-interview.mjs +78 -32
- package/scripts/lib/peer-discovery.mjs +73 -22
- package/scripts/lib/platform.mjs +72 -9
- package/scripts/lib/plugin-root.mjs +143 -19
- package/scripts/lib/project-hygiene.mjs +104 -4
- package/scripts/lib/quality-gate.mjs +271 -13
- package/scripts/lib/reconcile/emitter.mjs +87 -19
- package/scripts/lib/reconcile/engine.mjs +281 -13
- package/scripts/lib/reconcile/idempotency.mjs +102 -1
- package/scripts/lib/reconcile/renderer.mjs +165 -7
- package/scripts/lib/reconcile/sanitize.mjs +40 -17
- package/scripts/lib/reconcile/writer.mjs +415 -84
- package/scripts/lib/resource-probe/evaluate.mjs +330 -149
- package/scripts/lib/resource-probe/probe-platform.mjs +35 -0
- package/scripts/lib/resource-probe.mjs +18 -2
- package/scripts/lib/rule-loader.mjs +37 -2
- package/scripts/lib/rules-sync.mjs +51 -8
- package/scripts/lib/scope-gate.mjs +90 -0
- package/scripts/lib/session-close-backfill.mjs +369 -28
- package/scripts/lib/session-discovery.mjs +13 -3
- package/scripts/lib/session-end/phase-skip.mjs +37 -4
- package/scripts/lib/session-end/worktree-cleanup.mjs +154 -7
- package/scripts/lib/session-id.mjs +30 -14
- package/scripts/lib/session-identity/own-session.mjs +159 -0
- package/scripts/lib/session-lock.mjs +85 -30
- package/scripts/lib/session-schema/normalizer.mjs +70 -3
- package/scripts/lib/session-schema/validator.mjs +40 -0
- package/scripts/lib/session-start-probes.mjs +608 -0
- package/scripts/lib/session-transition.mjs +277 -0
- package/scripts/lib/sessions-staleness-banner.mjs +124 -57
- package/scripts/lib/spiral-carryover.mjs +111 -9
- package/scripts/lib/state-md/frontmatter-mutators.mjs +41 -8
- package/scripts/lib/state-md/mission-status.mjs +467 -72
- package/scripts/lib/state-md/yaml-parser.mjs +145 -16
- package/scripts/lib/state-md.mjs +12 -2
- package/scripts/lib/telemetry/sync.mjs +46 -8
- package/scripts/lib/validate/check-agents.mjs +66 -0
- package/scripts/lib/validate/check-auq-clarity.mjs +274 -0
- package/scripts/lib/validate/check-cursor-adapter.mjs +102 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +24 -2
- package/scripts/lib/validate/check-doc-cli-commands.mjs +16 -32
- package/scripts/lib/validate/check-hooks-symmetry.mjs +59 -63
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +13 -22
- package/scripts/lib/validate/check-plugin-monitors.mjs +10 -4
- package/scripts/lib/validate/check-rules.mjs +153 -9
- package/scripts/lib/validate/check-test-value-bans.mjs +165 -17
- package/scripts/lib/validate/check-unwired-features.mjs +340 -32
- package/scripts/lib/validate/repo-files.mjs +275 -0
- package/scripts/lib/validate-vendored-rules.mjs +229 -7
- package/scripts/lib/vault-backfill/glab.mjs +91 -58
- package/scripts/lib/vault-backfill/manifest.mjs +28 -8
- package/scripts/lib/vault-mirror/process.mjs +99 -43
- package/scripts/lib/vault-mirror/telemetry.mjs +210 -0
- package/scripts/lib/vault-staleness-banner.mjs +76 -6
- package/scripts/lib/vault-status/board-writer.mjs +211 -10
- package/scripts/lib/vault-status/narrative-mirror.mjs +188 -8
- package/scripts/lib/vcs-repo-spec.mjs +182 -13
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +832 -0
- package/scripts/lib/wave-resource-gate.mjs +67 -73
- package/scripts/lib/wave-transcript-tail.mjs +869 -0
- package/scripts/materialize-wave-scope.mjs +478 -0
- package/scripts/mcp-server.sh +11 -2
- package/scripts/parse-config.mjs +65 -0
- package/scripts/release.mjs +443 -122
- package/scripts/run-quality-gate.mjs +14 -0
- package/scripts/token-audit.sh +9 -2
- package/scripts/validate-plugin.mjs +6 -0
- package/scripts/validate-wave-scope.mjs +73 -1
- package/scripts/vault-backfill.mjs +32 -5
- package/scripts/vault-mirror.mjs +203 -34
- package/skills/_shared/monitor-patterns.md +31 -5
- package/skills/_shared/parallel-aware-auq.md +31 -25
- package/skills/_shared/parallel-aware-preamble.md +35 -4
- package/skills/_shared/platform-tools.md +11 -5
- package/skills/_shared/state-ownership.md +61 -8
- package/skills/autopilot/SKILL.md +5 -1
- package/skills/bootstrap/SKILL.md +5 -4
- package/skills/bootstrap/_shared-template.md +18 -10
- package/skills/bootstrap/deep-template.md +10 -6
- package/skills/bootstrap/fast-template.md +15 -8
- package/skills/bootstrap/standard-template.md +10 -6
- package/skills/brainstorm/SKILL.md +18 -18
- package/skills/brainstorm/soul.md +12 -0
- package/skills/claude-md-drift-check/checker.mjs +39 -11
- package/skills/discovery/SKILL.md +28 -24
- package/skills/dispatcher/SKILL.md +1 -1
- package/skills/eli5/SKILL.md +43 -0
- package/skills/evolve/SKILL.md +8 -9
- package/skills/gitlab-ops/SKILL.md +30 -26
- package/skills/grill/SKILL.md +6 -6
- package/skills/grill/soul.md +16 -0
- package/skills/journey-audit/SKILL.md +269 -0
- package/skills/memory-cleanup/SKILL.md +2 -2
- package/skills/npm-publish/SKILL.md +4 -4
- package/skills/peekaboo-driver/SKILL.md +18 -6
- package/skills/persona-panel/SKILL.md +1 -1
- package/skills/plan/SKILL.md +18 -16
- package/skills/plan/mode-feature.md +1 -1
- package/skills/plan/mode-new.md +35 -23
- package/skills/plan/soul.md +12 -0
- package/skills/reconcile/SKILL.md +44 -4
- package/skills/session-end/SKILL.md +70 -24
- package/skills/session-end/metrics-collection.md +7 -4
- package/skills/session-end/phase-3-6-tail.md +48 -5
- package/skills/session-end/phase-3-7a-recommendations.md +16 -2
- package/skills/session-plan/SKILL.md +6 -1
- package/skills/session-plan/wave-template.md +1 -0
- package/skills/session-start/SKILL.md +96 -48
- package/skills/session-start/phase-2-5-docs-planning.md +8 -8
- package/skills/session-start/phase-4-5-resource-health.md +82 -19
- package/skills/session-start/phase-7-5-mode-selector.md +15 -3
- package/skills/session-start/phase-8-5-express-path.md +77 -12
- package/skills/session-start/soul.md +110 -0
- package/skills/test-runner/SKILL.md +2 -2
- package/skills/using-orchestrator/SKILL.md +1 -1
- package/skills/vault-sync/validator.mjs +31 -0
- package/skills/wave-executor/SKILL.md +4 -2
- package/skills/wave-executor/circuit-breaker.md +34 -9
- package/skills/wave-executor/wave-loop.md +129 -24
- package/skills/write-executable-plan/SKILL.md +6 -6
- package/templates/_shared/journey-manifest.md +110 -0
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +0 -8
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +0 -8
- package/skills/vault-sync/tests/fixtures/archive-test-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/live-note.md +0 -8
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/bad-type.md +0 -8
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +0 -8
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +0 -8
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +0 -10
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +0 -8
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +0 -3
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +0 -11
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/has-dangling.md +0 -9
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +0 -8
- package/skills/vault-sync/tests/fixtures/empty-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/missing-field-vault/missing-id.md +0 -7
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +0 -9
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/nested-tags-note.md +0 -11
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +0 -3
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +0 -3
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +0 -11
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/hello-world.md +0 -11
- package/skills/vault-sync/tests/schema-drift.test.mjs +0 -133
- package/templates/_shared/rules/parallel-sessions.md +0 -77
package/hooks/on-stop.mjs
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
* JSONL format (`.orchestrator/metrics/events.jsonl`) — emitted via the canonical
|
|
17
17
|
* `emitEvent()` so the JSONL record and the optional Clank webhook always carry the
|
|
18
18
|
* SAME dotted event name (was: bare `stop`/`subagent_stop` in JSONL vs dotted in webhook):
|
|
19
|
-
* Stop: {"timestamp":<ISO>,"event":"orchestrator.session.stopped","session_id":"...","wave":<int>,"branch":"...","commit":"...","duration_ms":<int>}
|
|
19
|
+
* Stop: {"timestamp":<ISO>,"event":"orchestrator.session.stopped","session_id":"...","semantic_session_id":"...","wave":<int>,"branch":"...","commit":"...","duration_ms":<int>}
|
|
20
|
+
* (`session_id` / `semantic_session_id` are omitted when unresolvable — #1068 AC1.)
|
|
20
21
|
* SubagentStop: {"timestamp":<ISO>,"event":"orchestrator.agent.stopped","agent":"<name>"}
|
|
21
22
|
*/
|
|
22
23
|
|
|
@@ -29,6 +30,7 @@ if (!shouldRunHook('on-stop')) process.exit(0);
|
|
|
29
30
|
|
|
30
31
|
import { emitEvent } from '../scripts/lib/events.mjs';
|
|
31
32
|
import { SO_PROJECT_DIR } from '../scripts/lib/platform.mjs';
|
|
33
|
+
import { parseSessionId } from '../scripts/lib/session-id.mjs';
|
|
32
34
|
import { heartbeat, logSweepEvent } from '../scripts/lib/session-registry.mjs';
|
|
33
35
|
import { updateHeartbeat } from '../scripts/lib/session-lock.mjs';
|
|
34
36
|
|
|
@@ -216,17 +218,39 @@ async function readWaveNumber(projectRoot) {
|
|
|
216
218
|
// ---------------------------------------------------------------------------
|
|
217
219
|
|
|
218
220
|
/**
|
|
219
|
-
* Resolve this session's id
|
|
220
|
-
*
|
|
221
|
-
*
|
|
221
|
+
* Resolve this session's id + its attested semantic id. A stdin payload id wins
|
|
222
|
+
* ONLY when it parses as a UUID. If Claude Code did not pass one (Codex /
|
|
223
|
+
* Cursor paths, or older harnesses) — or passed something that is not a UUID —
|
|
224
|
+
* fall back to `.orchestrator/current-session.json` which on-session-start.mjs
|
|
225
|
+
* writes.
|
|
226
|
+
*
|
|
227
|
+
* #1091 / Kanevry#66 — WRITER/READER SYMMETRY, same defect class as
|
|
228
|
+
* `hooks/on-session-end.mjs`: `on-session-start.mjs` accepts a stdin raw id
|
|
229
|
+
* only when `parseSessionId(fromStdin)?.format === 'uuid'` and otherwise mints
|
|
230
|
+
* a `randomUUID()`, so every artifact this hook then addresses by id (the host
|
|
231
|
+
* registry entry, `session.lock`) is keyed by a UUID. Passing a non-UUID stdin
|
|
232
|
+
* string through meant `heartbeat()` and `updateHeartbeat()` addressed a key
|
|
233
|
+
* that was never written: the registry entry silently went un-refreshed (and
|
|
234
|
+
* aged into the zombie sweep) while the lock heartbeat no-oped on an ownership
|
|
235
|
+
* mismatch.
|
|
236
|
+
*
|
|
237
|
+
* `semanticSessionId` (#1068 AC1) is read from the SAME file and is deliberately
|
|
238
|
+
* gated on the resolved id BEING the recorded one — `current-session.json` is a
|
|
239
|
+
* single repo-global file describing whichever session most recently ran
|
|
240
|
+
* SessionStart, so an unrelated window's turn-end must not inherit a live
|
|
241
|
+
* peer's semantic identity (the #863 defect (c) contamination shape, mirrored
|
|
242
|
+
* here from `hooks/on-session-end.mjs`).
|
|
222
243
|
*
|
|
223
244
|
* @param {object|null} input
|
|
224
245
|
* @param {string} projectRoot
|
|
225
|
-
* @returns {Promise<string|null>}
|
|
246
|
+
* @returns {Promise<{sessionId: string|null, semanticSessionId: string|null}>}
|
|
226
247
|
*/
|
|
227
248
|
async function resolveSessionId(input, projectRoot) {
|
|
228
249
|
const fromStdin = input?.session_id ?? input?.sessionId ?? null;
|
|
229
|
-
|
|
250
|
+
let sessionId = parseSessionId(fromStdin)?.format === 'uuid' ? fromStdin : null;
|
|
251
|
+
|
|
252
|
+
let recordedId = null;
|
|
253
|
+
let semanticSessionId = null;
|
|
230
254
|
try {
|
|
231
255
|
const raw = await fs.readFile(
|
|
232
256
|
path.join(projectRoot, '.orchestrator', 'current-session.json'),
|
|
@@ -234,10 +258,20 @@ async function resolveSessionId(input, projectRoot) {
|
|
|
234
258
|
);
|
|
235
259
|
const parsed = JSON.parse(raw);
|
|
236
260
|
if (typeof parsed.session_id === 'string' && parsed.session_id.length > 0) {
|
|
237
|
-
|
|
261
|
+
recordedId = parsed.session_id;
|
|
262
|
+
}
|
|
263
|
+
if (typeof parsed.semantic_session_id === 'string' && parsed.semantic_session_id.length > 0) {
|
|
264
|
+
semanticSessionId = parsed.semantic_session_id;
|
|
238
265
|
}
|
|
239
266
|
} catch { /* missing or unparseable is fine */ }
|
|
240
|
-
|
|
267
|
+
|
|
268
|
+
if (sessionId === null) sessionId = recordedId;
|
|
269
|
+
|
|
270
|
+
const isRecordedSession = sessionId !== null && sessionId === recordedId;
|
|
271
|
+
return {
|
|
272
|
+
sessionId,
|
|
273
|
+
semanticSessionId: isRecordedSession ? semanticSessionId : null,
|
|
274
|
+
};
|
|
241
275
|
}
|
|
242
276
|
|
|
243
277
|
/**
|
|
@@ -250,7 +284,7 @@ async function handleStop(input) {
|
|
|
250
284
|
const wave = await readWaveNumber(projectRoot);
|
|
251
285
|
const { commit, branch } = await gitInfo(projectRoot);
|
|
252
286
|
|
|
253
|
-
const sessionId = await resolveSessionId(input, projectRoot);
|
|
287
|
+
const { sessionId, semanticSessionId } = await resolveSessionId(input, projectRoot);
|
|
254
288
|
|
|
255
289
|
// v3.1.0 multi-session registry (#169), corrected in #1047 — REFRESH the
|
|
256
290
|
// registry entry here; never remove it.
|
|
@@ -323,8 +357,13 @@ async function handleStop(input) {
|
|
|
323
357
|
// Single emission path: emitEvent writes the canonical {timestamp, event, ...payload}
|
|
324
358
|
// JSONL record AND fires the optional Clank webhook with the SAME event name — no
|
|
325
359
|
// more bare-`stop` (JSONL) vs dotted-`stopped` (webhook) divergence.
|
|
360
|
+
// #1068 AC1 — carry the attested semantic id alongside the raw UUID so a
|
|
361
|
+
// turn-end outcome is joinable by identity from events.jsonl alone. Omitted
|
|
362
|
+
// (never `""`/`null`) when unattested: an unresolved identity stays visibly
|
|
363
|
+
// unresolved rather than becoming a guessed id.
|
|
326
364
|
await emitEvent('orchestrator.session.stopped', {
|
|
327
365
|
...(sessionId !== null ? { session_id: sessionId } : {}),
|
|
366
|
+
...(semanticSessionId !== null ? { semantic_session_id: semanticSessionId } : {}),
|
|
328
367
|
wave,
|
|
329
368
|
...(branch !== null ? { branch } : {}),
|
|
330
369
|
...(commit !== null ? { commit } : {}),
|
|
@@ -30,6 +30,19 @@
|
|
|
30
30
|
* Why read the transcript: the SubagentStop stdin payload has NO output_text
|
|
31
31
|
* field. The agent's text lives in `input.transcript_path`.
|
|
32
32
|
*
|
|
33
|
+
* Output channels — THREE writes, TWO different recipients:
|
|
34
|
+
* - `discovery_validator_violation` in .orchestrator/metrics/events.jsonl,
|
|
35
|
+
* and the stderr WARN → the COORDINATOR's only copy of the finding. PSA-006
|
|
36
|
+
* makes REJECTING the unverified claim his duty, so these two are the
|
|
37
|
+
* channels that carry the rule's enforcement path.
|
|
38
|
+
* - stdout `hookSpecificOutput.additionalContext` → the STOPPING SUBAGENT
|
|
39
|
+
* (which continues and may self-correct), NOT the coordinator — a hook is
|
|
40
|
+
* structurally unable to address him. See the measured delivery note at the
|
|
41
|
+
* hookSpecificOutput write below for the shipped-binary evidence.
|
|
42
|
+
* All three are pinned together by the "all three channels fire" test in
|
|
43
|
+
* tests/hooks/post-subagent-discovery-validator.test.mjs — do not collapse
|
|
44
|
+
* the coordinator-visible pair into additionalContext.
|
|
45
|
+
*
|
|
33
46
|
* Exit codes: 0 always (informational, never blocking).
|
|
34
47
|
*/
|
|
35
48
|
|
|
@@ -594,12 +607,30 @@ async function main() {
|
|
|
594
607
|
}
|
|
595
608
|
|
|
596
609
|
if (alreadyWarned) {
|
|
597
|
-
// Events logged above; suppress
|
|
610
|
+
// Events logged above; suppress the repeat additionalContext for this
|
|
611
|
+
// already-warned real context. (Recipient is the stopping subagent, not the
|
|
612
|
+
// coordinator — see the delivery note at the hookSpecificOutput write below.)
|
|
598
613
|
return;
|
|
599
614
|
}
|
|
600
615
|
|
|
601
|
-
// v2.1.163+ additionalContext:
|
|
602
|
-
//
|
|
616
|
+
// v2.1.163+ additionalContext: surface the finding inline, not just in
|
|
617
|
+
// stderr + events.jsonl.
|
|
618
|
+
//
|
|
619
|
+
// The recipient is the SUBAGENT that just stopped — NOT the coordinator.
|
|
620
|
+
// Measured in the shipped binary (Claude Code 2.1.241, 2026-08-23): the
|
|
621
|
+
// SubagentStop hookSpecificOutput schema reads "additionalContext is
|
|
622
|
+
// non-error feedback delivered to the subagent; the subagent continues so it
|
|
623
|
+
// can act on it", and the emitter picks its target with
|
|
624
|
+
// `i.agentId ? "SubagentStop" : "Stop"`, yielding a `hook_additional_context`
|
|
625
|
+
// message into that agent's own loop. So this text lands in the transcript of
|
|
626
|
+
// the agent whose claims it is about, one moment after that agent is done.
|
|
627
|
+
//
|
|
628
|
+
// Worth knowing before "fixing" the path: PSA-006 asks the COORDINATOR to
|
|
629
|
+
// reject unverified distributional claims, and this channel never reaches
|
|
630
|
+
// him. His copy of the finding is events.jsonl + stderr, not this write.
|
|
631
|
+
// Whether he SHOULD receive it is a product question (#1116) — changing the
|
|
632
|
+
// route is not a comment edit.
|
|
633
|
+
//
|
|
603
634
|
// Non-blocking — exit 0 always. Decision:"block" must never be set here.
|
|
604
635
|
process.stdout.write(JSON.stringify({
|
|
605
636
|
hookSpecificOutput: {
|
|
@@ -41,6 +41,7 @@ if (!shouldRunHook('post-tool-batch-wave-signal')) process.exit(0);
|
|
|
41
41
|
|
|
42
42
|
import { SO_PROJECT_DIR } from '../scripts/lib/platform.mjs';
|
|
43
43
|
import { emitEvent } from '../scripts/lib/events.mjs';
|
|
44
|
+
import { findScopeFile } from '../scripts/lib/scope-gate.mjs';
|
|
44
45
|
|
|
45
46
|
// ---------------------------------------------------------------------------
|
|
46
47
|
// Helpers
|
|
@@ -135,17 +136,25 @@ async function resolveSessionIdForHeartbeat(input, sessionFile) {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
/**
|
|
138
|
-
* Resolve the current wave number from
|
|
139
|
+
* Resolve the current wave number from the wave-scope manifest's `.wave`.
|
|
139
140
|
* Returns 0 when the file is absent or unparseable, mirroring the
|
|
140
141
|
* pre-bash-memory-propose-audit.mjs G5 precedent ("wave defaults to 0 when
|
|
141
142
|
* wave-scope.json absent"). The file is deleted mid-session at Quality phase
|
|
142
143
|
* transitions and final cleanup, so absence is an expected, non-error state.
|
|
143
144
|
*
|
|
145
|
+
* The manifest is located via `findScopeFile()` (#1082), the same precedence
|
|
146
|
+
* every other consumer uses — `.pi` > `.cursor` > `.codex` > `.claude`. The
|
|
147
|
+
* previous hard-coded `.claude/` path made this hook's whole wave-lifecycle
|
|
148
|
+
* fallback structurally dead on Codex CLI, Cursor and pi: the manifest exists,
|
|
149
|
+
* it just is not under `.claude/`, so every batch read 0 and no
|
|
150
|
+
* `orchestrator.wave.started`/`completed` event was ever emitted there.
|
|
151
|
+
*
|
|
144
152
|
* @param {string} projectDir
|
|
145
153
|
* @returns {Promise<number>}
|
|
146
154
|
*/
|
|
147
155
|
async function resolveWaveNumber(projectDir) {
|
|
148
|
-
const waveFile =
|
|
156
|
+
const waveFile = findScopeFile(projectDir);
|
|
157
|
+
if (waveFile === null) return 0;
|
|
149
158
|
try {
|
|
150
159
|
const raw = await readFile(waveFile, 'utf8');
|
|
151
160
|
const data = JSON.parse(raw);
|