@outerlayer/cli 0.22.1 → 0.23.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 (114) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +4 -1
  3. package/dist/{agent-setup-LTSLXPS3.js → agent-setup-SNDCEHG2.js} +14 -12
  4. package/dist/{artifact-link-cmd-OWRI5AJX.js → artifact-link-cmd-LEI6EOZE.js} +2 -2
  5. package/dist/bridge-QFN3KJP6.js +8 -0
  6. package/dist/{build-6WRNZPVR.js → build-WHHFA7KM.js} +2 -2
  7. package/dist/build-info.json +1 -1
  8. package/dist/{builder-G3MLDMTI.js → builder-7FBQAWQZ.js} +3 -3
  9. package/dist/{check-UYKEMQNR.js → check-3CGLWMHM.js} +37 -37
  10. package/dist/{chunk-ZPSLJFGL.js → chunk-2TT7DEMZ.js} +2 -2
  11. package/dist/{chunk-3V5C64Y5.js → chunk-6AOZD3LY.js} +3 -4
  12. package/dist/{chunk-5NJIWKD4.js → chunk-BOG4ENP7.js} +9 -9
  13. package/dist/{chunk-G3IJ3N6F.js → chunk-BUP5N3X6.js} +1 -1
  14. package/dist/{chunk-FRNYCJ4W.js → chunk-C2XZBNHY.js} +1 -1
  15. package/dist/{chunk-BET347JZ.js → chunk-C64D7HR3.js} +6 -7
  16. package/dist/{chunk-AEKSX4EY.js → chunk-CBCKD6DO.js} +1 -1
  17. package/dist/{chunk-56X5TOJY.js → chunk-D64E222W.js} +5 -6
  18. package/dist/{chunk-URAKVDSI.js → chunk-DJYOCD65.js} +9 -10
  19. package/dist/{chunk-IZSVXRDR.js → chunk-DXDF43YG.js} +1 -1
  20. package/dist/{chunk-F7CU5ABH.js → chunk-DYEFPYME.js} +1 -1
  21. package/dist/{chunk-ORNJJ7XN.js → chunk-FX6IHR5C.js} +11 -12
  22. package/dist/{chunk-ENTHEUKT.js → chunk-G3LHWUBK.js} +4 -4
  23. package/dist/{chunk-5QRP3MVS.js → chunk-GNPTU4BM.js} +9 -4
  24. package/dist/{chunk-JRCSET55.js → chunk-GXV73IIS.js} +6 -6
  25. package/dist/{chunk-5OCIHFGE.js → chunk-HBISTTG3.js} +32 -23
  26. package/dist/chunk-JKNYTNYD.js +151 -0
  27. package/dist/{chunk-CUFFDEF3.js → chunk-KGKFEONR.js} +4 -4
  28. package/dist/{chunk-USWVXQIH.js → chunk-MQ743JX3.js} +3 -3
  29. package/dist/{chunk-XR56WEA5.js → chunk-OGMZJWWD.js} +1 -1
  30. package/dist/chunk-QS43O4DR.js +113 -0
  31. package/dist/{chunk-FOCML5FI.js → chunk-QSEPKZXR.js} +15 -14
  32. package/dist/{chunk-7VUK5RFS.js → chunk-QZBXLLTV.js} +36 -1
  33. package/dist/{chunk-WFSUUUAN.js → chunk-RKOTJQVG.js} +1 -1
  34. package/dist/{chunk-7FEY33MY.js → chunk-TFGXOHF6.js} +13 -13
  35. package/dist/{chunk-V7SAQ645.js → chunk-VJBFQP3H.js} +21 -12
  36. package/dist/{chunk-ZNPE7FW5.js → chunk-VPEGE3QZ.js} +1 -1
  37. package/dist/{chunk-W3SWJ2TD.js → chunk-VWFOKRYS.js} +5 -2
  38. package/dist/{chunk-XCRZTXRL.js → chunk-WX2WEERU.js} +63 -43
  39. package/dist/chunk-WXJXHZVB.js +73 -0
  40. package/dist/{chunk-BOMRFYTZ.js → chunk-WY7HFY62.js} +3 -3
  41. package/dist/{chunk-VSUXCMMH.js → chunk-XFGL53GU.js} +51 -33
  42. package/dist/{chunk-6YBLN4TR.js → chunk-XGPC3IOR.js} +4 -5
  43. package/dist/{chunk-QC72I5GQ.js → chunk-XOEV4FVK.js} +3 -3
  44. package/dist/{chunk-EAQSOE62.js → chunk-XSPA5ODY.js} +21 -19
  45. package/dist/{chunk-JZGFDTNC.js → chunk-Z42JY3LQ.js} +20 -3
  46. package/dist/{chunk-O6RJ3QMU.js → chunk-ZKWKQIJU.js} +86 -6
  47. package/dist/{chunk-QOALB6ZD.js → chunk-ZLZ3XVPI.js} +3 -3
  48. package/dist/{claude-launcher-TBWV3YL3.js → claude-launcher-KEESTJHO.js} +5 -5
  49. package/dist/{cli-U253V422.js → cli-44WGGICQ.js} +126 -112
  50. package/dist/{command-IQTPFSXY.js → command-4FAP2D3P.js} +22 -23
  51. package/dist/connect-cmd-6DUTUK63.js +22 -0
  52. package/dist/{context-cleanup-DSA3HGQU.js → context-cleanup-LTH77FC3.js} +3 -3
  53. package/dist/{control-plane-launch-OWSNH6YA.js → control-plane-launch-SEYCOZFH.js} +8 -9
  54. package/dist/{dist-7IH56ELA.js → dist-SOH3O24Y.js} +2 -2
  55. package/dist/{docker-JU422JL7.js → docker-KMK4LOET.js} +3 -3
  56. package/dist/{doctor-FZTS57ZO.js → doctor-4H77CEB7.js} +24 -25
  57. package/dist/{emit-artifact-cmd-YLZ5WLSF.js → emit-artifact-cmd-XCZ3ALLV.js} +15 -15
  58. package/dist/emit-cmd-WQH2NK7H.js +15 -0
  59. package/dist/{emit-criteria-cmd-MF6TVE7C.js → emit-criteria-cmd-JE72JHKJ.js} +10 -10
  60. package/dist/{emit-finding-cmd-S3YMFTZT.js → emit-finding-cmd-ILIDRMYN.js} +10 -10
  61. package/dist/{emit-result-cmd-JHEUFTPX.js → emit-result-cmd-WPKG5YAS.js} +15 -15
  62. package/dist/{emit-step-cmd-TUI2T3DS.js → emit-step-cmd-OVMLQSL6.js} +11 -11
  63. package/dist/{governing-source-XSEIRSBE.js → governing-source-EQBKPME7.js} +16 -17
  64. package/dist/{guest-init-DF7V5D2R.js → guest-init-HWSE7W6L.js} +3 -2
  65. package/dist/{hook-fast-O3UUN6SO.js → hook-fast-27SHD72I.js} +1 -1
  66. package/dist/{hook-wrap-fast-NPLHJXFK.js → hook-wrap-fast-NOOGDNSW.js} +2 -2
  67. package/dist/{import-capture-cmd-Q56DDZVO.js → import-capture-cmd-TCOKNVBM.js} +12 -7
  68. package/dist/{import-ruler-cmd-T6LLO6Q7.js → import-ruler-cmd-VJOHOJQ7.js} +2 -2
  69. package/dist/index.js +6 -6
  70. package/dist/{init-ZZZPYGUH.js → init-HAAHIQFN.js} +23 -24
  71. package/dist/{init-VZE72CR4.js → init-WQ62BXDN.js} +23 -24
  72. package/dist/{init-cmd-W5VV62ZN.js → init-cmd-VPFIDY64.js} +24 -24
  73. package/dist/init-update-UZIJ2FMU.js +529 -0
  74. package/dist/layout-UOJQGEPW.js +10 -0
  75. package/dist/{login-browser-BN5UKPHS.js → login-browser-4OMZFP3U.js} +4 -3
  76. package/dist/{logout-cmd-RZFWTNYD.js → logout-cmd-5V5MMBSY.js} +2 -2
  77. package/dist/{loop-6WENRS5S.js → loop-JPW2QJ64.js} +37 -37
  78. package/dist/{machine-M4MQBV5A.js → machine-PGDRWPI2.js} +22 -23
  79. package/dist/{mcp-install-cmd-GD4QUP7Z.js → mcp-install-cmd-GGWB3JJ2.js} +2 -2
  80. package/dist/{mcp-serve-cmd-SBW7HYKD.js → mcp-serve-cmd-CNRC5AL5.js} +3 -3
  81. package/dist/{runner-identity-FTHZFMGY.js → runner-identity-IIZ3RK7M.js} +3 -3
  82. package/dist/{runner-key-QT7GKGEE.js → runner-key-BPP5XRYR.js} +23 -24
  83. package/dist/{session-sender-BK6TGNVO.js → session-sender-EKKZ5DEU.js} +16 -16
  84. package/dist/{settings-J2652U5N.js → settings-AKYEOCC2.js} +1 -1
  85. package/dist/{spec-cmd-ZNJ3GXWC.js → spec-cmd-JDHGNFVJ.js} +11 -11
  86. package/dist/{starter-pack-5EQYGSJF.js → starter-pack-55EFILC5.js} +7 -4
  87. package/dist/{status-JOO7MGIC.js → status-UCQDEMFX.js} +30 -30
  88. package/dist/{statusline-fast-2OK3DVAA.js → statusline-fast-GVRSBHAF.js} +2 -2
  89. package/dist/{sync-cmd-W2FPY3T5.js → sync-cmd-NSVXOYFJ.js} +15 -15
  90. package/dist/{watch-WLH5ZUZU.js → watch-NQVZWPBJ.js} +15 -15
  91. package/dist/{work-claim-cmd-4PLDTEZR.js → work-claim-cmd-FPJXQAXP.js} +13 -13
  92. package/dist/{work-cmd-KWHAYUYB.js → work-cmd-FMPDXPU6.js} +11 -11
  93. package/dist/{work-comment-cmd-4CUI7ZDE.js → work-comment-cmd-ZVUE2IUN.js} +11 -11
  94. package/dist/{work-logs-cmd-AF253WLM.js → work-logs-cmd-CQH2SYT4.js} +11 -11
  95. package/dist/{work-open-pr-cmd-JETE6HRL.js → work-open-pr-cmd-YY2OGJOI.js} +12 -12
  96. package/dist/{work-pr-cmd-V5G4CPMG.js → work-pr-cmd-EHFTEVJO.js} +11 -11
  97. package/dist/{work-stop-cmd-FIEKUDGE.js → work-stop-cmd-LGWSBSBT.js} +11 -11
  98. package/package.json +1 -1
  99. package/skill-pack/maintained/outerlayer-amend/SKILL.md +83 -82
  100. package/skill-pack/maintained/outerlayer-build/SKILL.md +4 -2
  101. package/skill-pack/maintained/outerlayer-build/references/agent-briefs.md +17 -4
  102. package/skill-pack/maintained/outerlayer-build/references/criteria-judge.md +10 -0
  103. package/skill-pack/maintained/outerlayer-build/references/release.md +7 -4
  104. package/skill-pack/maintained/outerlayer-build/references/review-briefs.md +10 -3
  105. package/skill-pack/maintained/outerlayer-cli/SKILL.md +13 -4
  106. package/skill-pack/maintained/outerlayer-cli/references/merge-base-branch.md +54 -0
  107. package/dist/chunk-NTRCK4NH.js +0 -38
  108. package/dist/chunk-QF7WZUU6.js +0 -56
  109. package/dist/connect-cmd-ZFOK6HEL.js +0 -17
  110. package/dist/emit-cmd-3W5IO5ET.js +0 -14
  111. package/dist/init-update-YFPIQS5G.js +0 -211
  112. package/dist/{chunk-F35VMF5M.js → chunk-GOSFARMS.js} +1 -1
  113. package/dist/{chunk-3AZYLAJC.js → chunk-QILR6TZP.js} +1 -1
  114. package/dist/{chunk-DIB2WLBL.js → chunk-YVZJ6GKF.js} +1 -1
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { revokeTokenOnDashboard } from './chunk-F35VMF5M.js';
3
+ import { revokeTokenOnDashboard } from './chunk-GOSFARMS.js';
4
4
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
5
- import { readCloudConfig, writeCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
6
5
  import { C } from './chunk-ANPNT6PM.js';
6
+ import { readCloudConfig, writeCloudConfig, cloudConfigPath } from './chunk-EABW6AJQ.js';
7
7
  import { cliInvocation } from './chunk-CRB3POP4.js';
8
+ import { CLI_LOGIN_MACHINE_NAME_MAX, CliLoginPollResponseSchema, CLI_LOGIN_KIND, CliLoginRefusalSchema, CliLoginStartedSchema } from './chunk-QZBXLLTV.js';
8
9
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
9
10
  import { generateKeyPairSync, privateDecrypt, constants, createPrivateKey } from 'crypto';
10
11
  import { spawn } from 'child_process';
@@ -45,7 +46,6 @@ var PIPED_KEY_GIVE_UP_MS = 3e4;
45
46
  var REQUEST_TIMEOUT_MS = 15e3;
46
47
  var MAX_POLL_FAILURES = 5;
47
48
  var DEFAULT_POLL_INTERVAL_S = 3;
48
- var MACHINE_NAME_MAX = 255;
49
49
  function realLoginDeps() {
50
50
  return {
51
51
  fetchImpl: fetch,
@@ -74,7 +74,7 @@ function openInBrowser(url) {
74
74
  }
75
75
  function sanitizeMachineName(raw) {
76
76
  const cleaned = raw.replace(/[^\w\s\-().]/g, "").trim();
77
- return (cleaned.length > 0 ? cleaned : "machine").slice(0, MACHINE_NAME_MAX);
77
+ return (cleaned.length > 0 ? cleaned : "machine").slice(0, CLI_LOGIN_MACHINE_NAME_MAX);
78
78
  }
79
79
  function stdinKind(stdin) {
80
80
  if (stdin.isTTY) return "terminal";
@@ -168,16 +168,13 @@ function purgeExpiredPending(home, now, keepId) {
168
168
  }
169
169
  }
170
170
  }
171
- function asRecord(value) {
172
- return typeof value === "object" && value !== null ? value : {};
173
- }
174
171
  async function startLogin(deps, dashboard, publicKey, machineName) {
175
172
  let res;
176
173
  try {
177
174
  res = await deps.fetchImpl(`${dashboard}/api/cli/login`, {
178
175
  method: "POST",
179
176
  headers: { "content-type": "application/json" },
180
- body: JSON.stringify({ public_key: publicKey, machine_name: machineName, kind: "account" }),
177
+ body: JSON.stringify({ public_key: publicKey, machine_name: machineName, kind: CLI_LOGIN_KIND }),
181
178
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
182
179
  });
183
180
  } catch (err) {
@@ -189,16 +186,18 @@ async function startLogin(deps, dashboard, publicKey, machineName) {
189
186
  `${dashboard} is limiting logins from this address` + (wait > 0 ? `; try again in ${wait} seconds` : "; try again shortly")
190
187
  );
191
188
  }
192
- const body = asRecord(await res.json().catch(() => null));
189
+ const body = await res.json().catch(() => null);
193
190
  if (!res.ok) {
194
- const reason = typeof body.message === "string" ? `: ${body.message}` : "";
191
+ const refusal = CliLoginRefusalSchema.safeParse(body);
192
+ const reason = refusal.success && refusal.data.message !== void 0 ? `: ${refusal.data.message}` : "";
195
193
  throw new LoginError(`${dashboard} refused to start a login (HTTP ${res.status})${reason}`);
196
194
  }
197
- if (typeof body.id !== "string" || typeof body.code !== "string" || typeof body.expires_at !== "string") {
195
+ const started = CliLoginStartedSchema.safeParse(body);
196
+ if (!started.success) {
198
197
  throw new LoginError(`${dashboard} answered with something that is not a login; is --dashboard the dashboard's address?`);
199
198
  }
200
- const interval = typeof body.interval === "number" && body.interval > 0 ? body.interval : DEFAULT_POLL_INTERVAL_S;
201
- return { id: body.id, code: body.code, interval, expiresAt: body.expires_at };
199
+ const { id, code, interval, expires_at: expiresAt } = started.data;
200
+ return { id, code, interval: interval ?? DEFAULT_POLL_INTERVAL_S, expiresAt };
202
201
  }
203
202
  async function pollLogin(deps, dashboard, id) {
204
203
  let res;
@@ -215,13 +214,16 @@ async function pollLogin(deps, dashboard, id) {
215
214
  if (res.status === 202) return { kind: "pending" };
216
215
  if (res.status >= 500) return { kind: "unavailable", message: `HTTP ${res.status}` };
217
216
  if (!res.ok) return { kind: "error", message: `HTTP ${res.status}` };
218
- const body = asRecord(await res.json().catch(() => null));
219
- if (body.status === "pending") return { kind: "pending" };
220
- if (body.status === "denied") return { kind: "denied" };
221
- if (body.status === "approved" && typeof body.encrypted_token === "string" && typeof body.gateway_url === "string" && typeof body.email === "string") {
222
- return { kind: "approved", encryptedToken: body.encrypted_token, gatewayUrl: body.gateway_url, email: body.email };
217
+ const answer = CliLoginPollResponseSchema.safeParse(await res.json().catch(() => null));
218
+ if (!answer.success) return { kind: "error", message: "unexpected answer" };
219
+ switch (answer.data.status) {
220
+ case "pending":
221
+ return { kind: "pending" };
222
+ case "denied":
223
+ return { kind: "denied" };
224
+ case "approved":
225
+ return { kind: "approved", encryptedToken: answer.data.encrypted_token, gatewayUrl: answer.data.gateway_url, email: answer.data.email };
223
226
  }
224
- return { kind: "error", message: "unexpected answer" };
225
227
  }
226
228
  function decryptToken(privateKeyPem, encryptedToken) {
227
229
  try {
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { EXEC_PORT } from './chunk-2Q3PZ42G.js';
3
+ import { BRIDGE_ADDRESS, TUNNEL_PORT, BRIDGE_CIDR } from './chunk-WXJXHZVB.js';
4
4
  import { startTimeOf } from './chunk-JBJTC3UU.js';
5
+ import { EXEC_PORT } from './chunk-2Q3PZ42G.js';
5
6
  import { RELAY_PORT } from './chunk-URWYRAIC.js';
6
7
  import { spawn, spawnSync } from 'child_process';
7
8
  import { writeFileSync, chmodSync, mkdirSync } from 'fs';
@@ -12,6 +13,7 @@ var HELPER_RECORD = "/run/outerlayer-helpers";
12
13
  var KERNEL_FLAG = "outerlayer.relay";
13
14
  var DOCKER_FLAG = "outerlayer.docker";
14
15
  var DOCKERD_CONFIG = "/run/outerlayer-dockerd.json";
16
+ var NONLOCAL_BIND = "/proc/sys/net/ipv4/ip_nonlocal_bind";
15
17
  var DOCKERD_LOG = "/run/dockerd.log";
16
18
  var DOCKER_DATA_ROOT = "/build/docker";
17
19
  var BUILD_DISK = "/dev/vdb";
@@ -32,13 +34,25 @@ function relayPortsFrom(cmdline) {
32
34
  function dockerRequestedBy(cmdline) {
33
35
  return new RegExp(`(?:^|\\s)${DOCKER_FLAG.replace(".", "\\.")}=1(?:\\s|$)`).test(cmdline);
34
36
  }
37
+ function startBridgeForwarder(host) {
38
+ host.writeFile(NONLOCAL_BIND, "1");
39
+ host.spawnDetached([
40
+ "/opt/outerlayer/bin/node",
41
+ "/opt/outerlayer/cli/dist/index.js",
42
+ "vm-forward",
43
+ "--listen",
44
+ `${BRIDGE_ADDRESS}:${TUNNEL_PORT}`,
45
+ "--to",
46
+ `127.0.0.1:${TUNNEL_PORT}`
47
+ ]);
48
+ }
35
49
  function startDocker(host) {
36
50
  const proxy = `http://127.0.0.1:${RELAY_PORT}`;
37
51
  host.mount({ source: "cgroup2", target: "/sys/fs/cgroup", type: "cgroup2" });
38
52
  host.mkdir(DOCKER_DATA_ROOT, 457);
39
53
  host.writeFile(
40
54
  DOCKERD_CONFIG,
41
- `${JSON.stringify({ "data-root": DOCKER_DATA_ROOT, proxies: { "http-proxy": proxy, "https-proxy": proxy, "no-proxy": "localhost,127.0.0.1" } }, null, 2)}
55
+ `${JSON.stringify({ "data-root": DOCKER_DATA_ROOT, bip: BRIDGE_CIDR, proxies: { "http-proxy": proxy, "https-proxy": proxy, "no-proxy": "localhost,127.0.0.1" } }, null, 2)}
42
56
  `
43
57
  );
44
58
  host.spawnDetached(["/bin/sh", "-c", `exec dockerd --config-file ${DOCKERD_CONFIG} >${DOCKERD_LOG} 2>&1`]);
@@ -65,7 +79,10 @@ function runGuestInit(host, cmdline) {
65
79
  host.writeFile("/proc/sys/kernel/hostname", HOSTNAME);
66
80
  host.mount({ source: "tmpfs", target: "/outerlayer/job", type: "tmpfs", options: "mode=0755" });
67
81
  const relay = host.spawnDetached([HELPER_PATH, "relay", ...ports.flatMap((port) => ["--forward", String(port)])]);
68
- if (dockerRequestedBy(cmdline)) startDocker(host);
82
+ if (dockerRequestedBy(cmdline)) {
83
+ startBridgeForwarder(host);
84
+ startDocker(host);
85
+ }
69
86
  const agent = host.spawnDetached([HELPER_PATH, "exec-agent", "--port", String(EXEC_PORT)]);
70
87
  host.writeFile(HELPER_RECORD, [relay, agent].map((started) => `${started.pid} ${started.start}
71
88
  `).join(""));
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { runEmit } from './chunk-XCRZTXRL.js';
4
- import { resolveGitCommonDir, defaultGitRunner } from './chunk-6YBLN4TR.js';
5
- import { addStdioMcpEntryIfAbsent, addDocsMcpEntryIfAbsent, DOCS_MCP_SERVER_NAME } from './chunk-DIB2WLBL.js';
6
- import { installStarterPack } from './chunk-V7SAQ645.js';
7
- import { loadTemplateFiles, loadMaintainedFiles, skillDir } from './chunk-5OCIHFGE.js';
3
+ import { runEmit } from './chunk-WX2WEERU.js';
4
+ import { installStarterPack } from './chunk-VJBFQP3H.js';
5
+ import { resolveGitCommonDir, defaultGitRunner } from './chunk-XGPC3IOR.js';
6
+ import { addStdioMcpEntryIfAbsent, addDocsMcpEntryIfAbsent, DOCS_MCP_SERVER_NAME } from './chunk-YVZJ6GKF.js';
8
7
  import { C } from './chunk-ANPNT6PM.js';
8
+ import { AGENTS_MD_LAYOUT, declareAgentsMdLayout, linkClaudeSkills, SKILLS_LINK_PATH, describeSkillsLink, isAgentsMdLayout, holdsTodaysLayoutSources, discoverOuterlayerPaths } from './chunk-JKNYTNYD.js';
9
+ import { loadTemplateFiles, loadMaintainedFiles, skillDir, AGENTS_SKILLS_BASE } from './chunk-HBISTTG3.js';
9
10
  import { cliInvocation } from './chunk-CRB3POP4.js';
11
+ import { linkedAgentsPath } from './chunk-VWFOKRYS.js';
10
12
  import { cloneIsGoverned } from './chunk-YQR6E6OV.js';
11
- import { generatedHeaderSource } from './chunk-WFSUUUAN.js';
13
+ import { generatedHeaderSource } from './chunk-RKOTJQVG.js';
12
14
  import { execFileSync } from 'child_process';
13
15
  import { existsSync, mkdirSync, writeFileSync } from 'fs';
14
16
  import { join, dirname } from 'path';
@@ -19,6 +21,18 @@ var MCP_OUTPUT_PATH = ".mcp.json";
19
21
  var POLICY_PATH = ".outerlayer/policy.yaml";
20
22
  var DEFAULT_CONFIG = `${JSON.stringify({ targets: ["claude-code"] }, null, 2)}
21
23
  `;
24
+ var AGENTS_MD_CONFIG = `${JSON.stringify({ targets: ["claude-code"], layout: AGENTS_MD_LAYOUT }, null, 2)}
25
+ `;
26
+ var STARTER_AGENTS_MD = `# Agent instructions
27
+
28
+ Write here what an agent needs to work in this repository: how to build and test it, the rules it follows, and what to check before it opens a pull request.
29
+
30
+ Claude Code and Codex read this file as it is. Skills are in \`.agents/skills/\`.
31
+ `;
32
+ function inTodaysLayout(repoRoot) {
33
+ if (isAgentsMdLayout(repoRoot)) return false;
34
+ return existsSync(join(repoRoot, CONFIG_PATH)) || holdsTodaysLayoutSources(discoverOuterlayerPaths(repoRoot));
35
+ }
22
36
  var errorMessage = (err) => err instanceof Error ? err.message : String(err);
23
37
  var skipped = (reason) => ({
24
38
  outcome: "skipped",
@@ -75,6 +89,7 @@ function runAgentSetup(opts) {
75
89
  } catch (err) {
76
90
  return failed(errorMessage(err), /* @__PURE__ */ new Set(), []);
77
91
  }
92
+ if (!inTodaysLayout(repoRoot)) return runAgentsMdSetup(repoRoot, opts.skillsLink !== false);
78
93
  const written = /* @__PURE__ */ new Set();
79
94
  const kept = [];
80
95
  const problems = [];
@@ -142,6 +157,71 @@ function runAgentSetup(opts) {
142
157
  kept: keptPaths
143
158
  };
144
159
  }
160
+ function runAgentsMdSetup(repoRoot, skillsLink) {
161
+ const written = /* @__PURE__ */ new Set();
162
+ const kept = [];
163
+ const problems = [];
164
+ const linked = linkedAgentsPath(repoRoot);
165
+ if (linked !== void 0) return failed(`${linked} is a link, and a write there would land outside the repository; replace it with a folder and run this again`, written, kept);
166
+ try {
167
+ const pack = installStarterPack({ repoRoot, base: AGENTS_SKILLS_BASE });
168
+ for (const file of loadTemplateFiles(void 0, void 0, AGENTS_SKILLS_BASE).filter((f) => pack.copied.includes(f.skill))) written.add(file.path);
169
+ for (const path of pack.maintained) written.add(path);
170
+ for (const skill of pack.kept) kept.push(`${skillDir(skill, AGENTS_SKILLS_BASE)}/`);
171
+ if (pack.policy === "written") written.add(POLICY_PATH);
172
+ else kept.push(POLICY_PATH);
173
+ for (const path of pack.validatorsWritten) written.add(path);
174
+ kept.push(...pack.validatorsKept);
175
+ if (existsSync(join(repoRoot, "AGENTS.md")) || existsSync(join(repoRoot, "CLAUDE.md"))) {
176
+ kept.push(existsSync(join(repoRoot, "AGENTS.md")) ? "AGENTS.md" : "CLAUDE.md");
177
+ } else {
178
+ writeFileSync(join(repoRoot, "AGENTS.md"), STARTER_AGENTS_MD);
179
+ written.add("AGENTS.md");
180
+ }
181
+ if (existsSync(join(repoRoot, CONFIG_PATH))) {
182
+ kept.push(CONFIG_PATH);
183
+ } else {
184
+ mkdirSync(dirname(join(repoRoot, CONFIG_PATH)), { recursive: true });
185
+ writeFileSync(join(repoRoot, CONFIG_PATH), AGENTS_MD_CONFIG);
186
+ written.add(CONFIG_PATH);
187
+ }
188
+ declareAgentsMdLayout(repoRoot);
189
+ } catch (err) {
190
+ return failed(`could not install the skills: ${errorMessage(err)}`, written, kept);
191
+ }
192
+ try {
193
+ const mcp = addStdioMcpEntryIfAbsent(repoRoot);
194
+ if (mcp.added) written.add(mcp.path);
195
+ else kept.push(`${mcp.path} (already has an outerlayer server)`);
196
+ const docs = addDocsMcpEntryIfAbsent(repoRoot);
197
+ if (docs.added) written.add(docs.path);
198
+ else kept.push(`${docs.path} (already has an ${DOCS_MCP_SERVER_NAME} server)`);
199
+ } catch (err) {
200
+ problems.push(errorMessage(err));
201
+ }
202
+ let linkNote = "";
203
+ if (skillsLink) {
204
+ const link = linkClaudeSkills(repoRoot);
205
+ if (link.status === "linked") written.add(SKILLS_LINK_PATH);
206
+ linkNote = describeSkillsLink(link);
207
+ }
208
+ if (problems.length > 0) return failed(problems.join("; "), written, kept);
209
+ const paths = [...written].sort();
210
+ const lines = [
211
+ `${C.green}\u2713${C.reset} Agent setup: ${paths.length === 0 ? "already in place, nothing changed" : "instructions in AGENTS.md, skills in .agents/skills/"}`,
212
+ renderPaths(paths, kept).trimEnd()
213
+ ];
214
+ if (linkNote !== "") lines.push(` ${linkNote}`);
215
+ if (paths.length > 0) lines.push(` ${C.dim}Commit AGENTS.md, .agents/ and .mcp.json with .outerlayer/. Nothing is generated, so there is no emit step.${C.reset}`);
216
+ return {
217
+ outcome: "done",
218
+ reason: paths.length === 0 ? "already set up" : `${paths.length} files written`,
219
+ text: `${lines.join("\n")}
220
+ `,
221
+ paths,
222
+ kept: []
223
+ };
224
+ }
145
225
  function writtenBeforeFailure(repoRoot, pending, keep) {
146
226
  if (pending === void 0 || pending.length === 0) return [];
147
227
  try {
@@ -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-JRCSET55.js';
4
- import { resolveGatewayCredentials } from './chunk-NTRCK4NH.js';
3
+ import { fetchFactories, selectFactory, saveFactoryConnection, autoConnectedLine } from './chunk-GXV73IIS.js';
4
+ import { resolveGatewayCredentials } from './chunk-QS43O4DR.js';
5
5
  import { findGitDirs, readRepoConnection } from './chunk-BJ3KTMDH.js';
6
- import { resolveRepoIdentity } from './chunk-AEKSX4EY.js';
6
+ import { resolveRepoIdentity } from './chunk-CBCKD6DO.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';
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
- import { sharedSkillNames } from './chunk-ZNPE7FW5.js';
3
+ import { sharedSkillNames } from './chunk-VPEGE3QZ.js';
4
4
  import { GOVERNANCE_VARIABLE, versionAtLeast, MINIMUM_CLAUDE_VERSION, SHIM_SCRIPT, CONTROL_PLANE_DIR_VARIABLE } from './chunk-HCVLP7XA.js';
5
5
  export { MINIMUM_CLAUDE_VERSION } from './chunk-HCVLP7XA.js';
6
6
  import { findGitDirs } from './chunk-BJ3KTMDH.js';
7
- import './chunk-5OCIHFGE.js';
8
- import './chunk-WFSUUUAN.js';
9
- import './chunk-7VUK5RFS.js';
7
+ import './chunk-HBISTTG3.js';
8
+ import './chunk-RKOTJQVG.js';
9
+ import './chunk-QZBXLLTV.js';
10
10
  import { homeFromEnv } from './chunk-VNVZDWO3.js';
11
11
  import './chunk-RA3O54FC.js';
12
12
  import './chunk-Z5GEFMRW.js';
@@ -236,7 +236,7 @@ async function runClaudeLauncher(args, deps = {}) {
236
236
  return 1;
237
237
  }
238
238
  } else {
239
- const { resolveLaunchPlane } = await import('./control-plane-launch-OWSNH6YA.js');
239
+ const { resolveLaunchPlane } = await import('./control-plane-launch-SEYCOZFH.js');
240
240
  const plane = env[GOVERNANCE_VARIABLE] === "self" ? { kind: "none" } : await resolveLaunchPlane({ cwd, env, home, fetchImpl: deps.fetchImpl, stderr });
241
241
  if (plane.kind === "none") {
242
242
  const own2 = ownSkillsDirFor(cwd, home, [], stderr);