@outerlayer/cli 0.22.2 → 0.24.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.
- package/CHANGELOG.md +21 -0
- package/README.md +4 -0
- package/dist/agent-setup-QQYRBPK2.js +30 -0
- package/dist/{artifact-link-cmd-OWRI5AJX.js → artifact-link-cmd-LEI6EOZE.js} +2 -2
- package/dist/{bridge-QFN3KJP6.js → bridge-4ZARDVGS.js} +2 -2
- package/dist/{build-6WRNZPVR.js → build-OVZIT2G2.js} +5 -5
- package/dist/build-info.json +1 -1
- package/dist/{builder-G3MLDMTI.js → builder-MECDEKXX.js} +6 -6
- package/dist/{check-N6WLZCER.js → check-YYKNYFNI.js} +46 -44
- package/dist/{chunk-IPS2JCHK.js → chunk-5ECUMU53.js} +7 -7
- package/dist/{chunk-XR56WEA5.js → chunk-5XCAPBE2.js} +4 -4
- package/dist/{chunk-KOIMUHIS.js → chunk-6GSA2SKT.js} +20 -20
- package/dist/{chunk-HWZCE745.js → chunk-755WXDBI.js} +2 -2
- package/dist/{chunk-SFHR45FA.js → chunk-A62QFN2M.js} +3 -3
- package/dist/{chunk-URWYRAIC.js → chunk-BN3CSI7S.js} +0 -2
- package/dist/{chunk-ZCXP35T3.js → chunk-BOQY756V.js} +9 -8
- package/dist/{chunk-BVR6MQLS.js → chunk-BUBCPP3F.js} +3 -3
- package/dist/{chunk-G3IJ3N6F.js → chunk-BUP5N3X6.js} +1 -1
- package/dist/{chunk-WXJXHZVB.js → chunk-CZUH2SLQ.js} +1 -1
- package/dist/{chunk-AEKSX4EY.js → chunk-D4AMAEZ7.js} +13 -12
- package/dist/{chunk-U6RKHNC7.js → chunk-D7K446H6.js} +8 -8
- package/dist/{chunk-V5CG75NX.js → chunk-D7X5ITVT.js} +1 -1
- package/dist/{chunk-OBCFK4QD.js → chunk-DG2ULWM6.js} +2 -2
- package/dist/{chunk-SNVXHNU7.js → chunk-E4OUL7ZP.js} +5 -5
- package/dist/{chunk-B42BIYC6.js → chunk-F2W2IYNP.js} +3 -3
- package/dist/{chunk-JD6GWYY7.js → chunk-F7Y2USIM.js} +5 -5
- package/dist/{chunk-QS43O4DR.js → chunk-FKXGQOF5.js} +1 -1
- package/dist/{chunk-JV4YGAAW.js → chunk-FQPN5S4Q.js} +4 -4
- package/dist/{chunk-XACXXKQ5.js → chunk-FWEWFW3F.js} +1 -1
- package/dist/{chunk-WKSBSEWT.js → chunk-GU4PKXN7.js} +13 -13
- package/dist/{chunk-2CPOAPU4.js → chunk-H6IUKXXI.js} +90 -24
- package/dist/{chunk-5OCIHFGE.js → chunk-HBISTTG3.js} +32 -23
- package/dist/{chunk-EFB3FGLC.js → chunk-HHXBOTRO.js} +1 -1
- package/dist/chunk-IDSHLKQA.js +66 -0
- package/dist/chunk-JKNYTNYD.js +151 -0
- package/dist/{chunk-IHNQWF6F.js → chunk-KF37SUDM.js} +1 -1
- package/dist/{chunk-4AVDD7VX.js → chunk-LBCZXXOX.js} +2 -2
- package/dist/{chunk-NYTZ7HVN.js → chunk-LY2L3O2O.js} +1 -1
- package/dist/{chunk-USWVXQIH.js → chunk-MQ743JX3.js} +3 -3
- package/dist/{chunk-CQAEV3Z5.js → chunk-NGZID7UI.js} +1 -1
- package/dist/{chunk-UF5L4BAI.js → chunk-NTQTDCYR.js} +1 -1
- package/dist/{chunk-2Q3PZ42G.js → chunk-PDIM5T65.js} +1 -1
- package/dist/{chunk-OW52QLK3.js → chunk-PVRBE7S4.js} +1 -1
- package/dist/{chunk-7VUK5RFS.js → chunk-QZBXLLTV.js} +36 -1
- package/dist/{chunk-WFSUUUAN.js → chunk-RKOTJQVG.js} +1 -1
- package/dist/{chunk-FQE5RDHI.js → chunk-RVYOOYOA.js} +7 -7
- package/dist/{chunk-IMCVQF5F.js → chunk-TQ6Y7YV6.js} +6 -6
- package/dist/{chunk-I2UOAV7X.js → chunk-TQMI335S.js} +4 -1
- package/dist/{chunk-3AZYLAJC.js → chunk-TTLVQZSH.js} +4 -4
- package/dist/{chunk-EMUNEAQK.js → chunk-V5Q3S4NM.js} +19 -7
- package/dist/{chunk-FVDVC2GF.js → chunk-VBEXKEBV.js} +1 -1
- package/dist/{chunk-V7SAQ645.js → chunk-VJBFQP3H.js} +21 -12
- package/dist/{chunk-ZNPE7FW5.js → chunk-VPEGE3QZ.js} +1 -1
- package/dist/{chunk-276D7BJ7.js → chunk-VV7ZD5LR.js} +1 -1
- package/dist/{chunk-W3SWJ2TD.js → chunk-VWFOKRYS.js} +5 -2
- package/dist/{chunk-4542B3RR.js → chunk-W7O4LA4E.js} +3 -3
- package/dist/{chunk-4OYKJJ2V.js → chunk-WH2QV3UL.js} +86 -6
- package/dist/{chunk-XCRZTXRL.js → chunk-WX2WEERU.js} +63 -43
- package/dist/{chunk-VSUXCMMH.js → chunk-XFGL53GU.js} +51 -33
- package/dist/{chunk-EAQSOE62.js → chunk-XSPA5ODY.js} +21 -19
- package/dist/{chunk-QZX6DAAW.js → chunk-ZFLOFAUG.js} +11 -11
- package/dist/{claude-launcher-QD3C427Y.js → claude-launcher-JCPSHDZQ.js} +5 -5
- package/dist/{cli-A2Y67WAB.js → cli-ZTBH3FBG.js} +173 -137
- package/dist/{command-Q5Q2EIO4.js → command-DO4TERRT.js} +34 -33
- package/dist/{config-H4QS332G.js → config-7Z5DHSGY.js} +2 -2
- package/dist/connect-cmd-NY5LIKVC.js +25 -0
- package/dist/container-start-OHBUZEJJ.js +170 -0
- package/dist/{context-cleanup-DSA3HGQU.js → context-cleanup-LTH77FC3.js} +3 -3
- package/dist/{control-plane-launch-HE6OSWKO.js → control-plane-launch-GKGI6HJA.js} +11 -11
- package/dist/{dist-7IH56ELA.js → dist-2APO44JG.js} +2 -2
- package/dist/{docker-JU422JL7.js → docker-RKGBJESN.js} +6 -6
- package/dist/{doctor-BRN4BGMA.js → doctor-DOAFZV4O.js} +47 -34
- package/dist/{emit-artifact-cmd-GPAJCCUC.js → emit-artifact-cmd-VZHIDPXQ.js} +18 -15
- package/dist/emit-cmd-WQH2NK7H.js +15 -0
- package/dist/{emit-criteria-cmd-R3FKHSQG.js → emit-criteria-cmd-SYLBCWHW.js} +15 -12
- package/dist/{emit-finding-cmd-IK7RAVP5.js → emit-finding-cmd-52M43NPC.js} +15 -12
- package/dist/{emit-result-cmd-5FJTF7YD.js → emit-result-cmd-BTMTGDAV.js} +18 -15
- package/dist/{emit-step-cmd-VRTD5YPP.js → emit-step-cmd-6XTJITZT.js} +16 -13
- package/dist/{exec-client-ATPF2DDB.js → exec-client-CKPK62K2.js} +3 -3
- package/dist/governing-source-GWN7GVEN.js +35 -0
- package/dist/{guest-init-2OZ4YC7R.js → guest-init-ZBL5CN7Y.js} +4 -4
- package/dist/{hook-fast-QUGEI2IT.js → hook-fast-3JL4PXLG.js} +1 -1
- package/dist/{host-key-ATB23GI3.js → host-key-W2DLZGZ7.js} +3 -3
- package/dist/image-tag-AO4RBAKW.js +10 -0
- package/dist/{import-capture-cmd-Q56DDZVO.js → import-capture-cmd-TCOKNVBM.js} +12 -7
- package/dist/{import-ruler-cmd-T6LLO6Q7.js → import-ruler-cmd-VJOHOJQ7.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{init-X7FCQDFX.js → init-EQTR7AEF.js} +32 -31
- package/dist/init-TSQ3EOQW.js +52 -0
- package/dist/{init-cmd-VCKH2DUQ.js → init-cmd-AF2MH36A.js} +24 -23
- package/dist/init-update-SHISHMXV.js +555 -0
- package/dist/{install-SFACZU7E.js → install-ORQC26ZE.js} +4 -4
- package/dist/{install-cmd-6HTP7I43.js → install-cmd-4LA3UJZ4.js} +6 -6
- package/dist/layout-UOJQGEPW.js +10 -0
- package/dist/{login-browser-BN5UKPHS.js → login-browser-4OMZFP3U.js} +4 -3
- package/dist/{logout-cmd-RZFWTNYD.js → logout-cmd-5V5MMBSY.js} +2 -2
- package/dist/{logs-N3ZX7HFV.js → logs-5EPHIPZB.js} +2 -2
- package/dist/loop-4WUCS5JP.js +77 -0
- package/dist/machine-6UNLIPLE.js +47 -0
- package/dist/{mcp-install-cmd-GD4QUP7Z.js → mcp-install-cmd-GGWB3JJ2.js} +2 -2
- package/dist/{mcp-serve-cmd-TQSPFRC7.js → mcp-serve-cmd-KMWEKM7C.js} +5 -5
- package/dist/{paths-AKX2OOLF.js → paths-XY5ADO32.js} +2 -2
- package/dist/{pending-7SGWZCEH.js → pending-35J3ZPLR.js} +3 -3
- package/dist/{pidfile-G2J5WBQS.js → pidfile-OJ7RP4Q2.js} +3 -3
- package/dist/{record-Q4IEYIVV.js → record-BEJB4J7N.js} +3 -3
- package/dist/{runner-env-GZHXM27A.js → runner-env-ZJWJOJKQ.js} +5 -5
- package/dist/{runner-identity-FTHZFMGY.js → runner-identity-2OOUJSFJ.js} +6 -6
- package/dist/{runner-key-O42EUXQU.js → runner-key-WDFBSJRX.js} +32 -31
- package/dist/{session-sender-HF6DXFA2.js → session-sender-X3BBQZMF.js} +19 -16
- package/dist/{spec-cmd-ADPH236D.js → spec-cmd-QRF5YXKK.js} +16 -13
- package/dist/{starter-pack-5EQYGSJF.js → starter-pack-55EFILC5.js} +7 -4
- package/dist/{status-LXFIVGP3.js → status-ZCAAF6MD.js} +43 -34
- package/dist/{sync-cmd-5XS3CUV5.js → sync-cmd-UQK3RYAC.js} +18 -15
- package/dist/{watch-FBZHZV56.js → watch-MOQ3GQTE.js} +18 -15
- package/dist/{work-claim-cmd-LIIINECF.js → work-claim-cmd-RT343CLA.js} +19 -16
- package/dist/{work-cmd-SM6DY2WK.js → work-cmd-APXSER2D.js} +16 -13
- package/dist/{work-comment-cmd-VYVXGT4W.js → work-comment-cmd-AT5NUYUU.js} +16 -13
- package/dist/{work-logs-cmd-XZSCWWMW.js → work-logs-cmd-Z5DMNEJP.js} +16 -13
- package/dist/{work-open-pr-cmd-YZNC3P3R.js → work-open-pr-cmd-ZTS6MJHL.js} +17 -14
- package/dist/{work-pr-cmd-AMN23KFJ.js → work-pr-cmd-IWZCC3WH.js} +16 -13
- package/dist/{work-stop-cmd-HSR2GOJJ.js → work-stop-cmd-DCAWFDZC.js} +16 -13
- package/package.json +1 -1
- package/skill-pack/maintained/outerlayer-build/references/agent-briefs.md +7 -1
- package/skill-pack/maintained/outerlayer-build/references/criteria-judge.md +10 -0
- package/skill-pack/maintained/outerlayer-build/references/review-briefs.md +4 -0
- package/skill-pack/maintained/outerlayer-cli/SKILL.md +5 -3
- package/dist/agent-setup-KXPDPTAJ.js +0 -27
- package/dist/connect-cmd-TNGEIWCA.js +0 -22
- package/dist/emit-cmd-3W5IO5ET.js +0 -14
- package/dist/governing-source-WM736XR4.js +0 -34
- package/dist/init-U3I43XCP.js +0 -51
- package/dist/init-update-TCMH7M3Q.js +0 -210
- package/dist/loop-P3QDQOE5.js +0 -75
- package/dist/machine-EEFOW32K.js +0 -46
- package/dist/{chunk-F35VMF5M.js → chunk-GOSFARMS.js} +1 -1
- package/dist/{chunk-DIB2WLBL.js → chunk-YVZJ6GKF.js} +1 -1
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { runEmit } from './chunk-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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-E4OUL7ZP.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-
|
|
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,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { retiredSkillPaths, removeRetiredSkills } from './chunk-
|
|
4
|
-
import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-5OCIHFGE.js';
|
|
3
|
+
import { retiredSkillPaths, removeRetiredSkills } from './chunk-MQ743JX3.js';
|
|
5
4
|
import { C } from './chunk-ANPNT6PM.js';
|
|
5
|
+
import { isAgentsMdLayout, discoverOuterlayerPaths, isForeignTree, toRepoRelative } from './chunk-JKNYTNYD.js';
|
|
6
|
+
import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-HBISTTG3.js';
|
|
6
7
|
import { cliInvocation } from './chunk-CRB3POP4.js';
|
|
7
|
-
import { emitTree,
|
|
8
|
+
import { emitTree, generatedHeaderSource, parseOuterlayerConfig, classifyTree } from './chunk-RKOTJQVG.js';
|
|
8
9
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, unlinkSync, rmdirSync, readdirSync } from 'fs';
|
|
9
|
-
import { join, dirname
|
|
10
|
+
import { join, dirname } from 'path';
|
|
10
11
|
|
|
11
12
|
createRequire(import.meta.url);
|
|
12
13
|
var CONTENT_KINDS = /* @__PURE__ */ new Set(["instructions", "skill", "skill-reference", "command", "mcp"]);
|
|
@@ -14,6 +15,13 @@ var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
|
14
15
|
var NO_CONFIG_MESSAGE = 'no .outerlayer/config.json with a non-empty targets array \u2014 create one, e.g. {"targets": ["claude-code"]}';
|
|
15
16
|
var EmitError = class extends Error {
|
|
16
17
|
};
|
|
18
|
+
var EMIT_NOT_NEEDED_NOTICE = `Claude Code and Codex read AGENTS.md and .agents/skills/ without a generated copy. Run \`${cliInvocation()} init --update\` to move this repository there and stop committing generated files.`;
|
|
19
|
+
var NATIVE_TARGETS = /* @__PURE__ */ new Set(["claude-code", "codex"]);
|
|
20
|
+
function noticeFor(repoRoot, targets) {
|
|
21
|
+
if (targets.length === 0 || !targets.every((t) => NATIVE_TARGETS.has(t))) return void 0;
|
|
22
|
+
return isAgentsMdLayout(repoRoot) ? void 0 : EMIT_NOT_NEEDED_NOTICE;
|
|
23
|
+
}
|
|
24
|
+
var HAND_OWNED_OUTPUT = /(^|\/)(CLAUDE\.md|AGENTS\.md|\.claude\/skills\/|\.agents\/skills\/)/;
|
|
17
25
|
function resolveTargetsFromConfig(repoRoot) {
|
|
18
26
|
const configPath = join(repoRoot, ".outerlayer", "config.json");
|
|
19
27
|
if (!existsSync(configPath)) throw new EmitError(NO_CONFIG_MESSAGE);
|
|
@@ -24,36 +32,6 @@ function resolveTargetsFromConfig(repoRoot) {
|
|
|
24
32
|
const detail = result.errors.map((e) => `${e.path}: ${e.message}`).join("; ");
|
|
25
33
|
throw new EmitError(`invalid .outerlayer/config.json \u2014 ${detail}`);
|
|
26
34
|
}
|
|
27
|
-
function toRepoRelative(repoRoot, absPath) {
|
|
28
|
-
return normalizePath(relative(repoRoot, absPath).split(sep).join("/"));
|
|
29
|
-
}
|
|
30
|
-
function discoverOuterlayerPaths(repoRoot) {
|
|
31
|
-
const out = [];
|
|
32
|
-
walk(repoRoot, repoRoot, false, out);
|
|
33
|
-
return out.sort();
|
|
34
|
-
}
|
|
35
|
-
function isForeignTree(dir) {
|
|
36
|
-
return existsSync(join(dir, ".git")) || existsSync(join(dir, CONTEXT_PIN_FILENAME));
|
|
37
|
-
}
|
|
38
|
-
function walk(dir, repoRoot, insideOuterlayer, out) {
|
|
39
|
-
let entries;
|
|
40
|
-
try {
|
|
41
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
42
|
-
} catch {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
for (const entry of entries) {
|
|
46
|
-
if (entry.isSymbolicLink()) continue;
|
|
47
|
-
const full = join(dir, entry.name);
|
|
48
|
-
if (entry.isDirectory()) {
|
|
49
|
-
if (!insideOuterlayer && SKIP_DIRS.has(entry.name)) continue;
|
|
50
|
-
if (!insideOuterlayer && isForeignTree(full)) continue;
|
|
51
|
-
walk(full, repoRoot, insideOuterlayer || entry.name === ".outerlayer", out);
|
|
52
|
-
} else if (entry.isFile() && insideOuterlayer) {
|
|
53
|
-
out.push(toRepoRelative(repoRoot, full));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
35
|
function buildEmitInput(repoRoot, targets, maintained, excluded = /* @__PURE__ */ new Set()) {
|
|
58
36
|
const bundled = new Map(maintained.map((f) => [f.path, f.content]));
|
|
59
37
|
const discovered = [.../* @__PURE__ */ new Set([...discoverOuterlayerPaths(repoRoot).filter((p) => !excluded.has(p)), ...bundled.keys()])].sort();
|
|
@@ -143,10 +121,10 @@ function walkAll(dir, repoRoot, out) {
|
|
|
143
121
|
}
|
|
144
122
|
}
|
|
145
123
|
}
|
|
146
|
-
function findOrphans(repoRoot, computedFiles, sourcePaths) {
|
|
124
|
+
function findOrphans(repoRoot, computedFiles, sourcePaths, ignore) {
|
|
147
125
|
const orphans = [];
|
|
148
126
|
for (const path of discoverAllFiles(repoRoot)) {
|
|
149
|
-
if (computedFiles.has(path)) continue;
|
|
127
|
+
if (computedFiles.has(path) || ignore?.(path) === true) continue;
|
|
150
128
|
let content;
|
|
151
129
|
try {
|
|
152
130
|
content = readFileSync(join(repoRoot, path), "utf8");
|
|
@@ -200,17 +178,20 @@ function runEmit(opts = {}) {
|
|
|
200
178
|
const cwd = opts.cwd ?? process.cwd();
|
|
201
179
|
if (!existsSync(cwd)) throw new EmitError(`no such directory: ${cwd}`);
|
|
202
180
|
const targets = resolveTargetsFromConfig(cwd);
|
|
203
|
-
const
|
|
181
|
+
const agentsMd = isAgentsMdLayout(cwd);
|
|
182
|
+
const ignoreOrphan = agentsMd ? (path) => HAND_OWNED_OUTPUT.test(path) : void 0;
|
|
183
|
+
const maintained = agentsMd ? [] : maintainedFilesForExistingSkills(cwd, loadMaintainedFiles());
|
|
184
|
+
const notice = noticeFor(cwd, targets);
|
|
204
185
|
const retired = retiredSkillPaths(cwd);
|
|
205
186
|
const built = buildEmitInput(cwd, targets, maintained, new Set(retired));
|
|
206
187
|
const emitted = emitTree(built.input);
|
|
207
188
|
const { result, kept } = withholdKept(cwd, emitted, opts.keep);
|
|
208
189
|
const hasErrors = result.errors.length > 0;
|
|
209
190
|
const outputs = new Set(emitted.files.map((f) => f.path));
|
|
210
|
-
if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, outputs, built.sourcePaths, maintained, kept, retired);
|
|
191
|
+
if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, outputs, built.sourcePaths, maintained, kept, retired, notice, ignoreOrphan);
|
|
211
192
|
const written = hasErrors ? { files: [], copies: [], maintained: [] } : writeOutputs(cwd, result, maintained);
|
|
212
193
|
const removed = hasErrors ? [] : removeRetiredSkills(cwd);
|
|
213
|
-
const orphaned = hasErrors ? [] : removeOrphans(cwd, findOrphans(cwd, outputs, built.sourcePaths));
|
|
194
|
+
const orphaned = hasErrors ? [] : removeOrphans(cwd, findOrphans(cwd, outputs, built.sourcePaths, ignoreOrphan));
|
|
214
195
|
const exitCode = hasErrors ? 1 : 0;
|
|
215
196
|
const output = opts.json ? JSON.stringify({
|
|
216
197
|
targets,
|
|
@@ -232,8 +213,11 @@ function runEmit(opts = {}) {
|
|
|
232
213
|
for (const w of result.warnings) process.stderr.write(` ${C.yellow}!${C.reset} ${w.path}: ${w.message}
|
|
233
214
|
`);
|
|
234
215
|
}
|
|
216
|
+
if (notice !== void 0 && !opts.json) process.stderr.write(`${C.dim}${notice}${C.reset}
|
|
217
|
+
`);
|
|
235
218
|
}
|
|
236
219
|
return {
|
|
220
|
+
...notice === void 0 ? {} : { notice },
|
|
237
221
|
targets,
|
|
238
222
|
files: written.files,
|
|
239
223
|
copies: written.copies,
|
|
@@ -247,7 +231,7 @@ function runEmit(opts = {}) {
|
|
|
247
231
|
exitCode
|
|
248
232
|
};
|
|
249
233
|
}
|
|
250
|
-
function runCheck(cwd, opts, targets, result, hasErrors, outputs, sourcePaths, maintained, kept, retired) {
|
|
234
|
+
function runCheck(cwd, opts, targets, result, hasErrors, outputs, sourcePaths, maintained, kept, retired, notice, ignoreOrphan) {
|
|
251
235
|
const drift = [];
|
|
252
236
|
if (!hasErrors) {
|
|
253
237
|
for (const path of retired) drift.push({ kind: "retired", path });
|
|
@@ -264,7 +248,7 @@ function runCheck(cwd, opts, targets, result, hasErrors, outputs, sourcePaths, m
|
|
|
264
248
|
if (d) drift.push(d);
|
|
265
249
|
}
|
|
266
250
|
const retiredPaths = new Set(retired);
|
|
267
|
-
drift.push(...findOrphans(cwd, outputs, sourcePaths).filter((d) => !retiredPaths.has(d.path)));
|
|
251
|
+
drift.push(...findOrphans(cwd, outputs, sourcePaths, ignoreOrphan).filter((d) => !retiredPaths.has(d.path)));
|
|
268
252
|
drift.sort((a, b) => a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind));
|
|
269
253
|
}
|
|
270
254
|
const exitCode = hasErrors || drift.length > 0 ? 1 : 0;
|
|
@@ -279,8 +263,44 @@ function runCheck(cwd, opts, targets, result, hasErrors, outputs, sourcePaths, m
|
|
|
279
263
|
for (const w of result.warnings) process.stderr.write(` ${C.yellow}!${C.reset} ${w.path}: ${w.message}
|
|
280
264
|
`);
|
|
281
265
|
}
|
|
266
|
+
if (notice !== void 0 && !opts.json) process.stderr.write(`${C.dim}${notice}${C.reset}
|
|
267
|
+
`);
|
|
268
|
+
}
|
|
269
|
+
return { ...notice === void 0 ? {} : { notice }, targets, files: [], copies: [], maintained: [], kept, retired: [], orphaned: [], warnings: result.warnings, errors: result.errors, drift, output, exitCode };
|
|
270
|
+
}
|
|
271
|
+
var REPLACED_OUTPUT = /^(?:(?:.*\/)?(?:CLAUDE|AGENTS)\.md|(?:.*\/)?\.(?:claude|agents)\/skills\/.+)$/;
|
|
272
|
+
function inspectReplacedOutputs(repoRoot) {
|
|
273
|
+
let configured = [];
|
|
274
|
+
try {
|
|
275
|
+
configured = resolveTargetsFromConfig(repoRoot);
|
|
276
|
+
} catch {
|
|
277
|
+
}
|
|
278
|
+
const targets = [.../* @__PURE__ */ new Set([...configured, "claude-code", "codex"])];
|
|
279
|
+
const maintained = maintainedFilesForExistingSkills(repoRoot, loadMaintainedFiles());
|
|
280
|
+
const maintainedPaths = new Set(maintained.map((f) => f.path));
|
|
281
|
+
const built = buildEmitInput(repoRoot, targets, maintained, new Set(retiredSkillPaths(repoRoot)));
|
|
282
|
+
const emitted = emitTree(built.input);
|
|
283
|
+
const generated = [];
|
|
284
|
+
const edited = [];
|
|
285
|
+
const replacedDiffering = [];
|
|
286
|
+
const classify = (path, same) => {
|
|
287
|
+
(same ? generated : edited).push(path);
|
|
288
|
+
};
|
|
289
|
+
for (const file of emitted.files) {
|
|
290
|
+
if (!REPLACED_OUTPUT.test(file.path) || !existsSync(join(repoRoot, file.path))) continue;
|
|
291
|
+
const disk = readFileSync(join(repoRoot, file.path), "utf8");
|
|
292
|
+
const source = generatedHeaderSource(disk);
|
|
293
|
+
const stale = source !== null && maintainedPaths.has(source);
|
|
294
|
+
const same = stale ? true : disk === file.content;
|
|
295
|
+
if (stale && disk !== file.content) replacedDiffering.push(file.path);
|
|
296
|
+
classify(file.path, same);
|
|
297
|
+
}
|
|
298
|
+
for (const copy of emitted.copies) {
|
|
299
|
+
if (!REPLACED_OUTPUT.test(copy.toPath) || !existsSync(join(repoRoot, copy.toPath))) continue;
|
|
300
|
+
const source = join(repoRoot, copy.fromSourcePath);
|
|
301
|
+
classify(copy.toPath, existsSync(source) && readFileSync(join(repoRoot, copy.toPath)).equals(readFileSync(source)));
|
|
282
302
|
}
|
|
283
|
-
return {
|
|
303
|
+
return { generated: generated.sort(), edited: edited.sort(), replacedDiffering: replacedDiffering.sort() };
|
|
284
304
|
}
|
|
285
305
|
|
|
286
|
-
export { EmitError, runEmit };
|
|
306
|
+
export { EMIT_NOT_NEEDED_NOTICE, EmitError, inspectReplacedOutputs, runEmit };
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
+
import { POLICY_CONTENT, VALIDATOR_FILES, VALIDATORS_DIR, POLICY_PATH } from './chunk-VJBFQP3H.js';
|
|
3
4
|
import { findGitDirs } from './chunk-BJ3KTMDH.js';
|
|
4
|
-
import { mcpTargetPath, INIT_STDIO_ENTRY, INIT_DOCS_ENTRY, DOCS_MCP_SERVER_NAME } from './chunk-
|
|
5
|
-
import {
|
|
6
|
-
import { resolvePackRoot, skillDir, namesCore, loadTemplateFiles, TEMPLATE_SKILLS } from './chunk-
|
|
5
|
+
import { mcpTargetPath, INIT_STDIO_ENTRY, INIT_DOCS_ENTRY, DOCS_MCP_SERVER_NAME } from './chunk-YVZJ6GKF.js';
|
|
6
|
+
import { skillsBaseFor, isAgentsMdLayout } from './chunk-JKNYTNYD.js';
|
|
7
|
+
import { resolvePackRoot, OUTERLAYER_SKILLS_BASE, skillDir, namesCore, loadTemplateFiles, rewriteSkillPaths, restoreSkillPaths, TEMPLATE_SKILLS } from './chunk-HBISTTG3.js';
|
|
7
8
|
import { cliInvocation } from './chunk-CRB3POP4.js';
|
|
8
|
-
import { hasSymlinkComponent } from './chunk-
|
|
9
|
+
import { hasSymlinkComponent } from './chunk-VWFOKRYS.js';
|
|
9
10
|
import { cloneIsGoverned } from './chunk-YQR6E6OV.js';
|
|
10
|
-
import { emitTree, ALL_TARGET_IDS, classifyTree, splitRawFile } from './chunk-
|
|
11
|
+
import { emitTree, ALL_TARGET_IDS, classifyTree, splitRawFile } from './chunk-RKOTJQVG.js';
|
|
11
12
|
import { createHash } from 'crypto';
|
|
12
|
-
import { existsSync, readFileSync } from 'fs';
|
|
13
|
+
import { existsSync, readFileSync, realpathSync } from 'fs';
|
|
13
14
|
import { join, dirname } from 'path';
|
|
14
15
|
|
|
15
16
|
createRequire(import.meta.url);
|
|
16
17
|
var SHIPPED_MANIFEST = "shipped.json";
|
|
17
|
-
function currentStarterFiles(packRoot = resolvePackRoot(), policy = POLICY_CONTENT) {
|
|
18
|
-
const templates = loadTemplateFiles(packRoot).map((f) => ({
|
|
18
|
+
function currentStarterFiles(packRoot = resolvePackRoot(), policy = POLICY_CONTENT, base = OUTERLAYER_SKILLS_BASE) {
|
|
19
|
+
const templates = loadTemplateFiles(packRoot, void 0, base).map((f) => ({
|
|
19
20
|
path: f.path,
|
|
20
21
|
content: f.content,
|
|
21
22
|
skill: f.skill,
|
|
22
|
-
source: join(packRoot, "template", f.skill, f.path.slice(skillDir(f.skill).length + 1))
|
|
23
|
+
source: join(packRoot, "template", f.skill, f.path.slice(skillDir(f.skill, base).length + 1))
|
|
23
24
|
}));
|
|
24
25
|
const validators = VALIDATOR_FILES.map(({ name }) => {
|
|
25
26
|
const source = join(packRoot, "validators", name);
|
|
26
|
-
return { path: `${VALIDATORS_DIR}/${name}`, content: readFileSync(source, "utf8"), source };
|
|
27
|
+
return { path: `${VALIDATORS_DIR}/${name}`, content: rewriteSkillPaths(readFileSync(source, "utf8"), base), source };
|
|
27
28
|
});
|
|
28
29
|
return [...templates, ...validators, { path: POLICY_PATH, content: policy }];
|
|
29
30
|
}
|
|
@@ -66,12 +67,17 @@ function canonical(value) {
|
|
|
66
67
|
}
|
|
67
68
|
return JSON.stringify(value);
|
|
68
69
|
}
|
|
69
|
-
function
|
|
70
|
+
function shippedPath(path, base) {
|
|
71
|
+
return path.startsWith(`${base}/`) ? `${OUTERLAYER_SKILLS_BASE}/${path.slice(base.length + 1)}` : path;
|
|
72
|
+
}
|
|
73
|
+
function fileState(root, file, manifest, base) {
|
|
70
74
|
const abs = join(root, file.path);
|
|
71
75
|
if (!existsSync(abs)) return "missing";
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
|
|
76
|
+
const disk = readFileSync(abs, "utf8");
|
|
77
|
+
if (contentHash(disk) === contentHash(file.content)) return "current";
|
|
78
|
+
const hash = contentHash(restoreSkillPaths(disk, base));
|
|
79
|
+
if (hash === contentHash(restoreSkillPaths(file.content, base))) return "outdated";
|
|
80
|
+
if (manifest.ok && manifest.files.get(shippedPath(file.path, base))?.has(hash) === true) return "outdated";
|
|
75
81
|
return "edited";
|
|
76
82
|
}
|
|
77
83
|
function mcpItems(root) {
|
|
@@ -98,17 +104,18 @@ function mcpItems(root) {
|
|
|
98
104
|
return { ...base, state: "edited" };
|
|
99
105
|
});
|
|
100
106
|
}
|
|
101
|
-
function retiredFiles(root, shipped, manifest) {
|
|
107
|
+
function retiredFiles(root, shipped, manifest, base) {
|
|
102
108
|
if (!manifest.ok) return [];
|
|
103
|
-
const current = new Set(shipped.map((f) => f.path));
|
|
109
|
+
const current = new Set(shipped.map((f) => shippedPath(f.path, base)));
|
|
104
110
|
const prefixes = TEMPLATE_SKILLS.map((skill) => `${skillDir(skill)}/`);
|
|
105
111
|
const retired = [];
|
|
106
|
-
for (const [
|
|
107
|
-
if (current.has(
|
|
112
|
+
for (const [known, hashes] of manifest.files) {
|
|
113
|
+
if (current.has(known) || !prefixes.some((prefix) => known.startsWith(prefix))) continue;
|
|
114
|
+
const path = base === OUTERLAYER_SKILLS_BASE ? known : `${base}/${known.slice(OUTERLAYER_SKILLS_BASE.length + 1)}`;
|
|
108
115
|
const abs = join(root, path);
|
|
109
116
|
if (!existsSync(abs) || hasSymlinkComponent(root, path)) continue;
|
|
110
117
|
try {
|
|
111
|
-
retired.push({ path, state: hashes.has(contentHash(readFileSync(abs, "utf8"))) ? "unedited" : "edited" });
|
|
118
|
+
retired.push({ path, state: hashes.has(contentHash(restoreSkillPaths(readFileSync(abs, "utf8"), base))) ? "unedited" : "edited" });
|
|
112
119
|
} catch {
|
|
113
120
|
}
|
|
114
121
|
}
|
|
@@ -116,13 +123,14 @@ function retiredFiles(root, shipped, manifest) {
|
|
|
116
123
|
}
|
|
117
124
|
function inspectStarterFiles(root, opts = {}) {
|
|
118
125
|
const packRoot = opts.packRoot ?? resolvePackRoot();
|
|
126
|
+
const base = opts.base ?? skillsBaseFor(root);
|
|
119
127
|
const manifest = readShippedManifest(packRoot);
|
|
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 };
|
|
128
|
+
const shipped = currentStarterFiles(packRoot, void 0, base);
|
|
129
|
+
const files = shipped.map((file) => ({ kind: "file", path: file.path, state: fileState(root, file, manifest, base), file }));
|
|
130
|
+
const buildEdited = files.some((f) => f.path === `${skillDir("build", base)}/SKILL.md` && f.state === "edited");
|
|
131
|
+
const buildPrefix = `${skillDir("build", base)}/`;
|
|
132
|
+
const retired = retiredFiles(root, shipped, manifest, base).filter((f) => !(buildEdited && f.path.startsWith(buildPrefix)));
|
|
133
|
+
return { base, items: [...files, ...mcpItems(root)], retired, manifest: manifest.ok ? "ok" : manifest.problem };
|
|
126
134
|
}
|
|
127
135
|
function itemLabel(item) {
|
|
128
136
|
return item.kind === "file" ? item.path : `${item.path} "${item.server}" server`;
|
|
@@ -132,7 +140,7 @@ function contextIsGoverned(gitCommonDir) {
|
|
|
132
140
|
}
|
|
133
141
|
var NAME = "Starter files";
|
|
134
142
|
var UPDATE = `${cliInvocation()} init --update`;
|
|
135
|
-
function shownPaths(items, all) {
|
|
143
|
+
function shownPaths(items, all, base) {
|
|
136
144
|
const shown = [];
|
|
137
145
|
const whole = /* @__PURE__ */ new Set();
|
|
138
146
|
for (const item of items) {
|
|
@@ -140,7 +148,7 @@ function shownPaths(items, all) {
|
|
|
140
148
|
if (skill !== void 0) {
|
|
141
149
|
const ofSkill = all.filter((i) => i.kind === "file" && i.file.skill === skill);
|
|
142
150
|
if (ofSkill.every((i) => items.includes(i))) {
|
|
143
|
-
if (!whole.has(skill)) shown.push(`${skillDir(skill)}/`);
|
|
151
|
+
if (!whole.has(skill)) shown.push(`${skillDir(skill, base)}/`);
|
|
144
152
|
whole.add(skill);
|
|
145
153
|
continue;
|
|
146
154
|
}
|
|
@@ -164,8 +172,8 @@ function checkStarterFiles(cwd, opts = {}) {
|
|
|
164
172
|
const retired = report.retired.filter((f) => f.state === "unedited");
|
|
165
173
|
const parts = [];
|
|
166
174
|
if (current.length > 0) parts.push(`${current.length} current`);
|
|
167
|
-
if (outdated.length > 0) parts.push(`outdated and unedited: ${shownPaths(outdated, report.items).join(", ")}`);
|
|
168
|
-
if (missing.length > 0) parts.push(`missing: ${shownPaths(missing, report.items).join(", ")}`);
|
|
175
|
+
if (outdated.length > 0) parts.push(`outdated and unedited: ${shownPaths(outdated, report.items, report.base).join(", ")}`);
|
|
176
|
+
if (missing.length > 0) parts.push(`missing: ${shownPaths(missing, report.items, report.base).join(", ")}`);
|
|
169
177
|
if (retired.length > 0) parts.push(`no longer shipped, unedited: ${retired.map((f) => f.path).join(", ")}`);
|
|
170
178
|
if (edited.length > 0) parts.push(`edited by you, left as they are: ${edited.map(itemLabel).join(", ")}`);
|
|
171
179
|
if (unreadable.length > 0) parts.push(`${unreadable[0].path} is not valid JSON, so its servers were not read`);
|
|
@@ -244,15 +252,25 @@ ${shortBuild()}`
|
|
|
244
252
|
fix: `Rename each heading to a phase: ${BUILD_PHASES.join(", ")}.`
|
|
245
253
|
});
|
|
246
254
|
}
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
)
|
|
255
|
+
const agentsMd = isAgentsMdLayout(repoRoot);
|
|
256
|
+
const seen = /* @__PURE__ */ new Set();
|
|
257
|
+
const lacking = folders.filter((folder) => {
|
|
258
|
+
if (!namesCore(read(join(repoRoot, folder, "build", "SKILL.md")) ?? "") || existsSync(join(repoRoot, folder, "outerlayer-build", "SKILL.md"))) return false;
|
|
259
|
+
let key = folder;
|
|
260
|
+
try {
|
|
261
|
+
key = realpathSync(join(repoRoot, folder));
|
|
262
|
+
} catch {
|
|
263
|
+
}
|
|
264
|
+
if (seen.has(key)) return false;
|
|
265
|
+
seen.add(key);
|
|
266
|
+
return true;
|
|
267
|
+
});
|
|
250
268
|
if (lacking.length > 0) {
|
|
251
269
|
checks.push({
|
|
252
270
|
name: NAME2,
|
|
253
271
|
status: "warn",
|
|
254
272
|
detail: `${lacking.join(", ")} holds build with no outerlayer-build beside it`,
|
|
255
|
-
fix: `Run \`${cliInvocation()} context emit\` to write outerlayer-build, then commit.`
|
|
273
|
+
fix: `Run \`${cliInvocation()} ${agentsMd ? "init --update" : "context emit"}\` to write outerlayer-build, then commit.`
|
|
256
274
|
});
|
|
257
275
|
}
|
|
258
276
|
return checks;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { revokeTokenOnDashboard } from './chunk-
|
|
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,
|
|
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:
|
|
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 =
|
|
189
|
+
const body = await res.json().catch(() => null);
|
|
193
190
|
if (!res.ok) {
|
|
194
|
-
const
|
|
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
|
-
|
|
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
|
|
201
|
-
return { id
|
|
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
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { checkStarterFiles, contextIsGoverned, checkBuildSkill } from './chunk-
|
|
4
|
-
import { resolveCredentials, getJson, WorkCommandError } from './chunk-
|
|
5
|
-
import { isLinkedRepository } from './chunk-
|
|
6
|
-
import { sanitizeTerminal } from './chunk-
|
|
7
|
-
import { checkFormerSkillNames } from './chunk-
|
|
8
|
-
import { resolveGatewayCredentials, defaultFetch } from './chunk-
|
|
9
|
-
import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-
|
|
3
|
+
import { checkStarterFiles, contextIsGoverned, checkBuildSkill } from './chunk-XFGL53GU.js';
|
|
4
|
+
import { resolveCredentials, getJson, WorkCommandError } from './chunk-RVYOOYOA.js';
|
|
5
|
+
import { isLinkedRepository } from './chunk-V5Q3S4NM.js';
|
|
6
|
+
import { sanitizeTerminal } from './chunk-BUP5N3X6.js';
|
|
7
|
+
import { checkFormerSkillNames } from './chunk-MQ743JX3.js';
|
|
8
|
+
import { resolveGatewayCredentials, defaultFetch } from './chunk-FKXGQOF5.js';
|
|
9
|
+
import { sanitizeForContext, spoolDir, assessSyncHealth, readSyncStatus, SYNC_STALE_AFTER_MS, formatAgo, checkInstalledCliStaleness, workspaceRootOf, hookFiredMarkerPath, refreshCommand } from './chunk-755WXDBI.js';
|
|
10
10
|
import { readStatuslineState, STATE_FRESH_MS } from './chunk-DXDF43YG.js';
|
|
11
11
|
import { hookCommandEscapesControlPlane, CONTROL_PLANE_DIR_VARIABLE } from './chunk-HCVLP7XA.js';
|
|
12
12
|
import { findGitDirs } from './chunk-BJ3KTMDH.js';
|
|
13
|
-
import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-
|
|
13
|
+
import { resolveRepoIdentity, compareVersions, SUPPORTED_VERSIONS } from './chunk-D4AMAEZ7.js';
|
|
14
14
|
import { C } from './chunk-ANPNT6PM.js';
|
|
15
15
|
import { cliInvocation } from './chunk-CRB3POP4.js';
|
|
16
16
|
import { readSettings, settingsPath, isOurStatuslineSlot, statuslineWrappedOriginal, REGISTERED_EVENTS, isOurHookCommand, ourCommandBins, cliBinResolvable, ourDirectScriptBins, wrappedOriginalCommand } from './chunk-GNPTU4BM.js';
|
|
@@ -1174,7 +1174,7 @@ function doctorExitCode(checks) {
|
|
|
1174
1174
|
|
|
1175
1175
|
// src/doctor-report.ts
|
|
1176
1176
|
async function gatherDoctorChecks() {
|
|
1177
|
-
const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-
|
|
1177
|
+
const { defaultRunnerConfigPath, hasRunnerBlock, loadRunnerConfig, runnerVmOf } = await import('./config-7Z5DHSGY.js');
|
|
1178
1178
|
const configPath = defaultRunnerConfigPath();
|
|
1179
1179
|
const checks = runDoctor({ runnerHost: hasRunnerBlock(configPath) });
|
|
1180
1180
|
const credential = await credentialChecks();
|
|
@@ -1186,7 +1186,7 @@ async function gatherDoctorChecks() {
|
|
|
1186
1186
|
const { runnerVmCheck } = await import('./doctor-53F2PYY7.js');
|
|
1187
1187
|
checks.push(runnerVmCheck(configPath, { lima: realLima(), home: homeFromEnv(), instance: runnerVm.instance }));
|
|
1188
1188
|
} else if (hasRunnerBlock(configPath)) {
|
|
1189
|
-
const { runnerHostChecks } = await import('./doctor-
|
|
1189
|
+
const { runnerHostChecks } = await import('./doctor-DOAFZV4O.js');
|
|
1190
1190
|
const hooks = (() => {
|
|
1191
1191
|
try {
|
|
1192
1192
|
return loadRunnerConfig(configPath).hooks;
|
|
@@ -1221,7 +1221,7 @@ async function gatherDoctorChecks() {
|
|
|
1221
1221
|
const { existsSync: existsSync3 } = await import('fs');
|
|
1222
1222
|
if (process.platform !== "linux" || !existsSync3("/run/systemd/system")) return void 0;
|
|
1223
1223
|
const { inspectService, realInspectProbes } = await import('./inspect-6UYAAXH7.js');
|
|
1224
|
-
const { DEFAULT_UNIT_NAME } = await import('./install-
|
|
1224
|
+
const { DEFAULT_UNIT_NAME } = await import('./install-ORQC26ZE.js');
|
|
1225
1225
|
const { dirname: dirname2 } = await import('path');
|
|
1226
1226
|
return inspectService(DEFAULT_UNIT_NAME, dirname2(configPath), realInspectProbes());
|
|
1227
1227
|
})();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { sharedSkillNames } from './chunk-
|
|
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-
|
|
8
|
-
import './chunk-
|
|
9
|
-
import './chunk-
|
|
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-
|
|
239
|
+
const { resolveLaunchPlane } = await import('./control-plane-launch-GKGI6HJA.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);
|