@outerlayer/cli 0.34.0-next.20261024174615 → 0.34.0-next.20261024225538

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 (94) hide show
  1. package/README.md +5 -5
  2. package/dist/{agent-setup-FBAT5LGX.js → agent-setup-HEJM3D3V.js} +9 -9
  3. package/dist/build-info.json +1 -1
  4. package/dist/{check-K4I4EBEK.js → check-OOUGS65D.js} +20 -19
  5. package/dist/{chunk-SVLFZLTE.js → chunk-272AKVRP.js} +5 -5
  6. package/dist/{chunk-B5MSDF5B.js → chunk-2AIOOU3A.js} +4 -4
  7. package/dist/{chunk-BTHH5H5H.js → chunk-3IH6K7KG.js} +2 -2
  8. package/dist/{chunk-XFAJQZN2.js → chunk-4P6QGMPN.js} +2 -2
  9. package/dist/{chunk-DFLHVTXI.js → chunk-4Y54SQXH.js} +32 -14
  10. package/dist/{chunk-MHGIN2X6.js → chunk-5HZGLLNW.js} +2 -2
  11. package/dist/{chunk-74Q24R3B.js → chunk-5QBUX5YZ.js} +7 -7
  12. package/dist/{chunk-6AQLRSYU.js → chunk-62LXQM7U.js} +2 -2
  13. package/dist/{chunk-SHIGGHZO.js → chunk-65AKMFBH.js} +2 -2
  14. package/dist/{chunk-OHJDH5GV.js → chunk-6NUPXDAA.js} +1 -1
  15. package/dist/{chunk-ZADIXMKT.js → chunk-7WM7K2DY.js} +1 -1
  16. package/dist/{chunk-XLJHFZRL.js → chunk-ACRRO3MB.js} +7 -7
  17. package/dist/{chunk-OLCIPTST.js → chunk-AP2K4LPI.js} +4 -4
  18. package/dist/{chunk-YPCDDQFU.js → chunk-DQ6YO7FH.js} +1 -1
  19. package/dist/chunk-E4ASIOVL.js +170 -0
  20. package/dist/{chunk-NVDPSH72.js → chunk-EE2ZZGQV.js} +1 -1
  21. package/dist/{chunk-GWF3ZRUX.js → chunk-EN3YWO7Q.js} +1 -1
  22. package/dist/{chunk-CQRPR4WZ.js → chunk-FGXT5OXS.js} +56 -126
  23. package/dist/{chunk-3KT2IWV3.js → chunk-FVKH3PMV.js} +49 -9
  24. package/dist/{chunk-UF2FU3CM.js → chunk-JWNH4ZTF.js} +2 -2
  25. package/dist/{chunk-2G7PJAJZ.js → chunk-K5Q6T7SE.js} +1 -1
  26. package/dist/{chunk-TIRHZC2M.js → chunk-NKOM4JKY.js} +2 -2
  27. package/dist/{chunk-B44BFR2Q.js → chunk-O6DYCIVW.js} +3 -3
  28. package/dist/{chunk-YREGBU3O.js → chunk-QDVGOMSC.js} +1 -1
  29. package/dist/{chunk-5XZ6BUPH.js → chunk-QMWUPRYQ.js} +1 -1
  30. package/dist/{chunk-HMCBX3PL.js → chunk-RCRE42V6.js} +1 -1
  31. package/dist/{chunk-R2CLQJA2.js → chunk-TDAQHYM4.js} +1 -1
  32. package/dist/{chunk-SMAZA7DM.js → chunk-XFFUXXI4.js} +2 -2
  33. package/dist/{chunk-TFKROYY2.js → chunk-YEVPRO7L.js} +3 -3
  34. package/dist/{chunk-HBVHRC3A.js → chunk-YGSY2NWU.js} +2 -2
  35. package/dist/{chunk-PBIYM2Z6.js → chunk-YIBFGAYI.js} +2 -2
  36. package/dist/{chunk-HIGP4WOC.js → chunk-Z4KWHSO4.js} +3 -3
  37. package/dist/{chunk-ZGB4ZJ5E.js → chunk-ZQSANKS4.js} +1 -1
  38. package/dist/{chunk-5WCBFLES.js → chunk-ZW6L275N.js} +7 -7
  39. package/dist/{claude-launcher-YXRS4EZE.js → claude-launcher-MORG66PJ.js} +4 -4
  40. package/dist/{cli-KDAKXVVE.js → cli-XI7RUSC5.js} +100 -93
  41. package/dist/{command-YQBQDIAM.js → command-BJSHY6OB.js} +10 -10
  42. package/dist/{connect-cmd-42JHZKWN.js → connect-cmd-YAUOCX4X.js} +4 -4
  43. package/dist/{container-start-V5WVSWAB.js → container-start-QADK3YGL.js} +18 -17
  44. package/dist/{context-cleanup-YGWYIFFV.js → context-cleanup-LUBEZB3L.js} +2 -2
  45. package/dist/{context-show-cmd-LIWHRWVT.js → context-show-cmd-VHY3OBIA.js} +5 -5
  46. package/dist/{control-plane-launch-AXBWT5CC.js → control-plane-launch-QSBWTA2V.js} +5 -5
  47. package/dist/{doctor-AZZJBJYO.js → doctor-UR76MCGI.js} +11 -11
  48. package/dist/{emit-artifact-cmd-NU5JURAA.js → emit-artifact-cmd-DP2EQ54N.js} +9 -9
  49. package/dist/{emit-cmd-A4CB7BEC.js → emit-cmd-7NMNKDK7.js} +5 -5
  50. package/dist/{emit-criteria-cmd-RAU3PDEK.js → emit-criteria-cmd-TTFBN6RK.js} +6 -6
  51. package/dist/{emit-demo-cmd-524A54D5.js → emit-demo-cmd-Z7YGLEBJ.js} +10 -10
  52. package/dist/{emit-finding-cmd-LE3HFQWL.js → emit-finding-cmd-IQRD3J2X.js} +6 -6
  53. package/dist/{emit-result-cmd-XT2VEPAJ.js → emit-result-cmd-GIWB6UHH.js} +8 -8
  54. package/dist/{emit-step-cmd-LXOKBFQE.js → emit-step-cmd-PU5TTU6C.js} +6 -6
  55. package/dist/{findings-cmd-O5HUK26I.js → findings-cmd-7J5SHCUO.js} +6 -6
  56. package/dist/{fleet-readiness-VAKMSSWI.js → fleet-readiness-G63D76EX.js} +6 -6
  57. package/dist/{governing-source-FNSH4V4A.js → governing-source-DLESDP6T.js} +9 -9
  58. package/dist/{hook-fast-WENTLDMA.js → hook-fast-VQXRDS6E.js} +1 -1
  59. package/dist/index.js +4 -4
  60. package/dist/{init-RUIWHKLE.js → init-67R7LO4C.js} +10 -10
  61. package/dist/{init-LQDKX2XL.js → init-KSXU4PA7.js} +10 -10
  62. package/dist/{init-cmd-2OTTULTI.js → init-cmd-MNOVMADM.js} +14 -14
  63. package/dist/{init-update-TN2W4EN6.js → init-update-6KEXRCJH.js} +13 -13
  64. package/dist/{layout-NAPG4SX2.js → layout-7B3O3FT3.js} +3 -3
  65. package/dist/{loop-E4YJ6BLL.js → loop-KUEOPBKX.js} +20 -19
  66. package/dist/{machine-IEYKRHRK.js → machine-EQEAPT76.js} +10 -10
  67. package/dist/{machine-skills-2TT3RXMJ.js → machine-skills-3FEGR376.js} +3 -3
  68. package/dist/{runner-key-QKZZTKLY.js → runner-key-ML7R33HF.js} +10 -10
  69. package/dist/{session-sender-IH44FURK.js → session-sender-A43GZQ7T.js} +9 -9
  70. package/dist/{spec-cmd-2LRTOTAO.js → spec-cmd-VVUJZSG2.js} +7 -7
  71. package/dist/{starter-pack-5D4BANFU.js → starter-pack-LEL3Q2DB.js} +4 -4
  72. package/dist/{status-6ISCZDBX.js → status-4G6K7I2C.js} +15 -15
  73. package/dist/{sync-cmd-MIID2ANV.js → sync-cmd-ZEC65ABJ.js} +8 -8
  74. package/dist/update-steps-XLO7734I.js +73 -0
  75. package/dist/{watch-K5UUKCPB.js → watch-QB4AMWR3.js} +8 -8
  76. package/dist/{work-claim-cmd-2LD2JQKI.js → work-claim-cmd-6W3GBHRS.js} +8 -8
  77. package/dist/{work-cmd-NR53YCXJ.js → work-cmd-LTZXOPPN.js} +6 -6
  78. package/dist/{work-comment-cmd-PC4HNM45.js → work-comment-cmd-LDZBUO6M.js} +7 -7
  79. package/dist/{work-demo-cmd-S5EJXBVH.js → work-demo-cmd-77LISWQ3.js} +6 -6
  80. package/dist/{work-logs-cmd-5F6MDBLQ.js → work-logs-cmd-FK7HE7PC.js} +6 -6
  81. package/dist/{work-open-pr-cmd-SWVFDSMY.js → work-open-pr-cmd-WVONEHZL.js} +7 -7
  82. package/dist/{work-pr-cmd-DXW4RXG4.js → work-pr-cmd-6IPXWJEH.js} +6 -6
  83. package/dist/{work-proofs-cmd-UVTSPFLL.js → work-proofs-cmd-TGIAP5IO.js} +7 -7
  84. package/dist/work-proofs-record-XPAU7N57.js +2382 -0
  85. package/dist/{work-stop-cmd-HL6FZL5X.js → work-stop-cmd-UJ45EV3A.js} +6 -6
  86. package/package.json +2 -1
  87. package/skill-pack/maintained/outerlayer-amend/SKILL.md +1 -2
  88. package/skill-pack/maintained/outerlayer-build/SKILL.md +4 -3
  89. package/skill-pack/maintained/outerlayer-build/references/agent-briefs.md +30 -28
  90. package/skill-pack/maintained/outerlayer-build/references/evidence.md +5 -5
  91. package/skill-pack/maintained/outerlayer-evidence/SKILL.md +1 -1
  92. package/dist/chunk-RT6VNM3S.js +0 -148
  93. package/dist/work-proofs-init-GNGI7PZU.js +0 -35
  94. package/dist/work-proofs-record-HTWSMEDG.js +0 -402
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { stripTerminalControls } from './chunk-ACRRO3MB.js';
4
+ import { tagToPull, imageTag, pullInstruction, readUpdateStatus, runnerImageVersion } from './chunk-MZBQTVFG.js';
5
+ import { readFileSync } from 'fs';
6
+
7
+ createRequire(import.meta.url);
8
+ var COMPOSE_PROJECT_LABEL = "com.docker.compose.project";
9
+ var COMPOSE_SERVICE_LABEL = "com.docker.compose.service";
10
+ var COMPOSE_DIR_LABEL = "com.docker.compose.project.working_dir";
11
+ function firstLine(text) {
12
+ return text.trim().split("\n")[0] ?? "";
13
+ }
14
+ function candidateIds(env, readFile) {
15
+ const found = [];
16
+ const hostname = env.HOSTNAME?.trim();
17
+ if (hostname !== void 0 && hostname !== "") found.push(hostname);
18
+ try {
19
+ for (const match of readFile("/proc/self/mountinfo").matchAll(/\/containers\/([0-9a-f]{64})\//g)) {
20
+ if (!found.includes(match[1])) found.push(match[1]);
21
+ }
22
+ } catch {
23
+ }
24
+ return found;
25
+ }
26
+ function bindDestination(bind) {
27
+ const parts = bind.split(":");
28
+ if (parts.length >= 3 && !parts[parts.length - 1].startsWith("/")) parts.pop();
29
+ return parts[parts.length - 1];
30
+ }
31
+ function mountsOf(row) {
32
+ const binds = row.HostConfig?.Binds ?? [];
33
+ const covered = new Set(binds.map(bindDestination));
34
+ const values = [...binds];
35
+ for (const mount of row.Mounts ?? []) {
36
+ if (mount.Destination === void 0 || covered.has(mount.Destination)) continue;
37
+ const source = mount.Type === "volume" ? mount.Name : mount.Type === "bind" ? mount.Source : void 0;
38
+ if (source === void 0 || source === "") continue;
39
+ values.push(`${source}:${mount.Destination}${mount.RW === false ? ":ro" : ""}`);
40
+ }
41
+ return values;
42
+ }
43
+ function restartOf(row) {
44
+ const policy = row.HostConfig?.RestartPolicy;
45
+ if (policy?.Name === void 0 || policy.Name === "" || policy.Name === "no") return void 0;
46
+ return policy.Name === "on-failure" && (policy.MaximumRetryCount ?? 0) > 0 ? `on-failure:${policy.MaximumRetryCount}` : policy.Name;
47
+ }
48
+ function networkOf(row) {
49
+ const mode = row.HostConfig?.NetworkMode;
50
+ return mode === void 0 || mode === "" || mode === "default" || mode === "bridge" ? void 0 : mode;
51
+ }
52
+ function envNamesOf(row, imageEnv) {
53
+ const own = new Set(imageEnv);
54
+ const names = (row.Config?.Env ?? []).filter((entry) => !own.has(entry)).map((entry) => entry.split("=")[0]);
55
+ return [...new Set(names)].sort();
56
+ }
57
+ async function readOwnContainer(deps = {}) {
58
+ const run = deps.run ?? (await import('./docker-DJ73SZRC.js')).spawnRun;
59
+ const ids = candidateIds(deps.env ?? process.env, deps.readFile ?? ((path) => readFileSync(path, "utf8")));
60
+ if (ids.length === 0) return { ok: false, reason: "the runner cannot tell which container it runs in: HOSTNAME is empty and /proc/self/mountinfo names none" };
61
+ let problem = "";
62
+ let row;
63
+ for (const id of ids) {
64
+ try {
65
+ const result = await run("docker", ["inspect", id], { timeoutMs: 2e4 });
66
+ if (result.status !== 0) {
67
+ problem ||= firstLine(result.stderr) || `docker inspect exited with status ${result.status}`;
68
+ continue;
69
+ }
70
+ const parsed = JSON.parse(result.stdout)[0];
71
+ if (parsed?.Id !== void 0 && parsed.Id.startsWith(id)) {
72
+ row = parsed;
73
+ break;
74
+ }
75
+ problem ||= `docker inspect ${id} named another container`;
76
+ } catch (err) {
77
+ problem ||= err instanceof Error ? err.message : String(err);
78
+ }
79
+ }
80
+ if (row === void 0) {
81
+ return { ok: false, reason: `the runner could not read its container with \`docker inspect\` (is the Docker socket mounted?): ${problem}` };
82
+ }
83
+ const name = row.Name?.replace(/^\//, "");
84
+ const image = row.Config?.Image;
85
+ if (name === void 0 || name === "" || image === void 0 || image === "") {
86
+ return { ok: false, reason: "docker inspect gave no name or image for the container" };
87
+ }
88
+ let imageEnv = [];
89
+ if (row.Image !== void 0) {
90
+ try {
91
+ const result = await run("docker", ["image", "inspect", row.Image], { timeoutMs: 2e4 });
92
+ if (result.status === 0) imageEnv = JSON.parse(result.stdout)[0]?.Config?.Env ?? [];
93
+ } catch {
94
+ }
95
+ }
96
+ const labels = row.Config?.Labels ?? {};
97
+ const project = labels[COMPOSE_PROJECT_LABEL];
98
+ return {
99
+ ok: true,
100
+ container: {
101
+ name,
102
+ image,
103
+ mounts: mountsOf(row),
104
+ ...restartOf(row) === void 0 ? {} : { restart: restartOf(row) },
105
+ ...networkOf(row) === void 0 ? {} : { network: networkOf(row) },
106
+ envNames: envNamesOf(row, imageEnv),
107
+ ...project === void 0 || project === "" ? {} : { compose: { project, service: labels[COMPOSE_SERVICE_LABEL], workingDir: labels[COMPOSE_DIR_LABEL] } }
108
+ }
109
+ };
110
+ }
111
+ function shellWord(raw) {
112
+ const value = stripTerminalControls(raw);
113
+ return /^[\w@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
114
+ }
115
+ function variablesNote(names) {
116
+ return names.length === 0 ? ["The container sets no variables of its own."] : [`The container sets these variables. Check that your env file sets each one: ${names.map(stripTerminalControls).join(", ")}`];
117
+ }
118
+ function renderUpdateSteps(read, version) {
119
+ const tag = version === void 0 ? tagToPull(void 0) : imageTag(version);
120
+ if (!read.ok) return `${pullInstruction(tag)} \xB7 the runner could not print exact commands: ${stripTerminalControls(read.reason)}`;
121
+ const c = read.container;
122
+ const lines = [];
123
+ if (c.compose !== void 0) {
124
+ const dir = c.compose.workingDir === void 0 ? "" : stripTerminalControls(c.compose.workingDir);
125
+ const where = dir === "" ? "" : ` in ${dir}`;
126
+ lines.push(
127
+ `Update the runner that Docker Compose started (project ${stripTerminalControls(c.compose.project)}). Run these commands${where}:`,
128
+ `1. Set the image of the runner service in your Compose file to ${tag}. Skip this step when it names a tag that moves, such as latest.`,
129
+ "2. docker compose pull",
130
+ "3. docker compose up -d",
131
+ `4. Check that the new runner is up: docker logs ${shellWord(c.name)}`,
132
+ ` Look for no line that says the gateway refuses work from this runner. docker exec ${shellWord(c.name)} outerlayer --version prints ${version ?? "the new version"}.`,
133
+ ...variablesNote(c.envNames)
134
+ );
135
+ return lines.join("\n");
136
+ }
137
+ const name = shellWord(c.name);
138
+ const old = shellWord(`${c.name}-old`);
139
+ const run = [
140
+ `docker run -d --name ${name}`,
141
+ ...c.restart === void 0 ? [] : [`--restart ${shellWord(c.restart)}`],
142
+ ...c.network === void 0 ? [] : [`--network ${shellWord(c.network)}`],
143
+ ...c.mounts.map((mount) => `-v ${shellWord(mount)}`),
144
+ "--env-file <the file you started it with>",
145
+ tag
146
+ ];
147
+ lines.push(
148
+ `Update the runner to ${tag}. The steps keep the old container as ${stripTerminalControls(c.name)}-old until the new one runs.`,
149
+ `1. docker pull ${tag}`,
150
+ `2. docker stop ${name}`,
151
+ ` docker rename ${name} ${old}`,
152
+ `3. ${run.join(" \\\n ")}`,
153
+ `4. Check that the new runner is up: docker logs ${name}`,
154
+ ` Look for no line that says the gateway refuses work from this runner. docker exec ${name} outerlayer --version prints ${version ?? "the new version"}.`,
155
+ "5. Only after that check, remove the old container:",
156
+ ` docker rm ${old}`,
157
+ ...variablesNote(c.envNames)
158
+ );
159
+ return lines.join("\n");
160
+ }
161
+ async function runUpdateSteps(deps) {
162
+ const env = deps.env ?? process.env;
163
+ const named = readUpdateStatus(deps.runnerDirPath)?.named;
164
+ if (runnerImageVersion(env) === void 0) {
165
+ return `npm install -g @outerlayer/cli@${named ?? "latest"}, then "$(npm prefix -g)/bin/outerlayer" runner install, then start the runner again \xB7 this runner is not in the container image, so there is no container to read. A service runner uses \`runner install --service\` and updates itself.`;
166
+ }
167
+ return renderUpdateSteps(await readOwnContainer({ ...deps, env }), named);
168
+ }
169
+
170
+ export { readOwnContainer, renderUpdateSteps, runUpdateSteps };
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { sanitizeTerminal } from './chunk-MECW77XP.js';
4
4
  import { remoteLookupFailed } from './chunk-6ZFY2L2T.js';
5
- import { isAgentsMdLayout } from './chunk-TIRHZC2M.js';
5
+ import { isAgentsMdLayout } from './chunk-NKOM4JKY.js';
6
6
  import { DEFAULT_DASHBOARD } from './chunk-Y5YCX6AL.js';
7
7
  import { cliFetch, resolveGatewayCredentials } from './chunk-6RKD7YZ6.js';
8
8
  import { readCloudConfig } from './chunk-PJDQPF5N.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { resolveCredentials, postJson, getJson } from './chunk-HIGP4WOC.js';
3
+ import { resolveCredentials, postJson, getJson } from './chunk-Z4KWHSO4.js';
4
4
  import { detectActiveSession } from './chunk-IP7BIBXJ.js';
5
5
  import { sanitizeTerminal } from './chunk-MECW77XP.js';
6
6
  import { resolveRepoIdentity } from './chunk-6ZFY2L2T.js';
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { RESERVED_EMIT_NAMES, ArtifactCriterionIdSchema, ARTIFACT_KINDS } from './chunk-EOTMDIYC.js';
3
+ import { RESERVED_EMIT_NAMES, ARTIFACT_KINDS, ArtifactCriterionIdSchema } from './chunk-EOTMDIYC.js';
4
4
  import { __commonJS, __require, __toESM } from './chunk-Z5GEFMRW.js';
5
5
 
6
6
  createRequire(import.meta.url);
@@ -1460,7 +1460,7 @@ var require_stringify = __commonJS({
1460
1460
  props.push(doc.directives.tagString(tag));
1461
1461
  return props.join(" ");
1462
1462
  }
1463
- function stringify2(item, ctx, onComment, onChompKeep) {
1463
+ function stringify(item, ctx, onComment, onChompKeep) {
1464
1464
  if (identity.isPair(item))
1465
1465
  return item.toString(ctx, onComment, onChompKeep);
1466
1466
  if (identity.isAlias(item)) {
@@ -1489,7 +1489,7 @@ var require_stringify = __commonJS({
1489
1489
  ${ctx.indent}${str}`;
1490
1490
  }
1491
1491
  exports$1.createStringifyContext = createStringifyContext;
1492
- exports$1.stringify = stringify2;
1492
+ exports$1.stringify = stringify;
1493
1493
  }
1494
1494
  });
1495
1495
 
@@ -1498,7 +1498,7 @@ var require_stringifyPair = __commonJS({
1498
1498
  "../../node_modules/yaml/dist/stringify/stringifyPair.js"(exports$1) {
1499
1499
  var identity = require_identity();
1500
1500
  var Scalar = require_Scalar();
1501
- var stringify2 = require_stringify();
1501
+ var stringify = require_stringify();
1502
1502
  var stringifyComment = require_stringifyComment();
1503
1503
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
1504
1504
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
@@ -1520,7 +1520,7 @@ var require_stringifyPair = __commonJS({
1520
1520
  });
1521
1521
  let keyCommentDone = false;
1522
1522
  let chompKeep = false;
1523
- let str = stringify2.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
1523
+ let str = stringify.stringify(key, ctx, () => keyCommentDone = true, () => chompKeep = true);
1524
1524
  if (!explicitKey && !ctx.inFlow && str.length > 1024) {
1525
1525
  if (simpleKeys)
1526
1526
  throw new Error("With simple keys, single line scalar must not span more than 1024 characters");
@@ -1572,7 +1572,7 @@ ${indent}:`;
1572
1572
  ctx.indent = ctx.indent.substring(2);
1573
1573
  }
1574
1574
  let valueCommentDone = false;
1575
- const valueStr = stringify2.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
1575
+ const valueStr = stringify.stringify(value, ctx, () => valueCommentDone = true, () => chompKeep = true);
1576
1576
  let ws = " ";
1577
1577
  if (keyComment || vsb || vcb) {
1578
1578
  ws = vsb ? "\n" : "";
@@ -1710,7 +1710,7 @@ var require_addPairToJSMap = __commonJS({
1710
1710
  "../../node_modules/yaml/dist/nodes/addPairToJSMap.js"(exports$1) {
1711
1711
  var log = require_log();
1712
1712
  var merge = require_merge();
1713
- var stringify2 = require_stringify();
1713
+ var stringify = require_stringify();
1714
1714
  var identity = require_identity();
1715
1715
  var toJS = require_toJS();
1716
1716
  function addPairToJSMap(ctx, map, { key, value }) {
@@ -1746,7 +1746,7 @@ var require_addPairToJSMap = __commonJS({
1746
1746
  if (typeof jsKey !== "object")
1747
1747
  return String(jsKey);
1748
1748
  if (identity.isNode(key) && ctx?.doc) {
1749
- const strCtx = stringify2.createStringifyContext(ctx.doc, {});
1749
+ const strCtx = stringify.createStringifyContext(ctx.doc, {});
1750
1750
  strCtx.anchors = /* @__PURE__ */ new Set();
1751
1751
  for (const node of ctx.anchors.keys())
1752
1752
  strCtx.anchors.add(node.anchor);
@@ -1811,12 +1811,12 @@ var require_Pair = __commonJS({
1811
1811
  var require_stringifyCollection = __commonJS({
1812
1812
  "../../node_modules/yaml/dist/stringify/stringifyCollection.js"(exports$1) {
1813
1813
  var identity = require_identity();
1814
- var stringify2 = require_stringify();
1814
+ var stringify = require_stringify();
1815
1815
  var stringifyComment = require_stringifyComment();
1816
1816
  function stringifyCollection(collection, ctx, options) {
1817
1817
  const flow = ctx.inFlow ?? collection.flow;
1818
- const stringify3 = flow ? stringifyFlowCollection : stringifyBlockCollection;
1819
- return stringify3(collection, ctx, options);
1818
+ const stringify2 = flow ? stringifyFlowCollection : stringifyBlockCollection;
1819
+ return stringify2(collection, ctx, options);
1820
1820
  }
1821
1821
  function stringifyBlockCollection({ comment, items }, ctx, { blockItemPrefix, flowChars, itemIndent, onChompKeep, onComment }) {
1822
1822
  const { indent, options: { commentString } } = ctx;
@@ -1841,7 +1841,7 @@ var require_stringifyCollection = __commonJS({
1841
1841
  }
1842
1842
  }
1843
1843
  chompKeep = false;
1844
- let str2 = stringify2.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
1844
+ let str2 = stringify.stringify(item, itemCtx, () => comment2 = null, () => chompKeep = true);
1845
1845
  if (comment2)
1846
1846
  str2 += stringifyComment.lineComment(str2, itemIndent, commentString(comment2));
1847
1847
  if (chompKeep && comment2)
@@ -1908,7 +1908,7 @@ ${indent}${line}` : "\n";
1908
1908
  }
1909
1909
  if (comment)
1910
1910
  reqNewline = true;
1911
- let str = stringify2.stringify(item, itemCtx, () => comment = null);
1911
+ let str = stringify.stringify(item, itemCtx, () => comment = null);
1912
1912
  reqNewline || (reqNewline = lines.length > linesAtValue || str.includes("\n"));
1913
1913
  if (i < items.length - 1) {
1914
1914
  str += ",";
@@ -3245,7 +3245,7 @@ var require_Schema = __commonJS({
3245
3245
  var require_stringifyDocument = __commonJS({
3246
3246
  "../../node_modules/yaml/dist/stringify/stringifyDocument.js"(exports$1) {
3247
3247
  var identity = require_identity();
3248
- var stringify2 = require_stringify();
3248
+ var stringify = require_stringify();
3249
3249
  var stringifyComment = require_stringifyComment();
3250
3250
  function stringifyDocument(doc, options) {
3251
3251
  const lines = [];
@@ -3260,7 +3260,7 @@ var require_stringifyDocument = __commonJS({
3260
3260
  }
3261
3261
  if (hasDirectives)
3262
3262
  lines.push("---");
3263
- const ctx = stringify2.createStringifyContext(doc, options);
3263
+ const ctx = stringify.createStringifyContext(doc, options);
3264
3264
  const { commentString } = ctx.options;
3265
3265
  if (doc.commentBefore) {
3266
3266
  if (lines.length !== 1)
@@ -3282,7 +3282,7 @@ var require_stringifyDocument = __commonJS({
3282
3282
  contentComment = doc.contents.comment;
3283
3283
  }
3284
3284
  const onChompKeep = contentComment ? void 0 : () => chompKeep = true;
3285
- let body = stringify2.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
3285
+ let body = stringify.stringify(doc.contents, ctx, () => contentComment = null, onChompKeep);
3286
3286
  if (contentComment)
3287
3287
  body += stringifyComment.lineComment(body, "", commentString(contentComment));
3288
3288
  if ((body[0] === "|" || body[0] === ">") && lines[lines.length - 1] === "---") {
@@ -3290,7 +3290,7 @@ var require_stringifyDocument = __commonJS({
3290
3290
  } else
3291
3291
  lines.push(body);
3292
3292
  } else {
3293
- lines.push(stringify2.stringify(doc.contents, ctx));
3293
+ lines.push(stringify.stringify(doc.contents, ctx));
3294
3294
  }
3295
3295
  if (doc.directives?.docEnd) {
3296
3296
  if (doc.comment) {
@@ -5406,7 +5406,7 @@ var require_cst_scalar = __commonJS({
5406
5406
  // ../../node_modules/yaml/dist/parse/cst-stringify.js
5407
5407
  var require_cst_stringify = __commonJS({
5408
5408
  "../../node_modules/yaml/dist/parse/cst-stringify.js"(exports$1) {
5409
- var stringify2 = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
5409
+ var stringify = (cst) => "type" in cst ? stringifyToken(cst) : stringifyItem(cst);
5410
5410
  function stringifyToken(token) {
5411
5411
  switch (token.type) {
5412
5412
  case "block-scalar": {
@@ -5459,7 +5459,7 @@ var require_cst_stringify = __commonJS({
5459
5459
  res += stringifyToken(value);
5460
5460
  return res;
5461
5461
  }
5462
- exports$1.stringify = stringify2;
5462
+ exports$1.stringify = stringify;
5463
5463
  }
5464
5464
  });
5465
5465
 
@@ -7183,7 +7183,7 @@ var require_public_api = __commonJS({
7183
7183
  }
7184
7184
  return doc.toJS(Object.assign({ reviver: _reviver }, options));
7185
7185
  }
7186
- function stringify2(value, replacer, options) {
7186
+ function stringify(value, replacer, options) {
7187
7187
  let _replacer = null;
7188
7188
  if (typeof replacer === "function" || Array.isArray(replacer)) {
7189
7189
  _replacer = replacer;
@@ -7208,7 +7208,7 @@ var require_public_api = __commonJS({
7208
7208
  exports$1.parse = parse2;
7209
7209
  exports$1.parseAllDocuments = parseAllDocuments;
7210
7210
  exports$1.parseDocument = parseDocument2;
7211
- exports$1.stringify = stringify2;
7211
+ exports$1.stringify = stringify;
7212
7212
  }
7213
7213
  });
7214
7214
 
@@ -8707,126 +8707,56 @@ function sessionsToTimeline(sessions) {
8707
8707
  });
8708
8708
  return out;
8709
8709
  }
8710
- var DEMO = "demo";
8710
+ var FILES_PLACEHOLDER = "{files}";
8711
8711
  function isRecord2(value) {
8712
8712
  return typeof value === "object" && value !== null && !Array.isArray(value);
8713
8713
  }
8714
- function load(text) {
8715
- let raw;
8716
- try {
8717
- raw = (0, import_yaml.parse)(text);
8718
- } catch (err) {
8719
- return { ok: false, problems: [`the file is not valid YAML: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`] };
8720
- }
8721
- if (raw === null || raw === void 0) return { ok: true, value: {} };
8722
- if (!isRecord2(raw)) return { ok: false, problems: ["the file must be a mapping"] };
8723
- return { ok: true, value: raw };
8724
- }
8725
8714
  function unknownKeys(record, known, where, problems) {
8726
8715
  for (const key of Object.keys(record)) {
8727
8716
  if (!known.includes(key)) problems.push(`${where}: unknown key "${key}"`);
8728
8717
  }
8729
8718
  }
8730
- function criterionId(value, where, problems) {
8731
- if (typeof value !== "string" || !ArtifactCriterionIdSchema.safeParse(value).success) {
8732
- problems.push(`${where}: "${String(value)}" is not a criterion id (1-64 characters of letters, digits, "_", ".", ":" or "-")`);
8733
- return void 0;
8734
- }
8735
- return value;
8736
- }
8737
- function parseProofRecipe(text) {
8738
- var _a, _b;
8739
- const loaded = load(text);
8740
- if (!loaded.ok) return loaded;
8741
- const root = loaded.value;
8742
- const problems = [];
8743
- unknownKeys(root, ["run", "manual"], "recipe", problems);
8744
- const run = [];
8745
- const manual = [];
8746
- const named = /* @__PURE__ */ new Map();
8747
- const name = (id, where) => {
8748
- const earlier = named.get(id);
8749
- if (earlier !== void 0) problems.push(`${where}: criterion ${id} is already named in ${earlier}. Name each criterion in one place`);
8750
- else named.set(id, where);
8751
- };
8752
- const runRaw = (_a = root.run) != null ? _a : [];
8753
- if (!Array.isArray(runRaw)) problems.push("run: must be a list");
8754
- else {
8755
- let demos = 0;
8756
- runRaw.forEach((entry, index) => {
8757
- const where = `run[${index}]`;
8758
- if (!isRecord2(entry)) {
8759
- problems.push(`${where}: must be a mapping with command, emit and for`);
8760
- return;
8761
- }
8762
- unknownKeys(entry, ["command", "emit", "for"], where, problems);
8763
- const { command, emit } = entry;
8764
- if (typeof command !== "string") problems.push(`${where}: command must be a string`);
8765
- if (typeof emit !== "string") problems.push(`${where}: emit must be "${DEMO}" or a path in the repository`);
8766
- if (typeof command !== "string" || typeof emit !== "string") return;
8767
- if (emit === DEMO) {
8768
- demos += 1;
8769
- if (demos > 1) problems.push(`${where}: a recipe has one demo entry`);
8770
- if (entry.for !== void 0) problems.push(`${where}: a demo entry takes no "for". Its chapters name their criteria`);
8771
- run.push({ command, emit });
8772
- return;
8773
- }
8774
- if (entry.for === void 0) {
8775
- problems.push(`${where}: a command entry needs "for", the criterion its file proves`);
8776
- return;
8777
- }
8778
- const id = criterionId(entry.for, `${where}.for`, problems);
8779
- if (id === void 0) return;
8780
- name(id, where);
8781
- run.push({ command, emit, for: id });
8782
- });
8783
- }
8784
- const manualRaw = (_b = root.manual) != null ? _b : [];
8785
- if (!Array.isArray(manualRaw)) problems.push("manual: must be a list");
8786
- else {
8787
- manualRaw.forEach((entry, index) => {
8788
- const where = `manual[${index}]`;
8789
- if (!isRecord2(entry)) {
8790
- problems.push(`${where}: must be a mapping with criterion and reason`);
8791
- return;
8792
- }
8793
- unknownKeys(entry, ["criterion", "reason"], where, problems);
8794
- const id = criterionId(entry.criterion, `${where}.criterion`, problems);
8795
- if (typeof entry.reason !== "string" || entry.reason.trim() === "") {
8796
- problems.push(`${where}: reason must say why a person records this proof`);
8797
- return;
8798
- }
8799
- if (id === void 0) return;
8800
- name(id, where);
8801
- manual.push({ criterion: id, reason: entry.reason });
8802
- });
8719
+ function parseProofsConfig(text) {
8720
+ let raw;
8721
+ try {
8722
+ raw = (0, import_yaml.parse)(text);
8723
+ } catch (err) {
8724
+ return { ok: false, problems: [`the file is not valid YAML: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`] };
8803
8725
  }
8804
- return problems.length > 0 ? { ok: false, problems } : { ok: true, value: { run, manual } };
8805
- }
8806
- function parseProofSetup(text) {
8807
- const loaded = load(text);
8808
- if (!loaded.ok) return loaded;
8809
- const root = loaded.value;
8726
+ const root = raw === null || raw === void 0 ? {} : raw;
8727
+ if (!isRecord2(root)) return { ok: false, problems: ["the file must be a mapping"] };
8810
8728
  const problems = [];
8811
- unknownKeys(root, ["setup", "teardown"], "setup file", problems);
8812
- const commands = (key, value) => {
8729
+ unknownKeys(root, ["setup", "teardown", "runners"], "proofs file", problems);
8730
+ const commands = (key) => {
8731
+ const value = root[key];
8732
+ if (value === void 0) return [];
8813
8733
  if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string" && entry.trim() !== "")) {
8814
8734
  problems.push(`${key}: must be a list of commands`);
8815
8735
  return [];
8816
8736
  }
8817
8737
  return value;
8818
8738
  };
8819
- if (!("setup" in root)) problems.push("setup: the file needs a setup list. Use an empty list for no setup");
8820
- const setup = "setup" in root ? commands("setup", root.setup) : [];
8821
- const teardown = root.teardown === void 0 ? void 0 : commands("teardown", root.teardown);
8822
- if (problems.length > 0) return { ok: false, problems };
8823
- return { ok: true, value: { setup, ...teardown === void 0 ? {} : { teardown } } };
8824
- }
8825
- function renderProofRecipe(recipe) {
8826
- return (0, import_yaml.stringify)({ run: recipe.run, manual: recipe.manual }, { lineWidth: 0 });
8827
- }
8828
- function renderProofSetup(setup) {
8829
- return (0, import_yaml.stringify)({ setup: setup.setup, ...setup.teardown === void 0 ? {} : { teardown: setup.teardown } }, { lineWidth: 0 });
8739
+ const setup = commands("setup");
8740
+ const teardown = commands("teardown");
8741
+ const runners = [];
8742
+ if (!Array.isArray(root.runners)) {
8743
+ problems.push("runners: the file needs a runners list. Use an empty list for no runner");
8744
+ } else {
8745
+ root.runners.forEach((entry, index) => {
8746
+ const where = `runners[${index}]`;
8747
+ if (!isRecord2(entry)) {
8748
+ problems.push(`${where}: must be a mapping with files and command`);
8749
+ return;
8750
+ }
8751
+ unknownKeys(entry, ["files", "command"], where, problems);
8752
+ const { files, command } = entry;
8753
+ if (typeof files !== "string" || files.trim() === "") problems.push(`${where}: files must be a glob string`);
8754
+ if (typeof command !== "string" || command.trim() === "") problems.push(`${where}: command must be a string`);
8755
+ else if (!command.includes(FILES_PLACEHOLDER)) problems.push(`${where}: command must contain ${FILES_PLACEHOLDER}, where the matched test files go`);
8756
+ if (typeof files === "string" && files.trim() !== "" && typeof command === "string" && command.includes(FILES_PLACEHOLDER)) runners.push({ files, command });
8757
+ });
8758
+ }
8759
+ return problems.length > 0 ? { ok: false, problems } : { ok: true, value: { setup, teardown, runners } };
8830
8760
  }
8831
8761
 
8832
- export { ALL_TARGET_IDS, CONTEXT_PIN_FILENAME, classifyTree, emitTree, extractFacts, generatedHeaderSource, normalizePath, normalizeRepoName, orderSessions, parseOuterlayerConfig, parsePolicy, parseProofRecipe, parseProofSetup, renderProofRecipe, renderProofSetup, sessionsToTimeline, splitRawFile };
8762
+ export { ALL_TARGET_IDS, CONTEXT_PIN_FILENAME, classifyTree, emitTree, extractFacts, generatedHeaderSource, normalizePath, normalizeRepoName, orderSessions, parseOuterlayerConfig, parsePolicy, parseProofsConfig, sessionsToTimeline, splitRawFile };
@@ -1,20 +1,66 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { WorkCommandError, resolveCredentials, getJson } from './chunk-HIGP4WOC.js';
3
+ import { WorkCommandError, resolveCredentials, getJson } from './chunk-Z4KWHSO4.js';
4
4
  import { sanitizeTerminal } from './chunk-MECW77XP.js';
5
5
  import { resolveRepoIdentity } from './chunk-6ZFY2L2T.js';
6
6
  import { C } from './chunk-ANPNT6PM.js';
7
7
  import { defaultFetch } from './chunk-6RKD7YZ6.js';
8
8
  import { parseWorkItemEnv } from './chunk-T2Q7ISPE.js';
9
9
  import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
10
+ import { inferArtifactKind, mediaTypeForArtifactPath, WORK_ITEM_COMMENT_MAX_BODY_LENGTH } from './chunk-EOTMDIYC.js';
11
+ import { createHash } from 'crypto';
10
12
 
11
13
  createRequire(import.meta.url);
14
+ function kindProblem(declared, file) {
15
+ if (declared === "test") return "a test proof is recorded by CI, not by --record";
16
+ const kind = inferArtifactKind(mediaTypeForArtifactPath(file));
17
+ return kind === declared ? void 0 : `the kinds differ: the file is a ${kind}, but the criterion declares a ${declared} proof`;
18
+ }
19
+ function proofsCommentBody(head, lines) {
20
+ const header = `These proofs are not current at ${head.slice(0, 7)}:`;
21
+ const rows = lines.map((line) => `- ${line.id} (${line.proof}): ${line.reason}`);
22
+ const fits = (count2) => {
23
+ const left = rows.length - count2;
24
+ return [header, ...rows.slice(0, count2), ...left > 0 ? [`and ${left} more.`] : []].join("\n");
25
+ };
26
+ let count = rows.length;
27
+ while (count > 0 && fits(count).length > WORK_ITEM_COMMENT_MAX_BODY_LENGTH) count -= 1;
28
+ return fits(count);
29
+ }
30
+ function proofsCommentId(item, head, lines) {
31
+ const list = [...lines].sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0).map((line) => [line.id, line.proof, line.reason]);
32
+ const digest = createHash("sha256").update(JSON.stringify([item, head.toLowerCase(), list])).digest("hex");
33
+ return `proofs-${digest.slice(0, 32)}`;
34
+ }
35
+ function repositoryName(repository) {
36
+ return repository.replace(/\.git$/, "").split("/").filter((part) => part !== "").slice(-2).join("/").toLowerCase();
37
+ }
38
+ function ownPullRequest(pullRequests, requested, checkoutRepository) {
39
+ if (requested !== void 0) return { pr: requested };
40
+ const here = checkoutRepository === void 0 ? void 0 : repositoryName(checkoutRepository);
41
+ const open = pullRequests.filter(
42
+ (pr) => pr.state === "open" && typeof pr.prNumber === "number" && (here === void 0 || repositoryName(pr.repository ?? "") === here)
43
+ );
44
+ if (open.length > 1) return { ambiguous: open.map((pr) => pr.prNumber) };
45
+ return { pr: open[0]?.prNumber };
46
+ }
12
47
 
13
48
  // src/work-proofs-cmd.ts
14
49
  function liveHead(pr) {
15
50
  if (pr.state !== "open" && pr.state !== "merged" || typeof pr.headSha !== "string" || pr.headSha === "") return void 0;
16
51
  return pr.headSha.toLowerCase();
17
52
  }
53
+ function otherPullRequestHeads(pullRequests, ownPr, checkoutRepository) {
54
+ const here = checkoutRepository === void 0 ? void 0 : repositoryName(checkoutRepository);
55
+ const heads = /* @__PURE__ */ new Set();
56
+ for (const pr of pullRequests) {
57
+ const head = liveHead(pr);
58
+ if (head === void 0) continue;
59
+ const isOwn = ownPr !== void 0 && pr.prNumber === ownPr && (here === void 0 || repositoryName(pr.repository ?? "") === here);
60
+ if (!isOwn) heads.add(head);
61
+ }
62
+ return heads;
63
+ }
18
64
  function classifyProofs(data, checkoutHead) {
19
65
  const heads = /* @__PURE__ */ new Set();
20
66
  if (checkoutHead !== void 0 && checkoutHead !== "") heads.add(checkoutHead.toLowerCase());
@@ -83,14 +129,8 @@ async function runWorkProofs(opts) {
83
129
  }
84
130
  async function runWorkProofsCommand(opts) {
85
131
  try {
86
- if (opts.init) {
87
- const { runWorkProofsInit } = await import('./work-proofs-init-GNGI7PZU.js');
88
- await runWorkProofsInit(opts);
89
- process.exitCode = 0;
90
- return;
91
- }
92
132
  if (opts.record) {
93
- const { runWorkProofsRecord } = await import('./work-proofs-record-HTWSMEDG.js');
133
+ const { runWorkProofsRecord } = await import('./work-proofs-record-XPAU7N57.js');
94
134
  const result2 = await runWorkProofsRecord(opts);
95
135
  process.exitCode = result2.exitCode;
96
136
  return;
@@ -108,4 +148,4 @@ async function runWorkProofsCommand(opts) {
108
148
  }
109
149
  }
110
150
 
111
- export { classifyProofs, classifyProofsAt, liveHead, resolveProofsItem, runWorkProofs, runWorkProofsCommand };
151
+ export { classifyProofs, classifyProofsAt, kindProblem, otherPullRequestHeads, ownPullRequest, proofsCommentBody, proofsCommentId, resolveProofsItem, runWorkProofs, runWorkProofsCommand };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { skillDir, FORMER_MAINTAINED_NAMES, isMaintainedCopy } from './chunk-ZGB4ZJ5E.js';
3
+ import { skillDir, FORMER_MAINTAINED_NAMES, isMaintainedCopy } from './chunk-ZQSANKS4.js';
4
4
  import { cliInvocation } from './chunk-CRB3POP4.js';
5
- import { emitTree, ALL_TARGET_IDS, classifyTree } from './chunk-CQRPR4WZ.js';
5
+ import { emitTree, ALL_TARGET_IDS, classifyTree } from './chunk-FGXT5OXS.js';
6
6
  import { readFileSync, existsSync, unlinkSync, rmdirSync, readdirSync } from 'fs';
7
7
  import { join, dirname, relative, sep } from 'path';
8
8
 
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { launchRefusalForSession } from './chunk-ESVW4MJY.js';
4
4
  import { detectActiveSession } from './chunk-IP7BIBXJ.js';
5
- import { autoConnect } from './chunk-OHJDH5GV.js';
5
+ import { autoConnect } from './chunk-6NUPXDAA.js';
6
6
  import { resolveRepoIdentity } from './chunk-6ZFY2L2T.js';
7
7
  import { C } from './chunk-ANPNT6PM.js';
8
8
  import { resolveGatewayCredentials, defaultFetch, unauthorizedMessage } from './chunk-6RKD7YZ6.js';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { AGENTS_SKILLS_BASE, OUTERLAYER_SKILLS_BASE } from './chunk-ZGB4ZJ5E.js';
4
- import { normalizePath, CONTEXT_PIN_FILENAME } from './chunk-CQRPR4WZ.js';
3
+ import { AGENTS_SKILLS_BASE, OUTERLAYER_SKILLS_BASE } from './chunk-ZQSANKS4.js';
4
+ import { normalizePath, CONTEXT_PIN_FILENAME } from './chunk-FGXT5OXS.js';
5
5
  import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, lstatSync, readlinkSync, symlinkSync, rmdirSync } from 'fs';
6
6
  import { relative, sep, join } from 'path';
7
7