treelay 0.1.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/LICENSE +21 -0
- package/README.md +296 -0
- package/SPEC.md +920 -0
- package/dist/chunk-QKQUPZVD.js +2665 -0
- package/dist/chunk-QKQUPZVD.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +293 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +1399 -0
- package/dist/index.js +187 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
checkDrift,
|
|
4
|
+
compile,
|
|
5
|
+
explain,
|
|
6
|
+
explainDest,
|
|
7
|
+
extract,
|
|
8
|
+
formatDrift,
|
|
9
|
+
formatExplanation,
|
|
10
|
+
formatStatus,
|
|
11
|
+
hasDrift,
|
|
12
|
+
hasState,
|
|
13
|
+
lockfilePath,
|
|
14
|
+
planUpdate,
|
|
15
|
+
promote,
|
|
16
|
+
readState,
|
|
17
|
+
resolve,
|
|
18
|
+
resolveValues,
|
|
19
|
+
sourceOf,
|
|
20
|
+
status,
|
|
21
|
+
update,
|
|
22
|
+
writeLock
|
|
23
|
+
} from "./chunk-QKQUPZVD.js";
|
|
24
|
+
|
|
25
|
+
// src/cli.ts
|
|
26
|
+
import { readFileSync } from "fs";
|
|
27
|
+
import { createRequire } from "module";
|
|
28
|
+
import { Command } from "commander";
|
|
29
|
+
import { parse as parseYaml } from "yaml";
|
|
30
|
+
var { version } = createRequire(import.meta.url)("../package.json");
|
|
31
|
+
var program = new Command();
|
|
32
|
+
program.name("treelay").description(
|
|
33
|
+
"Compose directory trees from parents and mixins, materialize them, and keep the output linked for two-way updates."
|
|
34
|
+
).version(version);
|
|
35
|
+
function collectSet(value, previous = {}) {
|
|
36
|
+
const eq = value.indexOf("=");
|
|
37
|
+
if (eq === -1) throw new Error(`--set expects k=v, got "${value}"`);
|
|
38
|
+
previous[value.slice(0, eq)] = value.slice(eq + 1);
|
|
39
|
+
return previous;
|
|
40
|
+
}
|
|
41
|
+
program.command("plan").argument("[dir]", "leaf overlay directory", ".").option("--frozen-lockfile", "fail on any ref treelay.lock does not pin").description("print the linearized layer order; write nothing").action((dir, opts) => {
|
|
42
|
+
const graph = resolve(dir, opts.frozenLockfile ? { frozen: true } : {});
|
|
43
|
+
console.log("Layers (lowest \u2192 highest precedence):");
|
|
44
|
+
graph.layers.forEach((l, i) => {
|
|
45
|
+
const marks = [
|
|
46
|
+
l.mountPath ? `mounted at ${l.mountPath}/` : void 0,
|
|
47
|
+
l.origin?.revision ? `pinned ${shortRev(l.origin.revision)}` : void 0
|
|
48
|
+
].filter(Boolean);
|
|
49
|
+
const suffix = marks.length ? ` [${marks.join(", ")}]` : "";
|
|
50
|
+
console.log(` ${i + 1}. ${l.manifest.name ?? l.id}${suffix}`);
|
|
51
|
+
});
|
|
52
|
+
const vars = Object.keys(graph.variables);
|
|
53
|
+
if (vars.length) console.log(`Variables: ${vars.join(", ")}`);
|
|
54
|
+
if (graph.lockDirty) {
|
|
55
|
+
console.error(
|
|
56
|
+
`
|
|
57
|
+
treelay.lock is out of date \u2014 run \`treelay lock ${dir}\` to record the revisions this plan resolved.`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
function shortRev(rev) {
|
|
62
|
+
return /^[0-9a-f]{40}$/i.test(rev) ? rev.slice(0, 12) : rev;
|
|
63
|
+
}
|
|
64
|
+
program.command("lock").argument("[dir]", "leaf overlay directory", ".").option("--check", "verify the lockfile is complete and current; write nothing").option("--update", "re-resolve moving refs to their current upstream revision").option("--drift", "report refs whose upstream has moved (network)").description("resolve every layer ref and pin it in treelay.lock").action((dir, opts) => {
|
|
65
|
+
const graph = resolve(dir, {
|
|
66
|
+
// `--check` must not be able to *fix* what it is checking, so it resolves
|
|
67
|
+
// in the normal (non-frozen) mode and then refuses to write.
|
|
68
|
+
...opts.update ? { updateRefs: true } : {}
|
|
69
|
+
});
|
|
70
|
+
const refs = Object.entries(graph.lock?.refs ?? {});
|
|
71
|
+
if (opts.check) {
|
|
72
|
+
if (graph.lockDirty) {
|
|
73
|
+
console.error(
|
|
74
|
+
`${lockfilePath(dir)} is out of date.
|
|
75
|
+
Run \`treelay lock ${dir}\` and commit the result.`
|
|
76
|
+
);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
console.log(`treelay.lock is up to date (${refs.length} pinned ref(s)).`);
|
|
80
|
+
} else if (graph.lock && graph.lockDir) {
|
|
81
|
+
const wrote = writeLock(graph.lockDir, graph.lock);
|
|
82
|
+
console.log(
|
|
83
|
+
wrote ? `Wrote ${lockfilePath(dir)} \u2014 ${refs.length} pinned ref(s).` : `treelay.lock already current (${refs.length} pinned ref(s)).`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
for (const [ref, entry] of refs.sort()) {
|
|
87
|
+
console.log(` ${ref}
|
|
88
|
+
\u2192 ${shortRev(entry.resolved)} ${entry.integrity.slice(0, 21)}\u2026`);
|
|
89
|
+
}
|
|
90
|
+
if (opts.drift) {
|
|
91
|
+
const reports = checkDrift(graph);
|
|
92
|
+
const text = formatDrift(reports);
|
|
93
|
+
console.log(text || "\nAll pinned refs match their upstream.");
|
|
94
|
+
if (hasDrift(reports)) process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
function loadAnswers(file) {
|
|
98
|
+
const text = readFileSync(file, "utf8");
|
|
99
|
+
return file.endsWith(".json") ? JSON.parse(text) : parseYaml(text);
|
|
100
|
+
}
|
|
101
|
+
program.command("compile").argument("<src>", "leaf overlay directory").argument("<dest>", "destination directory").option("--set <k=v>", "set a variable", collectSet).option("--answers <file>", "answers file to seed values").option("--no-prompt", "do not prompt for missing variables").option("--frozen-lockfile", "fail on any ref treelay.lock does not pin").description("materialize template \u2192 destination (first run = instantiate)").action(
|
|
102
|
+
async (src, dest, opts) => {
|
|
103
|
+
if (hasState(dest)) {
|
|
104
|
+
console.error(
|
|
105
|
+
`treelay compile: ${dest} already has .treelay state \u2014 use \`treelay update ${dest}\` to pull template changes in.`
|
|
106
|
+
);
|
|
107
|
+
process.exit(2);
|
|
108
|
+
}
|
|
109
|
+
const graph = resolve(src, opts.frozenLockfile ? { frozen: true } : {});
|
|
110
|
+
const values = await resolveValues(graph, {
|
|
111
|
+
...opts.answers ? { answers: loadAnswers(opts.answers) } : {},
|
|
112
|
+
...opts.set ? { set: opts.set } : {},
|
|
113
|
+
prompt: opts.prompt !== false
|
|
114
|
+
});
|
|
115
|
+
const gainedPins = graph.lockDirty;
|
|
116
|
+
const result = await compile(graph, { destDir: dest, values });
|
|
117
|
+
const n = Object.keys(result.files).length;
|
|
118
|
+
console.log(`Compiled ${n} file${n === 1 ? "" : "s"} \u2192 ${dest}`);
|
|
119
|
+
if (gainedPins) {
|
|
120
|
+
console.log(`Recorded new pins in ${lockfilePath(src)} \u2014 commit it.`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
program.command("update").argument("<dest>", "destination directory").option("--set <k=v>", "override a saved answer", collectSet).option(
|
|
125
|
+
"--on-conflict <mode>",
|
|
126
|
+
"how to surface conflicts: markers | rej",
|
|
127
|
+
"markers"
|
|
128
|
+
).option("--no-prompt", "do not prompt for newly-introduced variables").option("--dry-run", "show what would change; write nothing").option("--frozen-lockfile", "fail on any ref treelay.lock does not pin").description("re-render with saved answers and 3-way merge into the project").action(
|
|
129
|
+
async (dest, opts) => {
|
|
130
|
+
requireState(dest, "update");
|
|
131
|
+
if (opts.onConflict !== "markers" && opts.onConflict !== "rej") {
|
|
132
|
+
console.error(
|
|
133
|
+
`treelay update: --on-conflict expects "markers" or "rej", got "${opts.onConflict}"`
|
|
134
|
+
);
|
|
135
|
+
process.exit(2);
|
|
136
|
+
}
|
|
137
|
+
const options = {
|
|
138
|
+
onConflict: opts.onConflict,
|
|
139
|
+
...opts.set ? { set: opts.set } : {},
|
|
140
|
+
...opts.frozenLockfile ? { frozen: true } : {},
|
|
141
|
+
prompt: opts.prompt !== false
|
|
142
|
+
};
|
|
143
|
+
const plan = opts.dryRun ? await planUpdate(dest, options) : await update(dest, options);
|
|
144
|
+
if (plan.newVariables.length) {
|
|
145
|
+
console.log(`New variables: ${plan.newVariables.join(", ")}`);
|
|
146
|
+
}
|
|
147
|
+
const drift = formatDrift(plan.drift);
|
|
148
|
+
if (drift) console.error(drift + "\n");
|
|
149
|
+
const mark = {
|
|
150
|
+
"take-theirs": "U",
|
|
151
|
+
merged: "M",
|
|
152
|
+
conflict: "C",
|
|
153
|
+
delete: "D"
|
|
154
|
+
};
|
|
155
|
+
const changed = Object.entries(plan.files).filter(([, r]) => r in mark);
|
|
156
|
+
const kept = Object.values(plan.files).filter((r) => r === "keep-ours").length;
|
|
157
|
+
if (!changed.length) {
|
|
158
|
+
console.log("Already up to date.");
|
|
159
|
+
if (kept) console.log(`(${kept} file(s) with local edits left as-is.)`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
for (const [path, r] of changed.sort()) {
|
|
163
|
+
console.log(` ${mark[r]} ${path}${r === "conflict" ? " \u2190 conflict" : ""}`);
|
|
164
|
+
}
|
|
165
|
+
if (kept) console.log(` \u2026 ${kept} file(s) with local edits left as-is.`);
|
|
166
|
+
if (plan.conflicts.length) {
|
|
167
|
+
console.error(
|
|
168
|
+
`
|
|
169
|
+
${plan.conflicts.length} conflict(s). ` + (opts.dryRun ? "Re-run without --dry-run to write them." : options.onConflict === "rej" ? "Your files are unchanged; incoming versions are in *.rej." : "Resolve the markers, then run `treelay update` again.")
|
|
170
|
+
);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
async function changesFor(dest, files) {
|
|
176
|
+
requireState(dest, "status");
|
|
177
|
+
const all = await status(dest);
|
|
178
|
+
if (!files.length) return all;
|
|
179
|
+
const selected = all.filter((c) => files.includes(c.path));
|
|
180
|
+
const missing = files.filter((f) => !all.some((c) => c.path === f));
|
|
181
|
+
if (missing.length) {
|
|
182
|
+
console.error(
|
|
183
|
+
`No change recorded for: ${missing.join(", ")}
|
|
184
|
+
Run \`treelay status ${dest}\` to see what diverged from the baseline.`
|
|
185
|
+
);
|
|
186
|
+
process.exit(2);
|
|
187
|
+
}
|
|
188
|
+
return selected;
|
|
189
|
+
}
|
|
190
|
+
function requireState(dest, cmd) {
|
|
191
|
+
if (hasState(dest)) return;
|
|
192
|
+
console.error(
|
|
193
|
+
`treelay ${cmd}: ${dest} has no .treelay state \u2014 it was not created by treelay. Use \`treelay compile <src> ${dest}\` first.`
|
|
194
|
+
);
|
|
195
|
+
process.exit(2);
|
|
196
|
+
}
|
|
197
|
+
program.command("status").argument("<dest>", "destination directory").option("--json", "emit machine-readable JSON").description("list changes vs baseline, annotated with producing layer").action(async (dest, opts) => {
|
|
198
|
+
requireState(dest, "status");
|
|
199
|
+
const changes = await status(dest);
|
|
200
|
+
if (opts.json) {
|
|
201
|
+
console.log(JSON.stringify(changes, null, 2));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const state = readState(dest);
|
|
205
|
+
const src = sourceOf(state);
|
|
206
|
+
console.log(formatStatus(changes, resolve(src)));
|
|
207
|
+
});
|
|
208
|
+
program.command("promote").argument("<dest>", "destination directory").argument("[files...]", "files to promote").option("--to <layer>", "target layer (auto-suggested if omitted)").option("--no-verify", "skip the round-trip recompile check (\xA78 guard 2)").option("--dry-run", "show what each target would gain; write nothing").description("push instance edits up into a layer").action(
|
|
209
|
+
async (dest, files, opts) => {
|
|
210
|
+
const changes = await changesFor(dest, files);
|
|
211
|
+
if (!changes.length) {
|
|
212
|
+
console.log("Nothing to promote \u2014 no changes vs baseline.");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (opts.dryRun) {
|
|
216
|
+
console.log(
|
|
217
|
+
`Would promote ${changes.length} change(s)${opts.to ? ` into ${opts.to}` : ""}:`
|
|
218
|
+
);
|
|
219
|
+
for (const c of changes) console.log(` ${c.kind.padEnd(8)} ${c.path}`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const result = await promote(dest, changes, {
|
|
223
|
+
...opts.to ? { to: opts.to } : {},
|
|
224
|
+
verify: opts.verify !== false
|
|
225
|
+
});
|
|
226
|
+
console.log(`Promoted into ${result.targetName}:`);
|
|
227
|
+
for (const l of result.landed) {
|
|
228
|
+
console.log(` ${l.mode.padEnd(9)} ${l.path} \u2192 ${l.wrote}`);
|
|
229
|
+
}
|
|
230
|
+
console.log(
|
|
231
|
+
result.verified ? "Round-trip verified: the destination reproduces from the template." : "Round-trip verification skipped (--no-verify)."
|
|
232
|
+
);
|
|
233
|
+
console.error(`
|
|
234
|
+
${result.blastRadiusWarning}`);
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
program.command("extract").argument("<dest>", "destination directory").argument("[files...]", "files to extract").requiredOption("--as <path>", "path for the new overlay layer").option("--mixin", "wire the new layer in as a mixin").option("--name <name>", "name for the new layer's manifest").description("capture instance edits as a new overlay layer").action(
|
|
238
|
+
async (dest, files, opts) => {
|
|
239
|
+
const changes = await changesFor(dest, files);
|
|
240
|
+
if (!changes.length) {
|
|
241
|
+
console.log("Nothing to extract \u2014 no changes vs baseline.");
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const result = await extract(dest, changes, {
|
|
245
|
+
as: opts.as,
|
|
246
|
+
...opts.mixin ? { asMixin: true } : {},
|
|
247
|
+
...opts.name ? { name: opts.name } : {}
|
|
248
|
+
});
|
|
249
|
+
console.log(`Extracted ${result.files.length} file(s) \u2192 ${result.layer}`);
|
|
250
|
+
for (const f of result.files) console.log(` ${f}`);
|
|
251
|
+
if (result.wired) {
|
|
252
|
+
console.log(`Wired in as a mixin of the leaf; round-trip verified.`);
|
|
253
|
+
} else {
|
|
254
|
+
console.error(
|
|
255
|
+
`
|
|
256
|
+
The new layer is not wired into the graph, so these edits are still local. Add "${opts.as}" to the leaf's parents or mixins (or re-run with --mixin) to make them inherited.`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
program.command("explain").argument("<dir>", "leaf overlay directory, or a compiled destination").argument("[file]", "a single output path to trace (default: every file)").option("--set <k=v>", "value used to render templated paths", collectSet).option("--answers <file>", "answers file to seed values").option("--json", "emit machine-readable JSON").description("trace which layers touched a file, in order").action(
|
|
262
|
+
async (dir, file, opts) => {
|
|
263
|
+
const result = hasState(dir) ? await explainDest(dir) : await explain(resolve(dir), {
|
|
264
|
+
values: {
|
|
265
|
+
...opts.answers ? loadAnswers(opts.answers) : {},
|
|
266
|
+
...opts.set ?? {}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
if (opts.json) {
|
|
270
|
+
const payload = file ? { layers: result.layers, files: pick(result.files, file) } : result;
|
|
271
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
console.log(formatExplanation(result, file));
|
|
275
|
+
if (file && !result.files[file]) process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
function pick(files, path) {
|
|
279
|
+
const hit = files[path];
|
|
280
|
+
return hit ? { [path]: hit } : {};
|
|
281
|
+
}
|
|
282
|
+
program.command("validate").argument("[dir]", "leaf overlay directory", ".").description("check for cycles, failing patches, conflicts, lock drift").action(() => notImplemented("validate"));
|
|
283
|
+
program.command("watch").argument("<src>", "leaf overlay directory").argument("<dest>", "destination directory").description("recompile on change").action(() => notImplemented("watch"));
|
|
284
|
+
program.command("eject").argument("<dest>", "destination directory").description("flatten and drop .treelay state (sever the template link)").action(() => notImplemented("eject"));
|
|
285
|
+
function notImplemented(cmd) {
|
|
286
|
+
console.error(`treelay ${cmd}: not implemented yet (see SPEC.md \xA712 build order)`);
|
|
287
|
+
process.exit(2);
|
|
288
|
+
}
|
|
289
|
+
program.parseAsync().catch((err) => {
|
|
290
|
+
console.error(err instanceof Error ? err.message : err);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
});
|
|
293
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * treelay CLI — SPEC §9.\n *\n * Thin shell over the library. Commands are wired to their API entry points;\n * unimplemented ones surface a clear \"not implemented yet\" until built (§12).\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { Command } from \"commander\";\nimport { parse as parseYaml } from \"yaml\";\nimport { resolve } from \"./resolve.js\";\nimport { resolveValues } from \"./variables.js\";\nimport { compile } from \"./compile.js\";\nimport { update, planUpdate } from \"./update.js\";\nimport { explain, explainDest, formatExplanation } from \"./explain.js\";\nimport { status, promote, extract, formatStatus } from \"./reflux.js\";\nimport { hasState, readState, sourceOf } from \"./state.js\";\nimport { lockfilePath, writeLock } from \"./lockfile.js\";\nimport { checkDrift, formatDrift, hasDrift } from \"./drift.js\";\nimport type { Values } from \"./types.js\";\n\n// The published version has exactly one home: package.json. `../package.json`\n// resolves to the package root from both `src/cli.ts` and the bundled\n// `dist/cli.js`, so dev and install agree without a build-time substitution.\nconst { version } = createRequire(import.meta.url)(\"../package.json\") as {\n version: string;\n};\n\nconst program = new Command();\n\nprogram\n .name(\"treelay\")\n .description(\n \"Compose directory trees from parents and mixins, materialize them, \" +\n \"and keep the output linked for two-way updates.\",\n )\n .version(version);\n\n/** Parse repeated `--set k=v` flags into an object. */\nfunction collectSet(value: string, previous: Record<string, string> = {}) {\n const eq = value.indexOf(\"=\");\n if (eq === -1) throw new Error(`--set expects k=v, got \"${value}\"`);\n previous[value.slice(0, eq)] = value.slice(eq + 1);\n return previous;\n}\n\nprogram\n .command(\"plan\")\n .argument(\"[dir]\", \"leaf overlay directory\", \".\")\n .option(\"--frozen-lockfile\", \"fail on any ref treelay.lock does not pin\")\n .description(\"print the linearized layer order; write nothing\")\n .action((dir: string, opts: { frozenLockfile?: boolean }) => {\n const graph = resolve(dir, opts.frozenLockfile ? { frozen: true } : {});\n console.log(\"Layers (lowest → highest precedence):\");\n graph.layers.forEach((l, i) => {\n const marks = [\n l.mountPath ? `mounted at ${l.mountPath}/` : undefined,\n l.origin?.revision ? `pinned ${shortRev(l.origin.revision)}` : undefined,\n ].filter(Boolean);\n const suffix = marks.length ? ` [${marks.join(\", \")}]` : \"\";\n console.log(` ${i + 1}. ${l.manifest.name ?? l.id}${suffix}`);\n });\n const vars = Object.keys(graph.variables);\n if (vars.length) console.log(`Variables: ${vars.join(\", \")}`);\n if (graph.lockDirty) {\n console.error(\n `\\ntreelay.lock is out of date — run \\`treelay lock ${dir}\\` to record ` +\n `the revisions this plan resolved.`,\n );\n }\n });\n\n/** Abbreviate a commit SHA for display; package versions pass through. */\nfunction shortRev(rev: string): string {\n return /^[0-9a-f]{40}$/i.test(rev) ? rev.slice(0, 12) : rev;\n}\n\nprogram\n .command(\"lock\")\n .argument(\"[dir]\", \"leaf overlay directory\", \".\")\n .option(\"--check\", \"verify the lockfile is complete and current; write nothing\")\n .option(\"--update\", \"re-resolve moving refs to their current upstream revision\")\n .option(\"--drift\", \"report refs whose upstream has moved (network)\")\n .description(\"resolve every layer ref and pin it in treelay.lock\")\n .action((dir: string, opts: { check?: boolean; update?: boolean; drift?: boolean }) => {\n const graph = resolve(dir, {\n // `--check` must not be able to *fix* what it is checking, so it resolves\n // in the normal (non-frozen) mode and then refuses to write.\n ...(opts.update ? { updateRefs: true } : {}),\n });\n\n const refs = Object.entries(graph.lock?.refs ?? {});\n if (opts.check) {\n if (graph.lockDirty) {\n console.error(\n `${lockfilePath(dir)} is out of date.\\n` +\n `Run \\`treelay lock ${dir}\\` and commit the result.`,\n );\n process.exit(1);\n }\n console.log(`treelay.lock is up to date (${refs.length} pinned ref(s)).`);\n } else if (graph.lock && graph.lockDir) {\n const wrote = writeLock(graph.lockDir, graph.lock);\n console.log(\n wrote\n ? `Wrote ${lockfilePath(dir)} — ${refs.length} pinned ref(s).`\n : `treelay.lock already current (${refs.length} pinned ref(s)).`,\n );\n }\n\n for (const [ref, entry] of refs.sort()) {\n console.log(` ${ref}\\n → ${shortRev(entry.resolved)} ${entry.integrity.slice(0, 21)}…`);\n }\n\n if (opts.drift) {\n const reports = checkDrift(graph);\n const text = formatDrift(reports);\n console.log(text || \"\\nAll pinned refs match their upstream.\");\n if (hasDrift(reports)) process.exit(1);\n }\n });\n\n/** Load an answers file (JSON or YAML) into a values object. */\nfunction loadAnswers(file: string): Values {\n const text = readFileSync(file, \"utf8\");\n return (file.endsWith(\".json\") ? JSON.parse(text) : parseYaml(text)) as Values;\n}\n\nprogram\n .command(\"compile\")\n .argument(\"<src>\", \"leaf overlay directory\")\n .argument(\"<dest>\", \"destination directory\")\n .option(\"--set <k=v>\", \"set a variable\", collectSet)\n .option(\"--answers <file>\", \"answers file to seed values\")\n .option(\"--no-prompt\", \"do not prompt for missing variables\")\n .option(\"--frozen-lockfile\", \"fail on any ref treelay.lock does not pin\")\n .description(\"materialize template → destination (first run = instantiate)\")\n .action(\n async (\n src: string,\n dest: string,\n opts: {\n set?: Values;\n answers?: string;\n prompt?: boolean;\n frozenLockfile?: boolean;\n },\n ) => {\n if (hasState(dest)) {\n console.error(\n `treelay compile: ${dest} already has .treelay state — use ` +\n `\\`treelay update ${dest}\\` to pull template changes in.`,\n );\n process.exit(2);\n }\n const graph = resolve(src, opts.frozenLockfile ? { frozen: true } : {});\n const values = await resolveValues(graph, {\n ...(opts.answers ? { answers: loadAnswers(opts.answers) } : {}),\n ...(opts.set ? { set: opts.set } : {}),\n prompt: opts.prompt !== false,\n });\n const gainedPins = graph.lockDirty;\n const result = await compile(graph, { destDir: dest, values });\n const n = Object.keys(result.files).length;\n console.log(`Compiled ${n} file${n === 1 ? \"\" : \"s\"} → ${dest}`);\n // Writing the source lockfile is a side effect on a tree the user may not\n // have expected this command to touch, so it is always announced.\n if (gainedPins) {\n console.log(`Recorded new pins in ${lockfilePath(src)} — commit it.`);\n }\n },\n );\n\nprogram\n .command(\"update\")\n .argument(\"<dest>\", \"destination directory\")\n .option(\"--set <k=v>\", \"override a saved answer\", collectSet)\n .option(\n \"--on-conflict <mode>\",\n \"how to surface conflicts: markers | rej\",\n \"markers\",\n )\n .option(\"--no-prompt\", \"do not prompt for newly-introduced variables\")\n .option(\"--dry-run\", \"show what would change; write nothing\")\n .option(\"--frozen-lockfile\", \"fail on any ref treelay.lock does not pin\")\n .description(\"re-render with saved answers and 3-way merge into the project\")\n .action(\n async (\n dest: string,\n opts: {\n set?: Values;\n onConflict?: string;\n prompt?: boolean;\n dryRun?: boolean;\n frozenLockfile?: boolean;\n },\n ) => {\n requireState(dest, \"update\");\n if (opts.onConflict !== \"markers\" && opts.onConflict !== \"rej\") {\n console.error(\n `treelay update: --on-conflict expects \"markers\" or \"rej\", got \"${opts.onConflict}\"`,\n );\n process.exit(2);\n }\n\n const options = {\n onConflict: opts.onConflict,\n ...(opts.set ? { set: opts.set } : {}),\n ...(opts.frozenLockfile ? { frozen: true } : {}),\n prompt: opts.prompt !== false,\n } as const;\n\n const plan = opts.dryRun\n ? await planUpdate(dest, options)\n : await update(dest, options);\n\n if (plan.newVariables.length) {\n console.log(`New variables: ${plan.newVariables.join(\", \")}`);\n }\n\n // Drift is advisory and goes to stderr: this update composed from the\n // pinned revisions, and saying so must not be mistaken for a file change.\n const drift = formatDrift(plan.drift);\n if (drift) console.error(drift + \"\\n\");\n\n // Only report files the working tree actually gained, lost, or had\n // rewritten. `keep-ours`/`unchanged` write nothing, and listing them every\n // run buries the handful that moved — and makes a no-op look like work.\n const mark: Record<string, string> = {\n \"take-theirs\": \"U\",\n merged: \"M\",\n conflict: \"C\",\n delete: \"D\",\n };\n const changed = Object.entries(plan.files).filter(([, r]) => r in mark);\n const kept = Object.values(plan.files).filter((r) => r === \"keep-ours\").length;\n\n if (!changed.length) {\n console.log(\"Already up to date.\");\n if (kept) console.log(`(${kept} file(s) with local edits left as-is.)`);\n return;\n }\n\n for (const [path, r] of changed.sort()) {\n console.log(` ${mark[r]} ${path}${r === \"conflict\" ? \" ← conflict\" : \"\"}`);\n }\n if (kept) console.log(` … ${kept} file(s) with local edits left as-is.`);\n\n if (plan.conflicts.length) {\n console.error(\n `\\n${plan.conflicts.length} conflict(s). ` +\n (opts.dryRun\n ? \"Re-run without --dry-run to write them.\"\n : options.onConflict === \"rej\"\n ? \"Your files are unchanged; incoming versions are in *.rej.\"\n : \"Resolve the markers, then run `treelay update` again.\"),\n );\n process.exit(1);\n }\n },\n );\n\n/** Load a destination's changes, narrowed to `files` when any were named. */\nasync function changesFor(dest: string, files: string[]) {\n requireState(dest, \"status\");\n const all = await status(dest);\n if (!files.length) return all;\n\n const selected = all.filter((c) => files.includes(c.path));\n const missing = files.filter((f) => !all.some((c) => c.path === f));\n if (missing.length) {\n console.error(\n `No change recorded for: ${missing.join(\", \")}\\n` +\n `Run \\`treelay status ${dest}\\` to see what diverged from the baseline.`,\n );\n process.exit(2);\n }\n return selected;\n}\n\n/** Exit with guidance when a directory carries no treelay state. */\nfunction requireState(dest: string, cmd: string): void {\n if (hasState(dest)) return;\n console.error(\n `treelay ${cmd}: ${dest} has no .treelay state — it was not created by ` +\n `treelay. Use \\`treelay compile <src> ${dest}\\` first.`,\n );\n process.exit(2);\n}\n\nprogram\n .command(\"status\")\n .argument(\"<dest>\", \"destination directory\")\n .option(\"--json\", \"emit machine-readable JSON\")\n .description(\"list changes vs baseline, annotated with producing layer\")\n .action(async (dest: string, opts: { json?: boolean }) => {\n requireState(dest, \"status\");\n const changes = await status(dest);\n if (opts.json) {\n console.log(JSON.stringify(changes, null, 2));\n return;\n }\n const state = readState(dest);\n const src = sourceOf(state);\n console.log(formatStatus(changes, resolve(src!)));\n });\n\nprogram\n .command(\"promote\")\n .argument(\"<dest>\", \"destination directory\")\n .argument(\"[files...]\", \"files to promote\")\n .option(\"--to <layer>\", \"target layer (auto-suggested if omitted)\")\n .option(\"--no-verify\", \"skip the round-trip recompile check (§8 guard 2)\")\n .option(\"--dry-run\", \"show what each target would gain; write nothing\")\n .description(\"push instance edits up into a layer\")\n .action(\n async (\n dest: string,\n files: string[],\n opts: { to?: string; verify?: boolean; dryRun?: boolean },\n ) => {\n const changes = await changesFor(dest, files);\n if (!changes.length) {\n console.log(\"Nothing to promote — no changes vs baseline.\");\n return;\n }\n\n if (opts.dryRun) {\n console.log(\n `Would promote ${changes.length} change(s)${opts.to ? ` into ${opts.to}` : \"\"}:`,\n );\n for (const c of changes) console.log(` ${c.kind.padEnd(8)} ${c.path}`);\n return;\n }\n\n const result = await promote(dest, changes, {\n ...(opts.to ? { to: opts.to } : {}),\n verify: opts.verify !== false,\n });\n\n console.log(`Promoted into ${result.targetName}:`);\n for (const l of result.landed) {\n console.log(` ${l.mode.padEnd(9)} ${l.path} → ${l.wrote}`);\n }\n console.log(\n result.verified\n ? \"Round-trip verified: the destination reproduces from the template.\"\n : \"Round-trip verification skipped (--no-verify).\",\n );\n // Guard 3 is advisory, but it is the one with consequences for other\n // people, so it goes to stderr where it will not be piped away silently.\n console.error(`\\n${result.blastRadiusWarning}`);\n },\n );\n\nprogram\n .command(\"extract\")\n .argument(\"<dest>\", \"destination directory\")\n .argument(\"[files...]\", \"files to extract\")\n .requiredOption(\"--as <path>\", \"path for the new overlay layer\")\n .option(\"--mixin\", \"wire the new layer in as a mixin\")\n .option(\"--name <name>\", \"name for the new layer's manifest\")\n .description(\"capture instance edits as a new overlay layer\")\n .action(\n async (\n dest: string,\n files: string[],\n opts: { as: string; mixin?: boolean; name?: string },\n ) => {\n const changes = await changesFor(dest, files);\n if (!changes.length) {\n console.log(\"Nothing to extract — no changes vs baseline.\");\n return;\n }\n\n const result = await extract(dest, changes, {\n as: opts.as,\n ...(opts.mixin ? { asMixin: true } : {}),\n ...(opts.name ? { name: opts.name } : {}),\n });\n\n console.log(`Extracted ${result.files.length} file(s) → ${result.layer}`);\n for (const f of result.files) console.log(` ${f}`);\n if (result.wired) {\n console.log(`Wired in as a mixin of the leaf; round-trip verified.`);\n } else {\n console.error(\n `\\nThe new layer is not wired into the graph, so these edits are still ` +\n `local. Add \"${opts.as}\" to the leaf's parents or mixins (or re-run ` +\n `with --mixin) to make them inherited.`,\n );\n }\n },\n );\n\nprogram\n .command(\"explain\")\n .argument(\"<dir>\", \"leaf overlay directory, or a compiled destination\")\n .argument(\"[file]\", \"a single output path to trace (default: every file)\")\n .option(\"--set <k=v>\", \"value used to render templated paths\", collectSet)\n .option(\"--answers <file>\", \"answers file to seed values\")\n .option(\"--json\", \"emit machine-readable JSON\")\n .description(\"trace which layers touched a file, in order\")\n .action(\n async (\n dir: string,\n file: string | undefined,\n opts: { set?: Values; answers?: string; json?: boolean },\n ) => {\n // A compiled destination explains itself from its own state (lineage +\n // saved answers); a source directory is resolved and explained directly.\n const result = hasState(dir)\n ? await explainDest(dir)\n : await explain(resolve(dir), {\n values: {\n ...(opts.answers ? loadAnswers(opts.answers) : {}),\n ...(opts.set ?? {}),\n },\n });\n\n if (opts.json) {\n const payload = file\n ? { layers: result.layers, files: pick(result.files, file) }\n : result;\n console.log(JSON.stringify(payload, null, 2));\n return;\n }\n\n console.log(formatExplanation(result, file));\n if (file && !result.files[file]) process.exit(1);\n },\n );\n\n/** Narrow an explanation's file map to a single path (empty when absent). */\nfunction pick<T>(files: Record<string, T>, path: string): Record<string, T> {\n const hit = files[path];\n return hit ? { [path]: hit } : {};\n}\n\nprogram\n .command(\"validate\")\n .argument(\"[dir]\", \"leaf overlay directory\", \".\")\n .description(\"check for cycles, failing patches, conflicts, lock drift\")\n .action(() => notImplemented(\"validate\"));\n\nprogram\n .command(\"watch\")\n .argument(\"<src>\", \"leaf overlay directory\")\n .argument(\"<dest>\", \"destination directory\")\n .description(\"recompile on change\")\n .action(() => notImplemented(\"watch\"));\n\nprogram\n .command(\"eject\")\n .argument(\"<dest>\", \"destination directory\")\n .description(\"flatten and drop .treelay state (sever the template link)\")\n .action(() => notImplemented(\"eject\"));\n\nfunction notImplemented(cmd: string): never {\n console.error(`treelay ${cmd}: not implemented yet (see SPEC.md §12 build order)`);\n process.exit(2);\n}\n\nprogram.parseAsync().catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : err);\n process.exit(1);\n});\n"],"mappings":"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","names":[]}
|