mandrel 1.94.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/README.md +116 -99
- package/.agents/agents/acceptance-critic.md +9 -7
- package/.agents/agents/story-worker.md +45 -51
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +498 -1287
- package/.agents/docs/agentrc-reference.json +185 -80
- package/.agents/docs/configuration.md +132 -190
- package/.agents/docs/execution-reference.md +51 -25
- package/.agents/docs/quality-gates.md +25 -33
- package/.agents/docs/workflows.md +8 -8
- package/.agents/instructions.md +113 -139
- package/.agents/rules/ci-remediation.md +11 -15
- package/.agents/rules/git-conventions-reference.md +48 -58
- package/.agents/rules/git-conventions.md +16 -22
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +83 -254
- package/.agents/schemas/audit-rules.json +59 -1
- package/.agents/schemas/audit-rules.schema.json +33 -1
- package/.agents/schemas/lifecycle/README.md +1 -2
- package/.agents/schemas/lifecycle/ledger-record.schema.json +1 -1
- package/.agents/schemas/lifecycle/merge.flip-failed.schema.json +33 -0
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +1 -0
- package/.agents/schemas/lifecycle/retro.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.merged.schema.json +1 -1
- package/.agents/schemas/signal-event.schema.json +3 -3
- package/.agents/schemas/story-deliver-terminal.schema.json +152 -0
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +22 -66
- package/.agents/scripts/agents-bootstrap-github.js +1 -1
- package/.agents/scripts/audit-to-stories.js +7 -7
- package/.agents/scripts/boot-sweep.js +1 -1
- package/.agents/scripts/bootstrap.js +3 -3
- package/.agents/scripts/check-dead-exports.js +43 -104
- package/.agents/scripts/check-doc-links.js +2 -2
- package/.agents/scripts/check-lifecycle-lint.js +7 -10
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- package/.agents/scripts/cleanup-repo-test-temp.js +6 -1
- package/.agents/scripts/deliver-recover.js +122 -0
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +20 -50
- package/.agents/scripts/generate-skills-index.js +17 -1
- package/.agents/scripts/generate-workflows-doc.js +4 -4
- package/.agents/scripts/lib/ITicketingProvider.js +1 -19
- package/.agents/scripts/lib/Logger.js +6 -10
- package/.agents/scripts/lib/audit-suite/runner.js +2 -2
- package/.agents/scripts/lib/audit-suite/selector.js +328 -28
- package/.agents/scripts/lib/audit-to-stories/{seed-epic-from-findings.js → seed-from-findings.js} +9 -9
- package/.agents/scripts/lib/baselines/kernel.js +206 -18
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -15
- package/.agents/scripts/lib/baselines/reader.js +1 -6
- package/.agents/scripts/lib/bdd-runner-detect.js +5 -9
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -33
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +32 -33
- package/.agents/scripts/lib/bootstrap/manifest.js +8 -11
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +30 -53
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +0 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +6 -3
- package/.agents/scripts/lib/checks/index.js +3 -2
- package/.agents/scripts/lib/checks/loop-health.js +12 -11
- package/.agents/scripts/lib/checks/state.js +17 -248
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +26 -24
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +3 -4
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +2 -2
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +3 -3
- package/.agents/scripts/lib/cli/standard-args.js +13 -22
- package/.agents/scripts/lib/cli-args.js +39 -9
- package/.agents/scripts/lib/close-validation/gates.js +15 -15
- package/.agents/scripts/lib/close-validation/projections/inputs.js +7 -7
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +12 -12
- package/.agents/scripts/lib/close-validation/runner.js +13 -21
- package/.agents/scripts/lib/close-validation/telemetry.js +17 -8
- package/.agents/scripts/lib/config/ci.js +6 -31
- package/.agents/scripts/lib/config/delivery-routing.js +52 -35
- package/.agents/scripts/lib/config/explain.js +61 -48
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +29 -80
- package/.agents/scripts/lib/config/paths.js +0 -2
- package/.agents/scripts/lib/config/quality.js +12 -15
- package/.agents/scripts/lib/config/runners.js +20 -66
- package/.agents/scripts/lib/config/temp-paths.js +30 -63
- package/.agents/scripts/lib/config/worktree-isolation.js +0 -5
- package/.agents/scripts/lib/config-resolver.js +2 -7
- package/.agents/scripts/lib/config-settings-schema-delivery.js +55 -161
- package/.agents/scripts/lib/config-settings-schema-quality.js +17 -16
- package/.agents/scripts/lib/config-settings-schema.js +100 -60
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/dependency-parser.js +3 -2
- package/.agents/scripts/lib/doc-tiers.js +2 -2
- package/.agents/scripts/lib/duplicate-search.js +242 -41
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +23 -14
- package/.agents/scripts/lib/format-generated-json.js +97 -0
- package/.agents/scripts/lib/framework-version.js +19 -190
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-cleanup.js +1 -10
- package/.agents/scripts/lib/git-branch-lifecycle.js +17 -180
- package/.agents/scripts/lib/git-utils.js +32 -20
- package/.agents/scripts/lib/github/framework-repo.js +6 -0
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +10 -38
- package/.agents/scripts/lib/label-taxonomy.js +10 -55
- package/.agents/scripts/lib/observability/active-story-env.js +44 -165
- package/.agents/scripts/lib/observability/runtime-friction.js +243 -0
- package/.agents/scripts/lib/observability/signal-validator.js +4 -4
- package/.agents/scripts/lib/observability/signals-writer.js +6 -82
- package/.agents/scripts/lib/observability/source-classifier.js +5 -5
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- package/.agents/scripts/lib/onboard/init-tail.js +1 -3
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +1 -1
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +2 -2
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +105 -44
- package/.agents/scripts/lib/orchestration/code-review.js +78 -436
- package/.agents/scripts/lib/orchestration/column-sync.js +1 -1
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +4 -4
- package/.agents/scripts/lib/orchestration/context-envelope.js +2 -5
- package/.agents/scripts/lib/orchestration/deliver-recover.js +328 -0
- package/.agents/scripts/lib/orchestration/detectors-phase.js +12 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +8 -8
- package/.agents/scripts/lib/orchestration/file-assumptions.js +7 -13
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +1 -1
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +34 -0
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -2
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +142 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +17 -19
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +86 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +37 -103
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +6 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +21 -43
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +50 -85
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +3 -14
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +4 -4
- package/.agents/scripts/lib/orchestration/merge-block-class.js +77 -21
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/phase-runner.js +3 -2
- package/.agents/scripts/lib/orchestration/plan-context.js +354 -282
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +11 -22
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +4 -8
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-navigation.js +92 -0
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +71 -0
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +245 -0
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +432 -858
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +778 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +47 -115
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-reachability.js +9 -14
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +1 -1
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/authoring-context.js +52 -51
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +27 -0
- package/.agents/scripts/lib/orchestration/{epic-plan-spec/phases → planning}/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +18 -28
- package/.agents/scripts/lib/orchestration/remote-verifier.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/resolves-token.js +1 -1
- package/.agents/scripts/lib/orchestration/retro-proposals.js +140 -79
- package/.agents/scripts/lib/orchestration/review-depth.js +126 -47
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +3 -13
- package/.agents/scripts/lib/orchestration/review-providers/native.js +1 -154
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +3 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +21 -56
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/types.js +5 -4
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +1 -1
- package/.agents/scripts/lib/orchestration/run-epilogue.js +784 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +25 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +11 -9
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +4 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +86 -41
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +608 -152
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +77 -32
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +305 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +44 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +37 -4
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +275 -46
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-freshness.js +14 -205
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +4 -5
- package/.agents/scripts/lib/orchestration/spec-spill.js +60 -0
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +188 -0
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +49 -0
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +28 -42
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +298 -0
- package/.agents/scripts/lib/orchestration/story-init-remote.js +51 -0
- package/.agents/scripts/lib/orchestration/story-plan-state.js +33 -0
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +1 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +60 -25
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +130 -75
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +192 -377
- package/.agents/scripts/lib/orchestration/ticket-validator.js +123 -25
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -72
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +45 -55
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +66 -6
- package/.agents/scripts/lib/orchestration/ticketing.js +0 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +12 -14
- package/.agents/scripts/lib/planning-corpus.js +12 -281
- package/.agents/scripts/lib/preflight-runner.js +4 -4
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -5
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +5 -5
- package/.agents/scripts/lib/signals/index.js +4 -17
- package/.agents/scripts/lib/signals/read.js +35 -35
- package/.agents/scripts/lib/signals/schema.js +8 -11
- package/.agents/scripts/lib/signals/span-tree.js +7 -7
- package/.agents/scripts/lib/signals/write.js +0 -1
- package/.agents/scripts/lib/single-story/story-merged-notify.js +13 -2
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +1 -1
- package/.agents/scripts/lib/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +17 -19
- package/.agents/scripts/lib/story-body/story-body.js +130 -75
- package/.agents/scripts/lib/story-plan.js +2 -4
- package/.agents/scripts/lib/templates/decomposer-prompts.js +51 -46
- package/.agents/scripts/lib/templates/spec-author-prompts.js +47 -45
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/{epic-body-sections.js → ticket-body-sections.js} +25 -39
- package/.agents/scripts/lib/validation-evidence.js +32 -60
- package/.agents/scripts/lib/wave-runner/ready-set.js +38 -12
- package/.agents/scripts/lib/workspace-provisioner.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +72 -25
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/lint-issue-body.js +71 -40
- package/.agents/scripts/mandrel-update-preflight.js +1 -1
- package/.agents/scripts/notify.js +4 -3
- package/.agents/scripts/plan-context.js +102 -80
- package/.agents/scripts/plan-persist.js +230 -279
- package/.agents/scripts/plan-run-epilogue.js +142 -0
- package/.agents/scripts/post-structured-comment.js +0 -38
- package/.agents/scripts/pr-watch-with-update.js +43 -22
- package/.agents/scripts/providers/github/compose.js +0 -1
- package/.agents/scripts/providers/github/errors.js +0 -19
- package/.agents/scripts/providers/github/issues.js +13 -39
- package/.agents/scripts/providers/github/mappers.js +5 -12
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -156
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/resolve-stories.js +236 -0
- package/.agents/scripts/run-coverage.js +4 -1
- package/.agents/scripts/run-lint.js +2 -2
- package/.agents/scripts/run-verify.js +31 -2
- package/.agents/scripts/signals-view.js +25 -21
- package/.agents/scripts/single-story-close.js +178 -26
- package/.agents/scripts/single-story-confirm-merge.js +313 -24
- package/.agents/scripts/single-story-init.js +35 -30
- package/.agents/scripts/stories-wave-tick.js +85 -10
- package/.agents/scripts/story-plan.js +28 -49
- package/.agents/scripts/update-ticket-state.js +14 -65
- package/.agents/skills/core/code-review-and-quality/SKILL.md +28 -450
- package/.agents/skills/core/code-review-and-quality/reference.md +458 -0
- package/.agents/skills/core/debugging-and-error-recovery/SKILL.md +22 -315
- package/.agents/skills/core/debugging-and-error-recovery/reference.md +323 -0
- package/.agents/skills/core/diagnose-friction/SKILL.md +14 -18
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +25 -397
- package/.agents/skills/core/documentation-and-adrs/reference.md +403 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +12 -12
- package/.agents/skills/core/idea-refinement/SKILL.md +9 -9
- package/.agents/skills/core/scope-triage/SKILL.md +31 -172
- package/.agents/skills/core/security-and-hardening/SKILL.md +22 -367
- package/.agents/skills/core/security-and-hardening/reference.md +375 -0
- package/.agents/skills/skills.index.json +3 -53
- package/.agents/skills/stack/qa/playwright-bdd/SKILL.md +2 -4
- package/.agents/skills/stack/qa/qa-explore-driving/SKILL.md +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -3
- package/.agents/starter-agentrc.json +0 -5
- package/.agents/templates/agent-protocol.md +9 -10
- package/.agents/workflows/audit-architecture.md +6 -7
- package/.agents/workflows/audit-clean-code.md +7 -7
- package/.agents/workflows/audit-dependencies.md +3 -3
- package/.agents/workflows/audit-devops.md +3 -3
- package/.agents/workflows/audit-documentation.md +9 -10
- package/.agents/workflows/audit-lighthouse.md +11 -3
- package/.agents/workflows/audit-navigability.md +13 -2
- package/.agents/workflows/audit-performance.md +5 -6
- package/.agents/workflows/audit-privacy.md +3 -3
- package/.agents/workflows/audit-quality.md +11 -12
- package/.agents/workflows/audit-security.md +4 -5
- package/.agents/workflows/audit-seo.md +13 -3
- package/.agents/workflows/audit-sre.md +3 -3
- package/.agents/workflows/audit-to-stories.md +20 -20
- package/.agents/workflows/audit-ux-ui.md +10 -3
- package/.agents/workflows/deliver.md +177 -176
- package/.agents/workflows/git-cleanup.md +5 -6
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +35 -40
- package/.agents/workflows/helpers/code-quality-guardrails.md +7 -7
- package/.agents/workflows/helpers/code-review.md +75 -196
- package/.agents/workflows/helpers/{single-story-deliver-reference.md → deliver-story-reference.md} +83 -44
- package/.agents/workflows/helpers/deliver-story.md +606 -0
- package/.agents/workflows/helpers/diagnose.md +10 -10
- package/.agents/workflows/helpers/parallel-tooling.md +3 -3
- package/.agents/workflows/helpers/signals.md +16 -16
- package/.agents/workflows/helpers/worktree-lifecycle.md +66 -86
- package/.agents/workflows/mandrel-update.md +2 -1
- package/.agents/workflows/plan.md +277 -145
- package/.agents/workflows/qa-assist.md +27 -33
- package/.agents/workflows/qa-explore.md +29 -38
- package/.agents/workflows/qa-run.md +2 -6
- package/README.md +9 -8
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +70 -0
- package/lib/cli/registry.js +262 -19
- package/lib/cli/sync-agents.js +157 -0
- package/lib/cli/sync-commands.js +115 -6
- package/lib/cli/sync.js +168 -6
- package/lib/cli/update.js +105 -8
- package/lib/cli/version-helpers.js +131 -0
- package/lib/migrations/README.md +7 -5
- package/lib/migrations/index.js +12 -8
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +100 -0
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +101 -0
- package/package.json +2 -2
- package/.agents/agents/retro.md +0 -42
- package/.agents/personas/architect.md +0 -113
- package/.agents/personas/devops-engineer.md +0 -38
- package/.agents/personas/engineer.md +0 -33
- package/.agents/personas/project-manager.md +0 -114
- package/.agents/personas/qa-engineer.md +0 -95
- package/.agents/personas/security-engineer.md +0 -111
- package/.agents/personas/technical-writer.md +0 -101
- package/.agents/schemas/dispatch-manifest.json +0 -232
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- package/.agents/schemas/epic-spec.schema.json +0 -153
- package/.agents/schemas/lifecycle/acceptance.reconcile.failed.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.ok.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.skipped.schema.json +0 -13
- package/.agents/schemas/lifecycle/acceptance.reconcile.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/acceptance.reconcile.waived.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.automerge.end.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.automerge.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.cleanup.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.cleanup.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.close.end.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.complete.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.end.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.finalize.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.merge.armed.schema.json +0 -13
- package/.agents/schemas/lifecycle/epic.merge.blocked.schema.json +0 -14
- package/.agents/schemas/lifecycle/epic.merge.confirmed.schema.json +0 -17
- package/.agents/schemas/lifecycle/epic.merge.ready.schema.json +0 -15
- package/.agents/schemas/lifecycle/epic.plan.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/epic.plan.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.snapshot.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/epic.snapshot.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/epic.watch.end.schema.json +0 -29
- package/.agents/schemas/lifecycle/epic.watch.start.schema.json +0 -16
- package/.agents/schemas/lifecycle/slice.end.schema.json +0 -21
- package/.agents/schemas/lifecycle/slice.heartbeat.schema.json +0 -20
- package/.agents/schemas/lifecycle/slice.start.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -66
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/acceptance-spec-reconciler.js +0 -642
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/bookkeeping-reconcile.js +0 -117
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- package/.agents/scripts/dispatcher.js +0 -295
- package/.agents/scripts/epic-audit-prepare.js +0 -497
- package/.agents/scripts/epic-audit-recheck.js +0 -274
- package/.agents/scripts/epic-deliver-note-intervention.js +0 -192
- package/.agents/scripts/epic-deliver-preflight.js +0 -462
- package/.agents/scripts/epic-deliver-prepare.js +0 -852
- package/.agents/scripts/epic-execute-record-wave.js +0 -449
- package/.agents/scripts/epic-plan-clarity.js +0 -211
- package/.agents/scripts/epic-plan-healthcheck.js +0 -581
- package/.agents/scripts/epic-reconcile.js +0 -625
- package/.agents/scripts/lib/baseline-snapshot.js +0 -979
- package/.agents/scripts/lib/checks/epic-merge-lock-stale.js +0 -54
- package/.agents/scripts/lib/checks/stale-origin-epic.js +0 -49
- package/.agents/scripts/lib/config/lifecycle.js +0 -40
- package/.agents/scripts/lib/config/preflight.js +0 -58
- package/.agents/scripts/lib/config/retro.js +0 -77
- package/.agents/scripts/lib/epic-merge-lock.js +0 -322
- package/.agents/scripts/lib/epic-plan-clarity.js +0 -181
- package/.agents/scripts/lib/epic-plan-ideation.js +0 -261
- package/.agents/scripts/lib/git-merge-orchestrator.js +0 -261
- package/.agents/scripts/lib/observability/baseline-refresh-rate.js +0 -221
- package/.agents/scripts/lib/observability/hook-heartbeat.js +0 -219
- package/.agents/scripts/lib/observability/perf-aggregator.js +0 -813
- package/.agents/scripts/lib/observability/perf-report-readers.js +0 -328
- package/.agents/scripts/lib/observability/perf-report-render.js +0 -182
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -270
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +0 -539
- package/.agents/scripts/lib/orchestration/deliver-route.js +0 -173
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +0 -134
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +0 -183
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +0 -801
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +0 -310
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/context.js +0 -163
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +0 -140
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +0 -64
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +0 -72
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist-helpers.js +0 -156
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/persist.js +0 -345
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/planning-artifacts.js +0 -41
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/reconcile-spawn.js +0 -86
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +0 -391
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/drain.js +0 -94
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +0 -236
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/risk-verdict.js +0 -105
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +0 -307
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/spec-freshness.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +0 -621
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +0 -186
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +0 -50
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +0 -129
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +0 -103
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +0 -267
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +0 -210
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +0 -238
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/_bullet-format.js +0 -32
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/component-drift.js +0 -203
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/crap-drift.js +0 -227
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/maintainability-drift.js +0 -117
- package/.agents/scripts/lib/orchestration/epic-runner/progress-signals/stalled-worktree.js +0 -37
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +0 -127
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +0 -276
- package/.agents/scripts/lib/orchestration/epic-runner/wave-scheduler.js +0 -66
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +0 -789
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +0 -676
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-discriminator.js +0 -389
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-format.js +0 -230
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +0 -361
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +0 -306
- package/.agents/scripts/lib/orchestration/finalize/post-handoff-comment.js +0 -489
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +0 -88
- package/.agents/scripts/lib/orchestration/lifecycle/emit-slice-lifecycle.js +0 -270
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +0 -147
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +0 -155
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-diff.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/acceptance-reconciler.js +0 -465
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +0 -501
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +0 -984
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +0 -264
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/checkpoint-pointer-writer.js +0 -284
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/cleaner.js +0 -355
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +0 -673
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +0 -378
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/intervention-recorder.js +0 -140
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +0 -144
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +0 -174
- package/.agents/scripts/lib/orchestration/manifest-builder.js +0 -222
- package/.agents/scripts/lib/orchestration/plan-persist/amend.js +0 -359
- package/.agents/scripts/lib/orchestration/plan-persist/delivery-mode.js +0 -127
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning-context-budget.js +0 -213
- package/.agents/scripts/lib/orchestration/planning-risk.js +0 -194
- package/.agents/scripts/lib/orchestration/post-merge/phases/branch-cleanup.js +0 -56
- package/.agents/scripts/lib/orchestration/post-merge/phases/dashboard-refresh.js +0 -33
- package/.agents/scripts/lib/orchestration/post-merge/phases/notification.js +0 -78
- package/.agents/scripts/lib/orchestration/post-merge/phases/temp-cleanup.js +0 -68
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +0 -118
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +0 -396
- package/.agents/scripts/lib/orchestration/post-merge-pipeline.js +0 -205
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +0 -152
- package/.agents/scripts/lib/orchestration/retro/phases/checks.js +0 -94
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +0 -571
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +0 -450
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +0 -191
- package/.agents/scripts/lib/orchestration/retro-heuristics.js +0 -57
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/retro-runner.js +0 -197
- package/.agents/scripts/lib/orchestration/spec-renderer.js +0 -447
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +0 -747
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/gate-failure.js +0 -211
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/pre-merge-attribution.js +0 -158
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/refresh-commit.js +0 -446
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/regression-projection.js +0 -297
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution/phases/scope-discovery.js +0 -48
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution-wiring.js +0 -67
- package/.agents/scripts/lib/orchestration/story-close/baseline-attribution.js +0 -161
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +0 -117
- package/.agents/scripts/lib/orchestration/story-close/cd-out-guard.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/cleanup-reconciler.js +0 -147
- package/.agents/scripts/lib/orchestration/story-close/close-inputs.js +0 -142
- package/.agents/scripts/lib/orchestration/story-close/comment-bodies.js +0 -62
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +0 -658
- package/.agents/scripts/lib/orchestration/story-close/merge-subject.js +0 -198
- package/.agents/scripts/lib/orchestration/story-close/phases/branch-restore.js +0 -105
- package/.agents/scripts/lib/orchestration/story-close/phases/close.js +0 -222
- package/.agents/scripts/lib/orchestration/story-close/phases/gates.js +0 -292
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +0 -270
- package/.agents/scripts/lib/orchestration/story-close/phases/preflight.js +0 -110
- package/.agents/scripts/lib/orchestration/story-close/phases/refresh.js +0 -86
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked-emitter.js +0 -112
- package/.agents/scripts/lib/orchestration/story-close/phases/timeout-blocked.js +0 -157
- package/.agents/scripts/lib/orchestration/story-close/post-merge-close.js +0 -421
- package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +0 -302
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +0 -163
- package/.agents/scripts/lib/orchestration/story-close-recovery.js +0 -690
- package/.agents/scripts/lib/orchestration/wave-marker.js +0 -28
- package/.agents/scripts/lib/orchestration/wave-record-io.js +0 -218
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +0 -145
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +0 -212
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +0 -111
- package/.agents/scripts/lib/presentation/manifest-builder.js +0 -239
- package/.agents/scripts/lib/presentation/manifest-formatter.js +0 -242
- package/.agents/scripts/lib/presentation/manifest-helpers.js +0 -213
- package/.agents/scripts/lib/presentation/manifest-persistence.js +0 -261
- package/.agents/scripts/lib/presentation/manifest-procedures.js +0 -55
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +0 -306
- package/.agents/scripts/lib/presentation/manifest-renderer.js +0 -188
- package/.agents/scripts/lib/presentation/manifest-story-views.js +0 -110
- package/.agents/scripts/lib/push-epic-retry.js +0 -209
- package/.agents/scripts/lib/spec/index.js +0 -36
- package/.agents/scripts/lib/spec/loader.js +0 -425
- package/.agents/scripts/lib/spec/state.js +0 -208
- package/.agents/scripts/lib/story-init/blocker-validator.js +0 -68
- package/.agents/scripts/lib/story-init/branch-initializer.js +0 -408
- package/.agents/scripts/lib/story-init/context-resolver.js +0 -92
- package/.agents/scripts/lib/story-init/donor-precheck.js +0 -207
- package/.agents/scripts/lib/story-init/state-transitioner.js +0 -80
- package/.agents/scripts/lib/story-init/task-graph-builder.js +0 -124
- package/.agents/scripts/lib/story-init/transition-summary.js +0 -34
- package/.agents/scripts/lib/test-reserved-epic-temp-ids.js +0 -35
- package/.agents/scripts/lib/wave-runner/tick.js +0 -754
- package/.agents/scripts/lib/wave-runner/wave-runner-error.js +0 -20
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +0 -194
- package/.agents/scripts/lifecycle-emit.js +0 -510
- package/.agents/scripts/retro-run.js +0 -218
- package/.agents/scripts/slice-phase.js +0 -361
- package/.agents/scripts/standalone-feedback-rollup.js +0 -188
- package/.agents/scripts/story-close.js +0 -294
- package/.agents/scripts/story-init.js +0 -599
- package/.agents/scripts/story-phase.js +0 -369
- package/.agents/scripts/wave-tick.js +0 -464
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -98
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +0 -172
- package/.agents/skills/core/epic-plan-consolidate/examples.md +0 -51
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +0 -441
- package/.agents/skills/core/epic-plan-decompose-author/examples.md +0 -47
- package/.agents/skills/core/epic-plan-premortem/SKILL.md +0 -146
- package/.agents/skills/core/epic-plan-premortem/examples.md +0 -53
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +0 -383
- package/.agents/skills/core/epic-plan-spec-author/examples.md +0 -91
- package/.agents/workflows/helpers/deliver-epic-reference.md +0 -547
- package/.agents/workflows/helpers/deliver-epic-single.md +0 -331
- package/.agents/workflows/helpers/deliver-epic.md +0 -998
- package/.agents/workflows/helpers/deliver-stories.md +0 -450
- package/.agents/workflows/helpers/epic-audit.md +0 -189
- package/.agents/workflows/helpers/epic-deliver-story.md +0 -436
- package/.agents/workflows/helpers/epic-testing.md +0 -125
- package/.agents/workflows/helpers/plan-epic-reference.md +0 -160
- package/.agents/workflows/helpers/plan-epic.md +0 -353
- package/.agents/workflows/helpers/plan-story.md +0 -251
- package/.agents/workflows/helpers/scope-triage-gate.md +0 -108
- package/.agents/workflows/helpers/single-story-deliver.md +0 -557
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// lib/cli/sync-agents.js
|
|
2
|
+
/**
|
|
3
|
+
* `mandrel sync-agents` subcommand (Story #4528 / #4530).
|
|
4
|
+
*
|
|
5
|
+
* Thin wrapper that delegates to the canonical sync script
|
|
6
|
+
* (.agents/scripts/sync-claude-agents.js), projecting `.agents/agents/` into
|
|
7
|
+
* a flat `.claude/agents/` tree. Exact sibling of `sync-commands.js` —
|
|
8
|
+
* same delegation shape, same marker-gated refusal check, same seams —
|
|
9
|
+
* targeting the role-agent tree instead of the command tree. The sync
|
|
10
|
+
* script owns all sync logic; this module exists only to expose it through
|
|
11
|
+
* the mandrel CLI surface without reimplementing it.
|
|
12
|
+
*
|
|
13
|
+
* `sync-claude-agents.js` uses top-level await and has no exported `main()`
|
|
14
|
+
* function (marked `cli-opt-out`), so delegation runs via a child process
|
|
15
|
+
* rather than a direct import. Exit code and all output are forwarded
|
|
16
|
+
* verbatim to the caller so `mandrel sync-agents` is transparent to scripts
|
|
17
|
+
* that check $?.
|
|
18
|
+
*
|
|
19
|
+
* ## Prior to this Story
|
|
20
|
+
*
|
|
21
|
+
* `sync-claude-agents.js` was invoked on the **bootstrap** path
|
|
22
|
+
* (`project-bootstrap.js`'s `sync:agents` script, `prepare`, and
|
|
23
|
+
* `runSyncCommands`) but had no `lib/cli/` subcommand counterpart and was
|
|
24
|
+
* never run by `mandrel sync` / `mandrel update` on the CLI path — the gap
|
|
25
|
+
* #4528 reported. See `update.js`'s `driftHealSteps()` /
|
|
26
|
+
* `fullUpgradeSteps()`, which now spawn a `sync-agents` phase alongside
|
|
27
|
+
* `sync-commands` so `.claude/agents/` materializes on that path too.
|
|
28
|
+
*
|
|
29
|
+
* ## Marker-gated refusal (Story #4526 / #4530) — same shape as sync-commands
|
|
30
|
+
*
|
|
31
|
+
* Before delegating, this wrapper checks whether the `.agents/` tree it is
|
|
32
|
+
* about to project agents FROM actually matches the running CLI's own
|
|
33
|
+
* payload version, exactly as `sync-commands.js` does for the command tree.
|
|
34
|
+
* See that module's doc comment for the full rationale and the anchor-trap
|
|
35
|
+
* warning — it applies identically here (`PROJECT_ROOT` is deliberately the
|
|
36
|
+
* package root, used only to read the running CLI's OWN version; the marker
|
|
37
|
+
* read is anchored at `cwd()`, never at `PROJECT_ROOT`).
|
|
38
|
+
*
|
|
39
|
+
* Gate order:
|
|
40
|
+
* 1. Marker present (`.agents/.mandrel-version`) → compare it to the
|
|
41
|
+
* running CLI's own package version. Mismatch → refuse.
|
|
42
|
+
* 2. Marker absent (a pre-marker install) → fall back to the existing
|
|
43
|
+
* `agents-drift` content-hash check. Drift detected → refuse.
|
|
44
|
+
* 3. Clean either way → project as before.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
import { spawnSync } from 'node:child_process';
|
|
48
|
+
import nodeFs from 'node:fs';
|
|
49
|
+
import path from 'node:path';
|
|
50
|
+
import { fileURLToPath } from 'node:url';
|
|
51
|
+
|
|
52
|
+
import { runAgentsDrift } from './registry.js';
|
|
53
|
+
import { readVersionMarker } from './sync.js';
|
|
54
|
+
|
|
55
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
56
|
+
// lib/cli/ → lib/ → project root
|
|
57
|
+
const PROJECT_ROOT = path.resolve(__dirname, '..', '..');
|
|
58
|
+
const SYNC_SCRIPT = path.join(
|
|
59
|
+
PROJECT_ROOT,
|
|
60
|
+
'.agents',
|
|
61
|
+
'scripts',
|
|
62
|
+
'sync-claude-agents.js',
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the running CLI's own package version from `PROJECT_ROOT`'s
|
|
67
|
+
* `package.json`. See `sync-commands.js`'s "anchor trap" module doc: this is
|
|
68
|
+
* the ONE place `PROJECT_ROOT` (the package's own two-dirs-up root) is the
|
|
69
|
+
* correct anchor.
|
|
70
|
+
*
|
|
71
|
+
* @param {typeof nodeFs} fsImpl
|
|
72
|
+
* @returns {string}
|
|
73
|
+
*/
|
|
74
|
+
function resolveOwnPackageVersion(fsImpl) {
|
|
75
|
+
const parsed = JSON.parse(
|
|
76
|
+
fsImpl.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf8'),
|
|
77
|
+
);
|
|
78
|
+
return String(parsed.version);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Run the sync-claude-agents script and forward its output + exit code —
|
|
83
|
+
* unless the marker-gated refusal check (see module doc) finds the
|
|
84
|
+
* `.agents/` tree mismatched against the running CLI, in which case it
|
|
85
|
+
* refuses and exits non-zero before spawning anything.
|
|
86
|
+
*
|
|
87
|
+
* Injectable seams — identical shape to `sync-commands.js`:
|
|
88
|
+
* - `runner` — replaces `spawnSync` for the real delegation.
|
|
89
|
+
* - `cwd()` — replaces `process.cwd`; anchors the marker read at the
|
|
90
|
+
* consumer project root.
|
|
91
|
+
* - `fs` — replaces the `node:fs` surface for both the marker read and the
|
|
92
|
+
* own-version read.
|
|
93
|
+
* - `ownVersion` — overrides the running CLI's own resolved version
|
|
94
|
+
* directly, bypassing `resolveOwnPackageVersion`.
|
|
95
|
+
* - `checkAgentsDrift` — overrides the fallback drift probe used when the
|
|
96
|
+
* marker is absent; defaults to `runAgentsDrift({ cwd })`.
|
|
97
|
+
* - `writeErr` / `exit` — replace the corresponding process surfaces.
|
|
98
|
+
*
|
|
99
|
+
* @param {string[]} _argv - Unused; reserved for future flags.
|
|
100
|
+
* @param {{
|
|
101
|
+
* runner?: typeof spawnSync,
|
|
102
|
+
* cwd?: () => string,
|
|
103
|
+
* fs?: typeof nodeFs,
|
|
104
|
+
* ownVersion?: string,
|
|
105
|
+
* checkAgentsDrift?: () => { ok: boolean, detail: string },
|
|
106
|
+
* writeErr?: (s: string) => void,
|
|
107
|
+
* exit?: (code: number) => void,
|
|
108
|
+
* }} [opts]
|
|
109
|
+
* @returns {void}
|
|
110
|
+
*/
|
|
111
|
+
export default function run(
|
|
112
|
+
_argv = [],
|
|
113
|
+
{
|
|
114
|
+
runner = spawnSync,
|
|
115
|
+
cwd = () => process.cwd(),
|
|
116
|
+
fs = nodeFs,
|
|
117
|
+
ownVersion,
|
|
118
|
+
checkAgentsDrift,
|
|
119
|
+
writeErr = (s) => process.stderr.write(s),
|
|
120
|
+
exit = (code) => process.exit(code),
|
|
121
|
+
} = {},
|
|
122
|
+
) {
|
|
123
|
+
const projectRoot = cwd();
|
|
124
|
+
const resolvedOwnVersion = ownVersion ?? resolveOwnPackageVersion(fs);
|
|
125
|
+
const marker = readVersionMarker(projectRoot, fs);
|
|
126
|
+
|
|
127
|
+
if (marker) {
|
|
128
|
+
if (marker !== resolvedOwnVersion) {
|
|
129
|
+
writeErr(
|
|
130
|
+
`mandrel sync-agents: the materialized .agents/ tree is v${marker} but the running CLI is v${resolvedOwnVersion} — refusing to project .claude/agents/ from a mismatched tree.\n` +
|
|
131
|
+
' → Run `mandrel sync` to re-materialize .agents/ to the current version, then re-run.\n',
|
|
132
|
+
);
|
|
133
|
+
exit(1);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
const drift = (checkAgentsDrift ?? (() => runAgentsDrift({ cwd })))();
|
|
138
|
+
if (!drift.ok) {
|
|
139
|
+
writeErr(
|
|
140
|
+
`mandrel sync-agents: .agents/ appears to have drifted from the installed package payload (${drift.detail}) — refusing to project .claude/agents/ from a mismatched tree.\n` +
|
|
141
|
+
' → Run `mandrel sync` to restore the materialized .agents/ payload, then re-run.\n',
|
|
142
|
+
);
|
|
143
|
+
exit(1);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const result = runner(process.execPath, [SYNC_SCRIPT], {
|
|
149
|
+
stdio: 'inherit',
|
|
150
|
+
env: process.env,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const exitCode = result.status ?? 1;
|
|
154
|
+
if (exitCode !== 0) {
|
|
155
|
+
exit(exitCode);
|
|
156
|
+
}
|
|
157
|
+
}
|
package/lib/cli/sync-commands.js
CHANGED
|
@@ -11,12 +11,49 @@
|
|
|
11
11
|
* (marked `cli-opt-out`), so delegation runs via a child process rather than
|
|
12
12
|
* a direct import. Exit code and all output are forwarded verbatim to the
|
|
13
13
|
* caller so `mandrel sync-commands` is transparent to scripts that check $?.
|
|
14
|
+
*
|
|
15
|
+
* ## Marker-gated refusal (Story #4526 / #4530)
|
|
16
|
+
*
|
|
17
|
+
* Before delegating, this wrapper checks whether the `.agents/` tree it is
|
|
18
|
+
* about to project commands FROM actually matches the running CLI's own
|
|
19
|
+
* payload version. Without this gate, a consumer whose `.agents/` tree lags
|
|
20
|
+
* the installed package (see #4525's pin-skew scenario) gets commands
|
|
21
|
+
* faithfully projected from a **stale** tree — describing a workflow whose
|
|
22
|
+
* backing scripts are not installed. Because `.claude/*` is conventionally
|
|
23
|
+
* gitignored, that wrong projection leaves no diff and no signal until an
|
|
24
|
+
* agent hits a missing-module error mid-task, far from the actual cause.
|
|
25
|
+
*
|
|
26
|
+
* Gate order:
|
|
27
|
+
* 1. Marker present (`.agents/.mandrel-version`, Story #4530) → compare it
|
|
28
|
+
* to the running CLI's own package version. Mismatch → refuse.
|
|
29
|
+
* 2. Marker absent (a pre-marker install with no baseline to compare) →
|
|
30
|
+
* fall back to the existing `agents-drift` content-hash check
|
|
31
|
+
* (`registry.js`). Drift detected → refuse.
|
|
32
|
+
* 3. Clean either way → project as before.
|
|
33
|
+
*
|
|
34
|
+
* ## Anchor trap (do not repeat)
|
|
35
|
+
*
|
|
36
|
+
* `PROJECT_ROOT` below is deliberately the **package** root — resolved from
|
|
37
|
+
* this module's own two-dirs-up location — because it is used ONLY to read
|
|
38
|
+
* the running CLI's OWN version, which is exactly what that self-referential
|
|
39
|
+
* pattern correctly answers (contrast with the #4525 bug in `update.js`,
|
|
40
|
+
* where the same pattern was wrongly used to answer a *consumer*-pin
|
|
41
|
+
* question). The marker read is a SEPARATE resolution, anchored at `cwd()`
|
|
42
|
+
* (the consumer project root) via `readVersionMarker` — never at
|
|
43
|
+
* `PROJECT_ROOT`. Comparing the marker to `PROJECT_ROOT`'s own version would
|
|
44
|
+
* make the check compare the package against itself and could never fire —
|
|
45
|
+
* the exact trap `registry.js`'s `agents-in-sync` check documents for the
|
|
46
|
+
* same reason.
|
|
14
47
|
*/
|
|
15
48
|
|
|
16
49
|
import { spawnSync } from 'node:child_process';
|
|
50
|
+
import nodeFs from 'node:fs';
|
|
17
51
|
import path from 'node:path';
|
|
18
52
|
import { fileURLToPath } from 'node:url';
|
|
19
53
|
|
|
54
|
+
import { runAgentsDrift } from './registry.js';
|
|
55
|
+
import { readVersionMarker } from './sync.js';
|
|
56
|
+
|
|
20
57
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
58
|
// lib/cli/ → lib/ → project root
|
|
22
59
|
const PROJECT_ROOT = path.resolve(__dirname, '..', '..');
|
|
@@ -28,16 +65,88 @@ const SYNC_SCRIPT = path.join(
|
|
|
28
65
|
);
|
|
29
66
|
|
|
30
67
|
/**
|
|
31
|
-
*
|
|
68
|
+
* Resolve the running CLI's own package version from `PROJECT_ROOT`'s
|
|
69
|
+
* `package.json`. See the "anchor trap" module doc: this is the ONE place
|
|
70
|
+
* `PROJECT_ROOT` (the package's own two-dirs-up root) is the correct anchor.
|
|
71
|
+
*
|
|
72
|
+
* @param {typeof nodeFs} fsImpl
|
|
73
|
+
* @returns {string}
|
|
74
|
+
*/
|
|
75
|
+
function resolveOwnPackageVersion(fsImpl) {
|
|
76
|
+
const parsed = JSON.parse(
|
|
77
|
+
fsImpl.readFileSync(path.join(PROJECT_ROOT, 'package.json'), 'utf8'),
|
|
78
|
+
);
|
|
79
|
+
return String(parsed.version);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run the sync-claude-commands script and forward its output + exit code —
|
|
84
|
+
* unless the marker-gated refusal check (see module doc) finds the
|
|
85
|
+
* `.agents/` tree mismatched against the running CLI, in which case it
|
|
86
|
+
* refuses and exits non-zero before spawning anything.
|
|
32
87
|
*
|
|
33
|
-
* Injectable
|
|
34
|
-
*
|
|
88
|
+
* Injectable seams (used by tests so no real filesystem, child process, or
|
|
89
|
+
* package resolution occurs on the gate path):
|
|
90
|
+
* - `runner` — replaces `spawnSync` for the real delegation.
|
|
91
|
+
* - `cwd()` — replaces `process.cwd`; anchors the marker read at the
|
|
92
|
+
* consumer project root.
|
|
93
|
+
* - `fs` — replaces the `node:fs` surface for both the marker read and the
|
|
94
|
+
* own-version read.
|
|
95
|
+
* - `ownVersion` — overrides the running CLI's own resolved version
|
|
96
|
+
* directly, bypassing `resolveOwnPackageVersion`.
|
|
97
|
+
* - `checkAgentsDrift` — overrides the fallback drift probe used when the
|
|
98
|
+
* marker is absent; defaults to `runAgentsDrift({ cwd })`.
|
|
99
|
+
* - `writeErr` / `exit` — replace the corresponding process surfaces.
|
|
35
100
|
*
|
|
36
101
|
* @param {string[]} _argv - Unused; reserved for future flags.
|
|
37
|
-
* @param {{
|
|
102
|
+
* @param {{
|
|
103
|
+
* runner?: typeof spawnSync,
|
|
104
|
+
* cwd?: () => string,
|
|
105
|
+
* fs?: typeof nodeFs,
|
|
106
|
+
* ownVersion?: string,
|
|
107
|
+
* checkAgentsDrift?: () => { ok: boolean, detail: string },
|
|
108
|
+
* writeErr?: (s: string) => void,
|
|
109
|
+
* exit?: (code: number) => void,
|
|
110
|
+
* }} [opts]
|
|
38
111
|
* @returns {void}
|
|
39
112
|
*/
|
|
40
|
-
export default function run(
|
|
113
|
+
export default function run(
|
|
114
|
+
_argv = [],
|
|
115
|
+
{
|
|
116
|
+
runner = spawnSync,
|
|
117
|
+
cwd = () => process.cwd(),
|
|
118
|
+
fs = nodeFs,
|
|
119
|
+
ownVersion,
|
|
120
|
+
checkAgentsDrift,
|
|
121
|
+
writeErr = (s) => process.stderr.write(s),
|
|
122
|
+
exit = (code) => process.exit(code),
|
|
123
|
+
} = {},
|
|
124
|
+
) {
|
|
125
|
+
const projectRoot = cwd();
|
|
126
|
+
const resolvedOwnVersion = ownVersion ?? resolveOwnPackageVersion(fs);
|
|
127
|
+
const marker = readVersionMarker(projectRoot, fs);
|
|
128
|
+
|
|
129
|
+
if (marker) {
|
|
130
|
+
if (marker !== resolvedOwnVersion) {
|
|
131
|
+
writeErr(
|
|
132
|
+
`mandrel sync-commands: the materialized .agents/ tree is v${marker} but the running CLI is v${resolvedOwnVersion} — refusing to project .claude/commands/ from a mismatched tree.\n` +
|
|
133
|
+
' → Run `mandrel sync` to re-materialize .agents/ to the current version, then re-run.\n',
|
|
134
|
+
);
|
|
135
|
+
exit(1);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
const drift = (checkAgentsDrift ?? (() => runAgentsDrift({ cwd })))();
|
|
140
|
+
if (!drift.ok) {
|
|
141
|
+
writeErr(
|
|
142
|
+
`mandrel sync-commands: .agents/ appears to have drifted from the installed package payload (${drift.detail}) — refusing to project .claude/commands/ from a mismatched tree.\n` +
|
|
143
|
+
' → Run `mandrel sync` to restore the materialized .agents/ payload, then re-run.\n',
|
|
144
|
+
);
|
|
145
|
+
exit(1);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
41
150
|
const result = runner(process.execPath, [SYNC_SCRIPT], {
|
|
42
151
|
stdio: 'inherit',
|
|
43
152
|
env: process.env,
|
|
@@ -45,6 +154,6 @@ export default function run(_argv = [], { runner = spawnSync } = {}) {
|
|
|
45
154
|
|
|
46
155
|
const exitCode = result.status ?? 1;
|
|
47
156
|
if (exitCode !== 0) {
|
|
48
|
-
|
|
157
|
+
exit(exitCode);
|
|
49
158
|
}
|
|
50
159
|
}
|
package/lib/cli/sync.js
CHANGED
|
@@ -26,6 +26,16 @@
|
|
|
26
26
|
* managed `.agents/` zone (everything except `.agents/local/`) that has
|
|
27
27
|
* no counterpart in the package payload is deleted. Consumer additions
|
|
28
28
|
* under `.agents/local/` are never touched.
|
|
29
|
+
* - Generated, never-pruned registry (Story #4534). Framework-generated
|
|
30
|
+
* `.agents/` files have no payload counterpart by design, so the prune
|
|
31
|
+
* pass would delete each one unless it is declared in
|
|
32
|
+
* {@link GENERATED_FILES}. That registry — not a per-file special case in
|
|
33
|
+
* {@link listDestFiles} — is the single place a generated artifact is
|
|
34
|
+
* exempted. Registered today: the version marker (Story #4530) and the
|
|
35
|
+
* install ledger the bootstrap writes and `mandrel uninstall` reads.
|
|
36
|
+
* - Version marker (Story #4530). After the prune pass, `.agents/.mandrel-
|
|
37
|
+
* version` is (re)written with the executing package's own version. See
|
|
38
|
+
* {@link readVersionMarker} for how callers consume it.
|
|
29
39
|
*
|
|
30
40
|
* Security (Tech Spec #3459 "Postinstall safety"):
|
|
31
41
|
* - Does nothing beyond a local file copy: no network, no shell, no writes
|
|
@@ -45,8 +55,19 @@ import nodeFs from 'node:fs';
|
|
|
45
55
|
import { createRequire } from 'node:module';
|
|
46
56
|
import path from 'node:path';
|
|
47
57
|
|
|
58
|
+
import { LEDGER_RELATIVE_PATH } from '../../.agents/scripts/lib/bootstrap/install-ledger.js';
|
|
59
|
+
|
|
48
60
|
export const PACKAGE_NAME = 'mandrel';
|
|
49
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Name of the managed destination directory, relative to the project root.
|
|
64
|
+
* Generating modules export their artifact paths relative to the *project
|
|
65
|
+
* root* (e.g. `install-ledger.js`'s `LEDGER_RELATIVE_PATH`), whereas the
|
|
66
|
+
* prune pass compares paths relative to this directory — {@link
|
|
67
|
+
* toManagedZoneRelative} is the one conversion between the two.
|
|
68
|
+
*/
|
|
69
|
+
const AGENTS_DIR = '.agents';
|
|
70
|
+
|
|
50
71
|
/**
|
|
51
72
|
* Top-level directory name (relative to `.agents/`) reserved as the
|
|
52
73
|
* sync-exempt local-additions zone (Story #3498, f-drift-local-zone).
|
|
@@ -70,6 +91,119 @@ export const LOCAL_ZONE_DIR = 'local';
|
|
|
70
91
|
*/
|
|
71
92
|
export const LOCAL_OVERRIDE_RE = /\.local\.[^.]+$/;
|
|
72
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Relative path (from `.agents/`) of the version marker `runSync` writes
|
|
96
|
+
* after every sync, carrying the executing package's own version.
|
|
97
|
+
*/
|
|
98
|
+
export const VERSION_MARKER_RELATIVE_PATH = '.mandrel-version';
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Convert a project-root-relative POSIX path — the shape a generating module
|
|
102
|
+
* exports as its own source of truth (e.g. `install-ledger.js`'s
|
|
103
|
+
* `LEDGER_RELATIVE_PATH`, `'.agents/.install-manifest.json'`) — into the
|
|
104
|
+
* `.agents/`-relative, OS-separator form {@link listDestFiles} enumerates and
|
|
105
|
+
* {@link GENERATED_FILES} is compared against.
|
|
106
|
+
*
|
|
107
|
+
* Throws on a path outside `.agents/`: a generated file the sync prune pass
|
|
108
|
+
* never walks has no business in the registry, and registering one would be a
|
|
109
|
+
* silent no-op that reads as protection. Failing at module load surfaces the
|
|
110
|
+
* mistake at the first import rather than as a mystery deletion in a
|
|
111
|
+
* consumer's tree.
|
|
112
|
+
*
|
|
113
|
+
* @param {string} projectRelativePosixPath - e.g. `.agents/.install-manifest.json`.
|
|
114
|
+
* @returns {string} e.g. `.install-manifest.json` (OS separators).
|
|
115
|
+
*/
|
|
116
|
+
function toManagedZoneRelative(projectRelativePosixPath) {
|
|
117
|
+
const segments = projectRelativePosixPath.split('/');
|
|
118
|
+
if (segments[0] !== AGENTS_DIR || segments.length < 2) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`generated-files registry: '${projectRelativePosixPath}' is not inside ${AGENTS_DIR}/ — ` +
|
|
121
|
+
'only files the sync prune pass walks can be registered as never-pruned.',
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return path.join(...segments.slice(1));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The **generated, never-pruned registry**: every framework-generated
|
|
129
|
+
* `.agents/` file that has no payload counterpart and must therefore be
|
|
130
|
+
* exempted from the prune pass. Paths are `.agents/`-relative with OS
|
|
131
|
+
* separators, matching what {@link listDestFiles} enumerates.
|
|
132
|
+
*
|
|
133
|
+
* The prune pass (Story #4046 A3) deletes any managed-zone file absent from
|
|
134
|
+
* the payload. That is the correct rule for consumer drift, but it is also
|
|
135
|
+
* exactly the shape of every file the framework itself generates into
|
|
136
|
+
* `.agents/` outside the payload — so each such artifact is deleted by the very
|
|
137
|
+
* sync that wrote it unless registered here. Two have hit this already: the
|
|
138
|
+
* install ledger (`.agents/.install-manifest.json`), whose loss made
|
|
139
|
+
* `mandrel uninstall` silently reverse nothing and exit 0 (Story #4534), and
|
|
140
|
+
* the version marker (Story #4530).
|
|
141
|
+
*
|
|
142
|
+
* This is deliberately a **registry, not a list of special cases**. Register a
|
|
143
|
+
* new generated file by adding one entry here — keyed off the generating
|
|
144
|
+
* module's own exported constant wherever one exists, never a duplicated
|
|
145
|
+
* string literal — rather than by adding another branch to
|
|
146
|
+
* {@link listDestFiles}. That keeps the never-prune contract declared in one
|
|
147
|
+
* place and keeps the registry honest: if the generator renames its artifact,
|
|
148
|
+
* the exemption moves with it.
|
|
149
|
+
*
|
|
150
|
+
* This registry does **not** subsume the `.agents/local/` zone or the
|
|
151
|
+
* `*.local.*` overrides ({@link LOCAL_ZONE_DIR}, {@link LOCAL_OVERRIDE_RE}).
|
|
152
|
+
* Those are a different concept — consumer-authored overrides, not
|
|
153
|
+
* framework-generated artifacts — and stay separate on purpose.
|
|
154
|
+
*/
|
|
155
|
+
export const GENERATED_FILES = Object.freeze([
|
|
156
|
+
// Version marker (Story #4530) — written by runSync itself, below.
|
|
157
|
+
VERSION_MARKER_RELATIVE_PATH,
|
|
158
|
+
// Install ledger (Story #4534) — written by the bootstrap
|
|
159
|
+
// (`install-ledger.js`), read by `mandrel uninstall` as its single source of
|
|
160
|
+
// truth. Keyed off the generator's exported constant.
|
|
161
|
+
toManagedZoneRelative(LEDGER_RELATIVE_PATH),
|
|
162
|
+
]);
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Resolve the version of the package whose `.agents/` payload was just
|
|
166
|
+
* copied — i.e. the version the marker must carry. Reads `package.json` at
|
|
167
|
+
* the already-resolved `packageRoot`, never the two-directories-up
|
|
168
|
+
* self-referential pattern `lib/cli/update.js`'s pre-Story-#4530
|
|
169
|
+
* `defaultCurrentVersion` used (that pattern conflates "the CLI that is
|
|
170
|
+
* running" with "the payload that was materialized" — the exact confusion
|
|
171
|
+
* #4525 fixes on the consumer-pin side of this Story).
|
|
172
|
+
*
|
|
173
|
+
* @param {string} packageRoot - Absolute path to the resolved package root.
|
|
174
|
+
* @param {typeof nodeFs} fsImpl
|
|
175
|
+
* @returns {string}
|
|
176
|
+
*/
|
|
177
|
+
function resolvePackageVersion(packageRoot, fsImpl) {
|
|
178
|
+
const pkgJsonPath = path.join(packageRoot, 'package.json');
|
|
179
|
+
const parsed = JSON.parse(fsImpl.readFileSync(pkgJsonPath, 'utf8'));
|
|
180
|
+
return String(parsed.version);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Read the consumer's `.agents/.mandrel-version` marker. Returns `null` when
|
|
185
|
+
* absent — a pre-marker install, or a tree that has never been synced —
|
|
186
|
+
* so callers (the sync-commands mismatch refusal, the doctor pin check) can
|
|
187
|
+
* degrade to their existing content-hash drift check rather than failing.
|
|
188
|
+
*
|
|
189
|
+
* @param {string} consumerRoot - Consumer project root (not `.agents/`).
|
|
190
|
+
* @param {typeof nodeFs} [fsImpl]
|
|
191
|
+
* @returns {string | null}
|
|
192
|
+
*/
|
|
193
|
+
export function readVersionMarker(consumerRoot, fsImpl = nodeFs) {
|
|
194
|
+
const markerPath = path.join(
|
|
195
|
+
consumerRoot,
|
|
196
|
+
'.agents',
|
|
197
|
+
VERSION_MARKER_RELATIVE_PATH,
|
|
198
|
+
);
|
|
199
|
+
try {
|
|
200
|
+
const raw = fsImpl.readFileSync(markerPath, 'utf8').trim();
|
|
201
|
+
return raw || null;
|
|
202
|
+
} catch {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
73
207
|
/**
|
|
74
208
|
* Default resolver: locate the installed `mandrel` package root by
|
|
75
209
|
* resolving its `package.json` and returning the directory that contains it.
|
|
@@ -126,12 +260,22 @@ export function listFiles(dir, fsImpl, prefix = '') {
|
|
|
126
260
|
|
|
127
261
|
/**
|
|
128
262
|
* Recursively enumerate every regular file under `dir`, returning paths
|
|
129
|
-
* relative to `dir` using OS separators.
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
263
|
+
* relative to `dir` using OS separators. Three disjoint classes are skipped,
|
|
264
|
+
* so a caller diffing this against the payload never treats them as stale:
|
|
265
|
+
*
|
|
266
|
+
* 1. The top-level `local/` subtree — consumer additions inside
|
|
267
|
+
* `.agents/local/` are never pruned (Story #3498).
|
|
268
|
+
* 2. Files matching the `*.local.*` convention (e.g.
|
|
269
|
+
* `.agents/instructions.local.md`) — the documented consumer override
|
|
270
|
+
* mechanism (instructions.md § 1.E); they never ship in the payload and
|
|
271
|
+
* must survive every sync.
|
|
272
|
+
* 3. Everything declared in the {@link GENERATED_FILES} registry —
|
|
273
|
+
* framework-generated artifacts with no payload counterpart by design
|
|
274
|
+
* (Story #4534). New generated files are registered there, not added as
|
|
275
|
+
* a fourth branch here.
|
|
276
|
+
*
|
|
277
|
+
* (1) and (2) are consumer-authored; (3) is framework-generated. They are
|
|
278
|
+
* kept separate deliberately — conflating them would muddy both contracts.
|
|
135
279
|
*
|
|
136
280
|
* Mirrors `listFiles` but operates on the destination tree so we can
|
|
137
281
|
* identify stale files that have no payload counterpart (Story #4046 A3).
|
|
@@ -162,6 +306,11 @@ function listDestFiles(dir, fsImpl, prefix = '') {
|
|
|
162
306
|
continue;
|
|
163
307
|
}
|
|
164
308
|
const rel = prefix ? path.join(prefix, ent.name) : ent.name;
|
|
309
|
+
// Framework-generated artifacts — declared once in the never-pruned
|
|
310
|
+
// registry (Story #4534); see GENERATED_FILES.
|
|
311
|
+
if (!ent.isDirectory() && GENERATED_FILES.includes(rel)) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
165
314
|
const abs = path.join(dir, ent.name);
|
|
166
315
|
if (ent.isDirectory()) {
|
|
167
316
|
out.push(...listDestFiles(abs, fsImpl, rel));
|
|
@@ -273,6 +422,19 @@ export function runSync({
|
|
|
273
422
|
fs.unlinkSync(dest);
|
|
274
423
|
}
|
|
275
424
|
|
|
425
|
+
// Version marker (Story #4530): written AFTER the prune pass, never
|
|
426
|
+
// before — the GENERATED_FILES registry already keeps listDestFiles from
|
|
427
|
+
// ever enumerating it as stale, but ordering the write after prune is a
|
|
428
|
+
// second, independent safeguard against the same class of bug (see the
|
|
429
|
+
// GENERATED_FILES doc comment) surviving a future prune-pass reorder. The
|
|
430
|
+
// install ledger gets no such belt-and-braces: it is written by the
|
|
431
|
+
// bootstrap, not here, so the registry is its only protection.
|
|
432
|
+
const packageVersion = resolvePackageVersion(packageRoot, fs);
|
|
433
|
+
fs.writeFileSync(
|
|
434
|
+
path.join(destRoot, VERSION_MARKER_RELATIVE_PATH),
|
|
435
|
+
`${packageVersion}\n`,
|
|
436
|
+
);
|
|
437
|
+
|
|
276
438
|
if (staleFiles.length > 0) {
|
|
277
439
|
write(
|
|
278
440
|
`✅ Installed ${payloadFiles.length} file(s) into ./.agents/ (pruned ${staleFiles.length} stale file(s))\n`,
|