mandrel 2.36.0 → 2.38.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 +16 -16
- package/.agents/agents/plan-critic.md +1 -1
- package/.agents/docs/SDLC.md +40 -40
- package/.agents/docs/configuration.md +41 -16
- 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/rules/testing-standards.md +56 -0
- package/.agents/schemas/agentrc.schema.json +9 -9
- 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/boot-sweep.js +7 -1
- package/.agents/scripts/check-context-budget.js +195 -103
- package/.agents/scripts/check-cyclomatic.js +112 -42
- package/.agents/scripts/check-doc-links.js +32 -4
- package/.agents/scripts/check-generated-validator.js +202 -0
- package/.agents/scripts/check-lifecycle-lint.js +2 -68
- package/.agents/scripts/check-schema-references.js +2 -28
- 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 +19 -2
- package/.agents/scripts/evidence-gate.js +1 -1
- 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/baselines/components.js +32 -2
- package/.agents/scripts/lib/baselines/env-overrides.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 +2 -2
- package/.agents/scripts/lib/bootstrap/commit-push.js +2 -2
- package/.agents/scripts/lib/bootstrap/install-ledger.js +1 -1
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +1 -1
- package/.agents/scripts/lib/bootstrap/prompt.js +1 -1
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +2 -2
- package/.agents/scripts/lib/checks/core-bare-clean.js +1 -1
- package/.agents/scripts/lib/checks/loop-health.js +1 -1
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +1 -1
- package/.agents/scripts/lib/cli-args.js +1 -3
- package/.agents/scripts/lib/close-validation/gates.js +1 -1
- package/.agents/scripts/lib/close-validation/process.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/sync-agentrc.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 +49 -9
- package/.agents/scripts/lib/coverage-baseline.js +2 -2
- package/.agents/scripts/lib/cpu-pool.js +90 -10
- package/.agents/scripts/lib/crap-utils.js +6 -2
- package/.agents/scripts/lib/cyclomatic-ceiling.js +28 -6
- package/.agents/scripts/lib/cyclomatic-scope.js +144 -0
- package/.agents/scripts/lib/dependency-version.js +86 -0
- package/.agents/scripts/lib/duplicate-search.js +2 -2
- package/.agents/scripts/lib/errors/index.js +1 -1
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +2 -2
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +5 -5
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +2 -2
- 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 +16 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/install-cmd-parser.js +1 -1
- package/.agents/scripts/lib/knip-entry-sync.js +1 -57
- package/.agents/scripts/lib/label-constants.js +2 -2
- package/.agents/scripts/lib/label-taxonomy.js +1 -1
- package/.agents/scripts/lib/maintainability-utils.js +108 -10
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- 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 +86 -25
- 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/pr-watch.js +1 -30
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +2 -2
- 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/review-providers/codex.js +3 -3
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/native.js +9 -2
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +2 -2
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +3 -3
- 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/options.js +52 -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-close/format-autofix.js +2 -5
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +14 -12
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-lease.js +34 -9
- package/.agents/scripts/lib/orchestration/ticket-validator.js +1 -1
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +6 -4
- package/.agents/scripts/lib/plan-phase-cleanup.js +1 -1
- package/.agents/scripts/lib/preflight-runner.js +3 -3
- package/.agents/scripts/lib/qa/qa-session.js +1 -1
- package/.agents/scripts/lib/runtime-deps/manifest.js +1 -7
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +3 -58
- package/.agents/scripts/lib/signals/schema.js +1 -1
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +284 -25
- package/.agents/scripts/lib/skills/walk-skill-files.js +1 -1
- package/.agents/scripts/lib/source-text/strip-js-comments.js +115 -0
- package/.agents/scripts/lib/story-adjacency.js +2 -2
- package/.agents/scripts/lib/templates/decomposer-prompts.js +1 -1
- package/.agents/scripts/lib/test-isolate/runner.js +3 -3
- package/.agents/scripts/lib/test-runner-contract.js +14 -6
- package/.agents/scripts/lib/test-tiers.js +135 -18
- package/.agents/scripts/lib/ticket-body-sections.js +1 -1
- package/.agents/scripts/lib/transpile.js +16 -3
- 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 +170 -32
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +2 -5
- 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/pr-watch-with-update.js +305 -137
- 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 +114 -21
- package/.agents/scripts/quality-preview.js +162 -70
- 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/run-test-profile.js +8 -5
- package/.agents/scripts/run-tests.js +79 -14
- package/.agents/scripts/single-story-close.js +2 -4
- package/.agents/scripts/single-story-init.js +10 -6
- package/.agents/scripts/stories-wave-tick.js +8 -8
- 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 +1 -1
- package/README.md +7 -7
- package/docs/CHANGELOG.md +43 -0
- package/lib/cli/doctor.js +1 -1
- package/lib/cli/init.js +1 -1
- package/lib/cli/migrate.js +100 -94
- package/lib/migrations/helpers/retire-agentrc-key.js +200 -0
- package/lib/migrations/index.js +32 -33
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +21 -80
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +15 -87
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +13 -71
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +1 -1
- package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +13 -101
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +13 -100
- package/package.json +7 -3
- package/.agents/scripts/lib/audit-suite/frontmatter-lint.js +0 -32
- package/.agents/scripts/lib/baselines/maintainability-baseline-save.js +0 -37
- package/.agents/scripts/lib/cli/parse-numeric.js +0 -60
- package/.agents/scripts/lib/close-validation/telemetry.js +0 -79
- package/.agents/scripts/lib/orchestration/label-transitions.js +0 -44
- package/.agents/scripts/lib/orchestration/parked-follow-ons.js +0 -147
- package/.agents/scripts/lib/orchestration/phase-runner.js +0 -88
- package/.agents/scripts/lib/orchestration/recut.js +0 -56
|
@@ -89,7 +89,7 @@ export function branchExistsViaTrackingRef(branch, cwd) {
|
|
|
89
89
|
/**
|
|
90
90
|
* Pure: classify how a `story-<id>` branch should be seeded from the (local,
|
|
91
91
|
* remote) ref-presence matrix. This is the single source of truth for
|
|
92
|
-
* `single-story-init.js#decideStoryBranchSeed` (v2 `/deliver` path).
|
|
92
|
+
* `single-story-init.js#decideStoryBranchSeed` (v2 `/mandrel-deliver` path).
|
|
93
93
|
*
|
|
94
94
|
* The init path previously re-implemented the same `local → no-op, remote →
|
|
95
95
|
* fetch, else create` decision tree; it now delegates here so the branching
|
|
@@ -122,7 +122,7 @@ export function classifyBranchSeed({ localHas, remoteHas }) {
|
|
|
122
122
|
* The two callers differ in exactly two behavioural axes, both of which are
|
|
123
123
|
* parameters here — no other conditional branching is introduced:
|
|
124
124
|
* - **`baseRef`** — the ref to branch from on `create` (`main` for v2
|
|
125
|
-
* `/deliver`; pre-v2 Epic close used the Epic branch).
|
|
125
|
+
* `/mandrel-deliver`; pre-v2 Epic close used the Epic branch).
|
|
126
126
|
* - **`swallowCreateRace`** — when `true`, a `git branch` that exits
|
|
127
127
|
* non-zero with an "already exists" stderr is treated as reuse rather
|
|
128
128
|
* than a fatal error (pre-v2 concurrent wave dispatch). When `false`, any create failure
|
|
@@ -17,7 +17,7 @@ import { spawnSync as defaultSpawnSync } from 'node:child_process';
|
|
|
17
17
|
* @param {string} installCmd
|
|
18
18
|
* @returns {{ bin: string, args: string[], shell: boolean }}
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
function parseInstallCmd(installCmd) {
|
|
21
21
|
const tokens = String(installCmd ?? '')
|
|
22
22
|
.trim()
|
|
23
23
|
.split(/\s+/)
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
resolveKnipEntryPatterns,
|
|
60
60
|
__testing as resolverTesting,
|
|
61
61
|
} from './knip-config-resolver.js';
|
|
62
|
+
import { stripJsComments } from './source-text/strip-js-comments.js';
|
|
62
63
|
|
|
63
64
|
// Only `resolveEntrySync` and `renderEntrySyncReport` are public — they are
|
|
64
65
|
// what `check-knip-entries.js` calls. Everything else is module-private and
|
|
@@ -89,63 +90,6 @@ const INVOCATION_SURFACES = Object.freeze([
|
|
|
89
90
|
{ kind: 'dir', at: SCRIPTS_DIR, test: /\.js$/ },
|
|
90
91
|
]);
|
|
91
92
|
|
|
92
|
-
/**
|
|
93
|
-
* Strip line and block comments from JavaScript source, preserving string and
|
|
94
|
-
* template literals so a `'https://…'` or a `` `${x}//y` `` is not mangled.
|
|
95
|
-
*
|
|
96
|
-
* Comments are stripped before scanning `.js` surfaces so a JSDoc paragraph
|
|
97
|
-
* that merely *names* a CLI ("superseded by `node .agents/scripts/foo.js`")
|
|
98
|
-
* cannot confer liveness on it. Several such mentions exist today; every one
|
|
99
|
-
* of them is prose about a script's internals, not a call.
|
|
100
|
-
*
|
|
101
|
-
* Replaces comment bodies with equivalent whitespace rather than deleting
|
|
102
|
-
* them, so byte offsets and line numbers survive for any future caller that
|
|
103
|
-
* wants to report a position.
|
|
104
|
-
*
|
|
105
|
-
* @param {string} source
|
|
106
|
-
* @returns {string}
|
|
107
|
-
*/
|
|
108
|
-
function stripJsComments(source) {
|
|
109
|
-
const text = String(source ?? '');
|
|
110
|
-
let out = '';
|
|
111
|
-
let i = 0;
|
|
112
|
-
const blank = (s) => s.replace(/[^\n]/g, ' ');
|
|
113
|
-
while (i < text.length) {
|
|
114
|
-
const two = text.slice(i, i + 2);
|
|
115
|
-
if (two === '//') {
|
|
116
|
-
const end = text.indexOf('\n', i);
|
|
117
|
-
const stop = end === -1 ? text.length : end;
|
|
118
|
-
out += blank(text.slice(i, stop));
|
|
119
|
-
i = stop;
|
|
120
|
-
} else if (two === '/*') {
|
|
121
|
-
const end = text.indexOf('*/', i + 2);
|
|
122
|
-
const stop = end === -1 ? text.length : end + 2;
|
|
123
|
-
out += blank(text.slice(i, stop));
|
|
124
|
-
i = stop;
|
|
125
|
-
} else {
|
|
126
|
-
const ch = text[i];
|
|
127
|
-
if (ch === "'" || ch === '"' || ch === '`') {
|
|
128
|
-
let j = i + 1;
|
|
129
|
-
while (j < text.length) {
|
|
130
|
-
if (text[j] === '\\') {
|
|
131
|
-
j += 2;
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (text[j] === ch) break;
|
|
135
|
-
j += 1;
|
|
136
|
-
}
|
|
137
|
-
const stop = Math.min(j + 1, text.length);
|
|
138
|
-
out += text.slice(i, stop);
|
|
139
|
-
i = stop;
|
|
140
|
-
} else {
|
|
141
|
-
out += ch;
|
|
142
|
-
i += 1;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return out;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
93
|
/**
|
|
150
94
|
* Recursively list files under `dir`, skipping `node_modules` and `.git`.
|
|
151
95
|
*
|
|
@@ -15,7 +15,7 @@ export const AGENT_LABELS = {
|
|
|
15
15
|
// the Story PR is opened against `main`. It flips to
|
|
16
16
|
// `agent::done` only after the close pipeline confirms the PR merge
|
|
17
17
|
// landed; if the close is killed mid-flight, the Story remains at
|
|
18
|
-
// `agent::closing` so `/deliver` can pick up at the
|
|
18
|
+
// `agent::closing` so `/mandrel-deliver` can pick up at the
|
|
19
19
|
// post-merge phase rather than re-running preflight. The label is the
|
|
20
20
|
// distinguishing signal between "hung close" and "finished work".
|
|
21
21
|
CLOSING: 'agent::closing',
|
|
@@ -101,7 +101,7 @@ export const ACCEPTANCE_NA = ACCEPTANCE_LABELS.N_A;
|
|
|
101
101
|
* loop). `meta::framework-gap` is applied to issues that surface a defect or
|
|
102
102
|
* missing capability in the framework itself; `meta::consumer-improvement`
|
|
103
103
|
* is applied to issues that surface improvements to a consumer project
|
|
104
|
-
* (workflow tweaks, ergonomic asks, doc polish). The `/plan` Phase 0
|
|
104
|
+
* (workflow tweaks, ergonomic asks, doc polish). The `/mandrel-plan` Phase 0
|
|
105
105
|
* fetcher (see `lib/feedback-loop/prior-feedback-fetcher.js`) reads open
|
|
106
106
|
* issues carrying either label and surfaces them to the planner so retro
|
|
107
107
|
* signals are routed into durable substrates rather than lost in chat.
|
|
@@ -40,7 +40,7 @@ export const LABEL_TAXONOMY = [
|
|
|
40
40
|
name: AGENT_LABELS.READY,
|
|
41
41
|
color: LABEL_COLORS.AGENT,
|
|
42
42
|
description:
|
|
43
|
-
'Parking state — frozen dispatch manifest exists; awaiting local /deliver',
|
|
43
|
+
'Parking state — frozen dispatch manifest exists; awaiting local /mandrel-deliver',
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
name: AGENT_LABELS.EXECUTING,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { Minimatch } from 'minimatch';
|
|
4
4
|
import { canonicalise as canonicalisePath } from './baselines/path-canon.js';
|
|
5
5
|
import { POOL_SERIAL_THRESHOLD, runOnPool } from './cpu-pool.js';
|
|
6
6
|
import { Logger } from './Logger.js';
|
|
@@ -27,6 +27,57 @@ const IGNORED_DIRS = new Set([
|
|
|
27
27
|
'.next',
|
|
28
28
|
]);
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Compiled-matcher cache for `isIgnoredByGlobs`, keyed on the pattern list.
|
|
32
|
+
*
|
|
33
|
+
* `minimatch(path, glob)` re-parses `glob` into an AST on every call, so the
|
|
34
|
+
* scan was paying O(files × globs) glob *compilations* to answer O(files ×
|
|
35
|
+
* globs) glob *matches* — 12–17 ms over the 619-file tree against 0.5 ms
|
|
36
|
+
* once the patterns are compiled (Story #5109). The number of distinct
|
|
37
|
+
* pattern lists in a process is tiny (one per gate), and each list is
|
|
38
|
+
* config-derived and immutable, so an unbounded `Map` keyed on the joined
|
|
39
|
+
* patterns is bounded in practice.
|
|
40
|
+
*
|
|
41
|
+
* Each entry also memoises the per-path verdict. The baseline gates ask the
|
|
42
|
+
* same question about the same path many times over — `crap.json` carries
|
|
43
|
+
* thousands of method rows spread over a few hundred files, and the evaluate
|
|
44
|
+
* phase filters every row — so the second and later asks about a path cost a
|
|
45
|
+
* `Map` lookup instead of a globstar walk. Both caches are keyed on
|
|
46
|
+
* config-derived, immutable inputs, and both are bounded by the tree the
|
|
47
|
+
* process is scanning.
|
|
48
|
+
*
|
|
49
|
+
* `\u0000` is the join separator because it cannot occur in a glob, so two
|
|
50
|
+
* different lists cannot collide onto one key.
|
|
51
|
+
*
|
|
52
|
+
* @type {Map<string, {matchers: import('minimatch').Minimatch[], verdicts: Map<string, boolean>}>}
|
|
53
|
+
*/
|
|
54
|
+
const IGNORE_MATCHER_CACHE = new Map();
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Compile (once) the `Minimatch` instances for a pattern list, alongside the
|
|
58
|
+
* per-path verdict memo that shares their lifetime.
|
|
59
|
+
*
|
|
60
|
+
* Non-string patterns are dropped rather than compiled — `minimatch()` would
|
|
61
|
+
* have thrown on them, and the functional call site never fed it any, so
|
|
62
|
+
* dropping preserves the observable result set.
|
|
63
|
+
*
|
|
64
|
+
* @param {string[]} ignoreGlobs
|
|
65
|
+
* @returns {{matchers: import('minimatch').Minimatch[], verdicts: Map<string, boolean>}}
|
|
66
|
+
*/
|
|
67
|
+
function ignoreMatcherEntry(ignoreGlobs) {
|
|
68
|
+
const key = ignoreGlobs.join('\u0000');
|
|
69
|
+
let entry = IGNORE_MATCHER_CACHE.get(key);
|
|
70
|
+
if (entry) return entry;
|
|
71
|
+
entry = {
|
|
72
|
+
matchers: ignoreGlobs
|
|
73
|
+
.filter((g) => typeof g === 'string')
|
|
74
|
+
.map((g) => new Minimatch(g, { dot: true })),
|
|
75
|
+
verdicts: new Map(),
|
|
76
|
+
};
|
|
77
|
+
IGNORE_MATCHER_CACHE.set(key, entry);
|
|
78
|
+
return entry;
|
|
79
|
+
}
|
|
80
|
+
|
|
30
81
|
/**
|
|
31
82
|
* Test whether an absolute (or repo-relative) file path matches any of the
|
|
32
83
|
* configured `ignoreGlobs`. This is the single source of truth for how the
|
|
@@ -39,22 +90,62 @@ const IGNORED_DIRS = new Set([
|
|
|
39
90
|
*
|
|
40
91
|
* Matching mirrors `scanDirectory`: the path is reduced to a canonicalised,
|
|
41
92
|
* POSIX, repo-relative form and tested against each glob with minimatch's
|
|
42
|
-
* `{ dot: true }` so dot-prefixed roots like `.agents/` match.
|
|
93
|
+
* `{ dot: true }` so dot-prefixed roots like `.agents/` match. The patterns
|
|
94
|
+
* are compiled at most once per distinct list (see `IGNORE_MATCHER_CACHE`);
|
|
95
|
+
* the matched set is identical to the functional `minimatch()` call this
|
|
96
|
+
* replaced, which is what the `gate-scan-fast-path` test pins over the real
|
|
97
|
+
* configured `ignoreGlobs`.
|
|
43
98
|
*
|
|
44
99
|
* @param {string} filePath absolute or relative path to the source file
|
|
45
100
|
* @param {string[]} ignoreGlobs minimatch patterns; empty/absent is a no-op
|
|
46
101
|
* @param {string} [cwd] root for repo-relative resolution; defaults to cwd
|
|
47
102
|
* @returns {boolean} true when the file matches at least one ignore glob
|
|
48
103
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Reduce an absolute-or-relative path to the canonicalised, POSIX,
|
|
106
|
+
* repo-relative form the ignore patterns are written against.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} filePath
|
|
109
|
+
* @param {string} matchCwd
|
|
110
|
+
* @returns {string}
|
|
111
|
+
*/
|
|
112
|
+
function canonicalRelPath(filePath, matchCwd) {
|
|
52
113
|
const absFilePath = path.isAbsolute(filePath)
|
|
53
114
|
? filePath
|
|
54
115
|
: path.resolve(matchCwd, filePath);
|
|
55
116
|
const rawRel = path.relative(matchCwd, absFilePath).replace(/\\/g, '/');
|
|
56
|
-
|
|
57
|
-
|
|
117
|
+
return canonicalisePath(rawRel);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Answer "does this path match any of the entry's patterns", consulting and
|
|
122
|
+
* populating the entry's verdict memo.
|
|
123
|
+
*
|
|
124
|
+
* Split out of `isIgnoredByGlobs` rather than inlined: the memo's
|
|
125
|
+
* hit/miss test is a branch, and folding it into the caller pushed that
|
|
126
|
+
* function from cyclomatic 4 to 5 — over the per-method CRAP contract the
|
|
127
|
+
* pre-push preview enforces. The lookup belongs beside the cache it reads
|
|
128
|
+
* anyway, and the hot function keeps a flat shape.
|
|
129
|
+
*
|
|
130
|
+
* @param {{matchers: import('minimatch').Minimatch[], verdicts: Map<string, boolean>}} entry
|
|
131
|
+
* @param {string} relPath Canonicalised, POSIX, repo-relative path.
|
|
132
|
+
* @returns {boolean}
|
|
133
|
+
*/
|
|
134
|
+
function memoisedIgnoreVerdict(entry, relPath) {
|
|
135
|
+
const memoised = entry.verdicts.get(relPath);
|
|
136
|
+
if (memoised !== undefined) return memoised;
|
|
137
|
+
const verdict = entry.matchers.some((m) => m.match(relPath));
|
|
138
|
+
entry.verdicts.set(relPath, verdict);
|
|
139
|
+
return verdict;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function isIgnoredByGlobs(filePath, ignoreGlobs = [], cwd) {
|
|
143
|
+
if (!Array.isArray(ignoreGlobs) || ignoreGlobs.length === 0) return false;
|
|
144
|
+
const matchCwd = cwd ?? process.cwd();
|
|
145
|
+
return memoisedIgnoreVerdict(
|
|
146
|
+
ignoreMatcherEntry(ignoreGlobs),
|
|
147
|
+
canonicalRelPath(filePath, matchCwd),
|
|
148
|
+
);
|
|
58
149
|
}
|
|
59
150
|
|
|
60
151
|
/**
|
|
@@ -107,7 +198,7 @@ export function scanDirectory(dir, fileList = [], opts = {}) {
|
|
|
107
198
|
* Calculates maintainability scores for a list of file paths.
|
|
108
199
|
*
|
|
109
200
|
* Each file's transpile-then-analyze unit is dispatched to a
|
|
110
|
-
* worker_threads pool
|
|
201
|
+
* worker_threads pool whose width `runOnPool` resolves. Workers
|
|
111
202
|
* are recycled across files so TypeScript loads at most once per
|
|
112
203
|
* worker. The pool is bypassed for batches of fewer than
|
|
113
204
|
* `SERIAL_THRESHOLD` files because spawn overhead dominates at small
|
|
@@ -129,9 +220,16 @@ export function scanDirectory(dir, fileList = [], opts = {}) {
|
|
|
129
220
|
* and nothing said so.
|
|
130
221
|
*
|
|
131
222
|
* @param {string[]} paths
|
|
223
|
+
* @param {{serialThreshold?: number}} [opts] `serialThreshold` overrides the
|
|
224
|
+
* pool-vs-serial cutover for this call only. Production callers omit it;
|
|
225
|
+
* the parity tests use it to drive the pooled path on a small fixture set
|
|
226
|
+
* rather than materialising 256 files to clear the cutover.
|
|
132
227
|
* @returns {Promise<Record<string, number>>}
|
|
133
228
|
*/
|
|
134
|
-
export async function calculateAll(paths) {
|
|
229
|
+
export async function calculateAll(paths, opts = {}) {
|
|
230
|
+
const serialThreshold = Number.isFinite(opts?.serialThreshold)
|
|
231
|
+
? opts.serialThreshold
|
|
232
|
+
: SERIAL_THRESHOLD;
|
|
135
233
|
const cwd = process.cwd();
|
|
136
234
|
const indexed = paths.map((p) => ({
|
|
137
235
|
abs: p,
|
|
@@ -139,7 +237,7 @@ export async function calculateAll(paths) {
|
|
|
139
237
|
}));
|
|
140
238
|
|
|
141
239
|
let perFile;
|
|
142
|
-
if (indexed.length <
|
|
240
|
+
if (indexed.length < serialThreshold) {
|
|
143
241
|
perFile = indexed.map(({ abs, relPath }) => {
|
|
144
242
|
try {
|
|
145
243
|
return { relPath, ...scoreFile(abs) };
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Phase 1 — Offer to scaffold missing docsContextFiles (scaffold-docs.js).
|
|
9
9
|
* Phase 2 — Run `mandrel doctor` as a readiness gate.
|
|
10
|
-
* Phase 3 — Print the /plan handoff next-step text.
|
|
10
|
+
* Phase 3 — Print the /mandrel-plan handoff next-step text.
|
|
11
11
|
*
|
|
12
12
|
* The whole tail is idempotent: re-running after an already-onboarded project
|
|
13
13
|
* re-checks and re-offers scaffolding without duplicating stubs (the scaffolder
|
|
@@ -31,13 +31,13 @@ import { STUB_MARKER, scaffoldDocs } from './scaffold-docs.js';
|
|
|
31
31
|
// ---------------------------------------------------------------------------
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* Text printed at the end of the init tail to hand the operator off to /plan.
|
|
34
|
+
* Text printed at the end of the init tail to hand the operator off to /mandrel-plan.
|
|
35
35
|
*
|
|
36
36
|
* @type {string}
|
|
37
37
|
*/
|
|
38
38
|
export const PLAN_HANDOFF_TEXT =
|
|
39
39
|
'\n✅ Mandrel is ready. Start your first project:\n\n' +
|
|
40
|
-
' /plan --seed "<one-line description of what you want to build>"\n';
|
|
40
|
+
' /mandrel-plan --seed "<one-line description of what you want to build>"\n';
|
|
41
41
|
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
43
|
// Internal helpers
|
|
@@ -200,7 +200,7 @@ export async function runInitTail({
|
|
|
200
200
|
return { scaffoldResult, doctorStatus, ok: false };
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
// --- Phase 3: Handoff to /plan -------------------------------------------
|
|
203
|
+
// --- Phase 3: Handoff to /mandrel-plan -------------------------------------------
|
|
204
204
|
stdout(PLAN_HANDOFF_TEXT);
|
|
205
205
|
return { scaffoldResult, doctorStatus, ok: true };
|
|
206
206
|
}
|
|
@@ -25,7 +25,7 @@ const AGENT_ROOT = path.resolve(__dirname, '../../..');
|
|
|
25
25
|
const DOCS_TEMPLATE_DIR = path.join(AGENT_ROOT, 'templates', 'docs');
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Deterministic marker written into every scaffolded stub. The `/plan`
|
|
28
|
+
* Deterministic marker written into every scaffolded stub. The `/mandrel-plan`
|
|
29
29
|
* first-run preflight (and any tooling that wants to detect unedited stubs)
|
|
30
30
|
* keys off this exact string — do not change it without a hard cutover.
|
|
31
31
|
*
|
|
@@ -59,7 +59,7 @@ function genericStub(fileName) {
|
|
|
59
59
|
/**
|
|
60
60
|
* Read the dedicated template body for a docsContextFile, or fall back to the
|
|
61
61
|
* generic stub when no template ships for that name. Either path prepends the
|
|
62
|
-
* {@link STUB_MARKER} so the `/plan` first-run preflight can detect un-edited
|
|
62
|
+
* {@link STUB_MARKER} so the `/mandrel-plan` first-run preflight can detect un-edited
|
|
63
63
|
* stubs regardless of whether a dedicated template was used.
|
|
64
64
|
*
|
|
65
65
|
* @param {string} fileName
|
|
@@ -170,7 +170,7 @@ export function decideAcceptanceEval({ verdict, maxRounds, round: roundIn }) {
|
|
|
170
170
|
/**
|
|
171
171
|
* Build the per-criterion acceptance-eval signal payload for the retro /
|
|
172
172
|
* feedback substrate. Carries which acceptance items needed rework and the
|
|
173
|
-
* round count so `/plan` Phase 0 feedback fetch and the retro can
|
|
173
|
+
* round count so `/mandrel-plan` Phase 0 feedback fetch and the retro can
|
|
174
174
|
* surface acceptance churn. PII-free by construction — it carries only
|
|
175
175
|
* acceptance-item indices, verdicts, and the terminal decision.
|
|
176
176
|
*
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Story #1155 (Epic #1142, 5.40.0) — extracted the helper-driven
|
|
5
5
|
* `epic-code-review` invocation into a callable module so the
|
|
6
|
-
* `/deliver` runner can run Phase D without spawning a child
|
|
6
|
+
* `/mandrel-deliver` runner can run Phase D without spawning a child
|
|
7
7
|
* process or routing through an LLM-driven helper.
|
|
8
8
|
*
|
|
9
9
|
* Story #2831 (Epic #2815, Pluggable Code Review) — refactored to load
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
* `code-review` and `audit-results` findings contracts into this one
|
|
33
33
|
* `verification-results` marker.
|
|
34
34
|
* - Treats severity.critical > 0 as a halting blocker — the merged
|
|
35
|
-
* `/deliver` runner consults `halted` and refuses to advance
|
|
35
|
+
* `/mandrel-deliver` runner consults `halted` and refuses to advance
|
|
36
36
|
* to Phase E (retro) when set.
|
|
37
37
|
*
|
|
38
38
|
* Halting on critical findings is the in-process replacement for the
|
|
39
|
-
* helper's "operator must remediate before /deliver" gate.
|
|
39
|
+
* helper's "operator must remediate before /mandrel-deliver" gate.
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
42
|
import { hasSurvivingCritical } from '../audit-suite/findings.js';
|
|
@@ -129,7 +129,7 @@ function resolveScopeEnvelope(opts, config) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
* In-process wrapper that the `/deliver` runner and the
|
|
132
|
+
* In-process wrapper that the `/mandrel-deliver` runner and the
|
|
133
133
|
* `/single-story-deliver` close path consume.
|
|
134
134
|
*
|
|
135
135
|
* Story #2252 — emits `code-review.start` immediately on entry and
|
|
@@ -132,7 +132,7 @@ export const LITE_ROUTE_LABEL = 'route::lite';
|
|
|
132
132
|
* footprint: `trivial` < `moderate` < `substantial`.
|
|
133
133
|
* - `maxUncertainty` — is the shape determined by the request
|
|
134
134
|
* (`determined`), or does it still need the design
|
|
135
|
-
* decisions `/plan` exists to resolve
|
|
135
|
+
* decisions `/mandrel-plan` exists to resolve
|
|
136
136
|
* (`needs-design`)?
|
|
137
137
|
* - `maxDeployables` — named deployable roots (`apps/<x>`, `packages/<x>`, …)
|
|
138
138
|
* the footprint spans; more than one is epic by
|
|
@@ -325,7 +325,7 @@ const EFFORT_RULES = Object.freeze([
|
|
|
325
325
|
UNCERTAINTY_SCALE.indexOf(s.uncertainty) >
|
|
326
326
|
UNCERTAINTY_SCALE.indexOf(c.maxUncertainty),
|
|
327
327
|
reason: (s) =>
|
|
328
|
-
`the shape is not determined by the request (uncertainty "${s.uncertainty}") — the design decisions /plan exists to resolve are still open; full route`,
|
|
328
|
+
`the shape is not determined by the request (uncertainty "${s.uncertainty}") — the design decisions /mandrel-plan exists to resolve are still open; full route`,
|
|
329
329
|
},
|
|
330
330
|
{
|
|
331
331
|
code: SHAPE_CODES.DEPLOYABLE_SPAN,
|
|
@@ -657,7 +657,7 @@ function buildEffortShape({
|
|
|
657
657
|
/**
|
|
658
658
|
* Derive the complexity route from an authored Story's **effort and risk**
|
|
659
659
|
* (Story #4722 AC-3/AC-4; re-anchored off artifact cardinality by Story #4764)
|
|
660
|
-
* — the single shape function persist's backstop and `/deliver`'s dispatch
|
|
660
|
+
* — the single shape function persist's backstop and `/mandrel-deliver`'s dispatch
|
|
661
661
|
* derivation both read, so the two can never disagree about the same body.
|
|
662
662
|
*
|
|
663
663
|
* `lite` requires **every** signal to agree, against
|
|
@@ -804,7 +804,7 @@ export function deriveStoryShape({
|
|
|
804
804
|
}
|
|
805
805
|
|
|
806
806
|
/**
|
|
807
|
-
* Decide how `/deliver` executes a Story: **run topology, and nothing else.**
|
|
807
|
+
* Decide how `/mandrel-deliver` executes a Story: **run topology, and nothing else.**
|
|
808
808
|
*
|
|
809
809
|
* **`inline` names one indivisible resource: the router's own session.** Two
|
|
810
810
|
* Stories cannot both own it, so exactly one premise can grant it —
|
|
@@ -839,7 +839,7 @@ export function deriveStoryShape({
|
|
|
839
839
|
* module header's non-negotiables.
|
|
840
840
|
*
|
|
841
841
|
* @param {{ storyCount?: unknown }} [args] `storyCount` is the number of
|
|
842
|
-
* Stories the invoking `/deliver` run resolved. Omitted (or not exactly 1)
|
|
842
|
+
* Stories the invoking `/mandrel-deliver` run resolved. Omitted (or not exactly 1)
|
|
843
843
|
* means the run cannot be shown sibling-free and therefore dispatches as a
|
|
844
844
|
* sub-agent — never an assumed 1.
|
|
845
845
|
* @returns {{ mode: 'inline'|'subagent', reasons: string[] }}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* - `closing` with a red PR → enter the fix loop. Waiting is pointless; no
|
|
22
22
|
* budget turns a failed check green.
|
|
23
23
|
* - `closing` with a MERGED PR → run confirm. **This is the strand a
|
|
24
|
-
* `/deliver` re-run refuses outright**, because `single-story-init.js`
|
|
24
|
+
* `/mandrel-deliver` re-run refuses outright**, because `single-story-init.js`
|
|
25
25
|
* hard-errors on an already-closed Story — so before this surface, the
|
|
26
26
|
* merged-but-label-stale Story had no automated way back.
|
|
27
27
|
* - `done` with a drifted board → run resync. The GitHub Projects bot won
|
|
@@ -367,7 +367,7 @@ export function decideRecovery({
|
|
|
367
367
|
nextCommand: NEXT_COMMANDS.confirmMerge(storyId),
|
|
368
368
|
detail:
|
|
369
369
|
`PR #${pr.number} is MERGED but the Story is at \`${label ?? 'no state label'}\`. ` +
|
|
370
|
-
`A /deliver re-run cannot fix this — single-story-init.js hard-errors on an ` +
|
|
370
|
+
`A /mandrel-deliver re-run cannot fix this — single-story-init.js hard-errors on an ` +
|
|
371
371
|
`already-closed Story. The confirm CLI is idempotent and flips the label from ` +
|
|
372
372
|
`the already-merged PR, then runs the land tail.`,
|
|
373
373
|
evidence,
|
|
@@ -482,7 +482,7 @@ export function decideRecovery({
|
|
|
482
482
|
nextCommand: NEXT_COMMANDS.close(storyId),
|
|
483
483
|
detail:
|
|
484
484
|
`Story is at \`${label ?? 'no agent:: state label'}\` — not mid-delivery, so there ` +
|
|
485
|
-
`is no strand to recover. Deliver it normally via /deliver ${storyId}.`,
|
|
485
|
+
`is no strand to recover. Deliver it normally via /mandrel-deliver ${storyId}.`,
|
|
486
486
|
evidence,
|
|
487
487
|
};
|
|
488
488
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* docs-digest.js — per-run docs digest builder (Story #4338).
|
|
3
3
|
*
|
|
4
|
-
* `/deliver` story sub-agents previously re-read every file in
|
|
4
|
+
* `/mandrel-deliver` story sub-agents previously re-read every file in
|
|
5
5
|
* `project.docsContextFiles` on every Story, re-paying the full docs payload
|
|
6
6
|
* per child. This module produces a single **digest** — one compact markdown
|
|
7
7
|
* outline per configured doc — that the parent threads into every child prompt
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* generate-and-write export so the planner-context surface
|
|
18
18
|
* (`plan-context.js` / `authoring-context.js`) can produce a session docs
|
|
19
19
|
* digest without duplicating the mkdir+writeFile plumbing shared by
|
|
20
|
-
* `plan-context.js` / `authoring-context.js` and the `/deliver` workflow.
|
|
20
|
+
* `plan-context.js` / `authoring-context.js` and the `/mandrel-deliver` workflow.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import fs from 'node:fs';
|
|
@@ -145,7 +145,7 @@ export async function buildDocsDigest({ docsContextFiles, docsRoot } = {}) {
|
|
|
145
145
|
* Build the docs digest and write it to `outputPath`, returning `null` (no
|
|
146
146
|
* write) when there is nothing to digest. This is the single shared
|
|
147
147
|
* generate-and-persist export both digest producers call: the per-run
|
|
148
|
-
* `/deliver` docs digest (`helpers/deliver-story.md`) and the planner-
|
|
148
|
+
* `/mandrel-deliver` docs digest (`helpers/deliver-story.md`) and the planner-
|
|
149
149
|
* context digest (`plan-context.js` → `authoring-context.js`, Story
|
|
150
150
|
* #4433). Callers own path construction (temp-root layout, run id, etc.)
|
|
151
151
|
* so both surfaces can keep — or deliberately share — their own convention;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* kernel shared by the three per-surface lease guards.
|
|
4
4
|
*
|
|
5
5
|
* The per-surface lease guards — today `single-story-lease-guard.js`;
|
|
6
|
-
* historically also the retired Epic-tier deliver/plan guards —
|
|
6
|
+
* historically also the retired Epic-tier deliver/mandrel-plan guards —
|
|
7
7
|
* each carried their own copy of
|
|
8
8
|
* the operator-handle resolution and the fail-closed acquire wrapper around
|
|
9
9
|
* `ticket-lease.acquireLease` (refuse any foreign assignee, throwing an
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* - **Operator candidates** — each surface supplies its own ordered
|
|
22
22
|
* candidate list (e.g. `--as` flag → `github.operatorHandle` →
|
|
23
|
-
* `git user.email` for `/deliver`; bare `operatorHandle` for the
|
|
23
|
+
* `git user.email` for `/mandrel-deliver`; bare `operatorHandle` for the
|
|
24
24
|
* plan/standalone paths).
|
|
25
25
|
* - **Missing-handle behaviour** — `'null'` (return null; the caller fails
|
|
26
26
|
* closed at acquire time) vs `'throw'` (refuse immediately with surface
|
|
@@ -71,7 +71,7 @@ function runDiffBackstop({
|
|
|
71
71
|
*
|
|
72
72
|
* A refusal also **preserves** the work before it reports (Story #4875): the
|
|
73
73
|
* implementation is finished and the recycle command hands the receipt to
|
|
74
|
-
* `/plan`, so leaving it on an untracked local branch that routine cleanup may
|
|
74
|
+
* `/mandrel-plan`, so leaving it on an untracked local branch that routine cleanup may
|
|
75
75
|
* reap is not an acceptable end state. Preservation is best-effort and its
|
|
76
76
|
* outcome is reported either way — a failed push degrades the message, never
|
|
77
77
|
* the verdict or the exit code.
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* {@link module:lib/orchestration/light-suitability}:
|
|
8
8
|
*
|
|
9
9
|
* 1. **Recycling the receipt.** A blocked diff backstop used to tell the
|
|
10
|
-
* operator to "escalate to `/plan`", which authored a brand-new Story and
|
|
10
|
+
* operator to "escalate to `/mandrel-plan`", which authored a brand-new Story and
|
|
11
11
|
* left the receipt open with no successor — orphaning its branch, its
|
|
12
|
-
* worktree, and a finished implementation. Naming the receipt as `/plan`'s
|
|
12
|
+
* worktree, and a finished implementation. Naming the receipt as `/mandrel-plan`'s
|
|
13
13
|
* *input* recycles it instead: tickets mode already fetches a ticket,
|
|
14
14
|
* rewrites it into properly-planned Stories, and closes the source as
|
|
15
15
|
* superseded.
|
|
@@ -45,13 +45,13 @@ import {
|
|
|
45
45
|
} from '../observability/runtime-friction.js';
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* The `/plan` invocation that owns a Story the light path could not land.
|
|
48
|
+
* The `/mandrel-plan` invocation that owns a Story the light path could not land.
|
|
49
49
|
*
|
|
50
50
|
* @param {number} storyId
|
|
51
51
|
* @returns {string}
|
|
52
52
|
*/
|
|
53
53
|
function buildRecycleCommand(storyId) {
|
|
54
|
-
return `/plan ${storyId}`;
|
|
54
|
+
return `/mandrel-plan ${storyId}`;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/**
|
|
@@ -106,7 +106,7 @@ export async function recordGateRefusal({
|
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
108
|
* Handle a blocked diff backstop: record the refusal as friction and return the
|
|
109
|
-
* `/plan` invocation that recycles the receipt.
|
|
109
|
+
* `/mandrel-plan` invocation that recycles the receipt.
|
|
110
110
|
*
|
|
111
111
|
* Lives here rather than in the CLI so the shell stays a shell — the backstop
|
|
112
112
|
* mode's job is to branch and print, not to decide what a refusal means.
|
|
@@ -152,7 +152,7 @@ export async function handleBlockedBackstop({
|
|
|
152
152
|
* recoverable (Story #4875).
|
|
153
153
|
*
|
|
154
154
|
* A blocked backstop refuses the *land*, not the *work*: the implementation is
|
|
155
|
-
* complete and the recycle command hands the receipt to `/plan`, which will
|
|
155
|
+
* complete and the recycle command hands the receipt to `/mandrel-plan`, which will
|
|
156
156
|
* want it. Before this, that work existed only as a local `story-<id>` branch
|
|
157
157
|
* with no remote ref — an untracked branch is exactly what the routine merged-
|
|
158
158
|
* branch sweeps and worktree reaping treat as disposable, so the only copy of a
|