@outerlayer/cli 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/README.md +229 -60
- package/dist/agent-setup-IFH3FB5X.js +197 -0
- package/dist/build-TZUUTRGH.js +9 -0
- package/dist/build-info.json +1 -1
- package/dist/check-7MFH6HNC.js +94 -0
- package/dist/chunk-3TFPDVTI.js +94 -0
- package/dist/{chunk-4TNZMO7V.js → chunk-4C4THABW.js} +5566 -754
- package/dist/{chunk-R5KBGVII.js → chunk-5QRP3MVS.js} +30 -14
- package/dist/chunk-5Y3QQRUH.js +300 -0
- package/dist/chunk-774HEQL6.js +178 -0
- package/dist/{work-pr-cmd-AZQPWH4H.js → chunk-7WERLFVR.js} +9 -26
- package/dist/chunk-ABIWDUMS.js +104 -0
- package/dist/chunk-AUFG23AA.js +534 -0
- package/dist/chunk-B2G7JHHB.js +42 -0
- package/dist/chunk-BCJNHMZT.js +34 -0
- package/dist/chunk-BCLJSQCV.js +56 -0
- package/dist/chunk-BFESLKPP.js +61 -0
- package/dist/chunk-BJ3KTMDH.js +63 -0
- package/dist/chunk-BKO6JEZI.js +47 -0
- package/dist/chunk-BOLTI6LR.js +37 -0
- package/dist/chunk-CBPPJSAR.js +89 -0
- package/dist/chunk-DM3VFDS3.js +1461 -0
- package/dist/{chunk-65WXAANR.js → chunk-DVDEBNQJ.js} +17 -2
- package/dist/{chunk-TFUIDMOB.js → chunk-EABW6AJQ.js} +12 -1
- package/dist/{chunk-KFYJV2ZG.js → chunk-EMY4I27X.js} +1 -1
- package/dist/{chunk-NTTPJV35.js → chunk-F47JBIAW.js} +3 -1
- package/dist/chunk-F6GFZXZ3.js +60 -0
- package/dist/{chunk-YOOSBOKS.js → chunk-F7CU5ABH.js} +1 -1
- package/dist/{emit-cmd-TWSYYEZI.js → chunk-H5NCNVDA.js} +68 -17
- package/dist/chunk-HZRNMGLF.js +2233 -0
- package/dist/chunk-LF6MLJCY.js +38 -0
- package/dist/{chunk-U32VSRLO.js → chunk-LT5TZHYH.js} +95 -634
- package/dist/chunk-LYCDNMOH.js +83 -0
- package/dist/chunk-M5POMKKW.js +1051 -0
- package/dist/{mcp-install-cmd-FDQH6SEN.js → chunk-MQ3IPHIZ.js} +35 -18
- package/dist/{chunk-D77LS3UI.js → chunk-N5FOE5PS.js} +33 -4
- package/dist/chunk-N6LURUEF.js +64 -0
- package/dist/chunk-OGFGZQA3.js +23 -0
- package/dist/chunk-QDQEUVUF.js +9 -0
- package/dist/chunk-QOZKPLVJ.js +226 -0
- package/dist/chunk-QY22NZUW.js +1764 -0
- package/dist/chunk-RA3O54FC.js +30 -0
- package/dist/chunk-RFUPN6KX.js +71 -0
- package/dist/chunk-SY4GK4SP.js +55 -0
- package/dist/chunk-TBT347UY.js +41 -0
- package/dist/chunk-TWNWNS2Q.js +1084 -0
- package/dist/{chunk-NXLLURA4.js → chunk-UFFXNXLQ.js} +115 -71
- package/dist/chunk-USO2DKBD.js +421 -0
- package/dist/chunk-W4SQCOZU.js +206 -0
- package/dist/{chunk-Q6CL5THG.js → chunk-W5FVUZXV.js} +208 -61
- package/dist/chunk-WFJ65NUD.js +383 -0
- package/dist/{chunk-A3WLZX2F.js → chunk-WIOZAJ2W.js} +15 -2
- package/dist/chunk-WO2BXCTQ.js +83 -0
- package/dist/{chunk-I3ETLSNE.js → chunk-XCCLFVXM.js} +120 -11
- package/dist/{context-materialize-6WKT3RBQ.js → chunk-XDDW4FRS.js} +134 -26
- package/dist/chunk-Y7KJLXYN.js +232 -0
- package/dist/chunk-YFHIIH4B.js +102 -0
- package/dist/chunk-YYYXRJUW.js +101 -0
- package/dist/chunk-ZM2IMMYN.js +76 -0
- package/dist/chunk-ZMYPLFG3.js +71 -0
- package/dist/chunk-ZNA27WEV.js +470 -0
- package/dist/{cli-G7DILYJY.js → cli-W62AFRSW.js} +616 -878
- package/dist/{paths-D2VGWWFI.js → cli-build-K56DK4DS.js} +1 -1
- package/dist/config-XVJYZ4IQ.js +9 -0
- package/dist/connect-cmd-ZTJONP37.js +16 -0
- package/dist/context-adopt-UMA4O5NY.js +105 -0
- package/dist/context-materialize-G2FUFC72.js +19 -0
- package/dist/dist-44CQVWGT.js +6 -0
- package/dist/docker-NEGDLU6D.js +7 -0
- package/dist/doctor-53F2PYY7.js +43 -0
- package/dist/doctor-ZLGZYMDK.js +426 -0
- package/dist/{emit-artifact-cmd-UQVT3OKW.js → emit-artifact-cmd-AKZP7TMF.js} +87 -23
- package/dist/emit-cmd-DCERAU27.js +9 -0
- package/dist/emit-criteria-cmd-7MXQVCKD.js +166 -0
- package/dist/{emit-finding-cmd-FDOU2OPD.js → emit-finding-cmd-N2FTGCVC.js} +34 -31
- package/dist/{emit-result-cmd-H2T4C2K3.js → emit-result-cmd-4CPDBMN2.js} +34 -62
- package/dist/exec-client-4XGXV3XN.js +8 -0
- package/dist/guest-init-GENRHNP7.js +8 -0
- package/dist/hook-fast-EYENPK6F.js +9 -0
- package/dist/{hook-wrap-fast-KXYNX3AD.js → hook-wrap-fast-NPLHJXFK.js} +2 -2
- package/dist/host-key-KDYZ5ECC.js +7 -0
- package/dist/import-capture-cmd-AVZ4VIVJ.js +68 -0
- package/dist/{import-ruler-cmd-7LH2QOMG.js → import-ruler-cmd-GUHL6IY5.js} +1 -1
- package/dist/index.js +4 -4
- package/dist/init-55Y4LHWF.js +36 -0
- package/dist/init-XXEKWZQP.js +221 -0
- package/dist/init-cmd-WLST2F7G.js +135 -0
- package/dist/install-cmd-7WXOIFDO.js +55 -0
- package/dist/lima-XN65D7GN.js +55 -0
- package/dist/login-browser-7XGSV7MA.js +10 -0
- package/dist/{config-POF7DEQW.js → logout-cmd-QAUFDJ6J.js} +3 -1
- package/dist/{logs-TRNPQM42.js → logs-7RYUH5A6.js} +1 -1
- package/dist/loop-JFIBP4B7.js +43 -0
- package/dist/machine-ZBPT2J3R.js +35 -0
- package/dist/mcp-install-cmd-RLK4SO3N.js +9 -0
- package/dist/{mcp-serve-cmd-57EZZOTL.js → mcp-serve-cmd-N6UD2KBX.js} +20 -9
- package/dist/paths-OYKMVYJP.js +6 -0
- package/dist/{pidfile-PTW76F56.js → pidfile-UZRH774M.js} +2 -3
- package/dist/real-deps-SU24ZA2K.js +21 -0
- package/dist/relay-L76HDX72.js +46 -0
- package/dist/settings-J2652U5N.js +7 -0
- package/dist/starter-pack-LIZYMKYQ.js +10 -0
- package/dist/{status-I27IST4L.js → status-UJXWZRN5.js} +30 -13
- package/dist/{statusline-fast-3C5OXHDD.js → statusline-fast-SVTMBMD7.js} +3 -2
- package/dist/sync-cmd-4G4A7EVN.js +28 -0
- package/dist/version-BWM6VLDI.js +6 -0
- package/dist/{watch-3DTPJETH.js → watch-7SKJKGAA.js} +19 -8
- package/dist/{work-claim-cmd-5AUNCLS2.js → work-claim-cmd-5F7VZ42N.js} +34 -21
- package/dist/work-cmd-QAUZ7MTD.js +17 -0
- package/dist/work-comment-cmd-BNCSBTLH.js +106 -0
- package/dist/{work-launch-LT663PB3.js → work-launch-YI4CJDAP.js} +1 -1
- package/dist/work-open-pr-cmd-VFYZHIIW.js +156 -0
- package/dist/work-pr-cmd-PV32ZLSI.js +16 -0
- package/package.json +13 -3
- package/skill-pack/maintained/amend/SKILL.md +104 -0
- package/skill-pack/maintained/emitting-evidence/SKILL.md +108 -0
- package/skill-pack/maintained/emitting-evidence/references/agents-snippet.md +20 -0
- package/skill-pack/maintained/outerlayer/SKILL.md +55 -0
- package/skill-pack/maintained/reporting-findings/SKILL.md +148 -0
- package/skill-pack/template/build/SKILL.md +193 -0
- package/skill-pack/template/build/references/agent-briefs.md +243 -0
- package/skill-pack/template/build/references/criteria-judge.md +91 -0
- package/skill-pack/template/build/references/evidence.md +42 -0
- package/skill-pack/template/build/references/release.md +74 -0
- package/skill-pack/template/build/references/review-briefs.md +275 -0
- package/skill-pack/template/build/references/review-loop.md +158 -0
- package/skill-pack/template/build/scripts/record-criteria.mjs +235 -0
- package/skill-pack/template/spec/SKILL.md +84 -0
- package/skill-pack/template/writing-specs/SKILL.md +134 -0
- package/dist/chunk-DCNOXRMV.js +0 -589
- package/dist/chunk-JJP7YLMN.js +0 -25
- package/dist/chunk-OZ7C3XUE.js +0 -34
- package/dist/chunk-WQ6VGRGZ.js +0 -150
- package/dist/hook-fast-J5LCDHUJ.js +0 -8
- package/dist/import-capture-cmd-EUMBGIV3.js +0 -176
- package/dist/init-PTBITAUO.js +0 -103
- package/dist/login-cmd-IRX6LZT7.js +0 -62
- package/dist/loop-ASZRX3CZ.js +0 -648
- package/dist/sync-cmd-BBAUZ5JD.js +0 -17
- package/dist/work-cmd-2P4BVX47.js +0 -18
|
@@ -5,7 +5,7 @@ import { mkdirSync, appendFileSync, readFileSync } from 'fs';
|
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
|
|
7
7
|
createRequire(import.meta.url);
|
|
8
|
-
var HOW_TO_CREATE_AN_ITEM = "outerlayer work
|
|
8
|
+
var HOW_TO_CREATE_AN_ITEM = "outerlayer work build --local";
|
|
9
9
|
function parseWorkItemEnv(raw) {
|
|
10
10
|
if (raw === void 0) return { reason: "OUTERLAYER_WORK is not set" };
|
|
11
11
|
const value = raw.trim();
|
|
@@ -58,6 +58,21 @@ function launchedItemForSession(sessionId, home, readImpl = readLaunchSpool) {
|
|
|
58
58
|
}
|
|
59
59
|
return found;
|
|
60
60
|
}
|
|
61
|
+
function launchedItemsBySession(home, readImpl = readLaunchSpool) {
|
|
62
|
+
const items = /* @__PURE__ */ new Map();
|
|
63
|
+
const read = readImpl(launchesPath(home));
|
|
64
|
+
if (read.kind !== "read") return items;
|
|
65
|
+
for (const line of read.text.split("\n")) {
|
|
66
|
+
try {
|
|
67
|
+
const record = JSON.parse(line);
|
|
68
|
+
if (typeof record.sessionId === "string" && typeof record.item === "number") {
|
|
69
|
+
items.set(record.sessionId, record.item);
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return items;
|
|
75
|
+
}
|
|
61
76
|
function readLaunchSpoolState(home, readImpl = readLaunchSpool) {
|
|
62
77
|
const ids = /* @__PURE__ */ new Set();
|
|
63
78
|
const read = readImpl(launchesPath(home));
|
|
@@ -78,4 +93,4 @@ function readLaunchSpoolState(home, readImpl = readLaunchSpool) {
|
|
|
78
93
|
return { ids, ...malformedLines > 0 ? { malformedLines } : {} };
|
|
79
94
|
}
|
|
80
95
|
|
|
81
|
-
export { appendLaunchRecord, launchStatusIsDecisive, launchedItemForSession, launchesPath, parseWorkItemEnv, readLaunchSpoolState };
|
|
96
|
+
export { appendLaunchRecord, launchStatusIsDecisive, launchedItemForSession, launchedItemsBySession, launchesPath, parseWorkItemEnv, readLaunchSpoolState };
|
|
@@ -30,5 +30,16 @@ function writeCloudConfig(config, home = homeFromEnv()) {
|
|
|
30
30
|
} catch {
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
+
function removeCloudConfigKeys(keys, home = homeFromEnv()) {
|
|
34
|
+
const path = cloudConfigPath(home);
|
|
35
|
+
if (!existsSync(path)) return;
|
|
36
|
+
const stored = { ...readCloudConfig(home) };
|
|
37
|
+
for (const key of keys) delete stored[key];
|
|
38
|
+
writeFileSync(path, JSON.stringify(stored, null, 2) + "\n", { mode: 384 });
|
|
39
|
+
try {
|
|
40
|
+
chmodSync(path, 384);
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
33
44
|
|
|
34
|
-
export { cloudConfigPath, readCloudConfig, writeCloudConfig };
|
|
45
|
+
export { cloudConfigPath, readCloudConfig, removeCloudConfigKeys, writeCloudConfig };
|
|
@@ -7975,4 +7975,4 @@ function normalizeRepoName(repo) {
|
|
|
7975
7975
|
var CONTEXT_PIN_FILENAME = ".outerlayer-pin.json";
|
|
7976
7976
|
var CONTEXT_PIN_SCHEMA_VERSION = 1;
|
|
7977
7977
|
|
|
7978
|
-
export { CONTEXT_PIN_FILENAME, CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_SOURCE_CONFIG_PATH, classifyTree, emitTree, generatedHeaderSource, normalizePath, normalizeRepoName, parseGoverns, parseOuterlayerConfig };
|
|
7978
|
+
export { CONTEXT_PIN_FILENAME, CONTEXT_PIN_SCHEMA_VERSION, CONTEXT_SOURCE_CONFIG_PATH, classifyTree, emitTree, generatedHeaderSource, normalizePath, normalizeRepoName, parseGoverns, parseOuterlayerConfig, splitRawFile };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
3
|
+
import { recordReportedCost } from './chunk-BKO6JEZI.js';
|
|
4
|
+
import { decodeWrappedCommand } from './chunk-5QRP3MVS.js';
|
|
4
5
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
5
6
|
import { readFileSync } from 'fs';
|
|
6
7
|
import { spawn } from 'child_process';
|
|
@@ -133,6 +134,7 @@ async function runStatuslineFast(args, opts = {}) {
|
|
|
133
134
|
const now = (opts.now ?? Date.now)();
|
|
134
135
|
const stdinText = (opts.read ?? readStdin)();
|
|
135
136
|
const stdin = parseStatuslineStdin(stdinText);
|
|
137
|
+
recordReportedCost(home, stdin.session_id, stdin.cost?.total_cost_usd);
|
|
136
138
|
const state = readStatuslineState(home);
|
|
137
139
|
const ourLine = renderStatusline(stdin, state, now);
|
|
138
140
|
const { wrapId } = parseStatuslineArgs(args);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
|
|
4
|
+
createRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
// src/runner/container/disk.ts
|
|
7
|
+
var UNITS = { "": 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3 };
|
|
8
|
+
function parseSize(text) {
|
|
9
|
+
const match = /^(\d+(?:\.\d+)?)([kKmMgG]?)$/.exec(text);
|
|
10
|
+
if (match === null) return void 0;
|
|
11
|
+
const bytes = Number(match[1]) * UNITS[match[2].toLowerCase()];
|
|
12
|
+
return bytes > 0 ? bytes : void 0;
|
|
13
|
+
}
|
|
14
|
+
function parseDuKilobytes(output) {
|
|
15
|
+
const match = /^(\d+)\s/.exec(output);
|
|
16
|
+
return match === null ? void 0 : Number(match[1]);
|
|
17
|
+
}
|
|
18
|
+
function exceedsDisk(usedKilobytes, limit) {
|
|
19
|
+
const bytes = parseSize(limit);
|
|
20
|
+
return usedKilobytes * 1024 > (bytes ?? Number.POSITIVE_INFINITY);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/runner/allow-hosts.ts
|
|
24
|
+
var MAX_ALLOW_HOSTS = 500;
|
|
25
|
+
var LABEL = /^(?!-)[a-z0-9-]{1,63}(?<!-)$/;
|
|
26
|
+
var IPV4 = /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/;
|
|
27
|
+
function isAddress(text) {
|
|
28
|
+
if (IPV4.test(text)) return true;
|
|
29
|
+
try {
|
|
30
|
+
new URL(`http://[${text}]/`);
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isHostName(text) {
|
|
37
|
+
const labels = text.split(".");
|
|
38
|
+
return text.length <= 253 && labels.every((label) => LABEL.test(label)) && !/^\d+$/.test(labels.at(-1));
|
|
39
|
+
}
|
|
40
|
+
function allowHostProblem(entry) {
|
|
41
|
+
if (typeof entry !== "string") return "is not a string";
|
|
42
|
+
const text = entry.toLowerCase();
|
|
43
|
+
if (isAddress(text)) return void 0;
|
|
44
|
+
if (text.startsWith("*.")) {
|
|
45
|
+
const domain = text.slice(2);
|
|
46
|
+
if (!isHostName(domain)) return "is not a host name after *.";
|
|
47
|
+
if (!domain.includes(".")) return "is too broad: a pattern needs a domain with at least two labels after *.";
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
return isHostName(text) ? void 0 : "is not a host name, a *. pattern or an IP address";
|
|
51
|
+
}
|
|
52
|
+
function hostAllowed(host, allowHosts) {
|
|
53
|
+
const name = host.toLowerCase().replace(/\.$/, "");
|
|
54
|
+
return allowHosts.some((entry) => {
|
|
55
|
+
const pattern = entry.toLowerCase();
|
|
56
|
+
return pattern.startsWith("*.") ? name.endsWith(pattern.slice(1)) : name === pattern;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { MAX_ALLOW_HOSTS, allowHostProblem, exceedsDisk, hostAllowed, parseDuKilobytes, parseSize };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { decodeWrappedCommand } from './chunk-
|
|
3
|
+
import { decodeWrappedCommand } from './chunk-5QRP3MVS.js';
|
|
4
4
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
5
5
|
import { readFileSync, mkdirSync, appendFileSync, writeFileSync } from 'fs';
|
|
6
6
|
import { spawn } from 'child_process';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { maintainedFilesForExistingSkills, loadMaintainedFiles, writeMaintainedFiles } from './chunk-WO2BXCTQ.js';
|
|
4
|
+
import { emitTree, parseOuterlayerConfig, classifyTree, generatedHeaderSource, CONTEXT_PIN_FILENAME, normalizePath } from './chunk-EMY4I27X.js';
|
|
5
5
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, copyFileSync, readdirSync } from 'fs';
|
|
6
6
|
import { join, dirname, relative, sep } from 'path';
|
|
7
7
|
|
|
@@ -53,19 +53,21 @@ function walk(dir, repoRoot, insideOuterlayer, out) {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
function buildEmitInput(repoRoot, targets) {
|
|
57
|
-
const
|
|
56
|
+
function buildEmitInput(repoRoot, targets, maintained) {
|
|
57
|
+
const bundled = new Map(maintained.map((f) => [f.path, f.content]));
|
|
58
|
+
const discovered = [.../* @__PURE__ */ new Set([...discoverOuterlayerPaths(repoRoot), ...bundled.keys()])].sort();
|
|
58
59
|
const { entries } = classifyTree(discovered);
|
|
59
60
|
const classified = new Set(entries.map((e) => e.path));
|
|
60
61
|
const contents = /* @__PURE__ */ new Map();
|
|
61
62
|
for (const entry of entries) {
|
|
62
63
|
if (!CONTENT_KINDS.has(entry.kind)) continue;
|
|
63
|
-
contents.set(entry.path, readFileSync(join(repoRoot, entry.path), "utf8"));
|
|
64
|
+
contents.set(entry.path, bundled.get(entry.path) ?? readFileSync(join(repoRoot, entry.path), "utf8"));
|
|
64
65
|
}
|
|
65
66
|
const assetPaths = discovered.filter((p) => !classified.has(p));
|
|
66
67
|
return { input: { entries, contents, assetPaths, targets }, sourcePaths: classified };
|
|
67
68
|
}
|
|
68
|
-
function writeOutputs(repoRoot, result) {
|
|
69
|
+
function writeOutputs(repoRoot, result, maintained) {
|
|
70
|
+
const changedMaintained = writeMaintainedFiles(repoRoot, maintained);
|
|
69
71
|
const files = [];
|
|
70
72
|
for (const file of result.files) {
|
|
71
73
|
const abs = join(repoRoot, file.path);
|
|
@@ -80,11 +82,15 @@ function writeOutputs(repoRoot, result) {
|
|
|
80
82
|
copyFileSync(join(repoRoot, copy.fromSourcePath), abs);
|
|
81
83
|
copies.push(copy.toPath);
|
|
82
84
|
}
|
|
83
|
-
return { files, copies };
|
|
85
|
+
return { files, copies, maintained: [...changedMaintained.created, ...changedMaintained.rewritten] };
|
|
84
86
|
}
|
|
85
|
-
function renderSuccess(targets, files, copies) {
|
|
87
|
+
function renderSuccess(targets, files, copies, maintained) {
|
|
86
88
|
const copySuffix = copies.length > 0 ? `, ${copies.length} ${copies.length === 1 ? "copy" : "copies"}` : "";
|
|
87
|
-
|
|
89
|
+
const lines = [
|
|
90
|
+
`${GREEN}\u2713${RESET} emitted ${files.length} file${files.length === 1 ? "" : "s"}${copySuffix} for ${DIM}${targets.join(", ")}${RESET}`
|
|
91
|
+
];
|
|
92
|
+
for (const path of maintained) lines.push(` ${DIM}updated ${path} to this CLI's version${RESET}`);
|
|
93
|
+
return lines.join("\n");
|
|
88
94
|
}
|
|
89
95
|
function renderFailure(errors) {
|
|
90
96
|
const lines = [`${RED}\u2717${RESET} emit failed \u2014 nothing written`];
|
|
@@ -150,17 +156,48 @@ function findOrphans(repoRoot, computedFiles, sourcePaths) {
|
|
|
150
156
|
}
|
|
151
157
|
return orphans;
|
|
152
158
|
}
|
|
159
|
+
function withholdKept(repoRoot, result, keep) {
|
|
160
|
+
if (keep === void 0) return { result, kept: [] };
|
|
161
|
+
const kept = [];
|
|
162
|
+
const files = result.files.filter((file) => {
|
|
163
|
+
const abs = join(repoRoot, file.path);
|
|
164
|
+
if (!existsSync(abs)) return true;
|
|
165
|
+
const existing = readFileSync(abs, "utf8");
|
|
166
|
+
if (existing === file.content || !keep({ kind: "file", path: file.path, existing, content: file.content })) return true;
|
|
167
|
+
kept.push(file.path);
|
|
168
|
+
return false;
|
|
169
|
+
});
|
|
170
|
+
const copies = result.copies.filter((copy) => {
|
|
171
|
+
const abs = join(repoRoot, copy.toPath);
|
|
172
|
+
if (!existsSync(abs)) return true;
|
|
173
|
+
const src = join(repoRoot, copy.fromSourcePath);
|
|
174
|
+
if (existsSync(src) && readFileSync(abs).equals(readFileSync(src))) return true;
|
|
175
|
+
if (!keep({ kind: "copy", path: copy.toPath, source: copy.fromSourcePath })) return true;
|
|
176
|
+
kept.push(copy.toPath);
|
|
177
|
+
return false;
|
|
178
|
+
});
|
|
179
|
+
return { result: { ...result, files, copies }, kept: kept.sort() };
|
|
180
|
+
}
|
|
153
181
|
function runEmit(opts = {}) {
|
|
154
182
|
const cwd = opts.cwd ?? process.cwd();
|
|
155
183
|
if (!existsSync(cwd)) throw new EmitError(`no such directory: ${cwd}`);
|
|
156
184
|
const targets = resolveTargetsFromConfig(cwd);
|
|
157
|
-
const
|
|
158
|
-
const
|
|
185
|
+
const maintained = maintainedFilesForExistingSkills(cwd, loadMaintainedFiles());
|
|
186
|
+
const built = buildEmitInput(cwd, targets, maintained);
|
|
187
|
+
const emitted = emitTree(built.input);
|
|
188
|
+
const { result, kept } = withholdKept(cwd, emitted, opts.keep);
|
|
159
189
|
const hasErrors = result.errors.length > 0;
|
|
160
|
-
if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, built.sourcePaths);
|
|
161
|
-
const written = hasErrors ? { files: [], copies: [] } : writeOutputs(cwd, result);
|
|
190
|
+
if (opts.check) return runCheck(cwd, opts, targets, result, hasErrors, built.sourcePaths, maintained, kept);
|
|
191
|
+
const written = hasErrors ? { files: [], copies: [], maintained: [] } : writeOutputs(cwd, result, maintained);
|
|
162
192
|
const exitCode = hasErrors ? 1 : 0;
|
|
163
|
-
const output = opts.json ? JSON.stringify({
|
|
193
|
+
const output = opts.json ? JSON.stringify({
|
|
194
|
+
targets,
|
|
195
|
+
files: written.files,
|
|
196
|
+
copies: written.copies,
|
|
197
|
+
maintained: written.maintained,
|
|
198
|
+
warnings: result.warnings,
|
|
199
|
+
errors: result.errors
|
|
200
|
+
}) : hasErrors ? renderFailure(result.errors) : renderSuccess(targets, written.files, written.copies, written.maintained);
|
|
164
201
|
if (!opts.quiet) {
|
|
165
202
|
if (opts.json) {
|
|
166
203
|
process.stdout.write(output + "\n");
|
|
@@ -172,11 +209,25 @@ function runEmit(opts = {}) {
|
|
|
172
209
|
`);
|
|
173
210
|
}
|
|
174
211
|
}
|
|
175
|
-
return {
|
|
212
|
+
return {
|
|
213
|
+
targets,
|
|
214
|
+
files: written.files,
|
|
215
|
+
copies: written.copies,
|
|
216
|
+
maintained: written.maintained,
|
|
217
|
+
kept,
|
|
218
|
+
warnings: result.warnings,
|
|
219
|
+
errors: result.errors,
|
|
220
|
+
output,
|
|
221
|
+
exitCode
|
|
222
|
+
};
|
|
176
223
|
}
|
|
177
|
-
function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths) {
|
|
224
|
+
function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths, maintained, kept) {
|
|
178
225
|
const drift = [];
|
|
179
226
|
if (!hasErrors) {
|
|
227
|
+
for (const file of maintained) {
|
|
228
|
+
const d = compareFile(cwd, file.path, file.content);
|
|
229
|
+
if (d) drift.push(d);
|
|
230
|
+
}
|
|
180
231
|
const computedFiles = new Set(result.files.map((f) => f.path));
|
|
181
232
|
for (const file of result.files) {
|
|
182
233
|
const d = compareFile(cwd, file.path, file.content);
|
|
@@ -202,7 +253,7 @@ function runCheck(cwd, opts, targets, result, hasErrors, sourcePaths) {
|
|
|
202
253
|
`);
|
|
203
254
|
}
|
|
204
255
|
}
|
|
205
|
-
return { targets, files: [], copies: [], warnings: result.warnings, errors: result.errors, drift, output, exitCode };
|
|
256
|
+
return { targets, files: [], copies: [], maintained: [], kept, warnings: result.warnings, errors: result.errors, drift, output, exitCode };
|
|
206
257
|
}
|
|
207
258
|
|
|
208
259
|
export { EmitError, runEmit };
|