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,417 @@
|
|
|
1
|
+
// scripts/lib/autopilot/dep-graph.mjs
|
|
2
|
+
//
|
|
3
|
+
// Issue dependency graph + topological-sort scheduler for autopilot --multi-story.
|
|
4
|
+
// Pure data layer — no I/O, no shell. Powers nextReady() lookups during multi-story
|
|
5
|
+
// pipeline scheduling per "Autopilot Phase D — Per-Story Worktree Pipelines"
|
|
6
|
+
// (#341; archived in the private Meta-Vault).
|
|
7
|
+
//
|
|
8
|
+
// Substrate: ADR-364 thin-slice MVP. Issue selection criterion: `status:ready` label
|
|
9
|
+
// only (OPEN-1 decision in PRD). Cross-loop wait semantics use commit-based deps
|
|
10
|
+
// (OPEN-4), but this module is pure-graph and doesn't enforce wait policy — the
|
|
11
|
+
// worktree-pipeline driver is responsible for that.
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @fileoverview Pure topological-sort dependency graph for GitLab/GitHub issues.
|
|
15
|
+
*
|
|
16
|
+
* Handles `blocks`/`blocked-by` relations between issues and exposes scheduling
|
|
17
|
+
* helpers for the `--multi-story` autopilot mode. All functions are pure data
|
|
18
|
+
* transformations with no I/O side effects.
|
|
19
|
+
*
|
|
20
|
+
* References:
|
|
21
|
+
* - ADR-364 thin-slice MVP
|
|
22
|
+
* - "Autopilot Phase D — Per-Story Worktree Pipelines" (#341; archived in the private Meta-Vault)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {object} Issue
|
|
27
|
+
* @property {number} iid - Issue IID/number
|
|
28
|
+
* @property {string[]} blocks - Array of iids (as strings or numbers) this issue blocks
|
|
29
|
+
* @property {string[]} blockedBy - Array of iids (as strings or numbers) blocking this issue
|
|
30
|
+
* @property {string[]} labels - Issue labels (e.g., ["status:ready"])
|
|
31
|
+
* @property {string} title - Issue title (for diagnostics)
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {object} DepGraph
|
|
36
|
+
* @property {Map<number, Issue>} nodes - All known issues keyed by iid
|
|
37
|
+
* @property {Map<number, Set<number>>} edges - iid → set of iids it blocks (outgoing)
|
|
38
|
+
* @property {Map<number, Set<number>>} reverse - iid → set of iids blocking it (incoming)
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Internal helpers
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Coerce a raw iid value (string or number) to a number, or return null if
|
|
47
|
+
* the value is not a valid finite integer.
|
|
48
|
+
*
|
|
49
|
+
* @param {unknown} raw
|
|
50
|
+
* @returns {number|null}
|
|
51
|
+
*/
|
|
52
|
+
function toIid(raw) {
|
|
53
|
+
const n = Number(raw);
|
|
54
|
+
return Number.isFinite(n) && Number.isInteger(n) ? n : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Safely coerce a field that should be an array of iids.
|
|
59
|
+
* Returns an empty array when the field is null/undefined/non-array.
|
|
60
|
+
*
|
|
61
|
+
* @param {unknown} field
|
|
62
|
+
* @returns {number[]}
|
|
63
|
+
*/
|
|
64
|
+
function normalizeIidArray(field) {
|
|
65
|
+
if (!Array.isArray(field)) return [];
|
|
66
|
+
return field.map(toIid).filter((n) => n !== null);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// buildGraph
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Build a DepGraph from an array of issues.
|
|
75
|
+
*
|
|
76
|
+
* Reconciles both directions of the blocks/blockedBy relationship:
|
|
77
|
+
* - If A.blocks includes B's iid, then B.blockedBy is extended to include A.
|
|
78
|
+
* - If A.blockedBy includes B's iid, then B.blocks is extended to include A.
|
|
79
|
+
*
|
|
80
|
+
* Issues referenced in blocks/blockedBy that are not present in the input
|
|
81
|
+
* array are silently ignored after emitting a `console.warn`. The graph will
|
|
82
|
+
* only contain nodes for issues present in the `issues` parameter.
|
|
83
|
+
*
|
|
84
|
+
* @param {Issue[]} issues - Flat array of issues to build the graph from.
|
|
85
|
+
* @returns {DepGraph}
|
|
86
|
+
*/
|
|
87
|
+
export function buildGraph(issues) {
|
|
88
|
+
/** @type {Map<number, Issue>} */
|
|
89
|
+
const nodes = new Map();
|
|
90
|
+
/** @type {Map<number, Set<number>>} */
|
|
91
|
+
const edges = new Map();
|
|
92
|
+
/** @type {Map<number, Set<number>>} */
|
|
93
|
+
const reverse = new Map();
|
|
94
|
+
|
|
95
|
+
if (!Array.isArray(issues) || issues.length === 0) {
|
|
96
|
+
return { nodes, edges, reverse };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// First pass: intern all issues, normalizing iid arrays defensively.
|
|
100
|
+
for (const raw of issues) {
|
|
101
|
+
const iid = toIid(raw?.iid);
|
|
102
|
+
if (iid === null) {
|
|
103
|
+
console.warn('[dep-graph] buildGraph: skipping issue with invalid iid', raw);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
/** @type {Issue} */
|
|
107
|
+
const issue = {
|
|
108
|
+
iid,
|
|
109
|
+
blocks: normalizeIidArray(raw.blocks),
|
|
110
|
+
blockedBy: normalizeIidArray(raw.blockedBy),
|
|
111
|
+
labels: Array.isArray(raw.labels) ? [...raw.labels] : [],
|
|
112
|
+
title: typeof raw.title === 'string' ? raw.title : String(raw.title ?? ''),
|
|
113
|
+
};
|
|
114
|
+
nodes.set(iid, issue);
|
|
115
|
+
edges.set(iid, new Set());
|
|
116
|
+
reverse.set(iid, new Set());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Second pass: reconcile both directions and populate edge maps.
|
|
120
|
+
// We first collect all declared relations, then validate both ends exist.
|
|
121
|
+
// Collect raw declarations: [blocker, blocked] pairs.
|
|
122
|
+
/** @type {Array<[number, number]>} */
|
|
123
|
+
const declared = [];
|
|
124
|
+
|
|
125
|
+
for (const issue of nodes.values()) {
|
|
126
|
+
for (const target of issue.blocks) {
|
|
127
|
+
declared.push([issue.iid, target]);
|
|
128
|
+
}
|
|
129
|
+
for (const source of issue.blockedBy) {
|
|
130
|
+
declared.push([source, issue.iid]);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Deduplicate and validate, then write into edge maps and normalised Issue fields.
|
|
135
|
+
const seen = new Set();
|
|
136
|
+
for (const [blocker, blocked] of declared) {
|
|
137
|
+
const key = `${blocker}:${blocked}`;
|
|
138
|
+
if (seen.has(key)) continue;
|
|
139
|
+
seen.add(key);
|
|
140
|
+
|
|
141
|
+
if (blocker === blocked) {
|
|
142
|
+
console.warn(`[dep-graph] buildGraph: self-loop on iid ${blocker} ignored`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const blockerNode = nodes.get(blocker);
|
|
147
|
+
const blockedNode = nodes.get(blocked);
|
|
148
|
+
|
|
149
|
+
if (!blockerNode) {
|
|
150
|
+
console.warn(`[dep-graph] buildGraph: iid ${blocker} referenced but not in issues array — ignored`);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (!blockedNode) {
|
|
154
|
+
console.warn(`[dep-graph] buildGraph: iid ${blocked} referenced but not in issues array — ignored`);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Sync normalised arrays on the Issue objects.
|
|
159
|
+
if (!blockerNode.blocks.includes(blocked)) blockerNode.blocks.push(blocked);
|
|
160
|
+
if (!blockedNode.blockedBy.includes(blocker)) blockedNode.blockedBy.push(blocker);
|
|
161
|
+
|
|
162
|
+
// Populate edge maps.
|
|
163
|
+
edges.get(blocker).add(blocked);
|
|
164
|
+
reverse.get(blocked).add(blocker);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { nodes, edges, reverse };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// topologicalSort
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Perform a topological sort on the graph using Kahn's BFS algorithm.
|
|
176
|
+
*
|
|
177
|
+
* Tie-breaking between nodes at the same depth is resolved by ascending iid
|
|
178
|
+
* (stable, deterministic output).
|
|
179
|
+
*
|
|
180
|
+
* When cycles are present, the `order` array contains only the nodes NOT
|
|
181
|
+
* involved in any cycle (processed in topological order). The `cycles` array
|
|
182
|
+
* contains each cycle as an array of iid numbers.
|
|
183
|
+
*
|
|
184
|
+
* @param {DepGraph} graph
|
|
185
|
+
* @returns {{ order: number[], cycles: number[][] }}
|
|
186
|
+
*/
|
|
187
|
+
export function topologicalSort(graph) {
|
|
188
|
+
const { nodes, edges, reverse } = graph;
|
|
189
|
+
|
|
190
|
+
if (nodes.size === 0) {
|
|
191
|
+
return { order: [], cycles: [] };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Build a mutable in-degree map.
|
|
195
|
+
/** @type {Map<number, number>} */
|
|
196
|
+
const inDegree = new Map();
|
|
197
|
+
for (const iid of nodes.keys()) {
|
|
198
|
+
inDegree.set(iid, reverse.get(iid)?.size ?? 0);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Seed the queue with all zero-in-degree nodes, sorted by ascending iid.
|
|
202
|
+
/** @type {number[]} */
|
|
203
|
+
const queue = [...inDegree.entries()]
|
|
204
|
+
.filter(([, deg]) => deg === 0)
|
|
205
|
+
.map(([iid]) => iid)
|
|
206
|
+
.sort((a, b) => a - b);
|
|
207
|
+
|
|
208
|
+
/** @type {number[]} */
|
|
209
|
+
const order = [];
|
|
210
|
+
|
|
211
|
+
while (queue.length > 0) {
|
|
212
|
+
// Dequeue the smallest iid (queue is always kept sorted).
|
|
213
|
+
const iid = queue.shift();
|
|
214
|
+
order.push(iid);
|
|
215
|
+
|
|
216
|
+
// Decrement in-degree for all nodes this iid blocks.
|
|
217
|
+
const neighbours = [...(edges.get(iid) ?? [])].sort((a, b) => a - b);
|
|
218
|
+
for (const neighbour of neighbours) {
|
|
219
|
+
const newDeg = (inDegree.get(neighbour) ?? 0) - 1;
|
|
220
|
+
inDegree.set(neighbour, newDeg);
|
|
221
|
+
if (newDeg === 0) {
|
|
222
|
+
// Insert in sorted position to maintain ascending-iid stability.
|
|
223
|
+
insertSorted(queue, neighbour);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Any node not in `order` is part of a cycle.
|
|
229
|
+
const inOrderSet = new Set(order);
|
|
230
|
+
const cycleNodes = [...nodes.keys()].filter((iid) => !inOrderSet.has(iid));
|
|
231
|
+
|
|
232
|
+
const cycles = cycleNodes.length > 0 ? detectCyclesFromNodes(graph, cycleNodes) : [];
|
|
233
|
+
|
|
234
|
+
return { order, cycles };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Insert `value` into a sorted array (ascending) in-place using binary search.
|
|
239
|
+
*
|
|
240
|
+
* @param {number[]} arr
|
|
241
|
+
* @param {number} value
|
|
242
|
+
*/
|
|
243
|
+
function insertSorted(arr, value) {
|
|
244
|
+
let lo = 0;
|
|
245
|
+
let hi = arr.length;
|
|
246
|
+
while (lo < hi) {
|
|
247
|
+
const mid = (lo + hi) >>> 1;
|
|
248
|
+
if (arr[mid] < value) lo = mid + 1;
|
|
249
|
+
else hi = mid;
|
|
250
|
+
}
|
|
251
|
+
arr.splice(lo, 0, value);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ---------------------------------------------------------------------------
|
|
255
|
+
// detectCycles
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Detect all strongly-connected components (SCCs) of size > 1 using an
|
|
260
|
+
* iterative implementation of Tarjan's SCC algorithm.
|
|
261
|
+
*
|
|
262
|
+
* Returns each cycle as an array of iid numbers (members of the SCC),
|
|
263
|
+
* sorted by ascending iid within each cycle. The outer array is sorted by
|
|
264
|
+
* the minimum iid of each cycle (ascending).
|
|
265
|
+
*
|
|
266
|
+
* @param {DepGraph} graph
|
|
267
|
+
* @returns {number[][]}
|
|
268
|
+
*/
|
|
269
|
+
export function detectCycles(graph) {
|
|
270
|
+
return detectCyclesFromNodes(graph, [...graph.nodes.keys()]);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Internal: run Tarjan's iterative SCC algorithm over a subset of nodes
|
|
275
|
+
* (or all nodes). Only SCCs of size > 1 are returned (true cycles).
|
|
276
|
+
*
|
|
277
|
+
* @param {DepGraph} graph
|
|
278
|
+
* @param {number[]} nodeSubset - iids to consider
|
|
279
|
+
* @returns {number[][]}
|
|
280
|
+
*/
|
|
281
|
+
function detectCyclesFromNodes(graph, nodeSubset) {
|
|
282
|
+
const { edges } = graph;
|
|
283
|
+
|
|
284
|
+
let index = 0;
|
|
285
|
+
/** @type {Map<number, number>} */
|
|
286
|
+
const indices = new Map();
|
|
287
|
+
/** @type {Map<number, number>} */
|
|
288
|
+
const lowlink = new Map();
|
|
289
|
+
/** @type {Set<number>} */
|
|
290
|
+
const onStack = new Set();
|
|
291
|
+
/** @type {number[]} */
|
|
292
|
+
const stack = [];
|
|
293
|
+
/** @type {number[][]} */
|
|
294
|
+
const sccs = [];
|
|
295
|
+
|
|
296
|
+
// Only process nodes in the subset.
|
|
297
|
+
const subsetSet = new Set(nodeSubset);
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Iterative Tarjan's SCC for a single root node.
|
|
301
|
+
*
|
|
302
|
+
* @param {number} root
|
|
303
|
+
*/
|
|
304
|
+
function strongconnect(root) {
|
|
305
|
+
// Explicit call-stack frames to avoid recursion limits.
|
|
306
|
+
// Each frame: { iid, neighbourIter, parentIid }
|
|
307
|
+
/** @type {Array<{ iid: number, neighbours: number[], ni: number }>} */
|
|
308
|
+
const callStack = [];
|
|
309
|
+
|
|
310
|
+
function visit(iid) {
|
|
311
|
+
indices.set(iid, index);
|
|
312
|
+
lowlink.set(iid, index);
|
|
313
|
+
index++;
|
|
314
|
+
stack.push(iid);
|
|
315
|
+
onStack.add(iid);
|
|
316
|
+
|
|
317
|
+
const neighbours = [...(edges.get(iid) ?? [])]
|
|
318
|
+
.filter((n) => subsetSet.has(n))
|
|
319
|
+
.sort((a, b) => a - b);
|
|
320
|
+
callStack.push({ iid, neighbours, ni: 0 });
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
visit(root);
|
|
324
|
+
|
|
325
|
+
while (callStack.length > 0) {
|
|
326
|
+
const frame = callStack[callStack.length - 1];
|
|
327
|
+
const { iid, neighbours } = frame;
|
|
328
|
+
|
|
329
|
+
if (frame.ni < neighbours.length) {
|
|
330
|
+
const w = neighbours[frame.ni++];
|
|
331
|
+
if (!indices.has(w)) {
|
|
332
|
+
visit(w);
|
|
333
|
+
} else if (onStack.has(w)) {
|
|
334
|
+
lowlink.set(iid, Math.min(lowlink.get(iid), indices.get(w)));
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
// Pop frame.
|
|
338
|
+
callStack.pop();
|
|
339
|
+
if (callStack.length > 0) {
|
|
340
|
+
const parent = callStack[callStack.length - 1];
|
|
341
|
+
lowlink.set(
|
|
342
|
+
parent.iid,
|
|
343
|
+
Math.min(lowlink.get(parent.iid), lowlink.get(iid))
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
// Check if this iid is an SCC root.
|
|
347
|
+
if (lowlink.get(iid) === indices.get(iid)) {
|
|
348
|
+
const scc = [];
|
|
349
|
+
let w;
|
|
350
|
+
do {
|
|
351
|
+
w = stack.pop();
|
|
352
|
+
onStack.delete(w);
|
|
353
|
+
scc.push(w);
|
|
354
|
+
} while (w !== iid);
|
|
355
|
+
if (scc.length > 1) {
|
|
356
|
+
sccs.push(scc.sort((a, b) => a - b));
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
for (const iid of nodeSubset) {
|
|
364
|
+
if (!indices.has(iid)) {
|
|
365
|
+
strongconnect(iid);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Sort by minimum iid in each SCC ascending.
|
|
370
|
+
sccs.sort((a, b) => Math.min(...a) - Math.min(...b));
|
|
371
|
+
return sccs;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
// nextReady
|
|
376
|
+
// ---------------------------------------------------------------------------
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Return the set of issues that are ready to be started next.
|
|
380
|
+
*
|
|
381
|
+
* An issue is considered ready when ALL of the following hold:
|
|
382
|
+
* 1. It is NOT in `inFlight` (already being processed).
|
|
383
|
+
* 2. It is NOT in `completed` (already done).
|
|
384
|
+
* 3. Every iid in its `blockedBy` list is present in `completed`.
|
|
385
|
+
* 4. It carries the label `"status:ready"`.
|
|
386
|
+
*
|
|
387
|
+
* The returned array is sorted by ascending iid.
|
|
388
|
+
*
|
|
389
|
+
* @param {DepGraph} graph - The dependency graph.
|
|
390
|
+
* @param {Set<number>} inFlight - iids currently being processed.
|
|
391
|
+
* @param {Set<number>} completed - iids that have finished successfully.
|
|
392
|
+
* @returns {Issue[]}
|
|
393
|
+
*/
|
|
394
|
+
export function nextReady(graph, inFlight, completed) {
|
|
395
|
+
const safeInFlight = inFlight instanceof Set ? inFlight : new Set();
|
|
396
|
+
const safeCompleted = completed instanceof Set ? completed : new Set();
|
|
397
|
+
|
|
398
|
+
/** @type {Issue[]} */
|
|
399
|
+
const ready = [];
|
|
400
|
+
|
|
401
|
+
for (const [iid, issue] of graph.nodes) {
|
|
402
|
+
if (safeInFlight.has(iid)) continue;
|
|
403
|
+
if (safeCompleted.has(iid)) continue;
|
|
404
|
+
|
|
405
|
+
// All blockers must be completed.
|
|
406
|
+
const blockers = Array.isArray(issue.blockedBy) ? issue.blockedBy : [];
|
|
407
|
+
const allBlockersCompleted = blockers.every((b) => safeCompleted.has(b));
|
|
408
|
+
if (!allBlockersCompleted) continue;
|
|
409
|
+
|
|
410
|
+
// Must carry status:ready label.
|
|
411
|
+
if (!Array.isArray(issue.labels) || !issue.labels.includes('status:ready')) continue;
|
|
412
|
+
|
|
413
|
+
ready.push(issue);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return ready.sort((a, b) => a.iid - b.iid);
|
|
417
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autopilot/durable-telemetry.mjs
|
|
3
|
+
*
|
|
4
|
+
* Framework module per ADR 0003 (Routines Adapter) — wraps telemetry writes
|
|
5
|
+
* with an optional claude/-branch commit so JSONL state survives ephemeral-clone
|
|
6
|
+
* reclamation in cloud execution contexts. Local execution: commit step is a no-op
|
|
7
|
+
* unless `enabled: true` is passed. This is intentional — the module ships as
|
|
8
|
+
* inert framework code; the empirical spike (issue #485 W3 P3) validates the
|
|
9
|
+
* commit path against real Routines fires before wiring it into production paths.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { execSync } from 'node:child_process';
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import { join, resolve } from 'node:path';
|
|
15
|
+
|
|
16
|
+
/** Branch names safe to interpolate into git commands (defense-in-depth; #483 W4-Q5-MED-1). */
|
|
17
|
+
const SAFE_BRANCH_RE = /^[A-Za-z0-9._/-]+$/;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {Object} DurableCommitOptions
|
|
21
|
+
* @property {string} sessionId - session identifier (e.g. main-2026-05-19-deep-3)
|
|
22
|
+
* @property {string} [branch] - target branch (default: `claude/${sessionId}`)
|
|
23
|
+
* @property {string[]} files - relative paths to commit (e.g. ['.orchestrator/metrics/autopilot.jsonl'])
|
|
24
|
+
* @property {string} [message] - commit message; default chore(autopilot)
|
|
25
|
+
* @property {boolean} [enabled=false] - when false, no-op (default local behaviour)
|
|
26
|
+
* @property {boolean} [push=false] - whether to push the branch to origin
|
|
27
|
+
* @property {string} [cwd] - repo root (default: process.cwd())
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Commit a set of telemetry files to a claude/-prefixed branch. When `enabled: false`
|
|
32
|
+
* (default), returns {ok: true, skipped: true} without touching git — local sessions
|
|
33
|
+
* do not need durable-commit behaviour.
|
|
34
|
+
*
|
|
35
|
+
* @param {DurableCommitOptions} opts
|
|
36
|
+
* @returns {Promise<{ok: boolean, skipped?: boolean, sha?: string, branch?: string, error?: string}>}
|
|
37
|
+
*/
|
|
38
|
+
export async function durableCommit(opts) {
|
|
39
|
+
if (!opts || typeof opts !== 'object') {
|
|
40
|
+
return { ok: false, error: 'opts must be an object' };
|
|
41
|
+
}
|
|
42
|
+
const enabled = opts.enabled === true;
|
|
43
|
+
const sessionId = opts.sessionId;
|
|
44
|
+
const files = Array.isArray(opts.files) ? opts.files : [];
|
|
45
|
+
const cwd = opts.cwd || process.cwd();
|
|
46
|
+
|
|
47
|
+
if (!sessionId) return { ok: false, error: 'sessionId required' };
|
|
48
|
+
if (files.length === 0) return { ok: false, error: 'files[] cannot be empty' };
|
|
49
|
+
|
|
50
|
+
if (!enabled) {
|
|
51
|
+
// Local execution path — no-op. Cloud spike wires enabled:true.
|
|
52
|
+
return { ok: true, skipped: true };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const branch = opts.branch || `claude/${sessionId}`;
|
|
56
|
+
const message = opts.message || `chore(autopilot): durable telemetry — ${sessionId}`;
|
|
57
|
+
|
|
58
|
+
// Defense-in-depth (#483 W4-Q5-MED-1): branch name is interpolated into git
|
|
59
|
+
// commands below — reject anything outside the safe charset before execution.
|
|
60
|
+
if (!SAFE_BRANCH_RE.test(branch)) {
|
|
61
|
+
return { ok: false, error: `unsafe branch name rejected: ${branch}` };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// cwd confinement (#483 W4-Q5-MED-2): git ops must run against the current
|
|
65
|
+
// project root unless the caller explicitly opts into a foreign tree.
|
|
66
|
+
const resolvedCwd = resolve(cwd);
|
|
67
|
+
if (resolvedCwd !== resolve(process.cwd()) && opts.allowForeignCwd !== true) {
|
|
68
|
+
return { ok: false, error: `cwd outside project root rejected: ${resolvedCwd}` };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// Ensure target branch exists (create if missing, checkout if exists)
|
|
73
|
+
// NOTE: this is a framework stub — production wiring (cloud spike, W3 P3)
|
|
74
|
+
// must reconcile with the worktree merge-back semantics.
|
|
75
|
+
const branches = execSync('git branch --list', { cwd, encoding: 'utf8' });
|
|
76
|
+
if (!branches.split('\n').some((l) => l.trim().replace(/^\* /, '') === branch)) {
|
|
77
|
+
execSync(`git branch ${JSON.stringify(branch)}`, { cwd });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Stage files individually (PSA-004: never `git add .` or `-A`)
|
|
81
|
+
for (const f of files) {
|
|
82
|
+
const abs = join(cwd, f);
|
|
83
|
+
if (!existsSync(abs)) {
|
|
84
|
+
return { ok: false, error: `file not found: ${f}` };
|
|
85
|
+
}
|
|
86
|
+
execSync(`git add ${JSON.stringify(f)}`, { cwd });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Commit on the target branch via a detached worktree to avoid touching the coordinator's HEAD.
|
|
90
|
+
// Framework stub: in cloud-mode (Routines), the runner is already on the claude/ branch.
|
|
91
|
+
// Local-mode: callers must ensure HEAD is the target branch before calling, OR pass
|
|
92
|
+
// the branch parameter and accept that this stub falls back to staging-only.
|
|
93
|
+
const commitOut = execSync(
|
|
94
|
+
`git commit -m ${JSON.stringify(message)} --allow-empty`,
|
|
95
|
+
{ cwd, encoding: 'utf8' }
|
|
96
|
+
);
|
|
97
|
+
const sha = commitOut.match(/\b[0-9a-f]{7,}\b/)?.[0] || 'unknown';
|
|
98
|
+
|
|
99
|
+
if (opts.push) {
|
|
100
|
+
execSync(`git push origin ${JSON.stringify(branch)}`, { cwd });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return { ok: true, sha, branch };
|
|
104
|
+
} catch (err) {
|
|
105
|
+
return { ok: false, error: err?.message || String(err) };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Convenience: wrap a telemetry-file write with durable-commit semantics.
|
|
111
|
+
* Local execution: write happens, commit is no-op (returns {ok:true, skipped:true}).
|
|
112
|
+
* Cloud execution: write happens, commit fires on `claude/<sessionId>` branch.
|
|
113
|
+
*
|
|
114
|
+
* @param {() => Promise<void> | void} writeFn - the underlying telemetry write
|
|
115
|
+
* @param {DurableCommitOptions} opts
|
|
116
|
+
* @returns {Promise<{ok: boolean, skipped?: boolean, sha?: string, branch?: string, error?: string}>}
|
|
117
|
+
*/
|
|
118
|
+
export async function withDurableCommit(writeFn, opts) {
|
|
119
|
+
await writeFn();
|
|
120
|
+
return durableCommit(opts);
|
|
121
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autopilot/flags.mjs — Flag parsing and bounds constants for the autopilot loop.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from autopilot.mjs as part of the W1A6 decomposition.
|
|
5
|
+
* Leaf module: no imports from other autopilot submodules.
|
|
6
|
+
*
|
|
7
|
+
* Exports:
|
|
8
|
+
* FLAG_BOUNDS — frozen bounds+defaults for numeric CLI flags
|
|
9
|
+
* DEFAULT_PEER_ABORT_THRESHOLD
|
|
10
|
+
* DEFAULT_JSONL_PATH
|
|
11
|
+
* DEFAULT_CARRYOVER_THRESHOLD
|
|
12
|
+
* parseFlags(argv) — silent-clamp argv → opts object
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Constants
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
export const FLAG_BOUNDS = Object.freeze({
|
|
20
|
+
maxSessions: { min: 1, max: 50, default: 5 },
|
|
21
|
+
maxHours: { min: 0.5, max: 24.0, default: 4.0 },
|
|
22
|
+
confidenceThreshold: { min: 0.0, max: 1.0, default: 0.85 },
|
|
23
|
+
maxTokens: { min: 0, max: 10_000_000, default: 500_000 },
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
/** Default peer Claude-process count above which `resource-overload` fires when verdict is critical. */
|
|
27
|
+
export const DEFAULT_PEER_ABORT_THRESHOLD = 6;
|
|
28
|
+
|
|
29
|
+
/** Default JSONL path for autopilot loop records. */
|
|
30
|
+
export const DEFAULT_JSONL_PATH = '.orchestrator/metrics/autopilot.jsonl';
|
|
31
|
+
|
|
32
|
+
/** Default carryover ratio threshold above which `carryover-too-high` fires post-session. */
|
|
33
|
+
export const DEFAULT_CARRYOVER_THRESHOLD = 0.5;
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Internal helpers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
function clampNumber(value, { min, max, fallback }) {
|
|
40
|
+
if (typeof value !== 'number' || Number.isNaN(value)) return fallback;
|
|
41
|
+
if (value < min) return min;
|
|
42
|
+
if (value > max) return max;
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function parseNumeric(raw) {
|
|
47
|
+
if (raw === undefined || raw === null) return null;
|
|
48
|
+
const n = Number(raw);
|
|
49
|
+
return Number.isFinite(n) ? n : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Flag parsing
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parse `/autopilot` argv into an opts object. Out-of-range numeric flags clamp
|
|
58
|
+
* silently to bounds. Unknown flags are ignored. `--dry-run` is a boolean flag.
|
|
59
|
+
*
|
|
60
|
+
* @param {string[]} argv — argument tokens (e.g. ['--max-sessions=3', '--dry-run'])
|
|
61
|
+
* @returns {{maxSessions: number, maxHours: number, confidenceThreshold: number, dryRun: boolean}}
|
|
62
|
+
*/
|
|
63
|
+
export function parseFlags(argv) {
|
|
64
|
+
const tokens = Array.isArray(argv) ? argv : [];
|
|
65
|
+
|
|
66
|
+
let rawSessions = null;
|
|
67
|
+
let rawHours = null;
|
|
68
|
+
let rawConfidence = null;
|
|
69
|
+
let dryRun = false;
|
|
70
|
+
|
|
71
|
+
for (const tok of tokens) {
|
|
72
|
+
if (typeof tok !== 'string') continue;
|
|
73
|
+
if (tok === '--dry-run' || tok === '--dryRun') {
|
|
74
|
+
dryRun = true;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const eq = tok.indexOf('=');
|
|
78
|
+
if (eq === -1) continue;
|
|
79
|
+
const key = tok.slice(0, eq);
|
|
80
|
+
const val = tok.slice(eq + 1);
|
|
81
|
+
if (key === '--max-sessions') rawSessions = parseNumeric(val);
|
|
82
|
+
else if (key === '--max-hours') rawHours = parseNumeric(val);
|
|
83
|
+
else if (key === '--confidence-threshold') rawConfidence = parseNumeric(val);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
maxSessions: Math.floor(clampNumber(rawSessions, {
|
|
88
|
+
min: FLAG_BOUNDS.maxSessions.min,
|
|
89
|
+
max: FLAG_BOUNDS.maxSessions.max,
|
|
90
|
+
fallback: FLAG_BOUNDS.maxSessions.default,
|
|
91
|
+
})),
|
|
92
|
+
maxHours: clampNumber(rawHours, {
|
|
93
|
+
min: FLAG_BOUNDS.maxHours.min,
|
|
94
|
+
max: FLAG_BOUNDS.maxHours.max,
|
|
95
|
+
fallback: FLAG_BOUNDS.maxHours.default,
|
|
96
|
+
}),
|
|
97
|
+
confidenceThreshold: clampNumber(rawConfidence, {
|
|
98
|
+
min: FLAG_BOUNDS.confidenceThreshold.min,
|
|
99
|
+
max: FLAG_BOUNDS.confidenceThreshold.max,
|
|
100
|
+
fallback: FLAG_BOUNDS.confidenceThreshold.default,
|
|
101
|
+
}),
|
|
102
|
+
dryRun,
|
|
103
|
+
};
|
|
104
|
+
}
|