@outerlayer/cli 0.34.0-next.20261028010245 → 0.34.0-next.20261028122415

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.
Files changed (123) hide show
  1. package/dist/{agent-setup-6FPE6EYN.js → agent-setup-LZ7PEM6A.js} +6 -6
  2. package/dist/{bridge-JGIHPGMY.js → bridge-4DFOWIY2.js} +2 -2
  3. package/dist/{build-AAQ4PVP2.js → build-VVZHFSZK.js} +8 -8
  4. package/dist/{build-disk-L7JRQA22.js → build-disk-QV4TO7HZ.js} +6 -6
  5. package/dist/build-info.json +1 -1
  6. package/dist/{builder-LMLAVVVF.js → builder-6JLFMAGJ.js} +5 -5
  7. package/dist/{check-C7UKLYZQ.js → check-FWRVWOVY.js} +38 -38
  8. package/dist/{chunk-WEQMLC7P.js → chunk-265SXBQ5.js} +3 -3
  9. package/dist/{chunk-AJTGTSNA.js → chunk-2CW2QMSG.js} +1 -1
  10. package/dist/{chunk-AHWMY3MS.js → chunk-2LCNMAWP.js} +4 -4
  11. package/dist/{chunk-SWCOWG2C.js → chunk-3EU4MWCE.js} +3 -3
  12. package/dist/{chunk-L2OARQKP.js → chunk-4N7BQBO4.js} +28 -13
  13. package/dist/{chunk-6OLXDSQ6.js → chunk-5B6DLEVM.js} +1 -1
  14. package/dist/{chunk-QNF7LT7W.js → chunk-5VKSPEST.js} +3 -3
  15. package/dist/{chunk-3X6OSXSB.js → chunk-64LLUVJR.js} +1 -1
  16. package/dist/{chunk-WSVE5QGL.js → chunk-6CQXOTNL.js} +4 -4
  17. package/dist/{chunk-GJYGOFF3.js → chunk-72N7GOLM.js} +6 -6
  18. package/dist/{chunk-4A5OJOCR.js → chunk-7DHESPSV.js} +10 -10
  19. package/dist/{chunk-VB4QD4WN.js → chunk-7JBG43BX.js} +67 -25
  20. package/dist/{chunk-EGJY6MBC.js → chunk-7LKOOGSN.js} +2 -2
  21. package/dist/{chunk-KTVZ7TZY.js → chunk-7XZQTJOD.js} +1 -1
  22. package/dist/{chunk-A6PJSNP6.js → chunk-A2KLVZBU.js} +31 -29
  23. package/dist/{chunk-BQ4C47K2.js → chunk-AGNFPJSP.js} +5 -5
  24. package/dist/{chunk-JXY66VYX.js → chunk-AKQX462F.js} +3 -3
  25. package/dist/{chunk-5LUN7TTR.js → chunk-AVI3MGQO.js} +2 -2
  26. package/dist/{chunk-3XOLOV5A.js → chunk-AXKSVN4U.js} +4 -4
  27. package/dist/{work-proofs-record-LIQGUDWH.js → chunk-BEGMZKMG.js} +176 -497
  28. package/dist/{chunk-QJ2SNBHL.js → chunk-BUVDDPOM.js} +1 -1
  29. package/dist/{chunk-32FAPJFD.js → chunk-C2E4PWEN.js} +6 -6
  30. package/dist/{chunk-57WFXHCB.js → chunk-D7MWJM2G.js} +1 -1
  31. package/dist/{chunk-G4SOMWXL.js → chunk-DKIZDYUX.js} +1 -1
  32. package/dist/{chunk-I4YOWQH7.js → chunk-E3GX4WVJ.js} +1 -1
  33. package/dist/{chunk-F3BGTGQC.js → chunk-EXKOPZQV.js} +1 -1
  34. package/dist/{chunk-BTDBDTUY.js → chunk-GJHOU5V3.js} +3 -3
  35. package/dist/{chunk-D6SH7DWA.js → chunk-H5YUWLIY.js} +3 -3
  36. package/dist/{chunk-PAGB3DCI.js → chunk-IZKUPAXF.js} +1 -1
  37. package/dist/{chunk-GET5HKLM.js → chunk-JDQBJUXQ.js} +1 -1
  38. package/dist/{chunk-23XAA7YD.js → chunk-LEJWPGO7.js} +3 -3
  39. package/dist/{chunk-NBETYM32.js → chunk-N4KQMGEZ.js} +4 -4
  40. package/dist/{chunk-4J5GRWAY.js → chunk-N6V4ZHI7.js} +2 -2
  41. package/dist/{chunk-PHIQHIRJ.js → chunk-NPTEYMBW.js} +1 -1
  42. package/dist/{chunk-3E7QAXUW.js → chunk-OFKM35MX.js} +6 -6
  43. package/dist/{chunk-LBKCYEJT.js → chunk-ORENXMHA.js} +1 -1
  44. package/dist/{chunk-6Q7O4MRI.js → chunk-QGTJ5IJN.js} +1 -1
  45. package/dist/{chunk-5IUC2B6J.js → chunk-QTL7VZVF.js} +2 -2
  46. package/dist/{chunk-GXMMILQ4.js → chunk-QXAPVAPR.js} +3 -3
  47. package/dist/{chunk-6LS62EO4.js → chunk-S37IAT3A.js} +3 -3
  48. package/dist/{chunk-PPQTTJSW.js → chunk-SODV2YMW.js} +5 -5
  49. package/dist/{chunk-SYMBXSAT.js → chunk-SX3LYSWR.js} +3 -3
  50. package/dist/{chunk-77D5ENBA.js → chunk-TZXJSNN4.js} +1 -1
  51. package/dist/{chunk-HFMK2R7O.js → chunk-U3O7MULV.js} +20 -20
  52. package/dist/{chunk-GMEXR6PY.js → chunk-UDMFRKFJ.js} +6 -6
  53. package/dist/{chunk-NCKH3KCM.js → chunk-UKEIJKCH.js} +25 -12
  54. package/dist/{chunk-VKYU4HHW.js → chunk-VJQQVTCS.js} +1 -1
  55. package/dist/{chunk-UEDRRWZ3.js → chunk-XDCD4GD5.js} +3 -3
  56. package/dist/{chunk-PBI4CM4M.js → chunk-YGU43DH4.js} +57 -27
  57. package/dist/{chunk-NOEJGR4X.js → chunk-ZIXLG6EQ.js} +3 -3
  58. package/dist/{claude-launcher-GGZEWVYJ.js → claude-launcher-XX2MLBDW.js} +1 -1
  59. package/dist/{cli-IG52447Q.js → cli-K7AWWU6C.js} +112 -112
  60. package/dist/{command-NSTOWAZ6.js → command-GJKJ5WT4.js} +25 -25
  61. package/dist/{config-YPUOOZB6.js → config-AB5Y73BU.js} +7 -7
  62. package/dist/{connect-cmd-RPEEANNE.js → connect-cmd-FOD7PKVW.js} +6 -6
  63. package/dist/{container-start-OOBTGHWF.js → container-start-XGKAKLUD.js} +32 -32
  64. package/dist/{context-show-cmd-R5WCECOT.js → context-show-cmd-A226Q6K5.js} +7 -7
  65. package/dist/{control-plane-launch-55CJGYBK.js → control-plane-launch-RJSAIFEP.js} +5 -5
  66. package/dist/{demo-record-cmd-SFOWQPL7.js → demo-record-cmd-KM2UPWPL.js} +2 -2
  67. package/dist/{demo-voice-cmd-ZOBRVHOK.js → demo-voice-cmd-W4NYPCVL.js} +12 -12
  68. package/dist/{dist-BUSLJNSZ.js → dist-ZW7I72SD.js} +1 -1
  69. package/dist/{docker-VPJW5LXB.js → docker-OQP6NU7P.js} +5 -5
  70. package/dist/{doctor-O2EJAPZB.js → doctor-OXMOYIKK.js} +25 -25
  71. package/dist/{emit-artifact-cmd-HBFYBXJR.js → emit-artifact-cmd-X2YWXLKQ.js} +11 -11
  72. package/dist/{emit-criteria-cmd-TPUL7M2R.js → emit-criteria-cmd-HYKOTFXG.js} +8 -8
  73. package/dist/{emit-demo-cmd-5CUT7W3R.js → emit-demo-cmd-DTARV6RI.js} +12 -12
  74. package/dist/{emit-finding-cmd-IKHGMACP.js → emit-finding-cmd-GSLYQC43.js} +8 -8
  75. package/dist/{emit-result-cmd-F7CI6SNZ.js → emit-result-cmd-PKJH76NG.js} +10 -10
  76. package/dist/{emit-step-cmd-DVEKGHK7.js → emit-step-cmd-IW2Y4N67.js} +8 -8
  77. package/dist/{exec-client-H2JG36OS.js → exec-client-BQIZRROT.js} +3 -3
  78. package/dist/find-unit-2C6EK5YY.js +19 -0
  79. package/dist/{findings-cmd-ODKZ462L.js → findings-cmd-CFF2I3TU.js} +8 -8
  80. package/dist/{fleet-readiness-UHCBNW6A.js → fleet-readiness-ZSG4UDYR.js} +5 -5
  81. package/dist/{governing-source-SRECHKPR.js → governing-source-TUGE7QJY.js} +10 -10
  82. package/dist/{guest-init-6FUC4XZX.js → guest-init-DXXSPKHY.js} +4 -4
  83. package/dist/{hook-fast-WM6YZVBJ.js → hook-fast-5C4MQ5ZS.js} +1 -1
  84. package/dist/{host-checks-FLIHLR35.js → host-checks-L4GX6F3H.js} +30 -30
  85. package/dist/{host-key-OSWPVMIA.js → host-key-5P3ZL5XW.js} +3 -3
  86. package/dist/{image-tag-LF3NEGSL.js → image-tag-3KPTSRB4.js} +3 -3
  87. package/dist/index.js +4 -4
  88. package/dist/{init-LPD75DCX.js → init-NSTWRPRM.js} +22 -22
  89. package/dist/{init-OX677NNB.js → init-WU2S3WRO.js} +22 -22
  90. package/dist/{init-cmd-ZCLVC5RR.js → init-cmd-H4HYM5V3.js} +11 -11
  91. package/dist/{init-update-POKSLQDQ.js → init-update-WOYX2AIO.js} +9 -9
  92. package/dist/{install-cmd-6SQVZEXL.js → install-cmd-6HGNO2HF.js} +5 -5
  93. package/dist/{logs-QHXZTSKZ.js → logs-E2O53NUI.js} +2 -2
  94. package/dist/{loop-ELTO36MN.js → loop-GQLSSBQB.js} +37 -37
  95. package/dist/{machine-7VPFAC6L.js → machine-IRBCGRUO.js} +22 -22
  96. package/dist/{mcp-serve-cmd-J32K42HM.js → mcp-serve-cmd-OFK3CS2T.js} +4 -4
  97. package/dist/{paths-4ZGWWNTG.js → paths-VQ3ALYZ3.js} +2 -2
  98. package/dist/{pending-CRXJKKKI.js → pending-V5FBWIJ4.js} +3 -3
  99. package/dist/{pidfile-VLZPRIBZ.js → pidfile-AVJFRZZT.js} +3 -3
  100. package/dist/{record-4ZJPJTWO.js → record-XE7Z3QGF.js} +3 -3
  101. package/dist/{runner-env-W53VDVOK.js → runner-env-TYGE6BFU.js} +9 -9
  102. package/dist/{runner-identity-BH42S2MU.js → runner-identity-B2MZQFYN.js} +5 -5
  103. package/dist/{runner-key-ESAZRV3A.js → runner-key-NPPEGU6H.js} +22 -22
  104. package/dist/{session-sender-UB45MUKV.js → session-sender-ZS4OIE3M.js} +11 -11
  105. package/dist/{spec-cmd-H5B55O5L.js → spec-cmd-N45YF6UL.js} +9 -9
  106. package/dist/{status-L2OYAZHY.js → status-EP6QSFRY.js} +30 -30
  107. package/dist/{sync-cmd-IWA5ZTI2.js → sync-cmd-VCB4YDCB.js} +10 -10
  108. package/dist/{update-steps-FWQ5ASZ6.js → update-steps-BJB7NL6L.js} +31 -31
  109. package/dist/{watch-NOEBVS6U.js → watch-XU2AUR6Z.js} +10 -10
  110. package/dist/{work-claim-cmd-7P7U3OQ6.js → work-claim-cmd-WEP3OWAU.js} +13 -13
  111. package/dist/{work-cmd-77GUT7LY.js → work-cmd-DWR27TKQ.js} +8 -8
  112. package/dist/{work-comment-cmd-VS3BSPGM.js → work-comment-cmd-HSDVPYWM.js} +9 -9
  113. package/dist/{work-demo-cmd-S3GXBYIA.js → work-demo-cmd-3EQYHRBP.js} +8 -8
  114. package/dist/{work-logs-cmd-6BXIINCM.js → work-logs-cmd-3YACDH7Y.js} +8 -8
  115. package/dist/{work-open-pr-cmd-EPOFWJDC.js → work-open-pr-cmd-MHVTTTLD.js} +9 -9
  116. package/dist/{work-pr-cmd-DYSYOP74.js → work-pr-cmd-XETSFFM2.js} +8 -8
  117. package/dist/{work-proofs-cmd-DS2VX4E4.js → work-proofs-cmd-RYQ7Y6KO.js} +10 -10
  118. package/dist/work-proofs-record-IC3RWDDQ.js +509 -0
  119. package/dist/{work-stop-cmd-HYQTDNUY.js → work-stop-cmd-4BE2B7TY.js} +8 -8
  120. package/package.json +1 -1
  121. package/skill-pack/maintained/outerlayer-build/scripts/criterion-citations.mjs +44 -4
  122. package/dist/chunk-6CK2OC4Q.js +0 -152
  123. package/dist/find-unit-ACTOZVVS.js +0 -19
@@ -1,87 +1,131 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { resolveProofsItem, ownPullRequest, proofsCommentId, otherPullRequestHeads, classifyProofsAt, kindProblem, proofsCommentBody, runWorkProofs } from './chunk-NCKH3KCM.js';
4
- import { runWorkComment } from './chunk-D6SH7DWA.js';
5
- import './chunk-6CK2OC4Q.js';
6
- import { runEmitDemo } from './chunk-WSVE5QGL.js';
7
- import { readNewestDemo } from './chunk-ER6KQCVJ.js';
8
- import { runEmitArtifact } from './chunk-3XOLOV5A.js';
9
- import { runSync } from './chunk-32FAPJFD.js';
10
- import './chunk-NOEJGR4X.js';
11
- import './chunk-ESVW4MJY.js';
12
- import './chunk-TBT347UY.js';
13
- import './chunk-2PGI6RDE.js';
14
- import './chunk-D3CT6XQ4.js';
15
- import { WorkCommandError, resolveCredentials, getJson } from './chunk-GJYGOFF3.js';
16
- import './chunk-IP7BIBXJ.js';
17
- import './chunk-BTDBDTUY.js';
18
- import './chunk-4J5GRWAY.js';
19
- import './chunk-NWHU5G6R.js';
20
- import './chunk-G2JWZDFA.js';
21
- import './chunk-ANPNT6PM.js';
22
- import './chunk-IXPH4EXK.js';
23
- import './chunk-LYCJQOO2.js';
24
- import { defaultFetch } from './chunk-PAGB3DCI.js';
25
- import './chunk-PJDQPF5N.js';
26
- import './chunk-VKYU4HHW.js';
27
- import './chunk-57WFXHCB.js';
28
- import './chunk-ZJSNLVCE.js';
29
- import './chunk-2O5KA67H.js';
30
- import './chunk-BKO6JEZI.js';
31
- import './chunk-HCVLP7XA.js';
32
- import './chunk-BJ3KTMDH.js';
33
- import './chunk-OVNF4LLC.js';
34
- import { resolveRepoIdentity } from './chunk-A6PJSNP6.js';
35
- import './chunk-5BHIBJDA.js';
36
- import './chunk-CDDED64E.js';
37
- import './chunk-RA3O54FC.js';
38
- import './chunk-T2Q7ISPE.js';
39
- import './chunk-WZBHBH3J.js';
40
- import './chunk-CRB3POP4.js';
41
- import './chunk-URIZRCRY.js';
42
- import './chunk-YQR6E6OV.js';
43
- import './chunk-TUSYOL2O.js';
3
+ import { sanitizeTerminal } from './chunk-IXPH4EXK.js';
4
+ import { resolvePackRoot } from './chunk-OVNF4LLC.js';
44
5
  import { parseProofsConfig } from './chunk-XFJ7YOPD.js';
45
- import { ARTIFACT_MAX_CAPTION_LENGTH } from './chunk-DINRXUQA.js';
46
- import './chunk-VNVZDWO3.js';
47
- import './chunk-AJTGTSNA.js';
48
- import './chunk-L2OARQKP.js';
49
- import './chunk-MESOOLF4.js';
50
- import './chunk-Z5GEFMRW.js';
51
- import { spawnSync, spawn } from 'child_process';
52
- import { mkdtempSync, rmSync, openSync, closeSync, readdirSync, readFileSync } from 'fs';
53
- import { tmpdir } from 'os';
6
+ import { CHECK_ITEM_REASON_MAX_LENGTH, CheckItemsSchema } from './chunk-DINRXUQA.js';
7
+ import { createHash } from 'crypto';
54
8
  import { join } from 'path';
9
+ import { pathToFileURL } from 'url';
55
10
 
56
11
  createRequire(import.meta.url);
57
- var runShell = (command, params) => {
58
- const logPath = join(params.logDir, `${params.groups.length}-${Date.now()}.log`);
59
- const fd = openSync(logPath, "w");
60
- return new Promise((resolve) => {
61
- const child = spawn("sh", ["-c", command], { cwd: params.cwd, env: params.env, detached: true, stdio: ["ignore", fd, fd] });
62
- closeSync(fd);
63
- if (child.pid !== void 0) params.groups.push(child.pid);
64
- let timedOut = false;
65
- const timer = setTimeout(() => {
66
- timedOut = true;
67
- try {
68
- process.kill(-child.pid, "SIGKILL");
69
- } catch {
70
- }
71
- }, params.timeoutMs);
72
- const finish = (status) => {
73
- clearTimeout(timer);
74
- let text = "";
75
- try {
76
- text = readFileSync(logPath, "utf8");
77
- } catch {
78
- }
79
- resolve({ status, timedOut, tail: text.trimEnd().split("\n").slice(-8).join("\n") });
12
+ var ARTIFACT_PROOF_REASON = "Its declared artifact proves it; the judge does not judge artifacts.";
13
+ var NO_CITING_TEST_REASON = "No test cites this criterion, and it declares no artifact proof.";
14
+ var NO_TEST_FILES_REASON = "No file at this commit is recognized as a test. Name the repository's test files with a runner glob in `.outerlayer-proofs.yaml`.";
15
+ var NO_VERDICT_REASON = "The judge gave no result for this criterion.";
16
+ function criterionInputs(input) {
17
+ const paths = [...new Set((input.citations[input.criterion.id] ?? []).map((citation) => citation.path))].sort();
18
+ const hash = createHash("sha256");
19
+ const part = (text) => {
20
+ hash.update(`${Buffer.byteLength(text)}:`);
21
+ hash.update(text);
22
+ };
23
+ part("judge-criterion-v1");
24
+ part(input.brief);
25
+ part(input.criterion.id);
26
+ part(input.criterion.text);
27
+ part(input.criterion.proof ?? "");
28
+ for (const path2 of paths) {
29
+ part(path2);
30
+ part(input.testFiles.get(path2) ?? "");
31
+ }
32
+ return hash.digest("hex");
33
+ }
34
+ var HTTPS_LINK = /^https:\/\/\S+$/;
35
+ function refsFor(id, citations) {
36
+ const refs = (citations[id] ?? []).slice(0, 20).map((citation) => ({
37
+ path: citation.path,
38
+ line: citation.line,
39
+ // Only an https link becomes an href on a page; any other is left off rather than refusing the check.
40
+ ...HTTPS_LINK.test(citation.href ?? "") ? { href: citation.href } : {}
41
+ }));
42
+ return refs.length === 0 ? void 0 : refs;
43
+ }
44
+ function planCriteria(input) {
45
+ const previousById = new Map(input.previous.map((item) => [item.id, item]));
46
+ const settled = [];
47
+ const toJudge = [];
48
+ for (const criterion of input.criteria) {
49
+ const inputs = input.inputs.get(criterion.id);
50
+ const base = { id: criterion.id, criterion: criterion.id, ...inputs === void 0 ? {} : { inputs } };
51
+ const refs = refsFor(criterion.id, input.citations);
52
+ if (criterion.proof !== null) {
53
+ settled.push({ ...base, result: "skipped", reason: ARTIFACT_PROOF_REASON });
54
+ continue;
55
+ }
56
+ if (refs === void 0) {
57
+ settled.push({ ...base, result: "fail", reason: input.noTestFiles === true ? NO_TEST_FILES_REASON : NO_CITING_TEST_REASON });
58
+ continue;
59
+ }
60
+ const kept = previousById.get(criterion.id);
61
+ if (kept !== void 0 && inputs !== void 0 && kept.inputs === inputs && (kept.result === "pass" || kept.result === "fail")) {
62
+ settled.push({ ...base, result: kept.result, ...kept.reason === void 0 ? {} : { reason: kept.reason }, refs });
63
+ continue;
64
+ }
65
+ toJudge.push(criterion);
66
+ }
67
+ return { settled, toJudge };
68
+ }
69
+ var MAX_ANSWER_ENTRIES = 500;
70
+ function readAnswer(raw) {
71
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return { ok: false, problem: "expected an object" };
72
+ const { result, items } = raw;
73
+ if (result !== void 0 && result !== "pass" && result !== "fail") return { ok: false, problem: 'result: must be "pass" or "fail"' };
74
+ if (items !== void 0 && !Array.isArray(items)) return { ok: false, problem: "items: must be an array" };
75
+ const entries = items ?? [];
76
+ if (entries.length > MAX_ANSWER_ENTRIES) return { ok: false, problem: `items: at most ${MAX_ANSWER_ENTRIES} entries` };
77
+ const read = [];
78
+ for (const [index, entry] of entries.entries()) {
79
+ const { id, result: itemResult, reason } = typeof entry === "object" && entry !== null ? entry : {};
80
+ if (typeof id !== "string" || id === "" || id.length > 200) return { ok: false, problem: `items.${index}.id: must be text of 1 to 200 characters` };
81
+ if (itemResult !== "pass" && itemResult !== "fail") return { ok: false, problem: `items.${index}.result: must be "pass" or "fail"` };
82
+ if (reason !== void 0 && typeof reason !== "string") return { ok: false, problem: `items.${index}.reason: must be text` };
83
+ read.push({ id, result: itemResult, ...reason === void 0 ? {} : { reason } });
84
+ }
85
+ return { ok: true, answer: { ...result === void 0 ? {} : { result }, items: read } };
86
+ }
87
+ function parseJudgeAnswer(text) {
88
+ if (text === void 0 || text.trim() === "") return void 0;
89
+ let raw;
90
+ try {
91
+ raw = JSON.parse(text);
92
+ } catch {
93
+ return { ok: false, reason: "the judge's items.json is not JSON" };
94
+ }
95
+ const read = readAnswer(raw);
96
+ return read.ok ? read : { ok: false, reason: `the judge's items.json does not match its shape: ${read.problem}` };
97
+ }
98
+ function oneLineReason(text) {
99
+ if (text === void 0) return void 0;
100
+ const line = text.replace(/\s+/g, " ").trim();
101
+ if (line === "") return void 0;
102
+ return line.length <= CHECK_ITEM_REASON_MAX_LENGTH ? line : `${line.slice(0, CHECK_ITEM_REASON_MAX_LENGTH - 1)}\u2026`;
103
+ }
104
+ function judgedItems(input) {
105
+ return input.toJudge.map((criterion) => {
106
+ const said = input.results.get(criterion.id);
107
+ const inputs = input.inputs.get(criterion.id);
108
+ const refs = refsFor(criterion.id, input.citations);
109
+ const reason = said === void 0 ? NO_VERDICT_REASON : oneLineReason(said.reason);
110
+ return {
111
+ id: criterion.id,
112
+ criterion: criterion.id,
113
+ result: said?.result ?? "fail",
114
+ ...reason === void 0 ? {} : { reason },
115
+ ...refs === void 0 ? {} : { refs },
116
+ ...inputs === void 0 || said === void 0 ? {} : { inputs }
80
117
  };
81
- child.on("error", () => finish(null));
82
- child.on("exit", (status) => finish(status));
83
118
  });
84
- };
119
+ }
120
+ function inCriteriaOrder(items, criteria) {
121
+ const order = new Map(criteria.map((criterion, index) => [criterion.id, index]));
122
+ return [...items].sort((a, b) => (order.get(a.id) ?? Number.MAX_SAFE_INTEGER) - (order.get(b.id) ?? Number.MAX_SAFE_INTEGER));
123
+ }
124
+ function itemsSentence(items, noun) {
125
+ const failing = items.filter((item) => item.result === "fail").map((item) => item.id);
126
+ if (failing.length === 0) return void 0;
127
+ return `${failing.length} of ${items.length} ${items.length === 1 ? noun.one : noun.many} not satisfied: ${failing.join(", ")}`;
128
+ }
85
129
 
86
130
  // ../../node_modules/balanced-match/dist/esm/index.js
87
131
  var balanced = (a, b, str) => {
@@ -1953,431 +1997,66 @@ minimatch.Minimatch = Minimatch;
1953
1997
  minimatch.escape = escape;
1954
1998
  minimatch.unescape = unescape;
1955
1999
 
1956
- // src/work-proofs-tests.ts
1957
- var ID_CHARACTER = "A-Za-z0-9_-";
1958
- function escapeRegExp(text) {
1959
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1960
- }
1961
- function containsId(text, id) {
1962
- return new RegExp(`(?<![${ID_CHARACTER}])${escapeRegExp(id)}(?![${ID_CHARACTER}])`).test(text);
1963
- }
1964
- function runnerFor(path2, runners) {
1965
- const index = runners.findIndex((runner) => minimatch(path2, runner.files, { dot: true }));
1966
- return index === -1 ? void 0 : index;
1967
- }
1968
- function planRuns(files, runners) {
1969
- const plan = /* @__PURE__ */ new Map();
1970
- for (const file of [...files].sort()) {
1971
- const index = runnerFor(file, runners);
1972
- if (index === void 0) continue;
1973
- plan.set(index, [...plan.get(index) ?? [], file]);
1974
- }
1975
- return new Map([...plan].sort(([a], [b]) => a - b));
1976
- }
1977
- function shellQuote(text) {
1978
- const path2 = text.startsWith("-") ? `./${text}` : text;
1979
- if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(path2)) return path2;
1980
- return `'${path2.replace(/'/g, `'\\''`)}'`;
1981
- }
1982
- function fillFiles(command, files) {
1983
- const quoted = files.map(shellQuote).join(" ");
1984
- return command.split("{files}").join(quoted);
1985
- }
1986
- function proofFileCriterion(name, declared) {
1987
- const dot = name.lastIndexOf(".");
1988
- if (dot <= 0) return void 0;
1989
- const stem = name.slice(0, dot);
1990
- return declared.has(stem) ? stem : void 0;
1991
- }
1992
- function git(root, args, accepted = [0]) {
1993
- const result = spawnSync("git", args, { cwd: root, encoding: "utf8", maxBuffer: 268435456 });
1994
- if (result.error !== void 0 || !accepted.includes(result.status)) {
1995
- throw new WorkCommandError(`git ${args[0]} failed (${result.error?.message ?? `exit status ${result.status}`}), so the tests that name a proof cannot be found.`);
1996
- }
1997
- return result.stdout;
1998
- }
1999
- function discoverTestFiles(root, ids, runners) {
2000
- const found = /* @__PURE__ */ new Map();
2001
- if (ids.length === 0 || runners.length === 0) return found;
2002
- const grep = git(root, ["grep", "-z", "-l", "-I", "-F", ...ids.flatMap((id) => ["-e", id]), "HEAD", "--"], [0, 1]);
2003
- const paths = grep.split("\0").filter((entry) => entry !== "").map((entry) => entry.slice("HEAD:".length)).filter((path2) => runnerFor(path2, runners) !== void 0).sort();
2004
- for (const path2 of paths) {
2005
- const shown = git(root, ["show", `HEAD:${path2}`]);
2006
- for (const id of ids) {
2007
- if (containsId(shown, id)) found.set(id, [...found.get(id) ?? [], path2]);
2008
- }
2009
- }
2010
- return found;
2011
- }
2012
-
2013
- // src/work-proofs-record.ts
2014
- var CONFIG_FILE = ".outerlayer-proofs.yaml";
2015
- var DEFAULT_TIMEOUT_MS = 10 * 60 * 1e3;
2016
- var DEMO_PROOFS = /* @__PURE__ */ new Set(["screenshot", "video"]);
2017
- var NO_TEST = "no test at HEAD names this criterion";
2018
- function changedTrackedFiles(root) {
2019
- const status = spawnSync("git", ["status", "--porcelain=v1", "-z", "--untracked-files=no"], { cwd: root, encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
2020
- if (status.error !== void 0 || status.status !== 0) {
2021
- throw new WorkCommandError(`git cannot say whether the working copy matches HEAD (${status.error?.message ?? `exit status ${status.status}`}), so nothing was recorded.`);
2022
- }
2023
- const fields = status.stdout.split("\0").filter((field) => field !== "");
2024
- const paths = [];
2025
- for (let i = 0; i < fields.length; i += 1) {
2026
- const field = fields[i];
2027
- paths.push(field.slice(3));
2028
- if (/[RC]/.test(field.slice(0, 2))) i += 1;
2029
- }
2030
- return paths;
2000
+ // src/runner-globs.ts
2001
+ var MAX_GLOB_ALTERNATIVES = 256;
2002
+ var MAX_GLOB_LENGTH = 1024;
2003
+ var MAX_GLOB_STARS_PER_SEGMENT = 3;
2004
+ var EXTGLOB = /[+*?@!]\(/;
2005
+ function compile(glob) {
2006
+ if (glob.length > MAX_GLOB_LENGTH) return `it is longer than ${MAX_GLOB_LENGTH} characters`;
2007
+ if (braceExpand(glob, { braceExpandMax: MAX_GLOB_ALTERNATIVES + 1 }).length > MAX_GLOB_ALTERNATIVES) {
2008
+ return `its braces expand to more than ${MAX_GLOB_ALTERNATIVES} alternatives`;
2009
+ }
2010
+ if (EXTGLOB.test(glob)) return "it uses an extended glob form such as +(...) or !(...), which can take exponential time to match";
2011
+ const crowded = glob.split("/").some((segment) => segment !== "**" && segment.split("*").length - 1 > MAX_GLOB_STARS_PER_SEGMENT);
2012
+ if (crowded) return `a path segment of it holds more than ${MAX_GLOB_STARS_PER_SEGMENT} "*" characters, which can take too long to match`;
2013
+ return new Minimatch(glob, { dot: true });
2031
2014
  }
2032
- function topLevelFiles(folder) {
2033
- try {
2034
- return readdirSync(folder, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
2035
- } catch {
2036
- return [];
2037
- }
2038
- }
2039
- function chapterCriteria(manifestPath) {
2040
- const ids = /* @__PURE__ */ new Set();
2041
- try {
2042
- const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
2043
- for (const chapter of parsed.chapters ?? []) {
2044
- if (typeof chapter?.criterionId === "string") ids.add(chapter.criterionId);
2045
- }
2046
- } catch {
2047
- }
2048
- return ids;
2049
- }
2050
- function showAtHead(root, path2) {
2051
- const shown = spawnSync("git", ["show", `HEAD:${path2}`], { cwd: root, encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
2052
- return shown.status === 0 ? shown.stdout : void 0;
2053
- }
2054
- function findManifests(folder) {
2055
- const found = [];
2056
- let entries = [];
2057
- try {
2058
- entries = readdirSync(folder, { withFileTypes: true });
2059
- } catch {
2060
- }
2061
- for (const entry of entries) {
2062
- const path2 = join(folder, entry.name);
2063
- if (entry.isDirectory()) found.push(...findManifests(path2));
2064
- else if (entry.name === "manifest.json" && folder.split("/").pop() === "demo") found.push(path2);
2065
- }
2066
- return found;
2015
+ function runnerMatcher(runners) {
2016
+ const matchers = runners.map((runner) => {
2017
+ const compiled = compile(runner.files);
2018
+ if (typeof compiled === "string") {
2019
+ process.stderr.write(`The runner glob ${JSON.stringify(sanitizeTerminal(runner.files.slice(0, 80)))} matches no file: ${compiled}.
2020
+ `);
2021
+ }
2022
+ return compiled;
2023
+ });
2024
+ return (path2) => {
2025
+ const index = matchers.findIndex((matcher) => typeof matcher !== "string" && matcher.match(path2));
2026
+ return index === -1 ? void 0 : index;
2027
+ };
2067
2028
  }
2068
- function unstoredUploads(result, spooled) {
2069
- if (typeof result !== "object" || result === null) return [];
2070
- const { artifactsDropped, artifactsHeld, rejected, uploadedArtifacts } = result;
2071
- if (Array.isArray(uploadedArtifacts)) {
2072
- const stored = new Set(uploadedArtifacts.map((a) => a?.artifactId));
2073
- return spooled.filter((id) => !stored.has(id));
2074
- }
2075
- const lost = typeof artifactsDropped === "number" && artifactsDropped > 0 || typeof artifactsHeld === "number" && artifactsHeld > 0 || Array.isArray(rejected) && rejected.length > 0;
2076
- return lost ? "all" : [];
2029
+ var MAX_TEST_FILES = 2e4;
2030
+ var MAX_TEST_FILE_BYTES = 1024 * 1024;
2031
+ async function loadCitationFinder() {
2032
+ return await import(pathToFileURL(join(resolvePackRoot(), "maintained", "outerlayer-build", "scripts", "criterion-citations.mjs")).href);
2077
2033
  }
2078
- function shortSha(sha) {
2079
- return sha.slice(0, 7);
2034
+ function testFileMatcher(finder, proofsText) {
2035
+ const parsed = proofsText === void 0 ? void 0 : parseProofsConfig(proofsText);
2036
+ const runners = parsed?.ok === true ? parsed.value.runners : [];
2037
+ const runnerFor = runnerMatcher(runners);
2038
+ const inRunnerGlob = (path2) => runnerFor(path2) !== void 0;
2039
+ return (path2) => finder.isTestFile(path2, inRunnerGlob);
2080
2040
  }
2081
- function oneLine(text) {
2082
- return text.replace(/\s+/g, " ").trim();
2041
+ function criteriaOf(workItem) {
2042
+ const criteria = Object(Object(workItem).criteria);
2043
+ if (!Array.isArray(criteria.items)) return void 0;
2044
+ const drafted = criteria.drafted === true;
2045
+ const items = [];
2046
+ for (const entry of criteria.items) {
2047
+ const { id, text, proof } = Object(entry);
2048
+ if (typeof id !== "string" || typeof text !== "string") continue;
2049
+ items.push({ id, text, proof: typeof proof === "string" ? proof : null, drafted });
2050
+ }
2051
+ return items.length === 0 ? void 0 : items;
2083
2052
  }
2084
- async function runWorkProofsRecord(opts) {
2085
- const env = opts.env ?? process.env;
2086
- const item = resolveProofsItem({ item: opts.item, env });
2087
- const cwd = opts.cwd ?? process.cwd();
2088
- const identity = resolveRepoIdentity(cwd);
2089
- if (identity.repoRoot === void 0 || identity.commitSha === void 0) {
2090
- throw new WorkCommandError("this is not a git checkout with a commit. Run this inside the repository, after the tests are committed.");
2091
- }
2092
- const { repoRoot: root, commitSha: head } = identity;
2093
- const changed = changedTrackedFiles(root);
2094
- if (changed.length > 0) {
2095
- throw new WorkCommandError(
2096
- `the working copy differs from HEAD in ${changed.join(", ")}. Only the committed files run, so nothing was recorded. Commit or discard the change, then record again.`
2097
- );
2098
- }
2099
- const fetchImpl = opts.fetchImpl ?? defaultFetch;
2100
- const creds = resolveCredentials({ ...opts, env });
2101
- const home = opts.home;
2102
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
2103
- const lines = [];
2104
- const say = (line) => void lines.push(line);
2105
- const { data } = await getJson(creds.url, `/v1/work-items/${item}`, creds.apiKey, creds.appId, fetchImpl);
2106
- const body = data;
2107
- const own = ownPullRequest(body.pullRequests ?? [], opts.pr, identity.gitRepo);
2108
- if ("ambiguous" in own) {
2109
- throw new WorkCommandError(`the item links several open pull requests (${own.ambiguous.map((n) => `#${n}`).join(", ")}). Pass --pr <number> to name this checkout's.`);
2110
- }
2111
- const ownPr = own.pr;
2112
- const postGeneral = async (text, clientCommentId) => {
2113
- try {
2114
- await runWorkComment({ ...creds, item, body: text, clientCommentId, cwd, home, env, fetchImpl, quiet: true });
2115
- } catch (err) {
2116
- if (!(err instanceof WorkCommandError && err.code === "comment_conflict")) {
2117
- say(`The comment on the item's thread was not posted: ${oneLine(String(err instanceof Error ? err.message : err))}`);
2118
- }
2119
- }
2120
- };
2121
- const configText = showAtHead(root, CONFIG_FILE);
2122
- const parsed = configText === void 0 ? void 0 : parseProofsConfig(configText);
2123
- if (parsed === void 0 || !parsed.ok) {
2124
- const problem = parsed === void 0 ? `${CONFIG_FILE} is missing at HEAD. Commit it at the repository root, with the setup, teardown and runners that run the tests.` : `${CONFIG_FILE} cannot be read: ${parsed.problems.join("; ")}`;
2125
- if (opts.comment) {
2126
- const text = `No proof was recorded at ${shortSha(head)}. ${problem}`.slice(0, 2e3);
2127
- await postGeneral(text, proofsCommentId(item, head, [{ id: CONFIG_FILE, proof: "setup file", reason: problem }]));
2128
- }
2129
- throw new WorkCommandError(problem);
2130
- }
2131
- const config = parsed.value;
2132
- const heads = /* @__PURE__ */ new Set([head.toLowerCase(), ...otherPullRequestHeads(body.pullRequests ?? [], ownPr, identity.gitRepo)]);
2133
- const states = classifyProofsAt(body, heads);
2134
- const todo = states.filter((state) => state.state !== "current").map((state) => state.id);
2135
- const declared = new Map((body.criteria?.items ?? []).map((criterion) => [criterion.id, criterion]));
2136
- const proofOf = (id) => declared.get(id).proof;
2137
- const reasons = /* @__PURE__ */ new Map();
2138
- const emitted = /* @__PURE__ */ new Map();
2139
- const found = discoverTestFiles(root, todo, config.runners);
2140
- for (const id of todo) {
2141
- if (!found.has(id)) reasons.set(id, NO_TEST);
2142
- }
2143
- const plan = planRuns([...new Set([...found.values()].flat())], config.runners);
2144
- const logDir = mkdtempSync(join(tmpdir(), "outerlayer-proofs-"));
2145
- const proofOuts = [];
2146
- const groups = [];
2147
- const runCommand = opts.runCommand ?? runShell;
2148
- const baseEnv = { ...process.env, ...env };
2149
- delete baseEnv.OUTERLAYER_PROOF_OUT;
2150
- let spooledCount = 0;
2151
- const spooledCriteria = /* @__PURE__ */ new Set();
2152
- const emitArtifact = async (emitOpts) => {
2153
- const result = await (opts.emitArtifact ?? runEmitArtifact)(emitOpts);
2154
- if (result.spooled) spooledCount += 1;
2155
- return result;
2156
- };
2157
- const common = { url: creds.url, apiKey: creds.apiKey, appId: creds.appId, cwd: root, home, env, fetchImpl, quiet: true };
2158
- const stopGroups = () => {
2159
- for (const pid of groups) {
2160
- try {
2161
- process.kill(-pid, "SIGTERM");
2162
- } catch {
2163
- }
2164
- }
2165
- };
2166
- const cleanUp = () => {
2167
- rmSync(logDir, { recursive: true, force: true });
2168
- for (const folder of proofOuts) rmSync(folder, { recursive: true, force: true });
2169
- };
2170
- const onSignal = (signal) => {
2171
- stopGroups();
2172
- cleanUp();
2173
- process.exit(signal === "SIGINT" ? 130 : 143);
2174
- };
2175
- const onInterrupt = () => onSignal("SIGINT");
2176
- const onTerminate = () => onSignal("SIGTERM");
2177
- process.once("SIGINT", onInterrupt);
2178
- process.once("SIGTERM", onTerminate);
2179
- const runs = [];
2180
- try {
2181
- let setupStarted = false;
2182
- try {
2183
- let setupFailed;
2184
- if (plan.size > 0) {
2185
- setupStarted = true;
2186
- for (const command of config.setup) {
2187
- const result = await runCommand(command, { cwd: root, env: baseEnv, timeoutMs, logDir, groups });
2188
- if (result.status !== 0) {
2189
- setupFailed = `setup failed: "${oneLine(command)}" ${result.timedOut ? `timed out after ${Math.round(timeoutMs / 1e3)} s` : `exited with status ${result.status}`}`;
2190
- say(setupFailed);
2191
- if (result.tail !== "") say(result.tail);
2192
- break;
2193
- }
2194
- }
2195
- }
2196
- for (const [index, files] of plan) {
2197
- const runner = config.runners[index];
2198
- const criteria = todo.filter((id) => found.get(id)?.some((file) => files.includes(file)));
2199
- if (setupFailed !== void 0) {
2200
- for (const id of criteria) reasons.set(id, setupFailed);
2201
- continue;
2202
- }
2203
- const proofOut = mkdtempSync(join(tmpdir(), "outerlayer-proof-out-"));
2204
- proofOuts.push(proofOut);
2205
- const result = await runCommand(fillFiles(runner.command, files), { cwd: root, env: { ...baseEnv, OUTERLAYER_PROOF_OUT: proofOut }, timeoutMs, logDir, groups });
2206
- const failure = result.timedOut ? `the runner for ${runner.files} timed out after ${Math.round(timeoutMs / 1e3)} s` : result.status === 0 ? void 0 : `the runner for ${runner.files} exited with status ${result.status}`;
2207
- if (failure !== void 0) {
2208
- say(failure);
2209
- if (result.tail !== "") say(result.tail);
2210
- }
2211
- runs.push({ glob: runner.files, proofOut, criteria, failure, tail: result.tail });
2212
- }
2213
- } finally {
2214
- if (setupStarted) {
2215
- for (const command of config.teardown) {
2216
- const result = await runCommand(command, { cwd: root, env: baseEnv, timeoutMs, logDir, groups });
2217
- if (result.status !== 0) say(`teardown failed: "${oneLine(command)}" ${result.timedOut ? "timed out" : `exited with status ${result.status}`}`);
2218
- }
2219
- }
2220
- process.off("SIGINT", onInterrupt);
2221
- process.off("SIGTERM", onTerminate);
2222
- stopGroups();
2223
- }
2224
- if (plan.size > 0) {
2225
- let left = [];
2226
- try {
2227
- left = changedTrackedFiles(root);
2228
- } catch {
2229
- }
2230
- if (left.length > 0) {
2231
- say(`The run changed tracked files: ${left.join(", ")}. The next --record records nothing until they match HEAD. Make setup, the tests and teardown leave them unchanged.`);
2232
- }
2233
- }
2234
- await emitProofs();
2235
- } finally {
2236
- cleanUp();
2237
- }
2238
- async function emitProofs() {
2239
- const notCurrent2 = new Set(todo);
2240
- const manifests = runs.flatMap((run) => findManifests(run.proofOut));
2241
- const chapters = /* @__PURE__ */ new Set();
2242
- if (manifests.length > 1) {
2243
- say(`Not recorded, the demo: the runners left ${manifests.length} demo manifests, so it is unclear which to store`);
2244
- } else if (manifests.length === 1) {
2245
- for (const id of chapterCriteria(manifests[0])) chapters.add(id);
2246
- await recordDemo(manifests[0], chapters);
2247
- }
2248
- for (const run of runs) {
2249
- const names = topLevelFiles(run.proofOut);
2250
- for (const name of names) {
2251
- const id = proofFileCriterion(name, new Set(declared.keys()));
2252
- if (id === void 0) {
2253
- say(`Ignored ${name}: its name is not the id of a declared criterion.`);
2254
- continue;
2255
- }
2256
- if (!notCurrent2.has(id)) {
2257
- say(`Ignored ${name}: the proof for ${id} is current, or no proof is declared for it.`);
2258
- continue;
2259
- }
2260
- if (DEMO_PROOFS.has(proofOf(id)) && chapters.has(id)) {
2261
- say(`Ignored ${name}: a demo chapter proves ${id}.`);
2262
- continue;
2263
- }
2264
- if (emitted.has(id)) continue;
2265
- const fail = (reason) => {
2266
- reasons.set(id, reason);
2267
- say(`Not recorded, ${id}: ${reason}`);
2268
- };
2269
- if (run.failure !== void 0) {
2270
- fail(`${run.failure}, so its files are not recorded`);
2271
- continue;
2272
- }
2273
- const problem = kindProblem(proofOf(id), name);
2274
- if (problem !== void 0) {
2275
- fail(problem);
2276
- continue;
2277
- }
2278
- try {
2279
- const caption = (declared.get(id).text ?? `Proof for ${id}`).slice(0, ARTIFACT_MAX_CAPTION_LENGTH);
2280
- const before = spooledCount;
2281
- const result = await emitArtifact({ ...common, file: join(run.proofOut, name), caption, criterionId: id, ...ownPr === void 0 ? {} : { pr: ownPr } });
2282
- const artifactId = result.record?.artifactId ?? result.data?.clientArtifactId;
2283
- if (artifactId === void 0) {
2284
- fail("the upload returned no artifact id");
2285
- continue;
2286
- }
2287
- emitted.set(id, artifactId);
2288
- if (spooledCount > before) spooledCriteria.add(id);
2289
- } catch (err) {
2290
- fail(`the upload failed: ${oneLine(String(err instanceof Error ? err.message : err))}`);
2291
- }
2292
- }
2293
- }
2294
- for (const run of runs) {
2295
- for (const id of run.criteria) {
2296
- if (emitted.has(id) || reasons.has(id)) continue;
2297
- reasons.set(id, run.failure ?? `the tests ran and wrote no ${id}.<ext> file under OUTERLAYER_PROOF_OUT`);
2298
- }
2299
- }
2300
- }
2301
- async function recordDemo(manifest, chapters) {
2302
- const demoCriteria = todo.filter((id) => DEMO_PROOFS.has(proofOf(id)));
2303
- let replaces;
2304
- try {
2305
- replaces = (await readNewestDemo({ url: creds.url, apiKey: creds.apiKey, appId: creds.appId, item, fetchImpl }))?.artifactId;
2306
- } catch (err) {
2307
- replaces = void 0;
2308
- say(`The previous demo could not be read, so the new demo does not replace it: ${oneLine(String(err instanceof Error ? err.message : err))}`);
2309
- }
2310
- const before = spooledCount;
2311
- let result;
2312
- try {
2313
- result = await (opts.emitDemo ?? runEmitDemo)({
2314
- ...common,
2315
- manifest,
2316
- item,
2317
- ...ownPr === void 0 ? {} : { pr: ownPr },
2318
- ...replaces === void 0 ? {} : { replaces },
2319
- emitArtifact
2320
- });
2321
- } catch (err) {
2322
- const reason = `the demo was not stored: ${oneLine(String(err instanceof Error ? err.message : err))}`;
2323
- for (const id of demoCriteria) reasons.set(id, reason);
2324
- say(`Not recorded, the demo: ${reason}`);
2325
- return;
2326
- }
2327
- for (const id of demoCriteria) {
2328
- const artifactId = proofOf(id) === "screenshot" ? result.screenshots.find((shot) => shot.criterionId === id && shot.artifactId !== void 0)?.artifactId : result.clips.find((clip) => clip.criterionId === id && clip.bound)?.clipArtifactId;
2329
- if (artifactId !== void 0) {
2330
- emitted.set(id, artifactId);
2331
- if (spooledCount > before) spooledCriteria.add(id);
2332
- } else if (chapters.has(id)) {
2333
- reasons.set(id, result.failures.length > 0 ? `the demo failed a check: ${oneLine(result.failures[0])}` : "the demo has no passing chapter for it");
2334
- }
2335
- }
2336
- for (const failure of result.failures) say(`Demo check failed: ${oneLine(failure)}`);
2337
- }
2338
- if (spooledCount > 0) {
2339
- try {
2340
- const synced = await (opts.sync ?? (() => runSync({ ...common })))();
2341
- const unstored = unstoredUploads(
2342
- synced,
2343
- [...spooledCriteria].map((id) => emitted.get(id))
2344
- );
2345
- const lostIds = unstored === "all" ? [...spooledCriteria] : [...spooledCriteria].filter((id) => unstored.includes(emitted.get(id)));
2346
- for (const id of lostIds) {
2347
- emitted.delete(id);
2348
- reasons.set(id, "the sync did not store the upload, so the proof is stored only in the session record");
2349
- }
2350
- if (lostIds.length > 0) say("The sync did not store an upload. The proofs that went through the session record are not stored.");
2351
- } catch (err) {
2352
- for (const id of spooledCriteria) {
2353
- emitted.delete(id);
2354
- reasons.set(id, "the sync failed, so the proof is stored only in the session record");
2355
- }
2356
- say(`The sync failed, so the new proofs are stored only in the session record: ${oneLine(String(err instanceof Error ? err.message : err))}`);
2357
- }
2358
- }
2359
- for (const [criterion, artifactId] of emitted) say(`Recorded ${criterion}: ${artifactId}`);
2360
- let finalStates = states;
2361
- try {
2362
- const { data: fresh } = await getJson(creds.url, `/v1/work-items/${item}`, creds.apiKey, creds.appId, fetchImpl);
2363
- finalStates = classifyProofsAt(fresh, heads);
2364
- } catch (err) {
2365
- say(`The item could not be read again, so the list below may be out of date: ${oneLine(String(err instanceof Error ? err.message : err))}`);
2366
- }
2367
- const notCurrent = finalStates.filter((state) => state.state !== "current" && !emitted.has(state.id)).map((state) => ({ id: state.id, proof: state.proof, reason: reasons.get(state.id) ?? "it was not recorded in this run" }));
2368
- if (opts.comment && notCurrent.length > 0) {
2369
- await postGeneral(proofsCommentBody(head, notCurrent), proofsCommentId(item, head, notCurrent));
2370
- }
2371
- for (const proof of notCurrent) say(`Not current, ${proof.id} (${proof.proof}): ${proof.reason}`);
2372
- const closing = await runWorkProofs({ ...opts, item, env, quiet: true, checkoutHead: head, fetchImpl });
2373
- const output = [...lines, closing.output].join("\n");
2374
- if (!opts.quiet) process.stdout.write(output + "\n");
2375
- return {
2376
- exitCode: closing.exitCode,
2377
- output,
2378
- emitted: [...emitted].map(([criterion, artifactId]) => ({ criterion, artifactId })),
2379
- notCurrent
2380
- };
2053
+ function hostItemsOf(workItem, name) {
2054
+ const checks = Object(workItem).checks;
2055
+ if (!Array.isArray(checks)) return [];
2056
+ const check = checks.find((entry) => Object(entry).name === name);
2057
+ if (check?.source !== "host") return [];
2058
+ const parsed = CheckItemsSchema.safeParse(check.items);
2059
+ return parsed.success ? parsed.data : [];
2381
2060
  }
2382
2061
 
2383
- export { runWorkProofsRecord };
2062
+ export { MAX_TEST_FILES, MAX_TEST_FILE_BYTES, NO_CITING_TEST_REASON, NO_TEST_FILES_REASON, NO_VERDICT_REASON, criteriaOf, criterionInputs, hostItemsOf, inCriteriaOrder, itemsSentence, judgedItems, loadCitationFinder, oneLineReason, parseJudgeAnswer, planCriteria, runnerMatcher, testFileMatcher };