@prestyj/cli 5.23.0 → 5.25.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/README.md +1 -1
- package/assets/skills/evidence-led-ui/SKILL.md +13 -2
- package/assets/skills/evidence-led-ui/references/craft-rulings.md +46 -4
- package/assets/skills/evidence-led-ui/references/production-contract.md +2 -2
- package/assets/skills/evidence-led-ui/references/quality-rubric.md +3 -3
- package/assets/skills/evidence-led-ui/references/ui-libraries.md +30 -0
- package/dist/app-sidecar.js +20 -8
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.js +8 -8
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.js +4 -4
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.js +2 -2
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts +7 -3
- package/dist/core/compaction/compactor.js +10 -4
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/policy.d.ts +2 -0
- package/dist/core/compaction/policy.js +61 -2
- package/dist/core/compaction/policy.js.map +1 -1
- package/dist/core/sandbox.js +4 -6
- package/dist/core/sandbox.js.map +1 -1
- package/dist/core/temp-paths.d.ts +5 -0
- package/dist/core/temp-paths.js +50 -0
- package/dist/core/temp-paths.js.map +1 -0
- package/dist/core/ui-adoption.d.ts +32 -0
- package/dist/core/ui-adoption.js +300 -0
- package/dist/core/ui-adoption.js.map +1 -0
- package/dist/core/ui-compatibility.d.ts +10 -0
- package/dist/core/ui-compatibility.js +51 -0
- package/dist/core/ui-compatibility.js.map +1 -0
- package/dist/core/ui-registry.d.ts +101 -0
- package/dist/core/ui-registry.js +291 -0
- package/dist/core/ui-registry.js.map +1 -0
- package/dist/core/workspace-guard.js +2 -1
- package/dist/core/workspace-guard.js.map +1 -1
- package/dist/core/worktree-setup.d.ts +59 -0
- package/dist/core/worktree-setup.js +224 -0
- package/dist/core/worktree-setup.js.map +1 -0
- package/dist/core/worktree.d.ts +19 -5
- package/dist/core/worktree.js +14 -11
- package/dist/core/worktree.js.map +1 -1
- package/dist/interactive.js +2 -1
- package/dist/interactive.js.map +1 -1
- package/dist/modes/acp-images.d.ts +10 -0
- package/dist/modes/acp-images.js +43 -0
- package/dist/modes/acp-images.js.map +1 -0
- package/dist/modes/acp-mode.js +8 -3
- package/dist/modes/acp-mode.js.map +1 -1
- package/dist/tools/index.js +11 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/path-utils.d.ts +4 -7
- package/dist/tools/path-utils.js +12 -7
- package/dist/tools/path-utils.js.map +1 -1
- package/dist/tools/prompt-hints.js +7 -3
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/steroids.d.ts +1 -1
- package/dist/tools/subagent.js +17 -0
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/tool-tiers.js +2 -0
- package/dist/tools/tool-tiers.js.map +1 -1
- package/dist/tools/ui-adopt.d.ts +16 -0
- package/dist/tools/ui-adopt.js +64 -0
- package/dist/tools/ui-adopt.js.map +1 -0
- package/dist/tools/ui-registry.d.ts +15 -0
- package/dist/tools/ui-registry.js +39 -0
- package/dist/tools/ui-registry.js.map +1 -0
- package/dist/ui/components/Footer.js +2 -1
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/hooks/useContextCompaction.js +10 -1
- package/dist/ui/hooks/useContextCompaction.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUrlPolicy } from "./network-guard.js";
|
|
4
|
+
export const UI_PROVIDERS = {
|
|
5
|
+
bklit: {
|
|
6
|
+
repo: "bklit/bklit-ui",
|
|
7
|
+
revision: "0dfdfc57ca068470ccfb93c4501cebc555c9054d",
|
|
8
|
+
manifest: "packages/ui/registry.json",
|
|
9
|
+
root: "https://ui.bklit.com/r/",
|
|
10
|
+
},
|
|
11
|
+
kokonut: {
|
|
12
|
+
repo: "kokonut-labs/kokonutui",
|
|
13
|
+
revision: "83eec6d982d400a18438001a8efdbac1f159dd43",
|
|
14
|
+
manifest: "registry.json",
|
|
15
|
+
root: "https://kokonutui.com/r/",
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const slug = z.string().regex(/^[a-z0-9][a-z0-9-]{0,99}$/);
|
|
19
|
+
const fileSchema = z
|
|
20
|
+
.object({
|
|
21
|
+
path: z.string().max(240),
|
|
22
|
+
type: z.string().optional(),
|
|
23
|
+
target: z.string().max(240).optional(),
|
|
24
|
+
content: z.string().max(500000).optional(),
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
const itemSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
name: slug,
|
|
30
|
+
type: z.enum([
|
|
31
|
+
"registry:component",
|
|
32
|
+
"registry:block",
|
|
33
|
+
"registry:example",
|
|
34
|
+
"registry:hook",
|
|
35
|
+
"registry:lib",
|
|
36
|
+
"registry:ui",
|
|
37
|
+
"registry:style",
|
|
38
|
+
"registry:theme",
|
|
39
|
+
"registry:file",
|
|
40
|
+
]),
|
|
41
|
+
title: z.string().optional(),
|
|
42
|
+
description: z.string().optional(),
|
|
43
|
+
files: z.array(fileSchema).max(150),
|
|
44
|
+
dependencies: z.array(z.string().max(300)).max(100).optional(),
|
|
45
|
+
devDependencies: z.array(z.string().max(300)).max(100).optional(),
|
|
46
|
+
registryDependencies: z.array(z.string().max(300)).max(100).optional(),
|
|
47
|
+
css: z.record(z.string(), z.unknown()).optional(),
|
|
48
|
+
cssVars: z.record(z.string(), z.unknown()).optional(),
|
|
49
|
+
meta: z.record(z.string(), z.unknown()).optional(),
|
|
50
|
+
categories: z.array(z.string()).optional(),
|
|
51
|
+
docs: z.string().optional(),
|
|
52
|
+
author: z.string().optional(),
|
|
53
|
+
$schema: z.string().optional(),
|
|
54
|
+
tailwind: z.record(z.string(), z.unknown()).optional(),
|
|
55
|
+
})
|
|
56
|
+
.strict();
|
|
57
|
+
export const payloadHash = (text) => createHash("sha256").update(text).digest("hex");
|
|
58
|
+
export function registryPath(value) {
|
|
59
|
+
// A leading slash in hosted source paths is a registry convention, not an absolute target.
|
|
60
|
+
const normalized = value.replace(/^\//, "");
|
|
61
|
+
if (!normalized ||
|
|
62
|
+
!/^(?:[a-zA-Z0-9_@().-]+\/)*[a-zA-Z0-9_@().-]+$/.test(normalized) ||
|
|
63
|
+
normalized.split("/").some((p) => p === "." || p === ".."))
|
|
64
|
+
throw new Error("Invalid registry path");
|
|
65
|
+
return normalized;
|
|
66
|
+
}
|
|
67
|
+
export function registryUrl(value) {
|
|
68
|
+
const url = new URL(value);
|
|
69
|
+
if (url.protocol !== "https:" ||
|
|
70
|
+
url.port ||
|
|
71
|
+
url.username ||
|
|
72
|
+
url.password ||
|
|
73
|
+
url.search ||
|
|
74
|
+
url.hash ||
|
|
75
|
+
/%|\\/.test(value))
|
|
76
|
+
throw new Error("Blocked registry URL");
|
|
77
|
+
const allowed = Object.values(UI_PROVIDERS).some((p) => url.href === `https://raw.githubusercontent.com/${p.repo}/${p.revision}/${p.manifest}` ||
|
|
78
|
+
url.href === `https://raw.githubusercontent.com/${p.repo}/${p.revision}/LICENSE` ||
|
|
79
|
+
(url.href.startsWith(p.root) && /^[a-z0-9-]+\.json$/.test(url.href.slice(p.root.length))));
|
|
80
|
+
if (!allowed &&
|
|
81
|
+
!(url.hostname === "ui.shadcn.com" &&
|
|
82
|
+
/^\/r\/styles\/new-york\/[a-z0-9-]+\.json$/.test(url.pathname)))
|
|
83
|
+
throw new Error("Blocked registry host/path");
|
|
84
|
+
return url;
|
|
85
|
+
}
|
|
86
|
+
export function registryKey(value) {
|
|
87
|
+
if (/^(bklit|kokonut|shadcn):/.test(value)) {
|
|
88
|
+
const [provider, name, extra] = value.split(":");
|
|
89
|
+
if (extra !== undefined)
|
|
90
|
+
throw new Error("Invalid item ID");
|
|
91
|
+
return `${provider}:${slug.parse(name)}`;
|
|
92
|
+
}
|
|
93
|
+
if (value.startsWith("@bklit/"))
|
|
94
|
+
return `bklit:${slug.parse(value.slice(7))}`;
|
|
95
|
+
if (value.startsWith("@kokonutui/"))
|
|
96
|
+
return `kokonut:${slug.parse(value.slice(11))}`;
|
|
97
|
+
if (value.startsWith("https://")) {
|
|
98
|
+
const url = registryUrl(value);
|
|
99
|
+
for (const [provider, p] of Object.entries(UI_PROVIDERS)) {
|
|
100
|
+
if (url.href.startsWith(p.root))
|
|
101
|
+
return `${provider}:${slug.parse(url.pathname.slice(3, -5))}`;
|
|
102
|
+
}
|
|
103
|
+
if (url.hostname === "ui.shadcn.com")
|
|
104
|
+
return `shadcn:${slug.parse(url.pathname.split("/").at(-1).slice(0, -5))}`;
|
|
105
|
+
throw new Error("Not an item URL");
|
|
106
|
+
}
|
|
107
|
+
return `shadcn:${slug.parse(value)}`;
|
|
108
|
+
}
|
|
109
|
+
export function validateRegistryItem(input, source = false) {
|
|
110
|
+
const item = itemSchema.parse(input);
|
|
111
|
+
const seen = new Set();
|
|
112
|
+
for (const file of item.files) {
|
|
113
|
+
const key = registryPath(file.path);
|
|
114
|
+
if (seen.has(key))
|
|
115
|
+
throw new Error("Duplicate registry source path");
|
|
116
|
+
seen.add(key);
|
|
117
|
+
if (file.target)
|
|
118
|
+
registryPath(file.target);
|
|
119
|
+
if (source && (file.content === undefined || Buffer.byteLength(file.content) > 500000))
|
|
120
|
+
throw new Error("Missing or oversized registry source");
|
|
121
|
+
}
|
|
122
|
+
return item;
|
|
123
|
+
}
|
|
124
|
+
export function resolveRegistryFile(source, selector) {
|
|
125
|
+
const matches = source.item.files.filter((file, index) => selector === `${source.id}#${index}` ||
|
|
126
|
+
registryPath(file.path) === selector.replace(/^\//, "") ||
|
|
127
|
+
(file.target && registryPath(file.target) === selector.replace(/^\//, "")));
|
|
128
|
+
if (matches.length !== 1)
|
|
129
|
+
throw new Error(`File selector matched ${matches.length} files; use a stable item#file-index ID`);
|
|
130
|
+
return matches[0];
|
|
131
|
+
}
|
|
132
|
+
export const MOTION_GUIDANCE = {
|
|
133
|
+
kind: "animation-api",
|
|
134
|
+
package: "motion",
|
|
135
|
+
import: "motion/react",
|
|
136
|
+
documentation: "https://motion.dev/docs/react",
|
|
137
|
+
guidance: "Use motion elements for declarative animation, AnimatePresence for exit transitions, useReducedMotion for user preferences, and useAnimate for scoped imperative animation. Hooks need real consumers. Preserve callbacks, keyboard semantics and teardown; do not mix competing animation owners. Check installed version before selecting APIs. Motion+ paid assets are excluded.",
|
|
138
|
+
families: [
|
|
139
|
+
"animate",
|
|
140
|
+
"exit",
|
|
141
|
+
"layout",
|
|
142
|
+
"gestures",
|
|
143
|
+
"scroll",
|
|
144
|
+
"drag",
|
|
145
|
+
"variants",
|
|
146
|
+
"spring",
|
|
147
|
+
"motion-values",
|
|
148
|
+
"transforms",
|
|
149
|
+
"reduced-motion",
|
|
150
|
+
"imperative",
|
|
151
|
+
"presence",
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
/** Lazy, bounded per-session cache; every fetch and redirect respects current network policy. */
|
|
155
|
+
export class UiRegistry {
|
|
156
|
+
getNetworkPolicy;
|
|
157
|
+
fetcher;
|
|
158
|
+
cache = new Map();
|
|
159
|
+
cacheBytes = 0;
|
|
160
|
+
constructor(getNetworkPolicy, fetcher = fetch) {
|
|
161
|
+
this.getNetworkPolicy = getNetworkPolicy;
|
|
162
|
+
this.fetcher = fetcher;
|
|
163
|
+
}
|
|
164
|
+
async fetchText(value, signal) {
|
|
165
|
+
let url = registryUrl(value);
|
|
166
|
+
const combined = AbortSignal.any([AbortSignal.timeout(20000), ...(signal ? [signal] : [])]);
|
|
167
|
+
for (let redirects = 0; redirects < 4; redirects++) {
|
|
168
|
+
combined.throwIfAborted();
|
|
169
|
+
const blocked = checkUrlPolicy(url.href, this.getNetworkPolicy);
|
|
170
|
+
if (blocked)
|
|
171
|
+
throw new Error(blocked);
|
|
172
|
+
const cached = this.cache.get(url.href);
|
|
173
|
+
if (cached)
|
|
174
|
+
return cached;
|
|
175
|
+
const response = await this.fetcher(url, { redirect: "manual", signal: combined });
|
|
176
|
+
if ([301, 302, 303, 307, 308].includes(response.status)) {
|
|
177
|
+
await response.body?.cancel();
|
|
178
|
+
const location = response.headers.get("location");
|
|
179
|
+
if (!location)
|
|
180
|
+
throw new Error("Registry redirect missing location");
|
|
181
|
+
url = registryUrl(new URL(location, url).href);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (!response.ok || !response.body) {
|
|
185
|
+
await response.body?.cancel();
|
|
186
|
+
throw new Error(`Registry HTTP ${response.status}`);
|
|
187
|
+
}
|
|
188
|
+
const reader = response.body.getReader();
|
|
189
|
+
const chunks = [];
|
|
190
|
+
let size = 0;
|
|
191
|
+
try {
|
|
192
|
+
for (;;) {
|
|
193
|
+
combined.throwIfAborted();
|
|
194
|
+
const { value: chunk, done } = await reader.read();
|
|
195
|
+
if (done)
|
|
196
|
+
break;
|
|
197
|
+
size += chunk.byteLength;
|
|
198
|
+
if (size > 3000000)
|
|
199
|
+
throw new Error("Registry payload exceeds 3 MB");
|
|
200
|
+
chunks.push(chunk);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await reader.cancel();
|
|
205
|
+
reader.releaseLock();
|
|
206
|
+
}
|
|
207
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
208
|
+
const result = { text, url: url.href, hash: payloadHash(text) };
|
|
209
|
+
while (this.cache.size >= 32 || this.cacheBytes + size > 12000000) {
|
|
210
|
+
const oldest = this.cache.keys().next().value;
|
|
211
|
+
if (!oldest)
|
|
212
|
+
break;
|
|
213
|
+
this.cacheBytes -= Buffer.byteLength(this.cache.get(oldest).text);
|
|
214
|
+
this.cache.delete(oldest);
|
|
215
|
+
}
|
|
216
|
+
this.cache.set(url.href, result);
|
|
217
|
+
this.cacheBytes += Buffer.byteLength(text);
|
|
218
|
+
return result;
|
|
219
|
+
}
|
|
220
|
+
throw new Error("Registry redirect limit");
|
|
221
|
+
}
|
|
222
|
+
async search(query = "", signal) {
|
|
223
|
+
const results = [];
|
|
224
|
+
for (const [provider, p] of Object.entries(UI_PROVIDERS)) {
|
|
225
|
+
const raw = await this.fetchText(`https://raw.githubusercontent.com/${p.repo}/${p.revision}/${p.manifest}`, signal);
|
|
226
|
+
const manifest = JSON.parse(raw.text);
|
|
227
|
+
const parsed = z.object({ items: z.array(z.unknown()).max(220) }).parse(manifest);
|
|
228
|
+
for (const value of parsed.items) {
|
|
229
|
+
const item = validateRegistryItem(value);
|
|
230
|
+
if (`${item.name} ${item.title ?? ""} ${item.description ?? ""}`
|
|
231
|
+
.toLowerCase()
|
|
232
|
+
.includes(query.toLowerCase())) {
|
|
233
|
+
results.push({
|
|
234
|
+
id: `${provider}:${item.name}`,
|
|
235
|
+
name: item.name,
|
|
236
|
+
description: item.description,
|
|
237
|
+
type: item.type,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return results;
|
|
243
|
+
}
|
|
244
|
+
async inspect(value, signal) {
|
|
245
|
+
const id = registryKey(value);
|
|
246
|
+
const [provider, name] = id.split(":");
|
|
247
|
+
const p = UI_PROVIDERS[provider];
|
|
248
|
+
const url = p
|
|
249
|
+
? `${p.root}${name}.json`
|
|
250
|
+
: `https://ui.shadcn.com/r/styles/new-york/${name}.json`;
|
|
251
|
+
const raw = await this.fetchText(url, signal);
|
|
252
|
+
const item = validateRegistryItem(JSON.parse(raw.text), true);
|
|
253
|
+
if (item.name !== name)
|
|
254
|
+
throw new Error("Registry name mismatch");
|
|
255
|
+
return {
|
|
256
|
+
id,
|
|
257
|
+
item,
|
|
258
|
+
url: raw.url,
|
|
259
|
+
payloadHash: raw.hash,
|
|
260
|
+
inventoryRevision: p?.revision,
|
|
261
|
+
hostedMatchesRevision: "not-verified",
|
|
262
|
+
dependencies: (item.registryDependencies ?? []).map(registryKey),
|
|
263
|
+
attribution: p
|
|
264
|
+
? `Public ${provider} source: https://github.com/${p.repo}; preserve notices. License: https://raw.githubusercontent.com/${p.repo}/${p.revision}/LICENSE. Review dependency licenses separately (including Iconists); public availability is not a license grant. Paid assets excluded.`
|
|
265
|
+
: "shadcn/ui supporting registry source; preserve notices and verify dependency licenses.",
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
async closure(value, signal) {
|
|
269
|
+
const result = [];
|
|
270
|
+
const active = new Set();
|
|
271
|
+
const seen = new Set();
|
|
272
|
+
const visit = async (id, depth) => {
|
|
273
|
+
if (active.has(id))
|
|
274
|
+
throw new Error("Registry dependency cycle");
|
|
275
|
+
if (seen.has(id))
|
|
276
|
+
return;
|
|
277
|
+
if (depth > 16 || seen.size >= 180)
|
|
278
|
+
throw new Error("Registry graph limit");
|
|
279
|
+
seen.add(id);
|
|
280
|
+
active.add(id);
|
|
281
|
+
const source = await this.inspect(id, signal);
|
|
282
|
+
for (const dependency of source.dependencies)
|
|
283
|
+
await visit(dependency, depth + 1);
|
|
284
|
+
active.delete(id);
|
|
285
|
+
result.push(source);
|
|
286
|
+
};
|
|
287
|
+
await visit(registryKey(value), 0);
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=ui-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-registry.js","sourceRoot":"","sources":["../../src/core/ui-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { realpathSync } from "node:fs";
|
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { getAppPaths } from "../config.js";
|
|
5
|
+
import { getTempRoots } from "./temp-paths.js";
|
|
5
6
|
/** True when `target` is `root` or contained within it. */
|
|
6
7
|
function isWithin(root, target) {
|
|
7
8
|
const relative = path.relative(root, target);
|
|
@@ -66,7 +67,7 @@ export function resolveWriteGuard(cwd, resolvedPath, settings) {
|
|
|
66
67
|
const allowedRoots = [
|
|
67
68
|
realResolve(cwd),
|
|
68
69
|
...extraRoots,
|
|
69
|
-
|
|
70
|
+
...getTempRoots().map(realResolve),
|
|
70
71
|
realResolve(getAppPaths().agentDir),
|
|
71
72
|
];
|
|
72
73
|
for (const root of allowedRoots) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-guard.js","sourceRoot":"","sources":["../../src/core/workspace-guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"workspace-guard.js","sourceRoot":"","sources":["../../src/core/workspace-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy allowlisted ignored config from the main checkout into a fresh worktree.
|
|
3
|
+
* Returns the repo-relative paths actually copied.
|
|
4
|
+
*
|
|
5
|
+
* Never throws: a worktree that exists but lacks its `.env` is still a worktree,
|
|
6
|
+
* and failing the creation over a copy would be a worse outcome than reporting
|
|
7
|
+
* what is missing.
|
|
8
|
+
*/
|
|
9
|
+
export declare function carryIgnoredConfig(mainRoot: string, worktreePath: string): Promise<string[]>;
|
|
10
|
+
export interface InstallCommand {
|
|
11
|
+
command: string;
|
|
12
|
+
args: string[];
|
|
13
|
+
}
|
|
14
|
+
/** Human-readable form, for logs and for telling the user what ran. */
|
|
15
|
+
export declare function formatCommand(cmd: InstallCommand): string;
|
|
16
|
+
/**
|
|
17
|
+
* The install command(s) this project uses, chosen by lockfile.
|
|
18
|
+
*
|
|
19
|
+
* Lockfile over `packageManager` field or heuristics: the lockfile is what the
|
|
20
|
+
* project actually installs with, and picking the wrong package manager in a
|
|
21
|
+
* copy produces a second lockfile as an unexplained diff.
|
|
22
|
+
*
|
|
23
|
+
* `install` rather than `ci`/`--frozen-lockfile`: this is a private copy of a
|
|
24
|
+
* tree the user is mid-edit on, where a lockfile that no longer matches
|
|
25
|
+
* `package.json` is normal. A frozen install would hard-fail on exactly that.
|
|
26
|
+
*/
|
|
27
|
+
export declare function detectInstallCommands(dir: string): Promise<InstallCommand[]>;
|
|
28
|
+
export interface InstallResult {
|
|
29
|
+
command: string;
|
|
30
|
+
ok: boolean;
|
|
31
|
+
/** Why it failed, trimmed to the tail that names the cause. Set when !ok. */
|
|
32
|
+
message?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface WorktreePreparation {
|
|
35
|
+
/** Repo-relative ignored config files copied into the copy. */
|
|
36
|
+
carried: string[];
|
|
37
|
+
/** One entry per install command attempted, in order. */
|
|
38
|
+
installs: InstallResult[];
|
|
39
|
+
/** Everything attempted succeeded. False when any install failed. */
|
|
40
|
+
ok: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface PrepareWorktreeOptions {
|
|
43
|
+
mainRoot: string;
|
|
44
|
+
worktreePath: string;
|
|
45
|
+
/** Skip the install step (carry only). */
|
|
46
|
+
skipInstall?: boolean;
|
|
47
|
+
/** Per-command cap. Default 10 minutes — a cold monorepo install is slow. */
|
|
48
|
+
timeoutMs?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Carry ignored config, then install dependencies, so the new copy can build
|
|
52
|
+
* and test without the user setting it up by hand.
|
|
53
|
+
*
|
|
54
|
+
* Never throws and never undoes the worktree: a copy with a failed install is
|
|
55
|
+
* still a copy the user can fix, and reporting the failure beats destroying the
|
|
56
|
+
* branch it sits on. Callers surface `installs[].message` rather than treating
|
|
57
|
+
* it as an error.
|
|
58
|
+
*/
|
|
59
|
+
export declare function prepareWorktree(opts: PrepareWorktreeOptions): Promise<WorktreePreparation>;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { log } from "./logger.js";
|
|
6
|
+
const exec = promisify(execFile);
|
|
7
|
+
/**
|
|
8
|
+
* Make a fresh worktree usable, not merely present.
|
|
9
|
+
*
|
|
10
|
+
* `git worktree add` checks out TRACKED files only, so a new copy is missing
|
|
11
|
+
* exactly the things a repo deliberately keeps out of git: `.env`, registry
|
|
12
|
+
* credentials, installed packages. The copy looks fine and then nothing runs in
|
|
13
|
+
* it — which, for an agent working unattended in that copy, reads as a broken
|
|
14
|
+
* project rather than a missing setup step.
|
|
15
|
+
*
|
|
16
|
+
* Two steps close that gap: carry a small allowlist of ignored CONFIG files
|
|
17
|
+
* across, then run the project's own install command.
|
|
18
|
+
*/
|
|
19
|
+
/** Cap on a carried file. Config is tiny; anything larger is data, not config. */
|
|
20
|
+
const CARRY_MAX_BYTES = 64 * 1024;
|
|
21
|
+
/**
|
|
22
|
+
* Basenames worth carrying, matched against ignored files only.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately an allowlist. The inverse — "copy every ignored file under some
|
|
25
|
+
* size" — sweeps up local databases, key material, scratch notes and editor
|
|
26
|
+
* state, and silently multiplies copies of whatever secret happens to sit in
|
|
27
|
+
* the repo. These are the files whose ABSENCE breaks a build:
|
|
28
|
+
* - `.env` and friends: the app's own configuration.
|
|
29
|
+
* - `.npmrc` / `.yarnrc`: private-registry auth, needed BY the install below,
|
|
30
|
+
* which is why the carry runs first.
|
|
31
|
+
*/
|
|
32
|
+
const CARRY_PATTERNS = [
|
|
33
|
+
/^\.env($|\.)/i, // .env, .env.local, .env.development…
|
|
34
|
+
/\.env$/i, // local.env, test.env…
|
|
35
|
+
/^\.npmrc$/i,
|
|
36
|
+
/^\.yarnrc(\.yml)?$/i,
|
|
37
|
+
];
|
|
38
|
+
function isCarryable(basename) {
|
|
39
|
+
return CARRY_PATTERNS.some((re) => re.test(basename));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Pure: is `candidate` inside `root`? Same reasoning as the worktree module's
|
|
43
|
+
* containment check — `path.relative`, never `startsWith`.
|
|
44
|
+
*/
|
|
45
|
+
function isInside(root, candidate) {
|
|
46
|
+
const rel = path.relative(path.resolve(root), path.resolve(candidate));
|
|
47
|
+
return Boolean(rel) && !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ignored files git knows about, as repo-relative paths.
|
|
51
|
+
*
|
|
52
|
+
* `--directory` collapses a wholly-ignored directory to a single `dir/` entry
|
|
53
|
+
* instead of listing its contents, which is what keeps `node_modules` from
|
|
54
|
+
* arriving here as 40,000 paths. Entries ending in `/` are those directories
|
|
55
|
+
* and are dropped: package trees get installed below, not copied.
|
|
56
|
+
*/
|
|
57
|
+
async function listIgnoredFiles(mainRoot) {
|
|
58
|
+
const { stdout } = await exec("git", ["ls-files", "--others", "--ignored", "--exclude-standard", "--directory", "-z"], {
|
|
59
|
+
cwd: mainRoot,
|
|
60
|
+
timeout: 15_000,
|
|
61
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
62
|
+
env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" },
|
|
63
|
+
});
|
|
64
|
+
return stdout.split("\0").filter((entry) => entry && !entry.endsWith("/"));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Copy allowlisted ignored config from the main checkout into a fresh worktree.
|
|
68
|
+
* Returns the repo-relative paths actually copied.
|
|
69
|
+
*
|
|
70
|
+
* Never throws: a worktree that exists but lacks its `.env` is still a worktree,
|
|
71
|
+
* and failing the creation over a copy would be a worse outcome than reporting
|
|
72
|
+
* what is missing.
|
|
73
|
+
*/
|
|
74
|
+
export async function carryIgnoredConfig(mainRoot, worktreePath) {
|
|
75
|
+
let entries;
|
|
76
|
+
try {
|
|
77
|
+
entries = await listIgnoredFiles(mainRoot);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
log("INFO", "worktree-setup", "could not list ignored files", { message: messageOf(err) });
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const carried = [];
|
|
84
|
+
for (const rel of entries) {
|
|
85
|
+
if (!isCarryable(path.basename(rel)))
|
|
86
|
+
continue;
|
|
87
|
+
// git reports paths relative to the repo root, but a path arriving from a
|
|
88
|
+
// subprocess is still input: a `..` segment or an absolute entry must not
|
|
89
|
+
// be able to read outside the checkout or write outside the worktree.
|
|
90
|
+
const from = path.resolve(mainRoot, rel);
|
|
91
|
+
const to = path.resolve(worktreePath, rel);
|
|
92
|
+
if (!isInside(mainRoot, from) || !isInside(worktreePath, to))
|
|
93
|
+
continue;
|
|
94
|
+
try {
|
|
95
|
+
// lstat, not stat: a symlink is followed by copyFile, so a link pointing
|
|
96
|
+
// at /etc/passwd or a 2GB file would be copied as its target. Only real,
|
|
97
|
+
// small, regular files qualify.
|
|
98
|
+
const stat = await fs.lstat(from);
|
|
99
|
+
if (!stat.isFile() || stat.size > CARRY_MAX_BYTES)
|
|
100
|
+
continue;
|
|
101
|
+
await fs.mkdir(path.dirname(to), { recursive: true });
|
|
102
|
+
// COPYFILE_EXCL: never clobber a file the checkout already produced.
|
|
103
|
+
await fs.copyFile(from, to, fs.constants.COPYFILE_EXCL);
|
|
104
|
+
carried.push(rel);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
log("INFO", "worktree-setup", "could not carry file", { rel, message: messageOf(err) });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return carried;
|
|
111
|
+
}
|
|
112
|
+
/** Human-readable form, for logs and for telling the user what ran. */
|
|
113
|
+
export function formatCommand(cmd) {
|
|
114
|
+
return [cmd.command, ...cmd.args].join(" ");
|
|
115
|
+
}
|
|
116
|
+
async function exists(p) {
|
|
117
|
+
try {
|
|
118
|
+
await fs.lstat(p);
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The install command(s) this project uses, chosen by lockfile.
|
|
127
|
+
*
|
|
128
|
+
* Lockfile over `packageManager` field or heuristics: the lockfile is what the
|
|
129
|
+
* project actually installs with, and picking the wrong package manager in a
|
|
130
|
+
* copy produces a second lockfile as an unexplained diff.
|
|
131
|
+
*
|
|
132
|
+
* `install` rather than `ci`/`--frozen-lockfile`: this is a private copy of a
|
|
133
|
+
* tree the user is mid-edit on, where a lockfile that no longer matches
|
|
134
|
+
* `package.json` is normal. A frozen install would hard-fail on exactly that.
|
|
135
|
+
*/
|
|
136
|
+
export async function detectInstallCommands(dir) {
|
|
137
|
+
const cmds = [];
|
|
138
|
+
const has = (name) => exists(path.join(dir, name));
|
|
139
|
+
if (await has("pnpm-lock.yaml"))
|
|
140
|
+
cmds.push({ command: "pnpm", args: ["install"] });
|
|
141
|
+
else if (await has("yarn.lock"))
|
|
142
|
+
cmds.push({ command: "yarn", args: ["install"] });
|
|
143
|
+
else if ((await has("bun.lockb")) || (await has("bun.lock")))
|
|
144
|
+
cmds.push({ command: "bun", args: ["install"] });
|
|
145
|
+
else if ((await has("package-lock.json")) || (await has("package.json")))
|
|
146
|
+
cmds.push({ command: "npm", args: ["install"] });
|
|
147
|
+
// Python projects whose environment lives in an ignored directory have the
|
|
148
|
+
// same problem as node_modules. Cargo and Go are absent on purpose: they
|
|
149
|
+
// fetch on first build, so there is nothing useful to pre-run.
|
|
150
|
+
if (await has("uv.lock"))
|
|
151
|
+
cmds.push({ command: "uv", args: ["sync"] });
|
|
152
|
+
else if (await has("poetry.lock"))
|
|
153
|
+
cmds.push({ command: "poetry", args: ["install"] });
|
|
154
|
+
return cmds;
|
|
155
|
+
}
|
|
156
|
+
/** Last `limit` characters of the output that actually says what went wrong. */
|
|
157
|
+
function tail(text, limit = 600) {
|
|
158
|
+
const trimmed = text.trim();
|
|
159
|
+
return trimmed.length <= limit ? trimmed : `…${trimmed.slice(-limit)}`;
|
|
160
|
+
}
|
|
161
|
+
function messageOf(err) {
|
|
162
|
+
return err instanceof Error ? err.message : String(err);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Run one install in `dir`. Argument array, never a shell string: the command
|
|
166
|
+
* is chosen from a fixed table above, and keeping it unparsed means a repo path
|
|
167
|
+
* containing shell metacharacters stays a path.
|
|
168
|
+
*/
|
|
169
|
+
async function runInstall(dir, cmd, timeoutMs) {
|
|
170
|
+
const label = formatCommand(cmd);
|
|
171
|
+
try {
|
|
172
|
+
await exec(cmd.command, cmd.args, {
|
|
173
|
+
cwd: dir,
|
|
174
|
+
timeout: timeoutMs,
|
|
175
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
176
|
+
// Inherit the enriched PATH the sidecar builds at startup, otherwise a
|
|
177
|
+
// GUI-launched app cannot find pnpm/uv at all.
|
|
178
|
+
env: process.env,
|
|
179
|
+
});
|
|
180
|
+
return { command: label, ok: true };
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
const stderr = err.stderr ?? "";
|
|
184
|
+
const stdout = err.stdout ?? "";
|
|
185
|
+
const killed = err.killed === true;
|
|
186
|
+
const detail = killed
|
|
187
|
+
? `it did not finish within ${Math.round(timeoutMs / 1000)}s`
|
|
188
|
+
: tail(stderr || stdout || messageOf(err));
|
|
189
|
+
return { command: label, ok: false, message: detail };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Carry ignored config, then install dependencies, so the new copy can build
|
|
194
|
+
* and test without the user setting it up by hand.
|
|
195
|
+
*
|
|
196
|
+
* Never throws and never undoes the worktree: a copy with a failed install is
|
|
197
|
+
* still a copy the user can fix, and reporting the failure beats destroying the
|
|
198
|
+
* branch it sits on. Callers surface `installs[].message` rather than treating
|
|
199
|
+
* it as an error.
|
|
200
|
+
*/
|
|
201
|
+
export async function prepareWorktree(opts) {
|
|
202
|
+
const { mainRoot, worktreePath } = opts;
|
|
203
|
+
const timeoutMs = opts.timeoutMs ?? 10 * 60_000;
|
|
204
|
+
const carried = await carryIgnoredConfig(mainRoot, worktreePath);
|
|
205
|
+
if (opts.skipInstall)
|
|
206
|
+
return { carried, installs: [], ok: true };
|
|
207
|
+
const installs = [];
|
|
208
|
+
for (const cmd of await detectInstallCommands(worktreePath)) {
|
|
209
|
+
const result = await runInstall(worktreePath, cmd, timeoutMs);
|
|
210
|
+
installs.push(result);
|
|
211
|
+
// Stop at the first failure: a later command in the same copy will almost
|
|
212
|
+
// always fail for the same reason, and one clear message beats three.
|
|
213
|
+
if (!result.ok)
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
const ok = installs.every((r) => r.ok);
|
|
217
|
+
log(ok ? "INFO" : "WARN", "worktree-setup", "prepared worktree", {
|
|
218
|
+
worktreePath,
|
|
219
|
+
carried: carried.length,
|
|
220
|
+
installs: installs.map((r) => `${r.command}${r.ok ? "" : " (failed)"}`),
|
|
221
|
+
});
|
|
222
|
+
return { carried, installs, ok };
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=worktree-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-setup.js","sourceRoot":"","sources":["../../src/core/worktree-setup.ts"],"names":[],"mappings":"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"}
|