@outerlayer/cli 0.20.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +15 -5
  3. package/dist/{agent-setup-AM42SA2D.js → agent-setup-LTSLXPS3.js} +13 -12
  4. package/dist/build-6WRNZPVR.js +12 -0
  5. package/dist/build-command-ND2ENDBS.js +50 -0
  6. package/dist/build-info.json +1 -1
  7. package/dist/{builder-C4QNTYMS.js → builder-G3MLDMTI.js} +7 -5
  8. package/dist/{check-BR5D27CX.js → check-UYKEMQNR.js} +48 -50
  9. package/dist/{chunk-AMFWYESY.js → chunk-276D7BJ7.js} +1 -1
  10. package/dist/{chunk-X5H2WYMB.js → chunk-2Q3PZ42G.js} +1 -1
  11. package/dist/{chunk-3CWUOFV6.js → chunk-3AZYLAJC.js} +13 -8
  12. package/dist/{chunk-LRG3ZMZD.js → chunk-3V5C64Y5.js} +4 -4
  13. package/dist/{chunk-QOZKPLVJ.js → chunk-3W333NFO.js} +40 -1
  14. package/dist/{chunk-7YP7T6GV.js → chunk-4AVDD7VX.js} +2 -2
  15. package/dist/{chunk-KYS3TQAG.js → chunk-56X5TOJY.js} +4 -4
  16. package/dist/{chunk-3ZR7Y23Y.js → chunk-5NJIWKD4.js} +650 -70
  17. package/dist/{chunk-NNLA7LLQ.js → chunk-5OCIHFGE.js} +29 -5
  18. package/dist/{chunk-EAEELQVQ.js → chunk-6YBLN4TR.js} +5 -5
  19. package/dist/{chunk-AD3EYI7P.js → chunk-7FEY33MY.js} +259 -56
  20. package/dist/{chunk-QNLX477Q.js → chunk-AEKSX4EY.js} +165 -72
  21. package/dist/{chunk-FBTGMSQF.js → chunk-BET347JZ.js} +16 -9
  22. package/dist/{chunk-JHGEBPLE.js → chunk-BOMRFYTZ.js} +3 -3
  23. package/dist/{chunk-MTP2QEVO.js → chunk-CQAEV3Z5.js} +1 -1
  24. package/dist/{chunk-XZ4H4X5F.js → chunk-CUFFDEF3.js} +15 -8
  25. package/dist/{chunk-BM63HB2M.js → chunk-EAQSOE62.js} +2 -2
  26. package/dist/{chunk-VYAL7PUE.js → chunk-EFB3FGLC.js} +1 -1
  27. package/dist/{chunk-GEMQLBMW.js → chunk-ENTHEUKT.js} +6 -6
  28. package/dist/{chunk-B6SCN5NY.js → chunk-FOCML5FI.js} +175 -44
  29. package/dist/{chunk-LW7G5TJB.js → chunk-FRNYCJ4W.js} +2 -2
  30. package/dist/chunk-GISNHSYL.js +41 -0
  31. package/dist/{chunk-G2YNJIGF.js → chunk-HCVLP7XA.js} +10 -1
  32. package/dist/{chunk-N2PXGQRL.js → chunk-IHNQWF6F.js} +1 -1
  33. package/dist/{chunk-CG36IONK.js → chunk-JRCSET55.js} +2 -2
  34. package/dist/{chunk-MLAAT4S6.js → chunk-JV4YGAAW.js} +3 -3
  35. package/dist/{chunk-XNGMQ27R.js → chunk-JZGFDTNC.js} +2 -2
  36. package/dist/{chunk-GGOMT6KF.js → chunk-NYTZ7HVN.js} +1 -1
  37. package/dist/{chunk-CGGPS7SI.js → chunk-O6RJ3QMU.js} +5 -5
  38. package/dist/{chunk-QEFKA2QD.js → chunk-OBCFK4QD.js} +2 -2
  39. package/dist/{chunk-HOKXGFDR.js → chunk-ORNJJ7XN.js} +22 -16
  40. package/dist/{chunk-M2ZWWTWZ.js → chunk-OW52QLK3.js} +1 -1
  41. package/dist/{chunk-PSN33ERW.js → chunk-QC72I5GQ.js} +3 -3
  42. package/dist/{chunk-FVMYKL6L.js → chunk-QF7WZUU6.js} +1 -1
  43. package/dist/{chunk-IF2OSI5T.js → chunk-QOALB6ZD.js} +2 -2
  44. package/dist/{chunk-ZX4I2MEK.js → chunk-TPKYTORP.js} +1 -1
  45. package/dist/{chunk-S5PCA3SN.js → chunk-UF5L4BAI.js} +1 -1
  46. package/dist/{chunk-R22NZSGA.js → chunk-URAKVDSI.js} +9 -9
  47. package/dist/{chunk-BQXFBI7T.js → chunk-URWYRAIC.js} +32 -7
  48. package/dist/{chunk-7UWVLZXD.js → chunk-USWVXQIH.js} +1 -1
  49. package/dist/{chunk-P53VEAOF.js → chunk-V5CG75NX.js} +1 -1
  50. package/dist/{chunk-6X4SQ5MY.js → chunk-V7SAQ645.js} +1 -1
  51. package/dist/{chunk-TWF3RICI.js → chunk-VSUXCMMH.js} +110 -11
  52. package/dist/{chunk-Z7K3L4FC.js → chunk-W3SWJ2TD.js} +2 -2
  53. package/dist/{chunk-ECODQ7II.js → chunk-XACXXKQ5.js} +1 -1
  54. package/dist/{chunk-5VML45HH.js → chunk-XCRZTXRL.js} +2 -2
  55. package/dist/chunk-XR56WEA5.js +718 -0
  56. package/dist/chunk-ZNPE7FW5.js +137 -0
  57. package/dist/{chunk-PIZRPNKR.js → chunk-ZPSLJFGL.js} +5 -5
  58. package/dist/claude-launcher-TBWV3YL3.js +267 -0
  59. package/dist/{cli-MKF7TU7X.js → cli-U253V422.js} +161 -120
  60. package/dist/{command-ZQNEPDS6.js → command-IQTPFSXY.js} +32 -34
  61. package/dist/{config-CLSGABD5.js → config-H4QS332G.js} +3 -2
  62. package/dist/{connect-cmd-UNYKGDAL.js → connect-cmd-ZFOK6HEL.js} +5 -5
  63. package/dist/{context-cleanup-CHEWNYU6.js → context-cleanup-DSA3HGQU.js} +1 -1
  64. package/dist/{control-plane-launch-34LNRJWR.js → control-plane-launch-OWSNH6YA.js} +62 -28
  65. package/dist/{dist-WO7NOJNG.js → dist-7IH56ELA.js} +1 -1
  66. package/dist/{docker-BFU3AQGY.js → docker-JU422JL7.js} +7 -7
  67. package/dist/{doctor-DHUM5DBB.js → doctor-FZTS57ZO.js} +35 -36
  68. package/dist/{emit-artifact-cmd-XBHM647X.js → emit-artifact-cmd-YLZ5WLSF.js} +19 -18
  69. package/dist/{emit-cmd-W55AEBCA.js → emit-cmd-3W5IO5ET.js} +3 -3
  70. package/dist/{emit-criteria-cmd-UNMWHOUY.js → emit-criteria-cmd-MF6TVE7C.js} +13 -12
  71. package/dist/{emit-finding-cmd-7JHVRYOP.js → emit-finding-cmd-S3YMFTZT.js} +13 -12
  72. package/dist/{emit-result-cmd-5NZMLCJK.js → emit-result-cmd-JHEUFTPX.js} +19 -18
  73. package/dist/{emit-step-cmd-347XNGPQ.js → emit-step-cmd-TUI2T3DS.js} +14 -13
  74. package/dist/{exec-client-7UMESIE2.js → exec-client-ATPF2DDB.js} +4 -3
  75. package/dist/{governing-source-HAA4OW57.js → governing-source-XSEIRSBE.js} +19 -18
  76. package/dist/{guest-init-KPBQOFE5.js → guest-init-DF7V5D2R.js} +4 -3
  77. package/dist/{hook-fast-RL5E5OXE.js → hook-fast-O3UUN6SO.js} +2 -2
  78. package/dist/host-key-ATB23GI3.js +9 -0
  79. package/dist/{import-capture-cmd-TK4XY7RD.js → import-capture-cmd-Q56DDZVO.js} +1 -1
  80. package/dist/index.js +5 -5
  81. package/dist/init-VZE72CR4.js +52 -0
  82. package/dist/{init-V6FOMD2V.js → init-ZZZPYGUH.js} +32 -33
  83. package/dist/{init-cmd-Z4O4PPLZ.js → init-cmd-W5VV62ZN.js} +25 -23
  84. package/dist/{init-update-7DVAKWW3.js → init-update-YFPIQS5G.js} +69 -24
  85. package/dist/{install-4SEFIIW2.js → install-SFACZU7E.js} +5 -4
  86. package/dist/{install-cmd-QDOTR4OM.js → install-cmd-6HTP7I43.js} +6 -5
  87. package/dist/{login-browser-DX35MARZ.js → login-browser-BN5UKPHS.js} +3 -3
  88. package/dist/{logout-cmd-5V5MMBSY.js → logout-cmd-RZFWTNYD.js} +2 -2
  89. package/dist/{logs-AMLKC3VP.js → logs-N3ZX7HFV.js} +3 -2
  90. package/dist/loop-6WENRS5S.js +75 -0
  91. package/dist/machine-M4MQBV5A.js +47 -0
  92. package/dist/{mcp-install-cmd-GGWB3JJ2.js → mcp-install-cmd-GD4QUP7Z.js} +2 -2
  93. package/dist/{mcp-serve-cmd-N3UTY6EE.js → mcp-serve-cmd-SBW7HYKD.js} +6 -5
  94. package/dist/{paths-7XP63OAX.js → paths-AKX2OOLF.js} +3 -2
  95. package/dist/pending-7SGWZCEH.js +9 -0
  96. package/dist/{pidfile-3DM4OBKO.js → pidfile-G2J5WBQS.js} +4 -3
  97. package/dist/receive-files-T2BIUBQL.js +254 -0
  98. package/dist/{record-3WP6V2K5.js → record-Q4IEYIVV.js} +4 -3
  99. package/dist/relay-PSZ4LGMW.js +210 -0
  100. package/dist/relay-protocol-K7KP2SPI.js +6 -0
  101. package/dist/{runner-env-FRZFFHDF.js → runner-env-GZHXM27A.js} +6 -5
  102. package/dist/runner-identity-FTHZFMGY.js +14 -0
  103. package/dist/{runner-key-5FOWCW7J.js → runner-key-QT7GKGEE.js} +32 -33
  104. package/dist/{session-sender-U2BBUWNO.js → session-sender-BK6TGNVO.js} +20 -19
  105. package/dist/{spec-cmd-FVLJOFGC.js → spec-cmd-ZNJ3GXWC.js} +13 -12
  106. package/dist/{starter-pack-6LQVLBIA.js → starter-pack-5EQYGSJF.js} +2 -2
  107. package/dist/{status-BINH7MBG.js → status-JOO7MGIC.js} +36 -38
  108. package/dist/{statusline-fast-KN3BX67H.js → statusline-fast-2OK3DVAA.js} +2 -2
  109. package/dist/{sync-cmd-VXOUFS4I.js → sync-cmd-W2FPY3T5.js} +19 -18
  110. package/dist/{watch-OH645CV2.js → watch-WLH5ZUZU.js} +19 -18
  111. package/dist/{work-claim-cmd-DRQCHCOK.js → work-claim-cmd-4PLDTEZR.js} +17 -16
  112. package/dist/{work-cmd-5I3J2XQQ.js → work-cmd-KWHAYUYB.js} +13 -12
  113. package/dist/{work-comment-cmd-UCCPWUSR.js → work-comment-cmd-4CUI7ZDE.js} +13 -12
  114. package/dist/{work-logs-cmd-7352CJPG.js → work-logs-cmd-AF253WLM.js} +13 -12
  115. package/dist/{work-open-pr-cmd-LSH4VHJM.js → work-open-pr-cmd-JETE6HRL.js} +15 -14
  116. package/dist/{work-pr-cmd-H4OQR26N.js → work-pr-cmd-V5G4CPMG.js} +14 -13
  117. package/dist/{work-stop-cmd-CRDHXQVW.js → work-stop-cmd-FIEKUDGE.js} +13 -12
  118. package/package.json +2 -2
  119. package/skill-pack/maintained/outerlayer-amend/SKILL.md +17 -6
  120. package/skill-pack/maintained/outerlayer-build/SKILL.md +347 -0
  121. package/skill-pack/{template/build → maintained/outerlayer-build}/references/evidence.md +2 -2
  122. package/skill-pack/{template/build → maintained/outerlayer-build}/references/release.md +4 -4
  123. package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-loop.md +3 -1
  124. package/skill-pack/shipped.json +2 -0
  125. package/skill-pack/template/build/SKILL.md +4 -253
  126. package/skill-pack/validators/acceptance-criteria.yaml +1 -1
  127. package/dist/build-TQ6X5PYN.js +0 -12
  128. package/dist/chunk-3UZTIRLF.js +0 -320
  129. package/dist/chunk-CX22S5BA.js +0 -45
  130. package/dist/chunk-LLM3I5YU.js +0 -89
  131. package/dist/chunk-SADUQSO4.js +0 -50
  132. package/dist/chunk-VMJPFQNE.js +0 -261
  133. package/dist/claude-launcher-J5M44PFS.js +0 -115
  134. package/dist/host-key-U4B5QETR.js +0 -8
  135. package/dist/init-XG47KCI4.js +0 -53
  136. package/dist/loop-EAZQMAE2.js +0 -77
  137. package/dist/machine-TRHBT5NE.js +0 -48
  138. package/dist/pending-532ABZYC.js +0 -8
  139. package/dist/relay-L76HDX72.js +0 -46
  140. package/dist/{chunk-YVZJ6GKF.js → chunk-DIB2WLBL.js} +1 -1
  141. package/dist/{chunk-GOSFARMS.js → chunk-F35VMF5M.js} +1 -1
  142. package/dist/{chunk-DSF2FWAZ.js → chunk-IZSVXRDR.js} +1 -1
  143. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/agent-briefs.md +0 -0
  144. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/criteria-judge.md +0 -0
  145. /package/skill-pack/{template/build → maintained/outerlayer-build}/references/review-briefs.md +0 -0
  146. /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/criterion-citations.mjs +0 -0
  147. /package/skill-pack/{template/build → maintained/outerlayer-build}/scripts/record-criteria.mjs +0 -0
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { checkStarterFiles, contextIsGoverned } from './chunk-TWF3RICI.js';
4
- import { resolveCredentials, getJson, WorkCommandError } from './chunk-FBTGMSQF.js';
5
- import { isLinkedRepository } from './chunk-CG36IONK.js';
3
+ import { checkStarterFiles, contextIsGoverned, checkBuildSkill } from './chunk-VSUXCMMH.js';
4
+ import { resolveCredentials, getJson, WorkCommandError } from './chunk-BET347JZ.js';
5
+ import { isLinkedRepository } from './chunk-JRCSET55.js';
6
6
  import { sanitizeTerminal } from './chunk-G3IJ3N6F.js';
7
- import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-PSN33ERW.js';
8
- import { readStatuslineState, STATE_FRESH_MS } from './chunk-DSF2FWAZ.js';
9
- import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-QNLX477Q.js';
10
- import { C } from './chunk-ANPNT6PM.js';
11
- import { readSettings, settingsPath, isOurStatuslineSlot, statuslineWrappedOriginal, REGISTERED_EVENTS, isOurHookCommand, ourCommandBins, cliBinResolvable, ourDirectScriptBins, wrappedOriginalCommand } from './chunk-5QRP3MVS.js';
12
- import { checkFormerSkillNames } from './chunk-7UWVLZXD.js';
13
- import { defaultFetch } from './chunk-FVMYKL6L.js';
7
+ import { checkFormerSkillNames } from './chunk-USWVXQIH.js';
8
+ import { defaultFetch } from './chunk-QF7WZUU6.js';
14
9
  import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
10
+ import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-QC72I5GQ.js';
11
+ import { readStatuslineState, STATE_FRESH_MS } from './chunk-IZSVXRDR.js';
12
+ import { hookCommandEscapesControlPlane, CONTROL_PLANE_DIR_VARIABLE } from './chunk-HCVLP7XA.js';
15
13
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
16
- import { hookCommandEscapesControlPlane, CONTROL_PLANE_DIR_VARIABLE } from './chunk-G2YNJIGF.js';
14
+ import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-AEKSX4EY.js';
15
+ import { C } from './chunk-ANPNT6PM.js';
17
16
  import { cliInvocation } from './chunk-CRB3POP4.js';
17
+ import { readSettings, settingsPath, isOurStatuslineSlot, statuslineWrappedOriginal, REGISTERED_EVENTS, isOurHookCommand, ourCommandBins, cliBinResolvable, ourDirectScriptBins, wrappedOriginalCommand } from './chunk-5QRP3MVS.js';
18
18
  import { readDeliveryRecord, readDegraded, readSourceCache } from './chunk-YQR6E6OV.js';
19
19
  import { deadHooksState, preparePackageManagerCommand } from './chunk-TUSYOL2O.js';
20
20
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -192,6 +192,7 @@ function runDoctor(env = {}) {
192
192
  ...checkInstalls(env),
193
193
  ...starter?.checks ?? [],
194
194
  ...laptop ? checkRenamedSkills(env.cwd) : [],
195
+ ...checkBuildSkillState(env.cwd),
195
196
  ...starter !== void 0 && !starter.mcpOutdated ? checkMcpCommand(env.cwd, env.processEnv) : [],
196
197
  ...checkContextSource(env.cwd),
197
198
  ...checkGovernsList(env.cwd),
@@ -204,6 +205,11 @@ function checkRenamedSkills(cwd) {
204
205
  if (dirs === void 0 || contextIsGoverned(dirs.gitCommonDir)) return [];
205
206
  return checkFormerSkillNames(dirs.repoRoot);
206
207
  }
208
+ function checkBuildSkillState(cwd) {
209
+ const dirs = findGitDirs(cwd ?? process.cwd());
210
+ if (dirs === void 0 || contextIsGoverned(dirs.gitCommonDir)) return [];
211
+ return checkBuildSkill(dirs.repoRoot);
212
+ }
207
213
  function checkInstalledCli(home, cwd) {
208
214
  const name = "Installed CLI";
209
215
  const result = checkInstalledCliStaleness({ home, cwd });
@@ -773,7 +779,7 @@ function checkContextSource(cwd) {
773
779
  const governed = readSourceCache(gitCommonDir)?.status === "governed";
774
780
  if (!governed && delivery === void 0 && !degraded) return [];
775
781
  const checks = [];
776
- const name = "Context source";
782
+ const name = "Control plane";
777
783
  if (delivery !== void 0 && existsSync(delivery.dir)) {
778
784
  checks.push({ name, status: degraded ? "warn" : "pass", detail: `control plane delivered at ${delivery.sha.slice(0, 7)}` });
779
785
  } else if (governed) {
@@ -786,7 +792,7 @@ function checkContextSource(cwd) {
786
792
  }
787
793
  if (degraded) {
788
794
  checks.push({
789
- name: "Context source degradation",
795
+ name: "Control plane degradation",
790
796
  status: degraded.kind === "conflict" ? "fail" : "warn",
791
797
  detail: degraded.message,
792
798
  fix: contextDegradedFix(degraded.kind)
@@ -1169,7 +1175,7 @@ function doctorExitCode(checks) {
1169
1175
 
1170
1176
  // src/doctor-report.ts
1171
1177
  async function gatherDoctorChecks() {
1172
- const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-CLSGABD5.js');
1178
+ const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-H4QS332G.js');
1173
1179
  const configPath = defaultRunnerConfigPath();
1174
1180
  const checks = runDoctor({ runnerHost: hasRunnerBlock(configPath) });
1175
1181
  const credential = await credentialChecks();
@@ -1181,7 +1187,7 @@ async function gatherDoctorChecks() {
1181
1187
  const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
1182
1188
  checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
1183
1189
  } else if (hasRunnerBlock(configPath)) {
1184
- const { runnerHostChecks } = await import('./doctor-DHUM5DBB.js');
1190
+ const { runnerHostChecks } = await import('./doctor-FZTS57ZO.js');
1185
1191
  const hooks = (() => {
1186
1192
  try {
1187
1193
  return loadRunnerConfig(configPath).hooks;
@@ -1216,7 +1222,7 @@ async function gatherDoctorChecks() {
1216
1222
  const { existsSync: existsSync3 } = await import('fs');
1217
1223
  if (process.platform !== "linux" || !existsSync3("/run/systemd/system")) return void 0;
1218
1224
  const { inspectService, realInspectProbes } = await import('./inspect-6UYAAXH7.js');
1219
- const { DEFAULT_UNIT_NAME } = await import('./install-4SEFIIW2.js');
1225
+ const { DEFAULT_UNIT_NAME } = await import('./install-SFACZU7E.js');
1220
1226
  const { dirname: dirname2 } = await import('path');
1221
1227
  return inspectService(DEFAULT_UNIT_NAME, dirname2(configPath), realInspectProbes());
1222
1228
  })();
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { hostKeyPath, runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
3
+ import { hostKeyPath, runnerDir, RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-IHNQWF6F.js';
4
4
  import { generateKeyPairSync, createPrivateKey, createPublicKey, sign } from 'crypto';
5
5
  import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
6
6
 
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { appendContextProvenance } from './chunk-ZJSNLVCE.js';
4
+ import { CONTROL_PLANE_DIR_VARIABLE } from './chunk-HCVLP7XA.js';
4
5
  import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
5
- import { CONTROL_PLANE_DIR_VARIABLE } from './chunk-G2YNJIGF.js';
6
6
  import { cliInvocation } from './chunk-CRB3POP4.js';
7
7
  import { deadHooksState, huskyPrepareScript, preparePackageManagerCommand } from './chunk-TUSYOL2O.js';
8
8
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
@@ -624,11 +624,11 @@ async function missingControlPlane(cwd, sessionId, home, env) {
624
624
  const dirs = findGitDirs(cwd);
625
625
  if (dirs === void 0) return void 0;
626
626
  if (existsSync(join(dirs.gitCommonDir, "outerlayer", "materialized.json")) || hasExcludeBlock(dirs.gitCommonDir)) {
627
- const { cleanupEarlierCopies } = await import('./context-cleanup-CHEWNYU6.js');
627
+ const { cleanupEarlierCopies } = await import('./context-cleanup-DSA3HGQU.js');
628
628
  cleanupEarlierCopies(dirs);
629
629
  }
630
630
  if (!contextPossiblyGoverned(cwd, home)) return void 0;
631
- const { governanceOf } = await import('./control-plane-launch-34LNRJWR.js');
631
+ const { governanceOf } = await import('./control-plane-launch-OWSNH6YA.js');
632
632
  if (await governanceOf({ cwd, env, home }) !== "governed") return void 0;
633
633
  recordMissingContext(dirs, sessionId, home);
634
634
  const launcher = `${cliInvocation()} claude`;
@@ -2,7 +2,7 @@
2
2
  import { createRequire } from 'node:module';
3
3
  import { readCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
4
4
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
5
- import { signRunnerRequest, signerFor } from './chunk-M2ZWWTWZ.js';
5
+ import { signRunnerRequest, signerFor } from './chunk-OW52QLK3.js';
6
6
 
7
7
  createRequire(import.meta.url);
8
8
 
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-CG36IONK.js';
4
- import { resolveRepoIdentity } from './chunk-QNLX477Q.js';
3
+ import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-JRCSET55.js';
5
4
  import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
6
5
  import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
6
+ import { resolveRepoIdentity } from './chunk-AEKSX4EY.js';
7
7
  import { cliInvocation } from './chunk-CRB3POP4.js';
8
8
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
9
9
  import { openSync, fstatSync, readSync, closeSync } from 'fs';
@@ -4,6 +4,6 @@ import { createRequire } from 'node:module';
4
4
  createRequire(import.meta.url);
5
5
 
6
6
  // src/runner/protocol.ts
7
- var RUNNER_PROTOCOL = 21;
7
+ var RUNNER_PROTOCOL = 22;
8
8
 
9
9
  export { RUNNER_PROTOCOL };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
3
+ import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-IHNQWF6F.js';
4
4
  import { readFileSync, mkdirSync, writeFileSync, renameSync } from 'fs';
5
5
  import { join } from 'path';
6
6
 
@@ -1,25 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { uploadSpooledSteps } from './chunk-KYS3TQAG.js';
3
+ import { uploadSpooledSteps } from './chunk-56X5TOJY.js';
4
4
  import { LaunchFilter } from './chunk-ESVW4MJY.js';
5
5
  import { RepoFilter } from './chunk-TBT347UY.js';
6
6
  import { migrateLegacyArtifactSidecars, planArtifactUpload, artifactsStatePath, sanitizeTerminal, acquireArtifactSpoolLock, artifactBlobsDir, resolveArtifactTurnIndex, isArtifactTombstoned, ARTIFACT_RETRY_MAX_AGE_MS, writeArtifactSpoolState, reclaimUnneededArtifactBlobs, neededArtifactShas } from './chunk-G3IJ3N6F.js';
7
- import { writeSyncStatus, spoolDir } from './chunk-PSN33ERW.js';
8
- import { hookExecSpoolPath } from './chunk-F7CU5ABH.js';
9
- import { applyReportedCost } from './chunk-BKO6JEZI.js';
10
- import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-QNLX477Q.js';
11
- import { C } from './chunk-ANPNT6PM.js';
12
- import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-T2Q7ISPE.js';
13
- import { defaultFetch } from './chunk-FVMYKL6L.js';
7
+ import { defaultFetch } from './chunk-QF7WZUU6.js';
14
8
  import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-NTRCK4NH.js';
9
+ import { writeSyncStatus, spoolDir } from './chunk-QC72I5GQ.js';
15
10
  import { readLatestProvenanceForSession, readContextProvenance } from './chunk-ZJSNLVCE.js';
11
+ import { hookExecSpoolPath } from './chunk-F7CU5ABH.js';
12
+ import { applyReportedCost } from './chunk-BKO6JEZI.js';
16
13
  import { readRepoConnection, findGitDirs } from './chunk-BJ3KTMDH.js';
14
+ import { setCustomScrubbers, setLocalIdentity, tailTranscript, enrichSessionRepo, scanAll, setRepoRoot, resolveRepoIdentity, sessionIdFromPath, scrubDeep, SOURCE_ADAPTERS } from './chunk-AEKSX4EY.js';
17
15
  import { readCloudConfig, cloudConfigPath, writeCloudConfig } from './chunk-EABW6AJQ.js';
16
+ import { C } from './chunk-ANPNT6PM.js';
17
+ import { readLaunchSpoolState, launchStatusIsDecisive, launchedItemsBySession, launchesPath } from './chunk-T2Q7ISPE.js';
18
18
  import { cliInvocation } from './chunk-CRB3POP4.js';
19
19
  import { removeJournalHooks } from './chunk-TUSYOL2O.js';
20
20
  import { CAPTURE_TIERS, inferArtifactKind, bannedPathsForTier, downconvertSession, isHumanUserTurn, turnCountBound, EVENT_TYPES } from './chunk-7VUK5RFS.js';
21
21
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
22
- import { signerFor, signRunnerRequest } from './chunk-M2ZWWTWZ.js';
22
+ import { signerFor, signRunnerRequest } from './chunk-OW52QLK3.js';
23
23
  import { dirname, basename, join } from 'path';
24
24
  import { statSync, readFileSync, readdirSync, mkdirSync, writeFileSync, renameSync, existsSync, rmSync } from 'fs';
25
25
  import { execFileSync } from 'child_process';
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { TARGET_TUNNEL, TARGET_LEASE, destinationTarget } from './chunk-GISNHSYL.js';
3
4
  import { existsSync, unlinkSync, chmodSync } from 'fs';
4
5
  import { request as request$1, createServer } from 'http';
5
6
  import { request } from 'https';
@@ -293,15 +294,20 @@ async function startDestination(input) {
293
294
  for (const socket of sockets) socket.destroy();
294
295
  await Promise.all(listeners.map((listener) => new Promise((resolve) => listener.close(() => resolve()))));
295
296
  };
296
- return { ...served, close };
297
+ return { ...served, acceptStream: (stream) => void server.emit("connection", stream), close };
297
298
  }
298
299
  async function startBuildServices(input) {
300
+ const streamed = input.serve === "stream";
299
301
  const tunnel = await input.startTunnel(join(input.buildDir, "tunnel.sock"), {
300
302
  ...input.tunnelOptions,
303
+ ...streamed ? { socket: false } : {},
301
304
  ...input.allowHosts === void 0 ? {} : { allowHosts: input.allowHosts },
302
305
  recordPath: join(input.jobDir, "tunnel.json")
303
306
  });
304
307
  const servers = [];
308
+ const targets = /* @__PURE__ */ new Map();
309
+ if (streamed) targets.set(TARGET_TUNNEL, (stream) => tunnel.acceptStream(stream));
310
+ if (streamed && input.lease !== void 0) targets.set(TARGET_LEASE, (stream) => input.lease.accept(stream));
305
311
  const closeAll = async () => {
306
312
  await Promise.all(servers.map((s) => s.close()));
307
313
  await tunnel.close();
@@ -314,30 +320,39 @@ async function startBuildServices(input) {
314
320
  for (const [index, destination] of input.destinations.entries()) {
315
321
  const server = await startDestination({
316
322
  destination,
317
- ...input.serve === "tcp" ? {} : { socketPath: destinationSocketPath(input.buildDir, index) },
318
- ...input.serve === "socket" ? {} : { port: input.ports?.destinations?.[index] ?? 0 },
323
+ ...input.serve === "tcp" || streamed ? {} : { socketPath: destinationSocketPath(input.buildDir, index) },
324
+ ...input.serve === "socket" || streamed ? {} : { port: input.ports?.destinations?.[index] ?? 0 },
319
325
  hostEnv: input.hostEnv,
320
326
  onUsed: (name) => tunnel.destinationUsed(name),
321
327
  ...input.destinationOptions
322
328
  });
323
329
  servers.push(server);
330
+ targets.set(destinationTarget(index), (stream) => server.acceptStream(stream));
324
331
  if (server.port !== void 0) destinationPorts.push(server.port);
325
332
  }
326
333
  const builtIns = input.builtIns === void 0 ? [] : builtInDestinations({ gatewayUrl: input.builtIns.gatewayUrl, itemKey: input.builtIns.itemKey, hostEnv: input.hostEnv, claudeUpstream: input.builtIns.claudeUpstream });
327
334
  for (const builtIn of builtIns) {
328
335
  const server = await startDestination({
329
336
  destination: builtIn.destination,
330
- ...input.serve === "tcp" ? {} : { socketPath: join(input.buildDir, builtIn.socket) },
331
- ...input.serve === "socket" ? {} : { port: input.ports?.builtIns?.[builtIn.destination.name] ?? 0 },
337
+ ...input.serve === "tcp" || streamed ? {} : { socketPath: join(input.buildDir, builtIn.socket) },
338
+ ...input.serve === "socket" || streamed ? {} : { port: input.ports?.builtIns?.[builtIn.destination.name] ?? 0 },
332
339
  hostEnv: builtIn.hostEnv,
333
340
  drop: builtIn.drop,
334
341
  onUsed: (name) => tunnel.destinationUsed(name),
335
342
  ...input.destinationOptions
336
343
  });
337
344
  servers.push(server);
345
+ targets.set(builtIn.destination.name, (stream) => server.acceptStream(stream));
338
346
  if (server.port !== void 0) builtInPorts[builtIn.destination.name] = server.port;
339
347
  }
340
- return { ...tunnel, proxyPort, destinationPorts, builtInPorts, close: closeAll };
348
+ return { ...tunnel, streams: {
349
+ accept: (target, stream) => {
350
+ const serve = targets.get(target);
351
+ if (serve === void 0) return false;
352
+ serve(stream);
353
+ return true;
354
+ }
355
+ }, proxyPort, destinationPorts, builtInPorts, close: closeAll };
341
356
  } catch (err) {
342
357
  await closeAll();
343
358
  throw err;
@@ -413,6 +428,16 @@ function parseClaimedRepositories(value) {
413
428
  const at = primaryAt === -1 ? 0 : primaryAt;
414
429
  return [{ ...parsed[at], primary: true }, ...parsed.filter((_, index) => index !== at).map((entry) => ({ ...entry, primary: false }))];
415
430
  }
431
+ function parseUnreachable(value) {
432
+ if (!Array.isArray(value)) return [];
433
+ const entries = [];
434
+ for (const entry of value) {
435
+ if (typeof entry !== "object" || entry === null) continue;
436
+ const { repository, reason } = entry;
437
+ if (typeof repository === "string" && repository !== "" && typeof reason === "string") entries.push({ repository, reason });
438
+ }
439
+ return entries;
440
+ }
416
441
  function repositoriesOf(input) {
417
442
  if (input.repositories !== void 0 && input.repositories.length > 0) return input.repositories;
418
443
  if (input.repository === void 0 || input.repository === null || input.repository === "" || input.branch === void 0) return [];
@@ -620,4 +645,4 @@ function withTunnelRecord(environment, record, onlyWhenUsed = false) {
620
645
  };
621
646
  }
622
647
 
623
- export { AGENT_CREDENTIAL_MISSING, BUILD_HOME, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, EVAL_INPUT_DIR, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, RELAY_PORT, authorEnvironment, buildEnvironment, builtInEnvironment, checkEnvironment, checkoutPath, claudeCredential, commitIdentityRecord, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, lifecycleWorkdir, parseClaimIdentity, parseClaimedRepositories, parseIsolation, primaryOf, proxyEnvironment, repositoriesOf, repositoryPath, resolveDestinations, sharedUserEnvironment, startBuildServices, tokenHeader, withGitConfig, withHooksPath, withProxyWarningHidden, withTokenHeader, withTunnelRecord };
648
+ export { AGENT_CREDENTIAL_MISSING, BUILD_HOME, BUILT_IN_NAMES, CHECKOUT_DIR, CLAUDE_CREDENTIAL_VARIABLES, CLAUDE_PORT, CLAUDE_SOCKET, DESTINATION_BASE_PORT, EVAL_INPUT_DIR, GATEWAY_PORT, GATEWAY_SOCKET, JOB_MOUNT, PROXY_WARNING_FLAG, RELAY_PORT, authorEnvironment, buildEnvironment, builtInEnvironment, checkEnvironment, checkoutPath, claudeCredential, commitIdentityRecord, containerLocalAddress, destinationEnvironment, headerVariables, isRefusedInConfig, isReservedVariable, lifecycleWorkdir, parseClaimIdentity, parseClaimedRepositories, parseIsolation, parseUnreachable, primaryOf, proxyEnvironment, repositoriesOf, repositoryPath, resolveDestinations, sharedUserEnvironment, startBuildServices, tokenHeader, withGitConfig, withHooksPath, withProxyWarningHidden, withTokenHeader, withTunnelRecord };
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { skillDir, FORMER_MAINTAINED_NAMES, isMaintainedCopy } from './chunk-NNLA7LLQ.js';
3
+ import { skillDir, FORMER_MAINTAINED_NAMES, isMaintainedCopy } from './chunk-5OCIHFGE.js';
4
4
  import { cliInvocation } from './chunk-CRB3POP4.js';
5
5
  import { emitTree, ALL_TARGET_IDS, classifyTree } from './chunk-WFSUUUAN.js';
6
6
  import { readFileSync, existsSync, unlinkSync, rmdirSync, readdirSync } from 'fs';
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module';
3
3
  import { MAX_ALLOW_HOSTS, allowHostProblem } from './chunk-UXYLWVTQ.js';
4
4
  import { parseSize } from './chunk-7RQ73DLO.js';
5
5
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
6
- import { isRefusedInConfig, resolveDestinations, isReservedVariable } from './chunk-BQXFBI7T.js';
6
+ import { isRefusedInConfig, resolveDestinations, isReservedVariable } from './chunk-URWYRAIC.js';
7
7
  import { existsSync, statSync, accessSync, constants, readFileSync } from 'fs';
8
8
  import { hostname } from 'os';
9
9
  import { join } from 'path';
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-5OCIHFGE.js';
3
4
  import { C } from './chunk-ANPNT6PM.js';
4
- import { resolvePackRoot, loadTemplateFiles, loadMaintainedFiles, TEMPLATE_SKILLS, skillDir, writeMaintainedFiles, MAINTAINED_SKILLS } from './chunk-NNLA7LLQ.js';
5
5
  import { cliInvocation } from './chunk-CRB3POP4.js';
6
6
  import { resolvePackageVersion } from './chunk-RA3O54FC.js';
7
7
  import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { mcpTargetPath, INIT_STDIO_ENTRY, INIT_DOCS_ENTRY, DOCS_MCP_SERVER_NAME } from './chunk-YVZJ6GKF.js';
4
- import { POLICY_CONTENT, VALIDATOR_FILES, VALIDATORS_DIR, POLICY_PATH } from './chunk-6X4SQ5MY.js';
5
3
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
6
- import { resolvePackRoot, loadTemplateFiles, skillDir } from './chunk-NNLA7LLQ.js';
4
+ import { mcpTargetPath, INIT_STDIO_ENTRY, INIT_DOCS_ENTRY, DOCS_MCP_SERVER_NAME } from './chunk-DIB2WLBL.js';
5
+ import { POLICY_CONTENT, VALIDATOR_FILES, VALIDATORS_DIR, POLICY_PATH } from './chunk-V7SAQ645.js';
6
+ import { resolvePackRoot, skillDir, namesCore, loadTemplateFiles, TEMPLATE_SKILLS } from './chunk-5OCIHFGE.js';
7
7
  import { cliInvocation } from './chunk-CRB3POP4.js';
8
+ import { hasSymlinkComponent } from './chunk-W3SWJ2TD.js';
8
9
  import { cloneIsGoverned } from './chunk-YQR6E6OV.js';
10
+ import { emitTree, ALL_TARGET_IDS, classifyTree, splitRawFile } from './chunk-WFSUUUAN.js';
9
11
  import { createHash } from 'crypto';
10
12
  import { existsSync, readFileSync } from 'fs';
11
- import { join } from 'path';
13
+ import { join, dirname } from 'path';
12
14
 
13
15
  createRequire(import.meta.url);
14
16
  var SHIPPED_MANIFEST = "shipped.json";
@@ -25,8 +27,9 @@ function currentStarterFiles(packRoot = resolvePackRoot(), policy = POLICY_CONTE
25
27
  });
26
28
  return [...templates, ...validators, { path: POLICY_PATH, content: policy }];
27
29
  }
30
+ var TEMPLATE_VERSION = /(Copied once from the default template by outerlayer init) [^\s;]+(; never overwritten\.)/;
28
31
  function contentHash(content) {
29
- return createHash("sha256").update(content.replace(/\r\n/g, "\n")).digest("hex");
32
+ return createHash("sha256").update(content.replace(/\r\n/g, "\n").replace(TEMPLATE_VERSION, "$1$2")).digest("hex");
30
33
  }
31
34
  function readShippedManifest(packRoot = resolvePackRoot()) {
32
35
  const path = join(packRoot, SHIPPED_MANIFEST);
@@ -95,13 +98,31 @@ function mcpItems(root) {
95
98
  return { ...base, state: "edited" };
96
99
  });
97
100
  }
101
+ function retiredFiles(root, shipped, manifest) {
102
+ if (!manifest.ok) return [];
103
+ const current = new Set(shipped.map((f) => f.path));
104
+ const prefixes = TEMPLATE_SKILLS.map((skill) => `${skillDir(skill)}/`);
105
+ const retired = [];
106
+ for (const [path, hashes] of manifest.files) {
107
+ if (current.has(path) || !prefixes.some((prefix) => path.startsWith(prefix))) continue;
108
+ const abs = join(root, path);
109
+ if (!existsSync(abs) || hasSymlinkComponent(root, path)) continue;
110
+ try {
111
+ retired.push({ path, state: hashes.has(contentHash(readFileSync(abs, "utf8"))) ? "unedited" : "edited" });
112
+ } catch {
113
+ }
114
+ }
115
+ return retired.sort((a, b) => a.path.localeCompare(b.path));
116
+ }
98
117
  function inspectStarterFiles(root, opts = {}) {
99
118
  const packRoot = opts.packRoot ?? resolvePackRoot();
100
119
  const manifest = readShippedManifest(packRoot);
101
- const files = currentStarterFiles(packRoot).map(
102
- (file) => ({ kind: "file", path: file.path, state: fileState(root, file, manifest), file })
103
- );
104
- return { items: [...files, ...mcpItems(root)], manifest: manifest.ok ? "ok" : manifest.problem };
120
+ const shipped = currentStarterFiles(packRoot);
121
+ const files = shipped.map((file) => ({ kind: "file", path: file.path, state: fileState(root, file, manifest), file }));
122
+ const buildEdited = files.some((f) => f.path === `${skillDir("build")}/SKILL.md` && f.state === "edited");
123
+ const buildPrefix = `${skillDir("build")}/`;
124
+ const retired = retiredFiles(root, shipped, manifest).filter((f) => !(buildEdited && f.path.startsWith(buildPrefix)));
125
+ return { items: [...files, ...mcpItems(root)], retired, manifest: manifest.ok ? "ok" : manifest.problem };
105
126
  }
106
127
  function itemLabel(item) {
107
128
  return item.kind === "file" ? item.path : `${item.path} "${item.server}" server`;
@@ -140,17 +161,19 @@ function checkStarterFiles(cwd, opts = {}) {
140
161
  const missing = by("missing");
141
162
  const edited = by("edited");
142
163
  const unreadable = by("unreadable");
164
+ const retired = report.retired.filter((f) => f.state === "unedited");
143
165
  const parts = [];
144
166
  if (current.length > 0) parts.push(`${current.length} current`);
145
167
  if (outdated.length > 0) parts.push(`outdated and unedited: ${shownPaths(outdated, report.items).join(", ")}`);
146
168
  if (missing.length > 0) parts.push(`missing: ${shownPaths(missing, report.items).join(", ")}`);
169
+ if (retired.length > 0) parts.push(`no longer shipped, unedited: ${retired.map((f) => f.path).join(", ")}`);
147
170
  if (edited.length > 0) parts.push(`edited by you, left as they are: ${edited.map(itemLabel).join(", ")}`);
148
171
  if (unreadable.length > 0) parts.push(`${unreadable[0].path} is not valid JSON, so its servers were not read`);
149
172
  if (report.manifest !== "ok") {
150
173
  parts.push(`this CLI's record of earlier versions is ${report.manifest}, so an outdated file cannot be told from an edited one`);
151
174
  }
152
175
  const mcpOutdated = outdated.some((i) => i.kind === "mcp" && i.server === "outerlayer");
153
- const actionable = outdated.length + missing.length > 0;
176
+ const actionable = outdated.length + missing.length + retired.length > 0;
154
177
  const compare = edited.length > 0 ? ` Compare an edited file with this CLI's version: \`${UPDATE} --dry-run\`.` : "";
155
178
  if (!actionable && report.manifest === "ok") {
156
179
  return { checks: [{ name: NAME, status: "pass", detail: parts.join("; ") + (compare === "" ? "" : `.${compare}`) }], mcpOutdated };
@@ -158,5 +181,81 @@ function checkStarterFiles(cwd, opts = {}) {
158
181
  const fix = actionable ? `Run \`${UPDATE}\` to update the outdated files and write the missing ones. It never changes a file you edited.${compare}` : "Reinstall the CLI: `npm install -g @outerlayer/cli`, or run it with `npx -y @outerlayer/cli`.";
159
182
  return { checks: [{ name: NAME, status: "warn", detail: parts.join("; "), fix }], mcpOutdated };
160
183
  }
184
+ var BUILD_PHASES = ["Intake", "Criteria", "Implement", "Review", "Pull request", "Evidence"];
185
+ var CHANGES_HEADING = "## Changes for this repository";
186
+ var NAME2 = "Build skill";
187
+ function changeHeadings(text) {
188
+ const lines = text.split(/\r?\n/);
189
+ const start = lines.findIndex((line) => line.trim() === CHANGES_HEADING);
190
+ if (start === -1) return [];
191
+ const headings = [];
192
+ for (const line of lines.slice(start + 1)) {
193
+ if (/^## /.test(line)) break;
194
+ const match = /^### (.+?)\s*$/.exec(line);
195
+ if (match) headings.push(match[1]);
196
+ }
197
+ return headings;
198
+ }
199
+ function skillsFolders() {
200
+ const probe = `${skillDir("probe")}/SKILL.md`;
201
+ const compiled = emitTree({
202
+ entries: classifyTree([probe]).entries,
203
+ contents: /* @__PURE__ */ new Map([[probe, "---\nname: probe\ndescription: probe\n---\n"]]),
204
+ assetPaths: [],
205
+ targets: [...ALL_TARGET_IDS]
206
+ });
207
+ return [...new Set(compiled.files.map((file) => dirname(dirname(file.path))))].sort();
208
+ }
209
+ function shortBuild() {
210
+ const file = loadTemplateFiles().find((f) => f.path === `${skillDir("build")}/SKILL.md`);
211
+ if (file === void 0) return "";
212
+ return splitRawFile(file.content).body.split("\n").filter((line) => !line.startsWith("<!--")).join("\n").trim();
213
+ }
214
+ var read = (abs) => {
215
+ try {
216
+ return readFileSync(abs, "utf8");
217
+ } catch {
218
+ return void 0;
219
+ }
220
+ };
221
+ function checkBuildSkill(repoRoot) {
222
+ const folders = [".outerlayer/skills", ...skillsFolders()];
223
+ const source = `${folders[0]}/build/SKILL.md`;
224
+ const builds = (existsSync(join(repoRoot, source)) ? [source] : folders.slice(1).map((f) => `${f}/build/SKILL.md`)).map((path) => ({ path, text: read(join(repoRoot, path)) })).filter((b) => b.text !== void 0);
225
+ const checks = [];
226
+ const detached = builds.filter((b) => !namesCore(b.text));
227
+ if (detached.length > 0) {
228
+ checks.push({
229
+ name: NAME2,
230
+ status: "warn",
231
+ detail: `${detached.map((b) => b.path).join(", ")} does not name outerlayer-build, so it gets no updates from the core`,
232
+ fix: `Move to the short build, and put your own changes under the name of the phase each applies to:
233
+
234
+ ${shortBuild()}`
235
+ });
236
+ }
237
+ for (const build of builds.filter((b) => namesCore(b.text))) {
238
+ const unknown = changeHeadings(build.text).filter((heading) => !BUILD_PHASES.includes(heading));
239
+ if (unknown.length === 0) continue;
240
+ checks.push({
241
+ name: NAME2,
242
+ status: "warn",
243
+ detail: `${build.path} has ${unknown.map((h) => `"${h}"`).join(", ")} under "Changes for this repository", which matches no phase`,
244
+ fix: `Rename each heading to a phase: ${BUILD_PHASES.join(", ")}.`
245
+ });
246
+ }
247
+ const lacking = folders.filter(
248
+ (folder) => namesCore(read(join(repoRoot, folder, "build", "SKILL.md")) ?? "") && !existsSync(join(repoRoot, folder, "outerlayer-build", "SKILL.md"))
249
+ );
250
+ if (lacking.length > 0) {
251
+ checks.push({
252
+ name: NAME2,
253
+ status: "warn",
254
+ detail: `${lacking.join(", ")} holds build with no outerlayer-build beside it`,
255
+ fix: `Run \`${cliInvocation()} context emit\` to write outerlayer-build, then commit.`
256
+ });
257
+ }
258
+ return checks;
259
+ }
161
260
 
162
- export { canonical, checkStarterFiles, contextIsGoverned, inspectStarterFiles };
261
+ export { canonical, checkBuildSkill, checkStarterFiles, contentHash, contextIsGoverned, inspectStarterFiles, readShippedManifest, skillsFolders };
@@ -4,7 +4,7 @@ import { readContextManifest, removeContextManifest } from './chunk-YQR6E6OV.js'
4
4
  import { removePreCommitGuardHook } from './chunk-TUSYOL2O.js';
5
5
  import { CONTEXT_PIN_FILENAME } from './chunk-WFSUUUAN.js';
6
6
  import { execFileSync } from 'child_process';
7
- import { existsSync, unlinkSync, lstatSync, readdirSync, rmdirSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
7
+ import { lstatSync, existsSync, unlinkSync, readdirSync, rmdirSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
8
8
  import { join, dirname, isAbsolute } from 'path';
9
9
 
10
10
  createRequire(import.meta.url);
@@ -171,4 +171,4 @@ function cleanupEarlierCopies(input) {
171
171
  return result;
172
172
  }
173
173
 
174
- export { cleanupEarlierCopies };
174
+ export { cleanupEarlierCopies, hasSymlinkComponent };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import { isSameProcess } from './chunk-JBJTC3UU.js';
4
- import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-N2PXGQRL.js';
4
+ import { RUNNER_DIR_MODE, RUNNER_FILE_MODE } from './chunk-IHNQWF6F.js';
5
5
  import { existsSync, readFileSync, rmSync, mkdirSync, writeFileSync } from 'fs';
6
6
  import { dirname } from 'path';
7
7
 
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
+ import { retiredSkillPaths, removeRetiredSkills } from './chunk-USWVXQIH.js';
4
+ import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-5OCIHFGE.js';
3
5
  import { C } from './chunk-ANPNT6PM.js';
4
- import { retiredSkillPaths, removeRetiredSkills } from './chunk-7UWVLZXD.js';
5
- import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-NNLA7LLQ.js';
6
6
  import { cliInvocation } from './chunk-CRB3POP4.js';
7
7
  import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-WFSUUUAN.js';
8
8
  import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, unlinkSync, rmdirSync, readdirSync } from 'fs';