@cleocode/core 2026.10.25 → 2026.10.26
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/build-provenance.json +2 -2
- package/dist/dispatch/contracts/output-contracts.d.ts +13 -0
- package/dist/dispatch/contracts/output-contracts.d.ts.map +1 -1
- package/dist/dispatch/contracts/output-contracts.js +29 -0
- package/dist/dispatch/contracts/output-contracts.js.map +1 -1
- package/dist/docs/docs-ops.d.ts +8 -0
- package/dist/docs/docs-ops.d.ts.map +1 -1
- package/dist/docs/docs-ops.js +24 -1
- package/dist/docs/docs-ops.js.map +1 -1
- package/dist/docs/docs-update.d.ts +8 -5
- package/dist/docs/docs-update.d.ts.map +1 -1
- package/dist/docs/docs-update.js +16 -5
- package/dist/docs/docs-update.js.map +1 -1
- package/dist/gateway-client/generated/types.gen.d.ts +27 -0
- package/dist/gateway-client/generated/types.gen.d.ts.map +1 -1
- package/dist/hooks/handlers/watchdog-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/watchdog-hooks.js +5 -0
- package/dist/hooks/handlers/watchdog-hooks.js.map +1 -1
- package/dist/internal.d.ts +3 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +5 -2
- package/dist/internal.js.map +1 -1
- package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
- package/dist/lifecycle/verification/satisfies-validator.js +22 -10
- package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
- package/dist/memory/brain-writer-thread.d.ts +30 -0
- package/dist/memory/brain-writer-thread.d.ts.map +1 -1
- package/dist/memory/brain-writer-thread.js +46 -1
- package/dist/memory/brain-writer-thread.js.map +1 -1
- package/dist/memory/brain-writer-worker.js +13 -2
- package/dist/memory/brain-writer-worker.js.map +1 -1
- package/dist/memory/embedding-backfill.d.ts +12 -0
- package/dist/memory/embedding-backfill.d.ts.map +1 -1
- package/dist/memory/embedding-backfill.js +51 -31
- package/dist/memory/embedding-backfill.js.map +1 -1
- package/dist/orchestrate/include-deps.d.ts +58 -0
- package/dist/orchestrate/include-deps.d.ts.map +1 -0
- package/dist/orchestrate/include-deps.js +138 -0
- package/dist/orchestrate/include-deps.js.map +1 -0
- package/dist/orchestrate/spawn-ops.d.ts +14 -33
- package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
- package/dist/orchestrate/spawn-ops.js +49 -61
- package/dist/orchestrate/spawn-ops.js.map +1 -1
- package/dist/orchestrate/worktree-complete.d.ts +15 -1
- package/dist/orchestrate/worktree-complete.d.ts.map +1 -1
- package/dist/orchestrate/worktree-complete.js +36 -3
- package/dist/orchestrate/worktree-complete.js.map +1 -1
- package/dist/release/ci-evidence.d.ts +142 -4
- package/dist/release/ci-evidence.d.ts.map +1 -1
- package/dist/release/ci-evidence.js +298 -48
- package/dist/release/ci-evidence.js.map +1 -1
- package/dist/release/open.d.ts +25 -1
- package/dist/release/open.d.ts.map +1 -1
- package/dist/release/open.js +63 -11
- package/dist/release/open.js.map +1 -1
- package/dist/resources/admission-ledger.d.ts +83 -11
- package/dist/resources/admission-ledger.d.ts.map +1 -1
- package/dist/resources/admission-ledger.js +138 -39
- package/dist/resources/admission-ledger.js.map +1 -1
- package/dist/resources/governor.js +1 -1
- package/dist/resources/governor.js.map +1 -1
- package/dist/resources/hook-footprint.d.ts +24 -0
- package/dist/resources/hook-footprint.d.ts.map +1 -1
- package/dist/resources/hook-footprint.js +38 -1
- package/dist/resources/hook-footprint.js.map +1 -1
- package/dist/resources/run-class.d.ts +38 -5
- package/dist/resources/run-class.d.ts.map +1 -1
- package/dist/resources/run-class.js +60 -11
- package/dist/resources/run-class.js.map +1 -1
- package/dist/resources/run-governed.d.ts +13 -3
- package/dist/resources/run-governed.d.ts.map +1 -1
- package/dist/resources/run-governed.js +42 -9
- package/dist/resources/run-governed.js.map +1 -1
- package/dist/resources/slot-holder.d.ts +3 -3
- package/dist/resources/slot-holder.js +3 -3
- package/dist/resources/tool-groups.d.ts +11 -7
- package/dist/resources/tool-groups.d.ts.map +1 -1
- package/dist/resources/tool-groups.js +24 -13
- package/dist/resources/tool-groups.js.map +1 -1
- package/dist/spawn/branch-integration.d.ts +281 -0
- package/dist/spawn/branch-integration.d.ts.map +1 -0
- package/dist/spawn/branch-integration.js +715 -0
- package/dist/spawn/branch-integration.js.map +1 -0
- package/dist/spawn/branch-lock.d.ts +32 -270
- package/dist/spawn/branch-lock.d.ts.map +1 -1
- package/dist/spawn/branch-lock.js +59 -770
- package/dist/spawn/branch-lock.js.map +1 -1
- package/dist/spawn/index.d.ts +3 -1
- package/dist/spawn/index.d.ts.map +1 -1
- package/dist/spawn/index.js +5 -1
- package/dist/spawn/index.js.map +1 -1
- package/dist/store/exodus/recovery.d.ts.map +1 -1
- package/dist/store/exodus/recovery.js +9 -4
- package/dist/store/exodus/recovery.js.map +1 -1
- package/dist/system/health.d.ts.map +1 -1
- package/dist/system/health.js +3 -1
- package/dist/system/health.js.map +1 -1
- package/dist/tasks/ac-coverage-gate.d.ts +18 -2
- package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
- package/dist/tasks/ac-coverage-gate.js +40 -6
- package/dist/tasks/ac-coverage-gate.js.map +1 -1
- package/dist/tasks/ac-table.d.ts.map +1 -1
- package/dist/tasks/ac-table.js +3 -10
- package/dist/tasks/ac-table.js.map +1 -1
- package/dist/tasks/affected-packages.d.ts.map +1 -1
- package/dist/tasks/affected-packages.js +54 -10
- package/dist/tasks/affected-packages.js.map +1 -1
- package/dist/tasks/affected-scope.d.ts +10 -1
- package/dist/tasks/affected-scope.d.ts.map +1 -1
- package/dist/tasks/affected-scope.js +13 -3
- package/dist/tasks/affected-scope.js.map +1 -1
- package/dist/tasks/change-set.d.ts +9 -6
- package/dist/tasks/change-set.d.ts.map +1 -1
- package/dist/tasks/change-set.js +75 -97
- package/dist/tasks/change-set.js.map +1 -1
- package/dist/tasks/command-line.d.ts.map +1 -1
- package/dist/tasks/command-line.js +6 -2
- package/dist/tasks/command-line.js.map +1 -1
- package/dist/tasks/complete.d.ts.map +1 -1
- package/dist/tasks/complete.js +7 -2
- package/dist/tasks/complete.js.map +1 -1
- package/dist/tasks/done-plan.d.ts.map +1 -1
- package/dist/tasks/done-plan.js +111 -29
- package/dist/tasks/done-plan.js.map +1 -1
- package/dist/tasks/done-record.d.ts +14 -0
- package/dist/tasks/done-record.d.ts.map +1 -1
- package/dist/tasks/done-record.js +17 -10
- package/dist/tasks/done-record.js.map +1 -1
- package/dist/tasks/evidence-tree.d.ts +33 -0
- package/dist/tasks/evidence-tree.d.ts.map +1 -0
- package/dist/tasks/evidence-tree.js +132 -0
- package/dist/tasks/evidence-tree.js.map +1 -0
- package/dist/tasks/evidence.d.ts +42 -6
- package/dist/tasks/evidence.d.ts.map +1 -1
- package/dist/tasks/evidence.js +175 -79
- package/dist/tasks/evidence.js.map +1 -1
- package/dist/tasks/gate-preview.d.ts.map +1 -1
- package/dist/tasks/gate-preview.js +3 -2
- package/dist/tasks/gate-preview.js.map +1 -1
- package/dist/tasks/gate-runner.d.ts +11 -3
- package/dist/tasks/gate-runner.d.ts.map +1 -1
- package/dist/tasks/gate-runner.js +156 -37
- package/dist/tasks/gate-runner.js.map +1 -1
- package/dist/tasks/gate-staleness.d.ts +58 -0
- package/dist/tasks/gate-staleness.d.ts.map +1 -0
- package/dist/tasks/gate-staleness.js +78 -0
- package/dist/tasks/gate-staleness.js.map +1 -0
- package/dist/tasks/heavy-tool-env.d.ts +26 -1
- package/dist/tasks/heavy-tool-env.d.ts.map +1 -1
- package/dist/tasks/heavy-tool-env.js +92 -5
- package/dist/tasks/heavy-tool-env.js.map +1 -1
- package/dist/tasks/heavy-tool-limit.d.ts +24 -0
- package/dist/tasks/heavy-tool-limit.d.ts.map +1 -1
- package/dist/tasks/heavy-tool-limit.js +44 -1
- package/dist/tasks/heavy-tool-limit.js.map +1 -1
- package/dist/tasks/show.d.ts.map +1 -1
- package/dist/tasks/show.js +43 -0
- package/dist/tasks/show.js.map +1 -1
- package/dist/tasks/test-run-binding.d.ts +48 -3
- package/dist/tasks/test-run-binding.d.ts.map +1 -1
- package/dist/tasks/test-run-binding.js +111 -3
- package/dist/tasks/test-run-binding.js.map +1 -1
- package/dist/tasks/tool-cache.d.ts +58 -7
- package/dist/tasks/tool-cache.d.ts.map +1 -1
- package/dist/tasks/tool-cache.js +216 -16
- package/dist/tasks/tool-cache.js.map +1 -1
- package/dist/tasks/tool-resolver.d.ts +13 -0
- package/dist/tasks/tool-resolver.d.ts.map +1 -1
- package/dist/tasks/tool-resolver.js +34 -0
- package/dist/tasks/tool-resolver.js.map +1 -1
- package/dist/tasks/tool-runner-guard.d.ts +6 -0
- package/dist/tasks/tool-runner-guard.d.ts.map +1 -1
- package/dist/tasks/tool-runner-guard.js.map +1 -1
- package/dist/tasks/tool-semaphore.js +1 -1
- package/dist/tasks/tool-semaphore.js.map +1 -1
- package/dist/tasks/verification-policy.d.ts +26 -3
- package/dist/tasks/verification-policy.d.ts.map +1 -1
- package/dist/tasks/verification-policy.js +76 -11
- package/dist/tasks/verification-policy.js.map +1 -1
- package/dist/validation/doctor/checks.d.ts +12 -0
- package/dist/validation/doctor/checks.d.ts.map +1 -1
- package/dist/validation/doctor/checks.js +33 -0
- package/dist/validation/doctor/checks.js.map +1 -1
- package/dist/validation/engine-ops.d.ts +6 -0
- package/dist/validation/engine-ops.d.ts.map +1 -1
- package/dist/validation/engine-ops.js +51 -1
- package/dist/validation/engine-ops.js.map +1 -1
- package/dist/worktree/force-unlock.js +2 -2
- package/dist/worktree/force-unlock.js.map +1 -1
- package/dist/worktree/list.d.ts +7 -7
- package/dist/worktree/list.d.ts.map +1 -1
- package/dist/worktree/list.js +11 -56
- package/dist/worktree/list.js.map +1 -1
- package/dist/worktree/prune.d.ts +2 -2
- package/dist/worktree/prune.d.ts.map +1 -1
- package/dist/worktree/prune.js +4 -4
- package/dist/worktree/prune.js.map +1 -1
- package/package.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-runner.d.ts","sourceRoot":"","sources":["../../src/tasks/gate-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAgBH,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,KAAK,EAEL,YAAY,EAIZ,QAAQ,EAER,IAAI,EAEL,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAGV,yBAAyB,EACzB,wBAAwB,EACxB,wBAAwB,EAExB,iCAAiC,EAClC,MAAM,qCAAqC,CAAC;AAO7C,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"gate-runner.d.ts","sourceRoot":"","sources":["../../src/tasks/gate-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,7 +33,7 @@ import { isDeepStrictEqual } from 'node:util';
|
|
|
33
33
|
import { acceptanceGateResultSchema, acceptanceGateSchema, testCountReportSchema, testCountSummarySchema, } from '@cleocode/contracts/acceptance-gate-schema.js';
|
|
34
34
|
import { findOnPath } from '@cleocode/paths';
|
|
35
35
|
import { resolveOriginDefault } from '../git/base-ref.js';
|
|
36
|
-
import { discoveryEnv
|
|
36
|
+
import { discoveryEnv } from '../git/work-tree.js';
|
|
37
37
|
import { getProjectRoot } from '../paths.js';
|
|
38
38
|
import { captureProjectScope, worktreeScope } from '../project-scope.js';
|
|
39
39
|
import { truncateString } from '../render/helpers.js';
|
|
@@ -44,6 +44,7 @@ import { registerTeardownAbort } from '../teardown-signal.js';
|
|
|
44
44
|
import { acItemToText, acTextHash } from './ac-table.js';
|
|
45
45
|
import { splitCommandLine } from './command-line.js';
|
|
46
46
|
import { resolveCanonicalProjectRoot } from './evidence.js';
|
|
47
|
+
import { resolveEvidenceTree } from './evidence-tree.js';
|
|
47
48
|
import { buildGateCacheEntryBody, captureGateCacheState, describeGateCacheMiss, evidenceCacheKeyPath, gateCacheEntryPath, readGateCacheEntry, sealGateCacheEntry, } from './gate-result-cache.js';
|
|
48
49
|
import { planHeavyToolEnv, vitestWorkerCeiling } from './heavy-tool-env.js';
|
|
49
50
|
import { resolveSpawnTimeoutMs } from './tool-cache.js';
|
|
@@ -239,7 +240,7 @@ export async function captureGateInputsHash(task, gate, execution, env = process
|
|
|
239
240
|
* @task T13693
|
|
240
241
|
*/
|
|
241
242
|
export async function captureGateInputs(task, gate, execution, env = process.env) {
|
|
242
|
-
const tree = resolveTypedGateRoot(resolve(execution.identity.projectRoot));
|
|
243
|
+
const tree = resolveTypedGateRoot(resolve(execution.identity.projectRoot), undefined, undefined, task.id);
|
|
243
244
|
const invocation = executableInvocation(gate, tree, { ...env });
|
|
244
245
|
const artifacts = await snapshotGateInputs(task, gate, invocation, execution, tree);
|
|
245
246
|
return {
|
|
@@ -271,18 +272,26 @@ export async function captureGateInputs(task, gate, execution, env = process.env
|
|
|
271
272
|
* or `evidence.gitRoot`) is consulted first, as `resolveEvidenceExecutionRoot`
|
|
272
273
|
* does for evidence tools. Without it, a run whose cwd had been moved to the
|
|
273
274
|
* store root keyed the gate cache to the primary checkout's HEAD even when the
|
|
274
|
-
* caller named its worktree.
|
|
275
|
-
*
|
|
275
|
+
* caller named its worktree.
|
|
276
|
+
*
|
|
277
|
+
* T14058: the tree comes from {@link resolveEvidenceTree}, the resolver
|
|
278
|
+
* change-set binding uses, so typed gates and a bound test-run never measure
|
|
279
|
+
* different checkouts: the invocation's linked worktree of the declared
|
|
280
|
+
* repository wins, and with `taskId` the task's `task/<id>` worktree is chosen
|
|
281
|
+
* from the main checkout. Only this project's checkout or one of its linked
|
|
282
|
+
* worktrees is accepted; any other candidate is skipped.
|
|
276
283
|
*
|
|
277
284
|
* @param projectRoot - CLEO store root (the typed gate's authority).
|
|
278
285
|
* @param cwd - Invocation directory. Defaults to `process.cwd()`.
|
|
279
286
|
* @param env - Where the evidence declaration is read. Defaults to `process.env`.
|
|
287
|
+
* @param taskId - Task whose `task/<id>` worktree may be the tree; null skips that tier.
|
|
280
288
|
* @returns The realpath of the tree typed gates execute in.
|
|
281
289
|
* @task T12625
|
|
282
290
|
* @task T13649
|
|
291
|
+
* @task T14058
|
|
283
292
|
*/
|
|
284
293
|
export function resolveTypedGateRoot(projectRoot, cwd = process.cwd(), // CWD-OK: the invocation tree is the subject (gh#1220)
|
|
285
|
-
env = process.env) {
|
|
294
|
+
env = process.env, taskId = null) {
|
|
286
295
|
const real = (p) => {
|
|
287
296
|
try {
|
|
288
297
|
return realpathSync(p);
|
|
@@ -292,15 +301,9 @@ env = process.env) {
|
|
|
292
301
|
}
|
|
293
302
|
};
|
|
294
303
|
const root = real(projectRoot);
|
|
295
|
-
const ofThisProject = (top) =>
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const declared = resolveDeclaredEvidenceGitRoot(projectRoot, env);
|
|
299
|
-
const declaredTop = declared ? gitToplevel(declared.path) : null;
|
|
300
|
-
// A declaration naming the store root itself is honoured as such.
|
|
301
|
-
if (declaredTop !== null && real(declaredTop) === root)
|
|
302
|
-
return projectRoot;
|
|
303
|
-
return ofThisProject(declaredTop) ?? ofThisProject(gitToplevel(cwd)) ?? projectRoot;
|
|
304
|
+
const ofThisProject = (top) => real(top) === root || real(resolveCanonicalProjectRoot(top)) === root;
|
|
305
|
+
const tree = real(resolveEvidenceTree(projectRoot, taskId, cwd, env, ofThisProject).root);
|
|
306
|
+
return tree === root ? projectRoot : tree;
|
|
304
307
|
}
|
|
305
308
|
/**
|
|
306
309
|
* Admission for a batch run without a caller-owned lifetime.
|
|
@@ -354,7 +357,7 @@ export async function runGates(gates, options = {}) {
|
|
|
354
357
|
if (!Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1)
|
|
355
358
|
throw new RangeError('Gate capture byte limit must be a positive safe integer');
|
|
356
359
|
// T12625: execute and fingerprint in the caller's worktree of this project.
|
|
357
|
-
const treeRoot = resolveTypedGateRoot(projectRoot);
|
|
360
|
+
const treeRoot = resolveTypedGateRoot(projectRoot, undefined, undefined, options.taskId ?? null);
|
|
358
361
|
const snapshot = structuredClone(gates);
|
|
359
362
|
const controller = new AbortController();
|
|
360
363
|
const deregister = registerTeardownAbort(controller);
|
|
@@ -619,7 +622,7 @@ export async function runTaskGates(task, criteria, options) {
|
|
|
619
622
|
assertCriterionProjection(snapshot, rows);
|
|
620
623
|
const env = { ...(options.env ?? process.env) };
|
|
621
624
|
const verificationId = randomUUID();
|
|
622
|
-
const tree = resolveTypedGateRoot(root);
|
|
625
|
+
const tree = resolveTypedGateRoot(root, undefined, undefined, snapshot.id);
|
|
623
626
|
return worktreeScope.run(scope, async () => {
|
|
624
627
|
const results = [];
|
|
625
628
|
for (const [index, gate] of (snapshot.acceptance ?? []).entries()) {
|
|
@@ -669,6 +672,7 @@ export async function runTaskGates(task, criteria, options) {
|
|
|
669
672
|
: (await runGates([gate], {
|
|
670
673
|
...options,
|
|
671
674
|
projectRoot: root,
|
|
675
|
+
taskId: snapshot.id,
|
|
672
676
|
env,
|
|
673
677
|
execution,
|
|
674
678
|
...(options.cache && options.cache !== 'off'
|
|
@@ -986,6 +990,8 @@ function typedRevalidationScope(task, criteria, results, options, requirePassing
|
|
|
986
990
|
results,
|
|
987
991
|
execution,
|
|
988
992
|
root,
|
|
993
|
+
// No task id: completion judges a stored result in the invocation's own
|
|
994
|
+
// tree, so completing from main before the merge stays refused (T12625).
|
|
989
995
|
tree: resolveTypedGateRoot(root, cwd),
|
|
990
996
|
env: { ...(options.env ?? process.env) },
|
|
991
997
|
requirePassing,
|
|
@@ -1668,6 +1674,71 @@ function matchingBrace(text, start) {
|
|
|
1668
1674
|
}
|
|
1669
1675
|
return -1;
|
|
1670
1676
|
}
|
|
1677
|
+
/** Top-level keys that mark a JSON object as an attempted test-count report. */
|
|
1678
|
+
const COUNT_REPORT_KEYS = ['numTotalTests', 'numPassedTests', 'numFailedTests', 'testResults'];
|
|
1679
|
+
/**
|
|
1680
|
+
* Why a parsed candidate was refused: its first schema issue, by field path
|
|
1681
|
+
* (T14060). A report that parsed but failed validation used to be dropped
|
|
1682
|
+
* silently, so the author was told no report existed at all.
|
|
1683
|
+
*/
|
|
1684
|
+
function firstSchemaIssue(error) {
|
|
1685
|
+
const issue = error.issues[0];
|
|
1686
|
+
if (issue === undefined)
|
|
1687
|
+
return 'invalid';
|
|
1688
|
+
return issue.path.length > 0
|
|
1689
|
+
? `${issue.path.map(String).join('.')}: ${issue.message}`
|
|
1690
|
+
: issue.message;
|
|
1691
|
+
}
|
|
1692
|
+
/** Whether `value` is a JSON object carrying any {@link COUNT_REPORT_KEYS}. */
|
|
1693
|
+
function looksLikeCountReport(value) {
|
|
1694
|
+
return (typeof value === 'object' &&
|
|
1695
|
+
value !== null &&
|
|
1696
|
+
COUNT_REPORT_KEYS.some((key) => Object.hasOwn(value, key)));
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Counts from node:test TAP output (`node --test --test-reporter=tap`, also
|
|
1700
|
+
* via `tsx --test`), which ships no JSON reporter (T14051). The run's LAST
|
|
1701
|
+
* top-level plan (`1..N` at column 0) must be followed by its `# tests N`,
|
|
1702
|
+
* `# pass N` and `# fail N` summary; `# cancelled N` counts as failed. Test
|
|
1703
|
+
* console output is re-emitted as indented or `# ` comment lines before that
|
|
1704
|
+
* plan, so it cannot forge the summary.
|
|
1705
|
+
*
|
|
1706
|
+
* @param stdout - The run's captured stdout.
|
|
1707
|
+
* @returns Counts, a refusal reason, or null when the output is not TAP.
|
|
1708
|
+
* @task T14051
|
|
1709
|
+
*/
|
|
1710
|
+
function tapTestCounts(stdout) {
|
|
1711
|
+
const lines = stdout.split(/\r?\n/);
|
|
1712
|
+
if (!lines.some((line) => /^TAP version \d+$/.test(line.trim())))
|
|
1713
|
+
return null;
|
|
1714
|
+
if (lines.some((line) => /^\s*Bail out!/.test(line)))
|
|
1715
|
+
return { refusal: 'its TAP output contains "Bail out!"' };
|
|
1716
|
+
const plan = lines.findLastIndex((line) => /^1\.\.\d+(?:\s|$)/.test(line));
|
|
1717
|
+
if (plan === -1)
|
|
1718
|
+
return { refusal: 'its TAP output has no top-level 1..N plan' };
|
|
1719
|
+
const summary = new Map();
|
|
1720
|
+
for (const line of lines.slice(plan + 1)) {
|
|
1721
|
+
const match = line.match(/^# (tests|pass|fail|cancelled) (\d+)$/);
|
|
1722
|
+
if (match)
|
|
1723
|
+
summary.set(match[1], Number(match[2]));
|
|
1724
|
+
}
|
|
1725
|
+
const tests = summary.get('tests');
|
|
1726
|
+
const pass = summary.get('pass');
|
|
1727
|
+
const fail = summary.get('fail');
|
|
1728
|
+
if (tests === undefined || pass === undefined || fail === undefined)
|
|
1729
|
+
return {
|
|
1730
|
+
refusal: 'its TAP output has no "# tests", "# pass" and "# fail" summary after the plan',
|
|
1731
|
+
};
|
|
1732
|
+
if (tests === 0 || /^1\.\.0(?:\s|$)/.test(lines[plan]))
|
|
1733
|
+
return { refusal: 'its TAP output reports zero tests' };
|
|
1734
|
+
const failed = fail + (summary.get('cancelled') ?? 0);
|
|
1735
|
+
return {
|
|
1736
|
+
numPassedTests: pass,
|
|
1737
|
+
numFailedTests: failed,
|
|
1738
|
+
numTotalTests: tests,
|
|
1739
|
+
success: failed === 0,
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1671
1742
|
/**
|
|
1672
1743
|
* Structured test counts emitted by THIS gate's own process, or `null`.
|
|
1673
1744
|
*
|
|
@@ -1686,32 +1757,59 @@ function matchingBrace(text, start) {
|
|
|
1686
1757
|
* code, at any time. Only the bytes this invocation emitted are bound to it.
|
|
1687
1758
|
*
|
|
1688
1759
|
* A non-runner command (a wrapper script) may instead print a bare count
|
|
1689
|
-
* summary ({@link testCountSummarySchema}) as its last stdout line (T13753)
|
|
1760
|
+
* summary ({@link testCountSummarySchema}) as its last stdout line (T13753),
|
|
1761
|
+
* and node:test may print TAP ({@link tapTestCounts}, T14051).
|
|
1762
|
+
*
|
|
1763
|
+
* A candidate that parses as a count report but fails its schema is recorded
|
|
1764
|
+
* in `refusals` with its first issue (T14060), so the error can say which
|
|
1765
|
+
* report was found and why it was refused.
|
|
1690
1766
|
*
|
|
1691
1767
|
* @param captured - Result of running the gate command.
|
|
1768
|
+
* @param refusals - Receives why each report-like candidate was refused, in the order the
|
|
1769
|
+
* candidates are tried (last stdout line, TAP, then the output newest-first); the
|
|
1770
|
+
* first is the one reported.
|
|
1692
1771
|
* @returns Validated counts, or `null` when the run emitted no usable report.
|
|
1693
1772
|
* @task T12308
|
|
1694
1773
|
* @task T13753
|
|
1774
|
+
* @task T14051
|
|
1775
|
+
* @task T14060
|
|
1695
1776
|
*/
|
|
1696
|
-
function structuredTestCounts(captured) {
|
|
1777
|
+
function structuredTestCounts(captured, refusals) {
|
|
1697
1778
|
const lastLine = captured.stdout.trimEnd().split('\n').at(-1)?.trim() ?? '';
|
|
1698
1779
|
if (lastLine.startsWith('{')) {
|
|
1699
1780
|
try {
|
|
1700
|
-
const
|
|
1781
|
+
const raw = JSON.parse(lastLine);
|
|
1782
|
+
const summary = testCountSummarySchema.safeParse(raw);
|
|
1701
1783
|
if (summary.success)
|
|
1702
1784
|
return summary.data;
|
|
1785
|
+
// A line carrying testResults is a full report: the search below judges it.
|
|
1786
|
+
if (looksLikeCountReport(raw) && !Object.hasOwn(raw, 'testResults'))
|
|
1787
|
+
refusals.push(`the last stdout line is not a count summary (${firstSchemaIssue(summary.error)})`);
|
|
1703
1788
|
}
|
|
1704
1789
|
catch {
|
|
1705
1790
|
// Not JSON: fall through to the full-report search.
|
|
1706
1791
|
}
|
|
1707
1792
|
}
|
|
1793
|
+
const tap = tapTestCounts(captured.stdout);
|
|
1794
|
+
if (tap !== null) {
|
|
1795
|
+
if ('refusal' in tap) {
|
|
1796
|
+
refusals.push(tap.refusal);
|
|
1797
|
+
return null;
|
|
1798
|
+
}
|
|
1799
|
+
return tap;
|
|
1800
|
+
}
|
|
1708
1801
|
const text = `${captured.stdout}\n${captured.stderr}`.trim();
|
|
1709
1802
|
if (text.length === 0)
|
|
1710
1803
|
return null;
|
|
1711
1804
|
const tryParse = (candidate) => {
|
|
1712
1805
|
try {
|
|
1713
|
-
const
|
|
1714
|
-
|
|
1806
|
+
const raw = JSON.parse(candidate);
|
|
1807
|
+
const report = testCountReportSchema.safeParse(raw);
|
|
1808
|
+
if (report.success)
|
|
1809
|
+
return report.data;
|
|
1810
|
+
if (looksLikeCountReport(raw))
|
|
1811
|
+
refusals.push(`a JSON report in its output fails the full report shape (${firstSchemaIssue(report.error)})`);
|
|
1812
|
+
return null;
|
|
1715
1813
|
}
|
|
1716
1814
|
catch {
|
|
1717
1815
|
return null;
|
|
@@ -1820,10 +1918,12 @@ async function fileStamp(path) {
|
|
|
1820
1918
|
*
|
|
1821
1919
|
* @param before - Each candidate's stamp just before the spawn.
|
|
1822
1920
|
* @param startedAt - Epoch ms just before the spawn.
|
|
1921
|
+
* @param refusals - Receives why a fresh report that failed its schema was refused (T14060).
|
|
1823
1922
|
* @returns Validated counts, or null.
|
|
1824
1923
|
* @task T13782
|
|
1924
|
+
* @task T14060
|
|
1825
1925
|
*/
|
|
1826
|
-
async function freshReportCounts(before, startedAt) {
|
|
1926
|
+
async function freshReportCounts(before, startedAt, refusals) {
|
|
1827
1927
|
for (const [path, was] of before) {
|
|
1828
1928
|
const now = await fileStamp(path);
|
|
1829
1929
|
if (now === null || now.mtimeMs < startedAt || (was !== null && was.sha256 === now.sha256))
|
|
@@ -1835,6 +1935,7 @@ async function freshReportCounts(before, startedAt) {
|
|
|
1835
1935
|
const report = testCountReportSchema.safeParse(raw);
|
|
1836
1936
|
if (report.success)
|
|
1837
1937
|
return report.data;
|
|
1938
|
+
refusals.push(`${path} fails the full report shape (${firstSchemaIssue(report.error)})`);
|
|
1838
1939
|
}
|
|
1839
1940
|
catch {
|
|
1840
1941
|
// Unreadable or not JSON: not a report of this run.
|
|
@@ -1849,24 +1950,40 @@ async function freshReportCounts(before, startedAt) {
|
|
|
1849
1950
|
* reader had no way to learn what "supported" meant, what shape was expected,
|
|
1850
1951
|
* or which flag produced it — so the reported resolution was to delete the
|
|
1851
1952
|
* `minCount` from the gate, which removes the guarantee rather than meeting it.
|
|
1953
|
+
* node:test (`node --test`, `tsx --test`) is detected before the package
|
|
1954
|
+
* managers, which run it too and whose `--reporter=json` it rejects (T14051);
|
|
1955
|
+
* a report that was found but refused is named with its first issue (T14060).
|
|
1852
1956
|
*
|
|
1853
1957
|
* @param gate - Gate whose command needs a machine-readable reporter.
|
|
1958
|
+
* @param refusal - Why the newest report-like candidate was refused, if any.
|
|
1854
1959
|
* @task T12308
|
|
1960
|
+
* @task T14051
|
|
1961
|
+
* @task T14060
|
|
1855
1962
|
*/
|
|
1856
|
-
function describeMissingTestCount(gate) {
|
|
1963
|
+
function describeMissingTestCount(gate, refusal) {
|
|
1857
1964
|
const invoked = [gate.command, ...(gate.args ?? [])].join(' ');
|
|
1858
|
-
const flag =
|
|
1859
|
-
? '--
|
|
1860
|
-
: /
|
|
1861
|
-
? '--
|
|
1862
|
-
:
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
`
|
|
1965
|
+
const flag = /\b(?:node|tsx)\b.*\s--test(?![\w-])/.test(invoked)
|
|
1966
|
+
? '--test-reporter=tap'
|
|
1967
|
+
: /jest/.test(invoked)
|
|
1968
|
+
? '--json'
|
|
1969
|
+
: /vitest|pnpm|npm|yarn|bun/.test(invoked)
|
|
1970
|
+
? '--reporter=json'
|
|
1971
|
+
: '<your runner\u2019s JSON reporter flag>';
|
|
1972
|
+
const found = refusal === undefined
|
|
1973
|
+
? `\`${invoked}\` emitted no machine-readable test report`
|
|
1974
|
+
: `\`${invoked}\` emitted a test report that was refused: ${refusal}`;
|
|
1975
|
+
return (`minCount ${gate.minCount} cannot be proved: ${found}, and an exit code alone carries no ` +
|
|
1976
|
+
`count. Add a reporter to the gate command itself (e.g. \`${invoked} ${flag}\`) so the run ` +
|
|
1977
|
+
`that is being attested is the run that is counted. Accepted: a full Vitest/Jest JSON report ` +
|
|
1978
|
+
`(numTotalTests, numPassedTests, numFailedTests, numPendingTests, numTodoTests, the four ` +
|
|
1979
|
+
`numTotal/Passed/Failed/PendingTestSuites counters, success, testResults[].assertionResults, ` +
|
|
1980
|
+
`counters equal to the assertions); a bare summary as the LAST stdout line, at minimum ` +
|
|
1981
|
+
`{"numPassedTests":N} (numFailedTests, numTotalTests and success optional, no testResults); ` +
|
|
1982
|
+
`or node:test TAP (--test-reporter=tap) with its 1..N plan and # tests/# pass/# fail summary. ` +
|
|
1983
|
+
`A report file this run writes (its --outputFile, or ${REDIRECTED_JSON_REPORT}) is read too, ` +
|
|
1984
|
+
`but one produced by a separate invocation is deliberately not accepted \u2014 it is not bound ` +
|
|
1985
|
+
`to this execution; record that as \`test-run:<path>\` evidence instead, or drop minCount if ` +
|
|
1986
|
+
`an exit code is the guarantee you want.`);
|
|
1870
1987
|
}
|
|
1871
1988
|
/**
|
|
1872
1989
|
* Zero-count runner summaries that name failure without reporting any: node:test
|
|
@@ -1917,13 +2034,15 @@ async function runTestGate(gate, index, projectRoot, timeoutMs, context) {
|
|
|
1917
2034
|
const announced = await announcedReportFile(captured.stdout, projectRoot);
|
|
1918
2035
|
if (announced !== null && !before.has(announced))
|
|
1919
2036
|
before.set(announced, null);
|
|
1920
|
-
const
|
|
2037
|
+
const refusals = [];
|
|
2038
|
+
const counts = structuredTestCounts(captured, refusals) ??
|
|
2039
|
+
(await freshReportCounts(before, startedAt, refusals));
|
|
1921
2040
|
// T12308: the counts come from this run's own validated report; only their
|
|
1922
2041
|
// ABSENCE is an error, because inferring a count from exit zero is the thing
|
|
1923
2042
|
// that must not happen. T13753: the error keeps the run's execution record.
|
|
1924
2043
|
if (gate.minCount !== undefined && gate.minCount > 0) {
|
|
1925
2044
|
if (counts === null)
|
|
1926
|
-
return processGateResult(index, gate, captured, 'error', describeMissingTestCount(gate));
|
|
2045
|
+
return processGateResult(index, gate, captured, 'error', describeMissingTestCount(gate, refusals[0]));
|
|
1927
2046
|
if (counts.numPassedTests < gate.minCount)
|
|
1928
2047
|
return processGateResult(index, gate, captured, 'fail', `Structured report counts ${counts.numPassedTests} passing tests, below the required minimum of ${gate.minCount}`);
|
|
1929
2048
|
}
|