@yagni-app/code-staging 1.2.6-staging.1952.1 → 1.2.6-staging.1958.1
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/dist/extension/branding.d.ts +21 -1
- package/dist/extension/branding.js +53 -12
- package/dist/extension/index.js +5 -0
- package/dist/extension/pipeline/changeScan.d.ts +62 -0
- package/dist/extension/pipeline/changeScan.js +307 -0
- package/dist/extension/pipeline/cloud.d.ts +205 -0
- package/dist/extension/pipeline/cloud.js +382 -0
- package/dist/extension/pipeline/continuation.d.ts +7 -3
- package/dist/extension/pipeline/continuation.js +29 -13
- package/dist/extension/pipeline/findings.d.ts +9 -4
- package/dist/extension/pipeline/findings.js +25 -10
- package/dist/extension/pipeline/finish.d.ts +11 -1
- package/dist/extension/pipeline/finish.js +51 -5
- package/dist/extension/pipeline/headlessGo.d.ts +20 -1
- package/dist/extension/pipeline/headlessGo.js +205 -33
- package/dist/extension/pipeline/orchestrator.d.ts +8 -2
- package/dist/extension/pipeline/orchestrator.js +249 -68
- package/dist/extension/pipeline/personas.d.ts +8 -3
- package/dist/extension/pipeline/personas.js +42 -7
- package/dist/extension/pipeline/planOutput.d.ts +42 -0
- package/dist/extension/pipeline/planOutput.js +94 -0
- package/dist/extension/pipeline/stages.d.ts +34 -5
- package/dist/extension/pipeline/stages.js +136 -7
- package/dist/extension/pipeline/tierCap.d.ts +22 -1
- package/dist/extension/pipeline/tierCap.js +48 -1
- package/dist/extension/pipeline/types.d.ts +31 -0
- package/dist/extension/pipeline/types.js +2 -0
- package/dist/extension/pipeline/verify.d.ts +33 -0
- package/dist/extension/pipeline/verify.js +101 -9
- package/package.json +2 -2
|
@@ -67,6 +67,33 @@ export interface PipelineStage {
|
|
|
67
67
|
* claimed files, sibling claims, and the shared-worktree discipline rules.
|
|
68
68
|
*/
|
|
69
69
|
personaClause?: string;
|
|
70
|
+
/**
|
|
71
|
+
* The persona body this stage runs with, in place of its agent's. The cloud
|
|
72
|
+
* plan stage takes the host's `plan-persona.md` (Reeve's persona) here.
|
|
73
|
+
*/
|
|
74
|
+
persona?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A stage list and the loop rules that go with it. The `full` lane is what
|
|
78
|
+
* interactive /go and mission builds run; the `cloud` lane is the one-attempt
|
|
79
|
+
* session (`yagni go --headless --cloud`).
|
|
80
|
+
*/
|
|
81
|
+
export interface PipelineLane {
|
|
82
|
+
stages: PipelineStage[];
|
|
83
|
+
/** The review angles fanned out each round; empty is one reviewer covering every angle. */
|
|
84
|
+
reviewLenses: readonly ReviewLens[];
|
|
85
|
+
/** Review rounds before the loop stops `round_cap`. */
|
|
86
|
+
maxReviewRounds: number;
|
|
87
|
+
/** Whether implement may fan out into parallel builders (the diamond). */
|
|
88
|
+
fanout: boolean;
|
|
89
|
+
/** The plan stage ends the run: the plan goes to its gate before anything is built. */
|
|
90
|
+
stopAfterPlan: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Every stage loads the Team's skills (the launcher's `--skill` /
|
|
93
|
+
* `--prompt-template` flags), not only the ones that write code: the
|
|
94
|
+
* cloud session plans and reviews with them too (spec decision 4).
|
|
95
|
+
*/
|
|
96
|
+
skillsEveryStage: boolean;
|
|
70
97
|
}
|
|
71
98
|
/** A single structured review finding parsed from a reviewer's output. */
|
|
72
99
|
export interface Finding {
|
|
@@ -210,6 +237,8 @@ export interface PipelineResult {
|
|
|
210
237
|
* orchestrator never sets it — commit/push live outside the LLM pipeline).
|
|
211
238
|
*/
|
|
212
239
|
finish?: FinishInfo;
|
|
240
|
+
/** The plan the run wrote, on a lane whose plan stage ends the run (`stopAfterPlan`). */
|
|
241
|
+
plan?: string;
|
|
213
242
|
}
|
|
214
243
|
/**
|
|
215
244
|
* The append-only resilience journal (spec: 2026-06-29-yagni-code-go-resilience).
|
|
@@ -512,6 +541,8 @@ export type PipelineProgress = {
|
|
|
512
541
|
* - Round two runs only when round one found a blocker (`shouldStop`); what is
|
|
513
542
|
* still open after the cap is written into the pull request body under
|
|
514
543
|
* "Left for review" for Proctor, never a third round.
|
|
544
|
+
* This is the `full` lane's cap. The cloud lane carries its own
|
|
545
|
+
* (`PipelineLane.maxReviewRounds`): one reviewer per round, so four rounds.
|
|
515
546
|
*/
|
|
516
547
|
export declare const MAX_REVIEW_ROUNDS = 2;
|
|
517
548
|
/**
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
* - Round two runs only when round one found a blocker (`shouldStop`); what is
|
|
18
18
|
* still open after the cap is written into the pull request body under
|
|
19
19
|
* "Left for review" for Proctor, never a third round.
|
|
20
|
+
* This is the `full` lane's cap. The cloud lane carries its own
|
|
21
|
+
* (`PipelineLane.maxReviewRounds`): one reviewer per round, so four rounds.
|
|
20
22
|
*/
|
|
21
23
|
export const MAX_REVIEW_ROUNDS = 2;
|
|
22
24
|
/**
|
|
@@ -96,7 +96,33 @@ export interface VerifyOutcome {
|
|
|
96
96
|
findings: Finding[];
|
|
97
97
|
/** Failures the clean tree already had (YAG-1003): named in `reason`, never findings. */
|
|
98
98
|
preexisting?: number;
|
|
99
|
+
/** Every command the gate ran, with how it exited (the cloud session's `result.json` checks). */
|
|
100
|
+
checks?: VerifyCheckRun[];
|
|
99
101
|
}
|
|
102
|
+
/** One command the gate ran, and how it went. */
|
|
103
|
+
export interface VerifyCheckRun {
|
|
104
|
+
name: string;
|
|
105
|
+
command: string;
|
|
106
|
+
/** Where it ran, repo-relative ("." for the root). */
|
|
107
|
+
cwd: string;
|
|
108
|
+
/** Null when the command never exited: it timed out, was aborted, or was not found. */
|
|
109
|
+
exitCode: number | null;
|
|
110
|
+
durationMs: number;
|
|
111
|
+
/**
|
|
112
|
+
* How the check stands on the unchanged code: it already failed there
|
|
113
|
+
* (the YAG-1003 baseline, or `checks.json`), the sandbox cannot run it, or
|
|
114
|
+
* neither.
|
|
115
|
+
*/
|
|
116
|
+
baseline: "runnable" | "fails_on_base" | "cannot_run";
|
|
117
|
+
/** Why it has no exit code: "timed out", "aborted", "not found" or "could not run". */
|
|
118
|
+
note?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Why a command threw instead of exiting, as its check record says it. `run`
|
|
122
|
+
* is the run's own signal (a /stop or the run's end); `capped` is the one
|
|
123
|
+
* the command ran under, which also carries its time cap.
|
|
124
|
+
*/
|
|
125
|
+
export declare function unexitedNote(err: unknown, run?: AbortSignal, capped?: AbortSignal): string;
|
|
100
126
|
/** Injectable fs seam so detection is unit-testable without a real repo. */
|
|
101
127
|
export interface DetectOpts {
|
|
102
128
|
readFile?: (path: string) => string;
|
|
@@ -404,6 +430,13 @@ export interface MakeRunVerifyOpts {
|
|
|
404
430
|
* findings. Absent: every failure is a finding, as before.
|
|
405
431
|
*/
|
|
406
432
|
baseline?: VerifyBaseline | null;
|
|
433
|
+
/**
|
|
434
|
+
* The host's secret and binary scans over what this run added
|
|
435
|
+
* (changeScan.ts, YAG-1000), given the tree's pre-run dirt to leave out;
|
|
436
|
+
* null when git could not say what changed. A hit is a finding the fix turn
|
|
437
|
+
* removes. Absent: no scan half, as before (the cloud session sets it).
|
|
438
|
+
*/
|
|
439
|
+
scanChange?: (cwd: string, signal?: AbortSignal, baselinePaths?: string[]) => Promise<Finding[] | null>;
|
|
407
440
|
}
|
|
408
441
|
/**
|
|
409
442
|
* One workstream as the scoped checker sees it: the name its findings are
|
|
@@ -53,7 +53,7 @@ import { readFileSync } from "node:fs";
|
|
|
53
53
|
// APIs accept forward-slash paths — while win32 join/dirname would emit
|
|
54
54
|
// backslashed strings that no longer compare equal to the git-derived repoRoot
|
|
55
55
|
// and would break the walk-up termination check.
|
|
56
|
-
import { basename, dirname, join } from "node:path/posix";
|
|
56
|
+
import { basename, dirname, join, relative } from "node:path/posix";
|
|
57
57
|
import { readToolchainFile } from "../toolchain/spawnHook.js";
|
|
58
58
|
import { killTreeSync, trackChild } from "./childRegistry.js";
|
|
59
59
|
import { claimCovers } from "./fanout.js";
|
|
@@ -89,6 +89,23 @@ const MAX_LOCATED_FINDINGS = 25;
|
|
|
89
89
|
const MAX_TAIL_CHARS = 1000;
|
|
90
90
|
/** The verify lens reuses `does_it_hold` (does the change build/test) to avoid widening ReviewLens. */
|
|
91
91
|
const VERIFY_LENS = "does_it_hold";
|
|
92
|
+
/**
|
|
93
|
+
* Why a command threw instead of exiting, as its check record says it. `run`
|
|
94
|
+
* is the run's own signal (a /stop or the run's end); `capped` is the one
|
|
95
|
+
* the command ran under, which also carries its time cap.
|
|
96
|
+
*/
|
|
97
|
+
export function unexitedNote(err, run, capped) {
|
|
98
|
+
if (run?.aborted)
|
|
99
|
+
return "aborted";
|
|
100
|
+
if (capped?.aborted)
|
|
101
|
+
return "timed out";
|
|
102
|
+
const shape = err;
|
|
103
|
+
if (shape?.code === "ENOENT")
|
|
104
|
+
return "not found";
|
|
105
|
+
if (shape?.name === "AbortError" || shape?.name === "TimeoutError")
|
|
106
|
+
return "timed out";
|
|
107
|
+
return "could not run";
|
|
108
|
+
}
|
|
92
109
|
/**
|
|
93
110
|
* The priority order of package.json scripts we treat as a verify command.
|
|
94
111
|
* Deliberately a SECRET-INDEPENDENT build check (`typecheck`/`lint`), NEVER the
|
|
@@ -1168,12 +1185,12 @@ export function makeRunVerify(opts = {}) {
|
|
|
1168
1185
|
const steps = jobs.flatMap((job) => job.steps.map((step) => ({ job, step })));
|
|
1169
1186
|
if (approved.length === 0 && steps.length === 0) {
|
|
1170
1187
|
report();
|
|
1171
|
-
return { findings, reasons, labels };
|
|
1188
|
+
return { findings, reasons, labels, checks: [] };
|
|
1172
1189
|
}
|
|
1173
1190
|
const buildLeft = (opts.repoChecksBuildBudgetMs ?? REPO_CHECKS_BUILD_BUDGET_MS) - repoChecksSpentMs;
|
|
1174
1191
|
if (buildLeft < REPO_CHECK_MIN_START_MS) {
|
|
1175
1192
|
reasons.push("approved checks and CI steps not run again: the build's check budget is spent; the host still runs the approved checks after the build");
|
|
1176
|
-
return { findings, reasons, labels };
|
|
1193
|
+
return { findings, reasons, labels, checks: [] };
|
|
1177
1194
|
}
|
|
1178
1195
|
const callBudget = Math.min(opts.repoChecksCallBudgetMs ?? REPO_CHECKS_CALL_BUDGET_MS, timeoutMs - (now() - input.callStartedAt), buildLeft);
|
|
1179
1196
|
const halfStartedAt = now();
|
|
@@ -1188,6 +1205,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1188
1205
|
notReached: 0,
|
|
1189
1206
|
failedJobs,
|
|
1190
1207
|
approvedFailed: new Set(),
|
|
1208
|
+
checks: [],
|
|
1191
1209
|
};
|
|
1192
1210
|
const before = await treeStatus(cwd, signal).catch((err) => {
|
|
1193
1211
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -1221,26 +1239,47 @@ export function makeRunVerify(opts = {}) {
|
|
|
1221
1239
|
if (run.notReached > 0) {
|
|
1222
1240
|
reasons.push(`${run.notReached} approved check(s) or CI step(s) not reached in the gate's time budget; the host still runs the approved checks after the build`);
|
|
1223
1241
|
}
|
|
1224
|
-
return { findings, reasons, labels };
|
|
1242
|
+
return { findings, reasons, labels, checks: run.checks };
|
|
1225
1243
|
}
|
|
1226
1244
|
/** One repository command's verdict: passed, a note (it could not run), or a failure with its output. */
|
|
1227
|
-
async function runRepoCommand(run, command, dir, stepEnv) {
|
|
1245
|
+
async function runRepoCommand(run, command, dir, stepEnv, check) {
|
|
1228
1246
|
const capMs = Math.min(opts.repoCheckTimeoutMs ?? REPO_CHECK_TIMEOUT_MS, run.left());
|
|
1229
1247
|
const composed = composeAbortSignal(run.signal, AbortSignal.timeout(Math.max(1, capMs)));
|
|
1230
1248
|
const env = opts.repoChecksEnv
|
|
1231
1249
|
? { ...opts.repoChecksEnv, ...(stepEnv ?? {}) }
|
|
1232
1250
|
: buildRepoCheckEnv(process.env, run.toolchainFile, stepEnv);
|
|
1251
|
+
const startedAt = now();
|
|
1233
1252
|
try {
|
|
1234
1253
|
const { code, output: rawOutput } = await exec(repoCheckArgv(command), dir, composed, env);
|
|
1235
|
-
|
|
1254
|
+
const record = (baseline) => run.checks.push({
|
|
1255
|
+
name: check.name,
|
|
1256
|
+
command,
|
|
1257
|
+
cwd: relative(run.cwd, dir) || ".",
|
|
1258
|
+
exitCode: code,
|
|
1259
|
+
durationMs: now() - startedAt,
|
|
1260
|
+
baseline,
|
|
1261
|
+
});
|
|
1262
|
+
if (code === 0) {
|
|
1263
|
+
record(check.baseline);
|
|
1236
1264
|
return { kind: "passed" };
|
|
1265
|
+
}
|
|
1237
1266
|
const output = scrubSecrets(rawOutput);
|
|
1238
1267
|
const cls = classifyTestFailure(output, code);
|
|
1268
|
+
record(cls.kind === "infra" ? "cannot_run" : check.baseline);
|
|
1239
1269
|
if (cls.kind === "infra")
|
|
1240
1270
|
return { kind: "note", reason: `could not run: ${cls.reason}` };
|
|
1241
1271
|
return { kind: "failed", output, code };
|
|
1242
1272
|
}
|
|
1243
1273
|
catch (err) {
|
|
1274
|
+
run.checks.push({
|
|
1275
|
+
name: check.name,
|
|
1276
|
+
command,
|
|
1277
|
+
cwd: relative(run.cwd, dir) || ".",
|
|
1278
|
+
exitCode: null,
|
|
1279
|
+
durationMs: now() - startedAt,
|
|
1280
|
+
baseline: check.baseline,
|
|
1281
|
+
note: unexitedNote(err, run.signal, composed),
|
|
1282
|
+
});
|
|
1244
1283
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1245
1284
|
return { kind: "note", reason: `could not run: ${scrubSecrets(msg)}` };
|
|
1246
1285
|
}
|
|
@@ -1271,7 +1310,10 @@ export function makeRunVerify(opts = {}) {
|
|
|
1271
1310
|
continue;
|
|
1272
1311
|
}
|
|
1273
1312
|
const label = check.command.length > 80 ? `${check.command.slice(0, 77)}...` : check.command;
|
|
1274
|
-
const verdict = await runRepoCommand(run, check.command, run.cwd, undefined
|
|
1313
|
+
const verdict = await runRepoCommand(run, check.command, run.cwd, undefined, {
|
|
1314
|
+
name: label,
|
|
1315
|
+
baseline: check.status,
|
|
1316
|
+
});
|
|
1275
1317
|
if (verdict.kind === "failed")
|
|
1276
1318
|
run.approvedFailed.add(check.command.trim());
|
|
1277
1319
|
if (verdict.kind === "note") {
|
|
@@ -1336,7 +1378,10 @@ export function makeRunVerify(opts = {}) {
|
|
|
1336
1378
|
const dir = step.workingDirectory
|
|
1337
1379
|
? join(run.cwd, step.workingDirectory.replace(/^\.\/+/, ""))
|
|
1338
1380
|
: run.cwd;
|
|
1339
|
-
const verdict = await runRepoCommand(run, step.run, dir, step.env
|
|
1381
|
+
const verdict = await runRepoCommand(run, step.run, dir, step.env, {
|
|
1382
|
+
name: `CI ${job.name}: ${step.name}`,
|
|
1383
|
+
baseline: "runnable",
|
|
1384
|
+
});
|
|
1340
1385
|
if (verdict.kind === "passed") {
|
|
1341
1386
|
lastCiFailure.delete(key);
|
|
1342
1387
|
run.labels.push(`CI ${job.name}: ${step.name}`);
|
|
@@ -1374,7 +1419,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1374
1419
|
// The approved checks carry the plan's approval, not the repository's own
|
|
1375
1420
|
// choice of how to verify, so an override never takes them out of the loop.
|
|
1376
1421
|
const repoFile = opts.repoChecks?.() ?? null;
|
|
1377
|
-
if (commands.length === 0 && testCommands.length === 0 && !repoFile) {
|
|
1422
|
+
if (commands.length === 0 && testCommands.length === 0 && !repoFile && !opts.scanChange) {
|
|
1378
1423
|
return {
|
|
1379
1424
|
ran: false,
|
|
1380
1425
|
ok: true,
|
|
@@ -1391,6 +1436,21 @@ export function makeRunVerify(opts = {}) {
|
|
|
1391
1436
|
if (n > 0)
|
|
1392
1437
|
preexisting.set(label, (preexisting.get(label) ?? 0) + n);
|
|
1393
1438
|
};
|
|
1439
|
+
const checks = [];
|
|
1440
|
+
// A detected command's standing on the clean tree, from the baseline run.
|
|
1441
|
+
const standing = (command) => {
|
|
1442
|
+
const counts = opts.baseline?.get(verifyCommandKey(command));
|
|
1443
|
+
return counts && [...counts.values()].some((n) => n > 0) ? "fails_on_base" : "runnable";
|
|
1444
|
+
};
|
|
1445
|
+
const recordCommand = (command, code, startedAt, baseline, note) => checks.push({
|
|
1446
|
+
name: command.label,
|
|
1447
|
+
command: command.argv.join(" "),
|
|
1448
|
+
cwd: relative(cwd, command.cwd) || ".",
|
|
1449
|
+
exitCode: code,
|
|
1450
|
+
durationMs: now() - startedAt,
|
|
1451
|
+
baseline,
|
|
1452
|
+
...(note ? { note } : {}),
|
|
1453
|
+
});
|
|
1394
1454
|
// TYPECHECK HALF (frozen behavior, §0.2): run every changed package's build
|
|
1395
1455
|
// check; union the findings. One package that cannot spawn fails OPEN (a
|
|
1396
1456
|
// recorded reason, no finding) without sinking the verdict for the packages
|
|
@@ -1398,6 +1458,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1398
1458
|
const typecheckLabels = [];
|
|
1399
1459
|
for (const command of commands) {
|
|
1400
1460
|
const composed = composeAbortSignal(signal, AbortSignal.timeout(timeoutMs));
|
|
1461
|
+
const startedAt = now();
|
|
1401
1462
|
try {
|
|
1402
1463
|
const { code, output: rawOutput } = await exec(command.argv, command.cwd, composed);
|
|
1403
1464
|
const output = scrubSecrets(rawOutput);
|
|
@@ -1409,9 +1470,11 @@ export function makeRunVerify(opts = {}) {
|
|
|
1409
1470
|
const infra = classifyVerifyInfraFailure(output, code);
|
|
1410
1471
|
if (infra) {
|
|
1411
1472
|
reasons.push(`verify (${command.label}) could not run: ${infra}`);
|
|
1473
|
+
recordCommand(command, code, startedAt, "cannot_run");
|
|
1412
1474
|
continue;
|
|
1413
1475
|
}
|
|
1414
1476
|
}
|
|
1477
|
+
recordCommand(command, code, startedAt, standing(command));
|
|
1415
1478
|
anyRan = true;
|
|
1416
1479
|
typecheckLabels.push(command.label);
|
|
1417
1480
|
if (code !== 0) {
|
|
@@ -1422,6 +1485,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1422
1485
|
}
|
|
1423
1486
|
}
|
|
1424
1487
|
catch (err) {
|
|
1488
|
+
recordCommand(command, null, startedAt, standing(command), unexitedNote(err, signal, composed));
|
|
1425
1489
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1426
1490
|
reasons.push(`verify (${command.label}) could not run: ${scrubSecrets(msg)}`);
|
|
1427
1491
|
}
|
|
@@ -1445,10 +1509,12 @@ export function makeRunVerify(opts = {}) {
|
|
|
1445
1509
|
for (const command of testCommands) {
|
|
1446
1510
|
const where = basename(command.cwd) || command.cwd;
|
|
1447
1511
|
const composed = composeAbortSignal(signal, AbortSignal.timeout(testTimeoutMs));
|
|
1512
|
+
const startedAt = now();
|
|
1448
1513
|
try {
|
|
1449
1514
|
const { code, output: rawOutput } = await exec(command.argv, command.cwd, composed, testEnv);
|
|
1450
1515
|
const output = scrubSecrets(rawOutput);
|
|
1451
1516
|
const cls = classifyTestFailure(output, code, Number.POSITIVE_INFINITY);
|
|
1517
|
+
recordCommand(command, code, startedAt, cls.kind === "infra" ? "cannot_run" : standing(command));
|
|
1452
1518
|
if (cls.kind === "infra") {
|
|
1453
1519
|
reasons.push(`tests (${where}) could not run: ${cls.reason}; 'clean' reflects typecheck + review only`);
|
|
1454
1520
|
continue;
|
|
@@ -1471,6 +1537,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1471
1537
|
}
|
|
1472
1538
|
}
|
|
1473
1539
|
catch (err) {
|
|
1540
|
+
recordCommand(command, null, startedAt, standing(command), unexitedNote(err, signal, composed));
|
|
1474
1541
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1475
1542
|
reasons.push(`tests (${where}) could not run: ${scrubSecrets(msg)}`);
|
|
1476
1543
|
}
|
|
@@ -1495,11 +1562,33 @@ export function makeRunVerify(opts = {}) {
|
|
|
1495
1562
|
});
|
|
1496
1563
|
reasons.push(...repo.reasons);
|
|
1497
1564
|
repoLabels.push(...repo.labels);
|
|
1565
|
+
checks.push(...repo.checks);
|
|
1498
1566
|
if (repo.labels.length > 0)
|
|
1499
1567
|
anyRan = true;
|
|
1500
1568
|
findings.push(...repo.findings);
|
|
1501
1569
|
}
|
|
1502
1570
|
}
|
|
1571
|
+
// SCAN HALF (YAG-1000): what this run added, against the host's own stop
|
|
1572
|
+
// rules, whatever the other halves found: a credential is never the
|
|
1573
|
+
// compile error's root cause, and it must not reach the host.
|
|
1574
|
+
const scanLabels = [];
|
|
1575
|
+
if (opts.scanChange) {
|
|
1576
|
+
try {
|
|
1577
|
+
const hits = await opts.scanChange(cwd, signal, baselinePaths);
|
|
1578
|
+
if (hits === null) {
|
|
1579
|
+
reasons.push("the secret and binary scan could not read the change; the host still scans it");
|
|
1580
|
+
}
|
|
1581
|
+
else {
|
|
1582
|
+
anyRan = true;
|
|
1583
|
+
scanLabels.push("secret and binary scan");
|
|
1584
|
+
findings.push(...hits.slice(0, MAX_LOCATED_FINDINGS));
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
catch (err) {
|
|
1588
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1589
|
+
reasons.push(`the secret and binary scan could not run: ${scrubSecrets(msg)}; the host still scans the change`);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1503
1592
|
const note = preexistingNote(preexisting);
|
|
1504
1593
|
if (note)
|
|
1505
1594
|
reasons.push(note);
|
|
@@ -1511,6 +1600,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1511
1600
|
...new Set(typecheckLabels),
|
|
1512
1601
|
...new Set(testLabels),
|
|
1513
1602
|
...new Set(repoLabels),
|
|
1603
|
+
...scanLabels,
|
|
1514
1604
|
].join(", ");
|
|
1515
1605
|
if (!anyRan) {
|
|
1516
1606
|
return {
|
|
@@ -1519,6 +1609,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1519
1609
|
command,
|
|
1520
1610
|
reason: reasons.join("; ") || "verify skipped",
|
|
1521
1611
|
findings: [],
|
|
1612
|
+
checks,
|
|
1522
1613
|
};
|
|
1523
1614
|
}
|
|
1524
1615
|
return {
|
|
@@ -1528,6 +1619,7 @@ export function makeRunVerify(opts = {}) {
|
|
|
1528
1619
|
findings,
|
|
1529
1620
|
...(reasons.length ? { reason: reasons.join("; ") } : {}),
|
|
1530
1621
|
...(preexistingTotal > 0 ? { preexisting: preexistingTotal } : {}),
|
|
1622
|
+
checks,
|
|
1531
1623
|
};
|
|
1532
1624
|
};
|
|
1533
1625
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yagni-app/code-staging",
|
|
3
|
-
"version": "1.2.6-staging.
|
|
3
|
+
"version": "1.2.6-staging.1958.1",
|
|
4
4
|
"description": "YAGNI Code: a terminal coding agent that already knows your company. One YAGNI login routes the model and grounds the agent in your team's context.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "YAGNI, Inc. <jack@yagni.app> (https://yagni.app)",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"turndown": "^7.2.4",
|
|
59
59
|
"typebox": "^1.3.15"
|
|
60
60
|
},
|
|
61
|
-
"yagniSourceSha": "
|
|
61
|
+
"yagniSourceSha": "419ce23e2c9fb464a83e7ffba0f48cdd5238126b"
|
|
62
62
|
}
|