mandrel 2.58.0 → 2.60.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 +17 -12
- package/.agents/agents/acceptance-critic.md +24 -43
- package/.agents/agents/story-worker.md +18 -19
- package/.agents/docs/SDLC.md +12 -13
- package/.agents/docs/agentrc-reference.json +1 -2
- package/.agents/docs/configuration.md +29 -46
- package/.agents/docs/quality-gates.md +9 -5
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +5 -7
- package/.agents/rules/ci-remediation.md +41 -8
- package/.agents/rules/known-tooling-behavior.md +65 -15
- package/.agents/runtime-deps.json +7 -2
- package/.agents/schemas/acceptance-eval-verdict.schema.json +1 -1
- package/.agents/schemas/agentrc.schema.json +6 -11
- package/.agents/schemas/crap-baseline.schema.json +1 -1
- package/.agents/schemas/crap-report.schema.json +1 -1
- package/.agents/schemas/story-deliver-terminal.schema.json +3 -3
- package/.agents/scripts/README.md +11 -1
- package/.agents/scripts/acceptance-eval.js +25 -27
- package/.agents/scripts/ceremony-derive.js +15 -10
- package/.agents/scripts/check-context-budget.js +148 -228
- package/.agents/scripts/check-schema-references.js +5 -3
- package/.agents/scripts/check-workflow-citations.js +33 -147
- package/.agents/scripts/coverage-capture.js +7 -4
- package/.agents/scripts/deliver-light.js +41 -100
- package/.agents/scripts/deliver-run.js +631 -0
- package/.agents/scripts/file-ci-gap.js +59 -11
- package/.agents/scripts/install-matrix-assert.js +48 -3
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +51 -33
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +6 -2
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +0 -8
- package/.agents/scripts/lib/baselines/kinds/crap.js +35 -18
- package/.agents/scripts/lib/changed-files.js +30 -0
- package/.agents/scripts/lib/config/delivery-routing.js +5 -4
- package/.agents/scripts/lib/config/explain.js +1 -3
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +1 -1
- package/.agents/scripts/lib/config-resolver.js +1 -0
- package/.agents/scripts/lib/config-settings-schema-delivery.js +28 -21
- package/.agents/scripts/lib/coverage-capture-fullscope.js +10 -2
- package/.agents/scripts/lib/coverage-capture-incremental.js +3 -2
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -1
- package/.agents/scripts/lib/crap-engine.js +2 -2
- package/.agents/scripts/lib/crap-utils.js +21 -5
- package/.agents/scripts/lib/doc-tiers.js +4 -2
- package/.agents/scripts/lib/escomplex-ast-compat.js +39 -17
- package/.agents/scripts/lib/escomplex-kernel.js +298 -0
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +7 -6
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +7 -5
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/gh-exec.js +160 -0
- package/.agents/scripts/lib/maintainability-engine.js +3 -3
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +74 -132
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +123 -12
- package/.agents/scripts/lib/orchestration/complexity-gate.js +180 -352
- package/.agents/scripts/lib/orchestration/light-suitability.js +71 -136
- package/.agents/scripts/lib/orchestration/plan-context.js +44 -50
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +8 -6
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +104 -119
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +41 -25
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +11 -11
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +63 -29
- package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +107 -0
- package/.agents/scripts/lib/orchestration/review-depth.js +14 -11
- package/.agents/scripts/lib/orchestration/run-epilogue.js +260 -182
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +63 -99
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +3 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +137 -0
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +105 -18
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +4 -3
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +156 -39
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +71 -0
- package/.agents/scripts/lib/orchestration/task-body-validator.js +8 -17
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +25 -209
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +8 -5
- package/.agents/scripts/lib/orchestration/ticket-validator.js +44 -183
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +14 -25
- package/.agents/scripts/lib/runtime-deps/dep-resolution.js +155 -0
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +44 -9
- package/.agents/scripts/lib/runtime-deps/parser-major.js +110 -0
- package/.agents/scripts/lib/runtime-deps/preflight.js +6 -25
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +46 -1
- package/.agents/scripts/lib/skills/walk-skill-files.js +1 -1
- package/.agents/scripts/lib/story-body/body-format-lints.js +58 -12
- package/.agents/scripts/lib/story-body/story-body.js +83 -29
- package/.agents/scripts/lib/templates/decomposer-prompts.js +28 -33
- package/.agents/scripts/lib/wave-runner/live-probe.js +31 -5
- package/.agents/scripts/merge-baseline.js +4 -5
- package/.agents/scripts/plan-context.js +117 -28
- package/.agents/scripts/plan-persist.js +79 -39
- package/.agents/scripts/plan-run-epilogue.js +11 -8
- package/.agents/scripts/pr-watch-with-update.js +9 -2
- package/.agents/scripts/run-verify.js +13 -6
- package/.agents/scripts/single-story-init.js +7 -57
- package/.agents/scripts/stories-wave-tick.js +160 -26
- package/.agents/skills/core/gates-and-baselines/reference.md +0 -1
- package/.agents/skills/skills.index.json +2 -12
- package/.agents/skills/stack/qa/playwright/SKILL.md +26 -0
- package/.agents/workflows/audit-to-stories.md +14 -11
- package/.agents/workflows/helpers/acceptance-self-eval.md +84 -157
- package/.agents/workflows/helpers/code-review.md +4 -2
- package/.agents/workflows/helpers/deliver-digest.md +31 -24
- package/.agents/workflows/helpers/deliver-light.md +92 -101
- package/.agents/workflows/helpers/deliver-reference.md +116 -100
- package/.agents/workflows/helpers/deliver-story-reference.md +58 -124
- package/.agents/workflows/helpers/deliver-story.md +17 -18
- package/.agents/workflows/helpers/plan-reference.md +82 -60
- package/.agents/workflows/mandrel-deliver.md +47 -31
- package/.agents/workflows/mandrel-plan.md +32 -30
- package/.agents/workflows/mandrel-update.md +36 -21
- package/README.md +3 -3
- package/docs/CHANGELOG.md +43 -0
- package/lib/cli/registry.js +45 -25
- package/lib/cli/update.js +376 -17
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +40 -0
- package/package.json +8 -2
- package/.agents/schemas/model-attribution.schema.json +0 -53
- package/.agents/scripts/lib/orchestration/model-attribution.js +0 -418
- package/.agents/scripts/lib/orchestration/split-policy-validator.js +0 -188
- package/.agents/scripts/lib/orchestration/story-plan-state.js +0 -33
- package/.agents/scripts/lib/orchestration/structured-comment-parser.js +0 -67
- package/.agents/scripts/lib/templates/spec-author-prompts.js +0 -76
- package/.agents/skills/core/scope-triage/SKILL.md +0 -48
|
@@ -33,7 +33,7 @@ you read:
|
|
|
33
33
|
| --- | --- | --- |
|
|
34
34
|
| `/mandrel-deliver` | bare | List the open `agent::ready` Stories and ask which to deliver. Deliver nothing until answered. |
|
|
35
35
|
| `/mandrel-deliver 4712` | ids | One Story via `helpers/deliver-story.md`, **inline in this session** — no `story-worker` spawn. |
|
|
36
|
-
| `/mandrel-deliver 4712 4713 …` | ids | Resolve the set,
|
|
36
|
+
| `/mandrel-deliver 4712 4713 …` | ids | Resolve the set, then beat `deliver-run.js` — it sequences by the discovered graph and hands back the spawns and closes. |
|
|
37
37
|
| `/mandrel-deliver 4712 - 4716` | ids | A **range** — every id in the inclusive span. |
|
|
38
38
|
| `/mandrel-deliver 4700` (a `type::epic`) | ids | The Epic's **open** child Stories. Mixes with Story ids. |
|
|
39
39
|
| `/mandrel-deliver add a --json flag to doctor` | prompt | Unplanned work: gate, author a receipt Story, land it — [`helpers/deliver-light.md`](helpers/deliver-light.md). |
|
|
@@ -42,10 +42,10 @@ you read:
|
|
|
42
42
|
id, and `^#?\d+\s*[-–—]\s*#?\d+$` an inclusive **range** — pass one on as a
|
|
43
43
|
single unspaced token, never hand-expanded (reference). Either shape
|
|
44
44
|
means ids; anything else means a prompt. A **mixed** invocation (ids *and*
|
|
45
|
-
prose) is
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
prose) is **ambiguous, not fatal** — disambiguate it rather than refusing:
|
|
46
|
+
ask which was meant, or, when the reading is obvious, name the one you
|
|
47
|
+
inferred before acting on it. A ticket that is neither `type::story` nor
|
|
48
|
+
`type::epic` is a **hard error**.
|
|
49
49
|
|
|
50
50
|
## Saying what you want
|
|
51
51
|
|
|
@@ -67,41 +67,51 @@ to an attended run.
|
|
|
67
67
|
1. **Resolve the set.** One command, one Story or many:
|
|
68
68
|
`node .agents/scripts/resolve-stories.js --ids <id,id,...>`. It validates the
|
|
69
69
|
set and shows what will run: read `stories[]`, `dag[]` and `done[]` to
|
|
70
|
-
present the order in step 2, but do **not** thread them into step 3 —
|
|
71
|
-
|
|
70
|
+
present the order in step 2, but do **not** thread them into step 3 — every
|
|
71
|
+
beat re-resolves the graph. A one-id run comes back `dispatchMode: "inline"`
|
|
72
|
+
and runs [`helpers/deliver-story.md`](helpers/deliver-story.md) in this
|
|
73
|
+
session; step 3 is the multi-Story path. An Epic id expands to its open child
|
|
72
74
|
Stories first — **announce it**. It hard-errors (exit 1) on an id that is
|
|
73
|
-
neither a Story nor an Epic, on an
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
neither a Story nor an Epic, on an Epic with no open children, or on edges
|
|
76
|
+
it cannot read — a missing gate would co-dispatch against an unlanded
|
|
77
|
+
blocker.
|
|
76
78
|
|
|
77
79
|
2. **Confirm (N>1).** Present the order; wait unless `--yes`.
|
|
78
80
|
|
|
79
|
-
3. **
|
|
81
|
+
3. **Run the beat.** One command per beat, repeated until the envelope reports
|
|
82
|
+
the run `done`:
|
|
80
83
|
|
|
81
84
|
```bash
|
|
82
|
-
node .agents/scripts/
|
|
83
|
-
--stories <id,id,...> --
|
|
84
|
-
--dispatched <every id you have dispatched so far>
|
|
85
|
+
node .agents/scripts/deliver-run.js \
|
|
86
|
+
--stories <id,id,...> [--handoff <id>]...
|
|
85
87
|
```
|
|
86
88
|
|
|
87
89
|
**Do not add `--concurrency` unless the operator explicitly asked for a
|
|
88
90
|
per-run cap** — an explicit value wins over config, so a literal defeats a
|
|
89
91
|
`.agentrc.local.json` override.
|
|
90
92
|
|
|
91
|
-
Each beat re-probes live state
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- **0** —
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
Each beat re-probes live state and keeps its own accounting: the run ledger
|
|
94
|
+
under `<tempRoot>/run-<id>/` records every id it hands out, so **nothing is
|
|
95
|
+
maintained across beats by you**. Cross-run de-confliction via the assignee
|
|
96
|
+
lease is automatic. Branch on the exit code:
|
|
97
|
+
- **0** — spawn one `story-worker` per `ready[]` entry, **all in one turn**,
|
|
98
|
+
each with that entry's `promptPath` file as its prompt; run each `close[]`
|
|
99
|
+
entry's command foreground and serialized as hand-offs arrive. An empty
|
|
100
|
+
`ready` with work in flight means "waiting", so beat again — **unless
|
|
101
|
+
`stalledDispatch[]` is non-empty**: those ids were dispatched but still
|
|
102
|
+
read `agent::ready`, which is a live init window the first beats or two
|
|
103
|
+
and a spawn that never started one after that. Beating again cannot
|
|
104
|
+
clear it. Relay `stalledDispatchReason` — it carries the recovery — and
|
|
105
|
+
let the operator decide; never edit the ledger for them.
|
|
106
|
+
`done: true` means every Story is landed — step 4.
|
|
98
107
|
- **2 / 3 / 4** — `cycleError` / `wedged` / `blocked`: stop the loop and
|
|
99
108
|
route per reference. **4** is the protocol's HITL pause
|
|
100
109
|
([`instructions.md` § 1.J](../instructions.md)) — surface it and wait for
|
|
101
110
|
the operator; never poll.
|
|
102
111
|
|
|
103
|
-
4. **
|
|
104
|
-
every Story landed, run the
|
|
112
|
+
4. **Land what the workers hand back** (§ Closing what the workers hand back —
|
|
113
|
+
the beat renders each command), then, with every Story landed, run the
|
|
114
|
+
**per-run epilogue (N>1)**:
|
|
105
115
|
`node .agents/scripts/plan-run-epilogue.js --stories 101,102`; N=1 has none
|
|
106
116
|
([reference](helpers/deliver-reference.md)). Every close rolls its container
|
|
107
117
|
Epic up from its children.
|
|
@@ -117,7 +127,10 @@ to an attended run.
|
|
|
117
127
|
**The tail is the orchestrator's, not the worker's.** A dispatched
|
|
118
128
|
`story-worker` stops at a pushed branch and returns a hand-off; **you** run
|
|
119
129
|
[`helpers/deliver-story.md`](helpers/deliver-story.md) Step 3
|
|
120
|
-
(`single-story-close.js`) for it, foreground, and relay its envelope.
|
|
130
|
+
(`single-story-close.js`) for it, foreground, and relay its envelope. Pass the
|
|
131
|
+
id as `--handoff` on the next beat and run the `close[]` command it prints
|
|
132
|
+
verbatim — the beat knows the run topology, so it decides
|
|
133
|
+
`--merge-watch-mode async` for you.
|
|
121
134
|
|
|
122
135
|
**Serialize the tail.** Implementation runs in parallel; closing does not.
|
|
123
136
|
Close one Story at a time — closes contend on the base branch, the merge queue
|
|
@@ -133,9 +146,11 @@ envelope — `landed` | `pending` | `blocked` | `failed`; statuses, exits and
|
|
|
133
146
|
fields are digest § 5. `pending` is **not** a failure — run its `nextCommand`.
|
|
134
147
|
|
|
135
148
|
**Branch model (authoritative).** `story-<id>` → PR → `main` (squash +
|
|
136
|
-
required checks), per digest § 2; dependent Stories land sequentially.
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
required checks), per digest § 2; dependent Stories land sequentially. The
|
|
150
|
+
acceptance verdict owner follows the ceremony profile alone
|
|
151
|
+
(`ceremony-routing.js`); the **derived level** feeds review depth instead
|
|
152
|
+
(`review-depth.js`). The rule and its one home are digest § 3; the profile
|
|
153
|
+
table is reference § Ceremony.
|
|
139
154
|
|
|
140
155
|
## Constraints
|
|
141
156
|
|
|
@@ -143,10 +158,11 @@ depth reads): reference § Ceremony.
|
|
|
143
158
|
default to close-and-land (`delivery.routing.closeAndLand: true`); rest at
|
|
144
159
|
`agent::closing` only when a human owns the merge.
|
|
145
160
|
- **`/mandrel-deliver` never plans.** Planned tickets come from
|
|
146
|
-
[`/mandrel-plan`](mandrel-plan.md), and
|
|
147
|
-
ends
|
|
148
|
-
|
|
149
|
-
|
|
161
|
+
[`/mandrel-plan`](mandrel-plan.md), and a refused prompt **escalates**: the
|
|
162
|
+
light path ends, and the escalation's `nextCommand` is what owns the work —
|
|
163
|
+
seeded with `escalation.reasons`, in this session or a fresh one
|
|
164
|
+
([`helpers/deliver-light.md`](helpers/deliver-light.md) § Continuing into
|
|
165
|
+
`/mandrel-plan`).
|
|
150
166
|
|
|
151
167
|
## See also
|
|
152
168
|
|
|
@@ -11,7 +11,7 @@ description:
|
|
|
11
11
|
|
|
12
12
|
## Inputs
|
|
13
13
|
|
|
14
|
-
Single planning path — there is no Epic/Story router, no
|
|
14
|
+
Single planning path — there is no Epic/Story router, no split-triage
|
|
15
15
|
`epic|story` verdict (Gate #3's container groups, never routes). **Derive the
|
|
16
16
|
mode from what the operator typed, announce it, act**:
|
|
17
17
|
|
|
@@ -47,14 +47,14 @@ checkpoints, not sibling tickets ([ref](helpers/plan-reference.md)).
|
|
|
47
47
|
### 1. Interrogate
|
|
48
48
|
|
|
49
49
|
```bash
|
|
50
|
-
node .agents/scripts/plan-context.js --seed "<seed>"
|
|
51
|
-
--out temp/plan-<slug>/plan-context.json
|
|
50
|
+
node .agents/scripts/plan-context.js --seed "<seed>"
|
|
52
51
|
# or: --seed-file <path> | --tickets 123,456 | --amends #<id>
|
|
53
52
|
```
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
and
|
|
57
|
-
|
|
54
|
+
It writes the envelope and **`stories.template.json`** (step 2's skeleton) to
|
|
55
|
+
`<tempRoot>/plan-<slug>/` and prints a digest naming both; `--out` overrides
|
|
56
|
+
the path. Persist auto-discovers the envelope from `--plan-dir` and derives
|
|
57
|
+
source ids from its `sourceTickets[]`.
|
|
58
58
|
|
|
59
59
|
The envelope carries docs context, the story-author prompt (`systemPrompts.story`,
|
|
60
60
|
plus `systemPrompts.storySplitRules` for an N>1 draft and
|
|
@@ -87,18 +87,18 @@ persist parses either, serializes canonical markdown and syncs top-level
|
|
|
87
87
|
`acceptance[]` / `verify[]` in — never dual-author them.
|
|
88
88
|
|
|
89
89
|
**Grounding = your reads + Phase 8.** Nothing inventories the repo: read each
|
|
90
|
-
file you cite
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
file you cite. A `changes[]` entry is a **bare path** by default — persist
|
|
91
|
+
derives its assumption by probing the base branch and reports the derivation;
|
|
92
|
+
pin `{path, assumption}` only when the probe would get it wrong, and always
|
|
93
|
+
for a `deletes`, which is the one shape still refused on an absent path.
|
|
94
|
+
Fields: [ref](helpers/plan-reference.md).
|
|
94
95
|
|
|
95
96
|
Artifacts under `temp/plan-<slug>/`: `stories.json` (**length 1 by default**;
|
|
96
|
-
a Spec is as long as the work needs, inline, never under `docs/`)
|
|
97
|
-
`techspec.md` (**N===1 only**, folded into `## Spec`)
|
|
98
|
-
`acceptance-manifest.json` (N>1 — `--plan-acceptance`). Use the envelope
|
|
97
|
+
a Spec is as long as the work needs, inline, never under `docs/`) and optional
|
|
98
|
+
`techspec.md` (**N===1 only**, folded into `## Spec`). Use the envelope
|
|
99
99
|
`systemPrompts.story`; split only under the policy above, and when you do,
|
|
100
|
-
read `systemPrompts.storySplitRules` too — it carries the schedule and
|
|
101
|
-
|
|
100
|
+
read `systemPrompts.storySplitRules` too — it carries the schedule rules and
|
|
101
|
+
the same-wave collision refusal the core omits. In **tickets mode** also read
|
|
102
102
|
`systemPrompts.storyTicketsRules`: the source ticket is evidence, not a
|
|
103
103
|
template — re-derive `acceptance[]` rather than carrying its list, handles
|
|
104
104
|
and tier suffixes forward.
|
|
@@ -112,32 +112,36 @@ The maker-blind **pre-mortem** critic is not a step of this spine: run
|
|
|
112
112
|
|
|
113
113
|
### 3. Persist
|
|
114
114
|
|
|
115
|
-
**Gate #2** — STOP for approval before persist
|
|
116
|
-
|
|
115
|
+
**Gate #2** — STOP for approval before persist when the draft carries **more
|
|
116
|
+
than one Story** (a split always earns operator eyes, `--force-review` or
|
|
117
|
+
not), or when the operator asked to review (`--force-review`).
|
|
118
|
+
Under `--yes`, auto-proceed.
|
|
117
119
|
|
|
118
120
|
**Gate #3 — adopt, else create.** Offer the top `epicCandidates[]` Epic at
|
|
119
121
|
**any N** (`--epic <id>`); else, at **N>2**, a new container (`--epic-title` /
|
|
120
122
|
`--epic-goal`). Never unasked ([ref](helpers/plan-reference.md)).
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
them; they never stop the persist:
|
|
124
|
+
**One command.** Persist runs every gate write-free first — including the
|
|
125
|
+
**same-wave collision refusal**, which rejects an N>1 draft whose siblings
|
|
126
|
+
declare a common path (merge them, or order them with `depends_on`) — and,
|
|
127
|
+
when the gate list comes back clean, creates the issues in the same
|
|
128
|
+
invocation:
|
|
128
129
|
|
|
129
130
|
```bash
|
|
130
131
|
node .agents/scripts/plan-persist.js \
|
|
131
132
|
--stories temp/plan-<slug>/stories.json \
|
|
132
133
|
--plan-dir temp/plan-<slug> \
|
|
133
|
-
[--plan-acceptance temp/plan-<slug>/acceptance-manifest.json] \
|
|
134
134
|
[--tech-spec temp/plan-<slug>/techspec.md] \
|
|
135
135
|
[--source-tickets 123,456] \
|
|
136
136
|
[--epic <id> | --epic-title "<name>" --epic-goal "<one paragraph>"]
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
The run **lists its warnings** (a `creates` / `refactors-existing` the base
|
|
140
|
+
branch disagrees with, a goal or acceptance path absent at base, an empty
|
|
141
|
+
`verify[]`, a source id assigned to the primary Story by default, an open
|
|
142
|
+
question in a body) and the `changes[]` repairs it applied
|
|
143
|
+
([list](helpers/plan-reference.md)). Read them; they never stop the persist.
|
|
144
|
+
Add `--dry-run` to validate without creating anything.
|
|
141
145
|
|
|
142
146
|
Persist creates `type::story` issue(s), a **metadata-only** `plan-run::<id>`
|
|
143
147
|
label, `blocked by #<id>` footers for every `depends_on` edge, and on a Gate #3
|
|
@@ -152,12 +156,10 @@ also comments on and closes each source id ([ref](helpers/plan-reference.md)).
|
|
|
152
156
|
- Duplicate search targets open Stories (`type::story`), not Epics; and
|
|
153
157
|
deterministic gates still fail closed under `--yes`.
|
|
154
158
|
- A container Epic is never a work item and only an **open** one is adoptable;
|
|
155
|
-
|
|
159
|
+
linkage is parent→child only.
|
|
156
160
|
- `depends_on` takes a sibling slug or `#<id>` (open Story).
|
|
157
161
|
|
|
158
162
|
## See also
|
|
159
163
|
|
|
160
164
|
[`/mandrel-deliver`](mandrel-deliver.md), [`/audit-to-stories`](audit-to-stories.md),
|
|
161
|
-
[`helpers/plan-reference.md`](helpers/plan-reference.md) (on-demand detail)
|
|
162
|
-
[`core/scope-triage`](../skills/core/scope-triage/SKILL.md) — optional
|
|
163
|
-
split-advisory notes only (no routing verdict).
|
|
165
|
+
[`helpers/plan-reference.md`](helpers/plan-reference.md) (on-demand detail).
|
|
@@ -7,7 +7,7 @@ description: >-
|
|
|
7
7
|
leaves unowned: reconcile `.agentrc.json`, install the stabilized
|
|
8
8
|
quality-gate surface, refresh the harness permission allowlist, reconcile
|
|
9
9
|
the consumer's `AGENTS.md` / runbooks against the surfaced changelog, and
|
|
10
|
-
stage + commit the
|
|
10
|
+
stage + commit the dependency bump the CLI's closing report describes.
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# /mandrel-update
|
|
@@ -19,14 +19,15 @@ description: >-
|
|
|
19
19
|
> **distribution-agnostic judgment steps** the CLI deliberately does **not**
|
|
20
20
|
> perform — config reconciliation, the quality-gate installs, the
|
|
21
21
|
> permission-allowlist refresh, the consumer-side changelog reconciliation,
|
|
22
|
-
> and the stage-and-commit of the
|
|
22
|
+
> and the stage-and-commit of the dependency bump.
|
|
23
23
|
|
|
24
24
|
The upgrade contract, in brief: the version only moves on explicit
|
|
25
25
|
invocation (no `postinstall` drift — teammates track the committed
|
|
26
26
|
lockfile pin, and CI's `npm ci` honours it); majors apply like any other
|
|
27
27
|
bump (Mandrel ships hard cutovers — the surfaced changelog is the
|
|
28
|
-
migration guide); the CLI **never
|
|
29
|
-
|
|
28
|
+
migration guide); the CLI **never mutates git** — it reads the index and
|
|
29
|
+
**reports** whether the bump is staged, so the operator follows that
|
|
30
|
+
report rather than an assumption; and the only authoritative writer of the
|
|
30
31
|
generated `.claude/commands/` tree is
|
|
31
32
|
[`sync-claude-commands.js`](../scripts/sync-claude-commands.js), invoked by
|
|
32
33
|
the CLI's sync step.
|
|
@@ -80,22 +81,32 @@ npx mandrel update
|
|
|
80
81
|
The dry run resolves the newest published version and prints the ordered
|
|
81
82
|
step plan (`npm-update → runSync → runMigrations → doctor → surface
|
|
82
83
|
changelog`) without touching anything — read the planned target version
|
|
83
|
-
before applying. The live run drives those phases in order,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
before applying. The live run drives those phases in order, never commits,
|
|
85
|
+
and finishes by printing the `docs/CHANGELOG.md` sections covering the
|
|
86
|
+
applied range `(current, target]`. **Capture that changelog output** —
|
|
87
|
+
Step 4 reconciles the consumer's own instructions against it.
|
|
88
|
+
Already-newest is a clean no-op (`Already up to date`, exit 0).
|
|
89
|
+
|
|
90
|
+
**Read the closing line — it reports the real index state.** Staging is
|
|
91
|
+
package-manager-specific (`npm install` may stage; `pnpm add` / `yarn add`
|
|
92
|
+
stage nothing), so the CLI probes git read-only and tells you which of three
|
|
93
|
+
states you are in rather than asserting one:
|
|
94
|
+
|
|
95
|
+
| Closing line | What it means | What you do |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| `The dependency bump is staged for review (package.json, <lockfile>).` | The index already carries both. | Go to Step 2. |
|
|
98
|
+
| `The dependency bump is NOT staged. … Review and stage it: git add …` | Nothing (or only half) is staged. | Run the exact `git add` the line prints — it names `.agents/` too when this consumer tracks the materialized tree. |
|
|
99
|
+
| `Review the working tree and commit the bump (git not available to report staging state).` | The probe could not read git; the update still succeeded (exit 0). | Inspect `git status` yourself before Step 5. |
|
|
89
100
|
|
|
90
101
|
## Step 2.5 — Partial-upgrade recovery (**blocker — resolve before Step 5**)
|
|
91
102
|
|
|
92
|
-
The install phase
|
|
103
|
+
The install phase writes the dependency bump *before* the later phases run,
|
|
93
104
|
and by deliberate design the CLI **never rolls back the install on
|
|
94
105
|
failure**. So when a post-install phase (`sync` / `sync-commands` /
|
|
95
106
|
`migrate` / `doctor`) exits non-zero you land in a **partially-upgraded
|
|
96
|
-
state**: the bump is already
|
|
97
|
-
half-materialized, the command tree out of sync, or a
|
|
98
|
-
applied — and the operator is one `git commit` away from recording a broken
|
|
107
|
+
state**: the bump is already on disk (and possibly in the index) while
|
|
108
|
+
`.agents/` may be half-materialized, the command tree out of sync, or a
|
|
109
|
+
migration partially applied — and the operator is one `git commit` away from recording a broken
|
|
99
110
|
half-upgrade as "done". **Treat any post-install phase failure as an
|
|
100
111
|
explicit blocker: do not proceed to Step 5 until the failed phase is
|
|
101
112
|
recovered and a clean re-run reports success.**
|
|
@@ -203,22 +214,25 @@ between the installed and target versions:
|
|
|
203
214
|
workflows for renamed flags / changed exit codes / removed scripts.
|
|
204
215
|
|
|
205
216
|
Do not invent updates — silence is a valid review outcome. Stage every
|
|
206
|
-
consumer-side edit alongside the
|
|
207
|
-
|
|
217
|
+
consumer-side edit alongside the dependency bump so the upgrade and the
|
|
218
|
+
reconciliation land in one reviewable commit.
|
|
208
219
|
|
|
209
220
|
## Step 5 — Commit the bump
|
|
210
221
|
|
|
211
|
-
> **Blocker check before you commit.** The
|
|
222
|
+
> **Blocker check before you commit.** The dependency bump is only safe
|
|
212
223
|
> to commit once every post-install phase has gone green. If `npx mandrel
|
|
213
224
|
> update` exited non-zero, resolve it via
|
|
214
225
|
> [Step 2.5 — Partial-upgrade recovery](#step-25--partial-upgrade-recovery-blocker--resolve-before-step-5)
|
|
215
226
|
> **before** the `git commit` below. Committing over a half-upgrade records
|
|
216
227
|
> a broken state as "done".
|
|
217
228
|
|
|
218
|
-
Stage and commit the bump plus everything the wraparound touched
|
|
229
|
+
Stage and commit the bump plus everything the wraparound touched. Start from
|
|
230
|
+
the `git add` the CLI's closing report printed (it names the detected
|
|
231
|
+
lockfile, and `.agents/` when this consumer tracks it), then add the
|
|
232
|
+
wraparound paths:
|
|
219
233
|
|
|
220
234
|
```bash
|
|
221
|
-
git add package.json package-lock.json .agentrc.json .claude/settings.json AGENTS.md # plus any runbook files touched in Step 4
|
|
235
|
+
git add package.json package-lock.json .agentrc.json .claude/settings.json AGENTS.md # lockfile per the CLI report; plus any runbook files touched in Step 4
|
|
222
236
|
git commit -m "chore: update mandrel to v<NEW_VERSION>
|
|
223
237
|
|
|
224
238
|
Upgraded v<OLD_VERSION> → v<NEW_VERSION> via mandrel update.
|
|
@@ -239,8 +253,9 @@ materialized tree.
|
|
|
239
253
|
|
|
240
254
|
- **Idempotent.** A second `mandrel update` after a successful run hits the
|
|
241
255
|
no-op short-circuit — exit 0, nothing bumped.
|
|
242
|
-
- **No auto-commit.** The CLI
|
|
243
|
-
|
|
256
|
+
- **No auto-commit.** The CLI never stages and never commits — it reads git
|
|
257
|
+
only to report whether the bump is staged; the operator writes the commit
|
|
258
|
+
(Step 5).
|
|
244
259
|
- **No framework-side version bump.** This workflow advances the
|
|
245
260
|
*consumer's* pinned version; framework releases remain the maintainer's
|
|
246
261
|
call via release-please.
|
package/README.md
CHANGED
|
@@ -86,9 +86,9 @@ time to confirm the install is healthy.
|
|
|
86
86
|
>
|
|
87
87
|
> Prefer a surgical alternative? Replace `shamefully-hoist` with a scoped
|
|
88
88
|
> `public-hoist-pattern[]=` line per package listed in
|
|
89
|
-
> `.agents/runtime-deps.json`
|
|
90
|
-
>
|
|
91
|
-
> reports `runtime-deps missing: …`, this is the fix.
|
|
89
|
+
> `.agents/runtime-deps.json` — read the file rather than copying a list from
|
|
90
|
+
> here, since the complexity kernel's closure is several packages. If
|
|
91
|
+
> `mandrel doctor` reports `runtime-deps missing: …`, this is the fix.
|
|
92
92
|
|
|
93
93
|
`bootstrap.js` is interactive on a TTY and auto-accepts the
|
|
94
94
|
owner/repo/base branch/operator handle it can infer from your local
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,49 @@ All notable changes to this project will be documented in this file.
|
|
|
15
15
|
-->
|
|
16
16
|
<!-- markdownlint-disable-file MD004 MD012 MD037 -->
|
|
17
17
|
|
|
18
|
+
## [2.60.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.59.0...mandrel-v2.60.0) (2026-09-18)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### ⚠ BREAKING CHANGES
|
|
22
|
+
|
|
23
|
+
* `delivery.feedbackLoop.auditResultsAutoFile` is no longer a valid `.agentrc.json` key. `mandrel update` strips it automatically.
|
|
24
|
+
* deliver-light.js no longer accepts --kinds, --magnitude, --uncertainty or --route; STORY_SHAPE_CEILINGS and the four ceiling SHAPE_CODES are removed, and no gate envelope carries warnings[].
|
|
25
|
+
* under delivery.routing.ceremonyProfile standard the acceptance verdict is authored inline; set strict to keep a fresh-context critic.
|
|
26
|
+
* plan-persist.js persists on a clean dry-run by default — pass --dry-run to validate only; the "Commit subject begins with '<prefix>:'" acceptance validator is removed; an empty verify[] is a warning, not a refusal.
|
|
27
|
+
* delivery.feedbackLoop.retroProposals and delivery.feedbackLoop.auditResultsAutoFile now default to false; a consumer that relied on auto-filed follow-up issues sets both to true in .agentrc.json.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
* add deliver-run.js so a multi-Story run is one script beat plus spawns and closes, not a hand-driven protocol ([#5345](https://github.com/dsj1984/mandrel/issues/5345)) ([#5354](https://github.com/dsj1984/mandrel/issues/5354)) ([591dad7](https://github.com/dsj1984/mandrel/commit/591dad75923133bef9e3a9d095ac47442464943b))
|
|
32
|
+
* clamp deliver-runner concurrency to one when worktree isolation resolves off, so two workers can never share a checkout ([#5357](https://github.com/dsj1984/mandrel/issues/5357)) ([#5360](https://github.com/dsj1984/mandrel/issues/5360)) ([1f3f651](https://github.com/dsj1984/mandrel/commit/1f3f6515e4a7a4fd2c730001dc6dd4cdb44f251e))
|
|
33
|
+
* close fails fast with a named blocker when GitHub GraphQL is unavailable, instead of a raw 403 after the full gate chain ([#5355](https://github.com/dsj1984/mandrel/issues/5355)) ([#5359](https://github.com/dsj1984/mandrel/issues/5359)) ([b46c263](https://github.com/dsj1984/mandrel/commit/b46c26329dd7cc1e968e607ccaae9d51a9f1ef84))
|
|
34
|
+
* collapse the ceremony decision to what it decides and delete the inert layer around it ([#5366](https://github.com/dsj1984/mandrel/issues/5366)) ([#5375](https://github.com/dsj1984/mandrel/issues/5375)) ([54d0ece](https://github.com/dsj1984/mandrel/commit/54d0ece864d8cb3ec824228dc097999781f7b29f))
|
|
35
|
+
* collapse the light path to one gate and let an escalation continue in-session ([#5344](https://github.com/dsj1984/mandrel/issues/5344)) ([#5353](https://github.com/dsj1984/mandrel/issues/5353)) ([c09acd6](https://github.com/dsj1984/mandrel/commit/c09acd69a8525dd33073922a7541bb9488929249))
|
|
36
|
+
* cut the restated delivery rules, the v1 refusals and the sibling-coherence step, and turn auto-filing off by default ([#5341](https://github.com/dsj1984/mandrel/issues/5341)) ([#5350](https://github.com/dsj1984/mandrel/issues/5350)) ([349d346](https://github.com/dsj1984/mandrel/commit/349d3468c11a23504b510ac80d0716b5dd709853))
|
|
37
|
+
* delivery ceremony diet: one inline verdict per Story, opt-in fresh critics and audit roster, fewer Story comments, and one CI rerun after a recorded verdict ([#5343](https://github.com/dsj1984/mandrel/issues/5343)) ([#5352](https://github.com/dsj1984/mandrel/issues/5352)) ([1ac35c4](https://github.com/dsj1984/mandrel/commit/1ac35c40745bd1d6f0945f9a5ffd3f975452dbff))
|
|
38
|
+
* loosen plan authoring: one persist command, bare paths in changes[], empty verify[] as a warning, and the fossil validators removed ([#5342](https://github.com/dsj1984/mandrel/issues/5342)) ([#5351](https://github.com/dsj1984/mandrel/issues/5351)) ([c7534a5](https://github.com/dsj1984/mandrel/commit/c7534a523cf39b24324d26f2cad81b2ec4fb22df))
|
|
39
|
+
* make a dispatch that never reached init visible in the beat envelope ([#5363](https://github.com/dsj1984/mandrel/issues/5363)) ([#5370](https://github.com/dsj1984/mandrel/issues/5370)) ([ab3c755](https://github.com/dsj1984/mandrel/commit/ab3c7553975ef5dce8c60112d7f8c278c5dd0d8d))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
* `mandrel update` reports whether the bump is actually staged instead of asserting it ([#5339](https://github.com/dsj1984/mandrel/issues/5339)) ([#5349](https://github.com/dsj1984/mandrel/issues/5349)) ([07f63c7](https://github.com/dsj1984/mandrel/commit/07f63c79bdb19a532e82d413de719a194c170504))
|
|
45
|
+
* anchor pre-push coverage capture and the CRAP preview on one resolved ref ([#5365](https://github.com/dsj1984/mandrel/issues/5365)) ([#5373](https://github.com/dsj1984/mandrel/issues/5373)) ([cb189e3](https://github.com/dsj1984/mandrel/commit/cb189e3a005749305cc0ce2075ea17793493bb0e))
|
|
46
|
+
* capture coverage before the pre-push quality preview (refs [#5356](https://github.com/dsj1984/mandrel/issues/5356)) ([#5358](https://github.com/dsj1984/mandrel/issues/5358)) ([14ef1dd](https://github.com/dsj1984/mandrel/commit/14ef1dde384455f16f3ddd502881c132fd6ae056))
|
|
47
|
+
* close the three correctness holes the plan-authoring loosening left in persist ([#5361](https://github.com/dsj1984/mandrel/issues/5361)) ([#5372](https://github.com/dsj1984/mandrel/issues/5372)) ([aef03bd](https://github.com/dsj1984/mandrel/commit/aef03bd90e14cc2dac68ea4d7a04f0f262e2494e))
|
|
48
|
+
* delete the write-only plan checkpoint payload and the three unreachable modules ([#5367](https://github.com/dsj1984/mandrel/issues/5367)) ([#5374](https://github.com/dsj1984/mandrel/issues/5374)) ([4c0c835](https://github.com/dsj1984/mandrel/commit/4c0c835d9eded8e993bb7ebd3e66e86bec4d2377))
|
|
49
|
+
* demote the workflow prose ratchets to reports and delete the reference sections that describe retired mechanisms ([#5340](https://github.com/dsj1984/mandrel/issues/5340)) ([#5347](https://github.com/dsj1984/mandrel/issues/5347)) ([8d76329](https://github.com/dsj1984/mandrel/commit/8d76329e3aacc726e39d1839f01e618fb7361662))
|
|
50
|
+
* report the index mandrel update actually observes, from one read ([#5364](https://github.com/dsj1984/mandrel/issues/5364)) ([#5371](https://github.com/dsj1984/mandrel/issues/5371)) ([12af953](https://github.com/dsj1984/mandrel/commit/12af95383f7ddbfe137715aa10bce3b25a7b95a3))
|
|
51
|
+
* treat a rate-limited GraphQL probe as fail-open rather than unreachable (refs [#5362](https://github.com/dsj1984/mandrel/issues/5362)) ([#5369](https://github.com/dsj1984/mandrel/issues/5369)) ([db6a9e0](https://github.com/dsj1984/mandrel/commit/db6a9e08441baf40281962e0b226575f9c7b1846))
|
|
52
|
+
|
|
53
|
+
## [2.59.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.58.0...mandrel-v2.59.0) (2026-09-14)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
* planning stops fragmenting cohesive work: the acceptance band goes, the dispatcher's own collision predicate becomes the split gate, and the audit seed stops pre-cutting the partition ([#5332](https://github.com/dsj1984/mandrel/issues/5332)) ([#5334](https://github.com/dsj1984/mandrel/issues/5334)) ([e6408e4](https://github.com/dsj1984/mandrel/commit/e6408e44d3f9a7fcbdf8c9a7df4a1b68fdffd88b))
|
|
59
|
+
* replace the complexity kernel's parse and dispatch layers and declare the runtime closure it leaves behind, so the framework's dependency guards describe what actually loads ([#5336](https://github.com/dsj1984/mandrel/issues/5336)) ([#5337](https://github.com/dsj1984/mandrel/issues/5337)) ([821c4f5](https://github.com/dsj1984/mandrel/commit/821c4f55fe3fe9b91b83a4ef9fe9ddee5da9db8f))
|
|
60
|
+
|
|
18
61
|
## [2.58.0](https://github.com/dsj1984/mandrel/compare/mandrel-v2.57.0...mandrel-v2.58.0) (2026-09-12)
|
|
19
62
|
|
|
20
63
|
|
package/lib/cli/registry.js
CHANGED
|
@@ -41,6 +41,8 @@ import {
|
|
|
41
41
|
} from '../../.agents/scripts/lib/bootstrap/project-bootstrap.js';
|
|
42
42
|
import { isCommandExcluded } from '../../.agents/scripts/lib/command-header.js';
|
|
43
43
|
import { getDeliveryRouting } from '../../.agents/scripts/lib/config/delivery-routing.js';
|
|
44
|
+
import { isResolvable } from '../../.agents/scripts/lib/runtime-deps/dep-resolution.js';
|
|
45
|
+
import { describeParserMajorError } from '../../.agents/scripts/lib/runtime-deps/parser-major.js';
|
|
44
46
|
import {
|
|
45
47
|
defaultResolvePackageRoot,
|
|
46
48
|
listFiles as listPayloadFiles,
|
|
@@ -519,6 +521,30 @@ function runAgentsInSync({
|
|
|
519
521
|
// check: runtime-deps
|
|
520
522
|
// ---------------------------------------------------------------------------
|
|
521
523
|
|
|
524
|
+
/**
|
|
525
|
+
* The verdict when every required package is present.
|
|
526
|
+
*
|
|
527
|
+
* Presence is not the whole contract: `.agents/` resolves from the consumer's
|
|
528
|
+
* node_modules, so a declared range cannot enforce which `@babel/parser` major
|
|
529
|
+
* the complexity kernel actually gets, and the wrong major fails scoring
|
|
530
|
+
* mid-scan with an opaque plugin-list error. Reporting it here puts it where a
|
|
531
|
+
* consumer is already looking for what to fix.
|
|
532
|
+
*
|
|
533
|
+
* @param {() => string|null} parserMajorError
|
|
534
|
+
* @returns {{ ok: boolean, detail: string, remedy?: string }}
|
|
535
|
+
*/
|
|
536
|
+
function allPresentVerdict(parserMajorError) {
|
|
537
|
+
const parserProblem = parserMajorError();
|
|
538
|
+
if (parserProblem === null) {
|
|
539
|
+
return { ok: true, detail: 'all dependencies found' };
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
ok: false,
|
|
543
|
+
detail: 'dependency version unsupported',
|
|
544
|
+
remedy: parserProblem,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
522
548
|
/**
|
|
523
549
|
* Verify that the framework's required runtime dependencies are resolvable
|
|
524
550
|
* from the project's node_modules.
|
|
@@ -536,6 +562,8 @@ function runAgentsInSync({
|
|
|
536
562
|
* is missing.
|
|
537
563
|
* - `manifestRequired` — array of required package names, skips the
|
|
538
564
|
* filesystem read of `runtime-deps.json`.
|
|
565
|
+
* - `parserMajorError()` — replaces the resolved-parser-major probe, so the
|
|
566
|
+
* unsupported-major report is assertable without installing one.
|
|
539
567
|
*
|
|
540
568
|
* @param {{ projectRoot?: string, resolve?: (dep: string) => string, manifestRequired?: string[] }} [opts]
|
|
541
569
|
* @returns {{ ok: boolean, detail: string, remedy?: string }}
|
|
@@ -544,6 +572,7 @@ function runRuntimeDeps({
|
|
|
544
572
|
projectRoot,
|
|
545
573
|
resolve: resolveSeam,
|
|
546
574
|
manifestRequired,
|
|
575
|
+
parserMajorError = describeParserMajorError,
|
|
547
576
|
} = {}) {
|
|
548
577
|
// Anchor at process.cwd() (the consumer root), not resolveProjectRoot() (the
|
|
549
578
|
// package root). Under pnpm isolated-mode the consumer's node_modules are not
|
|
@@ -569,33 +598,24 @@ function runRuntimeDeps({
|
|
|
569
598
|
|
|
570
599
|
const missing = [];
|
|
571
600
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
for (const dep of required) {
|
|
588
|
-
try {
|
|
589
|
-
req.resolve(dep);
|
|
590
|
-
} catch {
|
|
591
|
-
missing.push(dep);
|
|
592
|
-
}
|
|
593
|
-
}
|
|
601
|
+
// Anchor resolution to the consumer project root so it mirrors the context
|
|
602
|
+
// in which the framework scripts run (they free-ride on the consumer's
|
|
603
|
+
// node_modules). Under pnpm isolated-mode the consumer's node_modules are
|
|
604
|
+
// not reachable from inside node_modules/mandrel/; anchoring at process.cwd()
|
|
605
|
+
// finds them correctly.
|
|
606
|
+
//
|
|
607
|
+
// `isResolvable` is shared with the framework-side preflight rather than
|
|
608
|
+
// reimplemented here: it probes the bare specifier AND `<name>/package.json`,
|
|
609
|
+
// because a dependency with no `main` and no `exports` cannot be resolved by
|
|
610
|
+
// name at all. Probing only the bare name reports such a package missing
|
|
611
|
+
// while it sits installed, and this check gates `mandrel doctor`.
|
|
612
|
+
const resolve =
|
|
613
|
+
resolveSeam ?? createRequire(path.join(root, 'package.json')).resolve;
|
|
614
|
+
for (const dep of required) {
|
|
615
|
+
if (!isResolvable(dep, resolve)) missing.push(dep);
|
|
594
616
|
}
|
|
595
617
|
|
|
596
|
-
if (missing.length === 0)
|
|
597
|
-
return { ok: true, detail: 'all dependencies found' };
|
|
598
|
-
}
|
|
618
|
+
if (missing.length === 0) return allPresentVerdict(parserMajorError);
|
|
599
619
|
return {
|
|
600
620
|
ok: false,
|
|
601
621
|
detail: `missing: ${missing.join(', ')}`,
|