@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,133 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- import { CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_PIN_FILENAME } from './chunk-OHVJA253.js';
4
- import { readFileSync, existsSync, writeFileSync, mkdirSync, utimesSync, statSync, unlinkSync } from 'fs';
5
- import { join, dirname } from 'path';
6
-
7
- createRequire(import.meta.url);
8
- function pinPath(workpieceRoot) {
9
- return join(workpieceRoot, CONTEXT_PIN_FILENAME);
10
- }
11
- function readPin(workpieceRoot) {
12
- try {
13
- const parsed = JSON.parse(readFileSync(pinPath(workpieceRoot), "utf8"));
14
- if (typeof parsed === "object" && parsed !== null && typeof parsed.sha === "string" && typeof parsed.schemaVersion === "number") {
15
- return parsed;
16
- }
17
- return void 0;
18
- } catch {
19
- return void 0;
20
- }
21
- }
22
- function pinExists(workpieceRoot) {
23
- return existsSync(pinPath(workpieceRoot));
24
- }
25
- function writePinIfChanged(workpieceRoot, sha) {
26
- const existing = readPin(workpieceRoot);
27
- if (existing?.sha === sha && existing.schemaVersion === CONTEXT_PIN_SCHEMA_VERSION) return false;
28
- const pin = { schemaVersion: CONTEXT_PIN_SCHEMA_VERSION, sha };
29
- writeFileSync(pinPath(workpieceRoot), JSON.stringify(pin) + "\n");
30
- return true;
31
- }
32
- function stateDir(gitCommonDir) {
33
- return join(gitCommonDir, "outerlayer");
34
- }
35
- function readJson(path) {
36
- try {
37
- return JSON.parse(readFileSync(path, "utf8"));
38
- } catch {
39
- return void 0;
40
- }
41
- }
42
- function writeJson(path, value) {
43
- mkdirSync(dirname(path), { recursive: true });
44
- writeFileSync(path, JSON.stringify(value, null, 2) + "\n");
45
- }
46
- function manifestPath(gitCommonDir) {
47
- return join(stateDir(gitCommonDir), "materialized.json");
48
- }
49
- function readContextManifest(gitCommonDir) {
50
- const parsed = readJson(manifestPath(gitCommonDir));
51
- if (parsed && typeof parsed.sha === "string" && Array.isArray(parsed.files) && parsed.files.every((f) => typeof f === "string") && typeof parsed.materializedAt === "string") {
52
- return parsed;
53
- }
54
- return void 0;
55
- }
56
- function writeContextManifest(gitCommonDir, manifest) {
57
- writeJson(manifestPath(gitCommonDir), manifest);
58
- }
59
- function manifestFilesPresent(workpieceRoot, manifest) {
60
- return manifest.files.every((f) => existsSync(join(workpieceRoot, f)));
61
- }
62
- var DEBOUNCE_MS = 10 * 60 * 1e3;
63
- function lastCheckPath(gitCommonDir) {
64
- return join(stateDir(gitCommonDir), "last-check");
65
- }
66
- function touchLastCheck(gitCommonDir, now) {
67
- const path = lastCheckPath(gitCommonDir);
68
- mkdirSync(dirname(path), { recursive: true });
69
- writeFileSync(path, String(now));
70
- const seconds = now / 1e3;
71
- try {
72
- utimesSync(path, seconds, seconds);
73
- } catch {
74
- }
75
- }
76
- function isLastCheckFresh(gitCommonDir, now, debounceMs = DEBOUNCE_MS) {
77
- try {
78
- const mtimeMs = statSync(lastCheckPath(gitCommonDir)).mtimeMs;
79
- return now - mtimeMs < debounceMs;
80
- } catch {
81
- return false;
82
- }
83
- }
84
- function degradedPath(gitCommonDir) {
85
- return join(stateDir(gitCommonDir), "degraded.json");
86
- }
87
- function readDegraded(gitCommonDir) {
88
- const parsed = readJson(degradedPath(gitCommonDir));
89
- if (parsed && typeof parsed.kind === "string" && typeof parsed.message === "string") return parsed;
90
- return void 0;
91
- }
92
- function writeDegraded(gitCommonDir, state) {
93
- writeJson(degradedPath(gitCommonDir), state);
94
- }
95
- function clearDegraded(gitCommonDir) {
96
- try {
97
- unlinkSync(degradedPath(gitCommonDir));
98
- } catch {
99
- }
100
- }
101
- var SOURCE_CACHE_TTL_SUCCESS_MS = 24 * 60 * 60 * 1e3;
102
- var SOURCE_CACHE_TTL_RETRY_MS = 15 * 60 * 1e3;
103
- function sourceCachePath(gitCommonDir) {
104
- return join(stateDir(gitCommonDir), "source.json");
105
- }
106
- function readSourceCache(gitCommonDir) {
107
- const parsed = readJson(sourceCachePath(gitCommonDir));
108
- if (parsed && (parsed.status === "self" || parsed.status === "governed") && typeof parsed.checkedAt === "string" && typeof parsed.ttlMs === "number") {
109
- return parsed;
110
- }
111
- return void 0;
112
- }
113
- function writeSourceCache(gitCommonDir, cache) {
114
- writeJson(sourceCachePath(gitCommonDir), cache);
115
- }
116
- function isSourceCacheFresh(cache, now) {
117
- return now - Date.parse(cache.checkedAt) < cache.ttlMs;
118
- }
119
- function buildHoldPath(gitCommonDir) {
120
- return join(stateDir(gitCommonDir), "build-hold.json");
121
- }
122
- function readBuildHold(gitCommonDir) {
123
- const parsed = readJson(buildHoldPath(gitCommonDir));
124
- if (parsed && typeof parsed.sha === "string" && typeof parsed.repository === "string" && typeof parsed.ref === "string" && typeof parsed.at === "string") {
125
- return parsed;
126
- }
127
- return void 0;
128
- }
129
- function writeBuildHold(gitCommonDir, hold) {
130
- writeJson(buildHoldPath(gitCommonDir), hold);
131
- }
132
-
133
- export { SOURCE_CACHE_TTL_RETRY_MS, SOURCE_CACHE_TTL_SUCCESS_MS, clearDegraded, isLastCheckFresh, isSourceCacheFresh, manifestFilesPresent, pinExists, readBuildHold, readContextManifest, readDegraded, readPin, readSourceCache, touchLastCheck, writeBuildHold, writeContextManifest, writeDegraded, writePinIfChanged, writeSourceCache };
@@ -1,401 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from 'node:module';
3
- import { homeFromEnv } from './chunk-VNVZDWO3.js';
4
- import { mkdirSync, chmodSync, writeFileSync, readFileSync, readdirSync, existsSync, unlinkSync } from 'fs';
5
- import { join, isAbsolute, dirname, basename, resolve } from 'path';
6
- import { execFileSync } from 'child_process';
7
-
8
- createRequire(import.meta.url);
9
- var CONTEXT_EXCLUDE_MARKER = "outerlayer context materialization";
10
- var VERSION = 1;
11
- var CONTEXT_EXCLUDE_BEGIN_PREFIX = `# BEGIN ${CONTEXT_EXCLUDE_MARKER}`;
12
- var BEGIN_PREFIX = CONTEXT_EXCLUDE_BEGIN_PREFIX;
13
- var BEGIN = `${BEGIN_PREFIX} v${VERSION}`;
14
- var END = `# END ${CONTEXT_EXCLUDE_MARKER}`;
15
- var ENTRIES = ["/AGENTS.md", "/.claude/", "/.outerlayer/"];
16
- var BLOCK_LINES = [BEGIN, ...ENTRIES, END];
17
- function excludeFilePath(gitCommonDir) {
18
- return join(gitCommonDir, "info", "exclude");
19
- }
20
- function readLines(path) {
21
- if (!existsSync(path)) return [];
22
- const content = readFileSync(path, "utf8");
23
- if (content === "") return [];
24
- const lines = content.split("\n");
25
- if (lines[lines.length - 1] === "") lines.pop();
26
- return lines;
27
- }
28
- function writeLines(path, lines) {
29
- mkdirSync(dirname(path), { recursive: true });
30
- writeFileSync(path, lines.length ? lines.join("\n") + "\n" : "");
31
- }
32
- function findWellFormedBlock(lines) {
33
- let i = 0;
34
- while (i < lines.length) {
35
- if (!lines[i].startsWith(BEGIN_PREFIX)) {
36
- i++;
37
- continue;
38
- }
39
- const beginIdx = i;
40
- let endIdx = -1;
41
- let j = beginIdx + 1;
42
- for (; j < lines.length; j++) {
43
- if (lines[j] === END) {
44
- endIdx = j;
45
- break;
46
- }
47
- if (lines[j].startsWith(BEGIN_PREFIX)) break;
48
- }
49
- if (endIdx !== -1) return { beginIdx, endIdx };
50
- i = j;
51
- }
52
- return void 0;
53
- }
54
- function ensureContextExcludes(gitCommonDir) {
55
- const path = excludeFilePath(gitCommonDir);
56
- const lines = readLines(path);
57
- const block = findWellFormedBlock(lines);
58
- if (block !== void 0) {
59
- const { beginIdx, endIdx } = block;
60
- const current = lines.slice(beginIdx, endIdx + 1);
61
- if (current.length === BLOCK_LINES.length && current.every((l, i) => l === BLOCK_LINES[i])) {
62
- return { changed: false };
63
- }
64
- const next = [...lines.slice(0, beginIdx), ...BLOCK_LINES, ...lines.slice(endIdx + 1)];
65
- writeLines(path, next);
66
- return { changed: true };
67
- }
68
- writeLines(path, [...lines, ...BLOCK_LINES]);
69
- return { changed: true };
70
- }
71
- function contextExcludesPresent(gitCommonDir) {
72
- const lines = readLines(excludeFilePath(gitCommonDir));
73
- const beginIdx = lines.findIndex((l) => l === BEGIN);
74
- if (beginIdx === -1) return false;
75
- return BLOCK_LINES.every((l, i) => lines[beginIdx + i] === l);
76
- }
77
- var HOOKS_DIR_NAME = "git-hooks";
78
- var CO_AUTHOR_FILE = "co-author";
79
- var HOOKS = [
80
- "applypatch-msg",
81
- "pre-applypatch",
82
- "post-applypatch",
83
- "pre-commit",
84
- "pre-merge-commit",
85
- "prepare-commit-msg",
86
- "commit-msg",
87
- "post-commit",
88
- "pre-rebase",
89
- "post-checkout",
90
- "post-merge",
91
- "pre-push",
92
- "pre-receive",
93
- "update",
94
- "post-receive",
95
- "post-update",
96
- "reference-transaction",
97
- "pre-auto-gc",
98
- "post-rewrite",
99
- "sendemail-validate",
100
- "post-index-change"
101
- ];
102
- var READS_STDIN = /* @__PURE__ */ new Set(["pre-push", "pre-receive", "post-receive", "reference-transaction", "post-rewrite"]);
103
- var PRE_COMMIT_GUARD_MARKER = "# outerlayer materialized-context commit guard";
104
- var RUN_GUARD = `common=$(git rev-parse --git-common-dir 2>/dev/null)
105
- guard=$common/hooks/pre-commit
106
- if [ "$guard" != "$hook" ] && [ -f "$guard" ] && [ -x "$guard" ] &&
107
- sed -n 2p "$guard" | grep -q '^${PRE_COMMIT_GUARD_MARKER}'; then
108
- "$guard" "$@" || exit $?
109
- fi
110
- `;
111
- var ADD_TRAILER = `
112
- # Every commit of the build names the requester once: a trailer already there is left alone.
113
- file=\${1-}
114
- if [ -n "$file" ] && [ -f "$file" ]; then
115
- git interpret-trailers --in-place --if-exists addIfDifferent --trailer "Co-authored-by: $(cat "$here/${CO_AUTHOR_FILE}")" "$file" ||
116
- echo "outerlayer: could not add the co-author line to the commit message" >&2
117
- fi
118
- `;
119
- var HOOK_WRAPPER_MARKER = "# Written by the OuterLayer runner.";
120
- function script(name) {
121
- const adds = name === "prepare-commit-msg";
122
- return `#!/bin/sh
123
- ${HOOK_WRAPPER_MARKER} Runs the repository's own ${name} hook, then
124
- # ${adds ? "adds the co-author line to the commit message" : "hands its status on"}.
125
- here=$(dirname "$0")
126
-
127
- # The hooks path git would use without this directory: cut the list of configuration
128
- # entries the runner passes just before its own core.hooksPath entry, then ask git.
129
- n=\${GIT_CONFIG_COUNT-0}
130
- case $n in '' | *[!0-9]*) n=0 ;; esac
131
- cut=$n
132
- i=$n
133
- while [ "$i" -gt 0 ]; do
134
- i=$((i - 1))
135
- eval "key=\\\${GIT_CONFIG_KEY_$i-}"
136
- eval "value=\\\${GIT_CONFIG_VALUE_$i-}"
137
- if [ "$key" = core.hooksPath ] && { [ "$value" = "$here" ] || [ "$value" -ef "$here" ]; }; then
138
- cut=$i
139
- break
140
- fi
141
- done
142
- path=$(GIT_CONFIG_COUNT=$cut git config --type=path core.hooksPath 2>/dev/null) || path=
143
- if [ -z "$path" ]; then
144
- path=$(git rev-parse --git-common-dir 2>/dev/null)/hooks
145
- fi
146
-
147
- hook=$path/${name}
148
- ${name === "pre-commit" ? RUN_GUARD : ""}status=0
149
- if [ "$path" -ef "$here" ] || [ ! -f "$hook" ] || [ ! -x "$hook" ]; then
150
- ${READS_STDIN.has(name) ? " cat >/dev/null\n" : ""} :
151
- else
152
- ${adds ? ` "$hook" "$@" || status=$?` : ` exec "$hook" "$@"`}
153
- fi
154
- ${adds ? `[ "$status" -eq 0 ] || exit "$status"
155
- ${ADD_TRAILER}` : ""}exit 0
156
- `;
157
- }
158
- function writeCommitHooks(buildDir, coAuthor) {
159
- const dir = join(buildDir, HOOKS_DIR_NAME);
160
- mkdirSync(dir, { recursive: true });
161
- chmodSync(dir, 493);
162
- for (const name of HOOKS) {
163
- const path = join(dir, name);
164
- writeFileSync(path, script(name));
165
- chmodSync(path, 493);
166
- }
167
- const data = join(dir, CO_AUTHOR_FILE);
168
- writeFileSync(data, `${coAuthor.name} <${coAuthor.email}>
169
- `);
170
- chmodSync(data, 420);
171
- return dir;
172
- }
173
- var JOURNAL_HOOK_MARKER = "# outerlayer post-rewrite journal";
174
- var PRE_COMMIT_GUARD_VERSION = `${PRE_COMMIT_GUARD_MARKER} v1`;
175
- var PRE_COMMIT_GUARD_BODY_SIGNATURE = "outerlayer: refusing to commit materialized control-plane context";
176
- var PRE_COMMIT_GUARD_SCRIPT = `#!/bin/sh
177
- ${PRE_COMMIT_GUARD_VERSION}
178
- unset GIT_LITERAL_PATHSPECS GIT_GLOB_PATHSPECS GIT_NOGLOB_PATHSPECS GIT_ICASE_PATHSPECS
179
- PATH="$PATH:/usr/bin:/bin"
180
- export PATH
181
- COMMON_DIR="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)"
182
- if [ -z "$COMMON_DIR" ]; then
183
- COMMON_DIR="$(git rev-parse --git-common-dir 2>/dev/null)" || exit 0
184
- case "$COMMON_DIR" in /*) ;; *) COMMON_DIR="$PWD/$COMMON_DIR" ;; esac
185
- fi
186
- grep -qF "${CONTEXT_EXCLUDE_BEGIN_PREFIX}" "$COMMON_DIR/info/exclude" 2>/dev/null || exit 0
187
-
188
- if git rev-parse --verify -q HEAD >/dev/null 2>&1; then
189
- BASE=HEAD
190
- REMEDY="git restore --staged <path>"
191
- else
192
- BASE="$(git hash-object -t tree --stdin < /dev/null)"
193
- REMEDY="git rm --cached <path>"
194
- fi
195
- [ -n "$BASE" ] || exit 0
196
-
197
- BLOCKED="$(git diff --cached --name-only --diff-filter=A --no-renames --ignore-submodules=none "$BASE" -- ':(icase)AGENTS.md' ':(icase).claude' ':(icase).outerlayer' 2>/dev/null)"
198
- [ -n "$BLOCKED" ] || exit 0
199
-
200
- echo "${PRE_COMMIT_GUARD_BODY_SIGNATURE}:" >&2
201
- printf '%s\\n' "$BLOCKED" | while IFS= read -r path; do
202
- [ -n "$path" ] && echo " $path" >&2
203
- done
204
- echo "These paths come from a private control plane and must never enter this" >&2
205
- echo "repository's history. Unstage them to continue:" >&2
206
- echo " $REMEDY" >&2
207
- exit 1
208
- `;
209
- function managedHookScripts() {
210
- return [["pre-commit", printableHookScript(PRE_COMMIT_GUARD_SCRIPT)]];
211
- }
212
- function printableHookScript(script2) {
213
- const lines = script2.split("\n");
214
- return [lines[0], ...lines.slice(2)].join("\n");
215
- }
216
- function git(cwd, args) {
217
- try {
218
- return execFileSync("git", ["-C", cwd, ...args], {
219
- encoding: "utf8",
220
- stdio: ["ignore", "pipe", "ignore"],
221
- timeout: 2e3
222
- }).trim();
223
- } catch {
224
- return void 0;
225
- }
226
- }
227
- function hooksDir(cwd) {
228
- const dir = git(cwd, ["rev-parse", "--git-path", "hooks"]);
229
- if (dir === void 0) return void 0;
230
- return isAbsolute(dir) ? dir : resolve(cwd, dir);
231
- }
232
- function commonHooksDir(cwd) {
233
- const abs = git(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
234
- if (abs !== void 0) return join(abs, "hooks");
235
- const rel = git(cwd, ["rev-parse", "--git-common-dir"]);
236
- if (rel === void 0) return void 0;
237
- return join(isAbsolute(rel) ? rel : join(cwd, rel), "hooks");
238
- }
239
- function installHookFile(dir, name, script2, marker) {
240
- const path = join(dir, name);
241
- let existing;
242
- try {
243
- existing = readFileSync(path, "utf8");
244
- } catch {
245
- existing = void 0;
246
- }
247
- if (existing !== void 0) {
248
- if (!isOwnRecognitionLine(existing, marker)) return "skipped-foreign";
249
- if (existing === script2) {
250
- try {
251
- chmodSync(path, 493);
252
- } catch {
253
- }
254
- return "unchanged";
255
- }
256
- }
257
- mkdirSync(dir, { recursive: true });
258
- writeFileSync(path, script2);
259
- chmodSync(path, 493);
260
- return existing === void 0 ? "installed" : "updated";
261
- }
262
- function removeOurHookFile(path, marker) {
263
- if (!existsSync(path)) return false;
264
- let content;
265
- try {
266
- content = readFileSync(path, "utf8");
267
- } catch {
268
- return false;
269
- }
270
- if (!isOwnRecognitionLine(content, marker)) return false;
271
- unlinkSync(path);
272
- return true;
273
- }
274
- function isOwnRecognitionLine(content, marker) {
275
- const secondLine = content.split("\n", 2)[1];
276
- return secondLine !== void 0 && secondLine.startsWith(marker);
277
- }
278
- function removeJournalHooks(cwd) {
279
- const dir = hooksDir(cwd);
280
- if (dir === void 0) return { removed: false };
281
- let removed = false;
282
- for (const name of ["post-rewrite", "post-commit", "prepare-commit-msg"]) {
283
- if (removeOurHookFile(join(dir, name), JOURNAL_HOOK_MARKER)) removed = true;
284
- }
285
- return { removed, path: dir };
286
- }
287
- function installPreCommitGuardHook(cwd) {
288
- const inRepo = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
289
- if (inRepo !== "true") return { status: "not-a-repo", adopted: false };
290
- const hooksPath = git(cwd, ["config", "core.hooksPath"]) ?? "";
291
- if (hooksPath !== "") {
292
- const expanded = expandHooksPathTilde(hooksPath);
293
- const effectiveDir = isAbsolute(expanded) ? expanded : join(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd, expanded);
294
- const path2 = join(effectiveDir, "pre-commit");
295
- return { status: "skipped-custom-hooks-path", path: path2, adopted: guardAdoptedAtEffectiveHook(path2) };
296
- }
297
- const dir = hooksDir(cwd);
298
- if (dir === void 0) return { status: "not-a-repo", adopted: false };
299
- const path = join(dir, "pre-commit");
300
- const status = installHookFile(dir, "pre-commit", PRE_COMMIT_GUARD_SCRIPT, PRE_COMMIT_GUARD_MARKER);
301
- return { status, path, adopted: status === "skipped-foreign" ? guardBodyPresent(path) : true };
302
- }
303
- function removePreCommitGuardHook(cwd) {
304
- const dir = commonHooksDir(cwd);
305
- if (dir === void 0) return { removed: false };
306
- const path = join(dir, "pre-commit");
307
- return { removed: removeOurHookFile(path, PRE_COMMIT_GUARD_MARKER), path };
308
- }
309
- var GUARD_BODY_LINE_PREFIXES = [`echo "${PRE_COMMIT_GUARD_BODY_SIGNATURE}`, `echo '${PRE_COMMIT_GUARD_BODY_SIGNATURE}`];
310
- function guardBodyPresent(path) {
311
- let content;
312
- try {
313
- content = readFileSync(path, "utf8");
314
- } catch {
315
- return false;
316
- }
317
- return content.split("\n").some((line) => {
318
- const trimmed = line.trimStart();
319
- return GUARD_BODY_LINE_PREFIXES.some((prefix) => trimmed.startsWith(prefix));
320
- });
321
- }
322
- function guardAdoptedAtEffectiveHook(effectiveHookPath) {
323
- if (guardBodyPresent(effectiveHookPath)) return true;
324
- const shimDir = dirname(effectiveHookPath);
325
- if (basename(shimDir) !== "_") return false;
326
- return guardBodyPresent(join(dirname(shimDir), basename(effectiveHookPath)));
327
- }
328
- function expandHooksPathTilde(hooksPath) {
329
- if (hooksPath === "~") return homeFromEnv();
330
- if (hooksPath.startsWith("~/")) return join(homeFromEnv(), hooksPath.slice(2));
331
- return hooksPath;
332
- }
333
- function ensurePreCommitGuardHook(repoRoot, gitCommonDir) {
334
- const hooksPath = git(repoRoot, ["config", "core.hooksPath"]) ?? "";
335
- if (hooksPath !== "" && !isRunnerHookWrapper(hooksPath, repoRoot)) {
336
- const expanded = expandHooksPathTilde(hooksPath);
337
- const effectivePath = isAbsolute(expanded) ? join(expanded, "pre-commit") : join(repoRoot, expanded, "pre-commit");
338
- return { status: "skipped-custom-hooks-path", adopted: guardAdoptedAtEffectiveHook(effectivePath) };
339
- }
340
- return installPreCommitGuardInGitDir(gitCommonDir);
341
- }
342
- function installPreCommitGuardInGitDir(gitCommonDir) {
343
- const path = join(gitCommonDir, "hooks", "pre-commit");
344
- const status = installHookFile(join(gitCommonDir, "hooks"), "pre-commit", PRE_COMMIT_GUARD_SCRIPT, PRE_COMMIT_GUARD_MARKER);
345
- return { status, adopted: status === "skipped-foreign" ? guardBodyPresent(path) : true };
346
- }
347
- function isRunnerHookWrapper(hooksPath, repoRoot) {
348
- const dir = resolve(repoRoot, expandHooksPathTilde(hooksPath));
349
- if (basename(dir) !== HOOKS_DIR_NAME) return false;
350
- try {
351
- const script2 = readFileSync(join(dir, "pre-commit"), "utf8");
352
- const secondLine = script2.indexOf("\n") + 1;
353
- return secondLine > 0 && script2.startsWith(HOOK_WRAPPER_MARKER, secondLine);
354
- } catch {
355
- return false;
356
- }
357
- }
358
- function deadHooksState(cwd) {
359
- const inRepo = git(cwd, ["rev-parse", "--is-inside-work-tree"]);
360
- if (inRepo !== "true") return { dead: false };
361
- const hooksPath = git(cwd, ["config", "core.hooksPath"]) ?? "";
362
- if (hooksPath === "") return { dead: false };
363
- const top = git(cwd, ["rev-parse", "--show-toplevel"]);
364
- if (top === void 0) return { dead: false };
365
- const expanded = expandHooksPathTilde(hooksPath);
366
- const hooksDir2 = isAbsolute(expanded) ? expanded : join(top, expanded);
367
- let entries;
368
- try {
369
- entries = readdirSync(hooksDir2);
370
- } catch (err) {
371
- const code = err.code;
372
- if (code === "ENOENT" || code === "ENOTDIR") return { dead: true, hooksDir: hooksDir2, repoRoot: top };
373
- return { dead: false, hooksDir: hooksDir2, repoRoot: top, unreadableError: err };
374
- }
375
- const dead = entries.filter((e) => e !== ".gitignore").length === 0;
376
- return { dead, hooksDir: hooksDir2, repoRoot: top };
377
- }
378
- var ALLOWED_PACKAGE_MANAGERS = ["yarn", "npm", "pnpm", "bun"];
379
- function preparePackageManagerCommand(repoRoot) {
380
- let declared = "";
381
- try {
382
- const pkg = JSON.parse(readFileSync(join(repoRoot, "package.json"), "utf8"));
383
- if (typeof pkg.packageManager === "string") declared = pkg.packageManager.split("@")[0] ?? "";
384
- } catch {
385
- declared = "";
386
- }
387
- if (!ALLOWED_PACKAGE_MANAGERS.includes(declared)) declared = "";
388
- if (declared === "yarn") return "yarn prepare";
389
- return `${declared || "npm"} run prepare`;
390
- }
391
- function huskyPrepareScript(repoRoot) {
392
- try {
393
- const pkg = JSON.parse(readFileSync(join(repoRoot, "package.json"), "utf8"));
394
- const script2 = pkg.scripts?.prepare;
395
- if (typeof script2 === "string" && /husky/i.test(script2)) return script2;
396
- } catch {
397
- }
398
- return null;
399
- }
400
-
401
- export { HOOKS_DIR_NAME, contextExcludesPresent, deadHooksState, ensureContextExcludes, ensurePreCommitGuardHook, huskyPrepareScript, installPreCommitGuardHook, installPreCommitGuardInGitDir, managedHookScripts, preparePackageManagerCommand, removeJournalHooks, removePreCommitGuardHook, writeCommitHooks };