mandrel 2.0.0 → 2.2.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 +59 -28
- package/.agents/agents/acceptance-critic.md +20 -9
- package/.agents/agents/story-worker.md +45 -48
- package/.agents/audit-checklists/performance.md +1 -1
- package/.agents/docs/SDLC.md +60 -46
- package/.agents/docs/agentrc-reference.json +8 -13
- package/.agents/docs/configuration.md +33 -57
- package/.agents/docs/execution-reference.md +39 -10
- package/.agents/docs/quality-gates.md +17 -19
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +64 -79
- package/.agents/rules/ci-remediation.md +3 -3
- package/.agents/rules/gherkin-standards.md +10 -0
- package/.agents/rules/git-conventions-reference.md +42 -51
- package/.agents/schemas/acceptance-eval-verdict.schema.json +2 -2
- package/.agents/schemas/agentrc.schema.json +35 -46
- 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/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 +24 -68
- package/.agents/scripts/agents-bootstrap-github.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 +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +91 -0
- 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/audit-suite/selector.js +323 -23
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +0 -11
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +28 -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 +4 -1
- package/.agents/scripts/lib/checks/index.js +1 -1
- 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 +3 -3
- 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-args.js +23 -2
- package/.agents/scripts/lib/close-validation/gates.js +13 -13
- 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/acceptance-eval.js +2 -2
- package/.agents/scripts/lib/config/delivery-routing.js +7 -6
- package/.agents/scripts/lib/config/explain.js +10 -16
- package/.agents/scripts/lib/config/github.js +7 -5
- package/.agents/scripts/lib/config/limits.js +15 -25
- package/.agents/scripts/lib/config/quality.js +11 -14
- package/.agents/scripts/lib/config/runners.js +8 -21
- package/.agents/scripts/lib/config/temp-paths.js +18 -56
- package/.agents/scripts/lib/config-settings-schema-delivery.js +34 -16
- package/.agents/scripts/lib/config-settings-schema-quality.js +9 -2
- package/.agents/scripts/lib/config-settings-schema.js +48 -22
- package/.agents/scripts/lib/dead-exports-knip.js +105 -0
- package/.agents/scripts/lib/dead-exports-mode.js +51 -0
- package/.agents/scripts/lib/duplicate-search.js +38 -7
- 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 -189
- package/.agents/scripts/lib/gh-exec.js +8 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +0 -158
- package/.agents/scripts/lib/git-utils.js +0 -14
- package/.agents/scripts/lib/json-utils.js +1 -2
- package/.agents/scripts/lib/label-constants.js +0 -15
- package/.agents/scripts/lib/label-taxonomy.js +1 -12
- package/.agents/scripts/lib/observability/active-story-env.js +42 -163
- 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 +2 -2
- package/.agents/scripts/lib/observability/tool-trace-hook.js +2 -12
- 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 +43 -45
- package/.agents/scripts/lib/orchestration/change-set.js +103 -0
- package/.agents/scripts/lib/orchestration/code-review.js +70 -191
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +3 -3
- 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/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 +9 -11
- 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/listeners/README.md +7 -3
- 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/merge-block-class.js +76 -20
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -0
- package/.agents/scripts/lib/orchestration/plan-context.js +116 -33
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +26 -36
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +31 -22
- package/.agents/scripts/lib/orchestration/plan-metrics.js +38 -6
- package/.agents/scripts/lib/orchestration/plan-persist/fan-out-gate.js +16 -6
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +173 -25
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +116 -0
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +280 -100
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +472 -55
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +21 -16
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +509 -0
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +230 -0
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +41 -40
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -2
- package/.agents/scripts/lib/orchestration/planning/spec-authoring-grounding.js +1 -1
- package/.agents/scripts/lib/orchestration/resolve-stories.js +344 -0
- package/.agents/scripts/lib/orchestration/retro-proposals.js +7 -7
- package/.agents/scripts/lib/orchestration/review-depth.js +105 -40
- 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/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 +374 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +24 -0
- 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 +4 -13
- 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 +72 -30
- 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 +12 -8
- 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 +264 -43
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +10 -10
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +104 -279
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +191 -0
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +120 -0
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +360 -0
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +75 -14
- package/.agents/scripts/lib/orchestration/story-init-remote.js +12 -8
- package/.agents/scripts/lib/orchestration/story-plan-state.js +14 -29
- package/.agents/scripts/lib/orchestration/task-body-validator.js +52 -7
- package/.agents/scripts/lib/orchestration/ticket-lease.js +27 -74
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +119 -14
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +3 -4
- package/.agents/scripts/lib/orchestration/ticket-validator.js +121 -18
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +14 -47
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +19 -32
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +61 -1
- 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 -286
- package/.agents/scripts/lib/preflight-runner.js +2 -2
- 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/skills/parse-skill.js +16 -3
- package/.agents/scripts/lib/story-adjacency.js +8 -7
- package/.agents/scripts/lib/story-body/story-body.js +81 -13
- package/.agents/scripts/lib/templates/decomposer-prompts.js +15 -16
- package/.agents/scripts/lib/test-env.js +14 -1
- package/.agents/scripts/lib/test-tiers.js +0 -3
- package/.agents/scripts/lib/ticket-body-sections.js +0 -14
- package/.agents/scripts/lib/validation-evidence.js +31 -59
- package/.agents/scripts/lib/wave-runner/live-probe.js +315 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +32 -6
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +68 -19
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +1 -2
- package/.agents/scripts/plan-context.js +38 -7
- package/.agents/scripts/plan-critics.js +203 -0
- package/.agents/scripts/plan-persist.js +145 -35
- package/.agents/scripts/plan-run-epilogue.js +83 -38
- 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 +1 -11
- package/.agents/scripts/providers/github/mappers.js +5 -0
- package/.agents/scripts/providers/github/sub-issues.js +0 -47
- package/.agents/scripts/providers/github/tickets.js +33 -153
- package/.agents/scripts/providers/github.js +17 -6
- package/.agents/scripts/quality-preview.js +13 -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 +9 -10
- package/.agents/scripts/single-story-close.js +173 -18
- package/.agents/scripts/single-story-confirm-merge.js +288 -15
- package/.agents/scripts/single-story-init.js +6 -10
- package/.agents/scripts/stories-wave-tick.js +380 -53
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/update-ticket-state.js +8 -50
- 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 +3 -3
- package/.agents/skills/core/scope-triage/SKILL.md +3 -0
- 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 +2 -12
- 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/workflows/audit-architecture.md +3 -4
- package/.agents/workflows/audit-clean-code.md +4 -4
- package/.agents/workflows/audit-documentation.md +4 -5
- package/.agents/workflows/audit-lighthouse.md +8 -0
- package/.agents/workflows/audit-navigability.md +10 -0
- package/.agents/workflows/audit-performance.md +2 -3
- package/.agents/workflows/audit-quality.md +8 -9
- package/.agents/workflows/audit-security.md +1 -2
- package/.agents/workflows/audit-seo.md +10 -0
- package/.agents/workflows/audit-ux-ui.md +7 -0
- package/.agents/workflows/deliver.md +133 -45
- package/.agents/workflows/git-cleanup.md +2 -2
- package/.agents/workflows/git-deliver.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +34 -17
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -12
- package/.agents/workflows/helpers/code-review.md +14 -12
- package/.agents/workflows/helpers/deliver-story-reference.md +73 -32
- package/.agents/workflows/helpers/deliver-story.md +209 -118
- package/.agents/workflows/helpers/parallel-tooling.md +2 -2
- package/.agents/workflows/helpers/worktree-lifecycle.md +28 -32
- package/.agents/workflows/plan.md +239 -19
- package/.agents/workflows/qa-assist.md +6 -6
- package/.agents/workflows/qa-explore.md +3 -3
- package/.agents/workflows/qa-run.md +1 -5
- package/bin/mandrel.js +12 -1
- package/docs/CHANGELOG.md +62 -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 +17 -9
- 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/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +154 -0
- package/package.json +2 -2
- package/.agents/schemas/epic-perf-report.schema.json +0 -89
- 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/story.heartbeat.schema.json +0 -20
- package/.agents/schemas/risk-verdict.schema.json +0 -53
- package/.agents/schemas/story-perf-summary.schema.json +0 -73
- package/.agents/scripts/analyze-execution.js +0 -444
- package/.agents/scripts/check-prepush-recovery.js +0 -90
- 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 -187
- 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/audit-lens-routing.js +0 -128
- package/.agents/scripts/lib/orchestration/bookkeeping-outbox.js +0 -273
- package/.agents/scripts/lib/orchestration/error-journal.js +0 -139
- 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/merge-watcher.js +0 -665
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +0 -63
- package/.agents/scripts/lib/orchestration/planning/risk-verdict.js +0 -104
- 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 -21
- 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 -397
- package/.agents/scripts/lib/orchestration/preflight-cache.js +0 -187
- package/.agents/scripts/lib/orchestration/resolve-plan-run.js +0 -155
- package/.agents/scripts/lib/orchestration/retro-perf-heuristics.js +0 -275
- package/.agents/scripts/lib/orchestration/story-progress/story-run-progress-writer.js +0 -400
- package/.agents/scripts/lib/single-story/confirm-merge-follow-ups.js +0 -36
- package/.agents/scripts/resolve-plan-run.js +0 -117
- package/.agents/skills/core/analyze-execution/SKILL.md +0 -101
|
@@ -199,90 +199,6 @@ export function seedStoryBranchRef({
|
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
/**
|
|
203
|
-
* Ensure an Epic branch exists and is published to `origin`. Handles all
|
|
204
|
-
* four states of the (local, remote) matrix.
|
|
205
|
-
*
|
|
206
|
-
* @param {string} epicBranch
|
|
207
|
-
* @param {string} baseBranch
|
|
208
|
-
* @param {string} cwd
|
|
209
|
-
* @param {{ progress?: (phase: string, message: string) => void }} [opts]
|
|
210
|
-
*/
|
|
211
|
-
export async function ensureEpicBranch(epicBranch, baseBranch, cwd, opts = {}) {
|
|
212
|
-
assertBranchSafe(epicBranch, baseBranch);
|
|
213
|
-
const progress = opts.progress ?? (() => {});
|
|
214
|
-
|
|
215
|
-
// Short-circuit: if we're already on the epic branch, just sync with remote.
|
|
216
|
-
// This avoids redundant checkout calls and prevents the edge case where
|
|
217
|
-
// branchExistsLocally returns false while we're on the branch (detached HEAD,
|
|
218
|
-
// worktree race), which would route into the create path and fail on -b.
|
|
219
|
-
const onBranch = currentBranch(cwd);
|
|
220
|
-
if (onBranch === epicBranch) {
|
|
221
|
-
const remote = branchExistsRemotely(epicBranch, cwd);
|
|
222
|
-
if (remote) {
|
|
223
|
-
progress('GIT', `Already on ${epicBranch}. Syncing with remote.`);
|
|
224
|
-
await gitPullWithRetry(cwd, 'origin', epicBranch);
|
|
225
|
-
} else {
|
|
226
|
-
progress('GIT', `Already on ${epicBranch}. Publishing to remote.`);
|
|
227
|
-
gitSync(cwd, 'push', '--no-verify', '-u', 'origin', epicBranch);
|
|
228
|
-
}
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const local = branchExistsLocally(epicBranch, cwd);
|
|
233
|
-
const remote = branchExistsRemotely(epicBranch, cwd);
|
|
234
|
-
|
|
235
|
-
if (!local && !remote) {
|
|
236
|
-
progress('GIT', `Creating Epic branch: ${epicBranch} (from ${baseBranch})`);
|
|
237
|
-
gitSync(cwd, 'checkout', baseBranch);
|
|
238
|
-
await gitPullWithRetry(cwd, 'origin', baseBranch);
|
|
239
|
-
gitSync(cwd, 'checkout', '-b', epicBranch);
|
|
240
|
-
gitSync(cwd, 'push', '--no-verify', '-u', 'origin', epicBranch);
|
|
241
|
-
_assertOnBranch(cwd, epicBranch);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (local && !remote) {
|
|
246
|
-
progress(
|
|
247
|
-
'GIT',
|
|
248
|
-
`Epic branch exists locally only: ${epicBranch}. Publishing.`,
|
|
249
|
-
);
|
|
250
|
-
gitSync(cwd, 'checkout', epicBranch);
|
|
251
|
-
gitSync(cwd, 'push', '--no-verify', '-u', 'origin', epicBranch);
|
|
252
|
-
_assertOnBranch(cwd, epicBranch);
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (!local && remote) {
|
|
257
|
-
progress('GIT', `Tracking remote Epic branch: ${epicBranch}`);
|
|
258
|
-
gitSync(cwd, 'checkout', '-b', epicBranch, `origin/${epicBranch}`);
|
|
259
|
-
await gitPullWithRetry(cwd, 'origin', epicBranch);
|
|
260
|
-
_assertOnBranch(cwd, epicBranch);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
progress('GIT', `Epic branch exists. Syncing: ${epicBranch}`);
|
|
265
|
-
gitSync(cwd, 'checkout', epicBranch);
|
|
266
|
-
await gitPullWithRetry(cwd, 'origin', epicBranch);
|
|
267
|
-
_assertOnBranch(cwd, epicBranch);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Post-operation assertion: verify HEAD is on the expected branch.
|
|
272
|
-
* Guards against TOCTOU races where a parallel agent switches branches
|
|
273
|
-
* between our checkout and pull.
|
|
274
|
-
*/
|
|
275
|
-
function _assertOnBranch(cwd, expected) {
|
|
276
|
-
const actual = currentBranch(cwd);
|
|
277
|
-
if (actual !== expected) {
|
|
278
|
-
throw new Error(
|
|
279
|
-
`[git-branch-lifecycle] Branch assertion failed after checkout. ` +
|
|
280
|
-
`Expected HEAD on '${expected}', found '${actual}'. ` +
|
|
281
|
-
`A concurrent process may have switched branches.`,
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
202
|
/**
|
|
287
203
|
* Check out a Story branch, creating it from `epicBranch` if neither local
|
|
288
204
|
* nor remote exists. Non-destructive: if the branch already exists, this
|
|
@@ -337,80 +253,6 @@ export async function checkoutStoryBranch(
|
|
|
337
253
|
gitSync(cwd, 'checkout', '-b', storyBranch, epicBranch);
|
|
338
254
|
}
|
|
339
255
|
|
|
340
|
-
/**
|
|
341
|
-
* Ensure an Epic branch ref exists locally and is published to `origin`,
|
|
342
|
-
* **without moving HEAD**. Designed for the worktree bootstrap path where
|
|
343
|
-
* the main checkout must not switch branches (a parallel agent may be
|
|
344
|
-
* working there, or the tree may be dirty).
|
|
345
|
-
*
|
|
346
|
-
* Uses `git branch` (not `checkout -b`) to create refs, and `git push` to
|
|
347
|
-
* publish. Callers that need HEAD on the epic branch should use
|
|
348
|
-
* `ensureEpicBranch()` instead.
|
|
349
|
-
*
|
|
350
|
-
* @param {string} epicBranch
|
|
351
|
-
* @param {string} baseBranch
|
|
352
|
-
* @param {string} cwd
|
|
353
|
-
* @param {{ progress?: (phase: string, message: string) => void }} [opts]
|
|
354
|
-
*/
|
|
355
|
-
/**
|
|
356
|
-
* Pure: choose the action to take for `ensureEpicBranchRef` given whether
|
|
357
|
-
* the branch exists locally and/or remotely. One of:
|
|
358
|
-
* - `'noop'` — both refs exist; nothing to do.
|
|
359
|
-
* - `'fetch'` — only remote exists; fetch into local.
|
|
360
|
-
* - `'publish-existing'` — only local exists; push it.
|
|
361
|
-
* - `'create-and-publish'` — neither exists; create from base then push.
|
|
362
|
-
*
|
|
363
|
-
* @param {boolean} local
|
|
364
|
-
* @param {boolean} remote
|
|
365
|
-
* @returns {'noop' | 'fetch' | 'publish-existing' | 'create-and-publish'}
|
|
366
|
-
*/
|
|
367
|
-
export function planEnsureEpicBranchRefAction(local, remote) {
|
|
368
|
-
if (local) return remote ? 'noop' : 'publish-existing';
|
|
369
|
-
return remote ? 'fetch' : 'create-and-publish';
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
export function ensureEpicBranchRef(epicBranch, baseBranch, cwd, opts = {}) {
|
|
373
|
-
assertBranchSafe(epicBranch, baseBranch);
|
|
374
|
-
const progress = opts.progress ?? (() => {});
|
|
375
|
-
|
|
376
|
-
// `ensureEpicBranchRef` is always called after a `git fetch origin` (via
|
|
377
|
-
// `cachedGitFetch` / `fetchMainRefs` in `bootstrapWorktree`). The
|
|
378
|
-
// remote-tracking refs are therefore authoritative, so we check
|
|
379
|
-
// `refs/remotes/origin/<branch>` locally rather than issuing a second
|
|
380
|
-
// network `ls-remote` call.
|
|
381
|
-
const action = planEnsureEpicBranchRefAction(
|
|
382
|
-
branchExistsLocally(epicBranch, cwd),
|
|
383
|
-
branchExistsViaTrackingRef(epicBranch, cwd),
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
if (action === 'noop') {
|
|
387
|
-
progress('GIT', `Epic branch ref exists (local+remote): ${epicBranch}`);
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (action === 'fetch') {
|
|
392
|
-
progress('GIT', `Fetching remote Epic branch ref: ${epicBranch}`);
|
|
393
|
-
const res = gitSpawn(cwd, 'fetch', 'origin', `${epicBranch}:${epicBranch}`);
|
|
394
|
-
if (res.status !== 0) {
|
|
395
|
-
throw new Error(
|
|
396
|
-
`ensureEpicBranchRef: failed to fetch ${epicBranch}: ${res.stderr}`,
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (action === 'create-and-publish') {
|
|
403
|
-
progress(
|
|
404
|
-
'GIT',
|
|
405
|
-
`Creating Epic branch ref: ${epicBranch} (from ${baseBranch})`,
|
|
406
|
-
);
|
|
407
|
-
gitSync(cwd, 'branch', epicBranch, baseBranch);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
progress('GIT', `Publishing Epic branch: ${epicBranch}`);
|
|
411
|
-
gitSync(cwd, 'push', '--no-verify', '-u', 'origin', epicBranch);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
256
|
/**
|
|
415
257
|
* Ensure an arbitrary branch exists locally, creating from `baseBranch` if
|
|
416
258
|
* missing. Used by the dispatcher's task-dispatch path where the expected
|
|
@@ -315,20 +315,6 @@ export function gitPullWithRetry(cwd, ...args) {
|
|
|
315
315
|
return gitWithContentionRetry(cwd, ['pull', '--rebase'], args);
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
-
/**
|
|
319
|
-
* Resolves the canonical branch name for an Epic.
|
|
320
|
-
* v5 Standard: epic/[EPIC_ID]
|
|
321
|
-
* @param {string|number} epicId
|
|
322
|
-
* @returns {string}
|
|
323
|
-
*/
|
|
324
|
-
export function getEpicBranch(epicId) {
|
|
325
|
-
const id = typeof epicId === 'number' ? epicId : Number.parseInt(epicId, 10);
|
|
326
|
-
if (!Number.isFinite(id) || id <= 0) {
|
|
327
|
-
throw new Error(`getEpicBranch: invalid epicId: ${epicId}`);
|
|
328
|
-
}
|
|
329
|
-
return `epic/${id}`;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
318
|
/**
|
|
333
319
|
* Sanitize a string into a URL/branch-safe slug.
|
|
334
320
|
* Lowercases, replaces non-alphanumeric characters with hyphens,
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
* json-utils.js — shared JSON-shape helpers.
|
|
3
3
|
*
|
|
4
4
|
* Hoisted out of five callers (`lib/baselines/writer.js`,
|
|
5
|
-
* `lib/config/defaults.js`, `lib/
|
|
6
|
-
* `lib/observability/perf-aggregator.js`, `lib/signals/schema.js`) which
|
|
5
|
+
* `lib/config/defaults.js`, `lib/signals/schema.js`) which
|
|
7
6
|
* shipped functionally-equivalent copies of these predicates. See Story
|
|
8
7
|
* #2464.
|
|
9
8
|
*
|
|
@@ -135,20 +135,6 @@ export const PLANNING_LABELS = {
|
|
|
135
135
|
*/
|
|
136
136
|
export const PLANNING_HEALTHCHECK_WAIVED = 'planning::healthcheck-waived';
|
|
137
137
|
|
|
138
|
-
/**
|
|
139
|
-
* Delivery-routing labels (Epic #4474 PR4 — design §2 mode matrix).
|
|
140
|
-
* `delivery::single` marks an Epic whose plan was persisted in the
|
|
141
|
-
* spec-only single-delivery mode: no Story tree exists and the Delivery
|
|
142
|
-
* Slicing table of the Epic body's Tech Spec is the audit trail.
|
|
143
|
-
* `plan-persist.js` applies it when the risk verdict declares
|
|
144
|
-
* `deliveryShape: "single"`; a fan-out re-persist over the same Epic
|
|
145
|
-
* removes it. The marker is **inert until #4475** lands the deliver-side
|
|
146
|
-
* reader — nothing in the deliver path consumes it yet.
|
|
147
|
-
*/
|
|
148
|
-
export const DELIVERY_LABELS = {
|
|
149
|
-
SINGLE: 'delivery::single',
|
|
150
|
-
};
|
|
151
|
-
|
|
152
138
|
/** Palette for the taxonomy; consumed by label-taxonomy.js. */
|
|
153
139
|
export const LABEL_COLORS = {
|
|
154
140
|
TYPE: '#7057FF',
|
|
@@ -156,5 +142,4 @@ export const LABEL_COLORS = {
|
|
|
156
142
|
STATUS_BLOCKED: '#D93F0B',
|
|
157
143
|
ACCEPTANCE: '#FBCA04',
|
|
158
144
|
PLANNING: '#FEF2C0',
|
|
159
|
-
DELIVERY: '#BFD4F2',
|
|
160
145
|
};
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
import {
|
|
15
15
|
ACCEPTANCE_LABELS,
|
|
16
16
|
AGENT_LABELS,
|
|
17
|
-
DELIVERY_LABELS,
|
|
18
17
|
LABEL_COLORS,
|
|
19
18
|
PLANNING_LABELS,
|
|
20
19
|
STATUS_LABELS,
|
|
@@ -51,7 +50,7 @@ export const LABEL_TAXONOMY = [
|
|
|
51
50
|
{
|
|
52
51
|
name: AGENT_LABELS.CLOSING,
|
|
53
52
|
color: LABEL_COLORS.AGENT,
|
|
54
|
-
description: 'Close preflight passed; awaiting merge into the
|
|
53
|
+
description: 'Close preflight passed; awaiting merge into the base branch',
|
|
55
54
|
},
|
|
56
55
|
{
|
|
57
56
|
name: AGENT_LABELS.DONE,
|
|
@@ -84,16 +83,6 @@ export const LABEL_TAXONOMY = [
|
|
|
84
83
|
description:
|
|
85
84
|
'Historical operator override for the retired post-plan healthcheck',
|
|
86
85
|
},
|
|
87
|
-
|
|
88
|
-
// Delivery routing — applied by `plan-persist.js` when the risk verdict
|
|
89
|
-
// declares `deliveryShape: "single"` (Epic #4474 PR4). Inert until #4475
|
|
90
|
-
// lands the deliver-side reader.
|
|
91
|
-
{
|
|
92
|
-
name: DELIVERY_LABELS.SINGLE,
|
|
93
|
-
color: LABEL_COLORS.DELIVERY,
|
|
94
|
-
description:
|
|
95
|
-
'Single-delivery plan — no Story tree; the Delivery Slicing table is the audit trail (#4474/#4475)',
|
|
96
|
-
},
|
|
97
86
|
];
|
|
98
87
|
|
|
99
88
|
/** @type {Array<{ name: string, type: 'single_select', options?: string[] }>} */
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Active-Story env-var propagation (Epic #1030 Story #1043 / Task #1061).
|
|
3
3
|
*
|
|
4
4
|
* The PreToolUse / PostToolUse trace hook in
|
|
5
|
-
* `lib/observability/tool-trace-hook.js` resolves the active
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* `lib/observability/tool-trace-hook.js` resolves the active Story from
|
|
6
|
+
* `process.env.CC_STORY_ID`. This module is the single writer/clearer of
|
|
7
|
+
* that var:
|
|
8
8
|
*
|
|
9
|
-
* - `setActiveStoryEnv({
|
|
9
|
+
* - `setActiveStoryEnv({ storyId, workCwd })` is called from
|
|
10
10
|
* `single-story-init.js` after the worktree is materialised. It sets the
|
|
11
|
-
*
|
|
12
|
-
* orchestrator spawns inherit
|
|
11
|
+
* var on the current `process.env` (so any child commands the
|
|
12
|
+
* orchestrator spawns inherit it) and exports it to a sibling
|
|
13
13
|
* `.env.local` inside the worktree. The harness re-spawns the
|
|
14
14
|
* agent with that file's contents loaded, so the trace hook fires
|
|
15
15
|
* with the right ids on the *next* tool call after init returns.
|
|
@@ -37,96 +37,76 @@ const ENV_LOCAL_BASENAME = '.env.local';
|
|
|
37
37
|
/**
|
|
38
38
|
* Names of the env vars we own. Keeping the list central makes the
|
|
39
39
|
* round-trip (set on init, clear on close) trivially auditable —
|
|
40
|
-
* grep `
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* hook
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
40
|
+
* grep `CC_STORY_ID` / `CC_EPIC_ID` to find every read site.
|
|
41
|
+
*
|
|
42
|
+
* `CC_STORY_ID` is the one var this module writes. `CC_EPIC_ID` is retained
|
|
43
|
+
* on the CLEAR path only: v2 has no Epics and nothing here sets it, but
|
|
44
|
+
* `tool-trace-hook.js`'s `resolveActiveStory` still reads it, so wiping it at
|
|
45
|
+
* close keeps the trace path's "no stale context past close" contract honest
|
|
46
|
+
* against a value that leaked in from outside (a pre-upgrade `.env.local` the
|
|
47
|
+
* harness already loaded, or an operator's shell).
|
|
48
|
+
*
|
|
49
|
+
* `CC_SLICE_ID` / `CC_OPERATOR` were removed with the heartbeat substrate:
|
|
50
|
+
* their only writer was the never-called `setActiveSliceEnv` and their only
|
|
51
|
+
* reader the deleted `hook-heartbeat.js`.
|
|
48
52
|
*/
|
|
49
|
-
export const ACTIVE_STORY_ENV_KEYS = [
|
|
50
|
-
'CC_EPIC_ID',
|
|
51
|
-
'CC_STORY_ID',
|
|
52
|
-
'CC_SLICE_ID',
|
|
53
|
-
'CC_OPERATOR',
|
|
54
|
-
];
|
|
53
|
+
export const ACTIVE_STORY_ENV_KEYS = ['CC_EPIC_ID', 'CC_STORY_ID'];
|
|
55
54
|
|
|
56
55
|
/**
|
|
57
56
|
* Render the `.env.local` body. One `KEY=value` line per var, LF
|
|
58
57
|
* line endings (the harness's dotenv parser tolerates CRLF too but LF
|
|
59
58
|
* keeps the file deterministic across Windows / macOS / Linux).
|
|
60
59
|
*
|
|
61
|
-
*
|
|
62
|
-
* Epic
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* empty string and change the contract.
|
|
60
|
+
* Only `CC_STORY_ID` is emitted: v2 Stories are standalone, so there is no
|
|
61
|
+
* parent Epic to key. The trace hook's no-op contract reads "var absent from
|
|
62
|
+
* env" as the signal, so no `CC_EPIC_ID=` line is written at all — an empty
|
|
63
|
+
* one would set the var to the empty string and change the contract.
|
|
66
64
|
*
|
|
67
65
|
* Exported for testing.
|
|
68
66
|
*
|
|
69
|
-
* @param {{
|
|
67
|
+
* @param {{ storyId: number }} input
|
|
70
68
|
* @returns {string}
|
|
71
69
|
*/
|
|
72
|
-
export function renderActiveStoryEnvFile({
|
|
73
|
-
|
|
70
|
+
export function renderActiveStoryEnvFile({ storyId }) {
|
|
71
|
+
return [
|
|
74
72
|
'# Auto-managed by .agents/scripts/lib/observability/active-story-env.js',
|
|
75
73
|
'# Re-generated on every story-init; deleted on story-close.',
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return lines.join('\n');
|
|
74
|
+
`CC_STORY_ID=${storyId}`,
|
|
75
|
+
'',
|
|
76
|
+
].join('\n');
|
|
80
77
|
}
|
|
81
78
|
|
|
82
79
|
/**
|
|
83
|
-
* Set `
|
|
84
|
-
*
|
|
80
|
+
* Set `CC_STORY_ID` on the current process and (when `workCwd` is provided)
|
|
81
|
+
* export it to `<workCwd>/.env.local`.
|
|
85
82
|
*
|
|
86
|
-
* Idempotent: re-running with the same
|
|
87
|
-
* different
|
|
83
|
+
* Idempotent: re-running with the same id is a no-op on disk; with a
|
|
84
|
+
* different id the `.env.local` is overwritten.
|
|
88
85
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* no-op contract is keyed on the var's absence).
|
|
94
|
-
* - The rendered `.env.local` omits the `CC_EPIC_ID=` line.
|
|
95
|
-
* - `CC_STORY_ID` behaviour is unchanged.
|
|
96
|
-
* All other invalid `epicId` values (`0`, negative, NaN, non-integer)
|
|
97
|
-
* still throw — `null` is the only standalone signal.
|
|
86
|
+
* v2 Stories are standalone — there is no parent Epic — so `CC_EPIC_ID` is
|
|
87
|
+
* never set, and any pre-existing value is removed: the trace hook's
|
|
88
|
+
* `resolveActiveStory` no-op contract is keyed on the var's absence, and a
|
|
89
|
+
* stale epic id would key this Story's traces to a foreign Epic directory.
|
|
98
90
|
*
|
|
99
|
-
* @param {{
|
|
91
|
+
* @param {{ storyId: number, workCwd?: string,
|
|
100
92
|
* env?: NodeJS.ProcessEnv, fs?: typeof nodeFs,
|
|
101
93
|
* logger?: { warn?: (m: string) => void } }} args
|
|
102
94
|
* @returns {{ envSet: boolean, fileWritten: boolean, filePath: string|null }}
|
|
103
95
|
*/
|
|
104
96
|
export function setActiveStoryEnv({
|
|
105
|
-
epicId,
|
|
106
97
|
storyId,
|
|
107
98
|
workCwd,
|
|
108
99
|
env = process.env,
|
|
109
100
|
fs = nodeFs,
|
|
110
101
|
logger,
|
|
111
102
|
} = {}) {
|
|
112
|
-
if (epicId !== null && (!Number.isInteger(epicId) || epicId <= 0)) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
`[active-story-env] epicId must be a positive integer or null; got ${epicId}`,
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
103
|
if (!Number.isInteger(storyId) || storyId <= 0) {
|
|
118
104
|
throw new Error(
|
|
119
105
|
`[active-story-env] storyId must be a positive integer; got ${storyId}`,
|
|
120
106
|
);
|
|
121
107
|
}
|
|
122
108
|
|
|
123
|
-
if (
|
|
124
|
-
// Standalone Story — ensure CC_EPIC_ID is absent so the trace
|
|
125
|
-
// hook's no-op contract sees "no epic" rather than "epic=''".
|
|
126
|
-
if ('CC_EPIC_ID' in env) delete env.CC_EPIC_ID;
|
|
127
|
-
} else {
|
|
128
|
-
env.CC_EPIC_ID = String(epicId);
|
|
129
|
-
}
|
|
109
|
+
if ('CC_EPIC_ID' in env) delete env.CC_EPIC_ID;
|
|
130
110
|
env.CC_STORY_ID = String(storyId);
|
|
131
111
|
|
|
132
112
|
let fileWritten = false;
|
|
@@ -134,13 +114,9 @@ export function setActiveStoryEnv({
|
|
|
134
114
|
if (typeof workCwd === 'string' && workCwd.length > 0) {
|
|
135
115
|
filePath = nodePath.join(workCwd, ENV_LOCAL_BASENAME);
|
|
136
116
|
try {
|
|
137
|
-
fs.writeFileSync(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
{
|
|
141
|
-
encoding: 'utf8',
|
|
142
|
-
},
|
|
143
|
-
);
|
|
117
|
+
fs.writeFileSync(filePath, renderActiveStoryEnvFile({ storyId }), {
|
|
118
|
+
encoding: 'utf8',
|
|
119
|
+
});
|
|
144
120
|
fileWritten = true;
|
|
145
121
|
} catch (err) {
|
|
146
122
|
logger?.warn?.(
|
|
@@ -192,100 +168,3 @@ export function clearActiveStoryEnv({
|
|
|
192
168
|
}
|
|
193
169
|
return { envCleared: true, fileRemoved, filePath };
|
|
194
170
|
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Render the single-delivery `.env.local` body. The single-delivery executor
|
|
198
|
-
* (`deliver-epic-single.md`) walks the Delivery Slicing table inside ONE long
|
|
199
|
-
* session; there is no Story fan-out and thus no `CC_STORY_ID`. Instead the
|
|
200
|
-
* "current slice" is exported as `CC_SLICE_ID` so the PostToolUse hook emits
|
|
201
|
-
* `slice.heartbeat` — the watchdog's forward-progress signal for the single
|
|
202
|
-
* session — as a free byproduct of tool activity.
|
|
203
|
-
*
|
|
204
|
-
* `CC_STORY_ID` MUST be absent (its presence would make the hook emit
|
|
205
|
-
* `story.heartbeat` and the trace path key off a non-existent Story). The
|
|
206
|
-
* optional `operator` handle is emitted as `CC_OPERATOR` only when supplied.
|
|
207
|
-
*
|
|
208
|
-
* Exported for testing.
|
|
209
|
-
*
|
|
210
|
-
* @param {{ epicId: number, sliceId: string, operator?: string }} input
|
|
211
|
-
* @returns {string}
|
|
212
|
-
*/
|
|
213
|
-
export function renderActiveSliceEnvFile({ epicId, sliceId, operator }) {
|
|
214
|
-
const lines = [
|
|
215
|
-
'# Auto-managed by .agents/scripts/lib/observability/active-story-env.js',
|
|
216
|
-
'# Re-generated on every slice-start; deleted on epic-close.',
|
|
217
|
-
`CC_EPIC_ID=${epicId}`,
|
|
218
|
-
`CC_SLICE_ID=${sliceId}`,
|
|
219
|
-
];
|
|
220
|
-
if (typeof operator === 'string' && operator.length > 0) {
|
|
221
|
-
lines.push(`CC_OPERATOR=${operator}`);
|
|
222
|
-
}
|
|
223
|
-
lines.push('');
|
|
224
|
-
return lines.join('\n');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Set `CC_EPIC_ID` / `CC_SLICE_ID` (+ optional `CC_OPERATOR`) on the current
|
|
229
|
-
* process and, when `workCwd` is provided, export them to
|
|
230
|
-
* `<workCwd>/.env.local` for the harness to reload on the next tool call. The
|
|
231
|
-
* single-delivery analogue of {@link setActiveStoryEnv}; called at each
|
|
232
|
-
* `slice.start` boundary so the hook's throttled `slice.heartbeat` is keyed to
|
|
233
|
-
* the slice currently being implemented.
|
|
234
|
-
*
|
|
235
|
-
* `CC_STORY_ID` is explicitly removed so a prior Story context (if any ever
|
|
236
|
-
* leaked in) cannot make the hook emit the wrong heartbeat shape.
|
|
237
|
-
*
|
|
238
|
-
* @param {{ epicId: number, sliceId: string, operator?: string|null,
|
|
239
|
-
* workCwd?: string, env?: NodeJS.ProcessEnv, fs?: typeof nodeFs,
|
|
240
|
-
* logger?: { warn?: (m: string) => void } }} args
|
|
241
|
-
* @returns {{ envSet: boolean, fileWritten: boolean, filePath: string|null }}
|
|
242
|
-
*/
|
|
243
|
-
export function setActiveSliceEnv({
|
|
244
|
-
epicId,
|
|
245
|
-
sliceId,
|
|
246
|
-
operator,
|
|
247
|
-
workCwd,
|
|
248
|
-
env = process.env,
|
|
249
|
-
fs = nodeFs,
|
|
250
|
-
logger,
|
|
251
|
-
} = {}) {
|
|
252
|
-
if (!Number.isInteger(epicId) || epicId <= 0) {
|
|
253
|
-
throw new Error(
|
|
254
|
-
`[active-story-env] epicId must be a positive integer; got ${epicId}`,
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
if (typeof sliceId !== 'string' || sliceId.length === 0) {
|
|
258
|
-
throw new Error(
|
|
259
|
-
`[active-story-env] sliceId must be a non-empty string; got ${sliceId}`,
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
const normOperator =
|
|
263
|
-
typeof operator === 'string' && operator.length > 0 ? operator : undefined;
|
|
264
|
-
|
|
265
|
-
if ('CC_STORY_ID' in env) delete env.CC_STORY_ID;
|
|
266
|
-
env.CC_EPIC_ID = String(epicId);
|
|
267
|
-
env.CC_SLICE_ID = sliceId;
|
|
268
|
-
if (normOperator) env.CC_OPERATOR = normOperator;
|
|
269
|
-
else if ('CC_OPERATOR' in env) delete env.CC_OPERATOR;
|
|
270
|
-
|
|
271
|
-
let fileWritten = false;
|
|
272
|
-
let filePath = null;
|
|
273
|
-
if (typeof workCwd === 'string' && workCwd.length > 0) {
|
|
274
|
-
filePath = nodePath.join(workCwd, ENV_LOCAL_BASENAME);
|
|
275
|
-
try {
|
|
276
|
-
fs.writeFileSync(
|
|
277
|
-
filePath,
|
|
278
|
-
renderActiveSliceEnvFile({ epicId, sliceId, operator: normOperator }),
|
|
279
|
-
{ encoding: 'utf8' },
|
|
280
|
-
);
|
|
281
|
-
fileWritten = true;
|
|
282
|
-
} catch (err) {
|
|
283
|
-
logger?.warn?.(
|
|
284
|
-
`[active-story-env] Failed to write ${filePath}: ${
|
|
285
|
-
err instanceof Error ? err.message : String(err)
|
|
286
|
-
}`,
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return { envSet: true, fileWritten, filePath };
|
|
291
|
-
}
|