mandrel 1.59.0 → 1.61.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 +86 -44
- package/.agents/docs/SDLC.md +135 -141
- package/.agents/docs/configuration.md +77 -20
- package/.agents/docs/quality-gates.md +796 -0
- package/.agents/docs/workflows.md +6 -9
- package/.agents/instructions.md +12 -11
- package/.agents/personas/architect.md +1 -1
- package/.agents/personas/product.md +1 -1
- package/.agents/personas/project-manager.md +14 -14
- package/.agents/personas/technical-writer.md +1 -1
- package/.agents/rules/changelog-style.md +5 -5
- package/.agents/rules/git-conventions.md +3 -3
- package/.agents/runtime-deps.json +2 -2
- package/.agents/schemas/agentrc.schema.json +3 -3
- package/.agents/schemas/dispatch-manifest.json +4 -4
- package/.agents/schemas/epic-spec.schema.json +15 -45
- package/.agents/schemas/lifecycle/README.md +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +1 -1
- package/.agents/schemas/lifecycle/story.heartbeat.schema.json +1 -1
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/README.md +2 -2
- package/.agents/scripts/acceptance-eval.js +1 -1
- package/.agents/scripts/acceptance-spec-reconciler.js +2 -2
- package/.agents/scripts/agents-bootstrap-github.js +23 -119
- package/.agents/scripts/analyze-execution.js +2 -2
- package/.agents/scripts/audit-to-stories.js +1 -1
- package/.agents/scripts/check-doc-links.js +2 -3
- package/.agents/scripts/diagnose-friction.js +1 -1
- package/.agents/scripts/dispatcher.js +2 -2
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/epic-audit-prepare.js +3 -3
- package/.agents/scripts/epic-deliver-note-intervention.js +2 -2
- package/.agents/scripts/epic-deliver-preflight.js +6 -6
- package/.agents/scripts/epic-deliver-prepare.js +1 -1
- package/.agents/scripts/epic-execute-record-wave.js +4 -4
- package/.agents/scripts/epic-plan-healthcheck.js +6 -10
- package/.agents/scripts/epic-plan-spec-validate.js +1 -1
- package/.agents/scripts/epic-reconcile.js +11 -29
- package/.agents/scripts/evidence-gate.js +1 -1
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/hierarchy-gate.js +7 -11
- package/.agents/scripts/lib/ITicketingProvider.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-epic-from-findings.js +2 -2
- package/.agents/scripts/lib/baseline-snapshot.js +7 -7
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +47 -1
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/bootstrap/gh-preflight.js +7 -9
- package/.agents/scripts/lib/bootstrap/manifest.js +21 -1
- package/.agents/scripts/lib/bootstrap/merge-methods.js +31 -16
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +32 -11
- package/.agents/scripts/lib/codebase-snapshot.js +1 -1
- package/.agents/scripts/lib/config/explain.js +1 -1
- package/.agents/scripts/lib/config/runners.js +2 -2
- package/.agents/scripts/lib/config/runtime.js +1 -1
- package/.agents/scripts/lib/config/sync-agentrc.js +1 -1
- package/.agents/scripts/lib/config/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-quality.js +1 -1
- package/.agents/scripts/lib/config-settings-schema.js +3 -3
- package/.agents/scripts/lib/detect-package-manager.js +72 -0
- package/.agents/scripts/lib/duplicate-search.js +1 -1
- package/.agents/scripts/lib/dynamic-workflow/capability.js +1 -1
- package/.agents/scripts/lib/epic-plan-clarity.js +1 -1
- package/.agents/scripts/lib/epic-plan-ideation.js +1 -1
- package/.agents/scripts/lib/errors/index.js +4 -4
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +1 -1
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +1 -1
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +10 -10
- package/.agents/scripts/lib/label-constants.js +3 -4
- package/.agents/scripts/lib/label-taxonomy.js +5 -10
- package/.agents/scripts/lib/onboard/detect-stack.js +10 -10
- package/.agents/scripts/lib/onboard/init-tail.js +218 -0
- package/.agents/scripts/lib/onboard/scaffold-docs.js +18 -3
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
- package/.agents/scripts/lib/orchestration/code-review.js +5 -5
- package/.agents/scripts/lib/orchestration/context-hydration-engine.js +8 -9
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +3 -3
- package/.agents/scripts/lib/orchestration/detectors-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/dispatch-engine.js +30 -38
- package/.agents/scripts/lib/orchestration/dispatch-pipeline.js +9 -25
- package/.agents/scripts/lib/orchestration/epic-cleanup.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-deliver-lease-guard.js +8 -8
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/creation.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/dag.js +7 -21
- package/.agents/scripts/lib/orchestration/epic-plan-decompose/phases/diagnostics.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-plan-lease-guard.js +26 -13
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/plan-epic.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-plan-state-store.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-run-state-store.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/concurrency-gate.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/deliver-phases.js +3 -3
- package/.agents/scripts/lib/orchestration/epic-runner/phases/build-wave-dag.js +6 -21
- package/.agents/scripts/lib/orchestration/epic-runner/phases/snapshot.js +7 -7
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/composition.js +1 -1
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/signals.js +2 -2
- package/.agents/scripts/lib/orchestration/epic-runner/progress-reporter/transport.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-launcher.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-runner/story-run-progress-writer.js +8 -8
- package/.agents/scripts/lib/orchestration/epic-runner/sub-agent-return.js +4 -4
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-apply.js +7 -15
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-diff.js +72 -41
- package/.agents/scripts/lib/orchestration/epic-spec-reconciler-ops.js +2 -4
- package/.agents/scripts/lib/orchestration/file-assumptions.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/close-planning-tickets.js +1 -1
- package/.agents/scripts/lib/orchestration/finalize/open-or-locate-pr.js +2 -2
- package/.agents/scripts/lib/orchestration/finalize/sanitize-skip-ci.js +1 -1
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +3 -3
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-dispatch-end.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/emit-story-heartbeat.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/branch-cleaner.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +1 -1
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/watcher.js +1 -1
- package/.agents/scripts/lib/orchestration/manifest-builder.js +5 -5
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-runner/plan-router.js +5 -5
- package/.agents/scripts/lib/orchestration/post-merge/phases/ticket-closure.js +3 -3
- package/.agents/scripts/lib/orchestration/preflight-cache.js +1 -1
- package/.agents/scripts/lib/orchestration/recurring-failure-detector.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +1 -1
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +2 -2
- package/.agents/scripts/lib/orchestration/retro-runner.js +3 -3
- package/.agents/scripts/lib/orchestration/review-depth.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-freshness.js +1 -1
- package/.agents/scripts/lib/orchestration/spec-renderer.js +36 -73
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/baseline-friction-body.js +1 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/locked-pipeline.js +2 -2
- package/.agents/scripts/lib/orchestration/task-body-validator.js +6 -6
- package/.agents/scripts/lib/orchestration/ticket-lease.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +2 -2
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -10
- package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -70
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +5 -12
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +8 -8
- package/.agents/scripts/lib/orchestration/ticketing/state.js +3 -3
- package/.agents/scripts/lib/orchestration/wave-record-notifications.js +2 -2
- package/.agents/scripts/lib/orchestration/wave-record-projection.js +1 -1
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +1 -1
- package/.agents/scripts/lib/presentation/dispatch-manifest-render.js +4 -5
- package/.agents/scripts/lib/presentation/manifest-builder.js +28 -34
- package/.agents/scripts/lib/presentation/manifest-formatter.js +3 -4
- package/.agents/scripts/lib/presentation/manifest-helpers.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-procedures.js +4 -4
- package/.agents/scripts/lib/presentation/manifest-render-waves.js +4 -23
- package/.agents/scripts/lib/presentation/manifest-renderer.js +1 -1
- package/.agents/scripts/lib/presentation/manifest-story-views.js +2 -11
- package/.agents/scripts/lib/runtime-deps/preflight.js +6 -6
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/spec/index.js +1 -1
- package/.agents/scripts/lib/spec/loader.js +2 -2
- package/.agents/scripts/lib/spec/state.js +7 -16
- package/.agents/scripts/lib/story-init/context-resolver.js +3 -3
- package/.agents/scripts/lib/story-init/state-transitioner.js +2 -2
- package/.agents/scripts/lib/story-init/task-graph-builder.js +7 -7
- package/.agents/scripts/lib/story-lifecycle.js +8 -8
- package/.agents/scripts/lib/story-plan.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +59 -52
- package/.agents/scripts/lib/wave-runner/tick.js +1 -1
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +5 -2
- package/.agents/scripts/lifecycle-emit-story-dispatch.js +1 -1
- package/.agents/scripts/lifecycle-emit.js +1 -1
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/mappers.js +2 -2
- package/.agents/scripts/providers/github/tickets.js +4 -4
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/retro-run.js +2 -2
- package/.agents/scripts/run-lint.js +1 -1
- package/.agents/scripts/single-story-init.js +1 -1
- package/.agents/scripts/stories-wave-tick.js +5 -5
- package/.agents/scripts/story-close.js +1 -1
- package/.agents/scripts/story-init.js +13 -16
- package/.agents/scripts/story-phase.js +5 -5
- package/.agents/scripts/story-plan.js +3 -3
- package/.agents/scripts/sync-branch-from-base.js +1 -1
- package/.agents/scripts/validate-docs-freshness.js +1 -1
- package/.agents/scripts/wave-tick.js +1 -1
- package/.agents/skills/core/analyze-execution/SKILL.md +2 -2
- package/.agents/skills/core/epic-plan-consolidate/SKILL.md +21 -26
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +23 -56
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +4 -4
- package/.agents/skills/core/hydrate-context/SKILL.md +2 -2
- package/.agents/skills/core/idea-refinement/SKILL.md +4 -4
- package/.agents/skills/core/knowledge-transfer/SKILL.md +2 -2
- package/.agents/skills/core/planning-and-task-breakdown/SKILL.md +1 -1
- package/.agents/skills/core/scope-triage/SKILL.md +9 -10
- package/.agents/skills/core/using-agent-skills/SKILL.md +1 -1
- package/.agents/skills/skills.index.json +7 -7
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/workflows/agents-update.md +16 -31
- package/.agents/workflows/audit-architecture.md +2 -2
- package/.agents/workflows/audit-clean-code.md +2 -2
- package/.agents/workflows/audit-dependencies.md +1 -1
- package/.agents/workflows/audit-devops.md +1 -1
- package/.agents/workflows/audit-documentation.md +2 -2
- package/.agents/workflows/audit-lighthouse.md +1 -1
- package/.agents/workflows/audit-performance.md +2 -2
- package/.agents/workflows/audit-privacy.md +1 -1
- package/.agents/workflows/audit-quality.md +2 -2
- package/.agents/workflows/audit-security.md +2 -2
- package/.agents/workflows/audit-seo.md +1 -1
- package/.agents/workflows/audit-sre.md +1 -1
- package/.agents/workflows/audit-to-stories.md +10 -10
- package/.agents/workflows/audit-ux-ui.md +1 -1
- package/.agents/workflows/deliver.md +85 -0
- package/.agents/workflows/explain.md +3 -3
- package/.agents/workflows/git-merge-pr.md +1 -1
- package/.agents/workflows/git-pr-all.md +13 -10
- package/.agents/workflows/git-push.md +6 -3
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
- package/.agents/workflows/helpers/agents-sync-config.md +3 -2
- package/.agents/workflows/helpers/code-review.md +5 -5
- package/.agents/workflows/{epic-deliver.md → helpers/deliver-epic.md} +43 -43
- package/.agents/workflows/{story-deliver.md → helpers/deliver-stories.md} +25 -25
- package/.agents/workflows/helpers/diagnose.md +1 -1
- package/.agents/workflows/helpers/epic-audit.md +6 -6
- package/.agents/workflows/helpers/epic-deliver-story.md +13 -13
- package/.agents/workflows/helpers/epic-plan-decompose.md +23 -23
- package/.agents/workflows/helpers/epic-plan-spec.md +6 -6
- package/.agents/workflows/helpers/epic-testing.md +3 -3
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/{epic-plan.md → helpers/plan-epic.md} +84 -84
- package/.agents/workflows/{story-plan.md → helpers/plan-story.md} +43 -43
- package/.agents/workflows/helpers/signals.md +1 -1
- package/.agents/workflows/helpers/single-story-deliver.md +11 -11
- package/.agents/workflows/helpers/worktree-lifecycle.md +18 -18
- package/.agents/workflows/plan.md +131 -0
- package/.agents/workflows/qa-explore.md +1 -1
- package/.agents/workflows/qa-run-harness.md +1 -1
- package/README.md +19 -39
- package/bin/mandrel.js +235 -16
- package/docs/CHANGELOG.md +1173 -0
- package/lib/cli/doctor.js +45 -3
- package/lib/cli/init.js +97 -36
- package/lib/cli/registry.js +41 -145
- package/lib/cli/sync.js +122 -23
- package/lib/cli/uninstall.js +42 -7
- package/lib/cli/update.js +524 -210
- package/lib/cli/version-helpers.js +59 -0
- package/package.json +7 -6
- package/.agents/scripts/lib/orchestration/reconciler.js +0 -137
- package/.agents/workflows/onboard.md +0 -208
- package/lib/cli/__tests__/migrate.test.js +0 -268
- package/lib/cli/__tests__/sync-local-zone.test.js +0 -247
- package/lib/cli/__tests__/sync.test.js +0 -372
- package/lib/cli/__tests__/update-major.test.js +0 -217
- package/lib/cli/__tests__/update.test.js +0 -696
- package/lib/cli/__tests__/version-check.test.js +0 -398
- package/lib/migrations/__tests__/index.test.js +0 -216
|
@@ -15,13 +15,7 @@
|
|
|
15
15
|
* @see docs/v5-implementation-plan.md Sprint 1C
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import fs from 'node:fs';
|
|
19
|
-
import path from 'node:path';
|
|
20
18
|
import { applyBranchProtection } from './lib/bootstrap/branch-protection.js';
|
|
21
|
-
import {
|
|
22
|
-
CI_WORKFLOW_RELATIVE_PATH,
|
|
23
|
-
renderCiWorkflow,
|
|
24
|
-
} from './lib/bootstrap/ci-workflow-template.js';
|
|
25
19
|
import {
|
|
26
20
|
compareSemver,
|
|
27
21
|
MIN_GH_VERSION,
|
|
@@ -55,7 +49,7 @@ import {
|
|
|
55
49
|
import { createProvider } from './lib/provider-factory.js';
|
|
56
50
|
|
|
57
51
|
const PROJECTS_DOC_POINTER =
|
|
58
|
-
'
|
|
52
|
+
'Configure the board views manually in the GitHub Projects UI.';
|
|
59
53
|
|
|
60
54
|
/**
|
|
61
55
|
* Detect that an error is a not-found / 404 signal across the surfaces
|
|
@@ -266,106 +260,6 @@ async function ensureProjectFields(provider, project, log) {
|
|
|
266
260
|
return fields;
|
|
267
261
|
}
|
|
268
262
|
|
|
269
|
-
/**
|
|
270
|
-
* Create or additively-merge branch protection on `baseBranch` (typically
|
|
271
|
-
* `main`) so the `delivery.quality.prGate.checks` suite is required
|
|
272
|
-
* before merge. Behaviour rules:
|
|
273
|
-
*
|
|
274
|
-
* - `enforceBranchProtection: false` → skip, log the opt-out, return a
|
|
275
|
-
* `{ status: 'skipped' }` summary.
|
|
276
|
-
* - `prGate.checks` empty or absent → skip with a clear log, since there
|
|
277
|
-
* is nothing to enforce.
|
|
278
|
-
* - Existing protection rule → preserve every existing required-check
|
|
279
|
-
* context and append only the missing prGate names.
|
|
280
|
-
* - No existing rule → create a fresh one carrying just the prGate
|
|
281
|
-
* contexts plus minimal sensible defaults (strict status checks).
|
|
282
|
-
*
|
|
283
|
-
* Errors (insufficient scopes, repo permission denied, etc.) are logged
|
|
284
|
-
* and return a `{ status: 'failed' }` summary so the bootstrap CLI
|
|
285
|
-
* surfaces a non-fatal warning rather than aborting the entire run —
|
|
286
|
-
* matching how the project-board provisioning steps degrade.
|
|
287
|
-
*/
|
|
288
|
-
async function ensureMainBranchProtection(
|
|
289
|
-
provider,
|
|
290
|
-
{ baseBranch, prGate },
|
|
291
|
-
log,
|
|
292
|
-
) {
|
|
293
|
-
if (prGate?.enforceBranchProtection === false) {
|
|
294
|
-
log(
|
|
295
|
-
`[bootstrap] Branch protection on '${baseBranch}': skipped (delivery.quality.prGate.enforceBranchProtection=false).`,
|
|
296
|
-
);
|
|
297
|
-
return { status: 'skipped', reason: 'opt-out' };
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const checkNames = (prGate?.checks ?? [])
|
|
301
|
-
.map((c) => c?.name)
|
|
302
|
-
.filter((n) => typeof n === 'string' && n.length > 0);
|
|
303
|
-
if (checkNames.length === 0) {
|
|
304
|
-
log(
|
|
305
|
-
`[bootstrap] Branch protection on '${baseBranch}': skipped (no prGate.checks configured).`,
|
|
306
|
-
);
|
|
307
|
-
return { status: 'skipped', reason: 'no-checks' };
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
try {
|
|
311
|
-
const result = await provider.setBranchProtection(baseBranch, {
|
|
312
|
-
contexts: checkNames,
|
|
313
|
-
});
|
|
314
|
-
const verb = result.created ? 'Created' : 'Updated';
|
|
315
|
-
const addedSuffix = result.added.length
|
|
316
|
-
? ` (added: ${result.added.join(', ')})`
|
|
317
|
-
: ' (all required checks already present)';
|
|
318
|
-
log(
|
|
319
|
-
`[bootstrap] Branch protection on '${baseBranch}': ${verb} rule${addedSuffix}.`,
|
|
320
|
-
);
|
|
321
|
-
return { status: result.created ? 'created' : 'merged', ...result };
|
|
322
|
-
} catch (err) {
|
|
323
|
-
log(
|
|
324
|
-
`[bootstrap] Branch protection on '${baseBranch}': failed — ${err.message}. Proceeding without it.`,
|
|
325
|
-
);
|
|
326
|
-
return { status: 'failed', reason: err.message };
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Render the stabilized-quality-gates CI workflow template into a project
|
|
332
|
-
* checkout. Idempotent on the byte level: when `.github/workflows/ci.yml`
|
|
333
|
-
* already matches the rendered template, no write occurs and the action is
|
|
334
|
-
* `unchanged`. When the file is absent the action is `created`. When the
|
|
335
|
-
* file exists with operator-authored differences the helper preserves it
|
|
336
|
-
* and returns `custom-workflow-skip` along with the rendered body so the
|
|
337
|
-
* bootstrap caller (or `/agents-update`) can offer a side-by-side diff.
|
|
338
|
-
*
|
|
339
|
-
* Network-free; safe to invoke under tests with a tmp `projectRoot`.
|
|
340
|
-
*
|
|
341
|
-
* @param {object} args
|
|
342
|
-
* @param {string} args.projectRoot - Repo root (must contain or accept
|
|
343
|
-
* `.github/workflows/`).
|
|
344
|
-
* @param {object} [args.template] - Forwarded to `renderCiWorkflow`.
|
|
345
|
-
* @param {boolean} [args.write=true] - When `false`, the helper computes
|
|
346
|
-
* the would-be action without touching disk. Used by the
|
|
347
|
-
* bootstrap CLI's dry-run mode.
|
|
348
|
-
* @returns {{ action: 'created'|'unchanged'|'custom-workflow-skip',
|
|
349
|
-
* path: string, rendered: string }}
|
|
350
|
-
*/
|
|
351
|
-
export function ensureCiWorkflow(args) {
|
|
352
|
-
const projectRoot = args.projectRoot;
|
|
353
|
-
const rendered = renderCiWorkflow(args.template);
|
|
354
|
-
const target = path.join(projectRoot, CI_WORKFLOW_RELATIVE_PATH);
|
|
355
|
-
if (!fs.existsSync(target)) {
|
|
356
|
-
if (args.write !== false) {
|
|
357
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
358
|
-
fs.writeFileSync(target, rendered, 'utf8');
|
|
359
|
-
}
|
|
360
|
-
return { action: 'created', path: target, rendered };
|
|
361
|
-
}
|
|
362
|
-
const existing = fs.readFileSync(target, 'utf8');
|
|
363
|
-
if (existing === rendered) {
|
|
364
|
-
return { action: 'unchanged', path: target, rendered };
|
|
365
|
-
}
|
|
366
|
-
return { action: 'custom-workflow-skip', path: target, rendered };
|
|
367
|
-
}
|
|
368
|
-
|
|
369
263
|
/**
|
|
370
264
|
* Run the idempotent bootstrap sequence.
|
|
371
265
|
*
|
|
@@ -397,6 +291,7 @@ export function ensureCiWorkflow(args) {
|
|
|
397
291
|
* github?: object,
|
|
398
292
|
* baseBranch?: string,
|
|
399
293
|
* githubAdminApproved?: boolean,
|
|
294
|
+
* isTTY?: boolean,
|
|
400
295
|
* }} [opts] - `githubAdminApproved` MUST be `true` for any GitHub mutation to
|
|
401
296
|
* occur; any other value (absent / `false`) is treated as "not approved"
|
|
402
297
|
* and the run is a verified no-op.
|
|
@@ -463,12 +358,12 @@ export async function runBootstrap(config, opts = {}) {
|
|
|
463
358
|
// Consumer-facing bootstrap promotes the framework's CI-gates-only
|
|
464
359
|
// stance: branch protection with enforce_admins + 0-approval-count and
|
|
465
360
|
// the squash-only merge-method allowlist. Behavior-shifting drift on
|
|
466
|
-
//
|
|
467
|
-
// with a clear stderr message rather than silently apply.
|
|
361
|
+
// branch protection routes through the HITL confirm gate — non-TTY runs
|
|
362
|
+
// abort with a clear stderr message rather than silently apply. The
|
|
363
|
+
// merge-method step differs by design (Story #4045 A4): non-TTY without an
|
|
364
|
+
// assume override default-applies the framework stance with an explicit
|
|
365
|
+
// log line (see mergeMethodsHitlConfirm below).
|
|
468
366
|
//
|
|
469
|
-
// The legacy `ensureMainBranchProtection` helper is preserved (re-
|
|
470
|
-
// exported below) so the Epic #1142 Story #1157 contract tests stay
|
|
471
|
-
// green; `applyBranchProtection` is its consumer-parity successor.
|
|
472
367
|
// Post-reshape: bootstrap reads from the new `project` + `github` blocks
|
|
473
368
|
// exclusively. The legacy "agent settings" opt was removed in Epic #2880.
|
|
474
369
|
const projectCfg = opts.project ?? config.project ?? {};
|
|
@@ -493,10 +388,22 @@ export async function runBootstrap(config, opts = {}) {
|
|
|
493
388
|
hitlConfirm,
|
|
494
389
|
log,
|
|
495
390
|
});
|
|
391
|
+
|
|
392
|
+
// Merge-methods gate (Story #4045 A4): under non-TTY without an explicit
|
|
393
|
+
// assume override there is no operator to consult, and the default HITL
|
|
394
|
+
// gate declines every non-TTY prompt — which would make applyMergeMethods'
|
|
395
|
+
// documented non-TTY default-apply branch unreachable. Skip the gate in
|
|
396
|
+
// that case so the merge-method stance default-applies with its explicit
|
|
397
|
+
// log line. Interactive runs (and explicit --assume-yes/--assume-no, and
|
|
398
|
+
// injected gates) keep the loud confirm/decline behaviour.
|
|
399
|
+
const stdoutIsTTY = opts.isTTY ?? Boolean(process.stdout.isTTY);
|
|
400
|
+
const mergeMethodsHitlConfirm =
|
|
401
|
+
opts.hitlConfirm ??
|
|
402
|
+
(stdoutIsTTY || opts.assumeYes || opts.assumeNo ? hitlConfirm : undefined);
|
|
496
403
|
const mergeMethods = await applyMergeMethods({
|
|
497
404
|
provider,
|
|
498
405
|
settings,
|
|
499
|
-
hitlConfirm,
|
|
406
|
+
hitlConfirm: mergeMethodsHitlConfirm,
|
|
500
407
|
log,
|
|
501
408
|
});
|
|
502
409
|
|
|
@@ -539,8 +446,9 @@ async function main() {
|
|
|
539
446
|
}
|
|
540
447
|
|
|
541
448
|
// Preflight runtime deps before the dynamic config-resolver import so
|
|
542
|
-
// a
|
|
543
|
-
//
|
|
449
|
+
// a consumer who hasn't installed framework runtime deps yet gets a
|
|
450
|
+
// clear hint (`run mandrel init` or `npm install mandrel`) instead of
|
|
451
|
+
// a raw `ERR_MODULE_NOT_FOUND`.
|
|
544
452
|
try {
|
|
545
453
|
await preflightRuntimeDeps();
|
|
546
454
|
} catch (err) {
|
|
@@ -569,7 +477,6 @@ async function main() {
|
|
|
569
477
|
process.exit(1);
|
|
570
478
|
}
|
|
571
479
|
|
|
572
|
-
const installWorkflows = process.argv.includes('--install-workflows');
|
|
573
480
|
// Epic #1235 Story 5 — flags let CI / non-interactive callers pin the
|
|
574
481
|
// HITL gate's answer deterministically. The bootstrap is non-interactive
|
|
575
482
|
// by default in non-TTY contexts (the gate returns false and aborts);
|
|
@@ -594,7 +501,6 @@ async function main() {
|
|
|
594
501
|
|
|
595
502
|
try {
|
|
596
503
|
const result = await runBootstrap(config, {
|
|
597
|
-
installWorkflows,
|
|
598
504
|
project: config.project,
|
|
599
505
|
github: config.github,
|
|
600
506
|
assumeYes,
|
|
@@ -617,12 +523,10 @@ async function main() {
|
|
|
617
523
|
}
|
|
618
524
|
}
|
|
619
525
|
|
|
620
|
-
// Re-export internal helpers for test consumers (no production caller imports them).
|
|
621
526
|
// Re-export the gh-preflight surface so existing test consumers can keep
|
|
622
527
|
// importing it from this module after the Story #3349 split.
|
|
623
528
|
export {
|
|
624
529
|
compareSemver,
|
|
625
|
-
ensureMainBranchProtection,
|
|
626
530
|
isApiAccessNotFoundError,
|
|
627
531
|
MIN_GH_VERSION,
|
|
628
532
|
parseGhVersion,
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* fetching each `story-perf-summary` structured comment from the
|
|
19
19
|
* ticketing provider. Posts the
|
|
20
20
|
* `<!-- structured:epic-perf-report -->` comment on the Epic ticket.
|
|
21
|
-
* Run from the retro composer / `/
|
|
21
|
+
* Run from the retro composer / `/deliver` Phase 6.0.
|
|
22
22
|
*
|
|
23
23
|
* Both modes are idempotent: `upsertStructuredComment` deletes the prior
|
|
24
24
|
* marker before posting the new one.
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* NDJSON for a Story, no children for an Epic) so the close pipelines
|
|
28
28
|
* never block on observability output. Hard failures (bad CLI args,
|
|
29
29
|
* provider error, schema-violating payload) exit non-zero — the call
|
|
30
|
-
* sites in post-merge-pipeline / `/
|
|
30
|
+
* sites in post-merge-pipeline / `/deliver` Phase 5 treat that
|
|
31
31
|
* as a non-fatal warning.
|
|
32
32
|
*
|
|
33
33
|
* This file is a thin CLI: it wires the I/O readers from
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* stdout when --json is set).
|
|
14
14
|
*
|
|
15
15
|
* --emit-epic-seed --plan <plan.json> --out <path>
|
|
16
|
-
* Read the plan envelope from disk, render the `/
|
|
16
|
+
* Read the plan envelope from disk, render the `/plan --idea`
|
|
17
17
|
* seed markdown, persist to --out.
|
|
18
18
|
*
|
|
19
19
|
* --emit-stories --plan <plan.json>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// Story #2662 — Internal-link and slash-command resolver for active docs.
|
|
6
6
|
//
|
|
7
7
|
// Scans every `*.md` under `docs/` and `.agents/` (excluding
|
|
8
|
-
// `docs/CHANGELOG.md`
|
|
8
|
+
// `docs/CHANGELOG.md`) and validates:
|
|
9
9
|
//
|
|
10
10
|
// 1. Every Markdown relative-path link `[text](relative/path[#anchor])`
|
|
11
11
|
// resolves to a real file on disk (anchors are not validated, only
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
//
|
|
20
20
|
// 3. No active doc mentions any retired slash command. The retired-command
|
|
21
21
|
// blocklist is seeded with `agents-bootstrap-github`,
|
|
22
|
-
// `single-story-plan` (renamed to `/
|
|
22
|
+
// `single-story-plan` (renamed to `/plan`), and `mandrel`
|
|
23
23
|
// (retired in favor of the generated `.agents/docs/workflows.md`
|
|
24
24
|
// catalog) and takes precedence over the workflow-resolution check —
|
|
25
25
|
// a retired token is always a non-zero exit even if a stale workflow
|
|
@@ -125,7 +125,6 @@ export const SLASH_ALLOWLIST = new Set([
|
|
|
125
125
|
|
|
126
126
|
function isExcludedRelPath(relPath) {
|
|
127
127
|
if (relPath === 'docs/CHANGELOG.md') return true;
|
|
128
|
-
if (relPath.startsWith('docs/archive/')) return true;
|
|
129
128
|
return false;
|
|
130
129
|
}
|
|
131
130
|
|
|
@@ -134,7 +134,7 @@ function buildFrictionSignal({
|
|
|
134
134
|
timestamp: new Date().toISOString(),
|
|
135
135
|
epicId: epicId ?? null,
|
|
136
136
|
storyId: storyId ?? null,
|
|
137
|
-
//
|
|
137
|
+
// 2-tier hierarchy (Epic #3163): no Task tier, so friction signals
|
|
138
138
|
// carry no Task id. The field is retained for schema compatibility
|
|
139
139
|
// and always null.
|
|
140
140
|
taskId: null,
|
|
@@ -72,12 +72,12 @@ import { loadSpec, loadState } from './lib/spec/index.js';
|
|
|
72
72
|
* loaded state mapping. The spec-aware renderer (`buildManifestFromSpec`)
|
|
73
73
|
* looks up each Story's status via `state.mapping[slug].lastObservedAgentState`;
|
|
74
74
|
* that field is only refreshed by the structural reconciler, so during
|
|
75
|
-
* `/
|
|
75
|
+
* `/deliver` execution it stays `null` and every Story renders as ⬜
|
|
76
76
|
* pending even after the Story merges. The wave-runner replaced the
|
|
77
77
|
* dispatcher-per-wave refresh loop and the local state.json never sees
|
|
78
78
|
* the progress signal.
|
|
79
79
|
*
|
|
80
|
-
* Under the
|
|
80
|
+
* Under the 2-tier hierarchy (Epic #3163) the runtime manifest's wave
|
|
81
81
|
* records carry `stories[]` (each with the live `storyId` + `status` from
|
|
82
82
|
* `fetchEpicContext`'s GH query), not the retired `tasks[]` shape. The
|
|
83
83
|
* overlay walks `manifest.waves[].stories[]` and copies each Story's
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* any still-stuck entries by enumerating the processes holding handles
|
|
9
9
|
* inside the worktree path and terminating them.
|
|
10
10
|
*
|
|
11
|
-
* Invoked by `/
|
|
11
|
+
* Invoked by `/deliver`, `/epic-plan-spec` / `/epic-plan-decompose`
|
|
12
12
|
* (via `drainPendingCleanupAtBoot` → `worktree-sweep.js`), and
|
|
13
13
|
* `story-close` so the pending-cleanup ledger drains automatically
|
|
14
14
|
* across the sprint lifecycle. Operators can also run it standalone:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* node:coverage ignore file */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* epic-audit-prepare.js — Phase 4 prepare CLI for `/
|
|
5
|
+
* epic-audit-prepare.js — Phase 4 prepare CLI for `/deliver`.
|
|
6
6
|
*
|
|
7
7
|
* Thin glue around the audit-suite `selectAudits` SDK. Reads the Epic
|
|
8
8
|
* ticket, runs the change-set selector against the Epic branch diff
|
|
@@ -193,7 +193,7 @@ function resolveTaskSizing(config) {
|
|
|
193
193
|
* Best-effort and total, mirroring `resolveRiskRoutedLenses`: a
|
|
194
194
|
* missing/unparseable checkpoint, an absent `planningRisk` field, or a
|
|
195
195
|
* provider read failure all degrade to `standard` — the neutral default that
|
|
196
|
-
* preserves today's behavior — so an Epic that skipped `/
|
|
196
|
+
* preserves today's behavior — so an Epic that skipped `/plan` (no
|
|
197
197
|
* checkpoint) still gets a passing `standard` pass with no new failure mode.
|
|
198
198
|
* The changed-file count can only escalate a low-risk Epic to `deep` (a wide
|
|
199
199
|
* diff) and never downgrades a high-risk one; an unknown/absent count is the
|
|
@@ -295,7 +295,7 @@ export async function runEpicAuditPrepare(values, deps = {}) {
|
|
|
295
295
|
const runner = deps.selectAudits ?? selectAudits;
|
|
296
296
|
|
|
297
297
|
// Pin the change set to the requested Epic's own branch rather than the
|
|
298
|
-
// shared checkout's HEAD (Story #3362). Under two concurrent /
|
|
298
|
+
// shared checkout's HEAD (Story #3362). Under two concurrent /deliver
|
|
299
299
|
// runs sharing one working copy, a HEAD-relative diff silently reports the
|
|
300
300
|
// *other* Epic's change set; `refs/heads/epic/<id>` is unambiguous.
|
|
301
301
|
const epicBranch = `epic/${epicId}`;
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* epic-deliver-note-intervention.js — record a manual-intervention event
|
|
6
|
-
* against the active `/
|
|
6
|
+
* against the active `/deliver` run-state checkpoint.
|
|
7
7
|
*
|
|
8
|
-
* The host LLM driving `/
|
|
8
|
+
* The host LLM driving `/deliver` invokes this CLI whenever it does
|
|
9
9
|
* something out-of-band that disqualifies the Epic from auto-merge:
|
|
10
10
|
*
|
|
11
11
|
* - `AskUserQuestion` to the operator mid-run
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* epic-deliver-preflight.js — Story #2899 (Epic #2880, F13).
|
|
6
6
|
*
|
|
7
|
-
* Estimates the cost of an upcoming `/
|
|
7
|
+
* Estimates the cost of an upcoming `/deliver` run *before* Story
|
|
8
8
|
* fan-out and surfaces the result to the operator on two channels:
|
|
9
9
|
*
|
|
10
10
|
* 1. A JSON envelope on stdout (always) with the keys
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*
|
|
20
20
|
* The CLI is intentionally side-effect-light when `--dry-run` is set: no
|
|
21
21
|
* comment write, no lifecycle emit. The slash-command workflow
|
|
22
|
-
* (`/
|
|
22
|
+
* (`/deliver` Phase 1) calls the CLI without `--dry-run` so the
|
|
23
23
|
* comment is upserted; if any threshold is breached, the workflow flips
|
|
24
24
|
* the Epic to `agent::blocked` and surfaces the envelope in chat for
|
|
25
25
|
* operator review. The CLI itself does NOT flip labels — the workflow
|
|
@@ -70,7 +70,7 @@ const HELP = `Usage: node .agents/scripts/epic-deliver-preflight.js \\
|
|
|
70
70
|
[--per-story-claude-tokens <n>]
|
|
71
71
|
|
|
72
72
|
Estimates Story count, install cost, wave count, GitHub API request volume,
|
|
73
|
-
and Claude Max quota burn for an Epic *before* /
|
|
73
|
+
and Claude Max quota burn for an Epic *before* /deliver fan-out.
|
|
74
74
|
|
|
75
75
|
Flags:
|
|
76
76
|
--dry-run Compute the estimate and print the JSON
|
|
@@ -103,7 +103,7 @@ const DEFAULTS = Object.freeze({
|
|
|
103
103
|
perStoryApiRequests: 25,
|
|
104
104
|
perStoryClaudeTokens: 200_000,
|
|
105
105
|
// Base GH API budget: snapshot getTicket + getSubTickets + plan/manifest
|
|
106
|
-
// reads/writes that happen once per /
|
|
106
|
+
// reads/writes that happen once per /deliver run regardless of
|
|
107
107
|
// Story count. Empirical observation from a 5-Story Epic shows ~30
|
|
108
108
|
// requests for the non-per-Story floor.
|
|
109
109
|
baseApiRequests: 30,
|
|
@@ -240,7 +240,7 @@ export function renderPreflightBody({
|
|
|
240
240
|
);
|
|
241
241
|
} else {
|
|
242
242
|
lines.push(
|
|
243
|
-
'⛔ **Threshold breaches** — `/
|
|
243
|
+
'⛔ **Threshold breaches** — `/deliver` will flip the Epic to `agent::blocked` for operator review:',
|
|
244
244
|
);
|
|
245
245
|
for (const b of breaches) {
|
|
246
246
|
lines.push(`- \`${b.key}\` = ${b.observed} (max ${b.max})`);
|
|
@@ -284,7 +284,7 @@ export async function runPreflight({
|
|
|
284
284
|
const provider = injectedProvider ?? createProvider(config);
|
|
285
285
|
const thresholds = getPreflight(config);
|
|
286
286
|
|
|
287
|
-
// Compose the same two phases /
|
|
287
|
+
// Compose the same two phases /deliver Phase 1 runs so the
|
|
288
288
|
// preflight numbers match the actual dispatch plan.
|
|
289
289
|
const ctx = { epicId, provider };
|
|
290
290
|
let state = {};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* node:coverage ignore file */
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* epic-deliver-prepare.js — Step 0/1 of the operator-driven `/
|
|
5
|
+
* epic-deliver-prepare.js — Step 0/1 of the operator-driven `/deliver`.
|
|
6
6
|
*
|
|
7
7
|
* Composes the existing engine phases that the in-process epic-runner used to
|
|
8
8
|
* call sequentially, but does NOT dispatch any waves. The CLI is the single
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* advance the `epic-run-state` checkpoint, and re-render the unified
|
|
7
7
|
* `epic-run-progress` rollup on the Epic.
|
|
8
8
|
*
|
|
9
|
-
* The slash-command (`/
|
|
9
|
+
* The slash-command (`/deliver`) calls this CLI once per wave, after
|
|
10
10
|
* its host-level Agent-tool fan-out drains. It is the only writer of the
|
|
11
11
|
* `epic-run-progress` structured comment for the wave-completion path —
|
|
12
12
|
* there is no separate `/wave-execute` skill, no `wave-run-progress`
|
|
@@ -95,7 +95,7 @@ const HELP = `Usage: node .agents/scripts/epic-execute-record-wave.js \\
|
|
|
95
95
|
|
|
96
96
|
Records the wave's per-Story outcomes, advances the epic-run-state
|
|
97
97
|
checkpoint, and upserts the unified epic-run-progress rollup on the Epic.
|
|
98
|
-
Prints the next action for the /
|
|
98
|
+
Prints the next action for the /deliver slash command.
|
|
99
99
|
`;
|
|
100
100
|
|
|
101
101
|
/**
|
|
@@ -237,7 +237,7 @@ export async function runEpicExecuteRecordWave({
|
|
|
237
237
|
// Closes the start/end pairing the wave-tick reconciler and the
|
|
238
238
|
// `--check-idle` watchdog use to derive in-flight Stories. Before this
|
|
239
239
|
// the only producer was `wave-session.js`, which the host-LLM driven
|
|
240
|
-
// /
|
|
240
|
+
// /deliver path never imports — so every dispatched Story stayed
|
|
241
241
|
// "in-flight" forever and completed Stories tripped the watchdog.
|
|
242
242
|
// Best-effort: a failed append must not block the wave loop.
|
|
243
243
|
emitWaveDispatchEnds({ epicId, verified, config });
|
|
@@ -257,7 +257,7 @@ export async function runEpicExecuteRecordWave({
|
|
|
257
257
|
|
|
258
258
|
// 7. Fire the curated webhook events for this wave boundary. Mirrors the
|
|
259
259
|
// wave-loop emits in `lib/orchestration/epic-runner/phases/iterate-waves.js`
|
|
260
|
-
// for the host-LLM driven /
|
|
260
|
+
// for the host-LLM driven /deliver path (which does not pass
|
|
261
261
|
// through `runEpic`). Each helper is fire-and-forget — webhook
|
|
262
262
|
// misconfig or a transient Slack outage must not block the wave loop.
|
|
263
263
|
await emitWaveBoundaryNotifications({
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* epic-plan-healthcheck.js — Post-Plan Readiness Check
|
|
7
7
|
*
|
|
8
|
-
* Runs at the end of /
|
|
8
|
+
* Runs at the end of /plan (Phase 10) to validate the backlog and
|
|
9
9
|
* optionally prime the execution environment before handing off to
|
|
10
10
|
* /epic-deliver.
|
|
11
11
|
*
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* node epic-plan-healthcheck.js --epic <EPIC_ID> \
|
|
28
28
|
* [--paranoid] [--prime-install] [--dry-run]
|
|
29
29
|
*
|
|
30
|
-
* @see .agents/workflows/epic
|
|
30
|
+
* @see .agents/workflows/helpers/plan-epic.md Phase 10
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import { spawnSync } from 'node:child_process';
|
|
@@ -131,7 +131,7 @@ function checkGitRemote(baseBranch, cwd) {
|
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
133
|
* Detect whether a Story body carries an inline `## Acceptance` section with
|
|
134
|
-
* at least one checklist item. Epic #3078 — under
|
|
134
|
+
* at least one checklist item. Epic #3078 — under 2-tier hierarchy, Stories
|
|
135
135
|
* carry acceptance inline, so the hierarchy check uses this signal as the
|
|
136
136
|
* mark of a complete, executable Story.
|
|
137
137
|
*
|
|
@@ -152,7 +152,7 @@ function hasInlineAcceptance(body) {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
* Validate Epic ticket hierarchy.
|
|
155
|
+
* Validate Epic ticket hierarchy. 2-tier is the only supported hierarchy
|
|
156
156
|
* after Task #3154 deleted `planning.hierarchy`: every Story must carry an
|
|
157
157
|
* inline `## Acceptance` checklist; there is no Task layer to graph.
|
|
158
158
|
*
|
|
@@ -181,13 +181,9 @@ async function checkTickets(provider, epicId) {
|
|
|
181
181
|
return { ok: false, detail: `Epic #${epicId} has no child tickets.` };
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
const features = tickets.filter((t) =>
|
|
185
|
-
t.labels.includes(TYPE_LABELS.FEATURE),
|
|
186
|
-
);
|
|
187
184
|
const stories = tickets.filter((t) => t.labels.includes(TYPE_LABELS.STORY));
|
|
188
185
|
|
|
189
186
|
const errors = [];
|
|
190
|
-
if (features.length === 0) errors.push('no type::feature tickets');
|
|
191
187
|
if (stories.length === 0) errors.push('no type::story tickets');
|
|
192
188
|
|
|
193
189
|
const missingAcceptance = stories.filter(
|
|
@@ -214,7 +210,7 @@ async function checkTickets(provider, epicId) {
|
|
|
214
210
|
|
|
215
211
|
return {
|
|
216
212
|
ok: true,
|
|
217
|
-
detail: `${
|
|
213
|
+
detail: `${stories.length} stories (2-tier, inline acceptance) — hierarchy valid${advisory}.`,
|
|
218
214
|
};
|
|
219
215
|
}
|
|
220
216
|
|
|
@@ -313,7 +309,7 @@ export async function runPlanHealthcheck(opts = {}) {
|
|
|
313
309
|
await timed('git-remote', async () => checkGitRemote(baseBranch, cwd)),
|
|
314
310
|
);
|
|
315
311
|
|
|
316
|
-
// Paranoid lane: ticket-hierarchy revalidation (
|
|
312
|
+
// Paranoid lane: ticket-hierarchy revalidation (2-tier only).
|
|
317
313
|
if (paranoid) {
|
|
318
314
|
const provider = opts.injectedProvider || createProvider(config);
|
|
319
315
|
progress('CHECK', 'Validating ticket hierarchy...');
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* epic-plan-spec-validate.js — Phase 7.5 Tech Spec post-authoring gate CLI.
|
|
5
5
|
*
|
|
6
|
-
* `/
|
|
6
|
+
* `/plan` Phase 7 authors the Tech Spec; Phase 8.3 (Holistic
|
|
7
7
|
* Consolidation) reconciles the draft ticket array against the Tech Spec's
|
|
8
8
|
* `## Delivery Slicing` section, which the decompose-author skill uses as the
|
|
9
9
|
* capability-boundary anchor. When that section is absent the consolidation
|
|
@@ -195,11 +195,11 @@ export async function fetchGhState(provider, epicId) {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
/**
|
|
198
|
-
* Walk the spec
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
198
|
+
* Walk the spec and yield one `{ slug, entity, title, parentSlug,
|
|
199
|
+
* dependsOn }` record per logical entity (epic → story), mirroring the
|
|
200
|
+
* diff engine's `flattenSpec`. Local to the CLI so the reseed pass
|
|
201
|
+
* (below) can map spec slugs onto live GH issues without importing the
|
|
202
|
+
* diff engine's private walker. Pure.
|
|
203
203
|
*
|
|
204
204
|
* @param {object} spec
|
|
205
205
|
* @returns {Array<{slug: string, entity: string, title: string, parentSlug: string|null, dependsOn: string[]}>}
|
|
@@ -216,32 +216,14 @@ export function flattenSpecForReseed(spec) {
|
|
|
216
216
|
dependsOn: [],
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
|
-
for (const
|
|
219
|
+
for (const story of spec.stories ?? []) {
|
|
220
220
|
out.push({
|
|
221
|
-
slug:
|
|
222
|
-
entity: '
|
|
223
|
-
title: String(
|
|
221
|
+
slug: story.slug,
|
|
222
|
+
entity: 'story',
|
|
223
|
+
title: String(story.title ?? ''),
|
|
224
224
|
parentSlug: 'epic',
|
|
225
|
-
dependsOn: [],
|
|
225
|
+
dependsOn: story.dependsOn ?? [],
|
|
226
226
|
});
|
|
227
|
-
for (const story of feature.stories ?? []) {
|
|
228
|
-
out.push({
|
|
229
|
-
slug: story.slug,
|
|
230
|
-
entity: 'story',
|
|
231
|
-
title: String(story.title ?? ''),
|
|
232
|
-
parentSlug: feature.slug,
|
|
233
|
-
dependsOn: story.dependsOn ?? [],
|
|
234
|
-
});
|
|
235
|
-
for (const task of story.tasks ?? []) {
|
|
236
|
-
out.push({
|
|
237
|
-
slug: task.slug,
|
|
238
|
-
entity: 'task',
|
|
239
|
-
title: String(task.title ?? ''),
|
|
240
|
-
parentSlug: story.slug,
|
|
241
|
-
dependsOn: [],
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
227
|
}
|
|
246
228
|
return out;
|
|
247
229
|
}
|
|
@@ -255,7 +237,7 @@ export function flattenSpecForReseed(spec) {
|
|
|
255
237
|
* file is absent (a fresh checkout, a reaped temp dir, the exact
|
|
256
238
|
* situation `--resume` exists to recover from), `loadState` returns an
|
|
257
239
|
* empty mapping, the diff engine sees every spec slug as unmapped, and
|
|
258
|
-
* `apply` recreates the entire
|
|
240
|
+
* `apply` recreates the entire Story set on top of the existing
|
|
259
241
|
* one — duplicating every child. This is precisely the failure `--resume`
|
|
260
242
|
* is meant to prevent.
|
|
261
243
|
*
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* evidence-gate.js — evidence-aware wrapper around a single shell gate.
|
|
5
5
|
*
|
|
6
|
-
* Tech Spec #819 §"Evidence record (Story 7)" — `/
|
|
6
|
+
* Tech Spec #819 §"Evidence record (Story 7)" — `/deliver` Phase 3
|
|
7
7
|
* (close-validation) runs `npm run lint` and `npm test` against the Epic
|
|
8
8
|
* branch before opening the PR.
|
|
9
9
|
* If the same gate has already passed against the current `git rev-parse
|
|
@@ -91,7 +91,7 @@ export function renderWorkflowsDoc(catalog) {
|
|
|
91
91
|
'Every command file lives at `.agents/workflows/<name>.md` and is projected',
|
|
92
92
|
'into a flat `.claude/commands/` tree by `npm run sync:commands` (the',
|
|
93
93
|
'UserPromptSubmit hook keeps it current) so it shows up as a bare `/<name>`',
|
|
94
|
-
'slash command (e.g. `/
|
|
94
|
+
'slash command (e.g. `/deliver`). The projection writes only',
|
|
95
95
|
'`.claude/commands/<name>.md` — there is no plugin manifest and no',
|
|
96
96
|
'marketplace listing. The commands load in every Claude Code environment.',
|
|
97
97
|
'',
|