mandrel 2.37.0 → 2.39.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 +61 -24
- package/.agents/agents/plan-critic.md +1 -1
- package/.agents/docs/SDLC.md +40 -40
- package/.agents/docs/agentrc-reference.json +1 -4
- package/.agents/docs/configuration.md +18 -18
- package/.agents/docs/execution-reference.md +3 -3
- package/.agents/docs/quality-gates.md +2 -2
- package/.agents/docs/workflows.md +6 -6
- package/.agents/instructions.md +5 -5
- package/.agents/rules/changelog-style.md +3 -3
- package/.agents/rules/ci-remediation.md +1 -1
- package/.agents/rules/git-conventions-reference.md +4 -4
- package/.agents/schemas/agentrc.schema.json +15 -16
- package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
- package/.agents/schemas/validation-evidence.schema.json +1 -1
- package/.agents/scripts/acceptance-eval.js +1 -1
- package/.agents/scripts/apply-quality-bootstrap.js +1 -1
- package/.agents/scripts/audit-to-stories.js +2 -2
- package/.agents/scripts/check-doc-links.js +32 -4
- package/.agents/scripts/check-test-temp-hygiene.js +1 -1
- package/.agents/scripts/check-workflow-cli-lint.js +1 -1
- package/.agents/scripts/deliver-light.js +10 -10
- package/.agents/scripts/deliver-recover.js +1 -1
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +1 -1
- package/.agents/scripts/generate-skills-index.js +158 -75
- package/.agents/scripts/generate-workflows-doc.js +1 -1
- package/.agents/scripts/lib/audit-suite/selector.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +5 -5
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +1 -1
- package/.agents/scripts/lib/bdd-runner-detect.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-budget.js +1 -1
- package/.agents/scripts/lib/bdd-scenario-scanner.js +3 -3
- package/.agents/scripts/lib/bdd-step-index.js +1 -1
- package/.agents/scripts/lib/bootstrap/branch-protection.js +1 -1
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +1 -1
- package/.agents/scripts/lib/changed-files.js +100 -9
- package/.agents/scripts/lib/checks/core-bare-clean.js +1 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +1 -1
- package/.agents/scripts/lib/cli-args.js +1 -1
- package/.agents/scripts/lib/command-header.js +1 -1
- package/.agents/scripts/lib/config/delivery-routing.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/temp-paths.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-delivery.js +3 -3
- package/.agents/scripts/lib/config-settings-schema-quality.js +6 -6
- package/.agents/scripts/lib/config-settings-schema.js +28 -10
- package/.agents/scripts/lib/duplicate-search.js +1 -1
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +4 -4
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +1 -1
- package/.agents/scripts/lib/findings/classify-finding.js +1 -1
- package/.agents/scripts/lib/findings/promote-finding.js +12 -12
- package/.agents/scripts/lib/findings/route-finding.js +2 -2
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/label-constants.js +2 -2
- package/.agents/scripts/lib/label-taxonomy.js +1 -1
- package/.agents/scripts/lib/onboard/init-tail.js +4 -4
- package/.agents/scripts/lib/onboard/scaffold-docs.js +2 -2
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
- package/.agents/scripts/lib/orchestration/code-review.js +4 -4
- package/.agents/scripts/lib/orchestration/complexity-gate.js +5 -5
- package/.agents/scripts/lib/orchestration/deliver-recover.js +3 -3
- package/.agents/scripts/lib/orchestration/docs-digest.js +3 -3
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +2 -2
- package/.agents/scripts/lib/orchestration/light-backstop.js +1 -1
- package/.agents/scripts/lib/orchestration/light-escalation.js +6 -6
- package/.agents/scripts/lib/orchestration/light-suitability.js +19 -19
- package/.agents/scripts/lib/orchestration/plan-context.js +4 -4
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +2 -2
- package/.agents/scripts/lib/orchestration/plan-metrics.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +1 -1
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +3 -3
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +6 -6
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +16 -16
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +3 -3
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +6 -6
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +7 -7
- package/.agents/scripts/lib/orchestration/planning/decomposer-context.js +1 -1
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +3 -3
- package/.agents/scripts/lib/orchestration/remote-verifier.js +2 -2
- package/.agents/scripts/lib/orchestration/resolve-stories.js +4 -4
- package/.agents/scripts/lib/orchestration/run-epilogue.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +5 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +3 -3
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +2 -2
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +1 -1
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +14 -12
- package/.agents/scripts/lib/orchestration/ticket-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +3 -3
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +58 -6
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/skills/skills-index.js +168 -0
- package/.agents/scripts/lib/skills/walk-skill-files.js +133 -9
- package/.agents/scripts/lib/story-adjacency.js +2 -2
- package/.agents/scripts/lib/templates/decomposer-prompts.js +1 -1
- package/.agents/scripts/lib/ticket-body-sections.js +1 -1
- package/.agents/scripts/lib/util/concurrent-map.js +1 -1
- package/.agents/scripts/lib/util/parse-id-list.js +1 -1
- package/.agents/scripts/lib/wave-runner/live-probe.js +4 -4
- package/.agents/scripts/lib/wave-runner/ready-set.js +1 -1
- package/.agents/scripts/lib/workflow-closure.js +1 -1
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +2 -2
- package/.agents/scripts/lint-issue-body.js +3 -3
- package/.agents/scripts/plan-context.js +4 -4
- package/.agents/scripts/plan-critics.js +2 -2
- package/.agents/scripts/plan-persist.js +2 -2
- package/.agents/scripts/plan-run-epilogue.js +2 -2
- package/.agents/scripts/providers/github/board-add.js +1 -1
- package/.agents/scripts/providers/github/errors.js +1 -1
- package/.agents/scripts/providers/github/tickets.js +6 -6
- package/.agents/scripts/quality-preview.js +50 -9
- package/.agents/scripts/resolve-stories.js +3 -3
- package/.agents/scripts/resync-status-column.js +1 -1
- package/.agents/scripts/run-lint.js +1 -1
- package/.agents/scripts/single-story-close.js +2 -2
- package/.agents/scripts/single-story-init.js +5 -5
- package/.agents/scripts/stories-wave-tick.js +8 -8
- package/.agents/scripts/validate-skills.js +53 -66
- package/.agents/skills/core/idea-refinement/SKILL.md +5 -5
- package/.agents/skills/core/scope-triage/SKILL.md +3 -3
- package/.agents/skills/skills.index.json +1 -1
- package/.agents/skills/stack/qa/qa-harness/SKILL.md +1 -1
- package/.agents/workflows/audit-data-model.md +1 -1
- package/.agents/workflows/audit-documentation.md +2 -2
- package/.agents/workflows/audit-to-stories.md +11 -11
- package/.agents/workflows/git-deliver.md +4 -4
- package/.agents/workflows/helpers/_merge-conflict-template.md +1 -1
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-review.md +4 -4
- package/.agents/workflows/helpers/deliver-light.md +26 -26
- package/.agents/workflows/helpers/deliver-reference.md +15 -7
- package/.agents/workflows/helpers/deliver-story-reference.md +9 -4
- package/.agents/workflows/helpers/deliver-story.md +6 -7
- package/.agents/workflows/helpers/diagnose.md +2 -2
- package/.agents/workflows/helpers/parallel-tooling.md +1 -1
- package/.agents/workflows/helpers/plan-reference.md +9 -9
- package/.agents/workflows/helpers/qa-core.md +8 -8
- package/.agents/workflows/helpers/worktree-lifecycle.md +6 -6
- package/.agents/workflows/{deliver.md → mandrel-deliver.md} +15 -19
- package/.agents/workflows/{plan.md → mandrel-plan.md} +9 -9
- package/.agents/workflows/memory-consolidate.md +4 -4
- package/.agents/workflows/prototype.md +3 -3
- package/.agents/workflows/qa-assist.md +12 -12
- package/.agents/workflows/qa-explore.md +6 -6
- package/.agents/workflows/qa-run.md +14 -6
- package/README.md +7 -7
- package/docs/CHANGELOG.md +23 -0
- package/lib/cli/doctor.js +1 -1
- package/lib/cli/init.js +1 -1
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,15 @@
|
|
|
8
8
|
// generator output (ignoring the volatile `generatedAt` field) and exits
|
|
9
9
|
// non-zero with a diff-style message if they diverge.
|
|
10
10
|
//
|
|
11
|
+
// Two indexes, never one (Story #5135). The shipped manifest above is a
|
|
12
|
+
// committed payload file that `mandrel doctor` / `mandrel sync-agents`
|
|
13
|
+
// compare byte-for-byte against the installed package, so consumer-authored
|
|
14
|
+
// skills under the `.agents/local/skills/` zone MUST NOT be folded into it —
|
|
15
|
+
// a merged index would read as payload drift in every consumer that authored
|
|
16
|
+
// a skill, and those commands would refuse. Local skills are therefore
|
|
17
|
+
// indexed into their own `.agents/local/skills/skills.index.json`, inside
|
|
18
|
+
// the zone sync never prunes and drift never walks.
|
|
19
|
+
//
|
|
11
20
|
// CLI surface:
|
|
12
21
|
//
|
|
13
22
|
// node generate-skills-index.js [--check] [--root <dir>] [--out <file>]
|
|
@@ -38,7 +47,18 @@ import { runAsCli } from './lib/cli-utils.js';
|
|
|
38
47
|
import { formatGeneratedJson } from './lib/format-generated-json.js';
|
|
39
48
|
import { Logger } from './lib/Logger.js';
|
|
40
49
|
import { parseSkill } from './lib/skills/parse-skill.js';
|
|
41
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
diffManifests,
|
|
52
|
+
INDEX_FILENAME,
|
|
53
|
+
indexPathFor,
|
|
54
|
+
readManifest,
|
|
55
|
+
} from './lib/skills/skills-index.js';
|
|
56
|
+
import {
|
|
57
|
+
collectLocalSkillFiles,
|
|
58
|
+
collectSkillFiles,
|
|
59
|
+
LOCAL_SKILLS_SEGMENTS,
|
|
60
|
+
PAYLOAD_SKILLS_SEGMENTS,
|
|
61
|
+
} from './lib/skills/walk-skill-files.js';
|
|
42
62
|
|
|
43
63
|
const GENERATOR_ID = 'generate-skills-index.js@1';
|
|
44
64
|
|
|
@@ -103,8 +123,8 @@ function projectEntry(parsed) {
|
|
|
103
123
|
* Build the manifest object (without `generatedAt`) by walking the tree
|
|
104
124
|
* and projecting each parsed SKILL.md into an index entry.
|
|
105
125
|
*/
|
|
106
|
-
export function buildManifestBody(repoRoot) {
|
|
107
|
-
const skillFiles =
|
|
126
|
+
export function buildManifestBody(repoRoot, collect = collectSkillFiles) {
|
|
127
|
+
const skillFiles = collect(repoRoot);
|
|
108
128
|
const skills = skillFiles.map((absPath) =>
|
|
109
129
|
projectEntry(parseSkill(absPath, { repoRoot })),
|
|
110
130
|
);
|
|
@@ -118,8 +138,8 @@ export function buildManifestBody(repoRoot) {
|
|
|
118
138
|
* Build the full manifest with `generatedAt`. `nowIso` is injected so
|
|
119
139
|
* tests can pin the timestamp deterministically.
|
|
120
140
|
*/
|
|
121
|
-
export function buildManifest(repoRoot, { nowIso } = {}) {
|
|
122
|
-
const body = buildManifestBody(repoRoot);
|
|
141
|
+
export function buildManifest(repoRoot, { nowIso, collect } = {}) {
|
|
142
|
+
const body = buildManifestBody(repoRoot, collect);
|
|
123
143
|
return {
|
|
124
144
|
generatedAt: nowIso ?? new Date().toISOString(),
|
|
125
145
|
generator: body.generator,
|
|
@@ -143,66 +163,147 @@ export function serializeManifest(manifest) {
|
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
|
|
166
|
+
* Resolve the manifest output path given (root, optional explicit
|
|
167
|
+
* override).
|
|
168
|
+
*/
|
|
169
|
+
function resolveOutPath(root, override) {
|
|
170
|
+
return override
|
|
171
|
+
? path.resolve(override)
|
|
172
|
+
: indexPathFor(root, PAYLOAD_SKILLS_SEGMENTS);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Resolve the local-zone manifest path. Deliberately NOT overridable by
|
|
177
|
+
* `--out`: that flag redirects the payload manifest (tests stage fixture
|
|
178
|
+
* trees with it), and letting it also move the local manifest would let one
|
|
179
|
+
* invocation write both indexes to the same file.
|
|
180
|
+
*/
|
|
181
|
+
function resolveLocalOutPath(root) {
|
|
182
|
+
return indexPathFor(root, LOCAL_SKILLS_SEGMENTS);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Write one manifest through the project formatter so a regeneration on a
|
|
187
|
+
* clean tree leaves no format drift behind.
|
|
149
188
|
*/
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
|
|
189
|
+
function writeManifest(manifest, outPath, root) {
|
|
190
|
+
const serialized = serializeManifest(manifest);
|
|
191
|
+
const opts = { cwd: root, filename: INDEX_FILENAME };
|
|
192
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
193
|
+
fs.writeFileSync(
|
|
194
|
+
outPath,
|
|
195
|
+
formatGeneratedJson(serialized, opts) ?? serialized,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Write (or reap) the local-zone manifest. A consumer who deletes their last
|
|
201
|
+
* local skill would otherwise be left with a stale index reporting skills
|
|
202
|
+
* that no longer exist, so an emptied zone removes the artifact rather than
|
|
203
|
+
* leaving it behind.
|
|
204
|
+
*/
|
|
205
|
+
function writeLocalManifest(localFresh, localOutPath, root) {
|
|
206
|
+
const rel = path.relative(root, localOutPath).split(path.sep).join('/');
|
|
207
|
+
if (localFresh === null) {
|
|
208
|
+
if (fs.existsSync(localOutPath)) {
|
|
209
|
+
fs.rmSync(localOutPath);
|
|
210
|
+
Logger.info(`removed ${rel} (no local skills remain)`);
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
153
213
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
214
|
+
writeManifest(localFresh, localOutPath, root);
|
|
215
|
+
Logger.info(`wrote ${rel} (${localFresh.skills.length} entries)`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Compare the local-zone manifest against fresh generator output. Returns
|
|
220
|
+
* null when in sync (including the common case of no local skills and no
|
|
221
|
+
* artifact), or a diff-style message.
|
|
222
|
+
*/
|
|
223
|
+
function checkLocalManifest(localFresh, localOutPath) {
|
|
224
|
+
const exists = fs.existsSync(localOutPath);
|
|
225
|
+
if (localFresh === null) {
|
|
226
|
+
return exists
|
|
227
|
+
? 'local skills.index.json drift detected: the local skills zone is ' +
|
|
228
|
+
'empty but .agents/local/skills/skills.index.json still exists — ' +
|
|
229
|
+
"run 'node .agents/scripts/generate-skills-index.js' to reap it"
|
|
230
|
+
: null;
|
|
159
231
|
}
|
|
160
|
-
|
|
161
|
-
return
|
|
162
|
-
|
|
163
|
-
|
|
232
|
+
if (!exists) {
|
|
233
|
+
return (
|
|
234
|
+
'local skills.index.json drift detected: missing — run ' +
|
|
235
|
+
"'node .agents/scripts/generate-skills-index.js' to write it"
|
|
236
|
+
);
|
|
164
237
|
}
|
|
238
|
+
const { manifest: disk } = readManifest(localOutPath);
|
|
239
|
+
return diffManifests(disk, localFresh, 'local skills.index.json');
|
|
165
240
|
}
|
|
166
241
|
|
|
167
242
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
243
|
+
* Build the local zone's manifest plan for this invocation: its output path,
|
|
244
|
+
* and a fresh manifest when the consumer has authored any local skill (null
|
|
245
|
+
* otherwise, which is the signal to reap a stale artifact).
|
|
246
|
+
*
|
|
247
|
+
* Split out of `run` so the payload path and the local path each read as one
|
|
248
|
+
* step there rather than interleaving.
|
|
249
|
+
*
|
|
250
|
+
* @param {string} root
|
|
251
|
+
* @param {Date} now
|
|
252
|
+
* @returns {{ localFresh: object | null, localOutPath: string }}
|
|
170
253
|
*/
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (sa === sb) return null;
|
|
182
|
-
// Surface a structural summary rather than a full JSON dump.
|
|
183
|
-
const diskCount = Array.isArray(diskManifest.skills)
|
|
184
|
-
? diskManifest.skills.length
|
|
185
|
-
: 'n/a';
|
|
186
|
-
const freshCount = Array.isArray(freshManifest.skills)
|
|
187
|
-
? freshManifest.skills.length
|
|
188
|
-
: 'n/a';
|
|
189
|
-
const summary = [
|
|
190
|
-
'skills.index.json drift detected:',
|
|
191
|
-
` on-disk entries: ${diskCount}`,
|
|
192
|
-
` generated entries: ${freshCount}`,
|
|
193
|
-
" run 'node .agents/scripts/generate-skills-index.js' to refresh",
|
|
194
|
-
].join('\n');
|
|
195
|
-
return summary;
|
|
254
|
+
function buildLocalPlan(root, now) {
|
|
255
|
+
const localOutPath = resolveLocalOutPath(root);
|
|
256
|
+
const localFresh =
|
|
257
|
+
collectLocalSkillFiles(root).length > 0
|
|
258
|
+
? buildManifest(root, {
|
|
259
|
+
nowIso: now.toISOString(),
|
|
260
|
+
collect: collectLocalSkillFiles,
|
|
261
|
+
})
|
|
262
|
+
: null;
|
|
263
|
+
return { localFresh, localOutPath };
|
|
196
264
|
}
|
|
197
265
|
|
|
198
266
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
267
|
+
* Render the freshness line's entry counts, naming the local zone only when
|
|
268
|
+
* one exists.
|
|
269
|
+
*
|
|
270
|
+
* @param {object} fresh
|
|
271
|
+
* @param {object | null} localFresh
|
|
272
|
+
* @returns {string}
|
|
201
273
|
*/
|
|
202
|
-
function
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
274
|
+
function describeCounts(fresh, localFresh) {
|
|
275
|
+
const base = `${fresh.skills.length} entries`;
|
|
276
|
+
return localFresh === null
|
|
277
|
+
? base
|
|
278
|
+
: `${base}, ${localFresh.skills.length} local`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* `--check` mode: compare both manifests against fresh generator output and
|
|
283
|
+
* report the first drift found, payload first.
|
|
284
|
+
*
|
|
285
|
+
* Lives outside `run` so the entry point reads as "resolve inputs, then check
|
|
286
|
+
* or write" — and so the check path's branches are not charged to a function
|
|
287
|
+
* that also owns argument resolution.
|
|
288
|
+
*
|
|
289
|
+
* @param {{ outPath: string, fresh: object, localOutPath: string, localFresh: object | null }} plan
|
|
290
|
+
* @returns {{ status: number, output: string }}
|
|
291
|
+
*/
|
|
292
|
+
function checkBothManifests({ outPath, fresh, localOutPath, localFresh }) {
|
|
293
|
+
const { manifest: disk, reason } = readManifest(outPath);
|
|
294
|
+
if (disk === null) {
|
|
295
|
+
return { status: 1, output: `${INDEX_FILENAME} drift detected: ${reason}` };
|
|
296
|
+
}
|
|
297
|
+
const drift =
|
|
298
|
+
diffManifests(disk, fresh, INDEX_FILENAME) ??
|
|
299
|
+
checkLocalManifest(localFresh, localOutPath);
|
|
300
|
+
if (drift !== null) {
|
|
301
|
+
return { status: 1, output: drift };
|
|
302
|
+
}
|
|
303
|
+
Logger.info(
|
|
304
|
+
`${INDEX_FILENAME} is fresh (${describeCounts(fresh, localFresh)})`,
|
|
305
|
+
);
|
|
306
|
+
return { status: 0, output: '' };
|
|
206
307
|
}
|
|
207
308
|
|
|
208
309
|
/**
|
|
@@ -225,35 +326,17 @@ export function run({ argv = [], now = new Date(), repoRoot } = {}) {
|
|
|
225
326
|
: (repoRoot ?? defaultRepoRoot());
|
|
226
327
|
const outPath = resolveOutPath(root, parsed.out);
|
|
227
328
|
const fresh = buildManifest(root, { nowIso: now.toISOString() });
|
|
329
|
+
const { localFresh, localOutPath } = buildLocalPlan(root, now);
|
|
228
330
|
|
|
229
331
|
if (parsed.check) {
|
|
230
|
-
|
|
231
|
-
if (disk === null) {
|
|
232
|
-
return {
|
|
233
|
-
status: 1,
|
|
234
|
-
output: `skills.index.json drift detected: ${reason}`,
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
const diff = diffManifestsIgnoringTimestamp(disk, fresh);
|
|
238
|
-
if (diff === null) {
|
|
239
|
-
Logger.info(
|
|
240
|
-
`skills.index.json is fresh (${fresh.skills.length} entries)`,
|
|
241
|
-
);
|
|
242
|
-
return { status: 0, output: '' };
|
|
243
|
-
}
|
|
244
|
-
return { status: 1, output: diff };
|
|
332
|
+
return checkBothManifests({ outPath, fresh, localOutPath, localFresh });
|
|
245
333
|
}
|
|
246
334
|
|
|
247
|
-
|
|
248
|
-
const opts = { cwd: root, filename: 'skills.index.json' };
|
|
249
|
-
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
250
|
-
fs.writeFileSync(
|
|
251
|
-
outPath,
|
|
252
|
-
formatGeneratedJson(serialized, opts) ?? serialized,
|
|
253
|
-
);
|
|
335
|
+
writeManifest(fresh, outPath, root);
|
|
254
336
|
Logger.info(
|
|
255
337
|
`wrote ${path.relative(root, outPath).split(path.sep).join('/')} (${fresh.skills.length} entries)`,
|
|
256
338
|
);
|
|
339
|
+
writeLocalManifest(localFresh, localOutPath, root);
|
|
257
340
|
return { status: 0, output: '' };
|
|
258
341
|
}
|
|
259
342
|
|
|
@@ -93,7 +93,7 @@ export function renderWorkflowsDoc(catalog, loopCatalog = []) {
|
|
|
93
93
|
'Every command file lives at `.agents/workflows/<name>.md` and is projected',
|
|
94
94
|
'into a flat `.claude/commands/` tree by `npm run sync:commands` (kept',
|
|
95
95
|
'current at install time and on every `mandrel sync`/`update`) so it shows',
|
|
96
|
-
'up as a bare `/<name>` slash command (e.g. `/deliver`). The projection',
|
|
96
|
+
'up as a bare `/<name>` slash command (e.g. `/mandrel-deliver`). The projection',
|
|
97
97
|
'writes only `.claude/commands/<name>.md` — there is no plugin manifest and no',
|
|
98
98
|
'marketplace listing. The commands load in every Claude Code environment.',
|
|
99
99
|
'',
|
|
@@ -701,7 +701,7 @@ export function changeSetLacksSiblingTest(changedFiles) {
|
|
|
701
701
|
* callers MUST pass the requested Epic's own branch ref (e.g.
|
|
702
702
|
* `refs/heads/epic/<id>`) so the change set is pinned to that Epic's branch
|
|
703
703
|
* rather than whatever HEAD the shared checkout happens to sit on. Under two
|
|
704
|
-
* concurrent `/deliver` runs sharing one checkout, diffing against
|
|
704
|
+
* concurrent `/mandrel-deliver` runs sharing one checkout, diffing against
|
|
705
705
|
* `HEAD` silently resolves the *other* Epic's change set (Story #3362). When
|
|
706
706
|
* `headRef` cannot be resolved in the repo, the selector returns a
|
|
707
707
|
* `degraded: true` envelope (or hard-fails in gate-mode) instead of diffing
|
|
@@ -140,7 +140,7 @@ const AUDIT_STORY_AXIS_LABELS = Object.freeze([
|
|
|
140
140
|
name: AGENT_LABELS.READY,
|
|
141
141
|
color: hex(LABEL_COLORS.AGENT),
|
|
142
142
|
description:
|
|
143
|
-
'Parking state — frozen dispatch manifest exists; awaiting local /deliver',
|
|
143
|
+
'Parking state — frozen dispatch manifest exists; awaiting local /mandrel-deliver',
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
name: RISK_LABELS.HIGH,
|
|
@@ -292,7 +292,7 @@ export function buildStoryBody({ group, edges = [], issueByGroupKey = null }) {
|
|
|
292
292
|
};
|
|
293
293
|
|
|
294
294
|
// The `---` / `blocked by #N` footer is the canonical serializer's own, so
|
|
295
|
-
// the body round-trips through `parse()` and `/deliver`'s resolver reads the
|
|
295
|
+
// the body round-trips through `parse()` and `/mandrel-deliver`'s resolver reads the
|
|
296
296
|
// ordering from the same place it reads every other Story's.
|
|
297
297
|
const canonicalSections = serialize(storyBody, {
|
|
298
298
|
includeFooter: storyBody.depends_on.length > 0,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/audit-to-stories/seed-from-findings.js
|
|
3
3
|
*
|
|
4
|
-
* Build the `/plan --seed`-shaped one-pager markdown that the audit-to-
|
|
5
|
-
* stories Single-plan grouping path emits for `/plan` to consume.
|
|
4
|
+
* Build the `/mandrel-plan --seed`-shaped one-pager markdown that the audit-to-
|
|
5
|
+
* stories Single-plan grouping path emits for `/mandrel-plan` to consume.
|
|
6
6
|
*
|
|
7
7
|
* The seed renders the canonical one-pager sections so the authoring
|
|
8
8
|
* pass can sharpen it without having to invent context:
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - Recommended Direction (rollup of recommendations by dimension)
|
|
11
11
|
* - Key Assumptions (carries the source-report links forward)
|
|
12
12
|
* - MVP Scope (the proposed Stories, one bullet per group)
|
|
13
|
-
* - Key Files (explicit file paths so `/plan` authoring has concrete
|
|
13
|
+
* - Key Files (explicit file paths so `/mandrel-plan` authoring has concrete
|
|
14
14
|
* anchors)
|
|
15
15
|
* - Not Doing (out-of-scope items by convention)
|
|
16
16
|
*
|
|
@@ -97,8 +97,8 @@ function formatMVPScope(groups) {
|
|
|
97
97
|
const dims = g.dimensions.join(' / ');
|
|
98
98
|
const file = g.files[0] ? ` (\`${g.files[0]}\`)` : '';
|
|
99
99
|
// Carry each group's fingerprint (and location-based semantic-key)
|
|
100
|
-
// footer into the seed so a Story authored from it via `/plan` inherits
|
|
101
|
-
// the dedup identity — without this the recommended `/plan --seed-file`
|
|
100
|
+
// footer into the seed so a Story authored from it via `/mandrel-plan` inherits
|
|
101
|
+
// the dedup identity — without this the recommended `/mandrel-plan --seed-file`
|
|
102
102
|
// path is invisible to the next sweep's dedup (Story #4626). The footers
|
|
103
103
|
// are HTML comments, so they never render in the visible one-pager but
|
|
104
104
|
// stay machine-readable for the dedup probe.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* edges**. Both halves are written:
|
|
18
18
|
*
|
|
19
19
|
* 1. The **body footer** (`---` / `blocked by #N`) — canonical, parsed by
|
|
20
|
-
* `/deliver`'s resolver, and the fallback when the dependencies API is
|
|
20
|
+
* `/mandrel-deliver`'s resolver, and the fallback when the dependencies API is
|
|
21
21
|
* unavailable.
|
|
22
22
|
* 2. The **native `blocked_by` relation** — visible in the GitHub UI,
|
|
23
23
|
* readable without parsing markdown, and settable by an operator later.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* The verification is **static**: we inspect `package.json` for a known BDD
|
|
14
14
|
* runner dependency, and consult a small lookup table of which runners
|
|
15
15
|
* support which pending/skip tag. We do not boot the runner. This keeps
|
|
16
|
-
* `/plan` Phase 7 hermetic and offline.
|
|
16
|
+
* `/mandrel-plan` Phase 7 hermetic and offline.
|
|
17
17
|
*
|
|
18
18
|
* **Workspace awareness (Story #2956).** In a pnpm / npm / yarn monorepo the
|
|
19
19
|
* BDD runner is rarely a root devDependency — it lives in the workspace
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* bdd-scenario-budget.js — envelope byte budget for the `bddScenarios`
|
|
3
|
-
* `/plan` context-envelope field (Story #4977).
|
|
3
|
+
* `/mandrel-plan` context-envelope field (Story #4977).
|
|
4
4
|
*
|
|
5
5
|
* `bdd-scenario-scanner.js`'s `scanBddScenarios` stays a faithful, uncapped
|
|
6
6
|
* index of the project's `.feature` corpus — that scan is also used
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* bdd-scenario-scanner.js — Gherkin scenario index for /plan Phase 7.
|
|
2
|
+
* bdd-scenario-scanner.js — Gherkin scenario index for /mandrel-plan Phase 7.
|
|
3
3
|
*
|
|
4
4
|
* Story #2637 (sibling to #2636's file-assumption gate; the #2634 and #2635
|
|
5
5
|
* planner-grounding siblings were retired in Story #4811). The Acceptance
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* alone — it never inspects the consumer project's existing `.feature`
|
|
9
9
|
* files. Planned ACs frequently duplicate scenarios that already exist or
|
|
10
10
|
* re-specify behaviour the codebase already proves; the duplication is
|
|
11
|
-
* only discovered (at best) during `/deliver` or (at worst) after
|
|
11
|
+
* only discovered (at best) during `/mandrel-deliver` or (at worst) after
|
|
12
12
|
* a redundant PR ships.
|
|
13
13
|
*
|
|
14
14
|
* `scanBddScenarios` walks every configured feature root, parses each
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* have a matching scenario.
|
|
22
22
|
*
|
|
23
23
|
* Determinism is load-bearing: the matcher is keyword-based, not
|
|
24
|
-
* embedding-based, so re-running `/plan` against the same
|
|
24
|
+
* embedding-based, so re-running `/mandrel-plan` against the same
|
|
25
25
|
* acceptance spec produces the same disposition annotations.
|
|
26
26
|
*/
|
|
27
27
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 1. **Discovery** — which files under a scope's `stepRoots` hold step
|
|
10
10
|
* definitions, and which `.feature` files sit under its `featureRoots`.
|
|
11
11
|
* Feature discovery is delegated to `listFeatureFiles` in
|
|
12
|
-
* `bdd-scenario-scanner.js` rather than copied: /plan's scenario index and
|
|
12
|
+
* `bdd-scenario-scanner.js` rather than copied: /mandrel-plan's scenario index and
|
|
13
13
|
* this gate must agree on what counts as a feature file, and two walkers
|
|
14
14
|
* would eventually disagree.
|
|
15
15
|
* 2. **Matching** — turn each definition's Cucumber expression or regular
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - `enforce_admins: true` — admins do not bypass the prGate suite.
|
|
8
8
|
* - `required_pull_request_reviews.required_approving_review_count: 0` —
|
|
9
9
|
* CI is the gate; the operator monitors and iterates the open PR
|
|
10
|
-
* to green via `/deliver`'s Phase 7 watch loop.
|
|
10
|
+
* to green via `/mandrel-deliver`'s Phase 7 watch loop.
|
|
11
11
|
*
|
|
12
12
|
* Behaviour rules
|
|
13
13
|
* ---------------
|
|
@@ -112,8 +112,8 @@ export function buildManualInstructions({ stagePaths, baseBranch }) {
|
|
|
112
112
|
` git push -u origin ${baseBranch}`,
|
|
113
113
|
'',
|
|
114
114
|
'Story delivery runs in git worktrees that check out tracked files only,',
|
|
115
|
-
'so the .agents/ wiring MUST be committed before any /deliver or',
|
|
116
|
-
'/deliver run — otherwise the worktree has no scripts and breaks.',
|
|
115
|
+
'so the .agents/ wiring MUST be committed before any /mandrel-deliver or',
|
|
116
|
+
'/mandrel-deliver run — otherwise the worktree has no scripts and breaks.',
|
|
117
117
|
].join('\n');
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -325,7 +325,7 @@ function renderConformanceWorkflow() {
|
|
|
325
325
|
# Generated by agents-bootstrap-github. Runs the canonical story-body parser
|
|
326
326
|
# against human-opened type::story issues and comments when the
|
|
327
327
|
# body does not round-trip, instead of letting the supported human entry
|
|
328
|
-
# points (e.g. /plan from an existing Epic ID) fail silently later. The lint
|
|
328
|
+
# points (e.g. /mandrel-plan from an existing Epic ID) fail silently later. The lint
|
|
329
329
|
# informs; it never fails the issue. Re-run /agents-bootstrap-github to refresh.
|
|
330
330
|
name: Issue Body Conformance
|
|
331
331
|
|
|
@@ -122,13 +122,98 @@ export function getChangedFiles({
|
|
|
122
122
|
return parseNameOnlyStdout(res.stdout);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* A full-length hex object id, as `git rev-parse` prints it. Used to reject
|
|
127
|
+
* anything that is not a resolved commit — a stubbed git interface in a test
|
|
128
|
+
* answers every `gitSpawn` with the same canned stdout, and a file list must
|
|
129
|
+
* never be mistaken for a merge head.
|
|
130
|
+
*/
|
|
131
|
+
const OBJECT_ID_RE = /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Resolve the commit an in-progress merge is merging **in**, or `null` when no
|
|
135
|
+
* merge is in progress.
|
|
136
|
+
*
|
|
137
|
+
* Story #5131. `git diff --cached` with no commit argument diffs the index
|
|
138
|
+
* against `HEAD`, and during a merge `HEAD` is still the pre-merge tip — so a
|
|
139
|
+
* base-sync merge commit (`git merge --no-edit origin/<base>`, which
|
|
140
|
+
* `single-story-close`'s base-sync phase tells the operator to run by hand)
|
|
141
|
+
* put every file the base branch had landed into the staged scope. The
|
|
142
|
+
* pre-commit MI/CRAP gate then blocked the resolution commit for deltas
|
|
143
|
+
* belonging to already-landed, already-gated work, with no remedy: the preview
|
|
144
|
+
* is a delta against the baseline, not a baseline comparison, so no baseline
|
|
145
|
+
* refresh could silence it.
|
|
146
|
+
*
|
|
147
|
+
* Two details are load-bearing:
|
|
148
|
+
*
|
|
149
|
+
* - **Ask git, never the filesystem.** `.git` is a *file*, not a directory,
|
|
150
|
+
* in the linked worktrees this repo delivers from, so an
|
|
151
|
+
* `existsSync('.git/MERGE_HEAD')` probe would be silently inert exactly
|
|
152
|
+
* where deliveries happen. `rev-parse --verify` resolves the ref through
|
|
153
|
+
* git's own worktree-aware lookup.
|
|
154
|
+
* - **`--verify` fails closed on an octopus merge.** It refuses a
|
|
155
|
+
* `MERGE_HEAD` naming more than one head, which lands here as `null` — the
|
|
156
|
+
* pre-#5131 behaviour. Narrowing the scope wrongly would hide a real
|
|
157
|
+
* regression; widening it only restores the status quo.
|
|
158
|
+
*
|
|
159
|
+
* Never throws: a merge is either detectable or it is not, and an
|
|
160
|
+
* undetectable one must degrade to the plain cached diff rather than fail the
|
|
161
|
+
* gate.
|
|
162
|
+
*
|
|
163
|
+
* @param {object} [params]
|
|
164
|
+
* @param {string} [params.cwd=process.cwd()]
|
|
165
|
+
* @param {ReturnType<typeof createGitInterface>} [params.git]
|
|
166
|
+
* @returns {string | null} The merge head's object id, or `null`.
|
|
167
|
+
*/
|
|
168
|
+
export function resolveMergeHead({ cwd = process.cwd(), git } = {}) {
|
|
169
|
+
const gitIface = git ?? createGitInterface({});
|
|
170
|
+
let res;
|
|
171
|
+
try {
|
|
172
|
+
res = gitIface.gitSpawn(cwd, 'rev-parse', '-q', '--verify', 'MERGE_HEAD');
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
if (res?.status !== 0) return null;
|
|
177
|
+
const sha = (res.stdout ?? '').trim();
|
|
178
|
+
return OBJECT_ID_RE.test(sha) ? sha : null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Read the index file list against an explicit base, shared by
|
|
183
|
+
* `getStagedFiles` and `resolvePreviewScope` so the merge head is resolved
|
|
184
|
+
* once per scope resolution rather than once per caller.
|
|
185
|
+
*
|
|
186
|
+
* @param {object} params
|
|
187
|
+
* @param {string} params.cwd
|
|
188
|
+
* @param {ReturnType<typeof createGitInterface>} params.git
|
|
189
|
+
* @param {string | null} params.mergeHead
|
|
190
|
+
* @returns {string[]}
|
|
191
|
+
*/
|
|
192
|
+
function stagedFilesAgainst({ cwd, git, mergeHead }) {
|
|
193
|
+
const args = ['diff', '--name-only', '--cached'];
|
|
194
|
+
if (mergeHead) args.push(mergeHead);
|
|
195
|
+
const res = git.gitSpawn(cwd, ...args);
|
|
196
|
+
if (res.status !== 0) {
|
|
197
|
+
const detail = res.stderr || res.stdout || `exit ${res.status}`;
|
|
198
|
+
throw new Error(`[staged] unable to read cached diff: ${detail}`);
|
|
199
|
+
}
|
|
200
|
+
return parseNameOnlyStdout(res.stdout);
|
|
201
|
+
}
|
|
202
|
+
|
|
125
203
|
/**
|
|
126
204
|
* Resolve paths in the index (staged for commit). Used by `quality-preview
|
|
127
205
|
* --staged` so pre-commit gates score only the commit payload, not unstaged
|
|
128
206
|
* working-tree edits.
|
|
129
207
|
*
|
|
130
208
|
* Semantics:
|
|
131
|
-
* - Runs `git diff --name-only --cached
|
|
209
|
+
* - Runs `git diff --name-only --cached`, which diffs the index against
|
|
210
|
+
* `HEAD`.
|
|
211
|
+
* - **During a merge**, diffs the index against `MERGE_HEAD` instead
|
|
212
|
+
* (Story #5131), so the scope is the merging branch's own contribution
|
|
213
|
+
* plus its conflict resolutions — not the base branch's incoming work.
|
|
214
|
+
* `git merge-base HEAD MERGE_HEAD` would *not* do: diffing the index
|
|
215
|
+
* against the fork point re-admits everything the base branch landed since
|
|
216
|
+
* it, which is the whole defect.
|
|
132
217
|
* - Returns forward-slash-normalized repo-relative paths.
|
|
133
218
|
* - Non-zero git exit throws — staged mode must not silently widen scope.
|
|
134
219
|
*
|
|
@@ -139,12 +224,11 @@ export function getChangedFiles({
|
|
|
139
224
|
*/
|
|
140
225
|
export function getStagedFiles({ cwd = process.cwd(), git } = {}) {
|
|
141
226
|
const gitIface = git ?? createGitInterface({});
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
return parseNameOnlyStdout(res.stdout);
|
|
227
|
+
return stagedFilesAgainst({
|
|
228
|
+
cwd,
|
|
229
|
+
git: gitIface,
|
|
230
|
+
mergeHead: resolveMergeHead({ cwd, git: gitIface }),
|
|
231
|
+
});
|
|
148
232
|
}
|
|
149
233
|
|
|
150
234
|
/**
|
|
@@ -154,6 +238,11 @@ export function getStagedFiles({ cwd = process.cwd(), git } = {}) {
|
|
|
154
238
|
* is ignored. Otherwise a `changedSinceRef` limits to that three-dot diff;
|
|
155
239
|
* when both are absent the caller runs in full-repo mode (`scopeSet: null`).
|
|
156
240
|
*
|
|
241
|
+
* In `staged` scope, `diffRef` carries the in-progress merge head when there
|
|
242
|
+
* is one (Story #5131) and `null` otherwise, so a caller can tell the operator
|
|
243
|
+
* *why* the scope narrowed. `scope` stays `'staged'` either way — the merge is
|
|
244
|
+
* a property of the base the index is read against, not a different mode.
|
|
245
|
+
*
|
|
157
246
|
* @param {object} [params]
|
|
158
247
|
* @param {boolean} [params.staged=false]
|
|
159
248
|
* @param {string | null} [params.changedSinceRef=null]
|
|
@@ -172,8 +261,10 @@ export function resolvePreviewScope({
|
|
|
172
261
|
git,
|
|
173
262
|
} = {}) {
|
|
174
263
|
if (staged) {
|
|
175
|
-
const
|
|
176
|
-
|
|
264
|
+
const gitIface = git ?? createGitInterface({});
|
|
265
|
+
const mergeHead = resolveMergeHead({ cwd, git: gitIface });
|
|
266
|
+
const files = stagedFilesAgainst({ cwd, git: gitIface, mergeHead });
|
|
267
|
+
return { scopeSet: new Set(files), scope: 'staged', diffRef: mergeHead };
|
|
177
268
|
}
|
|
178
269
|
if (changedSinceRef) {
|
|
179
270
|
try {
|
|
@@ -26,7 +26,7 @@ export default {
|
|
|
26
26
|
severity: 'blocker',
|
|
27
27
|
// 'npm-test' keeps the test-wrapper preflight's refusal claim true: a
|
|
28
28
|
// poisoned shared config is caught before a suite (or N concurrent
|
|
29
|
-
// /deliver workers) inherits it, not only at close/retro time (#4580).
|
|
29
|
+
// /mandrel-deliver workers) inherits it, not only at close/retro time (#4580).
|
|
30
30
|
scope: ['story-close', 'retro', 'npm-test'],
|
|
31
31
|
autoCorrect: 'refuse-and-print',
|
|
32
32
|
detect(state) {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Scope: 'story-close', 'retro'. The check runs at every
|
|
13
13
|
* preflight surface that has the opportunity to invoke Story init —
|
|
14
|
-
* primarily `/deliver`'s init step — and surfaces as a retro audit
|
|
14
|
+
* primarily `/mandrel-deliver`'s init step — and surfaces as a retro audit
|
|
15
15
|
* signal if the failure mode resurfaces during a sprint.
|
|
16
16
|
*
|
|
17
17
|
* The check is `refuse-and-print`. Auto-rewriting an orchestration call
|
|
@@ -253,7 +253,7 @@ export function parseSprintArgs(
|
|
|
253
253
|
process.env.AGENT_WORKTREE_ROOT ||
|
|
254
254
|
null,
|
|
255
255
|
recutOf: parseTicketId(values['recut-of']),
|
|
256
|
-
// Story #4253: pre-resolved Epic linkage threaded by the /deliver
|
|
256
|
+
// Story #4253: pre-resolved Epic linkage threaded by the /mandrel-deliver
|
|
257
257
|
// fan-out so `single-story-init.js` can skip redundant Epic lookups when
|
|
258
258
|
// the parent already threaded Epic context (pre-v2; field retained for
|
|
259
259
|
// CLI compatibility).
|
|
@@ -36,7 +36,7 @@ export function applyHeader(content, header) {
|
|
|
36
36
|
* True when a workflow opts out of slash-command projection via a
|
|
37
37
|
* `command: false` key in its YAML frontmatter (#4482). Used for dual-use
|
|
38
38
|
* lens files (e.g. `audit-security.md`) that stay in
|
|
39
|
-
* the payload as `/deliver` audit-suite prompts but must NOT surface as
|
|
39
|
+
* the payload as `/mandrel-deliver` audit-suite prompts but must NOT surface as
|
|
40
40
|
* standalone slash commands because the host ships a native equivalent.
|
|
41
41
|
*
|
|
42
42
|
* Both `sync-claude-commands.js` (projection + orphan-reap) and the
|
|
@@ -36,7 +36,7 @@ export const DELIVERY_ROUTING_DEFAULTS = Object.freeze({
|
|
|
36
36
|
/** @type {'minimal'|'standard'|'strict'} */
|
|
37
37
|
ceremonyProfile: 'standard',
|
|
38
38
|
/**
|
|
39
|
-
* When true (default), attended `/deliver` lands through merge in one
|
|
39
|
+
* When true (default), attended `/mandrel-deliver` lands through merge in one
|
|
40
40
|
* close (`--wait-merge` semantics) instead of stopping at `agent::closing`.
|
|
41
41
|
* Operators opt out per-run with `--no-wait-merge`.
|
|
42
42
|
*/
|