mandrel 2.54.0 → 2.55.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/story-worker.md +24 -23
- package/.agents/audit-checklists/accessibility.md +0 -3
- package/.agents/audit-checklists/mobile.md +0 -4
- package/.agents/docs/agentrc-reference.json +4 -2
- package/.agents/docs/configuration.md +2 -0
- package/.agents/schemas/agentrc.schema.json +15 -1
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +2 -1
- package/.agents/schemas/story-deliver-terminal.schema.json +1 -0
- package/.agents/scripts/audit-to-stories.js +158 -7
- package/.agents/scripts/check-audit-attribution.js +119 -62
- package/.agents/scripts/check-test-portability.js +512 -0
- package/.agents/scripts/coverage-capture.js +17 -10
- package/.agents/scripts/evidence-gate.js +31 -4
- package/.agents/scripts/generate-workflows-doc.js +65 -14
- package/.agents/scripts/git-cleanup.js +4 -0
- package/.agents/scripts/lib/ITicketingProvider.js +78 -0
- package/.agents/scripts/lib/audit-advisories.js +195 -0
- package/.agents/scripts/lib/audit-attribution.js +22 -0
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +68 -5
- package/.agents/scripts/lib/audit-to-stories/issue-index.js +83 -0
- package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +60 -114
- package/.agents/scripts/lib/audit-to-stories/ledger-pr.js +347 -0
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +169 -44
- package/.agents/scripts/lib/baselines/merge-envelopes.js +298 -32
- package/.agents/scripts/lib/bootstrap/baseline-merge-driver.js +180 -14
- package/.agents/scripts/lib/cli-args.js +26 -0
- package/.agents/scripts/lib/close-validation/gates.js +113 -7
- package/.agents/scripts/lib/close-validation/process.js +7 -3
- package/.agents/scripts/lib/close-validation/runner.js +62 -11
- package/.agents/scripts/lib/config/ci.js +28 -9
- package/.agents/scripts/lib/config-settings-schema-delivery.js +7 -0
- package/.agents/scripts/lib/config-settings-schema.js +19 -1
- package/.agents/scripts/lib/coverage-capture-fullscope.js +23 -11
- package/.agents/scripts/lib/coverage-capture-incremental.js +22 -16
- package/.agents/scripts/lib/coverage-capture-usage.js +5 -1
- package/.agents/scripts/lib/coverage-capture.js +77 -3
- package/.agents/scripts/lib/findings/route-finding.js +4 -2
- package/.agents/scripts/lib/full-suite-lock.js +232 -6
- package/.agents/scripts/lib/generated/agentrc-validator.js +1 -1
- package/.agents/scripts/lib/git/sync-from-base.js +130 -13
- package/.agents/scripts/lib/observability/source-classifier.js +1 -0
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +10 -2
- package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +75 -15
- package/.agents/scripts/lib/orchestration/deliver-recover.js +82 -43
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +8 -4
- package/.agents/scripts/lib/orchestration/epic-candidates.js +9 -4
- package/.agents/scripts/lib/orchestration/epic-container.js +66 -4
- package/.agents/scripts/lib/orchestration/epic-rollup.js +233 -84
- package/.agents/scripts/lib/orchestration/file-assumptions.js +218 -16
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +93 -7
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +22 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +26 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +13 -2
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +35 -5
- package/.agents/scripts/lib/orchestration/merge-block-class.js +18 -3
- package/.agents/scripts/lib/orchestration/merge-poll.js +284 -40
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +49 -2
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +43 -7
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +24 -1
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +5 -0
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +3 -0
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +63 -0
- package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +110 -0
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +130 -40
- package/.agents/scripts/lib/orchestration/resolve-stories.js +44 -1
- package/.agents/scripts/lib/orchestration/review-providers/native.js +31 -11
- package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +27 -24
- package/.agents/scripts/lib/orchestration/run-epilogue.js +59 -38
- package/.agents/scripts/lib/orchestration/single-story-close/close-note.js +81 -0
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +40 -51
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +10 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +101 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +351 -28
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +27 -6
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +117 -22
- package/.agents/scripts/lib/orchestration/story-close/baseline-upward-writeback.js +94 -12
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +6 -1
- package/.agents/scripts/lib/orchestration/ticket-validator.js +25 -14
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +30 -0
- package/.agents/scripts/lib/orchestration/verify-credit.js +37 -0
- package/.agents/scripts/lib/pinned-override-notes.js +41 -53
- package/.agents/scripts/lib/pinned-override-resolve.js +212 -0
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +18 -0
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +173 -9
- package/.agents/scripts/lib/skills/walk-skill-files.js +24 -7
- package/.agents/scripts/lib/test-temp.js +167 -30
- package/.agents/scripts/lib/validation-evidence.js +37 -0
- package/.agents/scripts/lib/wave-runner/footprint.js +167 -14
- package/.agents/scripts/lib/wave-runner/live-probe.js +7 -1
- package/.agents/scripts/lib/wave-runner/ready-set.js +1 -1
- package/.agents/scripts/merge-baseline.js +175 -21
- package/.agents/scripts/providers/github/errors.js +22 -1
- package/.agents/scripts/providers/github/issues.js +106 -1
- package/.agents/scripts/providers/github/sub-issue-add.js +18 -1
- package/.agents/scripts/providers/github.js +6 -0
- package/.agents/scripts/resolve-stories.js +44 -34
- package/.agents/scripts/single-story-close.js +5 -0
- package/.agents/scripts/stories-wave-tick.js +37 -13
- package/.agents/templates/docs/audit-sweep-runbook.md +41 -7
- package/.agents/workflows/audit-accessibility.md +16 -31
- package/.agents/workflows/audit-mobile.md +20 -37
- package/.agents/workflows/git-cleanup.md +17 -3
- package/.agents/workflows/helpers/audit-lens-core.md +45 -0
- package/.agents/workflows/helpers/deliver-digest.md +7 -6
- package/.agents/workflows/helpers/deliver-reference.md +35 -14
- package/.agents/workflows/helpers/deliver-story-reference.md +7 -4
- package/.agents/workflows/helpers/deliver-story.md +15 -12
- package/.agents/workflows/helpers/plan-reference.md +7 -0
- package/.agents/workflows/mandrel-plan.md +4 -7
- package/.agents/workflows/memory-consolidate.md +14 -9
- package/docs/CHANGELOG.md +27 -0
- package/lib/cli/registry.js +64 -21
- package/lib/cli/sync.js +27 -2
- package/package.json +7 -4
|
@@ -24,11 +24,14 @@ import process from 'node:process';
|
|
|
24
24
|
|
|
25
25
|
import {
|
|
26
26
|
attributionExitCode,
|
|
27
|
+
auditAdvisories,
|
|
27
28
|
deriveVerdict,
|
|
29
|
+
diffAdvisories,
|
|
30
|
+
renderAdvisoryDetail,
|
|
28
31
|
renderAttribution,
|
|
29
32
|
UNKNOWN,
|
|
30
33
|
} from './lib/audit-attribution.js';
|
|
31
|
-
import { execFileCapture
|
|
34
|
+
import { execFileCapture } from './lib/child-exec.js';
|
|
32
35
|
import { runAsCli } from './lib/cli-utils.js';
|
|
33
36
|
import { Logger } from './lib/Logger.js';
|
|
34
37
|
|
|
@@ -43,6 +46,10 @@ const HELP = {
|
|
|
43
46
|
flags: [
|
|
44
47
|
['--base <ref>', 'Base commit or ref to attribute against. Required.'],
|
|
45
48
|
['--cwd <dir>', 'Repository root. Default: process.cwd().'],
|
|
49
|
+
[
|
|
50
|
+
'--no-tracking-issue',
|
|
51
|
+
"Skip the `gh issue list` lookup for the nightly sweep's tracking issue.",
|
|
52
|
+
],
|
|
46
53
|
],
|
|
47
54
|
notes: [
|
|
48
55
|
'Run it only after the required SCA step has already failed — it re-audits\nthe base to attribute that failure, and reports `unknown` when the head\naudits clean.',
|
|
@@ -52,43 +59,20 @@ const HELP = {
|
|
|
52
59
|
};
|
|
53
60
|
|
|
54
61
|
export function parseArgs(argv) {
|
|
55
|
-
const out = { base: null, cwd: process.cwd() };
|
|
62
|
+
const out = { base: null, cwd: process.cwd(), trackingIssue: true };
|
|
56
63
|
for (let i = 2; i < argv.length; i += 1) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
// Read the option KEY, not the dashed spelling: the key is what the
|
|
65
|
+
// negation guard and every reader below name.
|
|
66
|
+
const key = argv[i].replace(/^--/, '');
|
|
67
|
+
if (key === 'base') out.base = argv[++i] ?? null;
|
|
68
|
+
else if (key === 'cwd') out.cwd = argv[++i] ?? out.cwd;
|
|
69
|
+
// A runner with no `gh` credentials would spend a subprocess to fail; the
|
|
70
|
+
// verdict never depended on the lookup, so let the caller skip it.
|
|
71
|
+
else if (key === 'no-tracking-issue') out.trackingIssue = false;
|
|
60
72
|
}
|
|
61
73
|
return out;
|
|
62
74
|
}
|
|
63
75
|
|
|
64
|
-
/**
|
|
65
|
-
* Run `npm audit --audit-level=high` over a dependency manifest pair.
|
|
66
|
-
*
|
|
67
|
-
* `--package-lock-only` audits the committed lockfile without installing, so
|
|
68
|
-
* the probe never touches the job's own `node_modules`: an attribution
|
|
69
|
-
* mechanism that could disturb the tree it is reporting on would be a worse
|
|
70
|
-
* defect than the one it explains.
|
|
71
|
-
*
|
|
72
|
-
* @param {string} dir directory holding package.json + package-lock.json
|
|
73
|
-
* @returns {{ failed: boolean }}
|
|
74
|
-
*/
|
|
75
|
-
function auditDir(dir) {
|
|
76
|
-
const result = spawnCapture(
|
|
77
|
-
'npm',
|
|
78
|
-
['audit', '--audit-level=high', '--package-lock-only'],
|
|
79
|
-
{ cwd: dir },
|
|
80
|
-
);
|
|
81
|
-
if (result.status === 0) return { failed: false };
|
|
82
|
-
// npm exits non-zero for "advisories found" and for "could not audit"
|
|
83
|
-
// alike. Only a real audit verdict carries a report on stdout; anything
|
|
84
|
-
// else is a probe failure the caller must read as `unknown`.
|
|
85
|
-
if (/vulnerabilit/i.test(String(result.stdout ?? '')))
|
|
86
|
-
return { failed: true };
|
|
87
|
-
throw new Error(
|
|
88
|
-
`npm audit could not evaluate the base tree: ${String(result.stderr ?? '').slice(0, 200)}`,
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
76
|
/**
|
|
93
77
|
* Materialize the base commit's manifest pair into a scratch directory.
|
|
94
78
|
*
|
|
@@ -121,8 +105,8 @@ const defaultGit = (cwd, ...args) => execFileCapture('git', args, { cwd });
|
|
|
121
105
|
export function runAttribution(argv = process.argv, deps = {}) {
|
|
122
106
|
const {
|
|
123
107
|
git = defaultGit,
|
|
124
|
-
auditHead =
|
|
125
|
-
auditBase =
|
|
108
|
+
auditHead = auditAdvisories,
|
|
109
|
+
auditBase = auditAdvisories,
|
|
126
110
|
materialize = materializeBase,
|
|
127
111
|
lookupTrackingIssue = defaultLookupTrackingIssue,
|
|
128
112
|
cleanup = (dir) => rmSync(dir, { recursive: true, force: true }),
|
|
@@ -139,29 +123,93 @@ export function runAttribution(argv = process.argv, deps = {}) {
|
|
|
139
123
|
return { verdict: UNKNOWN, exitCode: 0, lines };
|
|
140
124
|
}
|
|
141
125
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
} catch (err) {
|
|
146
|
-
return report({ verdict: UNKNOWN, args, logger, reason: msg(err) });
|
|
126
|
+
const head = auditTheHead({ args, auditHead });
|
|
127
|
+
if (head.reason) {
|
|
128
|
+
return report({ verdict: UNKNOWN, args, logger, reason: head.reason });
|
|
147
129
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
130
|
+
|
|
131
|
+
const { baseAudit, reason } = auditTheBase({
|
|
132
|
+
args,
|
|
133
|
+
git,
|
|
134
|
+
auditBase,
|
|
135
|
+
materialize,
|
|
136
|
+
cleanup,
|
|
137
|
+
});
|
|
138
|
+
const { introduced, preExisting } = diffAdvisories({
|
|
139
|
+
head: head.advisories,
|
|
140
|
+
base: baseAudit?.advisories ?? null,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Per advisory: the merge base is "already failing for this" exactly when it
|
|
144
|
+
// carries every advisory the head does. A base red for its own advisory must
|
|
145
|
+
// not absolve a diff that added a different one.
|
|
146
|
+
const verdict = deriveVerdict({
|
|
147
|
+
headFailed: true,
|
|
148
|
+
baseAudit: baseAudit && { failed: introduced.length === 0 },
|
|
149
|
+
});
|
|
150
|
+
return report({
|
|
151
|
+
verdict,
|
|
152
|
+
args,
|
|
153
|
+
logger,
|
|
154
|
+
reason,
|
|
155
|
+
trackingIssue: resolveTrackingIssue({
|
|
156
|
+
verdict,
|
|
151
157
|
args,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
lookupTrackingIssue,
|
|
159
|
+
}),
|
|
160
|
+
introduced,
|
|
161
|
+
preExisting,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Audit the head tree, converting both no-verdict cases — the audit itself
|
|
167
|
+
* broke, or the head is clean — into a `reason` the caller reports as
|
|
168
|
+
* `unknown`. Neither is an accusation, and neither is worth auditing a base for.
|
|
169
|
+
*
|
|
170
|
+
* @param {{ args: object, auditHead: Function }} ctx
|
|
171
|
+
* @returns {{ advisories?: Array<object>, reason: string|null }}
|
|
172
|
+
*/
|
|
173
|
+
function auditTheHead({ args, auditHead }) {
|
|
174
|
+
try {
|
|
175
|
+
const head = auditHead(args.cwd);
|
|
176
|
+
return head.failed
|
|
177
|
+
? { advisories: head.advisories, reason: null }
|
|
178
|
+
: {
|
|
179
|
+
reason:
|
|
180
|
+
'the head tree audits clean, so there is nothing to attribute',
|
|
181
|
+
};
|
|
182
|
+
} catch (err) {
|
|
183
|
+
return { reason: msg(err) };
|
|
155
184
|
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Look the nightly sweep's tracking issue up, unless there is no verdict to
|
|
189
|
+
* attach it to or `--no-tracking-issue` said not to spend the round-trip.
|
|
190
|
+
*
|
|
191
|
+
* @param {{ verdict: string, args: object, lookupTrackingIssue: Function }} ctx
|
|
192
|
+
* @returns {number|null}
|
|
193
|
+
*/
|
|
194
|
+
function resolveTrackingIssue({ verdict, args, lookupTrackingIssue }) {
|
|
195
|
+
if (verdict === UNKNOWN || !args.trackingIssue) return null;
|
|
196
|
+
return safeLookup(lookupTrackingIssue, args.cwd);
|
|
197
|
+
}
|
|
156
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Materialize the merge base and audit it, converting every way that can fail
|
|
201
|
+
* into a `reason` rather than a throw. The scratch directory is always removed.
|
|
202
|
+
*
|
|
203
|
+
* @param {object} ctx
|
|
204
|
+
* @returns {{ baseAudit: object|null, reason: string|null }}
|
|
205
|
+
*/
|
|
206
|
+
function auditTheBase({ args, git, auditBase, materialize, cleanup }) {
|
|
157
207
|
let dir = null;
|
|
158
|
-
let baseAudit = null;
|
|
159
|
-
let reason = null;
|
|
160
208
|
try {
|
|
161
209
|
dir = materialize({ cwd: args.cwd, base: args.base, git });
|
|
162
|
-
baseAudit
|
|
210
|
+
return { baseAudit: auditBase(dir), reason: null };
|
|
163
211
|
} catch (err) {
|
|
164
|
-
reason
|
|
212
|
+
return { baseAudit: null, reason: msg(err) };
|
|
165
213
|
} finally {
|
|
166
214
|
if (dir) {
|
|
167
215
|
try {
|
|
@@ -172,11 +220,6 @@ export function runAttribution(argv = process.argv, deps = {}) {
|
|
|
172
220
|
}
|
|
173
221
|
}
|
|
174
222
|
}
|
|
175
|
-
|
|
176
|
-
const verdict = deriveVerdict({ headFailed, baseAudit });
|
|
177
|
-
const trackingIssue =
|
|
178
|
-
verdict === UNKNOWN ? null : safeLookup(lookupTrackingIssue, args.cwd);
|
|
179
|
-
return report({ verdict, args, logger, reason, trackingIssue });
|
|
180
223
|
}
|
|
181
224
|
|
|
182
225
|
function msg(err) {
|
|
@@ -189,15 +232,29 @@ function report({
|
|
|
189
232
|
logger,
|
|
190
233
|
reason = null,
|
|
191
234
|
trackingIssue = null,
|
|
235
|
+
introduced = [],
|
|
236
|
+
preExisting = [],
|
|
192
237
|
}) {
|
|
193
|
-
const lines =
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
238
|
+
const lines = [
|
|
239
|
+
...renderAttribution({
|
|
240
|
+
verdict,
|
|
241
|
+
baseRef: args.base,
|
|
242
|
+
trackingIssue,
|
|
243
|
+
reason,
|
|
244
|
+
}),
|
|
245
|
+
// The two lists are reported separately even when the verdict is
|
|
246
|
+
// `introduced-by-this-diff`: an author fixing B still needs to know A is
|
|
247
|
+
// not theirs.
|
|
248
|
+
...renderAdvisoryDetail({ introduced, preExisting }),
|
|
249
|
+
];
|
|
199
250
|
for (const line of lines) logger.info(line);
|
|
200
|
-
return {
|
|
251
|
+
return {
|
|
252
|
+
verdict,
|
|
253
|
+
exitCode: attributionExitCode(verdict),
|
|
254
|
+
lines,
|
|
255
|
+
introduced,
|
|
256
|
+
preExisting,
|
|
257
|
+
};
|
|
201
258
|
}
|
|
202
259
|
|
|
203
260
|
/**
|