mandrel 2.63.0 → 2.65.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/agents/acceptance-critic.md +3 -2
- package/.agents/agents/auditor.md +3 -2
- package/.agents/agents/plan-critic.md +3 -2
- package/.agents/agents/story-worker.md +2 -2
- package/.agents/audit-checklists/quality.md +3 -0
- package/.agents/docs/agentrc-reference.json +1 -9
- package/.agents/docs/configuration.md +8 -7
- package/.agents/schemas/agentrc.schema.json +6 -13
- package/.agents/schemas/audit-rules.schema.json +1 -1
- package/.agents/schemas/story-deliver-terminal.schema.json +5 -0
- package/.agents/scripts/bootstrap.js +8 -2
- package/.agents/scripts/check-context-budget.js +1 -1
- package/.agents/scripts/lib/ITicketingProvider.js +1 -3
- package/.agents/scripts/lib/audit-suite/findings.js +1 -17
- package/.agents/scripts/lib/audit-suite/frontmatter.js +0 -28
- package/.agents/scripts/lib/audit-suite/index.js +0 -6
- package/.agents/scripts/lib/audit-suite/selector.js +0 -31
- package/.agents/scripts/lib/bootstrap/agents-md-fold.js +156 -0
- package/.agents/scripts/lib/bootstrap/commit-push.js +1 -1
- package/.agents/scripts/lib/bootstrap/manifest.js +2 -2
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +13 -29
- package/.agents/scripts/lib/config/review-chain-default.js +13 -0
- package/.agents/scripts/lib/config-settings-schema-delivery.js +2 -2
- package/.agents/scripts/lib/config-settings-schema-quality.js +11 -13
- package/.agents/scripts/lib/doc-tiers.js +25 -6
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/observability/metrics-ledger.js +0 -72
- package/.agents/scripts/lib/orchestration/ci-red-handling.js +73 -0
- package/.agents/scripts/lib/orchestration/code-review.js +11 -6
- package/.agents/scripts/lib/orchestration/deliver-recover.js +56 -11
- package/.agents/scripts/lib/orchestration/epic-rollup.js +29 -12
- package/.agents/scripts/lib/orchestration/merge-block-class.js +20 -4
- package/.agents/scripts/lib/orchestration/merge-poll.js +41 -22
- package/.agents/scripts/lib/orchestration/required-checks.js +147 -0
- package/.agents/scripts/lib/orchestration/review-providers/code-review.js +203 -0
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +6 -4
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +3 -2
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +1 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +0 -12
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +135 -20
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +112 -82
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +72 -5
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +12 -87
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +3 -0
- package/.agents/scripts/lib/templates/decomposer-prompts.js +5 -24
- package/.agents/scripts/pr-watch-with-update.js +13 -19
- package/.agents/scripts/providers/github/issues.js +14 -23
- package/.agents/scripts/sync-claude-agents.js +1 -1
- package/.agents/workflows/audit-quality.md +42 -7
- package/.agents/workflows/helpers/acceptance-self-eval.md +1 -1
- package/.agents/workflows/helpers/code-review.md +15 -38
- package/.agents/workflows/helpers/deliver-reference.md +4 -2
- package/.agents/workflows/helpers/deliver-story.md +3 -0
- package/.agents/workflows/helpers/plan-reference.md +9 -8
- package/.agents/workflows/mandrel-deliver.md +2 -1
- package/.agents/workflows/mandrel-plan.md +10 -7
- package/.agents/workflows/mandrel-update.md +5 -3
- package/docs/CHANGELOG.md +38 -0
- package/lib/cli/claude-code-version.js +73 -0
- package/lib/cli/doctor.js +2 -2
- package/lib/cli/registry.js +9 -0
- package/lib/cli/uninstall.js +37 -9
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.65.0-fold-claude-md-into-agents-md.js +38 -0
- package/package.json +2 -1
- package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +0 -99
- package/.agents/scripts/lib/audit-suite/runner.js +0 -205
- package/.agents/scripts/lib/audit-suite/substitutions.js +0 -96
- package/.agents/scripts/lib/audit-suite/workflow-loader.js +0 -37
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +0 -234
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* phases/local-lens-review.js — the Story-scope local-lens pass: selects the
|
|
3
|
-
* local lenses matching the Story diff and materializes their prompts. The
|
|
4
|
-
* review spine (`runStoryReviewCore`) owns diff enumeration and code review.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
evaluateLensDiffFloor,
|
|
9
|
-
runAuditSuite,
|
|
10
|
-
selectLocalLenses,
|
|
11
|
-
} from '../../../audit-suite/index.js';
|
|
12
|
-
import { gitSpawn } from '../../../git-utils.js';
|
|
13
|
-
import {
|
|
14
|
-
emitRuntimeFriction,
|
|
15
|
-
RUNTIME_FRICTION_CATEGORIES,
|
|
16
|
-
} from '../../../observability/runtime-friction.js';
|
|
17
|
-
import { computeChangeSet } from '../../change-set.js';
|
|
18
|
-
|
|
19
|
-
/** Fixed for this tier; not risk-scaled. */
|
|
20
|
-
const STORY_SCOPE_LENS_DEPTH = 'light';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Roster of materialized lens-prompt artifacts the host MUST walk — the
|
|
24
|
-
* default review provider never reads them, so without this they are inert.
|
|
25
|
-
*
|
|
26
|
-
* @param {object|null} materialized the `runAuditSuite` result envelope.
|
|
27
|
-
* @returns {string|null} the roster block, or `null` when there is nothing to walk.
|
|
28
|
-
*/
|
|
29
|
-
function renderLensArtifactRoster(materialized) {
|
|
30
|
-
const paths = (materialized?.workflows ?? [])
|
|
31
|
-
.map((w) => w?.artifactPath)
|
|
32
|
-
.filter((p) => typeof p === 'string' && p.length > 0);
|
|
33
|
-
if (paths.length === 0) return null;
|
|
34
|
-
return [
|
|
35
|
-
`Lens prompts materialized (host MUST read/walk each against the Story diff):`,
|
|
36
|
-
...paths.map((p) => ` - ${p}`),
|
|
37
|
-
].join('\n');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Built-in substitution keys, so no per-lens declaration is needed.
|
|
42
|
-
*
|
|
43
|
-
* @param {{ changedFiles: string[], storyId?: number|string|null }} args
|
|
44
|
-
* @returns {Record<string, string>}
|
|
45
|
-
*/
|
|
46
|
-
function buildLensSubstitutions({ changedFiles, storyId }) {
|
|
47
|
-
const substitutions = { changedFiles: changedFiles.join('\n') };
|
|
48
|
-
if (storyId != null && `${storyId}`.length > 0) {
|
|
49
|
-
substitutions.ticketId = String(storyId);
|
|
50
|
-
}
|
|
51
|
-
return substitutions;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Never throws: an unknown diff returns `[]`, which matches no lens, same as
|
|
56
|
-
* an empty one.
|
|
57
|
-
*
|
|
58
|
-
* @param {{
|
|
59
|
-
* baseRef: string,
|
|
60
|
-
* headRef: string,
|
|
61
|
-
* gitSpawnFn?: import('../../change-set.js').GitSpawnFn,
|
|
62
|
-
* }} args
|
|
63
|
-
* @returns {string[]} Changed file paths, or `[]` on any failure.
|
|
64
|
-
*/
|
|
65
|
-
function enumerateChangedFiles({ baseRef, headRef, gitSpawnFn = gitSpawn }) {
|
|
66
|
-
return computeChangeSet({ baseRef, headRef, gitSpawnFn }).files ?? [];
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Three-state injection: an array is used verbatim; `null` means the spine
|
|
71
|
-
* already failed to enumerate, so don't re-spawn git; `undefined` means
|
|
72
|
-
* nobody enumerated, so self-enumerate.
|
|
73
|
-
*
|
|
74
|
-
* @param {{
|
|
75
|
-
* changedFiles: string[]|null|undefined,
|
|
76
|
-
* baseRef: string,
|
|
77
|
-
* headRef: string,
|
|
78
|
-
* gitSpawnFn?: import('../../change-set.js').GitSpawnFn,
|
|
79
|
-
* }} args
|
|
80
|
-
* @returns {string[]}
|
|
81
|
-
*/
|
|
82
|
-
function resolveLensChangeSet({
|
|
83
|
-
changedFiles,
|
|
84
|
-
baseRef,
|
|
85
|
-
headRef,
|
|
86
|
-
gitSpawnFn = gitSpawn,
|
|
87
|
-
}) {
|
|
88
|
-
if (changedFiles === undefined) {
|
|
89
|
-
return enumerateChangedFiles({ baseRef, headRef, gitSpawnFn });
|
|
90
|
-
}
|
|
91
|
-
return changedFiles ?? [];
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Run the maker-blind Story-scope lens pass (called only from
|
|
96
|
-
* `runStoryReviewCore`). No matching lens → no lens work. A diff below the
|
|
97
|
-
* lens diff-floor with no sensitive-path hits records the roster but skips
|
|
98
|
-
* materialization; an unknown line count fails open. Advisory: any failure
|
|
99
|
-
* degrades to a skipped envelope plus a friction signal.
|
|
100
|
-
*
|
|
101
|
-
* @param {{
|
|
102
|
-
* baseRef: string,
|
|
103
|
-
* headRef: string,
|
|
104
|
-
* changedFiles?: string[]|null,
|
|
105
|
-
* changedLineCount?: number|null,
|
|
106
|
-
* lensDiffFloor?: number,
|
|
107
|
-
* storyId?: number|string|null,
|
|
108
|
-
* artifactPrefix?: string,
|
|
109
|
-
* progress: (tag: string, msg: string) => void,
|
|
110
|
-
* progressTag?: string,
|
|
111
|
-
* gitSpawnFn?: import('../../change-set.js').GitSpawnFn,
|
|
112
|
-
* selectLocalLensesFn?: typeof selectLocalLenses,
|
|
113
|
-
* runAuditSuiteFn?: typeof runAuditSuite,
|
|
114
|
-
* evaluateLensDiffFloorFn?: typeof evaluateLensDiffFloor,
|
|
115
|
-
* emitToolDegradationFn?: typeof emitRuntimeFriction,
|
|
116
|
-
* }} args
|
|
117
|
-
* @returns {Promise<{
|
|
118
|
-
* depth: 'light',
|
|
119
|
-
* lenses: string[],
|
|
120
|
-
* skipped: boolean,
|
|
121
|
-
* floorSkip: object|null,
|
|
122
|
-
* materialized: object|null,
|
|
123
|
-
* artifactPaths: string[],
|
|
124
|
-
* }>}
|
|
125
|
-
*/
|
|
126
|
-
export async function runLocalLensReview({
|
|
127
|
-
baseRef,
|
|
128
|
-
headRef,
|
|
129
|
-
changedFiles: injectedChangedFiles,
|
|
130
|
-
changedLineCount = null,
|
|
131
|
-
lensDiffFloor,
|
|
132
|
-
storyId,
|
|
133
|
-
artifactPrefix,
|
|
134
|
-
progress,
|
|
135
|
-
progressTag = 'CODE-REVIEW',
|
|
136
|
-
gitSpawnFn = gitSpawn,
|
|
137
|
-
selectLocalLensesFn = selectLocalLenses,
|
|
138
|
-
runAuditSuiteFn = runAuditSuite,
|
|
139
|
-
evaluateLensDiffFloorFn = evaluateLensDiffFloor,
|
|
140
|
-
emitToolDegradationFn = emitRuntimeFriction,
|
|
141
|
-
}) {
|
|
142
|
-
const empty = {
|
|
143
|
-
depth: STORY_SCOPE_LENS_DEPTH,
|
|
144
|
-
lenses: [],
|
|
145
|
-
skipped: true,
|
|
146
|
-
floorSkip: null,
|
|
147
|
-
materialized: null,
|
|
148
|
-
artifactPaths: [],
|
|
149
|
-
};
|
|
150
|
-
try {
|
|
151
|
-
const changedFiles = resolveLensChangeSet({
|
|
152
|
-
changedFiles: injectedChangedFiles,
|
|
153
|
-
baseRef,
|
|
154
|
-
headRef,
|
|
155
|
-
gitSpawnFn,
|
|
156
|
-
});
|
|
157
|
-
const lenses = selectLocalLensesFn({ changedFiles });
|
|
158
|
-
if (lenses.length === 0) {
|
|
159
|
-
progress(
|
|
160
|
-
progressTag,
|
|
161
|
-
'No local lens matched the Story diff — skipping the lens pass.',
|
|
162
|
-
);
|
|
163
|
-
return empty;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// After selection so a floor-skip still records which lenses it skipped.
|
|
167
|
-
const floorVerdict = evaluateLensDiffFloorFn({
|
|
168
|
-
changedFiles,
|
|
169
|
-
changedLineCount,
|
|
170
|
-
floor: lensDiffFloor,
|
|
171
|
-
});
|
|
172
|
-
if (floorVerdict.skip) {
|
|
173
|
-
progress(
|
|
174
|
-
progressTag,
|
|
175
|
-
`Lens diff-floor: ${floorVerdict.changedLineCount} changed line(s) < ` +
|
|
176
|
-
`floor ${floorVerdict.floor} with zero sensitive-path hits — ` +
|
|
177
|
-
`skipping materialization of ${lenses.join(', ')}.`,
|
|
178
|
-
);
|
|
179
|
-
return {
|
|
180
|
-
depth: STORY_SCOPE_LENS_DEPTH,
|
|
181
|
-
lenses,
|
|
182
|
-
skipped: true,
|
|
183
|
-
floorSkip: floorVerdict,
|
|
184
|
-
materialized: null,
|
|
185
|
-
artifactPaths: [],
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
// Story-scoped names so concurrent closes can't clobber each other.
|
|
189
|
-
const effectivePrefix =
|
|
190
|
-
artifactPrefix ?? (storyId != null ? `story-${storyId}` : 'story-scope');
|
|
191
|
-
const materialized = await runAuditSuiteFn({
|
|
192
|
-
auditWorkflows: lenses,
|
|
193
|
-
substitutions: buildLensSubstitutions({ changedFiles, storyId }),
|
|
194
|
-
artifactPrefix: effectivePrefix,
|
|
195
|
-
});
|
|
196
|
-
progress(
|
|
197
|
-
progressTag,
|
|
198
|
-
`Ran ${lenses.length} local lens(es) at ${STORY_SCOPE_LENS_DEPTH} depth: ${lenses.join(', ')}.`,
|
|
199
|
-
);
|
|
200
|
-
const roster = renderLensArtifactRoster(materialized);
|
|
201
|
-
if (roster) progress(progressTag, roster);
|
|
202
|
-
const artifactPaths = (materialized?.workflows ?? [])
|
|
203
|
-
.map((w) => w?.artifactPath)
|
|
204
|
-
.filter((p) => typeof p === 'string' && p.length > 0);
|
|
205
|
-
return {
|
|
206
|
-
depth: STORY_SCOPE_LENS_DEPTH,
|
|
207
|
-
lenses,
|
|
208
|
-
skipped: false,
|
|
209
|
-
floorSkip: floorVerdict,
|
|
210
|
-
materialized,
|
|
211
|
-
artifactPaths,
|
|
212
|
-
};
|
|
213
|
-
} catch (err) {
|
|
214
|
-
// Degradations are operational signals (friction), not findings.
|
|
215
|
-
progress(
|
|
216
|
-
progressTag,
|
|
217
|
-
`⚠️ local lens pass failed (continuing without it): ${err?.message ?? err}`,
|
|
218
|
-
);
|
|
219
|
-
try {
|
|
220
|
-
await emitToolDegradationFn({
|
|
221
|
-
storyId,
|
|
222
|
-
category: RUNTIME_FRICTION_CATEGORIES.TOOL_DEGRADED,
|
|
223
|
-
tool: 'local-lens-review',
|
|
224
|
-
details: {
|
|
225
|
-
surface: 'lens-materialization',
|
|
226
|
-
reason: String(err?.message ?? err).slice(0, 500),
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
|
-
} catch {
|
|
230
|
-
// Observability must never fail the close.
|
|
231
|
-
}
|
|
232
|
-
return empty;
|
|
233
|
-
}
|
|
234
|
-
}
|