session-orchestrator 5.2.0 → 5.4.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/.agents/skills/architecture/SKILL.md +3 -1
- package/.agents/skills/autopilot/SKILL.md +5 -1
- package/.agents/skills/autopilot/agents/openai.yaml +5 -0
- package/.agents/skills/bootstrap/SKILL.md +5 -1
- package/.agents/skills/bootstrap/agents/openai.yaml +5 -0
- package/.agents/skills/brainstorm/SKILL.md +5 -1
- package/.agents/skills/brainstorm/agents/openai.yaml +5 -0
- package/.agents/skills/claude-md-drift-check/SKILL.md +4 -2
- package/.agents/skills/close/SKILL.md +5 -1
- package/.agents/skills/close/agents/openai.yaml +5 -0
- package/.agents/skills/convergence-monitoring/SKILL.md +4 -2
- package/.agents/skills/debug/SKILL.md +5 -1
- package/.agents/skills/debug/agents/openai.yaml +5 -0
- package/.agents/skills/discovery/SKILL.md +5 -1
- package/.agents/skills/discovery/agents/openai.yaml +5 -0
- package/.agents/skills/dispatcher/SKILL.md +5 -1
- package/.agents/skills/dispatcher/agents/openai.yaml +5 -0
- package/.agents/skills/docs-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ecosystem-health/SKILL.md +3 -1
- package/.agents/skills/eli5/SKILL.md +5 -1
- package/.agents/skills/eli5/agents/openai.yaml +5 -0
- package/.agents/skills/eval/SKILL.md +6 -2
- package/.agents/skills/eval/agents/openai.yaml +5 -0
- package/.agents/skills/evolve/SKILL.md +6 -2
- package/.agents/skills/evolve/agents/openai.yaml +5 -0
- package/.agents/skills/frontmatter-guard/SKILL.md +3 -1
- package/.agents/skills/gitlab-ops/SKILL.md +3 -1
- package/.agents/skills/gitlab-portfolio/SKILL.md +3 -1
- package/.agents/skills/go/SKILL.md +5 -1
- package/.agents/skills/go/agents/openai.yaml +5 -0
- package/.agents/skills/grill/SKILL.md +5 -1
- package/.agents/skills/grill/agents/openai.yaml +5 -0
- package/.agents/skills/harness-audit/SKILL.md +5 -1
- package/.agents/skills/harness-audit/agents/openai.yaml +5 -0
- package/.agents/skills/hook-development/SKILL.md +3 -1
- package/.agents/skills/mcp-builder/SKILL.md +3 -1
- package/.agents/skills/memory-cleanup/SKILL.md +5 -1
- package/.agents/skills/memory-cleanup/agents/openai.yaml +5 -0
- package/.agents/skills/mode-selector/SKILL.md +3 -1
- package/.agents/skills/navigator/SKILL.md +22 -0
- package/.agents/skills/navigator/agents/openai.yaml +5 -0
- package/.agents/skills/npm-publish/SKILL.md +4 -2
- package/.agents/skills/peekaboo-driver/SKILL.md +3 -1
- package/.agents/skills/persona-panel/SKILL.md +5 -1
- package/.agents/skills/persona-panel/agents/openai.yaml +5 -0
- package/.agents/skills/plan/SKILL.md +5 -1
- package/.agents/skills/plan/agents/openai.yaml +5 -0
- package/.agents/skills/playwright-driver/SKILL.md +3 -1
- package/.agents/skills/portfolio/SKILL.md +5 -1
- package/.agents/skills/portfolio/agents/openai.yaml +5 -0
- package/.agents/skills/quality-gates/SKILL.md +3 -1
- package/.agents/skills/reconcile/SKILL.md +5 -1
- package/.agents/skills/reconcile/agents/openai.yaml +5 -0
- package/.agents/skills/release/SKILL.md +5 -1
- package/.agents/skills/release/agents/openai.yaml +5 -0
- package/.agents/skills/remote-offload/SKILL.md +3 -1
- package/.agents/skills/repo-audit/SKILL.md +5 -1
- package/.agents/skills/repo-audit/agents/openai.yaml +5 -0
- package/.agents/skills/session/SKILL.md +21 -0
- package/.agents/skills/session/agents/openai.yaml +5 -0
- package/.agents/skills/session-end/SKILL.md +3 -1
- package/.agents/skills/session-plan/SKILL.md +3 -1
- package/.agents/skills/session-start/SKILL.md +3 -1
- package/.agents/skills/spinout/SKILL.md +5 -1
- package/.agents/skills/spinout/agents/openai.yaml +5 -0
- package/.agents/skills/sunset-review/SKILL.md +5 -1
- package/.agents/skills/sunset-review/agents/openai.yaml +5 -0
- package/.agents/skills/templates-ack/SKILL.md +21 -0
- package/.agents/skills/templates-ack/agents/openai.yaml +5 -0
- package/.agents/skills/test/SKILL.md +5 -1
- package/.agents/skills/test/agents/openai.yaml +5 -0
- package/.agents/skills/test-audit/SKILL.md +21 -0
- package/.agents/skills/test-audit/agents/openai.yaml +5 -0
- package/.agents/skills/test-runner/SKILL.md +3 -1
- package/.agents/skills/tmux-layout/SKILL.md +3 -1
- package/.agents/skills/using-orchestrator/SKILL.md +3 -1
- package/.agents/skills/ux-grill/SKILL.md +5 -1
- package/.agents/skills/ux-grill/agents/openai.yaml +5 -0
- package/.agents/skills/vault-mirror/SKILL.md +3 -1
- package/.agents/skills/vault-sync/SKILL.md +3 -1
- package/.agents/skills/wave-executor/SKILL.md +3 -1
- package/.agents/skills/write-executable-plan/SKILL.md +3 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +4 -4
- package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.codex-plugin/skills/convergence-monitoring/SKILL.md +1 -3
- package/.codex-plugin/skills/eval/SKILL.md +1 -1
- package/.codex-plugin/skills/evolve/SKILL.md +1 -1
- package/.codex-plugin/skills/navigator/SKILL.md +22 -0
- package/.codex-plugin/skills/{convergence-monitoring → navigator}/agents/openai.yaml +2 -2
- package/.codex-plugin/skills/npm-publish/SKILL.md +1 -3
- package/.codex-plugin/skills/session/SKILL.md +1 -1
- package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
- package/.codex-plugin/skills/{npm-publish → test-audit}/agents/openai.yaml +1 -1
- package/.cursor/commands/eval.md +1 -1
- package/.cursor/commands/navigator.md +15 -0
- package/.cursor/commands/session.md +1 -1
- package/.cursor/commands/test-audit.md +14 -0
- package/.cursor/rules/000-session-orchestrator.mdc +0 -2
- package/.cursor/rules/050-plan.mdc +1 -1
- package/.cursor/rules/060-evolve.mdc +27 -12
- package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
- package/.cursor/skills/convergence-monitoring/SKILL.md +1 -0
- package/.cursor/skills/eval/SKILL.md +1 -1
- package/.cursor/skills/navigator/SKILL.md +13 -0
- package/.cursor/skills/npm-publish/SKILL.md +1 -0
- package/.cursor/skills/test-audit/SKILL.md +12 -0
- package/.cursor-plugin/plugin.json +1 -1
- package/.orchestrator/policy/blocked-commands.json +12 -3
- package/AGENTS.md +9 -30
- package/CHANGELOG.md +206 -0
- package/README.md +13 -9
- package/SECURITY.md +12 -0
- package/agents/dialectic-deriver.md +13 -10
- package/agents/eval-judge.md +67 -45
- package/agents/skill-applied-judge.md +34 -19
- package/commands/session.md +7 -3
- package/docs/agent-authoring.md +2 -2
- package/docs/baseline.md +22 -7
- package/docs/ci-setup.md +57 -4
- package/docs/codex-setup.md +14 -2
- package/docs/components.md +12 -10
- package/docs/events-schema.md +65 -15
- package/docs/persona-panel.md +5 -4
- package/docs/rule-authoring.md +84 -17
- package/docs/scope-collision-guard.md +26 -4
- package/docs/session-config-reference.md +154 -12
- package/docs/session-config-template.md +41 -3
- package/docs/telemetry.md +2 -0
- package/hooks/_lib/hook-import-set.json +87 -6
- package/hooks/_lib/subagent-transcript.mjs +582 -31
- package/hooks/config-protection.mjs +11 -3
- package/hooks/cwd-change-restore.mjs +11 -3
- package/hooks/enforce-commands.mjs +70 -23
- package/hooks/enforce-scope.mjs +143 -33
- package/hooks/hooks-codex.json +1 -1
- package/hooks/hooks-cursor.json +5 -0
- package/hooks/hooks-pi.json +5 -0
- package/hooks/hooks.json +6 -1
- package/hooks/loop-guard.mjs +11 -3
- package/hooks/on-session-end.mjs +58 -23
- package/hooks/on-session-start.mjs +101 -11
- package/hooks/on-stop.mjs +170 -22
- package/hooks/operator-steer.mjs +11 -3
- package/hooks/post-bash-issue-budget-refund.mjs +18 -8
- package/hooks/post-bash-write-verify.mjs +3 -2
- package/hooks/post-edit-import-probe.mjs +17 -9
- package/hooks/post-edit-validate.mjs +13 -5
- package/hooks/post-subagent-discovery-validator.mjs +98 -13
- package/hooks/post-tool-batch-wave-signal.mjs +202 -38
- package/hooks/post-tool-failure-corrective-context.mjs +11 -5
- package/hooks/post-tooluse-frontend-slop.mjs +10 -4
- package/hooks/pre-auq-clarity.mjs +15 -2
- package/hooks/pre-bash-destructive-guard.mjs +80 -9
- package/hooks/pre-bash-issue-budget.mjs +16 -11
- package/hooks/pre-bash-memory-propose-audit.mjs +137 -56
- package/hooks/pre-bash-sessions-ledger-guard.mjs +419 -22
- package/hooks/pre-bash-staging-fence.mjs +335 -31
- package/hooks/pre-bash-templates-first.mjs +19 -14
- package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
- package/hooks/pre-task-scope-disjoint.mjs +792 -74
- package/hooks/subagent-telemetry.mjs +111 -38
- package/hooks/wave-scope-commit-guard.mjs +197 -100
- package/monitors/monitors.json +1 -1
- package/output-styles/wave-summary.md +1 -1
- package/package.json +3 -3
- package/pi/prompts/eval.md +1 -1
- package/pi/prompts/navigator.md +12 -0
- package/pi/prompts/session.md +1 -1
- package/pi/prompts/test-audit.md +12 -0
- package/rules/README.md +7 -2
- package/rules/_index.md +3 -3
- package/rules/always-on/bash-harness-pitfalls.md +7 -1
- package/rules/opt-in-domain/prompt-caching.md +6 -2
- package/rules/opt-in-stack/backend-data.md +10 -2
- package/rules/opt-in-stack/backend.md +10 -4
- package/rules/opt-in-stack/frontend.md +7 -2
- package/rules/opt-in-stack/security-web.md +10 -4
- package/rules/opt-in-stack/swift.md +6 -2
- package/scripts/apply-session-learnings.mjs +492 -0
- package/scripts/archive-closed-prds.mjs +2 -1
- package/scripts/autopilot.mjs +70 -53
- package/scripts/backfill-abandoned-sessions.mjs +118 -16
- package/scripts/baseline-archetypes.mjs +1 -1
- package/scripts/check-package-manager.mjs +62 -5
- package/scripts/check-sessions-integrity.mjs +300 -0
- package/scripts/cursor-install.mjs +1 -4
- package/scripts/dialectic-deriver.mjs +50 -13
- package/scripts/emit-session.mjs +371 -31
- package/scripts/eval-session.mjs +65 -3
- package/scripts/export-hw-learnings.mjs +22 -3
- package/scripts/fleet-checkin.mjs +147 -0
- package/scripts/generate-agents-skills.mjs +102 -29
- package/scripts/generate-cursor-adapter.mjs +61 -16
- package/scripts/lib/agent-frontmatter.mjs +3 -3
- package/scripts/lib/agent-status.mjs +2 -31
- package/scripts/lib/auq/clarity.mjs +10 -2
- package/scripts/lib/auq/parse.mjs +12 -31
- package/scripts/lib/auq/schema.mjs +56 -41
- package/scripts/lib/auto-dialectic.mjs +304 -15
- package/scripts/lib/auto-dream.mjs +7 -6
- package/scripts/lib/autopilot/flags.mjs +18 -2
- package/scripts/lib/autopilot/kill-switches.mjs +6 -3
- package/scripts/lib/autopilot/loop.mjs +19 -2
- package/scripts/lib/autopilot/stall-sampler.mjs +80 -23
- package/scripts/lib/baseline-archetypes.mjs +41 -22
- package/scripts/lib/ci-status-banner.mjs +376 -16
- package/scripts/lib/command-blocker.mjs +275 -28
- package/scripts/lib/config/dialectic.mjs +12 -3
- package/scripts/lib/config/gate.mjs +74 -0
- package/scripts/lib/config/host-paths.mjs +79 -0
- package/scripts/lib/config/persona-gate-wave.mjs +3 -3
- package/scripts/lib/config/reaper.mjs +163 -0
- package/scripts/lib/config-schema.mjs +13 -0
- package/scripts/lib/config.mjs +85 -10
- package/scripts/lib/convergence-monitor.mjs +74 -11
- package/scripts/lib/ecosystem-health.mjs +11 -0
- package/scripts/lib/eval/engine.mjs +421 -53
- package/scripts/lib/eval/judge.mjs +463 -40
- package/scripts/lib/eval/schema.mjs +10 -1
- package/scripts/lib/events-rotation.mjs +221 -25
- package/scripts/lib/events-schema.mjs +114 -0
- package/scripts/lib/events.mjs +545 -7
- package/scripts/lib/fleet-protocol.mjs +270 -0
- package/scripts/lib/frontmatter-guard.mjs +21 -10
- package/scripts/lib/gates/gate-baseline.mjs +40 -5
- package/scripts/lib/gates/gate-full.mjs +35 -5
- package/scripts/lib/gates/gate-helpers.mjs +336 -23
- package/scripts/lib/gates/gate-incremental.mjs +49 -23
- package/scripts/lib/gates/gate-per-file.mjs +42 -8
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +6 -1
- package/scripts/lib/instruction-budget-guard.mjs +208 -8
- package/scripts/lib/io.mjs +42 -8
- package/scripts/lib/issue-close-strip-labels.mjs +207 -49
- package/scripts/lib/js-mask.mjs +197 -0
- package/scripts/lib/learnings/evolve-telemetry.mjs +11 -7
- package/scripts/lib/learnings/expiry-sweep.mjs +34 -3
- package/scripts/lib/learnings/io.mjs +154 -26
- package/scripts/lib/learnings/schema.mjs +163 -15
- package/scripts/lib/learnings/sizing-subject.mjs +2 -2
- package/scripts/lib/maintenance-due-banner.mjs +53 -88
- package/scripts/lib/memory-proposals/schema.mjs +11 -5
- package/scripts/lib/named-baseline-resolver.mjs +53 -28
- package/scripts/lib/named-vault-resolver.mjs +104 -5
- package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
- package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
- package/scripts/lib/orphan-reaper/reaper-audit.mjs +291 -0
- package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
- package/scripts/lib/orphan-reaper/scan-throttle.mjs +92 -0
- package/scripts/lib/orphan-reaper/scan.mjs +506 -0
- package/scripts/lib/orphan-reaper.mjs +316 -0
- package/scripts/lib/owner-yaml.mjs +104 -6
- package/scripts/lib/peer-cards/merger.mjs +48 -10
- package/scripts/lib/peer-cards/reader.mjs +78 -2
- package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
- package/scripts/lib/process-group.mjs +950 -0
- package/scripts/lib/project-hygiene.mjs +21 -1
- package/scripts/lib/quality-gate.mjs +152 -33
- package/scripts/lib/reconcile/backlog.mjs +368 -0
- package/scripts/lib/reconcile/engine.mjs +55 -188
- package/scripts/lib/reconcile/rule-expiry-sweep.mjs +302 -60
- package/scripts/lib/reconcile/sanitize.mjs +69 -3
- package/scripts/lib/reconcile-nudge-banner.mjs +138 -45
- package/scripts/lib/resource-probe/parsers.mjs +31 -0
- package/scripts/lib/resource-probe.mjs +1 -1
- package/scripts/lib/rule-loader.mjs +141 -74
- package/scripts/lib/rules-sync.mjs +27 -12
- package/scripts/lib/scope-baseline.mjs +3 -4
- package/scripts/lib/scope-echo.mjs +39 -2
- package/scripts/lib/scope-gate.mjs +605 -1
- package/scripts/lib/session-close-backfill.mjs +33 -6
- package/scripts/lib/session-id.mjs +9 -20
- package/scripts/lib/session-invocation.mjs +20 -0
- package/scripts/lib/session-record-repair.mjs +183 -26
- package/scripts/lib/session-registry.mjs +27 -2
- package/scripts/lib/session-schema/constants.mjs +56 -2
- package/scripts/lib/session-schema/normalizer.mjs +56 -4
- package/scripts/lib/session-schema/validator.mjs +28 -1
- package/scripts/lib/session-schema.mjs +8 -3
- package/scripts/lib/session-start-probes.mjs +95 -10
- package/scripts/lib/session-token-rollup.mjs +245 -52
- package/scripts/lib/sessions-canonical.mjs +118 -4
- package/scripts/lib/sessions-integrity-banner.mjs +7 -1
- package/scripts/lib/sessions-staleness-banner.mjs +193 -51
- package/scripts/lib/sh-quote.mjs +29 -0
- package/scripts/lib/skill-evidence-window.mjs +891 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +133 -12
- package/scripts/lib/skill-evolution/engine.mjs +18 -9
- package/scripts/lib/skill-judge.mjs +45 -3
- package/scripts/lib/subagents-schema.mjs +30 -3
- package/scripts/lib/tail-window.mjs +56 -0
- package/scripts/lib/telemetry/pricing.mjs +118 -71
- package/scripts/lib/telemetry/schema.mjs +30 -0
- package/scripts/lib/telemetry/sync.mjs +61 -6
- package/scripts/lib/telemetry-flush-health-banner.mjs +4 -22
- package/scripts/lib/test-runner/issue-reconcile.mjs +48 -16
- package/scripts/lib/tests-src-ratio.mjs +140 -23
- package/scripts/lib/tmux-layout/layouts.mjs +1 -11
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +72 -13
- package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
- package/scripts/lib/user-invocable-skills.mjs +23 -3
- package/scripts/lib/ux-grill/reconcile.mjs +48 -22
- package/scripts/lib/validate/check-agents-skills.mjs +26 -15
- package/scripts/lib/validate/check-agents.mjs +1 -1
- package/scripts/lib/validate/check-cursor-adapter.mjs +1 -0
- package/scripts/lib/validate/check-entry-guard.mjs +13 -50
- package/scripts/lib/validate/check-hook-entry-guards.mjs +636 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
- package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +1 -0
- package/scripts/lib/validate/check-rules.mjs +7 -5
- package/scripts/lib/validate/check-skill-links.mjs +9 -1
- package/scripts/lib/validate/check-skill-script-paths.mjs +239 -27
- package/scripts/lib/validate/check-test-git-config-target.mjs +24 -34
- package/scripts/lib/validate/check-test-value-bans.mjs +87 -14
- package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
- package/scripts/lib/validate/check-untracked-test-deps.mjs +7 -102
- package/scripts/lib/validate/check-unwired-features.mjs +130 -27
- package/scripts/lib/validate/check-validator-registration.mjs +34 -10
- package/scripts/lib/validate/confidential-names.mjs +10 -0
- package/scripts/lib/validate-vendored-rules.mjs +210 -84
- package/scripts/lib/vault-mirror/namespace.mjs +46 -8
- package/scripts/lib/vault-mirror/process.mjs +10 -3
- package/scripts/lib/vault-mirror/render-sessions.mjs +12 -2
- package/scripts/lib/vault-mirror/telemetry.mjs +8 -1
- package/scripts/lib/vault-status/board-writer.mjs +48 -11
- package/scripts/lib/vault-status/narrative-mirror.mjs +71 -16
- package/scripts/lib/vault-yaml.mjs +118 -0
- package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
- package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
- package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
- package/scripts/lib/wave-resource-gate.mjs +34 -8
- package/scripts/lib/worktree/lifecycle.mjs +153 -1
- package/scripts/memory-propose.mjs +18 -5
- package/scripts/release-session-lock.mjs +306 -0
- package/scripts/release.mjs +40 -8
- package/scripts/repair-invalid-sessions.mjs +37 -4
- package/scripts/resolve-session-invocation.mjs +59 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +158 -30
- package/scripts/run-quality-gate.mjs +357 -197
- package/scripts/site-numbers.mjs +163 -5
- package/scripts/sweep-expired-learnings.mjs +56 -5
- package/scripts/sweep-expired-rules.mjs +16 -4
- package/scripts/validate-plugin.mjs +19 -0
- package/scripts/validate-wave-scope.mjs +32 -105
- package/scripts/vault-integration-watcher.mjs +2 -1
- package/scripts/vault-mirror.mjs +81 -47
- package/scripts/wave-scope-binding.mjs +2 -1
- package/skills/_shared/config-reading.md +3 -3
- package/skills/_shared/fleet-protocol.md +131 -0
- package/skills/_shared/platform-tools.md +23 -11
- package/skills/_shared/state-ownership.md +5 -0
- package/skills/autopilot/SKILL.md +47 -18
- package/skills/bootstrap/SKILL.md +1 -1
- package/skills/bootstrap/_shared-template.md +1 -1
- package/skills/bootstrap/fast-template.md +1 -1
- package/skills/bootstrap/private-contract.md +2 -1
- package/skills/bootstrap/public-fallback.md +6 -3
- package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
- package/skills/claude-md-drift-check/SKILL.md +10 -10
- package/skills/claude-md-drift-check/checker.mjs +26 -18
- package/skills/convergence-monitoring/README.md +8 -1
- package/skills/convergence-monitoring/SIGNALS.md +50 -6
- package/skills/convergence-monitoring/SKILL.md +15 -6
- package/skills/eval/SKILL.md +39 -24
- package/skills/eval/rubric-v1.md +1 -0
- package/skills/eval/rubric-v2.md +457 -0
- package/skills/evolve/SKILL.md +3 -3
- package/skills/evolve/references/evolve-analyze-mode.md +10 -6
- package/skills/evolve/references/evolve-dialectic-mode.md +42 -25
- package/skills/gitlab-ops/SKILL.md +3 -2
- package/skills/memory-cleanup/SKILL.md +1 -1
- package/skills/navigator/SKILL.md +193 -0
- package/skills/navigator/references/account-check.sh +87 -0
- package/skills/navigator/references/fleet-decisions.mjs +231 -0
- package/skills/navigator/references/slot-check.sh +114 -0
- package/skills/npm-publish/SKILL.md +1 -1
- package/skills/persona-panel/SKILL.md +2 -2
- package/skills/persona-panel/persona-format.md +2 -2
- package/skills/persona-panel/presets/designer-lens.md +1 -1
- package/skills/persona-panel/presets/engineer-lens.md +1 -1
- package/skills/persona-panel/presets/pm-lens.md +1 -1
- package/skills/plan/mode-retro.md +19 -4
- package/skills/quality-gates/SKILL.md +6 -4
- package/skills/reconcile/SKILL.md +11 -0
- package/skills/remote-offload/SKILL.md +4 -2
- package/skills/session-end/SKILL.md +13 -16
- package/skills/session-end/discovery-scan.md +1 -1
- package/skills/session-end/learning-patterns.md +22 -12
- package/skills/session-end/metrics-collection.md +5 -6
- package/skills/session-end/phase-3-6-tail.md +55 -9
- package/skills/session-end/references/phase-3-documentation-updates.md +2 -2
- package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
- package/skills/session-end/references/phase-5-issue-cleanup.md +9 -14
- package/skills/session-end/references/session-summary-template.md +1 -1
- package/skills/session-end/session-metrics-write.md +32 -60
- package/skills/session-plan/SKILL.md +17 -8
- package/skills/session-plan/references/session-plan-task-classification.md +2 -2
- package/skills/session-start/SKILL.md +6 -0
- package/skills/session-start/references/operations-contract.md +4 -0
- package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
- package/skills/session-start/references/phase-4-ssot-environment-check.md +4 -3
- package/skills/test-audit/SKILL.md +152 -0
- package/skills/test-audit/references/campaign.md +111 -0
- package/skills/test-audit/references/mutate.sh +50 -0
- package/skills/ux-grill/SKILL.md +1 -1
- package/skills/wave-executor/SKILL.md +9 -5
- package/skills/wave-executor/circuit-breaker.md +2 -0
- package/skills/wave-executor/references/wave-executor-state-init.md +8 -3
- package/skills/wave-executor/references/wave-loop-dispatch.md +5 -2
- package/skills/wave-executor/references/wave-loop-review.md +3 -5
- package/templates/personas/README.md +5 -5
- package/templates/personas/accounting-compliance.v1.md +1 -1
- package/templates/personas/accounting-tax-advisor.v1.md +1 -1
- package/templates/personas/buyer-p1-cto.v1.md +1 -1
- package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
- package/templates/personas/buyer-p3-build.v1.md +1 -1
- package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
- package/templates/personas/buyer-p5-solo.v1.md +1 -1
- package/templates/personas/buyer-p6-ld.v1.md +1 -1
- package/templates/personas/klima-ai-expert.v1.md +1 -1
- package/templates/personas/klima-physicist.v1.md +1 -1
- package/.cursor/commands/convergence-monitoring.md +0 -13
- package/.cursor/commands/npm-publish.md +0 -13
- package/pi/prompts/convergence-monitoring.md +0 -11
- package/pi/prompts/npm-publish.md +0 -11
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/check-sessions-integrity.mjs
|
|
3
|
+
//
|
|
4
|
+
// CLI front-end for `checkSessionsIntegrity` (GitLab #1417).
|
|
5
|
+
//
|
|
6
|
+
// WHY THIS EXISTS:
|
|
7
|
+
// session-end step 4a (`skills/session-end/session-metrics-write.md`) has to
|
|
8
|
+
// prove that the session record it JUST appended to
|
|
9
|
+
// `.orchestrator/metrics/sessions.jsonl` is schema-valid AND renderable by
|
|
10
|
+
// vault-mirror — step 4 before it only proves the line is JSON. The #1408
|
|
11
|
+
// record parsed fine and was still invalid (`ended_at` instead of
|
|
12
|
+
// `completed_at`, four required fields missing), so vault-mirror dropped it as
|
|
13
|
+
// `skipped-invalid` and that session got no vault note; nobody was told until
|
|
14
|
+
// the NEXT session-start banner. Until now the check existed only as a
|
|
15
|
+
// `node --input-type=module -e` one-liner inside the skill body, because the
|
|
16
|
+
// function had no CLI entry point (`scripts/repair-invalid-sessions.mjs` is a
|
|
17
|
+
// REPAIR path whose `--dry-run` exit reports repairability, not validity).
|
|
18
|
+
//
|
|
19
|
+
// WHAT IT CHECKS (exactly what the banner checks — no second opinion here):
|
|
20
|
+
// every parseable record in the ledger is run through `validateSession()` AND
|
|
21
|
+
// through vault-mirror's real render path. `--session-id` narrows the VERDICT
|
|
22
|
+
// to one record; other sessions' findings are still printed (they are not this
|
|
23
|
+
// close's to fix) but never decide the exit code.
|
|
24
|
+
//
|
|
25
|
+
// WHY A MISSING RECORD EXITS 1 (the deliberate call, #1417):
|
|
26
|
+
// `checkSessionsIntegrity` is silent both when a named record is sound and
|
|
27
|
+
// when it does not exist — "no finding" cannot tell those apart. Reporting the
|
|
28
|
+
// absent case as success would make this guard fail-open in precisely the
|
|
29
|
+
// shape it exists to catch: a close that proceeds with NO ledger record, one
|
|
30
|
+
// notch worse than the #1408 invalid one. So with `--session-id` the ledger is
|
|
31
|
+
// additionally read for that id and its absence is a named failure ("record
|
|
32
|
+
// not found"), never a silent pass. Without `--session-id` there is no id to
|
|
33
|
+
// be absent, and an empty/missing ledger is simply nothing to judge (exit 0).
|
|
34
|
+
//
|
|
35
|
+
// USAGE:
|
|
36
|
+
// node scripts/check-sessions-integrity.mjs [--repo-root <path>] [--session-id <id>] [--json]
|
|
37
|
+
//
|
|
38
|
+
// EXIT CODES:
|
|
39
|
+
// 0 every judged record validates and mirrors
|
|
40
|
+
// 1 a judged record is schema-invalid, is dropped by vault-mirror, or (with
|
|
41
|
+
// --session-id) is not in the ledger at all
|
|
42
|
+
// 2 tool error — unknown/incomplete flag, or an unreadable repo root
|
|
43
|
+
//
|
|
44
|
+
// Node stdlib only apart from two repo-local imports; safe to call from a hook,
|
|
45
|
+
// a skill body or CI without any dependency install.
|
|
46
|
+
|
|
47
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
48
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
49
|
+
import { fileURLToPath } from 'node:url';
|
|
50
|
+
|
|
51
|
+
import { checkSessionsIntegrity, SESSIONS_PATH } from './lib/sessions-integrity-banner.mjs';
|
|
52
|
+
import { isMainModule } from './lib/is-main-module.mjs';
|
|
53
|
+
|
|
54
|
+
const SELF_DIR = dirname(fileURLToPath(import.meta.url));
|
|
55
|
+
|
|
56
|
+
const HELP_TEXT = `check-sessions-integrity.mjs — session-ledger schema + vault-mirror gate (#1417)
|
|
57
|
+
|
|
58
|
+
USAGE
|
|
59
|
+
node scripts/check-sessions-integrity.mjs [options]
|
|
60
|
+
|
|
61
|
+
DESCRIPTION
|
|
62
|
+
Runs every parseable record in .orchestrator/metrics/sessions.jsonl through
|
|
63
|
+
validateSession() AND through vault-mirror's real render path — the same two
|
|
64
|
+
populations the session-start banner reports. A record can pass one and fail
|
|
65
|
+
the other, so both are checked and reported separately.
|
|
66
|
+
|
|
67
|
+
This is the command form of session-end step 4a: after appending a session
|
|
68
|
+
record, prove it is sound BEFORE the close continues.
|
|
69
|
+
|
|
70
|
+
OPTIONS
|
|
71
|
+
--repo-root <path> Repo root holding .orchestrator/metrics/ (default: cwd).
|
|
72
|
+
--session-id <id> Judge only the record(s) carrying this session_id. Other
|
|
73
|
+
sessions' findings are still printed but never decide the
|
|
74
|
+
exit code — they are pre-existing, not this close's to fix.
|
|
75
|
+
An id with NO record in the ledger is a FAILURE (exit 1),
|
|
76
|
+
not a silent pass: absent and sound are indistinguishable
|
|
77
|
+
to the checker, and the fail-open reading is the dangerous
|
|
78
|
+
one.
|
|
79
|
+
--json Emit one JSON result object on stdout (diagnostics stay
|
|
80
|
+
on stderr).
|
|
81
|
+
--help, -h Show this help and exit.
|
|
82
|
+
--version Print the package version and exit.
|
|
83
|
+
|
|
84
|
+
EXIT CODES
|
|
85
|
+
0 every judged record validates and mirrors
|
|
86
|
+
1 a judged record is schema-invalid, is dropped by vault-mirror, or (with
|
|
87
|
+
--session-id) is not in the ledger at all
|
|
88
|
+
2 tool error — unknown/incomplete flag, or an unreadable repo root
|
|
89
|
+
|
|
90
|
+
EXAMPLES
|
|
91
|
+
node scripts/check-sessions-integrity.mjs
|
|
92
|
+
node scripts/check-sessions-integrity.mjs --session-id main-2026-09-21-session-4
|
|
93
|
+
node scripts/check-sessions-integrity.mjs --json | jq '.findings'
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Parse argv. Returns `error` (a message) instead of throwing, so the caller
|
|
98
|
+
* owns the exit code.
|
|
99
|
+
*
|
|
100
|
+
* @param {string[]} argv
|
|
101
|
+
* @returns {{opts: {repoRoot: string|null, sessionId: string|null, json: boolean,
|
|
102
|
+
* help: boolean, version: boolean}, error: string|null}}
|
|
103
|
+
*/
|
|
104
|
+
export function parseArgs(argv) {
|
|
105
|
+
const opts = { repoRoot: null, sessionId: null, json: false, help: false, version: false };
|
|
106
|
+
for (let i = 0; i < argv.length; i++) {
|
|
107
|
+
const arg = argv[i];
|
|
108
|
+
switch (arg) {
|
|
109
|
+
case '--repo-root':
|
|
110
|
+
case '--session-id': {
|
|
111
|
+
const value = argv[i + 1];
|
|
112
|
+
// A flag whose value is missing — or is itself the next flag — must be a
|
|
113
|
+
// usage error, never a silently empty filter that judges nothing.
|
|
114
|
+
if (typeof value !== 'string' || value === '' || value.startsWith('--')) {
|
|
115
|
+
return { opts, error: `${arg} requires a value` };
|
|
116
|
+
}
|
|
117
|
+
if (arg === '--repo-root') opts.repoRoot = value;
|
|
118
|
+
else opts.sessionId = value;
|
|
119
|
+
i += 1;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
case '--json':
|
|
123
|
+
opts.json = true;
|
|
124
|
+
break;
|
|
125
|
+
case '--help':
|
|
126
|
+
case '-h':
|
|
127
|
+
opts.help = true;
|
|
128
|
+
break;
|
|
129
|
+
case '--version':
|
|
130
|
+
opts.version = true;
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
return { opts, error: `unknown flag: ${arg}` };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { opts, error: null };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Count the ledger records carrying `sessionId`. Unparseable lines are skipped —
|
|
141
|
+
* the same posture the banner takes: this judges schema integrity, not file
|
|
142
|
+
* corruption.
|
|
143
|
+
*
|
|
144
|
+
* @param {string} repoRoot
|
|
145
|
+
* @param {string} sessionId
|
|
146
|
+
* @returns {number}
|
|
147
|
+
*/
|
|
148
|
+
function countLedgerRecords(repoRoot, sessionId) {
|
|
149
|
+
const filePath = join(repoRoot, SESSIONS_PATH);
|
|
150
|
+
if (!existsSync(filePath)) return 0;
|
|
151
|
+
let matched = 0;
|
|
152
|
+
for (const line of readFileSync(filePath, 'utf8').split('\n')) {
|
|
153
|
+
if (line.trim() === '') continue;
|
|
154
|
+
let record;
|
|
155
|
+
try {
|
|
156
|
+
record = JSON.parse(line);
|
|
157
|
+
} catch {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (record && typeof record === 'object' && record.session_id === sessionId) matched += 1;
|
|
161
|
+
}
|
|
162
|
+
return matched;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Run the check and return a plain result object. Never throws; never exits.
|
|
167
|
+
*
|
|
168
|
+
* @param {{repoRoot?: string, sessionId?: string|null}} [opts]
|
|
169
|
+
* @returns {{ok: boolean, exitCode: 0|1|2, repoRoot: string, sessionId: string|null,
|
|
170
|
+
* total: number|null, matched: number|null, severity: 'warn'|'alert'|null,
|
|
171
|
+
* message: string|null, findings: {kind: string, line: number, sessionId: string, error: string}[],
|
|
172
|
+
* error: string|null}}
|
|
173
|
+
*/
|
|
174
|
+
export function runSessionsIntegrityCheck({ repoRoot, sessionId = null } = {}) {
|
|
175
|
+
const root = resolve(repoRoot ?? process.cwd());
|
|
176
|
+
const base = {
|
|
177
|
+
ok: false,
|
|
178
|
+
exitCode: 2,
|
|
179
|
+
repoRoot: root,
|
|
180
|
+
sessionId: sessionId ?? null,
|
|
181
|
+
total: null,
|
|
182
|
+
matched: null,
|
|
183
|
+
severity: null,
|
|
184
|
+
message: null,
|
|
185
|
+
findings: [],
|
|
186
|
+
error: null,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
if (!existsSync(root) || !statSync(root).isDirectory()) {
|
|
191
|
+
return { ...base, error: `repo root is not a directory: ${root}` };
|
|
192
|
+
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
return { ...base, error: `repo root unreadable: ${err?.message ?? String(err)}` };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const banner = checkSessionsIntegrity({ repoRoot: root });
|
|
198
|
+
|
|
199
|
+
const findings = banner
|
|
200
|
+
? [
|
|
201
|
+
...banner.schemaInvalid.map((f) => ({ kind: 'schema-invalid', ...f })),
|
|
202
|
+
...banner.mirrorSkipped.map((f) => ({ kind: 'mirror-skipped', ...f })),
|
|
203
|
+
]
|
|
204
|
+
: [];
|
|
205
|
+
|
|
206
|
+
const result = {
|
|
207
|
+
...base,
|
|
208
|
+
total: banner ? banner.total : null,
|
|
209
|
+
severity: banner ? banner.severity : null,
|
|
210
|
+
message: banner ? banner.message : null,
|
|
211
|
+
findings,
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
if (sessionId === null || sessionId === undefined) {
|
|
215
|
+
// No filter: every finding decides.
|
|
216
|
+
const ok = findings.length === 0;
|
|
217
|
+
return { ...result, ok, exitCode: ok ? 0 : 1 };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const matched = countLedgerRecords(root, sessionId);
|
|
221
|
+
const mine = findings.filter((f) => f.sessionId === sessionId);
|
|
222
|
+
|
|
223
|
+
if (matched === 0) {
|
|
224
|
+
return {
|
|
225
|
+
...result,
|
|
226
|
+
matched,
|
|
227
|
+
ok: false,
|
|
228
|
+
exitCode: 1,
|
|
229
|
+
error:
|
|
230
|
+
`no record with session_id "${sessionId}" in ${SESSIONS_PATH} — ` +
|
|
231
|
+
'it was never written, or it was written under a different id. ' +
|
|
232
|
+
'Re-emit it via scripts/emit-session.mjs.',
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const ok = mine.length === 0;
|
|
237
|
+
return { ...result, matched, ok, exitCode: ok ? 0 : 1 };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function readVersion() {
|
|
241
|
+
try {
|
|
242
|
+
const pkg = JSON.parse(readFileSync(join(SELF_DIR, '..', 'package.json'), 'utf8'));
|
|
243
|
+
return typeof pkg.version === 'string' ? pkg.version : 'unknown';
|
|
244
|
+
} catch {
|
|
245
|
+
return 'unknown';
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// CLI entry — only when run directly, never on import (an import must do
|
|
250
|
+
// nothing: this module is loaded by tests and is reachable from hook code).
|
|
251
|
+
if (isMainModule(import.meta.url)) {
|
|
252
|
+
const { opts, error } = parseArgs(process.argv.slice(2));
|
|
253
|
+
|
|
254
|
+
if (error !== null) {
|
|
255
|
+
process.stderr.write(`[check-sessions-integrity] ${error}\n`);
|
|
256
|
+
process.stderr.write('Run with --help for usage.\n');
|
|
257
|
+
process.exit(2);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (opts.help) {
|
|
261
|
+
process.stdout.write(HELP_TEXT);
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (opts.version) {
|
|
266
|
+
process.stdout.write(`${readVersion()}\n`);
|
|
267
|
+
process.exit(0);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const repoRootArg =
|
|
271
|
+
opts.repoRoot === null ? undefined : isAbsolute(opts.repoRoot) ? opts.repoRoot : resolve(process.cwd(), opts.repoRoot);
|
|
272
|
+
|
|
273
|
+
const result = runSessionsIntegrityCheck({ repoRoot: repoRootArg, sessionId: opts.sessionId });
|
|
274
|
+
|
|
275
|
+
if (opts.json) {
|
|
276
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
277
|
+
process.exit(result.exitCode);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// The banner text covers EVERY record, including other sessions' pre-existing
|
|
281
|
+
// findings — printed for visibility, even when the verdict below is clean.
|
|
282
|
+
if (result.message) process.stderr.write(`${result.message}\n`);
|
|
283
|
+
if (result.error) process.stderr.write(`[check-sessions-integrity] ${result.error}\n`);
|
|
284
|
+
|
|
285
|
+
if (result.exitCode === 2) process.exit(2);
|
|
286
|
+
|
|
287
|
+
if (result.ok) {
|
|
288
|
+
const scope = result.sessionId ? `record "${result.sessionId}"` : 'every ledger record';
|
|
289
|
+
process.stdout.write(`[check-sessions-integrity] OK — ${scope} validates and mirrors\n`);
|
|
290
|
+
process.exit(0);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const scope = result.sessionId ? `session "${result.sessionId}"` : 'the sessions ledger';
|
|
294
|
+
process.stderr.write(
|
|
295
|
+
`[check-sessions-integrity] FAIL — ${scope} is not sound. ` +
|
|
296
|
+
'Re-emit the affected record(s) via scripts/emit-session.mjs ' +
|
|
297
|
+
'(bulk repair: node scripts/repair-invalid-sessions.mjs --apply).\n',
|
|
298
|
+
);
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
@@ -20,6 +20,7 @@ import path from 'node:path';
|
|
|
20
20
|
import { fileURLToPath } from 'node:url';
|
|
21
21
|
|
|
22
22
|
import { CURSOR_TO_CANONICAL_EVENT } from './lib/cursor-hook-bridge.mjs';
|
|
23
|
+
import { shellQuote as shQuote } from './lib/sh-quote.mjs';
|
|
23
24
|
|
|
24
25
|
const __filename = fileURLToPath(import.meta.url);
|
|
25
26
|
const SCRIPT_DIR = path.dirname(__filename);
|
|
@@ -62,10 +63,6 @@ function _isDir(p) {
|
|
|
62
63
|
try { return statSync(p).isDirectory(); } catch { return false; }
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
function shQuote(value) {
|
|
66
|
-
return `'${String(value).replace(/'/g, `'\\''`)}'`;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
66
|
function linkPath(source, dest, label) {
|
|
70
67
|
mkdirSync(path.dirname(dest), { recursive: true });
|
|
71
68
|
if (_isSymlink(dest)) {
|
|
@@ -49,6 +49,7 @@ import { readPeerCards } from './lib/peer-cards/reader.mjs';
|
|
|
49
49
|
import { filterRealSessions } from './lib/session-schema/filters.mjs';
|
|
50
50
|
import { readCanonicalSessions } from './lib/sessions-canonical.mjs';
|
|
51
51
|
import { recordDialecticRun } from './lib/learnings/evolve-telemetry.mjs';
|
|
52
|
+
import { DEFAULT_BUDGET_TOKENS } from './lib/config/dialectic.mjs';
|
|
52
53
|
|
|
53
54
|
// ---------------------------------------------------------------------------
|
|
54
55
|
// Constants
|
|
@@ -57,8 +58,11 @@ import { recordDialecticRun } from './lib/learnings/evolve-telemetry.mjs';
|
|
|
57
58
|
/** Allowed LLM model identifiers. Per #506 EARS unwanted-behaviour: fail-fast on others. */
|
|
58
59
|
export const ALLOWED_MODELS = Object.freeze(['haiku', 'sonnet', 'opus']);
|
|
59
60
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Default per-call budget (input + output tokens). Per #506 AC2; the input
|
|
63
|
+
* ceiling is `DEFAULT_BUDGET_TOKENS` from the config parser (SSOT, #1380).
|
|
64
|
+
*/
|
|
65
|
+
export const DEFAULT_BUDGET = Object.freeze({ input: DEFAULT_BUDGET_TOKENS, output: 4000 });
|
|
62
66
|
|
|
63
67
|
/** Industry-standard heuristic: ~4 chars per token for English prose. */
|
|
64
68
|
const CHARS_PER_TOKEN = 4;
|
|
@@ -309,19 +313,21 @@ export function buildPrompt(payload, model, randomNonce = () => randomBytes(4).t
|
|
|
309
313
|
'',
|
|
310
314
|
'```diff',
|
|
311
315
|
'# target: user',
|
|
312
|
-
'<
|
|
316
|
+
'<the `## ` sections of USER.md you change or add>',
|
|
313
317
|
'```',
|
|
314
318
|
'',
|
|
315
319
|
'```diff',
|
|
316
320
|
'# target: agent',
|
|
317
|
-
'<
|
|
321
|
+
'<the `## ` sections of AGENT.md you change or add>',
|
|
318
322
|
'```',
|
|
319
323
|
'',
|
|
320
324
|
'Rules:',
|
|
321
325
|
'- Emit at most one block per target. Omit a target entirely when no update is warranted.',
|
|
322
|
-
'- The block body is
|
|
326
|
+
'- The block body is a set of whole `## ` sections — not a unified diff hunk. It is merged per section:',
|
|
327
|
+
' omitted sections stay UNCHANGED (nothing is deleted), so emit ONLY the sections you change or newly',
|
|
328
|
+
' ground, and reuse an existing heading verbatim to update that section.',
|
|
323
329
|
'- Preserve existing peer-card frontmatter; do not include `---` frontmatter lines in your block.',
|
|
324
|
-
'- Do not invent
|
|
330
|
+
'- Do not invent sections without evidence from the supplied learnings or sessions — nothing downstream rejects them.',
|
|
325
331
|
`- Operate within the dialectic budget appropriate for model '${model}'.`,
|
|
326
332
|
'',
|
|
327
333
|
].join('\n');
|
|
@@ -505,6 +511,26 @@ async function readSteering(repoRoot) {
|
|
|
505
511
|
* @property {number} [budget]
|
|
506
512
|
*/
|
|
507
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Record a THROWN abort (`unknown-model`, `subagent-crash`) before the caller
|
|
516
|
+
* rethrows the original error (#1221). The record is guarded on its own:
|
|
517
|
+
* `recordDialecticRun()` is best-effort today, but the rethrow contract must
|
|
518
|
+
* not depend on that staying true — a telemetry failure never replaces the
|
|
519
|
+
* error the caller is about to rethrow.
|
|
520
|
+
*
|
|
521
|
+
* @param {string} repoRoot
|
|
522
|
+
* @param {'unknown-model' | 'subagent-crash'} status
|
|
523
|
+
* @param {number} t0 — `Date.now()` at run start
|
|
524
|
+
* @returns {Promise<void>}
|
|
525
|
+
*/
|
|
526
|
+
async function recordThrownAbort(repoRoot, status, t0) {
|
|
527
|
+
try {
|
|
528
|
+
await recordDialecticRun({ repoRoot, status, durationMs: Date.now() - t0 });
|
|
529
|
+
} catch {
|
|
530
|
+
/* swallowed on purpose — see docblock */
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
508
534
|
/**
|
|
509
535
|
* Run the deriver loop: load inputs → build payload → check budget → dispatch
|
|
510
536
|
* agent → parse response → guard empty-card. Returns a structured verdict.
|
|
@@ -546,15 +572,20 @@ export async function runDialecticDeriver({
|
|
|
546
572
|
|
|
547
573
|
// #1206 — telemetry start marker for the mechanical `orchestrator.dialectic.
|
|
548
574
|
// completed` emits below. Mechanical (measured), not the coordinator's own
|
|
549
|
-
// typed DURATION_MS placeholder — covers every
|
|
550
|
-
//
|
|
551
|
-
//
|
|
552
|
-
//
|
|
553
|
-
//
|
|
575
|
+
// typed DURATION_MS placeholder — covers every outcome THIS function can
|
|
576
|
+
// see: the returns, and since #1221 the two THROWN aborts (`unknown-model`,
|
|
577
|
+
// `subagent-crash`), recorded at the throw point before the original error
|
|
578
|
+
// is rethrown. Only APPLY-mode success stays with the skill-prose caller —
|
|
579
|
+
// the merge happens one layer up, outside this pure pipeline.
|
|
554
580
|
const t0 = Date.now();
|
|
555
581
|
|
|
556
582
|
// Gate 1: model fail-fast. Throws Error with the canonical message.
|
|
557
|
-
|
|
583
|
+
try {
|
|
584
|
+
validateModel(model);
|
|
585
|
+
} catch (err) {
|
|
586
|
+
await recordThrownAbort(repoRoot, 'unknown-model', t0);
|
|
587
|
+
throw err;
|
|
588
|
+
}
|
|
558
589
|
|
|
559
590
|
// Load inputs (best-effort, never throws on missing).
|
|
560
591
|
const [learnings, sessions, peerCardsResult, steering] = await Promise.all([
|
|
@@ -611,7 +642,13 @@ export async function runDialecticDeriver({
|
|
|
611
642
|
|
|
612
643
|
// Dispatch — DI boundary. Caller wires the real Agent({...}) wrapper or a mock.
|
|
613
644
|
const maxTokens = typeof budget?.output === 'number' ? budget.output : DEFAULT_BUDGET.output;
|
|
614
|
-
|
|
645
|
+
let response;
|
|
646
|
+
try {
|
|
647
|
+
response = await dispatchAgent({ model, prompt, maxTokens });
|
|
648
|
+
} catch (err) {
|
|
649
|
+
await recordThrownAbort(repoRoot, 'subagent-crash', t0);
|
|
650
|
+
throw err;
|
|
651
|
+
}
|
|
615
652
|
|
|
616
653
|
const text = typeof response?.text === 'string' ? response.text : '';
|
|
617
654
|
const { diff } = parseResponse(text);
|