session-orchestrator 3.16.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 +29 -0
- package/.claude-plugin/plugin.json +18 -0
- package/.codex-plugin/agents/explorer.toml +14 -0
- package/.codex-plugin/agents/session-reviewer.toml +23 -0
- package/.codex-plugin/agents/wave-worker.toml +15 -0
- package/.codex-plugin/config.toml +20 -0
- package/.codex-plugin/plugin.json +37 -0
- package/.cursor/rules/000-session-orchestrator.mdc +73 -0
- package/.cursor/rules/010-session-workflow.mdc +170 -0
- package/.cursor/rules/020-quality-gates.mdc +128 -0
- package/.cursor/rules/030-wave-execution.mdc +216 -0
- package/.cursor/rules/040-discovery.mdc +242 -0
- package/.cursor/rules/050-plan.mdc +235 -0
- package/.cursor/rules/060-evolve.mdc +232 -0
- package/.cursor/rules/070-gitlab-ops.mdc +246 -0
- package/.cursor/rules/080-ecosystem-health.mdc +145 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +1544 -0
- package/LICENSE +21 -0
- package/NOTICE +64 -0
- package/README.md +242 -0
- package/SECURITY.md +90 -0
- package/agents/AGENTS.md +136 -0
- package/agents/analyst.md +99 -0
- package/agents/architect-reviewer.md +93 -0
- package/agents/code-implementer.md +106 -0
- package/agents/db-specialist.md +104 -0
- package/agents/dialectic-deriver.md +139 -0
- package/agents/docs-writer.md +113 -0
- package/agents/eval-judge.md +146 -0
- package/agents/memory-proposal-collector.md +297 -0
- package/agents/qa-strategist.md +102 -0
- package/agents/schemas/analyst.schema.json +46 -0
- package/agents/schemas/architect-reviewer.schema.json +50 -0
- package/agents/schemas/code-implementer.schema.json +61 -0
- package/agents/schemas/db-specialist.schema.json +80 -0
- package/agents/schemas/docs-writer.schema.json +56 -0
- package/agents/schemas/persona-panel-sidecar.schema.json +245 -0
- package/agents/schemas/qa-strategist.schema.json +46 -0
- package/agents/schemas/security-reviewer.schema.json +86 -0
- package/agents/schemas/session-reviewer.schema.json +69 -0
- package/agents/schemas/test-writer.schema.json +69 -0
- package/agents/schemas/ui-developer.schema.json +90 -0
- package/agents/schemas/ux-evaluator.schema.json +51 -0
- package/agents/security-reviewer.md +236 -0
- package/agents/session-reviewer.md +201 -0
- package/agents/skill-applied-judge.md +122 -0
- package/agents/test-writer.md +123 -0
- package/agents/ui-developer.md +109 -0
- package/agents/ux-evaluator.md +161 -0
- package/assets/icon.svg +11 -0
- package/assets/og-card.png +0 -0
- package/assets/og-card.svg +47 -0
- package/commands/autopilot-multi.md +74 -0
- package/commands/autopilot.md +80 -0
- package/commands/bootstrap.md +56 -0
- package/commands/brainstorm.md +48 -0
- package/commands/close.md +24 -0
- package/commands/debug.md +36 -0
- package/commands/discovery.md +32 -0
- package/commands/dispatcher.md +59 -0
- package/commands/eval.md +28 -0
- package/commands/evolve.md +10 -0
- package/commands/go.md +41 -0
- package/commands/grill.md +45 -0
- package/commands/harness-audit.md +26 -0
- package/commands/memory-cleanup.md +25 -0
- package/commands/persona-panel.md +121 -0
- package/commands/plan.md +15 -0
- package/commands/portfolio.md +97 -0
- package/commands/reconcile.md +23 -0
- package/commands/repo-audit.md +24 -0
- package/commands/session.md +30 -0
- package/commands/spinout.md +15 -0
- package/commands/sunset-review.md +27 -0
- package/commands/templates-ack.md +96 -0
- package/commands/test.md +97 -0
- package/docs/README.md +105 -0
- package/docs/USER-GUIDE.md +1403 -0
- package/docs/ci-setup.md +81 -0
- package/docs/codex-setup.md +142 -0
- package/docs/components.md +74 -0
- package/docs/cursor-setup.md +104 -0
- package/docs/events-schema.md +81 -0
- package/docs/migration-v3.md +148 -0
- package/docs/owner-config-schema.md +154 -0
- package/docs/persona-panel.md +433 -0
- package/docs/pi-setup.md +115 -0
- package/docs/plugin-architecture-v3.md +296 -0
- package/docs/pm-skills-marketplace.md +114 -0
- package/docs/policy-cache-validation-2026-04-28.md +118 -0
- package/docs/rule-authoring.md +316 -0
- package/docs/session-config-reference.md +1439 -0
- package/docs/session-config-template.md +961 -0
- package/docs/vault-docs-architecture.md +297 -0
- package/hooks/_lib/lock-bootstrap.mjs +272 -0
- package/hooks/_lib/lock-reconcile.mjs +93 -0
- package/hooks/_lib/profile-gate.mjs +95 -0
- package/hooks/_lib/transcript-history.mjs +211 -0
- package/hooks/agent-teams-h3-test.sh +362 -0
- package/hooks/config-protection.mjs +0 -0
- package/hooks/cwd-change-restore.mjs +131 -0
- package/hooks/enforce-commands.mjs +179 -0
- package/hooks/enforce-scope.mjs +273 -0
- package/hooks/hooks-codex.json +60 -0
- package/hooks/hooks-cursor.json +15 -0
- package/hooks/hooks-pi.json +115 -0
- package/hooks/hooks.json +215 -0
- package/hooks/loop-guard.mjs +260 -0
- package/hooks/on-session-end.mjs +217 -0
- package/hooks/on-session-start.mjs +660 -0
- package/hooks/on-stop.mjs +294 -0
- package/hooks/operator-steer.mjs +64 -0
- package/hooks/post-edit-validate.mjs +225 -0
- package/hooks/post-subagent-discovery-validator.mjs +398 -0
- package/hooks/post-tool-batch-wave-signal.mjs +328 -0
- package/hooks/post-tool-failure-corrective-context.mjs +248 -0
- package/hooks/post-tooluse-frontend-slop.mjs +184 -0
- package/hooks/pre-bash-destructive-guard.mjs +515 -0
- package/hooks/pre-bash-memory-propose-audit.mjs +206 -0
- package/hooks/pre-bash-staging-fence.mjs +223 -0
- package/hooks/pre-bash-templates-first.mjs +404 -0
- package/hooks/run-node.sh +72 -0
- package/hooks/skill-invocation-telemetry.mjs +99 -0
- package/hooks/subagent-telemetry.mjs +249 -0
- package/hooks/wave-scope-commit-guard.mjs +191 -0
- package/monitors/monitors.json +14 -0
- package/output-styles/finding-report.md +48 -0
- package/output-styles/session-report.md +53 -0
- package/output-styles/wave-summary.md +38 -0
- package/package.json +94 -0
- package/pi/extensions/session-orchestrator.ts +25 -0
- package/pi/prompts/autopilot-multi.md +12 -0
- package/pi/prompts/autopilot.md +12 -0
- package/pi/prompts/bootstrap.md +12 -0
- package/pi/prompts/brainstorm.md +12 -0
- package/pi/prompts/close.md +11 -0
- package/pi/prompts/debug.md +12 -0
- package/pi/prompts/discovery.md +12 -0
- package/pi/prompts/dispatcher.md +12 -0
- package/pi/prompts/eval.md +12 -0
- package/pi/prompts/evolve.md +12 -0
- package/pi/prompts/go.md +12 -0
- package/pi/prompts/grill.md +12 -0
- package/pi/prompts/harness-audit.md +12 -0
- package/pi/prompts/memory-cleanup.md +12 -0
- package/pi/prompts/persona-panel.md +12 -0
- package/pi/prompts/plan.md +12 -0
- package/pi/prompts/portfolio.md +12 -0
- package/pi/prompts/reconcile.md +12 -0
- package/pi/prompts/repo-audit.md +12 -0
- package/pi/prompts/session.md +12 -0
- package/pi/prompts/spinout.md +12 -0
- package/pi/prompts/sunset-review.md +12 -0
- package/pi/prompts/templates-ack.md +12 -0
- package/pi/prompts/test.md +12 -0
- package/rules/_index.md +51 -0
- package/rules/always-on/commit-discipline.md +26 -0
- package/rules/always-on/npm-quality-gates.md +26 -0
- package/rules/always-on/parallel-sessions.md +43 -0
- package/rules/opt-in-domain/prompt-caching.md +270 -0
- package/rules/opt-in-stack/backend-data.md +188 -0
- package/rules/opt-in-stack/backend.md +390 -0
- package/rules/opt-in-stack/frontend.md +98 -0
- package/rules/opt-in-stack/security-web.md +194 -0
- package/rules/opt-in-stack/swift.md +65 -0
- package/scripts/archive-closed-prds.mjs +416 -0
- package/scripts/autopilot-multi.mjs +802 -0
- package/scripts/autopilot.mjs +383 -0
- package/scripts/backfill-abandoned-sessions.mjs +265 -0
- package/scripts/backfill-learnings-expires.mjs +196 -0
- package/scripts/backfill-learnings.mjs +203 -0
- package/scripts/backfill-sessions.mjs +282 -0
- package/scripts/check-doc-consistency.sh +279 -0
- package/scripts/check-package-manager.mjs +445 -0
- package/scripts/ci/assert-vitest-green.mjs +267 -0
- package/scripts/codex-install.mjs +435 -0
- package/scripts/compute-grounding-injection.sh +186 -0
- package/scripts/cursor-install.mjs +113 -0
- package/scripts/dialectic-deriver.mjs +573 -0
- package/scripts/emit-event.mjs +160 -0
- package/scripts/emit-session.mjs +212 -0
- package/scripts/eval-session.mjs +262 -0
- package/scripts/export-hw-learnings.mjs +437 -0
- package/scripts/gc-stale-worktrees.mjs +666 -0
- package/scripts/generate-pi-prompts.mjs +127 -0
- package/scripts/harness-audit.mjs +287 -0
- package/scripts/lib/agent-frontmatter.mjs +266 -0
- package/scripts/lib/agent-output-schema.mjs +166 -0
- package/scripts/lib/agent-status.mjs +303 -0
- package/scripts/lib/ajv-loader.mjs +34 -0
- package/scripts/lib/auto-dialectic.mjs +382 -0
- package/scripts/lib/auto-dream.mjs +471 -0
- package/scripts/lib/autonomy/suitability.mjs +212 -0
- package/scripts/lib/autopilot/dep-graph.mjs +417 -0
- package/scripts/lib/autopilot/durable-telemetry.mjs +121 -0
- package/scripts/lib/autopilot/flags.mjs +104 -0
- package/scripts/lib/autopilot/kill-switches.mjs +174 -0
- package/scripts/lib/autopilot/loop.mjs +320 -0
- package/scripts/lib/autopilot/mr-draft.mjs +520 -0
- package/scripts/lib/autopilot/multi-killswitch.mjs +184 -0
- package/scripts/lib/autopilot/recent-runs.mjs +106 -0
- package/scripts/lib/autopilot/stall-sampler.mjs +97 -0
- package/scripts/lib/autopilot/telemetry.mjs +224 -0
- package/scripts/lib/autopilot/worktree-pipeline.mjs +605 -0
- package/scripts/lib/autopilot-telemetry.mjs +11 -0
- package/scripts/lib/autopilot.mjs +39 -0
- package/scripts/lib/backlog-scan.mjs +179 -0
- package/scripts/lib/bootstrap-lock-freshness.mjs +260 -0
- package/scripts/lib/bootstrap-lock-refresh.mjs +186 -0
- package/scripts/lib/build-live-signals.mjs +150 -0
- package/scripts/lib/ci-status-banner.mjs +425 -0
- package/scripts/lib/claude-md-budget-lint.mjs +246 -0
- package/scripts/lib/cli-flags.mjs +158 -0
- package/scripts/lib/codex/plugin-contract.mjs +610 -0
- package/scripts/lib/cold-start-detector.mjs +240 -0
- package/scripts/lib/command-blocker.mjs +458 -0
- package/scripts/lib/common.mjs +333 -0
- package/scripts/lib/config/auto-dream.mjs +77 -0
- package/scripts/lib/config/block-header.mjs +94 -0
- package/scripts/lib/config/broken-window.mjs +114 -0
- package/scripts/lib/config/coercers.mjs +248 -0
- package/scripts/lib/config/cold-start.mjs +92 -0
- package/scripts/lib/config/config-protection.mjs +120 -0
- package/scripts/lib/config/cross-repo.mjs +104 -0
- package/scripts/lib/config/custom-phases.mjs +213 -0
- package/scripts/lib/config/dialectic.mjs +92 -0
- package/scripts/lib/config/discovery-validator.mjs +75 -0
- package/scripts/lib/config/dispatcher-autonomy-capture.mjs +240 -0
- package/scripts/lib/config/dispatcher-autonomy.mjs +152 -0
- package/scripts/lib/config/docs-orchestrator.mjs +90 -0
- package/scripts/lib/config/docs-staleness.mjs +96 -0
- package/scripts/lib/config/drift-check.mjs +155 -0
- package/scripts/lib/config/eval.mjs +130 -0
- package/scripts/lib/config/events-rotation.mjs +74 -0
- package/scripts/lib/config/evolve.mjs +308 -0
- package/scripts/lib/config/frontend-slop-hook.mjs +104 -0
- package/scripts/lib/config/gitlab-portfolio.mjs +150 -0
- package/scripts/lib/config/handover-gate.mjs +106 -0
- package/scripts/lib/config/host-paths.mjs +76 -0
- package/scripts/lib/config/io.mjs +54 -0
- package/scripts/lib/config/loop-guard.mjs +117 -0
- package/scripts/lib/config/memory.mjs +150 -0
- package/scripts/lib/config/persona-gate-wave.mjs +258 -0
- package/scripts/lib/config/reconcile.mjs +205 -0
- package/scripts/lib/config/section-extractor.mjs +100 -0
- package/scripts/lib/config/skill-evolution.mjs +112 -0
- package/scripts/lib/config/slopcheck.mjs +99 -0
- package/scripts/lib/config/state-md-lock.mjs +83 -0
- package/scripts/lib/config/templates-first.mjs +94 -0
- package/scripts/lib/config/test.mjs +113 -0
- package/scripts/lib/config/vault-integration.mjs +201 -0
- package/scripts/lib/config/vault-mirror-quality.mjs +99 -0
- package/scripts/lib/config/vault-staleness.mjs +84 -0
- package/scripts/lib/config/vault-sync.mjs +96 -0
- package/scripts/lib/config/verification-auto-fix.mjs +84 -0
- package/scripts/lib/config/wave-reviewers.mjs +133 -0
- package/scripts/lib/config-schema.mjs +345 -0
- package/scripts/lib/config.mjs +474 -0
- package/scripts/lib/convergence-monitor.mjs +389 -0
- package/scripts/lib/coordinator-snapshot.mjs +371 -0
- package/scripts/lib/crypto-digest-utils.mjs +91 -0
- package/scripts/lib/discovery/helpers.mjs +127 -0
- package/scripts/lib/discovery/triage-state.mjs +279 -0
- package/scripts/lib/dispatcher/cli.mjs +257 -0
- package/scripts/lib/dispatcher/enumerate.mjs +243 -0
- package/scripts/lib/dispatcher/rank.mjs +363 -0
- package/scripts/lib/ecosystem-health.mjs +224 -0
- package/scripts/lib/ecosystem-wizard/ci-detector.mjs +18 -0
- package/scripts/lib/ecosystem-wizard/config-parser.mjs +54 -0
- package/scripts/lib/ecosystem-wizard/config-writer.mjs +287 -0
- package/scripts/lib/ecosystem-wizard/package-manager-detector.mjs +42 -0
- package/scripts/lib/ecosystem-wizard/wizard-prompt.mjs +246 -0
- package/scripts/lib/ecosystem-wizard.mjs +48 -0
- package/scripts/lib/env-check.mjs +89 -0
- package/scripts/lib/eval/engine.mjs +605 -0
- package/scripts/lib/eval/judge.mjs +433 -0
- package/scripts/lib/eval/report.mjs +367 -0
- package/scripts/lib/eval/schema.mjs +618 -0
- package/scripts/lib/eval/session-resolve.mjs +137 -0
- package/scripts/lib/eval/sink.mjs +77 -0
- package/scripts/lib/events-rotation.mjs +86 -0
- package/scripts/lib/events-schema.mjs +81 -0
- package/scripts/lib/events.mjs +80 -0
- package/scripts/lib/evolve/autonomy-verdict.mjs +461 -0
- package/scripts/lib/evolve/autopilot-effectiveness.mjs +293 -0
- package/scripts/lib/exclusivity-matrix.mjs +68 -0
- package/scripts/lib/fetch-baseline.mjs +311 -0
- package/scripts/lib/file-lock.mjs +512 -0
- package/scripts/lib/frontend-detect/detect.mjs +138 -0
- package/scripts/lib/frontend-detect/rules.mjs +295 -0
- package/scripts/lib/frontmatter-guard.mjs +241 -0
- package/scripts/lib/gates/echo-stub-detect.mjs +39 -0
- package/scripts/lib/gates/gate-baseline.mjs +42 -0
- package/scripts/lib/gates/gate-full.mjs +85 -0
- package/scripts/lib/gates/gate-helpers.mjs +231 -0
- package/scripts/lib/gates/gate-incremental.mjs +76 -0
- package/scripts/lib/gates/gate-per-file.mjs +55 -0
- package/scripts/lib/gitlab-ops/stale-mr-sweep.mjs +447 -0
- package/scripts/lib/gitlab-portfolio/aggregator.mjs +383 -0
- package/scripts/lib/gitlab-portfolio/cli.mjs +428 -0
- package/scripts/lib/gitlab-portfolio/markdown-writer.mjs +289 -0
- package/scripts/lib/gitlab-portfolio/vcs-detect.mjs +182 -0
- package/scripts/lib/handover-gate.mjs +222 -0
- package/scripts/lib/hardening.mjs +43 -0
- package/scripts/lib/hardware-pattern-detector.mjs +238 -0
- package/scripts/lib/harness-audit/categories/category1.mjs +123 -0
- package/scripts/lib/harness-audit/categories/category2.mjs +145 -0
- package/scripts/lib/harness-audit/categories/category3.mjs +143 -0
- package/scripts/lib/harness-audit/categories/category4.mjs +202 -0
- package/scripts/lib/harness-audit/categories/category5.mjs +152 -0
- package/scripts/lib/harness-audit/categories/category6.mjs +211 -0
- package/scripts/lib/harness-audit/categories/category7.mjs +125 -0
- package/scripts/lib/harness-audit/categories/category8.mjs +328 -0
- package/scripts/lib/harness-audit/categories/category9.mjs +294 -0
- package/scripts/lib/harness-audit/categories/helpers.mjs +165 -0
- package/scripts/lib/harness-audit/categories.mjs +19 -0
- package/scripts/lib/historical-guard.mjs +15 -0
- package/scripts/lib/host-identity.mjs +262 -0
- package/scripts/lib/instruction-budget-guard.mjs +332 -0
- package/scripts/lib/io.mjs +304 -0
- package/scripts/lib/issue-close-strip-labels.mjs +161 -0
- package/scripts/lib/language-mappers/README.md +57 -0
- package/scripts/lib/language-mappers/index.mjs +165 -0
- package/scripts/lib/language-mappers/markdown.mjs +149 -0
- package/scripts/lib/language-mappers/python.mjs +249 -0
- package/scripts/lib/language-mappers/swift.mjs +201 -0
- package/scripts/lib/language-mappers/typescript.mjs +433 -0
- package/scripts/lib/learnings/expiry-sweep.mjs +164 -0
- package/scripts/lib/learnings/filters.mjs +43 -0
- package/scripts/lib/learnings/io.mjs +255 -0
- package/scripts/lib/learnings/schema.mjs +518 -0
- package/scripts/lib/learnings/surface.mjs +207 -0
- package/scripts/lib/learnings.mjs +42 -0
- package/scripts/lib/lock-reaper.mjs +648 -0
- package/scripts/lib/locks/index.mjs +31 -0
- package/scripts/lib/locks/lock-body.mjs +62 -0
- package/scripts/lib/locks/staging-fence-lock.mjs +267 -0
- package/scripts/lib/locks/state-md-lock.mjs +351 -0
- package/scripts/lib/loop-readiness-banner.mjs +144 -0
- package/scripts/lib/memory-banner.mjs +478 -0
- package/scripts/lib/memory-cleanup/worktree-sweep.mjs +108 -0
- package/scripts/lib/memory-cleanup-stamp.mjs +56 -0
- package/scripts/lib/memory-paths.mjs +31 -0
- package/scripts/lib/memory-proposals/collector.mjs +334 -0
- package/scripts/lib/memory-proposals/schema.mjs +289 -0
- package/scripts/lib/memory-proposals/sink.mjs +507 -0
- package/scripts/lib/memory-proposals/store.mjs +441 -0
- package/scripts/lib/mission-status-schema.mjs +114 -0
- package/scripts/lib/mode-selector/alternatives.mjs +64 -0
- package/scripts/lib/mode-selector/constants.mjs +29 -0
- package/scripts/lib/mode-selector/context-pressure.mjs +157 -0
- package/scripts/lib/mode-selector/rationale.mjs +55 -0
- package/scripts/lib/mode-selector/scoring.mjs +221 -0
- package/scripts/lib/mode-selector-accuracy.mjs +121 -0
- package/scripts/lib/mode-selector.mjs +160 -0
- package/scripts/lib/multi-provider-build/providers.mjs +64 -0
- package/scripts/lib/multi-provider-build/templating.mjs +130 -0
- package/scripts/lib/named-baseline-resolver.mjs +233 -0
- package/scripts/lib/named-vault-resolver.mjs +433 -0
- package/scripts/lib/owner-config/coerce.mjs +29 -0
- package/scripts/lib/owner-config/constants.mjs +21 -0
- package/scripts/lib/owner-config/defaults.mjs +50 -0
- package/scripts/lib/owner-config/error.mjs +19 -0
- package/scripts/lib/owner-config/index.mjs +13 -0
- package/scripts/lib/owner-config/merge.mjs +52 -0
- package/scripts/lib/owner-config/validate.mjs +259 -0
- package/scripts/lib/owner-config-banner.mjs +126 -0
- package/scripts/lib/owner-config-loader.mjs +159 -0
- package/scripts/lib/owner-config.example.yaml +72 -0
- package/scripts/lib/owner-config.mjs +28 -0
- package/scripts/lib/owner-interview.mjs +243 -0
- package/scripts/lib/owner-yaml.mjs +571 -0
- package/scripts/lib/package-manager.mjs +160 -0
- package/scripts/lib/path-utils.mjs +217 -0
- package/scripts/lib/peer-cards/merger.mjs +310 -0
- package/scripts/lib/peer-cards/reader.mjs +125 -0
- package/scripts/lib/peer-cards/schema.mjs +230 -0
- package/scripts/lib/peer-cards/staleness-banner.mjs +86 -0
- package/scripts/lib/peer-cards/writer.mjs +138 -0
- package/scripts/lib/peer-discovery.mjs +200 -0
- package/scripts/lib/persona-panel/catalog-loader.mjs +577 -0
- package/scripts/lib/persona-panel/consolidator.mjs +370 -0
- package/scripts/lib/persona-panel/persona-runner.mjs +375 -0
- package/scripts/lib/persona-panel/threshold.mjs +130 -0
- package/scripts/lib/pi-hook-bridge.mjs +328 -0
- package/scripts/lib/platform.mjs +266 -0
- package/scripts/lib/playwright-driver/runner.mjs +297 -0
- package/scripts/lib/plugin-root.mjs +210 -0
- package/scripts/lib/pre-dispatch-check.mjs +126 -0
- package/scripts/lib/product-repo-detect.mjs +121 -0
- package/scripts/lib/profiles/registry.mjs +176 -0
- package/scripts/lib/profiles/schema.mjs +209 -0
- package/scripts/lib/qg-command-drift-banner.mjs +88 -0
- package/scripts/lib/quality-gate/diagnostics.mjs +92 -0
- package/scripts/lib/quality-gate.mjs +536 -0
- package/scripts/lib/quality-gates-cache.mjs +228 -0
- package/scripts/lib/quality-gates-policy.mjs +95 -0
- package/scripts/lib/recommendations-v0.mjs +156 -0
- package/scripts/lib/reconcile/eligibility.mjs +203 -0
- package/scripts/lib/reconcile/emitter.mjs +244 -0
- package/scripts/lib/reconcile/engine.mjs +412 -0
- package/scripts/lib/reconcile/idempotency.mjs +239 -0
- package/scripts/lib/reconcile/renderer.mjs +211 -0
- package/scripts/lib/reconcile/writer.mjs +293 -0
- package/scripts/lib/reconcile-nudge-banner.mjs +284 -0
- package/scripts/lib/resource-probe/evaluate.mjs +190 -0
- package/scripts/lib/resource-probe/parsers.mjs +181 -0
- package/scripts/lib/resource-probe/probe-platform.mjs +300 -0
- package/scripts/lib/resource-probe.mjs +95 -0
- package/scripts/lib/rule-loader.mjs +552 -0
- package/scripts/lib/rules-sync.mjs +439 -0
- package/scripts/lib/scope-gate.mjs +496 -0
- package/scripts/lib/session-close-backfill.mjs +539 -0
- package/scripts/lib/session-discovery.mjs +256 -0
- package/scripts/lib/session-end/phase-skip.mjs +357 -0
- package/scripts/lib/session-end/worktree-cleanup.mjs +112 -0
- package/scripts/lib/session-id.mjs +362 -0
- package/scripts/lib/session-lock.mjs +703 -0
- package/scripts/lib/session-registry.mjs +355 -0
- package/scripts/lib/session-schema/aliases.mjs +71 -0
- package/scripts/lib/session-schema/constants.mjs +115 -0
- package/scripts/lib/session-schema/normalizer.mjs +66 -0
- package/scripts/lib/session-schema/timestamps.mjs +64 -0
- package/scripts/lib/session-schema/validator.mjs +453 -0
- package/scripts/lib/session-schema.mjs +71 -0
- package/scripts/lib/session-token-rollup.mjs +137 -0
- package/scripts/lib/sessions-staleness-banner.mjs +247 -0
- package/scripts/lib/skill-evolution/blast-radius-classifier.mjs +114 -0
- package/scripts/lib/skill-evolution/candidate-intake.mjs +270 -0
- package/scripts/lib/skill-evolution/config-validation-gate.mjs +279 -0
- package/scripts/lib/skill-evolution/engine.mjs +719 -0
- package/scripts/lib/skill-evolution/idempotency.mjs +279 -0
- package/scripts/lib/skill-evolution/mr-opener.mjs +507 -0
- package/scripts/lib/skill-health/join.mjs +181 -0
- package/scripts/lib/skill-health/score.mjs +123 -0
- package/scripts/lib/skill-invocations-schema.mjs +214 -0
- package/scripts/lib/skill-judge.mjs +348 -0
- package/scripts/lib/skill-judgments-schema.mjs +264 -0
- package/scripts/lib/slopcheck.mjs +501 -0
- package/scripts/lib/soul-resolve.mjs +118 -0
- package/scripts/lib/spiral-carryover.mjs +495 -0
- package/scripts/lib/state-md/body-sections.mjs +851 -0
- package/scripts/lib/state-md/frontmatter-mutators.mjs +453 -0
- package/scripts/lib/state-md/mission-status.mjs +247 -0
- package/scripts/lib/state-md/recommendations.mjs +57 -0
- package/scripts/lib/state-md/yaml-parser.mjs +234 -0
- package/scripts/lib/state-md-peer-guard.mjs +232 -0
- package/scripts/lib/state-md.mjs +53 -0
- package/scripts/lib/subagents-schema.mjs +309 -0
- package/scripts/lib/sunset/walker.mjs +1192 -0
- package/scripts/lib/test-runner/artifact-paths.mjs +94 -0
- package/scripts/lib/test-runner/fingerprint.mjs +33 -0
- package/scripts/lib/test-runner/issue-reconcile.mjs +770 -0
- package/scripts/lib/tmux-layout/layouts.mjs +224 -0
- package/scripts/lib/tmux-layout/telemetry-stats.mjs +100 -0
- package/scripts/lib/tmux-layout/telemetry.mjs +88 -0
- package/scripts/lib/tmux-layout/tmux-shell.mjs +82 -0
- package/scripts/lib/tmux-layout/vcs-detector.mjs +88 -0
- package/scripts/lib/validate/check-agents.mjs +457 -0
- package/scripts/lib/validate/check-codex-plugin.mjs +37 -0
- package/scripts/lib/validate/check-commands.mjs +148 -0
- package/scripts/lib/validate/check-component-paths.mjs +112 -0
- package/scripts/lib/validate/check-dead-bridge.mjs +180 -0
- package/scripts/lib/validate/check-hooks-symmetry.mjs +258 -0
- package/scripts/lib/validate/check-json-files.mjs +116 -0
- package/scripts/lib/validate/check-owner-leakage.mjs +1011 -0
- package/scripts/lib/validate/check-path-utils-canary.mjs +175 -0
- package/scripts/lib/validate/check-peekaboo-driver-canary.mjs +201 -0
- package/scripts/lib/validate/check-pi-package.mjs +110 -0
- package/scripts/lib/validate/check-pi-prompts.mjs +43 -0
- package/scripts/lib/validate/check-playwright-mcp-canary.mjs +154 -0
- package/scripts/lib/validate/check-plugin-json.mjs +96 -0
- package/scripts/lib/validate/check-plugin-monitors.mjs +206 -0
- package/scripts/lib/validate/check-plugin-schema.mjs +137 -0
- package/scripts/lib/validate/check-rules.mjs +143 -0
- package/scripts/lib/validate/check-session-plan-routing.mjs +154 -0
- package/scripts/lib/validate/check-test-fixture-shapes.mjs +280 -0
- package/scripts/lib/validate/check-unicode-safety.mjs +533 -0
- package/scripts/lib/validate/confidential-names.mjs +169 -0
- package/scripts/lib/validate/dead-bridge-corpus.mjs +141 -0
- package/scripts/lib/validate/dead-bridge-detectors.mjs +568 -0
- package/scripts/lib/validate/tier-inference.mjs +100 -0
- package/scripts/lib/validate-vendored-rules.mjs +519 -0
- package/scripts/lib/vault-archive.mjs +404 -0
- package/scripts/lib/vault-backfill/glab.mjs +164 -0
- package/scripts/lib/vault-backfill/manifest.mjs +75 -0
- package/scripts/lib/vault-backfill/template.mjs +130 -0
- package/scripts/lib/vault-consolidate-fs.mjs +331 -0
- package/scripts/lib/vault-migration-rules.mjs +155 -0
- package/scripts/lib/vault-mirror/auto-commit.mjs +203 -0
- package/scripts/lib/vault-mirror/namespace.mjs +152 -0
- package/scripts/lib/vault-mirror/process.mjs +567 -0
- package/scripts/lib/vault-mirror/pseudonym-map.mjs +164 -0
- package/scripts/lib/vault-mirror/render-learnings.mjs +201 -0
- package/scripts/lib/vault-mirror/render-sessions.mjs +367 -0
- package/scripts/lib/vault-mirror/render.mjs +8 -0
- package/scripts/lib/vault-mirror/utils.mjs +217 -0
- package/scripts/lib/vault-relocation-rules.mjs +555 -0
- package/scripts/lib/vault-repo-backfill.mjs +235 -0
- package/scripts/lib/vault-staleness-banner.mjs +142 -0
- package/scripts/lib/vault-status/board-writer.mjs +769 -0
- package/scripts/lib/vault-status/narrative-mirror.mjs +544 -0
- package/scripts/lib/vault-sync-baseline.mjs +152 -0
- package/scripts/lib/wave-context.mjs +29 -0
- package/scripts/lib/wave-executor/pool.mjs +248 -0
- package/scripts/lib/wave-resource-gate.mjs +204 -0
- package/scripts/lib/wave-sizing.mjs +75 -0
- package/scripts/lib/webhook-url.mjs +105 -0
- package/scripts/lib/workspace.mjs +198 -0
- package/scripts/lib/worktree/constants.mjs +35 -0
- package/scripts/lib/worktree/index.mjs +17 -0
- package/scripts/lib/worktree/lifecycle.mjs +287 -0
- package/scripts/lib/worktree/listing.mjs +118 -0
- package/scripts/lib/worktree/meta.mjs +64 -0
- package/scripts/lib/worktree-freshness.mjs +313 -0
- package/scripts/lib/worktree.mjs +15 -0
- package/scripts/lifecycle-sim-v6.mjs +347 -0
- package/scripts/lock-reaper.mjs +185 -0
- package/scripts/mcp-server.sh +241 -0
- package/scripts/measure-policy-cache-effectiveness.mjs +427 -0
- package/scripts/memory-propose.mjs +464 -0
- package/scripts/migrate-cold-start-seed.mjs +404 -0
- package/scripts/migrate-learnings-jsonl.mjs +189 -0
- package/scripts/migrate-legacy-learnings.sh +61 -0
- package/scripts/migrate-sessions-jsonl.mjs +448 -0
- package/scripts/migrate-subagents-jsonl.mjs +196 -0
- package/scripts/migrate-vault-paths.mjs +796 -0
- package/scripts/parse-config.mjs +149 -0
- package/scripts/pi-install.mjs +117 -0
- package/scripts/print-applicable-rules.mjs +247 -0
- package/scripts/promote-vault-strict.mjs +496 -0
- package/scripts/relocate-vault-corpus.mjs +1178 -0
- package/scripts/run-migrate-v2-cross-repo.mjs +385 -0
- package/scripts/run-quality-gate.mjs +216 -0
- package/scripts/spikes/h3-agent-teams/preflight.sh +53 -0
- package/scripts/spikes/h3-agent-teams/run-h3.sh +112 -0
- package/scripts/spikes/h3-agent-teams/setup.sh +137 -0
- package/scripts/spikes/h3-agent-teams/toggle.sh +38 -0
- package/scripts/sweep-expired-learnings.mjs +135 -0
- package/scripts/sync-vault-schema.mjs +376 -0
- package/scripts/tests/fixtures/fetch-baseline/sample-rule.md +8 -0
- package/scripts/tmux-layout.mjs +245 -0
- package/scripts/token-audit.sh +191 -0
- package/scripts/typecheck.mjs +42 -0
- package/scripts/upload-social-preview.mjs +316 -0
- package/scripts/validate-config.mjs +46 -0
- package/scripts/validate-plugin-manifests.mjs +163 -0
- package/scripts/validate-plugin.mjs +264 -0
- package/scripts/validate-wave-scope.mjs +289 -0
- package/scripts/vault-backfill.mjs +404 -0
- package/scripts/vault-consolidate.mjs +596 -0
- package/scripts/vault-integration-watcher.mjs +394 -0
- package/scripts/vault-mirror.mjs +430 -0
- package/skills/_shared/bootstrap-gate.md +111 -0
- package/skills/_shared/config-reading.md +226 -0
- package/skills/_shared/instruction-file-resolution.md +79 -0
- package/skills/_shared/model-selection.md +64 -0
- package/skills/_shared/monitor-patterns.md +300 -0
- package/skills/_shared/parallel-aware-auq.md +121 -0
- package/skills/_shared/parallel-aware-preamble.md +185 -0
- package/skills/_shared/platform-tools.md +96 -0
- package/skills/_shared/state-ownership.md +221 -0
- package/skills/architecture/DEEPENING.md +37 -0
- package/skills/architecture/INTERFACE-DESIGN.md +44 -0
- package/skills/architecture/LANGUAGE.md +53 -0
- package/skills/architecture/SKILL.md +92 -0
- package/skills/autopilot/SKILL.md +419 -0
- package/skills/bootstrap/SKILL.md +592 -0
- package/skills/bootstrap/STATE.md.template +24 -0
- package/skills/bootstrap/_shared-template.md +243 -0
- package/skills/bootstrap/deep-template.md +659 -0
- package/skills/bootstrap/fast-template.md +251 -0
- package/skills/bootstrap/intensity-heuristic.md +80 -0
- package/skills/bootstrap/public-fallback.md +342 -0
- package/skills/bootstrap/standard-template.md +736 -0
- package/skills/bootstrap/templates/agents/project-code-review.md +18 -0
- package/skills/bootstrap/templates/agents/project-discovery.md +18 -0
- package/skills/bootstrap/templates/agents/project-quality-gate.md +18 -0
- package/skills/brainstorm/SKILL.md +268 -0
- package/skills/brainstorm/soul.md +49 -0
- package/skills/claude-md-drift-check/SKILL.md +186 -0
- package/skills/claude-md-drift-check/checker.mjs +1380 -0
- package/skills/claude-md-drift-check/checker.sh +37 -0
- package/skills/claude-md-drift-check/package.json +16 -0
- package/skills/convergence-monitoring/README.md +39 -0
- package/skills/convergence-monitoring/SIGNALS.md +246 -0
- package/skills/convergence-monitoring/SKILL.md +285 -0
- package/skills/daily/SKILL.md +222 -0
- package/skills/daily/generate.sh +92 -0
- package/skills/daily/templates/daily.md.tpl +36 -0
- package/skills/debug/SKILL.md +188 -0
- package/skills/debug/soul.md +35 -0
- package/skills/discovery/SKILL.md +567 -0
- package/skills/discovery/issue-templates.md +237 -0
- package/skills/discovery/probes/docs-staleness.mjs +195 -0
- package/skills/discovery/probes/frontend-slop.mjs +186 -0
- package/skills/discovery/probes/ssot-code-diff.mjs +310 -0
- package/skills/discovery/probes/supply-chain-slopcheck.mjs +440 -0
- package/skills/discovery/probes/vault-narrative-staleness.mjs +355 -0
- package/skills/discovery/probes/vault-staleness.mjs +272 -0
- package/skills/discovery/probes-arch.md +252 -0
- package/skills/discovery/probes-audit.md +95 -0
- package/skills/discovery/probes-code.md +329 -0
- package/skills/discovery/probes-docs.md +76 -0
- package/skills/discovery/probes-feature.md +150 -0
- package/skills/discovery/probes-infra.md +138 -0
- package/skills/discovery/probes-intro.md +25 -0
- package/skills/discovery/probes-session.md +495 -0
- package/skills/discovery/probes-supply-chain.md +94 -0
- package/skills/discovery/probes-ui.md +147 -0
- package/skills/discovery/probes-vault.md +64 -0
- package/skills/discovery/slop-patterns.md +115 -0
- package/skills/dispatcher/SKILL.md +173 -0
- package/skills/docs-orchestrator/SKILL.md +362 -0
- package/skills/docs-orchestrator/audience-mapping.md +140 -0
- package/skills/domain-model/ADR-FORMAT.md +47 -0
- package/skills/domain-model/CONTEXT-FORMAT.md +77 -0
- package/skills/domain-model/SKILL.md +85 -0
- package/skills/ecosystem-health/SKILL.md +119 -0
- package/skills/ecosystem-health/wizard.md +193 -0
- package/skills/eval/SKILL.md +293 -0
- package/skills/eval/rubric-v1.md +218 -0
- package/skills/evolve/SKILL.md +546 -0
- package/skills/frontmatter-guard/SKILL.md +126 -0
- package/skills/gitlab-ops/SKILL.md +368 -0
- package/skills/gitlab-portfolio/SKILL.md +196 -0
- package/skills/grill/SKILL.md +185 -0
- package/skills/grill/soul.md +55 -0
- package/skills/hook-development/SKILL.md +413 -0
- package/skills/mcp-builder/SKILL.md +260 -0
- package/skills/memory-cleanup/SKILL.md +310 -0
- package/skills/mode-selector/SKILL.md +226 -0
- package/skills/peekaboo-driver/SKILL.md +237 -0
- package/skills/peekaboo-driver/soul.md +32 -0
- package/skills/persona-panel/SKILL.md +365 -0
- package/skills/persona-panel/persona-format.md +205 -0
- package/skills/persona-panel/presets/designer-lens.md +87 -0
- package/skills/persona-panel/presets/engineer-lens.md +88 -0
- package/skills/persona-panel/presets/pm-lens.md +86 -0
- package/skills/plan/SKILL.md +496 -0
- package/skills/plan/mode-feature.md +141 -0
- package/skills/plan/mode-new.md +297 -0
- package/skills/plan/mode-retro.md +271 -0
- package/skills/plan/prd-feature-template.md +132 -0
- package/skills/plan/prd-full-template.md +151 -0
- package/skills/plan/prd-reviewer-prompt.md +103 -0
- package/skills/plan/retro-template.md +75 -0
- package/skills/plan/soul.md +62 -0
- package/skills/playwright-driver/SKILL.md +226 -0
- package/skills/playwright-driver/soul.md +30 -0
- package/skills/quality-gates/SKILL.md +212 -0
- package/skills/reconcile/SKILL.md +324 -0
- package/skills/repo-audit/SKILL.md +272 -0
- package/skills/session-end/SKILL.md +1044 -0
- package/skills/session-end/discovery-scan.md +37 -0
- package/skills/session-end/drift-operations.md +97 -0
- package/skills/session-end/learning-patterns.md +78 -0
- package/skills/session-end/metrics-collection.md +175 -0
- package/skills/session-end/phase-3-2-docs-verification.md +148 -0
- package/skills/session-end/phase-3-6-tail.md +344 -0
- package/skills/session-end/phase-3-7a-recommendations.md +86 -0
- package/skills/session-end/plan-verification.md +288 -0
- package/skills/session-end/session-metrics-write.md +223 -0
- package/skills/session-end/vault-operations.md +50 -0
- package/skills/session-end/verification-checklist.md +20 -0
- package/skills/session-plan/SKILL.md +554 -0
- package/skills/session-plan/wave-template.md +37 -0
- package/skills/session-start/SKILL.md +1043 -0
- package/skills/session-start/phase-2-5-docs-planning.md +119 -0
- package/skills/session-start/phase-4-5-resource-health.md +49 -0
- package/skills/session-start/phase-7-1-premise-check.md +47 -0
- package/skills/session-start/phase-7-5-mode-selector.md +237 -0
- package/skills/session-start/phase-8-5-express-path.md +61 -0
- package/skills/session-start/presentation-format.md +81 -0
- package/skills/session-start/soul.md +57 -0
- package/skills/skill-creator/SKILL.md +168 -0
- package/skills/spinout/SKILL.md +76 -0
- package/skills/sunset-review/SKILL.md +96 -0
- package/skills/test-runner/SKILL.md +362 -0
- package/skills/test-runner/rubric-v1.md +388 -0
- package/skills/test-runner/soul.md +46 -0
- package/skills/tmux-layout/SKILL.md +104 -0
- package/skills/ubiquitous-language/SKILL.md +97 -0
- package/skills/using-orchestrator/SKILL.md +144 -0
- package/skills/vault-mirror/SKILL.md +234 -0
- package/skills/vault-sync/SKILL.md +319 -0
- package/skills/vault-sync/package-lock.json +40 -0
- package/skills/vault-sync/package.json +11 -0
- package/skills/vault-sync/tests/fixtures/archive-test-vault/90-archive/bad-archived.md +8 -0
- 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 +8 -0
- 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 +8 -0
- package/skills/vault-sync/tests/fixtures/broken-frontmatter-vault/good-note.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/.obsidian/config.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/01-projects/foo/projects-baseline.md +10 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/03-daily/daily-2026-04-13.md +8 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/clean-vault/hello-world.md +11 -0
- 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 +9 -0
- package/skills/vault-sync/tests/fixtures/dangling-link-vault/real-target.md +8 -0
- 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 +7 -0
- package/skills/vault-sync/tests/fixtures/nested-tag-vault/03-daily/daily-2026-04-13.md +9 -0
- 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 +11 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/README.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_MOC.md +3 -0
- package/skills/vault-sync/tests/fixtures/no-frontmatter-vault/_meta/.gitkeep +0 -0
- package/skills/vault-sync/tests/fixtures/with-moc-vault/_MOC.md +11 -0
- 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 +11 -0
- package/skills/vault-sync/tests/schema-drift.test.mjs +133 -0
- package/skills/vault-sync/validator.mjs +658 -0
- package/skills/vault-sync/validator.sh +55 -0
- package/skills/wave-executor/SKILL.md +496 -0
- package/skills/wave-executor/circuit-breaker.md +169 -0
- package/skills/wave-executor/wave-loop.md +1043 -0
- package/skills/write-executable-plan/SKILL.md +237 -0
- package/skills/write-executable-plan/plan-template.md +154 -0
- package/templates/_minimal/CLAUDE.md.tmpl +41 -0
- package/templates/_minimal/README.md.tmpl +15 -0
- package/templates/_minimal/gitignore.tmpl +47 -0
- package/templates/_shared/harte-regeln.md +16 -0
- package/templates/_shared/loop.md +90 -0
- package/templates/_shared/rules/parallel-sessions.md +77 -0
- package/templates/nextjs-minimal/README.md +30 -0
- package/templates/nextjs-minimal/app/layout.tsx +18 -0
- package/templates/nextjs-minimal/app/page.tsx +7 -0
- package/templates/nextjs-minimal/eslint.config.mjs +16 -0
- package/templates/nextjs-minimal/next.config.mjs +4 -0
- package/templates/nextjs-minimal/package.json +27 -0
- package/templates/nextjs-minimal/tsconfig.json +23 -0
- package/templates/node-minimal/README.md +33 -0
- package/templates/node-minimal/eslint.config.mjs +10 -0
- package/templates/node-minimal/package.json +21 -0
- package/templates/node-minimal/src/index.ts +1 -0
- package/templates/node-minimal/tests/sanity.test.ts +5 -0
- package/templates/node-minimal/tsconfig.json +17 -0
- package/templates/personas/README.md +150 -0
- package/templates/personas/accounting-compliance.v1.md +120 -0
- package/templates/personas/accounting-tax-advisor.v1.md +116 -0
- package/templates/personas/buyer-p1-cto.v1.md +125 -0
- package/templates/personas/buyer-p2-kanzlei.v1.md +134 -0
- package/templates/personas/buyer-p3-build.v1.md +130 -0
- package/templates/personas/buyer-p4-tech-veto.v1.md +130 -0
- package/templates/personas/buyer-p5-solo.v1.md +132 -0
- package/templates/personas/buyer-p6-ld.v1.md +130 -0
- package/templates/personas/klima-ai-expert.v1.md +114 -0
- package/templates/personas/klima-physicist.v1.md +117 -0
- package/templates/python-uv/README.md +28 -0
- package/templates/python-uv/pyproject.toml +32 -0
- package/templates/python-uv/src/__PROJECT_NAME__/__init__.py +0 -0
- package/templates/python-uv/src/__PROJECT_NAME__/main.py +6 -0
- package/templates/python-uv/tests/test_sanity.py +2 -0
- package/templates/static-html/README.md +19 -0
- package/templates/static-html/index.html +15 -0
- package/templates/static-html/script.js +1 -0
- package/templates/static-html/styles.css +26 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-discovery.mjs — discover active sessions across all worktrees.
|
|
3
|
+
*
|
|
4
|
+
* Purpose: enumerate all active Claude sessions in the repo's worktree set
|
|
5
|
+
* (P1.1 of the Parallel-Aware Sessions Epic #568, Issue #569).
|
|
6
|
+
*
|
|
7
|
+
* Liveness rule (Epic #583, W2-I3 — REPLACES PID-liveness):
|
|
8
|
+
* - A lock is "live" when (now - last_heartbeat) < ttl_hours.
|
|
9
|
+
* - PID-liveness is no longer the discovery-time filter; the writer-process
|
|
10
|
+
* PID is the *hook* PID, not the session PID, so PID-liveness incorrectly
|
|
11
|
+
* filtered out locks whose semantic owner (Claude harness) was still
|
|
12
|
+
* alive (D2 defect from Epic #583 audit).
|
|
13
|
+
* - `isPidAliveOnHost` is preserved in session-lock.mjs as a forensic helper
|
|
14
|
+
* but is not called from the discovery decision tree.
|
|
15
|
+
* - #799 evaluated (2026-07-17): dead-PID stale-marking for source=discovered
|
|
16
|
+
* registry entries is an explicit NO-GO — the recorded PID is the ephemeral
|
|
17
|
+
* hook-subprocess PID (see above), so a same-host dead-PID filter would
|
|
18
|
+
* misclassify nearly every entry as stale seconds after write; even a
|
|
19
|
+
* corroborating PID *label* adds zero detection power over heartbeat
|
|
20
|
+
* freshness (it could only ever annotate entries the heartbeat gate has
|
|
21
|
+
* already excluded). Do not re-attempt without new evidence.
|
|
22
|
+
*
|
|
23
|
+
* Cross-host policy:
|
|
24
|
+
* - Same-host: heartbeat freshness rules.
|
|
25
|
+
* - Cross-host: heartbeat freshness rules (PID-liveness was already skipped
|
|
26
|
+
* across hosts; nothing changes here).
|
|
27
|
+
*
|
|
28
|
+
* Registry fallback (Epic #583, W2-I3 — Merged Source-of-Truth):
|
|
29
|
+
* - When a worktree's lock is null OR not live, the discovery path consults
|
|
30
|
+
* the host registry as a fallback. Entries matching the current repo's
|
|
31
|
+
* `repo_path_hash` and within `freshnessMin` are merged into the result.
|
|
32
|
+
* - Lock takes precedence over registry (more detail per session); registry
|
|
33
|
+
* supplements missing per-worktree entries (e.g., when the hook ran but
|
|
34
|
+
* the prose Phase 1.2 acquire was skipped).
|
|
35
|
+
*
|
|
36
|
+
* Timeout + A1 fallback:
|
|
37
|
+
* - listWorktrees() is raced against DEFAULT_DISCOVERY_TIMEOUT_MS (2 s).
|
|
38
|
+
* - On timeout or throw → falls back to reading only the local session.lock.
|
|
39
|
+
* - Timer uses .unref() so it never keeps the Node event loop alive.
|
|
40
|
+
* - Stderr WARN: `[session-discovery] WARN: <reason> — falling back to single-worktree mode`
|
|
41
|
+
*
|
|
42
|
+
* DI hooks (for tests): opts.listWorktreesImpl, opts.timeoutMs, opts.registryReader.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import os from 'node:os';
|
|
46
|
+
import { listWorktrees } from './worktree/listing.mjs';
|
|
47
|
+
import { readLock, isLockLive } from './session-lock.mjs';
|
|
48
|
+
import { readRegistry, repoPathHash, isRegistryEntryFresh } from './session-registry.mjs';
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Constants
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
/** Default timeout in milliseconds for the listWorktrees race. */
|
|
55
|
+
export const DEFAULT_DISCOVERY_TIMEOUT_MS = 2000;
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Private helpers
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Convert a lock object + worktree path/branch into the session-shape that
|
|
63
|
+
* discoverActiveSessions returns. Centralised so the in-tree + fallback paths
|
|
64
|
+
* emit identical shapes.
|
|
65
|
+
*
|
|
66
|
+
* @param {object} lock Parsed lock body (schema v2).
|
|
67
|
+
* @param {string} worktreePath Absolute worktree path.
|
|
68
|
+
* @param {string} [branch] Branch from worktree object (falsy → '').
|
|
69
|
+
* @returns {{worktreePath:string,sessionId:string,mode:string,startedAt:string,pid:number,host:string,branch:string}}
|
|
70
|
+
*/
|
|
71
|
+
function sessionFromLock(lock, worktreePath, branch = '') {
|
|
72
|
+
return {
|
|
73
|
+
worktreePath,
|
|
74
|
+
sessionId: lock.session_id,
|
|
75
|
+
mode: lock.mode,
|
|
76
|
+
startedAt: lock.started_at,
|
|
77
|
+
pid: lock.pid,
|
|
78
|
+
host: lock.host,
|
|
79
|
+
branch: typeof branch === 'string' ? branch : '',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Convert a registry entry into the same session-shape. `worktreePath` is set
|
|
85
|
+
* to the repoRoot under which the discovery is running, since the registry
|
|
86
|
+
* does not record per-worktree paths — only repo-path-hashes. Branch is
|
|
87
|
+
* passed through from the registry entry when available.
|
|
88
|
+
*
|
|
89
|
+
* @param {object} entry Registry entry.
|
|
90
|
+
* @param {string} repoRoot Discovery repoRoot (used as worktreePath fallback).
|
|
91
|
+
*/
|
|
92
|
+
function sessionFromRegistryEntry(entry, repoRoot) {
|
|
93
|
+
return {
|
|
94
|
+
worktreePath: repoRoot,
|
|
95
|
+
sessionId: entry.session_id,
|
|
96
|
+
mode: typeof entry.mode === 'string' ? entry.mode : 'session',
|
|
97
|
+
startedAt: entry.started_at,
|
|
98
|
+
pid: typeof entry.pid === 'number' ? entry.pid : 0,
|
|
99
|
+
// Registry entries do not currently record `host` (hostname); use the
|
|
100
|
+
// local hostname as the default since registry entries are host-scoped
|
|
101
|
+
// by design (see ~/.config/session-orchestrator/sessions/).
|
|
102
|
+
host: os.hostname(),
|
|
103
|
+
branch: typeof entry.branch === 'string' ? entry.branch : '',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* A1 fallback — read only the local repoRoot's session.lock (0-or-1 result).
|
|
109
|
+
* `branch` is left empty; callers treat it as "unknown — A1 fallback active".
|
|
110
|
+
*
|
|
111
|
+
* Liveness rule: heartbeat freshness via isLockLive (Epic #583, W2-I3).
|
|
112
|
+
*
|
|
113
|
+
* @param {string} repoRoot
|
|
114
|
+
* @returns {Array<{worktreePath:string,sessionId:string,mode:string,startedAt:string,pid:number,host:string,branch:string}>}
|
|
115
|
+
*/
|
|
116
|
+
function readLocalSession(repoRoot) {
|
|
117
|
+
const lock = readLock({ repoRoot });
|
|
118
|
+
if (lock === null) return [];
|
|
119
|
+
if (!isLockLive(lock)) return [];
|
|
120
|
+
return [sessionFromLock(lock, repoRoot, '')];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Deduplicate a session list by sessionId, preferring earlier entries. The
|
|
125
|
+
* discovery path constructs the result with lock-sourced entries first
|
|
126
|
+
* (which carry more detail — exact worktreePath, branch from git) and
|
|
127
|
+
* appends registry-sourced entries; this dedupe keeps the lock-sourced one.
|
|
128
|
+
*
|
|
129
|
+
* @param {Array<{sessionId:string}>} sessions
|
|
130
|
+
* @returns {Array<{sessionId:string}>}
|
|
131
|
+
*/
|
|
132
|
+
function dedupeBySessionId(sessions) {
|
|
133
|
+
const seen = new Set();
|
|
134
|
+
const out = [];
|
|
135
|
+
for (const s of sessions) {
|
|
136
|
+
if (seen.has(s.sessionId)) continue;
|
|
137
|
+
seen.add(s.sessionId);
|
|
138
|
+
out.push(s);
|
|
139
|
+
}
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// discoverActiveSessions
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Discover all active sessions across the repository's worktree set.
|
|
149
|
+
*
|
|
150
|
+
* Liveness rule (Epic #583, W2-I3): heartbeat-based — `isLockLive(lock)`
|
|
151
|
+
* returns true when `(now - last_heartbeat) < ttl_hours`. Replaces the
|
|
152
|
+
* previous PID-liveness rule which incorrectly filtered out locks whose
|
|
153
|
+
* writer-process (hook PID) had exited.
|
|
154
|
+
*
|
|
155
|
+
* Registry fallback: after iterating worktree locks, registry entries with
|
|
156
|
+
* matching `repo_path_hash` that pass `isRegistryEntryFresh()` are merged
|
|
157
|
+
* into the result. Lock entries take precedence (they carry per-worktree
|
|
158
|
+
* detail); registry entries supplement when locks are absent or stale.
|
|
159
|
+
*
|
|
160
|
+
* On listWorktrees() failure or timeout, falls back to A1 single-worktree
|
|
161
|
+
* mode and emits a WARN to stderr.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} repoRoot Absolute path to the main repository root.
|
|
164
|
+
* @param {object} [opts]
|
|
165
|
+
* @param {number} [opts.timeoutMs=2000] Race timeout (ms). Default DEFAULT_DISCOVERY_TIMEOUT_MS.
|
|
166
|
+
* @param {Function} [opts.listWorktreesImpl] DI hook replacing listWorktrees() for tests.
|
|
167
|
+
* @param {Function} [opts.registryReader] DI hook replacing readRegistry() for tests.
|
|
168
|
+
* @param {number} [opts.freshnessMin=15] Registry-entry freshness threshold in minutes.
|
|
169
|
+
* @param {number} [opts.now] ms-since-epoch (test seam for heartbeat freshness).
|
|
170
|
+
* @returns {Promise<Array<{worktreePath:string,sessionId:string,mode:string,startedAt:string,pid:number,host:string,branch:string}>>}
|
|
171
|
+
*/
|
|
172
|
+
export async function discoverActiveSessions(repoRoot, opts = {}) {
|
|
173
|
+
const listWorktreesFn = opts.listWorktreesImpl ?? listWorktrees;
|
|
174
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_DISCOVERY_TIMEOUT_MS;
|
|
175
|
+
const registryReaderFn = opts.registryReader ?? readRegistry;
|
|
176
|
+
const freshnessMin = typeof opts.freshnessMin === 'number' ? opts.freshnessMin : 15;
|
|
177
|
+
const nowMs = typeof opts.now === 'number' ? opts.now : Date.now();
|
|
178
|
+
|
|
179
|
+
let worktrees;
|
|
180
|
+
try {
|
|
181
|
+
worktrees = await Promise.race([
|
|
182
|
+
listWorktreesFn(),
|
|
183
|
+
new Promise((_, reject) => {
|
|
184
|
+
const timer = setTimeout(() => reject(new Error('timeout')), timeoutMs);
|
|
185
|
+
timer.unref();
|
|
186
|
+
}),
|
|
187
|
+
]);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
// Either listWorktrees threw, or our timeout fired. Either way: A1 fallback.
|
|
190
|
+
const reason = err.message === 'timeout'
|
|
191
|
+
? `git worktree list timed out at ${timeoutMs}ms`
|
|
192
|
+
: `git worktree list failed: ${err.message}`;
|
|
193
|
+
process.stderr.write(`[session-discovery] WARN: ${reason} — falling back to single-worktree mode\n`);
|
|
194
|
+
return readLocalSession(repoRoot);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const lockSessions = [];
|
|
198
|
+
|
|
199
|
+
for (const worktree of worktrees) {
|
|
200
|
+
// Read the lock for this worktree (returns null if absent or malformed).
|
|
201
|
+
const lock = readLock({ repoRoot: worktree.path });
|
|
202
|
+
|
|
203
|
+
// No lock → no session in this worktree (registry fallback handled below).
|
|
204
|
+
if (lock === null) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Liveness rule (Epic #583, W2-I3): heartbeat freshness, not PID-liveness.
|
|
209
|
+
if (!isLockLive(lock, nowMs)) {
|
|
210
|
+
// Stale by heartbeat — exclude. (Registry fallback may still recover the
|
|
211
|
+
// session id if the registry entry is fresh.)
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
lockSessions.push(sessionFromLock(lock, worktree.path, worktree.branch));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Registry fallback (Merged Source-of-Truth, Epic #583, W2-I3).
|
|
219
|
+
// Filter to entries that (a) match this repo's repo_path_hash and (b) pass
|
|
220
|
+
// the freshness gate. Failures are swallowed — registry is advisory.
|
|
221
|
+
let registrySessions;
|
|
222
|
+
try {
|
|
223
|
+
const allEntries = await registryReaderFn();
|
|
224
|
+
const myRepoHash = repoPathHash(repoRoot);
|
|
225
|
+
registrySessions = allEntries
|
|
226
|
+
.filter((e) => e && e.repo_path_hash === myRepoHash)
|
|
227
|
+
.filter((e) => isRegistryEntryFresh(e, { freshnessMin, now: nowMs }))
|
|
228
|
+
.map((e) => sessionFromRegistryEntry(e, repoRoot));
|
|
229
|
+
} catch {
|
|
230
|
+
// Registry read failure → keep going with lock-only results.
|
|
231
|
+
registrySessions = [];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Merge: lock-sourced first (more detail), then registry. Dedupe by
|
|
235
|
+
// sessionId so a session that has both a lock and a registry entry only
|
|
236
|
+
// appears once with the richer lock detail.
|
|
237
|
+
return dedupeBySessionId([...lockSessions, ...registrySessions]);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// findWorktrees
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Thin namespace-cohesion wrapper around listWorktrees().
|
|
246
|
+
*
|
|
247
|
+
* The `repoRoot` parameter is reserved for future per-worktree filtering
|
|
248
|
+
* (Issue #569 P1.2) and is currently passed through without effect.
|
|
249
|
+
*
|
|
250
|
+
* @param {string} _repoRoot Absolute path to the main repository root (reserved).
|
|
251
|
+
* @returns {Promise<Array<{path: string, branch: string, head: string}>>}
|
|
252
|
+
* Same shape as listWorktrees(); empty array on git failure.
|
|
253
|
+
*/
|
|
254
|
+
export async function findWorktrees(_repoRoot) {
|
|
255
|
+
return listWorktrees();
|
|
256
|
+
}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-end/phase-skip.mjs — Tail-Diät skip-plan aggregator (Issue #724).
|
|
3
|
+
*
|
|
4
|
+
* The session-end Phase 3.6.x tail (3.6.3 Memory-Proposals, 3.6.4 Expired-Sweep,
|
|
5
|
+
* 3.6.5 Auto-Dream, 3.6.6 Skill-Judge, 3.6.7 Auto-Dialectic, 3.6.8 Reconcile) is
|
|
6
|
+
* the close-out abort-attractor: six phases, each ~50 lines of coordinator prose,
|
|
7
|
+
* that in the overwhelming majority of sessions do nothing (no proposals queued,
|
|
8
|
+
* nothing expired, under cadence, judge off, reconcile off). This aggregator
|
|
9
|
+
* computes — side-effect-free — WHICH of the six should actually run, so the
|
|
10
|
+
* coordinator loads only the detail procedure for the `run: true` phases and
|
|
11
|
+
* emits a one-line `skippedReport` for the rest.
|
|
12
|
+
*
|
|
13
|
+
* Every one of the six phases already ships a mechanical fast-path in its own lib
|
|
14
|
+
* (a config kill-switch, an `existsSync` short-circuit, or a cadence/trigger
|
|
15
|
+
* decision). This module WRAPS those existing signals — it never re-implements
|
|
16
|
+
* their logic. Config gates run FIRST as the cheap short-circuit (no disk touch),
|
|
17
|
+
* then the input-detection helpers run only when the config gate passed.
|
|
18
|
+
*
|
|
19
|
+
* Side-effect-free contract:
|
|
20
|
+
* - reads only (existsSync / read helpers); writes NOTHING.
|
|
21
|
+
* - reconcile runs with `dryRun: true` so the candidate sidecar is never written.
|
|
22
|
+
* - the sweep runs with `dryRun: true` (its default) so the store is untouched.
|
|
23
|
+
*
|
|
24
|
+
* Never-throws contract (mirrors the banner-probe posture): a failure while
|
|
25
|
+
* probing a single phase degrades to `run: true` (fail-open) with a
|
|
26
|
+
* `probe-error: …` reason — when in doubt, RUN the phase rather than silently
|
|
27
|
+
* lose it. `planTailPhases` itself never throws to its caller.
|
|
28
|
+
*
|
|
29
|
+
* Plain Node ESM, no external deps — Node 20+ stdlib + the six read-only signal
|
|
30
|
+
* helpers only.
|
|
31
|
+
*
|
|
32
|
+
* @typedef {Object} PhaseDecision
|
|
33
|
+
* @property {string} phase - the phase id, e.g. '3.6.3'.
|
|
34
|
+
* @property {boolean} run - true → coordinator runs the detail procedure.
|
|
35
|
+
* @property {string} reason - human-readable reason for the decision.
|
|
36
|
+
* @property {string} inputSource - which signal drove the decision
|
|
37
|
+
* ('config-gate' | 'proposals.jsonl' | 'sweep-dry-run' | 'auto-dream-signal' |
|
|
38
|
+
* 'skill-invocations.jsonl' | 'auto-dialectic-signal' | 'reconcile-dry-run' |
|
|
39
|
+
* 'learnings.jsonl' | 'probe-error').
|
|
40
|
+
*
|
|
41
|
+
* @typedef {Object} TailPlan
|
|
42
|
+
* @property {PhaseDecision[]} plan
|
|
43
|
+
* @property {string} skippedReport
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
import { existsSync } from 'node:fs';
|
|
47
|
+
import path from 'node:path';
|
|
48
|
+
|
|
49
|
+
import { collectProposals } from '../memory-proposals/collector.mjs';
|
|
50
|
+
import { sweepExpiredLearnings } from '../learnings/expiry-sweep.mjs';
|
|
51
|
+
import { shouldDispatchAutoDream } from '../auto-dream.mjs';
|
|
52
|
+
import { shouldDispatchAutoDialectic } from '../auto-dialectic.mjs';
|
|
53
|
+
import { readSkillInvocations } from '../skill-invocations-schema.mjs';
|
|
54
|
+
import { runReconcile } from '../reconcile/engine.mjs';
|
|
55
|
+
import { resolveMemoryDir } from '../memory-paths.mjs';
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Decision constructors
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {string} phase
|
|
63
|
+
* @param {boolean} run
|
|
64
|
+
* @param {string} reason
|
|
65
|
+
* @param {string} inputSource
|
|
66
|
+
* @returns {PhaseDecision}
|
|
67
|
+
*/
|
|
68
|
+
function decision(phase, run, reason, inputSource) {
|
|
69
|
+
return { phase, run, reason, inputSource };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Skip decision. */
|
|
73
|
+
function mkSkip(phase, reason, inputSource) {
|
|
74
|
+
return decision(phase, false, reason, inputSource);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Run decision. */
|
|
78
|
+
function mkRun(phase, reason, inputSource) {
|
|
79
|
+
return decision(phase, true, reason, inputSource);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Fail-open decision for a probe that threw. Runs the phase (never silently
|
|
84
|
+
* loses it) and stamps a `probe-error: …` reason.
|
|
85
|
+
*/
|
|
86
|
+
function mkProbeError(phase, err) {
|
|
87
|
+
const msg = err && err.message ? err.message : String(err);
|
|
88
|
+
return decision(phase, true, `probe-error: ${msg}`, 'probe-error');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Config / platform helpers
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
/** persistence is off only when explicitly `false`; absent → treated as on. */
|
|
96
|
+
function isPersistenceOff(cfg) {
|
|
97
|
+
return cfg && cfg.persistence === false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* MEMORY.md (Auto-Dream signal source) lives under `~/.claude/projects/` — a
|
|
102
|
+
* Claude Code-only path. Absent platform → treated as Claude Code (the common
|
|
103
|
+
* coordinator context); any explicit non-Claude platform gates 3.6.5 off.
|
|
104
|
+
*/
|
|
105
|
+
function isClaudePlatform(platform) {
|
|
106
|
+
if (platform === undefined || platform === null || platform === '') return true;
|
|
107
|
+
const p = String(platform).toLowerCase();
|
|
108
|
+
return p === 'claude' || p === 'claude-code' || p === 'claudecode';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Per-phase deciders — each wraps an EXISTING signal helper, config-gate first.
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* 3.6.3 Memory-Proposals Collection (#501). Config gate (persistence,
|
|
117
|
+
* memory.proposals.enabled) → then `collectProposals` (existsSync short-circuit
|
|
118
|
+
* on proposals.jsonl → empty queue).
|
|
119
|
+
*/
|
|
120
|
+
async function decideMemoryProposals({ repoRoot, cfg }) {
|
|
121
|
+
const phase = '3.6.3';
|
|
122
|
+
try {
|
|
123
|
+
if (isPersistenceOff(cfg)) return mkSkip(phase, 'persistence=false', 'config-gate');
|
|
124
|
+
if (cfg?.memory?.proposals?.enabled === false) {
|
|
125
|
+
return mkSkip(phase, 'memory.proposals.enabled=false', 'config-gate');
|
|
126
|
+
}
|
|
127
|
+
const { queue, stats } = await collectProposals({
|
|
128
|
+
repoRoot,
|
|
129
|
+
minConfidence: cfg?.['auto-dream']?.['min-confidence'],
|
|
130
|
+
});
|
|
131
|
+
if (!Array.isArray(queue) || queue.length === 0) {
|
|
132
|
+
return mkSkip(phase, `proposals empty (queued=${stats?.queued ?? 0})`, 'proposals.jsonl');
|
|
133
|
+
}
|
|
134
|
+
return mkRun(phase, `${queue.length} proposal(s) queued`, 'proposals.jsonl');
|
|
135
|
+
} catch (err) {
|
|
136
|
+
return mkProbeError(phase, err);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 3.6.4 Expired-Learnings Sweep (Epic #723 B4). No config gate — best-effort,
|
|
142
|
+
* non-blocking. `sweepExpiredLearnings` runs in `dryRun: true` (writes nothing):
|
|
143
|
+
* archived === 0 → nothing to move → skip.
|
|
144
|
+
*/
|
|
145
|
+
async function decideExpiredSweep({ repoRoot }) {
|
|
146
|
+
const phase = '3.6.4';
|
|
147
|
+
try {
|
|
148
|
+
const filePath = path.join(repoRoot, '.orchestrator', 'metrics', 'learnings.jsonl');
|
|
149
|
+
if (!existsSync(filePath)) return mkSkip(phase, 'learnings.jsonl absent', 'learnings.jsonl');
|
|
150
|
+
const archivePath = path.join(
|
|
151
|
+
repoRoot,
|
|
152
|
+
'.orchestrator',
|
|
153
|
+
'metrics',
|
|
154
|
+
'learnings-archive.jsonl',
|
|
155
|
+
);
|
|
156
|
+
const res = await sweepExpiredLearnings({ filePath, archivePath, dryRun: true });
|
|
157
|
+
if (!res || res.archived === 0) {
|
|
158
|
+
return mkSkip(phase, `nothing archive-eligible (scanned=${res?.scanned ?? 0})`, 'sweep-dry-run');
|
|
159
|
+
}
|
|
160
|
+
const plural = res.archived === 1 ? 'y' : 'ies';
|
|
161
|
+
return mkRun(phase, `${res.archived} entr${plural} archive-eligible`, 'sweep-dry-run');
|
|
162
|
+
} catch (err) {
|
|
163
|
+
return mkProbeError(phase, err);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 3.6.5 Auto-Dream nudge (#502). Config gate (kill-switch threshold=0, platform)
|
|
169
|
+
* → then `shouldDispatchAutoDream` (trigger:false branches → skip).
|
|
170
|
+
*/
|
|
171
|
+
async function decideAutoDream({ repoRoot, cfg, platform, memoryDir }) {
|
|
172
|
+
const phase = '3.6.5';
|
|
173
|
+
try {
|
|
174
|
+
const threshold = cfg?.['memory-cleanup-threshold'] ?? 5;
|
|
175
|
+
if (threshold === 0) {
|
|
176
|
+
return mkSkip(phase, 'kill-switch (memory-cleanup-threshold=0)', 'config-gate');
|
|
177
|
+
}
|
|
178
|
+
if (!isClaudePlatform(platform)) {
|
|
179
|
+
return mkSkip(phase, 'non-Claude-Code platform (memory dir unavailable)', 'config-gate');
|
|
180
|
+
}
|
|
181
|
+
const dir = memoryDir ?? resolveMemoryDir();
|
|
182
|
+
const dec = await shouldDispatchAutoDream({
|
|
183
|
+
repoRoot,
|
|
184
|
+
memoryDir: dir,
|
|
185
|
+
threshold,
|
|
186
|
+
softLimit: cfg?.['memory-cleanup-soft-limit'] ?? 180,
|
|
187
|
+
});
|
|
188
|
+
if (!dec.trigger) return mkSkip(phase, dec.reason, 'auto-dream-signal');
|
|
189
|
+
return mkRun(phase, dec.reason, 'auto-dream-signal');
|
|
190
|
+
} catch (err) {
|
|
191
|
+
return mkProbeError(phase, err);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 3.6.6 Skill-Applied Judge (#645 L3). Config gate (judge default OFF,
|
|
197
|
+
* persistence) → then the judged-set emptiness check via
|
|
198
|
+
* `readSkillInvocations` (mirrors runSkillJudge's `empty-input` gate: no
|
|
199
|
+
* selected skill this session → nothing to judge → skip). This computes the
|
|
200
|
+
* judged set the coordinator would compute anyway; it does NOT re-implement the
|
|
201
|
+
* judge (runSkillJudge needs a live dispatch, which is not side-effect-free).
|
|
202
|
+
*
|
|
203
|
+
* `sessionId === null/undefined` (noSessionFilter) deliberately falls to the
|
|
204
|
+
* BROADER match — every entry in skill-invocations.jsonl counts toward
|
|
205
|
+
* `judged`, regardless of which session recorded it. This can over-count (a
|
|
206
|
+
* `run: true` decision when the true current-session set would have been
|
|
207
|
+
* empty), which is the fail-open direction: worst case the coordinator loads
|
|
208
|
+
* the 3.6.6 detail procedure for nothing, since the REAL `runSkillJudge` self-
|
|
209
|
+
* gates on its own empty-input check when it actually runs. It never
|
|
210
|
+
* under-counts into a false skip.
|
|
211
|
+
*/
|
|
212
|
+
async function decideSkillJudge({ repoRoot, cfg, sessionId }) {
|
|
213
|
+
const phase = '3.6.6';
|
|
214
|
+
try {
|
|
215
|
+
if (cfg?.['skill-evolution']?.judge !== true) {
|
|
216
|
+
return mkSkip(phase, 'disabled (skill-evolution.judge=false)', 'config-gate');
|
|
217
|
+
}
|
|
218
|
+
if (isPersistenceOff(cfg)) return mkSkip(phase, 'persistence=false', 'config-gate');
|
|
219
|
+
const invPath = path.join(repoRoot, '.orchestrator', 'metrics', 'skill-invocations.jsonl');
|
|
220
|
+
const entries = await readSkillInvocations(invPath);
|
|
221
|
+
const noSessionFilter = sessionId === null || sessionId === undefined;
|
|
222
|
+
const judged = new Set(
|
|
223
|
+
entries
|
|
224
|
+
.filter((e) => noSessionFilter || e.session_id === sessionId)
|
|
225
|
+
.map((e) => e.skill)
|
|
226
|
+
.filter((s) => typeof s === 'string' && s.trim().length > 0),
|
|
227
|
+
);
|
|
228
|
+
if (judged.size === 0) {
|
|
229
|
+
return mkSkip(phase, 'empty-input (no selected skills this session)', 'skill-invocations.jsonl');
|
|
230
|
+
}
|
|
231
|
+
return mkRun(phase, `${judged.size} selected skill(s) to judge`, 'skill-invocations.jsonl');
|
|
232
|
+
} catch (err) {
|
|
233
|
+
return mkProbeError(phase, err);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 3.6.7 Auto-Dialectic nudge (#506). Config gate (persistence, kill-switch
|
|
239
|
+
* cadence=0) → then `shouldDispatchAutoDialectic` (the reference implementation
|
|
240
|
+
* of the no-new-input-since-last-run pattern via `.orchestrator/dialectic-last-run`).
|
|
241
|
+
*/
|
|
242
|
+
async function decideAutoDialectic({ repoRoot, cfg }) {
|
|
243
|
+
const phase = '3.6.7';
|
|
244
|
+
try {
|
|
245
|
+
if (isPersistenceOff(cfg)) return mkSkip(phase, 'persistence=false', 'config-gate');
|
|
246
|
+
const cadence = cfg?.dialectic?.cadence ?? 5;
|
|
247
|
+
if (cadence === 0) return mkSkip(phase, 'kill-switch (dialectic.cadence=0)', 'config-gate');
|
|
248
|
+
const dec = await shouldDispatchAutoDialectic({ repoRoot, cadence });
|
|
249
|
+
if (!dec.trigger) return mkSkip(phase, dec.reason, 'auto-dialectic-signal');
|
|
250
|
+
return mkRun(phase, dec.reason, 'auto-dialectic-signal');
|
|
251
|
+
} catch (err) {
|
|
252
|
+
return mkProbeError(phase, err);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 3.6.8 Reconciliation Rule Proposals (#696). Config gate (persistence,
|
|
258
|
+
* reconcile.enabled default OFF, learnings.jsonl present) → then `runReconcile`
|
|
259
|
+
* with `dryRun: true` (SKIPs the candidate-sidecar merge — no write) and the
|
|
260
|
+
* operator confidence-floor delivery gate. 0 proposals above floor → skip.
|
|
261
|
+
* runReconcile never throws; an engine `error` is treated fail-open (run).
|
|
262
|
+
*/
|
|
263
|
+
async function decideReconcile({ repoRoot, cfg }) {
|
|
264
|
+
const phase = '3.6.8';
|
|
265
|
+
try {
|
|
266
|
+
if (isPersistenceOff(cfg)) return mkSkip(phase, 'persistence=false', 'config-gate');
|
|
267
|
+
if (cfg?.reconcile?.enabled !== true) {
|
|
268
|
+
return mkSkip(phase, 'disabled (reconcile.enabled=false)', 'config-gate');
|
|
269
|
+
}
|
|
270
|
+
const learningsPath = path.join(repoRoot, '.orchestrator', 'metrics', 'learnings.jsonl');
|
|
271
|
+
if (!existsSync(learningsPath)) {
|
|
272
|
+
return mkSkip(phase, 'learnings.jsonl absent', 'learnings.jsonl');
|
|
273
|
+
}
|
|
274
|
+
const { proposals, summary, error } = await runReconcile({
|
|
275
|
+
repoRoot,
|
|
276
|
+
ruleExpiryDays: cfg?.reconcile?.['rule-expiry-days'] ?? undefined,
|
|
277
|
+
minRuleDays: cfg?.reconcile?.['min-rule-days'] ?? undefined,
|
|
278
|
+
minInsightChars: cfg?.reconcile?.['min-insight-chars'] ?? undefined,
|
|
279
|
+
now: new Date(),
|
|
280
|
+
dryRun: true, // never write the candidate sidecar from the aggregator
|
|
281
|
+
});
|
|
282
|
+
if (error) return mkProbeError(phase, new Error(error)); // fail-open on engine error
|
|
283
|
+
const floor = cfg?.reconcile?.['confidence-floor'] ?? 0.5;
|
|
284
|
+
const surfaced = (Array.isArray(proposals) ? proposals : []).filter(
|
|
285
|
+
(p) => typeof p.confidence === 'number' && p.confidence >= floor,
|
|
286
|
+
);
|
|
287
|
+
if (surfaced.length === 0) {
|
|
288
|
+
return mkSkip(
|
|
289
|
+
phase,
|
|
290
|
+
`0 proposals above confidence floor (eligible=${summary?.eligible ?? 0}, floor=${floor})`,
|
|
291
|
+
'reconcile-dry-run',
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
return mkRun(phase, `${surfaced.length} proposal(s) above confidence floor`, 'reconcile-dry-run');
|
|
295
|
+
} catch (err) {
|
|
296
|
+
return mkProbeError(phase, err);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
// Report builder
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Build the compact one-line skip report from a plan.
|
|
306
|
+
*
|
|
307
|
+
* @param {PhaseDecision[]} plan
|
|
308
|
+
* @returns {string}
|
|
309
|
+
*/
|
|
310
|
+
export function buildSkippedReport(plan) {
|
|
311
|
+
const parts = (Array.isArray(plan) ? plan : []).map((d) => {
|
|
312
|
+
const verb = d.run ? 'RUN' : 'skipped';
|
|
313
|
+
return `${d.phase} ${verb} (${d.reason})`;
|
|
314
|
+
});
|
|
315
|
+
return `Tail-Diät: ${parts.join(' · ')}`;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
// Main aggregator
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Compute the run/skip plan for the six session-end Phase 3.6.x tail phases.
|
|
324
|
+
*
|
|
325
|
+
* NEVER throws — each phase probe fail-opens to `run: true`, and the top-level
|
|
326
|
+
* guard converts any unexpected error into an all-run plan so the coordinator
|
|
327
|
+
* runs the full tail rather than silently skipping it.
|
|
328
|
+
*
|
|
329
|
+
* @param {object} args
|
|
330
|
+
* @param {string} args.repoRoot Absolute repo root.
|
|
331
|
+
* @param {object} args.config Parsed Session Config object (from parse-config.mjs).
|
|
332
|
+
* @param {string|null} [args.sessionId] Current session id (for the 3.6.6 judged-set filter).
|
|
333
|
+
* @param {string} [args.platform] Platform id ('claude' | 'codex' | 'cursor' | …).
|
|
334
|
+
* @param {string} [args.memoryDir] Optional Auto-Dream memory dir override (default resolveMemoryDir()).
|
|
335
|
+
* @returns {Promise<TailPlan>}
|
|
336
|
+
*/
|
|
337
|
+
export async function planTailPhases({ repoRoot, config, sessionId, platform, memoryDir } = {}) {
|
|
338
|
+
const cfg = config ?? {};
|
|
339
|
+
try {
|
|
340
|
+
const plan = await Promise.all([
|
|
341
|
+
decideMemoryProposals({ repoRoot, cfg }),
|
|
342
|
+
decideExpiredSweep({ repoRoot }),
|
|
343
|
+
decideAutoDream({ repoRoot, cfg, platform, memoryDir }),
|
|
344
|
+
decideSkillJudge({ repoRoot, cfg, sessionId }),
|
|
345
|
+
decideAutoDialectic({ repoRoot, cfg }),
|
|
346
|
+
decideReconcile({ repoRoot, cfg }),
|
|
347
|
+
]);
|
|
348
|
+
return { plan, skippedReport: buildSkippedReport(plan) };
|
|
349
|
+
} catch (err) {
|
|
350
|
+
// Top-level fail-open guard: run the full tail rather than lose it silently.
|
|
351
|
+
const msg = err && err.message ? err.message : String(err);
|
|
352
|
+
const plan = ['3.6.3', '3.6.4', '3.6.5', '3.6.6', '3.6.7', '3.6.8'].map((p) =>
|
|
353
|
+
decision(p, true, `probe-error: ${msg}`, 'probe-error'),
|
|
354
|
+
);
|
|
355
|
+
return { plan, skippedReport: buildSkippedReport(plan) };
|
|
356
|
+
}
|
|
357
|
+
}
|