@outerlayer/cli 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/README.md +36 -2
  3. package/dist/agent-setup-TPR4BBFV.js +27 -0
  4. package/dist/{artifact-link-cmd-2F47LT7F.js → artifact-link-cmd-W7XF5BFB.js} +4 -3
  5. package/dist/{build-BG2YENGK.js → build-TQ6X5PYN.js} +5 -4
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-2D3WSOOY.js → builder-C4QNTYMS.js} +5 -6
  8. package/dist/{check-5XE7XMC4.js → check-UWQAL2MN.js} +56 -52
  9. package/dist/{chunk-R7PF5OOU.js → chunk-3CWUOFV6.js} +21 -14
  10. package/dist/{chunk-4NPZVMJU.js → chunk-3UZTIRLF.js} +60 -4
  11. package/dist/chunk-452TM7J4.js +502 -0
  12. package/dist/{chunk-NNRTPG7X.js → chunk-5GHGAF6P.js} +4 -4
  13. package/dist/{chunk-WVUIRTWA.js → chunk-5MYFOW5V.js} +196 -37
  14. package/dist/{chunk-HGECYFEI.js → chunk-5TN7GLYX.js} +138 -109
  15. package/dist/{chunk-VQYBXPI7.js → chunk-6D7GT22T.js} +5 -5
  16. package/dist/{chunk-G5NPRL2K.js → chunk-6U3MV7TZ.js} +687 -76
  17. package/dist/{chunk-42ZI52JW.js → chunk-6X4SQ5MY.js} +4 -3
  18. package/dist/{chunk-MAK5LYRF.js → chunk-7KSSBQTS.js} +278 -535
  19. package/dist/{chunk-NWQTTSBB.js → chunk-7SJPQWBM.js} +41 -16
  20. package/dist/{chunk-J5M7BSJQ.js → chunk-7VUK5RFS.js} +23 -4
  21. package/dist/{chunk-OZGHL5Y5.js → chunk-7YP7T6GV.js} +2 -2
  22. package/dist/{chunk-TI7B7UEO.js → chunk-AMFWYESY.js} +1 -1
  23. package/dist/{chunk-YRYMNBGQ.js → chunk-ANPNT6PM.js} +2 -1
  24. package/dist/{chunk-4KSQKQXE.js → chunk-BM63HB2M.js} +20 -16
  25. package/dist/{chunk-4Q7OMKAT.js → chunk-BQXFBI7T.js} +81 -5
  26. package/dist/{chunk-ADJRGVZC.js → chunk-BWSUPRDK.js} +1 -1
  27. package/dist/{chunk-3NSNIIBE.js → chunk-CG36IONK.js} +18 -17
  28. package/dist/chunk-CJJDJ7AT.js +56 -0
  29. package/dist/chunk-CRB3POP4.js +34 -0
  30. package/dist/{chunk-LWSJQJC6.js → chunk-DADWEUH3.js} +7 -7
  31. package/dist/{chunk-KG5ECZGJ.js → chunk-DJ3ZUSC3.js} +11 -11
  32. package/dist/{chunk-F47JBIAW.js → chunk-DSF2FWAZ.js} +2 -1
  33. package/dist/{chunk-N5FOE5PS.js → chunk-ECODQ7II.js} +4 -33
  34. package/dist/{chunk-HHJDN6AU.js → chunk-ESVW4MJY.js} +1 -1
  35. package/dist/{chunk-YO4PSLVB.js → chunk-FVMYKL6L.js} +1 -1
  36. package/dist/chunk-G2YNJIGF.js +44 -0
  37. package/dist/{chunk-WUYTWNMA.js → chunk-G3IJ3N6F.js} +5 -3
  38. package/dist/{chunk-QKFB4K7X.js → chunk-GGOMT6KF.js} +1 -1
  39. package/dist/{chunk-N6LURUEF.js → chunk-GOSFARMS.js} +1 -1
  40. package/dist/{chunk-S3NYLI2P.js → chunk-HPJNLETG.js} +93 -38
  41. package/dist/{chunk-IP7BIBXJ.js → chunk-IF2OSI5T.js} +35 -1
  42. package/dist/{chunk-C5Y5ZJJZ.js → chunk-IXYZUUYQ.js} +5 -4
  43. package/dist/chunk-JBJTC3UU.js +35 -0
  44. package/dist/chunk-KYS3TQAG.js +296 -0
  45. package/dist/chunk-LLM3I5YU.js +89 -0
  46. package/dist/{chunk-YU3VKZ5F.js → chunk-LRG3ZMZD.js} +6 -7
  47. package/dist/{chunk-V7NIVOFD.js → chunk-M2ZWWTWZ.js} +1 -1
  48. package/dist/{chunk-ERI5GBNI.js → chunk-MLAAT4S6.js} +3 -3
  49. package/dist/{chunk-O765JR4W.js → chunk-MTP2QEVO.js} +1 -1
  50. package/dist/{chunk-ZM2IMMYN.js → chunk-N2PXGQRL.js} +9 -1
  51. package/dist/{chunk-BWQ66M6N.js → chunk-NFIR3GEE.js} +98 -24
  52. package/dist/{chunk-POJMEEJJ.js → chunk-NNLA7LLQ.js} +1 -1
  53. package/dist/{chunk-PLMTLGYH.js → chunk-NTRCK4NH.js} +5 -4
  54. package/dist/{chunk-22RMZBGW.js → chunk-P53VEAOF.js} +1 -1
  55. package/dist/{chunk-RLYZLUQ7.js → chunk-QEFKA2QD.js} +2 -2
  56. package/dist/{chunk-JXYVA45C.js → chunk-QNLX477Q.js} +1200 -322
  57. package/dist/{chunk-UGP76IZ5.js → chunk-S5PCA3SN.js} +1 -1
  58. package/dist/{chunk-RMWLBUCJ.js → chunk-SADUQSO4.js} +1 -1
  59. package/dist/{chunk-GQD22KKN.js → chunk-T2Q7ISPE.js} +2 -1
  60. package/dist/chunk-TUSYOL2O.js +113 -0
  61. package/dist/{chunk-NBGDBTO2.js → chunk-TWF3RICI.js} +9 -8
  62. package/dist/{chunk-ONKJUM6R.js → chunk-UVG35MWF.js} +1 -1
  63. package/dist/{chunk-KMDLFI4P.js → chunk-VMJPFQNE.js} +1 -1
  64. package/dist/chunk-VRRGENS4.js +144 -0
  65. package/dist/{chunk-PTW6W5NR.js → chunk-VYAL7PUE.js} +1 -1
  66. package/dist/{chunk-OHVJA253.js → chunk-WFSUUUAN.js} +47 -30
  67. package/dist/{chunk-RSNSZ2LJ.js → chunk-X5H2WYMB.js} +1 -1
  68. package/dist/{chunk-HYZRY4KZ.js → chunk-XNGMQ27R.js} +16 -6
  69. package/dist/chunk-XSZD4AZ6.js +490 -0
  70. package/dist/chunk-YQR6E6OV.js +109 -0
  71. package/dist/{chunk-XCK2YAY5.js → chunk-YVZJ6GKF.js} +3 -2
  72. package/dist/{chunk-2MNPHL23.js → chunk-ZHAUSEEN.js} +38 -15
  73. package/dist/claude-launcher-FPPHZPMR.js +115 -0
  74. package/dist/{cli-A76AXELQ.js → cli-HROW5T7X.js} +567 -285
  75. package/dist/{command-R2QCVX55.js → command-OEAV7BVX.js} +42 -40
  76. package/dist/{config-N3C6DFQA.js → config-CLSGABD5.js} +2 -3
  77. package/dist/{connect-cmd-JBKAQNSF.js → connect-cmd-UNYKGDAL.js} +10 -9
  78. package/dist/context-cleanup-HSVYDGMI.js +9 -0
  79. package/dist/control-plane-launch-NYVDJESK.js +216 -0
  80. package/dist/{dist-LKDWQWZ7.js → dist-WO7NOJNG.js} +2 -2
  81. package/dist/{docker-4J77Q2BF.js → docker-BFU3AQGY.js} +7 -8
  82. package/dist/{doctor-4TAIARIG.js → doctor-23BBJWBX.js} +48 -42
  83. package/dist/{emit-artifact-cmd-MPZVR56N.js → emit-artifact-cmd-O6SCM7TV.js} +27 -24
  84. package/dist/emit-cmd-7SP3I6UZ.js +14 -0
  85. package/dist/{emit-criteria-cmd-EFGYI23V.js → emit-criteria-cmd-LQNERZRV.js} +17 -16
  86. package/dist/{emit-finding-cmd-5GF3V4LR.js → emit-finding-cmd-AJPKHIOV.js} +18 -17
  87. package/dist/{emit-result-cmd-I4OADKMD.js → emit-result-cmd-RUICOKWQ.js} +22 -19
  88. package/dist/emit-step-cmd-347XNGPQ.js +26 -0
  89. package/dist/{exec-client-CQV746UF.js → exec-client-7UMESIE2.js} +3 -4
  90. package/dist/governing-source-V5EEGPTA.js +34 -0
  91. package/dist/guest-init-KPBQOFE5.js +9 -0
  92. package/dist/{hook-fast-R4FVSZ2H.js → hook-fast-YAZG5MDX.js} +5 -2
  93. package/dist/host-key-U4B5QETR.js +8 -0
  94. package/dist/{import-capture-cmd-EQ35EARA.js → import-capture-cmd-KKFFOGWP.js} +7 -5
  95. package/dist/{import-ruler-cmd-BGAZXCQM.js → import-ruler-cmd-5P6JOXQN.js} +5 -3
  96. package/dist/index.js +8 -4
  97. package/dist/{init-PWU5YVL7.js → init-LWHDMZQG.js} +40 -38
  98. package/dist/init-MOINY2DD.js +53 -0
  99. package/dist/{init-cmd-XAVO7HYZ.js → init-cmd-HSMRID6A.js} +75 -30
  100. package/dist/{init-update-CVCWD6VS.js → init-update-LWX5MPPR.js} +29 -29
  101. package/dist/{install-HDBIPHTX.js → install-4SEFIIW2.js} +4 -5
  102. package/dist/{install-cmd-5HYMXLEW.js → install-cmd-QDOTR4OM.js} +5 -4
  103. package/dist/{login-browser-QZCS3WW6.js → login-browser-DX35MARZ.js} +5 -4
  104. package/dist/{logout-cmd-QAUFDJ6J.js → logout-cmd-5V5MMBSY.js} +3 -2
  105. package/dist/{logs-H55NWW4H.js → logs-AMLKC3VP.js} +3 -1
  106. package/dist/loop-SYYPVFYW.js +77 -0
  107. package/dist/machine-6X63G2KH.js +48 -0
  108. package/dist/{mcp-install-cmd-FDTPQQS6.js → mcp-install-cmd-GGWB3JJ2.js} +3 -2
  109. package/dist/{mcp-serve-cmd-3KVYEUXG.js → mcp-serve-cmd-N3UTY6EE.js} +11 -9
  110. package/dist/paths-7XP63OAX.js +7 -0
  111. package/dist/pending-532ABZYC.js +8 -0
  112. package/dist/{pidfile-UZRH774M.js → pidfile-3DM4OBKO.js} +4 -2
  113. package/dist/{record-C43U4PKS.js → record-3WP6V2K5.js} +3 -2
  114. package/dist/{runner-env-EN7YE7QX.js → runner-env-FRZFFHDF.js} +5 -6
  115. package/dist/{runner-key-6SLBI7PP.js → runner-key-276SJU5R.js} +40 -38
  116. package/dist/session-sender-GGIY5OAX.js +36 -0
  117. package/dist/{pending-MXLSRYMO.js → shell-function-NRD4KVUK.js} +1 -2
  118. package/dist/spec-cmd-SIZBRN7D.js +115 -0
  119. package/dist/{starter-pack-KF66HGZR.js → starter-pack-6LQVLBIA.js} +7 -5
  120. package/dist/{status-7VNQN5PW.js → status-NAK6DYSF.js} +46 -42
  121. package/dist/{statusline-fast-SVTMBMD7.js → statusline-fast-KN3BX67H.js} +2 -1
  122. package/dist/sync-cmd-G7GF4UTW.js +35 -0
  123. package/dist/{watch-23HSAEI6.js → watch-EVM5GSMP.js} +22 -15
  124. package/dist/{work-claim-cmd-LKL3GHFQ.js → work-claim-cmd-3J3QW56U.js} +26 -29
  125. package/dist/work-cmd-5EPPD33Y.js +24 -0
  126. package/dist/{work-comment-cmd-AWHP56M2.js → work-comment-cmd-2ACOZQAE.js} +16 -15
  127. package/dist/{work-launch-R5HTAP6X.js → work-launch-LEQ2MPM3.js} +3 -1
  128. package/dist/work-logs-cmd-QDD2NMJL.js +60 -0
  129. package/dist/{work-open-pr-cmd-IOM4AVQQ.js → work-open-pr-cmd-XNCEI4ZM.js} +18 -17
  130. package/dist/work-pr-cmd-H4OQR26N.js +25 -0
  131. package/package.json +3 -2
  132. package/skill-pack/maintained/outerlayer-amend/SKILL.md +4 -2
  133. package/skill-pack/maintained/outerlayer-cli/SKILL.md +9 -2
  134. package/skill-pack/maintained/outerlayer-cli/references/find-out-why-a-build-ended.md +76 -0
  135. package/skill-pack/shipped.json +18 -2
  136. package/skill-pack/template/build/SKILL.md +23 -10
  137. package/skill-pack/template/build/references/agent-briefs.md +3 -1
  138. package/skill-pack/template/build/references/criteria-judge.md +27 -0
  139. package/skill-pack/template/build/references/release.md +22 -29
  140. package/skill-pack/template/spec/SKILL.md +35 -10
  141. package/skill-pack/validators/acceptance-criteria.yaml +25 -26
  142. package/dist/agent-setup-T624CWPD.js +0 -27
  143. package/dist/chunk-6Y5RUTHO.js +0 -39
  144. package/dist/chunk-BYT5O5RV.js +0 -61
  145. package/dist/chunk-WTE3MQML.js +0 -133
  146. package/dist/chunk-XCCLFVXM.js +0 -401
  147. package/dist/chunk-YZ5F4PIS.js +0 -797
  148. package/dist/context-adopt-NFHCLVUB.js +0 -108
  149. package/dist/context-materialize-IV2TUUFO.js +0 -22
  150. package/dist/emit-cmd-IJ3GVRFD.js +0 -12
  151. package/dist/guest-init-LJP5GPZF.js +0 -9
  152. package/dist/host-key-YMLXY6QB.js +0 -7
  153. package/dist/init-6XPDRDTC.js +0 -51
  154. package/dist/loop-FK3LPMMZ.js +0 -73
  155. package/dist/machine-SQXEBAM2.js +0 -46
  156. package/dist/paths-OYKMVYJP.js +0 -6
  157. package/dist/session-sender-FO3LCREV.js +0 -29
  158. package/dist/sync-cmd-GVPPFZ3G.js +0 -28
  159. package/dist/work-cmd-Z2WXLZPH.js +0 -23
  160. package/dist/work-pr-cmd-HNEUIEN7.js +0 -24
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { C } from './chunk-YRYMNBGQ.js';
4
- import { retiredSkillPaths, removeRetiredSkills } from './chunk-C5Y5ZJJZ.js';
5
- import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-POJMEEJJ.js';
6
- import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-OHVJA253.js';
7
- import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, readdirSync } from 'fs';
3
+ import { C } from './chunk-ANPNT6PM.js';
4
+ import { retiredSkillPaths, removeRetiredSkills } from './chunk-IXYZUUYQ.js';
5
+ import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-NNLA7LLQ.js';
6
+ import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-WFSUUUAN.js';
7
+ import { cliInvocation } from './chunk-CRB3POP4.js';
8
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, unlinkSync, rmdirSync, readdirSync } from 'fs';
8
9
  import { join, dirname, relative, sep } from 'path';
9
10
 
10
11
  createRequire(import.meta.url);
@@ -31,6 +32,9 @@ function discoverOuterlayerPaths(repoRoot) {
31
32
  walk(repoRoot, repoRoot, false, out);
32
33
  return out.sort();
33
34
  }
35
+ function isForeignTree(dir) {
36
+ return existsSync(join(dir, ".git")) || existsSync(join(dir, CONTEXT_PIN_FILENAME));
37
+ }
34
38
  function walk(dir, repoRoot, insideOuterlayer, out) {
35
39
  let entries;
36
40
  try {
@@ -43,7 +47,7 @@ function walk(dir, repoRoot, insideOuterlayer, out) {
43
47
  const full = join(dir, entry.name);
44
48
  if (entry.isDirectory()) {
45
49
  if (!insideOuterlayer && SKIP_DIRS.has(entry.name)) continue;
46
- if (!insideOuterlayer && existsSync(join(full, CONTEXT_PIN_FILENAME))) continue;
50
+ if (!insideOuterlayer && isForeignTree(full)) continue;
47
51
  walk(full, repoRoot, insideOuterlayer || entry.name === ".outerlayer", out);
48
52
  } else if (entry.isFile() && insideOuterlayer) {
49
53
  out.push(toRepoRelative(repoRoot, full));
@@ -81,13 +85,14 @@ function writeOutputs(repoRoot, result, maintained) {
81
85
  }
82
86
  return { files, copies, maintained: [...changedMaintained.created, ...changedMaintained.rewritten] };
83
87
  }
84
- function renderSuccess(targets, files, copies, maintained, retired) {
88
+ function renderSuccess(targets, files, copies, maintained, retired, orphaned) {
85
89
  const copySuffix = copies.length > 0 ? `, ${copies.length} ${copies.length === 1 ? "copy" : "copies"}` : "";
86
90
  const lines = [
87
91
  `${C.green}\u2713${C.reset} emitted ${files.length} file${files.length === 1 ? "" : "s"}${copySuffix} for ${C.dim}${targets.join(", ")}${C.reset}`
88
92
  ];
89
93
  for (const path of maintained) lines.push(` ${C.dim}updated ${path} to this CLI's version${C.reset}`);
90
94
  for (const path of retired) lines.push(` ${C.dim}removed ${path}: this skill has a new name${C.reset}`);
95
+ for (const path of orphaned) lines.push(` ${C.dim}removed ${path}: its source is gone${C.reset}`);
91
96
  return lines.join("\n");
92
97
  }
93
98
  function renderFailure(errors) {
@@ -97,7 +102,7 @@ function renderFailure(errors) {
97
102
  }
98
103
  function renderCheck(targets, drift) {
99
104
  if (drift.length === 0) return `${C.green}\u2713${C.reset} up to date for ${C.dim}${targets.join(", ")}${C.reset}`;
100
- const lines = [`${C.red}\u2717${C.reset} drift detected (${drift.length}) \u2014 run \`outerlayer emit\` to update`];
105
+ const lines = [`${C.red}\u2717${C.reset} drift detected (${drift.length}) \u2014 run \`${cliInvocation()} emit\` to update`];
101
106
  for (const d of drift) lines.push(` ${C.red}\u2717${C.reset} ${d.kind.padEnd(8)} ${d.path}`);
102
107
  return lines.join("\n");
103
108
  }
@@ -131,7 +136,7 @@ function walkAll(dir, repoRoot, out) {
131
136
  if (entry.isSymbolicLink()) continue;
132
137
  const full = join(dir, entry.name);
133
138
  if (entry.isDirectory()) {
134
- if (SKIP_DIRS.has(entry.name) || entry.name === ".outerlayer") continue;
139
+ if (SKIP_DIRS.has(entry.name) || entry.name === ".outerlayer" || isForeignTree(full)) continue;
135
140
  walkAll(full, repoRoot, out);
136
141
  } else if (entry.isFile()) {
137
142
  out.push(toRepoRelative(repoRoot, full));
@@ -154,6 +159,21 @@ function findOrphans(repoRoot, computedFiles, sourcePaths) {
154
159
  }
155
160
  return orphans;
156
161
  }
162
+ function removeOrphans(repoRoot, orphans) {
163
+ const removed = [];
164
+ for (const { path } of orphans) {
165
+ unlinkSync(join(repoRoot, path));
166
+ removed.push(path);
167
+ for (let dir = dirname(path); dir !== "."; dir = dirname(dir)) {
168
+ try {
169
+ rmdirSync(join(repoRoot, dir));
170
+ } catch {
171
+ break;
172
+ }
173
+ }
174
+ }
175
+ return removed;
176
+ }
157
177
  function withholdKept(repoRoot, result, keep) {
158
178
  if (keep === void 0) return { result, kept: [] };
159
179
  const kept = [];
@@ -186,9 +206,11 @@ function runEmit(opts = {}) {
186
206
  const emitted = emitTree(built.input);
187
207
  const { result, kept } = withholdKept(cwd, emitted, opts.keep);
188
208
  const hasErrors = result.errors.length > 0;
189
- if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, built.sourcePaths, maintained, kept, retired);
209
+ const outputs = new Set(emitted.files.map((f) => f.path));
210
+ if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, outputs, built.sourcePaths, maintained, kept, retired);
190
211
  const written = hasErrors ? { files: [], copies: [], maintained: [] } : writeOutputs(cwd, result, maintained);
191
212
  const removed = hasErrors ? [] : removeRetiredSkills(cwd);
213
+ const orphaned = hasErrors ? [] : removeOrphans(cwd, findOrphans(cwd, outputs, built.sourcePaths));
192
214
  const exitCode = hasErrors ? 1 : 0;
193
215
  const output = opts.json ? JSON.stringify({
194
216
  targets,
@@ -196,9 +218,10 @@ function runEmit(opts = {}) {
196
218
  copies: written.copies,
197
219
  maintained: written.maintained,
198
220
  retired: removed,
221
+ orphaned,
199
222
  warnings: result.warnings,
200
223
  errors: result.errors
201
- }) : hasErrors ? renderFailure(result.errors) : renderSuccess(targets, written.files, written.copies, written.maintained, removed);
224
+ }) : hasErrors ? renderFailure(result.errors) : renderSuccess(targets, written.files, written.copies, written.maintained, removed, orphaned);
202
225
  if (!opts.quiet) {
203
226
  if (opts.json) {
204
227
  process.stdout.write(output + "\n");
@@ -217,13 +240,14 @@ function runEmit(opts = {}) {
217
240
  maintained: written.maintained,
218
241
  kept,
219
242
  retired: removed,
243
+ orphaned,
220
244
  warnings: result.warnings,
221
245
  errors: result.errors,
222
246
  output,
223
247
  exitCode
224
248
  };
225
249
  }
226
- function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained, kept, retired) {
250
+ function runCheck(cwd, opts, targets, result, hasErrors, outputs, sourcePaths, maintained, kept, retired) {
227
251
  const drift = [];
228
252
  if (!hasErrors) {
229
253
  for (const path of retired) drift.push({ kind: "retired", path });
@@ -231,7 +255,6 @@ function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained
231
255
  const d = compareFile(cwd, file.path, file.content);
232
256
  if (d) drift.push(d);
233
257
  }
234
- const computedFiles = new Set(result.files.map((f) => f.path));
235
258
  for (const file of result.files) {
236
259
  const d = compareFile(cwd, file.path, file.content);
237
260
  if (d) drift.push(d);
@@ -241,7 +264,7 @@ function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained
241
264
  if (d) drift.push(d);
242
265
  }
243
266
  const retiredPaths = new Set(retired);
244
- drift.push(...findOrphans(cwd, computedFiles, sourcePaths).filter((d) => !retiredPaths.has(d.path)));
267
+ drift.push(...findOrphans(cwd, outputs, sourcePaths).filter((d) => !retiredPaths.has(d.path)));
245
268
  drift.sort((a, b) => a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind));
246
269
  }
247
270
  const exitCode = hasErrors || drift.length > 0 ? 1 : 0;
@@ -257,7 +280,7 @@ function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained
257
280
  `);
258
281
  }
259
282
  }
260
- return { targets, files: [], copies: [], maintained: [], kept, retired: [], warnings: result.warnings, errors: result.errors, drift, output, exitCode };
283
+ return { targets, files: [], copies: [], maintained: [], kept, retired: [], orphaned: [], warnings: result.warnings, errors: result.errors, drift, output, exitCode };
261
284
  }
262
285
 
263
286
  export { EmitError, runEmit };
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from 'node:module';
3
+ import { versionAtLeast, MINIMUM_CLAUDE_VERSION, SHIM_SCRIPT, CONTROL_PLANE_DIR_VARIABLE } from './chunk-G2YNJIGF.js';
4
+ export { MINIMUM_CLAUDE_VERSION } from './chunk-G2YNJIGF.js';
5
+ import { homeFromEnv } from './chunk-VNVZDWO3.js';
6
+ import './chunk-Z5GEFMRW.js';
7
+ import { spawnSync, execFileSync, spawn } from 'child_process';
8
+ import { existsSync, accessSync, constants, statSync, readFileSync } from 'fs';
9
+ import { join, delimiter, isAbsolute, resolve } from 'path';
10
+
11
+ createRequire(import.meta.url);
12
+ function readDeliveryRecord(cwd) {
13
+ let common;
14
+ try {
15
+ common = execFileSync("git", ["rev-parse", "--git-common-dir"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 5e3 }).trim();
16
+ } catch {
17
+ return { kind: "none" };
18
+ }
19
+ const path = join(isAbsolute(common) ? common : resolve(cwd, common), "outerlayer", "delivery.json");
20
+ if (!existsSync(path)) return { kind: "none" };
21
+ try {
22
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
23
+ if (typeof parsed.dir === "string" && isAbsolute(parsed.dir) && typeof parsed.repository === "string" && typeof parsed.sha === "string") {
24
+ return { kind: "found", record: { repository: parsed.repository, sha: parsed.sha, dir: parsed.dir, launcher: parsed.launcher === true } };
25
+ }
26
+ } catch {
27
+ }
28
+ return { kind: "invalid", path };
29
+ }
30
+ function findClaude(path) {
31
+ for (const entry of (path ?? "").split(delimiter)) {
32
+ if (entry === "") continue;
33
+ const candidate = join(entry, "claude");
34
+ try {
35
+ accessSync(candidate, constants.X_OK);
36
+ if (statSync(candidate).size === Buffer.byteLength(SHIM_SCRIPT) && readFileSync(candidate, "utf8") === SHIM_SCRIPT) continue;
37
+ } catch {
38
+ continue;
39
+ }
40
+ return candidate;
41
+ }
42
+ return void 0;
43
+ }
44
+ var SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
45
+ var SIGNAL_NUMBERS = { SIGHUP: 1, SIGINT: 2, SIGTERM: 15 };
46
+ function run(program, argv, env, cwd, stderr) {
47
+ return new Promise((done) => {
48
+ const child = spawn(program, argv, { cwd, env, stdio: "inherit" });
49
+ const forward = (signal) => () => {
50
+ child.kill(signal);
51
+ };
52
+ const handlers = SIGNALS.map((signal) => [signal, forward(signal)]);
53
+ for (const [signal, handler] of handlers) process.on(signal, handler);
54
+ const finish = (code) => {
55
+ for (const [signal, handler] of handlers) process.off(signal, handler);
56
+ done(code);
57
+ };
58
+ child.on("error", (err) => {
59
+ stderr(`outerlayer claude: could not start ${program}: ${err.message}
60
+ `);
61
+ finish(127);
62
+ });
63
+ child.on("exit", (code, signal) => finish(code ?? 128 + (signal === null ? 0 : SIGNAL_NUMBERS[signal] ?? 0)));
64
+ });
65
+ }
66
+ async function runClaudeLauncher(args, deps = {}) {
67
+ const cwd = deps.cwd ?? process.cwd();
68
+ const env = deps.env ?? process.env;
69
+ const stderr = deps.stderr ?? ((text) => void process.stderr.write(text));
70
+ const claude = findClaude(env.PATH);
71
+ if (claude === void 0) {
72
+ stderr("outerlayer claude: no claude program found on PATH\n");
73
+ return 127;
74
+ }
75
+ const found = readDeliveryRecord(cwd);
76
+ const build = found.kind === "found" && found.record.launcher !== true ? found.record : void 0;
77
+ if (found.kind === "invalid" && env.OUTERLAYER_JOB_DIR !== void 0) {
78
+ stderr(`outerlayer claude: ${found.path} is not a readable delivery record, so the control plane cannot be attached
79
+ `);
80
+ return 1;
81
+ }
82
+ let dir;
83
+ if (build !== void 0) {
84
+ dir = build.dir;
85
+ if (!existsSync(dir)) {
86
+ stderr(`outerlayer claude: the control plane of ${build.repository} is not at ${dir}, so it cannot be attached
87
+ `);
88
+ return 1;
89
+ }
90
+ } else {
91
+ const { resolveLaunchPlane } = await import('./control-plane-launch-NYVDJESK.js');
92
+ const plane = await resolveLaunchPlane({ cwd, env, home: homeFromEnv(env), fetchImpl: deps.fetchImpl, stderr });
93
+ if (plane.kind === "none") return run(claude, args, env, cwd, stderr);
94
+ if (plane.kind === "refused") {
95
+ stderr(plane.message);
96
+ return 1;
97
+ }
98
+ dir = plane.dir;
99
+ }
100
+ const reported = spawnSync(claude, ["--version"], { env, encoding: "utf8", timeout: 15e3, stdio: ["ignore", "pipe", "ignore"] }).stdout ?? "";
101
+ if (/\d+\.\d+\.\d+/.test(reported) && !versionAtLeast(reported)) {
102
+ stderr(`outerlayer claude: Claude Code ${reported.trim().split(/\s+/)[0]} is older than ${MINIMUM_CLAUDE_VERSION}, the oldest version known to load a control plane's instructions for subagents; the minimum version is ${MINIMUM_CLAUDE_VERSION}
103
+ `);
104
+ return 1;
105
+ }
106
+ return run(
107
+ claude,
108
+ ["--add-dir", dir, "--settings", join(dir, "settings.json"), ...args],
109
+ { ...env, CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD: "1", [CONTROL_PLANE_DIR_VARIABLE]: dir },
110
+ cwd,
111
+ stderr
112
+ );
113
+ }
114
+
115
+ export { runClaudeLauncher };