@dadado/agent-kit-cli 5.15.1 → 5.17.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/dashboard/dashboard-data.mjs +69 -65
- package/dashboard/lib/guards.d.mts +5 -0
- package/dashboard/lib/guards.mjs +31 -0
- package/dashboard/lib/identity-probe.mjs +56 -0
- package/dashboard/lib/pipeline-cache.mjs +58 -0
- package/dashboard/lib/processes.mjs +71 -0
- package/dashboard/serve.mjs +43 -1
- package/dashboard/start-broadcast.mjs +2 -12
- package/dashboard/start.mjs +2 -13
- package/dist/add-HTYIFKMN.js +150 -0
- package/dist/chunk-2IPXQFJE.js +253 -0
- package/dist/chunk-2RDRMGD3.js +82 -0
- package/dist/chunk-2YU2H7I6.js +42 -0
- package/dist/chunk-4IWG5CVE.js +214 -0
- package/dist/chunk-5VCOWTTP.js +6 -0
- package/dist/chunk-77V75A7O.js +39 -0
- package/dist/chunk-7HDQEK6T.js +26 -0
- package/dist/chunk-AW74INUW.js +1456 -0
- package/dist/chunk-B73KQ5KX.js +972 -0
- package/dist/chunk-CBCW5R5J.js +484 -0
- package/dist/chunk-DE3LQFSJ.js +18 -0
- package/dist/chunk-DQA434Y4.js +106 -0
- package/dist/chunk-F4VMYR7U.js +318 -0
- package/dist/chunk-F6C3GFKV.js +57 -0
- package/dist/chunk-HFUH3HVS.js +282 -0
- package/dist/chunk-HS7LVVLO.js +74 -0
- package/dist/chunk-IHROBTNM.js +135 -0
- package/dist/chunk-KD2MYBB6.js +213 -0
- package/dist/chunk-MAPOQEA2.js +43 -0
- package/dist/chunk-N3HTJVBR.js +341 -0
- package/dist/chunk-NQ7IQ5XT.js +26 -0
- package/dist/chunk-OUQZC744.js +1315 -0
- package/dist/chunk-PCCQUWE5.js +817 -0
- package/dist/chunk-PNFF6OU3.js +273 -0
- package/dist/chunk-PNG7LO2F.js +53 -0
- package/dist/chunk-QTON2GQX.js +203 -0
- package/dist/chunk-S6GMFDKV.js +50 -0
- package/dist/chunk-SMGFN3Z4.js +503 -0
- package/dist/chunk-STGFBAYT.js +641 -0
- package/dist/chunk-TFZ2JUXH.js +1081 -0
- package/dist/chunk-VY7MTPJ2.js +205 -0
- package/dist/chunk-W24CMQ32.js +525 -0
- package/dist/chunk-WW3YZKHW.js +165 -0
- package/dist/chunk-ZB43YMHW.js +20 -0
- package/dist/chunk-ZCTSUQRR.js +874 -0
- package/dist/chunk-ZXKZBTXE.js +17 -0
- package/dist/contribute-C6AW2P6J.js +367 -0
- package/dist/cursor-awareness-KTL2RGKD.js +77 -0
- package/dist/dashboard-YSNUGBFY.js +21 -0
- package/dist/dashboard-broadcast-M4CMW7RX.js +119 -0
- package/dist/diff-VHNR62SI.js +74 -0
- package/dist/doctor-PET2HRRJ.js +236 -0
- package/dist/dogfood-KKFVRWT6.js +366 -0
- package/dist/guard-EHXF76ID.js +530 -0
- package/dist/handoff-3UI6VKVG.js +302 -0
- package/dist/hook-DYIMKJYL.js +1074 -0
- package/dist/index.js +62 -14068
- package/dist/init-Q4LBM6KT.js +127 -0
- package/dist/install-RHOS3OYZ.js +34 -0
- package/dist/mission-control-LJACEVVN.js +89 -0
- package/dist/monitors-QV2IS3MP.js +176 -0
- package/dist/plan-index-JMC7Z4DW.js +44 -0
- package/dist/public-inbound-radar-WP3XF7GS.js +68 -0
- package/dist/remote-issues-SZ4HDQL5.js +44 -0
- package/dist/run-I3BFGULT.js +243 -0
- package/dist/run-plan-FO7CL4M3.js +118 -0
- package/dist/scan-NI2SWJ2E.js +33 -0
- package/dist/setup-global-M42GEODI.js +340 -0
- package/dist/status-XPVQVQMX.js +150 -0
- package/dist/update-FJ2EBZVO.js +283 -0
- package/dist/validate-V2CW7J4B.js +201 -0
- package/package.json +3 -3
|
@@ -0,0 +1,1456 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HANDOFF_REL
|
|
3
|
+
} from "./chunk-5VCOWTTP.js";
|
|
4
|
+
import {
|
|
5
|
+
fileExists,
|
|
6
|
+
readJson,
|
|
7
|
+
writeJson
|
|
8
|
+
} from "./chunk-77V75A7O.js";
|
|
9
|
+
|
|
10
|
+
// src/manifest/types.ts
|
|
11
|
+
var MANIFEST_FILENAME = "agent-kit.json";
|
|
12
|
+
var MANIFEST_RELATIVE_PATH = `.cursor/${MANIFEST_FILENAME}`;
|
|
13
|
+
var MANIFEST_SCHEMA_VERSION = 1;
|
|
14
|
+
var DEFAULT_PROTECTED_PATHS = [
|
|
15
|
+
HANDOFF_REL,
|
|
16
|
+
".cursor/plans/**",
|
|
17
|
+
".cursor/memory/**",
|
|
18
|
+
".cursor/context/config.json",
|
|
19
|
+
".cursor/context/current/**",
|
|
20
|
+
".cursor/context/backups/**"
|
|
21
|
+
];
|
|
22
|
+
var LEGACY_CONTEXT_PROTECTED_GLOB = ".cursor/context/**";
|
|
23
|
+
var DOMAIN_PACK_IDS = [
|
|
24
|
+
"cybersec",
|
|
25
|
+
"devops",
|
|
26
|
+
"engineering-architecture",
|
|
27
|
+
"clean-code",
|
|
28
|
+
"project-management",
|
|
29
|
+
"context-management",
|
|
30
|
+
"quality"
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// src/manifest/index.ts
|
|
34
|
+
import path from "path";
|
|
35
|
+
|
|
36
|
+
// src/manifest/parse.ts
|
|
37
|
+
var SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
38
|
+
var KEBAB_ID = /^[a-z][a-z0-9-]*$/;
|
|
39
|
+
var ManifestValidationError = class extends Error {
|
|
40
|
+
constructor(message, issues) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.issues = issues;
|
|
43
|
+
this.name = "ManifestValidationError";
|
|
44
|
+
}
|
|
45
|
+
issues;
|
|
46
|
+
};
|
|
47
|
+
function isPlainObject(value) {
|
|
48
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
49
|
+
}
|
|
50
|
+
function assertStringArray(label, value, issues) {
|
|
51
|
+
if (value === void 0) return void 0;
|
|
52
|
+
if (!Array.isArray(value)) {
|
|
53
|
+
issues.push(`${label} must be an array`);
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
const out = [];
|
|
57
|
+
for (let i = 0; i < value.length; i++) {
|
|
58
|
+
const item = value[i];
|
|
59
|
+
if (typeof item !== "string" || item.length === 0) {
|
|
60
|
+
issues.push(`${label}[${i}] must be a non-empty string`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
out.push(item);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
function assertKebabIdArray(label, value, issues) {
|
|
68
|
+
const arr = assertStringArray(label, value, issues);
|
|
69
|
+
if (!arr) return arr;
|
|
70
|
+
for (let i = 0; i < arr.length; i++) {
|
|
71
|
+
if (!KEBAB_ID.test(arr[i] ?? "")) {
|
|
72
|
+
issues.push(`${label}[${i}] must match ${KEBAB_ID}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return arr;
|
|
76
|
+
}
|
|
77
|
+
function parseOverrides(value, issues) {
|
|
78
|
+
if (value === void 0) return void 0;
|
|
79
|
+
if (!Array.isArray(value)) {
|
|
80
|
+
issues.push("overrides must be an array");
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
const out = [];
|
|
84
|
+
for (let i = 0; i < value.length; i++) {
|
|
85
|
+
const item = value[i];
|
|
86
|
+
if (!isPlainObject(item)) {
|
|
87
|
+
issues.push(`overrides[${i}] must be an object`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (typeof item.path !== "string" || item.path.length === 0) {
|
|
91
|
+
issues.push(`overrides[${i}].path must be a non-empty string`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const entry = { path: item.path };
|
|
95
|
+
if (item.replaces !== void 0) {
|
|
96
|
+
if (typeof item.replaces !== "string" || item.replaces.length === 0) {
|
|
97
|
+
issues.push(`overrides[${i}].replaces must be a non-empty string`);
|
|
98
|
+
} else {
|
|
99
|
+
entry.replaces = item.replaces;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (item.note !== void 0) {
|
|
103
|
+
if (typeof item.note !== "string") {
|
|
104
|
+
issues.push(`overrides[${i}].note must be a string`);
|
|
105
|
+
} else {
|
|
106
|
+
entry.note = item.note;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
out.push(entry);
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
function parseAgentKitManifest(raw, warnings = []) {
|
|
114
|
+
const issues = [];
|
|
115
|
+
if (!isPlainObject(raw)) {
|
|
116
|
+
throw new ManifestValidationError("Manifest must be a JSON object", ["root must be object"]);
|
|
117
|
+
}
|
|
118
|
+
const { $schema: _schema, ...rest } = raw;
|
|
119
|
+
void _schema;
|
|
120
|
+
if (rest.schemaVersion !== MANIFEST_SCHEMA_VERSION) {
|
|
121
|
+
issues.push(`schemaVersion must be ${MANIFEST_SCHEMA_VERSION}`);
|
|
122
|
+
}
|
|
123
|
+
if (typeof rest.version !== "string" || !SEMVER.test(rest.version)) {
|
|
124
|
+
issues.push("version must be a semver string");
|
|
125
|
+
}
|
|
126
|
+
if (rest.profile !== void 0 && (typeof rest.profile !== "string" || rest.profile.length === 0)) {
|
|
127
|
+
issues.push("profile must be a non-empty string");
|
|
128
|
+
}
|
|
129
|
+
const packs = assertKebabIdArray("packs", rest.packs, issues);
|
|
130
|
+
const skills = assertKebabIdArray("skills", rest.skills, issues);
|
|
131
|
+
const protectedPaths = assertStringArray("protected", rest.protected, issues);
|
|
132
|
+
const overrides = parseOverrides(rest.overrides, issues);
|
|
133
|
+
let registry;
|
|
134
|
+
if (rest.registry !== void 0) {
|
|
135
|
+
if (!isPlainObject(rest.registry)) {
|
|
136
|
+
issues.push("registry must be an object");
|
|
137
|
+
} else {
|
|
138
|
+
registry = {};
|
|
139
|
+
if (rest.registry.url !== void 0) {
|
|
140
|
+
if (typeof rest.registry.url !== "string") {
|
|
141
|
+
issues.push("registry.url must be a string");
|
|
142
|
+
} else {
|
|
143
|
+
registry.url = rest.registry.url;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (rest.registry.ref !== void 0) {
|
|
147
|
+
if (typeof rest.registry.ref !== "string" || rest.registry.ref.length === 0) {
|
|
148
|
+
issues.push("registry.ref must be a non-empty string");
|
|
149
|
+
} else {
|
|
150
|
+
registry.ref = rest.registry.ref;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
let personalization;
|
|
156
|
+
if (rest.personalization !== void 0) {
|
|
157
|
+
if (!isPlainObject(rest.personalization)) {
|
|
158
|
+
issues.push("personalization must be an object");
|
|
159
|
+
} else if (typeof rest.personalization.contractVersion !== "number" || typeof rest.personalization.generatorVersion !== "string" || rest.personalization.origin !== "repository-profile" || typeof rest.personalization.resultPath !== "string") {
|
|
160
|
+
issues.push("personalization must contain a valid origin and version contract");
|
|
161
|
+
} else {
|
|
162
|
+
personalization = {
|
|
163
|
+
contractVersion: rest.personalization.contractVersion,
|
|
164
|
+
generatorVersion: rest.personalization.generatorVersion,
|
|
165
|
+
origin: "repository-profile",
|
|
166
|
+
resultPath: rest.personalization.resultPath
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (rest.installedAt !== void 0 && typeof rest.installedAt !== "string") {
|
|
171
|
+
issues.push("installedAt must be a string");
|
|
172
|
+
}
|
|
173
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
174
|
+
"schemaVersion",
|
|
175
|
+
"version",
|
|
176
|
+
"profile",
|
|
177
|
+
"packs",
|
|
178
|
+
"skills",
|
|
179
|
+
"protected",
|
|
180
|
+
"overrides",
|
|
181
|
+
"registry",
|
|
182
|
+
"personalization",
|
|
183
|
+
"installedAt"
|
|
184
|
+
]);
|
|
185
|
+
const unknownFields = {};
|
|
186
|
+
for (const key of Object.keys(rest)) {
|
|
187
|
+
if (!allowed.has(key)) {
|
|
188
|
+
warnings.push(`unknown field: ${key}`);
|
|
189
|
+
unknownFields[key] = rest[key];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (issues.length > 0) {
|
|
193
|
+
throw new ManifestValidationError(`Invalid agent-kit.json (${issues.length} issue(s))`, issues);
|
|
194
|
+
}
|
|
195
|
+
const manifest = {
|
|
196
|
+
schemaVersion: 1,
|
|
197
|
+
version: rest.version
|
|
198
|
+
};
|
|
199
|
+
if (typeof rest.profile === "string") manifest.profile = rest.profile;
|
|
200
|
+
if (packs) manifest.packs = packs;
|
|
201
|
+
if (skills) manifest.skills = skills;
|
|
202
|
+
if (protectedPaths) manifest.protected = protectedPaths;
|
|
203
|
+
if (overrides) manifest.overrides = overrides;
|
|
204
|
+
if (registry) manifest.registry = registry;
|
|
205
|
+
if (personalization) manifest.personalization = personalization;
|
|
206
|
+
if (typeof rest.installedAt === "string") manifest.installedAt = rest.installedAt;
|
|
207
|
+
if (Object.keys(unknownFields).length > 0) manifest.unknownFields = unknownFields;
|
|
208
|
+
return manifest;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/manifest/index.ts
|
|
212
|
+
async function loadAgentKitManifest(cwd, options = {}) {
|
|
213
|
+
const target = path.join(cwd, MANIFEST_RELATIVE_PATH);
|
|
214
|
+
const raw = await readJson(target);
|
|
215
|
+
if (raw === null) return null;
|
|
216
|
+
const warnings = [];
|
|
217
|
+
const manifest = parseAgentKitManifest(raw, warnings);
|
|
218
|
+
for (const warning of warnings) {
|
|
219
|
+
options.onWarning?.(
|
|
220
|
+
`${MANIFEST_RELATIVE_PATH}: ${warning} (kept, but not understood by this CLI; newer CLI?)`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
return manifest;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/lifecycle/glob.ts
|
|
227
|
+
function normalizeRelPath(input) {
|
|
228
|
+
return input.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
|
|
229
|
+
}
|
|
230
|
+
function matchSegments(patternParts, pathParts) {
|
|
231
|
+
let pi = 0;
|
|
232
|
+
let si = 0;
|
|
233
|
+
while (pi < patternParts.length && si < pathParts.length) {
|
|
234
|
+
const p = patternParts[pi] ?? "";
|
|
235
|
+
if (p === "**") {
|
|
236
|
+
if (pi === patternParts.length - 1) return true;
|
|
237
|
+
for (let skip = si; skip <= pathParts.length; skip++) {
|
|
238
|
+
if (matchSegments(patternParts.slice(pi + 1), pathParts.slice(skip))) return true;
|
|
239
|
+
}
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
const segment = pathParts[si] ?? "";
|
|
243
|
+
if (p.includes("*") || p.includes("?")) {
|
|
244
|
+
const re = new RegExp(
|
|
245
|
+
`^${p.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".")}$`
|
|
246
|
+
);
|
|
247
|
+
if (!re.test(segment)) return false;
|
|
248
|
+
} else if (p !== segment) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
pi += 1;
|
|
252
|
+
si += 1;
|
|
253
|
+
}
|
|
254
|
+
while (pi < patternParts.length && patternParts[pi] === "**") pi += 1;
|
|
255
|
+
return pi === patternParts.length && si === pathParts.length;
|
|
256
|
+
}
|
|
257
|
+
function matchesAnyGlob(relPath, globs) {
|
|
258
|
+
const normalized = normalizeRelPath(relPath);
|
|
259
|
+
const pathParts = normalized.split("/").filter(Boolean);
|
|
260
|
+
for (const glob of globs) {
|
|
261
|
+
const pattern = normalizeRelPath(glob);
|
|
262
|
+
if (matchSegments(pattern.split("/").filter(Boolean), pathParts)) return true;
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/lifecycle/protected.ts
|
|
268
|
+
var CONTEXT_SESSION_GLOBS = [
|
|
269
|
+
".cursor/context/config.json",
|
|
270
|
+
".cursor/context/current/**",
|
|
271
|
+
".cursor/context/backups/**"
|
|
272
|
+
];
|
|
273
|
+
function normalizeProtectedGlobs(globs) {
|
|
274
|
+
const out = [];
|
|
275
|
+
let sawLegacyContext = false;
|
|
276
|
+
for (const raw of globs) {
|
|
277
|
+
const g = normalizeRelPath(raw);
|
|
278
|
+
if (g === LEGACY_CONTEXT_PROTECTED_GLOB) {
|
|
279
|
+
sawLegacyContext = true;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
out.push(g);
|
|
283
|
+
}
|
|
284
|
+
if (sawLegacyContext) {
|
|
285
|
+
out.push(...CONTEXT_SESSION_GLOBS);
|
|
286
|
+
}
|
|
287
|
+
return [...new Set(out)];
|
|
288
|
+
}
|
|
289
|
+
function resolveProtectedGlobs(manifest) {
|
|
290
|
+
const fromManifest = manifest?.protected ?? [];
|
|
291
|
+
const overrides = (manifest?.overrides ?? []).map((o) => o.path);
|
|
292
|
+
const merged = [...DEFAULT_PROTECTED_PATHS, ...fromManifest, ...overrides];
|
|
293
|
+
return normalizeProtectedGlobs(merged);
|
|
294
|
+
}
|
|
295
|
+
function isProtectedPath(relPath, globs) {
|
|
296
|
+
return matchesAnyGlob(relPath, globs);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/registry/client.ts
|
|
300
|
+
import path2 from "path";
|
|
301
|
+
|
|
302
|
+
// src/registry/paths.ts
|
|
303
|
+
var REGISTRY_INDEX_REL = "registry/registry.json";
|
|
304
|
+
|
|
305
|
+
// src/registry/client.ts
|
|
306
|
+
async function loadRegistry(rootDir) {
|
|
307
|
+
const indexPath = path2.join(rootDir, REGISTRY_INDEX_REL);
|
|
308
|
+
const index = await readJson(indexPath);
|
|
309
|
+
if (!index) throw new Error(`Registry not found at ${indexPath}`);
|
|
310
|
+
return index;
|
|
311
|
+
}
|
|
312
|
+
function allSkills(index) {
|
|
313
|
+
return [...index.skills.core, ...index.skills.community];
|
|
314
|
+
}
|
|
315
|
+
function allPacks(index) {
|
|
316
|
+
return index.packs ?? [];
|
|
317
|
+
}
|
|
318
|
+
async function findSkill(rootDir, skillId) {
|
|
319
|
+
const index = await loadRegistry(rootDir);
|
|
320
|
+
const skill = allSkills(index).find((item) => item.id === skillId);
|
|
321
|
+
if (!skill) throw new Error(`Skill '${skillId}' not found in registry.`);
|
|
322
|
+
return skill;
|
|
323
|
+
}
|
|
324
|
+
async function findPack(rootDir, packId) {
|
|
325
|
+
const index = await loadRegistry(rootDir);
|
|
326
|
+
const pack = allPacks(index).find((item) => item.id === packId);
|
|
327
|
+
if (!pack) throw new Error(`Pack '${packId}' not found in registry.`);
|
|
328
|
+
return pack;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/lifecycle/overlay.ts
|
|
332
|
+
import { createHash } from "crypto";
|
|
333
|
+
import { mkdir, readFile, readdir, writeFile } from "fs/promises";
|
|
334
|
+
import path4 from "path";
|
|
335
|
+
|
|
336
|
+
// src/lifecycle/overlay-known-hashes.ts
|
|
337
|
+
var KNOWN_SHIPPED_OVERLAY_HASHES = /* @__PURE__ */ new Set([
|
|
338
|
+
"004d98f557942677264d053dcd8335f2bbcf19c5591123ec16a7a2697cb88932",
|
|
339
|
+
"05ee6ecde4215e33ace0ee152ffbf2cd885d2bd4b032900f0f0bb001d350ef0f",
|
|
340
|
+
"082bdbc584be3f3d8aa6e9d7b9f4e076450f3ff48f9147a1deb557e31475036b",
|
|
341
|
+
"09850afc201eccb3e700cb934400d49c9cbe7510d4a546ee84ee519771a8200e",
|
|
342
|
+
"0b5fe4729c3c68654434837630d775b847c082418f25b0b2c581700fe84b797a",
|
|
343
|
+
"1106b279558b6a20f87951102f172a680976f3e6530855d5dad083e1f89b9ba3",
|
|
344
|
+
"12bed56b332406477cf546d9e8360d3cab129bd82a638bea356726d00a6847a3",
|
|
345
|
+
"13f6a0711a2fcadcc7f1b751772448517ce4871cdef6a0269fc26dad51ebe26d",
|
|
346
|
+
"15566765ec95dad3bc3160f20ac910e01a13471df536e6d990f4b263700784a9",
|
|
347
|
+
"1681e6cf7b80a67cd999b94b8b6e16eb8caed0e11b32905848ba733da956e902",
|
|
348
|
+
"17818e47e06349ee35c1d8e1cc16e8bcbbbcc89c664014e9096e1f08c8567807",
|
|
349
|
+
"1974a5af0e4ba2bb0fc7e1872ef9ab70e323323ab216958c31731bcdd82c8241",
|
|
350
|
+
"1b384771cc6228215e31e6a9ab0943b13a5cdc463354a2641f1c0d85b4357e84",
|
|
351
|
+
"1b5f8c4197393dc9110d020f3b619b8502862adeb6522a6b9be4b49dd8794612",
|
|
352
|
+
"1c5c1af87951367ad04bb6fa5b1d6ebaaefbc0ee95989b624cabf406a1869907",
|
|
353
|
+
"1ded5c7b7eefc355fc1d17feb65ec472e35ed96076e47ce95f7bff5c1b84746c",
|
|
354
|
+
"1e58e0d4f2e8459b95a40d1b1e72c5c85a87230cbde945840a84073fe3a20422",
|
|
355
|
+
"2280e3ca96129ab2de8a85a301df7c2b15ffaa6204b734ed3b1f303e0055c41d",
|
|
356
|
+
"285668d08f1b15d96286d27e29cc4a67e126e097fb8a940bdde33ccf25bd2bcd",
|
|
357
|
+
"2acdb148b07f3a4872b896da419af796fd3fefaace7ac79cdee0aab447004a83",
|
|
358
|
+
"2cd7fc018a384b0188737259ecf593ce25b4b75cc38b3e410063ac91745894b9",
|
|
359
|
+
"2f6cedfa61cb62126efd6b845bbf4d8d7913e39223d5f799ac09ef64c0489824",
|
|
360
|
+
"3204a7449f3031916a8d57b37144e5d8ded6c94aa5659493fa5cc2c7321f4eab",
|
|
361
|
+
"33982aea21a074d21a638850475ce1fefa7d043ec035de3855889cc68d60cf35",
|
|
362
|
+
"38675aec695e9d4e7f16e8fbe3facc3280f47fb875bf9ac50bd6837b92b7a7fa",
|
|
363
|
+
"3ee94e2441218025c085856679d17b4a4fe7a6e3d0274423abe20a422a5ab05d",
|
|
364
|
+
"3f3354825ff06ff9f9ae1e29b71784fef4250020c23c1b490940cf06b2be0f28",
|
|
365
|
+
"46a1dd4a07a2190ab9fb09abc05a3962277209f8e0c28033bb41450301474c86",
|
|
366
|
+
"48a0d55e21132a305946b195db7f6b75da78d44a1d32166fb0c69bef4a5ffbe2",
|
|
367
|
+
"4b62a46c74e5fa6a80283f21e8e6711958fbcd577051dc73ff4050643a031475",
|
|
368
|
+
"4ba6e319ac79455a7d2713674f64fabbc9cd401b5d26b1c0edbd19c27a52297e",
|
|
369
|
+
"4bf23acbc9bd4e0f8468e61f4970e182600b72d9025d29e81ddbd83cb7b1710a",
|
|
370
|
+
"4c5167d0ebde685f266dce32c516a7c43876e0520647b93f07f2e2147e6a7b2f",
|
|
371
|
+
"4dc4efcd1b43c643d3889fb349df8d4964d0867c3a67eb67e2ec168fbb70fc75",
|
|
372
|
+
"4f133554d01cedc62280006f4cf6453e25a5cb41ef6dde4a43f9508cb36ef75d",
|
|
373
|
+
"4fe1e2bce8bd55a6decdd62c887a423cf85148b692f313aad4c777d0e50596b3",
|
|
374
|
+
"4ff844cf789cef4b1e809a55ca006316cd964bcdb2557d91c916a08e30ad15f6",
|
|
375
|
+
"533b41599c25698e5746166096a68fd4080efb5e16287b2a1ed5f73295cda446",
|
|
376
|
+
"54dda8addb74bc187ee23c31f8b7d17ad19e745a45169d29ffea094860eb18f2",
|
|
377
|
+
"570c3f91fd31a4cc1e56e997c85feab5c6756f45fc73dc741afe573912111231",
|
|
378
|
+
"5cb36f5dab846b2551afd05eab92c14122853c147d7f02136d1c04e01e3c9def",
|
|
379
|
+
"5d302d207521c53b9fa814ee0eba1376a5b2bfd2983c0373657c9fdf9884541b",
|
|
380
|
+
"5f5c125f7edf280029f214589ce3e088fc74bad717e30178405a3b537673c42f",
|
|
381
|
+
"621bc6cecf7c710a97e93463ca9b8872a1fcab1325c358cc8be65b418eebb339",
|
|
382
|
+
"693c732658e31d6403cf59e85985518f24ab92bf7fcdc3c225e9a79e54597a43",
|
|
383
|
+
"69715048da3963947aa8a39e7ac30ec01632fec862bfcb9559c46764b4833be0",
|
|
384
|
+
"6994595e3a62edb6c518006a6bece6848c7077977c041439cf7c822b89304a14",
|
|
385
|
+
"6a42e76fc038ca69ddad18541b8df161770c58980fefaf9e5e80d87407074bec",
|
|
386
|
+
"6a9af9e8a95dbb279347166c43dcee245ca673f9687841086b49911c54944c26",
|
|
387
|
+
"99fdd85310e658a1c1b0e8f92257493409c28c3d693f24deeaa665861788e1e4",
|
|
388
|
+
// public registry SoT n8n-workflows/SKILL.md (em dash description)
|
|
389
|
+
"6b66ed7747ea2d19cb457f5af656e3c07f9f563f7f32b3951fa4ae5f27f0ac46",
|
|
390
|
+
"6dede0588274f5b44d833bcc696ec4776eb978ed24a20efdcc9c38caf3df1576",
|
|
391
|
+
"71991a10972b8b956cae93c88517e31741c95e351814082df65e44f813590210",
|
|
392
|
+
"75ae3018a70ed838428c0e63e8b6901ac05bf1f1cf1845faa6f73c3940d22e4a",
|
|
393
|
+
"75e591bfde61ca1ca3ca1303cc9bc487197af2f713c68f346a46e94ca9432fd5",
|
|
394
|
+
"76ae85bbc336c6f435d9653e8f254ae49774b4ebaecf7335697115933eb8797c",
|
|
395
|
+
"76c4361e70a73276771e841e2c939253b4124d690a0fd25aff2a3ac636d8f4b0",
|
|
396
|
+
// mission-kit-comms/SKILL.md
|
|
397
|
+
"79878f0f6f59d1a0b65d94011c0cafe7b6f8e03e89f568aa638b8ba7a2c34076",
|
|
398
|
+
"8108b202c829627c3c2df33575016ebe942df42acf4f1cc393900be3b82b402c",
|
|
399
|
+
"819b7bd3ba9e8bf12dcd4f81a76c98e48261b34c397f339b36d36eb364d9c3f4",
|
|
400
|
+
"8619500b0c7024390d43e3aaefa2a2d731728d7c664aaf90e0acdd067f3397ce",
|
|
401
|
+
"875b0a8805280b2a2df43f2c42f9063fe0623a34fa19c3aa5d2ec48211f3ebae",
|
|
402
|
+
"8a11c80b0fbf6c4aabf60eec05b8cca7dccf5bca472787a8afa3028fd8fbedfa",
|
|
403
|
+
"8b25659727063013e8bf6d7925f815b2630c2919b21e6fdac354362bf122bfab",
|
|
404
|
+
"8c7edbacc74b1431fbecb04c9857c0e7a9cb1578fc6ca6367be888dbcec3c98f",
|
|
405
|
+
"8d8d60e929ebf717eed3c1a29ee0de7c71ae917d125eb1b220a77220597281ed",
|
|
406
|
+
"8ffc181bb152c68a3353309bfdc87c42bdb925b98675cdba959c0cdb90b2adea",
|
|
407
|
+
"91ce0c933e3c8ee81927b8224f944ec5ce5445098a2ad154773092e3541dbf69",
|
|
408
|
+
"9309af07a0a99a56143386b3ddd2a35fae29378fba3f6b4c9297a5d1c02a9724",
|
|
409
|
+
"9439da963acbe5dd88a3aa4d6ba4fb297db666ce8f2c9d3917dbc6d6e517f9aa",
|
|
410
|
+
"989e7e1bdfb29dedf850405f28648810d008885196efe7ae38c6e7554c7ce45d",
|
|
411
|
+
"98d96e25f67aa9c234cb0c422f0d701c22a04bfe184fb4eb68295003d429552b",
|
|
412
|
+
"99031145609af46e7e0f315006bf633f47002eccece8eb7af8b5efd762313ade",
|
|
413
|
+
"9a3cea681399b42ef930a0720802378fe1b06ee73370df9ede9d0309c3c60ab2",
|
|
414
|
+
"9ccf52fe53c6fa4d731650ab4928ce50e201fa34f3e174fee70e3d29867fef2a",
|
|
415
|
+
"9d905aca0123f3018c81c579217104f1749d8da802f3837b2407fbad8f2d803f",
|
|
416
|
+
"9e324c52c1a9d1ceee738bccf47da92910aca9f7a5a21cc41738d9573c414830",
|
|
417
|
+
"9eb457654167df562481637b25ecd91f0ff3c9282ba79409089d644d3b09b926",
|
|
418
|
+
"a013a6a476160183d6457ff6c1c51ec228bdca359b11eb15cd9b7fc177a705db",
|
|
419
|
+
"a08d04f8efa121ad498f96873778c22630c9172c07c216839e348cd0bb7c2292",
|
|
420
|
+
"a7cd7058bcb6fbd962c37317fa16893bc86a270d0164af5a0e6f3f026aa408ad",
|
|
421
|
+
"a833a7131cdfc003b45a48cb26c6ce33dc218c1814156047db5211a79192e0a0",
|
|
422
|
+
"ac2f1f7d9e68f9c98fc4fe5ca348b1a90cf484141bbd116db871d63bdcc3c7c3",
|
|
423
|
+
"b5c7a10df90d209be07159b7ff9bfa24e869538a0b6026bb5ce79e1cdd5b2528",
|
|
424
|
+
"bd9fd1efacbd132c5dafc12cd0cf2b651a2b1fab7b2d7a9ba4a3e44128097f48",
|
|
425
|
+
"be964ff33a40280e13ce6071fb3e30ce87c374527efbb74c25c9d4534084a634",
|
|
426
|
+
"c245035b539e41e822fab8c74fcde3b18c45f4b9f26f1c8583fc9e7254249698",
|
|
427
|
+
"c794accc6668d74a739c982c1b63985a8be4be08afe3766214ab1e08d25ea95c",
|
|
428
|
+
"c96d522be440fbb638dbe953cebf1bb31185c431ac2e14446369cfb7d155a951",
|
|
429
|
+
"cf2bd11891b934484171fa705f470de284e3874402e1e487750735dbc7692857",
|
|
430
|
+
"d0e3bf82efbe32c09761689802ffea7838046dbdd4803b88ead5ec3dfc7efb7e",
|
|
431
|
+
"d4659e4bb6fd6022559fc632b17db6a39007c04bc0ded59017a0dacc013632ed",
|
|
432
|
+
"d484243167e13c34f9df7ff378baf2967f7cbfcd88170d4d32e745efbcae7480",
|
|
433
|
+
"d67ac8fa1edec6e50c82aeca064335e799e408d0e4bbc95e1407cf7463a61de3",
|
|
434
|
+
"d7ad53f06a41bcb2f2b998fd4a4c99209a0cf287cf0d0d4acbcc36c73dd46e4a",
|
|
435
|
+
"d96aa15dde45147aa40db64684688a4b5c9ad660dcd16c55156b31933a42c37e",
|
|
436
|
+
"d9ecd90f80ebc25db73ebed27c32596b9cfce518b3026a3a4d5787321ba6324a",
|
|
437
|
+
"dd01d051dbab257e16609b02c983bad6a576ed8473781b4f1df9ef2eb5f85795",
|
|
438
|
+
"dd9ff2ff8aa7bcb2cdfc59092ad73227631c1c3619b495131f7faee65224cb17",
|
|
439
|
+
"de6efabde6a1d69357926b88b5a4ed3eec19e11b82597cb999f5365f952305b8",
|
|
440
|
+
"debc0758b3e39294df85ccb7eab3455e93a2b8c608602d309a7b0ebdb6618805",
|
|
441
|
+
"e03b5764b908f9ed5c592108fbc11d5962d9256fd129a63ab4a39c8efaa2ef3e",
|
|
442
|
+
"e102e77f9f520f938d26861978249e4d85a8c8755d48c8e79b21fef9423325ee",
|
|
443
|
+
"e2d89f780c6ae5393dc05818f9e3e9a8bf6629eac05702eea8f9a25b578e3ff1",
|
|
444
|
+
"e2f1e9108fd450817ab42570db656b1e43b20b5ba703b14027ce540e1b8fe502",
|
|
445
|
+
"e37c62695b5c70451ef1a0c90b31b73a9c442ebc55fb3fc3f79c294b993b99ea",
|
|
446
|
+
"e3c32aec17e8f728cbd13162a123a9debffb8bbcec527a00b1c2df30a1a20080",
|
|
447
|
+
"e511e04064ffb8c429b659d2ae2e0f223e8cc51039ae816753095a5f7a160595",
|
|
448
|
+
"e5682d4696e874d09f12a1d65891fee5971201a29c654c08f5d3b90fb9a6a0b7",
|
|
449
|
+
"e57437bf790fda1d43b895e2b5b0a7d2d57635c319ac0e2439ba2222a825bcde",
|
|
450
|
+
"e8bb214c3e551c44f379db13c5962ef20698b505b0227d283d3ae632e1bc3626",
|
|
451
|
+
"ea36e74c9d592980cba5c08d04ee70fc59a6cd01e87a50bbfae4f668557df4b4",
|
|
452
|
+
"ebd41f8df764a14b3460016fafcfdde98c4c3a59a3c17f773451ef061fc42f95",
|
|
453
|
+
"ef181a4e2bd9f82f45628637b8d66925ffa20801558808f1b03ea72b7cb82a72",
|
|
454
|
+
"f061432a2606049717c0cbf098ef07b1da4df2b136c4cb9cdaa7ea44c876bcd6",
|
|
455
|
+
"f061d36a1180293519fbb560bbf659c621bd90885e995fca6eaf2eda9e418a50",
|
|
456
|
+
"f28731a82f4b394a5765fdefe2d1b667810831f6dcea400ca62bc66e1d65371c",
|
|
457
|
+
"f43a5484e39aca4e6af86e7f8d2941773cdc1c960838ad88ae3540c49a1097df",
|
|
458
|
+
"f46c108457e4fe12953dca75b409e06fca9cb264baffabe0c0d04c89af471e56",
|
|
459
|
+
"f6bc17efa746680a44bbc49be67ac3f924d9c306c6d937f9959c57a1d3c5b9af",
|
|
460
|
+
"f981764422d468567b5aff31148dc659aeee22cb13dc0ecd873d737deaf07372",
|
|
461
|
+
"fa306a0cdb0f40c817e32164cd03b946564a02b4b7f7c3f4f0b9513096584d28",
|
|
462
|
+
"fa5cf460eb314437081f7cea30dc8041c0bd6fc3f560a74bc2d7be1bf07384b0",
|
|
463
|
+
"fc39ec6d8a22498697f968ffc0fe5f717bed97afd68f922c76a80ed1f10d6579",
|
|
464
|
+
"a8756742197c3a2e1a6d64f4bde2a88db48abb66a0f449d625cd2e1c7b8d0cb4",
|
|
465
|
+
"6a5f8795a4a26b419f167e249576b798781c95308dc1ea50958351de713231d4",
|
|
466
|
+
"4009c5e2faf9775d5708cdff0b5f9da80fd3ce390cc42aed0bb94272f6b05b1b",
|
|
467
|
+
"a8e070fae187908ef7b2cf2a41605e3079329403b1802b5fc67e83294c96a070",
|
|
468
|
+
"81186b528105f2873818ea91f51d20c95a68c0c4b3d128aa8896dd38a1bb3159",
|
|
469
|
+
"b2c7db73a0e18bd475651001722aa34b39276af9f73f0921102b680eb42bea0e",
|
|
470
|
+
"d03445b726cb6afe2ff37a936de97605cc60e441896e06385abfc15a127e2f45",
|
|
471
|
+
"f5ef970adaf4cfa7af551e35cb41b4052576109f5444a280b1e26562338b39e8",
|
|
472
|
+
"fe3f8e2339a7f183545f2aad6b7f02d3687277ca67597fa7620bfee269392bcd",
|
|
473
|
+
"b2489e381ea7daaef7299e5aede437a8baaa39baaddaac849efbf0a6ccb84a2b",
|
|
474
|
+
"0ae7d076904fd342de3ba38745f38fed8ca5c1f02d7b099d27deeb0a9be79740",
|
|
475
|
+
"15ca459811f0f050f4eeff77d4567b45c0790beb77904ecf37e145d65a858c77",
|
|
476
|
+
"1dc329c0c0695a4395bb7c30db0fb7b6fb06bcf5fdc1d6a475656ac6a525aa5f",
|
|
477
|
+
"35bb0008ef52af147a45fba667f7dceb841d537ad5e185317672577afbcbc189",
|
|
478
|
+
"42b701d224f4e690dc027d66fcc1214bab31a0ae0c50ef982124f57d4dae4982",
|
|
479
|
+
"65272f85a32f8fe95ed19d0823fa9d1d6dee5bc18a0244f7b553ea5162ba9b36",
|
|
480
|
+
"73cd50bac290b84df6245d3647e686dee8ec3b0434736d08fdba6e30d342ef0a",
|
|
481
|
+
"61b635ea8a08171062bd329a4615d7426eb787eb796271aa882f55f39db56810",
|
|
482
|
+
"86afbea8f64de68a79ad5e374f3132bdbe2582b94321fb3d438314838e36c776",
|
|
483
|
+
"65cc1c0293b145e48ed73ad0ca9ab33cbba5ed834a5bfb31f195ed30c2f143df",
|
|
484
|
+
"f04fcfe31354d1b09aeb256a17e4aab91c98ea48a5cff25e4a0281af3cfb289f",
|
|
485
|
+
"34e559ad9036d93d9cbc96d394bc2bbeb10ce50ead00d58a914158ae19daa76c",
|
|
486
|
+
"359a142aeadd769a9b89ac909ae5129940e7e6b0892b70256098c584d97631ce",
|
|
487
|
+
"8eab94f7a78149db1bbbc0fd45f21dc2d874209d534bcff39077fd6e1d2c42fb",
|
|
488
|
+
"9be406f92f7dca71f3af814b14fb26b011f9f12c37c789f7ddc3d647b1a7ab60",
|
|
489
|
+
"bb67ddcdd9ab58ed89287421f5e4b6ebfb3941e6a789287ddec9b9c25b56b1ed",
|
|
490
|
+
"7343ecd797f484eea1a3ebc11e87c75d90f617bd627bfc367a1eca5a1628bdf1",
|
|
491
|
+
"8a723b4808f14413fc173a6ce33370067ffc78d0c2e05a21c4406d7fa3e66457",
|
|
492
|
+
"65554e304a70b77e07fe40facf0ef305d6216399bfbb811db2491ce2f31d86d7",
|
|
493
|
+
"f8cc89a52fb1ec17f7f26ecd5cb18f79a5e9c7b7ffe7a6899465aa4090433b98",
|
|
494
|
+
"543e6596e7ce9f3ce4de642f1ea7e5d437d553fa28c0d56eb0f244ec8526ce17",
|
|
495
|
+
"71c6d1cce604c4a275db7c9a5c48f1753604bf35e083be054511ebc91f4977e6",
|
|
496
|
+
"8d0fd61bcbb9e035dea3a8b9f298a48c226bb28785923cb07e1154cf084934ad",
|
|
497
|
+
"1d489cea7648a73b4fee12dbadc592700024272d0f1562378e1b1e8ed2bbeffe",
|
|
498
|
+
"246216002ee4c98ee4daf1402c531fc2788bb2dc1656d5517844da0ab674c086",
|
|
499
|
+
"9dea9e262e096c9cde32dfd1d1c2d832114018f8768679320b5dba9d442ebaa8",
|
|
500
|
+
"ec78c2d6cae7b1120a88bc8a2e4796e1525b894c4c44e653770ef2807ba0080c",
|
|
501
|
+
"221ebfef9a7b94f4d10ab21d13be073426405bb7d8550e89bc04935a43494284",
|
|
502
|
+
"78dc088900961ef37419d050ac7f5b499f8dbcc1ec663ef923dbac892e236d32",
|
|
503
|
+
"379f565e3321bb89c51d04ad9b2f939d8e0a4758b0b6950ad98b19c5963d091f",
|
|
504
|
+
"b65c495e70ced29711e0b213a9eb5333b5446e7f5393ad2a461b373dfb60f53c",
|
|
505
|
+
// .cursor/commands/run-plan-all.md PO adjustment-class hard drift
|
|
506
|
+
"b0058c7516917079514696e5a4e25250b3f5542145557d4bb94761c48e1f5ffe",
|
|
507
|
+
// .cursor/commands/run-plan-all.md start/resume 3-way Ask
|
|
508
|
+
"19562f3079fe27380b947742107dd693f5cf606188f468203f0a481b2668e9c7",
|
|
509
|
+
"3bdad79bd9e25ca127b85a8e5f659db6334cf11903e2ad163d053a94d5efe4f2",
|
|
510
|
+
"48a6c5e9a9a07ed7ee11ef31b6895be3176f727ac9a7665959d87a97de89da0b",
|
|
511
|
+
"4aaff4b1d51c3627e353458aa4d733736666dc2c3f8b7711b9677131eed7cefb",
|
|
512
|
+
"6bc92f215031c0f9702b39cf7cee2076928a0516c4a756c603c730bd0878eca3",
|
|
513
|
+
"8a6b53d5702431af97a9dfcbc97c47b9bf562561c40e2b09f7271a19998a8d06",
|
|
514
|
+
"949d8c97a7c2cdad133ab9e28b9c2955157fee988125f4e94f0659d10a24ea0d",
|
|
515
|
+
"96a77a9d75de9985d967f030626d779677db18f54a5966f5df1d770557c87190",
|
|
516
|
+
"cdef696f85a7e594289ec604918aad8122c4d03cfd3991dc28a114e853190186",
|
|
517
|
+
"e10ec219a3bfa6cea556f9cf0c1905ae35a578fc329c9476808faf9084b62d01",
|
|
518
|
+
// Hooks and scripts joined the overlay after v5.7.0; bodies shipped at released
|
|
519
|
+
// tags are listed so an unedited older consumer copy still refreshes instead of
|
|
520
|
+
// being preserved as customized.
|
|
521
|
+
"196f18aac06c4dc82f937bc147d00f44177aea1a3c0bdeb661d5d81cfd84523e",
|
|
522
|
+
// .cursor/scripts/plan-external-review.sh as shipped in v5.3.0–v5.4.0
|
|
523
|
+
"ca7698db9747f8b2333d7f9f0ed2de72b0f029ee8b1d6dcf3e54e52cff6dbf3c",
|
|
524
|
+
// .cursor/scripts/plan-external-review.sh as shipped in v5.5.0
|
|
525
|
+
"fd621d8a5fe64f9dde94c62dd7a3402602e1d92d9c5b80fde60660532a1a06d3",
|
|
526
|
+
// .cursor/scripts/plan-external-review.sh as shipped in v5.6.0
|
|
527
|
+
"901471bdf9dedb5d87659dade4102b56794f480617ab534d3f86d18a291be443",
|
|
528
|
+
// .cursor/scripts/plan-external-review.sh as shipped in v5.7.0
|
|
529
|
+
// .cursor/scripts/comms-draft.mjs is not an L0 artifact today (never written to a
|
|
530
|
+
// consumer); listed so a copy at any released tag refreshes if it joins the overlay.
|
|
531
|
+
"9f44b146b88d6bad2f27ddf03b7241223e63d5785f4bfc5fe3fba2e5208286f3",
|
|
532
|
+
// .cursor/scripts/comms-draft.mjs as shipped in v5.3.0
|
|
533
|
+
"f9377bc3547b6202267745905337e7b4562fb8cb5949198401b89fa5ff99c628",
|
|
534
|
+
// .cursor/scripts/comms-draft.mjs as shipped in v5.4.0–v5.7.0
|
|
535
|
+
"434d3c01e60a3ce5247b990486d251b9ddba66f3cdf0cf6da84b8b3a030b41e4",
|
|
536
|
+
"b5f6bbbb9ae839989dccf1758ebf2d08c826295be820c1c41e0b7914dd34481d",
|
|
537
|
+
"c18004ccafe021fcef38b0a567e2701aeaa6d7d890f43684b7317b5e6428a31b",
|
|
538
|
+
"e093af1f2c8f3bdf6dfa6ab92586ab84b1df180a8b77718b884a0f6f91bd53c4",
|
|
539
|
+
"3a88df22375f90a3a6743f50d9a01129e0373f4ca8dff03fb744c1de3c149409",
|
|
540
|
+
"481a9994ccecaa611173f9ef91a1dbe7458d89758c6a6b5e7c3bbbbf460888ce",
|
|
541
|
+
"691d91fd1e9032b6f9315f29348d4473201917da257258afd74eb954298d8d71",
|
|
542
|
+
"ab0808b7dbc333e523b87b126bb655353cde2574db30d849cc9c9037843bef8c",
|
|
543
|
+
"85514e26af694bbe38e7ddf625710a32719ddf6afc173843c9cdfbffdad8e466",
|
|
544
|
+
"35b6c0cde7538fb1837d54ba841668e82ac7b9e3ef274adcea3d7f34ba4bfb64",
|
|
545
|
+
"4230e45f2ccd89cf8e25c56d21dfbfbe134613c686ea361243f94c49cf6802af",
|
|
546
|
+
"b4fbb2c15a1330ba36351a90490696fd558a347d25ac14af768017d6155335c0",
|
|
547
|
+
"c37ee51662b6eca65224d737911a4bb209a3742694b37a4d00ed29abc4e0b253",
|
|
548
|
+
"f46a0e36c1ee887ad7e62fa00a8facefe90605827de7bf2e6f90655d6660ed0e",
|
|
549
|
+
"40edd2d21be802af95501cf3492665ee48423439cfc64c14f17ed1e7eb8bdfdf",
|
|
550
|
+
"08c15346f42360bd7a4b4e803ca88e5f1727d9db106e7dc4d96523ee7aba129a",
|
|
551
|
+
"0cc36b633ca1a18fa472ed8040a5b927b4c918318dbd17f6163b706cd7a8acbe",
|
|
552
|
+
"0fdc92828174abba815db3799a274aca70cccacca573d949e412d4622928ec50",
|
|
553
|
+
"33fc7d6bc49cea32bd737e46aaf63ad2bedbc72a52615fc2b881e6ddbb34587a",
|
|
554
|
+
"45c475337798bdbf5bd3a42c1f085278d1563a9e76c1295961b1ce66a89b4820",
|
|
555
|
+
"484df32ebf132fb121ab1e31b0e64345058c9c82b2a39498cc06d1794c270f23",
|
|
556
|
+
"60aa86ca3f2873908e57c2830675eec393c114cd711b3b162d02be355792b697",
|
|
557
|
+
"85c307d01e36dc62d4a341c1932b0a7fae3663f28ec0e32ad5cda30f35ffca86",
|
|
558
|
+
"9133d73c070243947b3bf9ffec78d21d66a5cb7488c11a4bf731b3c9c3529b3c",
|
|
559
|
+
"c082e903d9569b297c93a41ea561718a5258dfefd6a0f0457402f565caa1bbd0",
|
|
560
|
+
"c10bcbc952e58e8f89818c5119cde7b54bab5b74c5b194b5d26b2b125ec1036a",
|
|
561
|
+
"ed68d0fe3dca46c159402a1ae62148d2482352718be792ff65fd38efae706bef",
|
|
562
|
+
"8356eda7f3597c3d3726b32f87f6f4da87999be93760e738748138acc2a3d73e",
|
|
563
|
+
"90a8e3a67e41c33b93da824290148e4af84d3d49848727fa88b34d8df9bad29a",
|
|
564
|
+
"ec51cebd225fc861072b62e4ee0292fd4ba01ba0817770e7a379ad41d7bd850a",
|
|
565
|
+
"3edb378d29c89081c9ad6439b077aa928a21aed864aed5ef02e819b75ac33d7a",
|
|
566
|
+
"634f1d9ac6f632074054c5b029567303d783f1fc01e62be588668d20044fadcc",
|
|
567
|
+
"bc5c76a5b63fad600c94786300284987f54d237e3f7d38bb8b520906a9685ba2",
|
|
568
|
+
"efcbbf40f1e616e2e7ae513765463806b192bd5e6b8acd3be832bf590c14a542",
|
|
569
|
+
"2ef2688b31b86a4bbf358f3662495a65314b2edf2b7b2215d71e5be9cff90d22",
|
|
570
|
+
"a9cad5b77ae12cfa907a4e460d39be75c8f864a27e7f85394bef67120a6fba45",
|
|
571
|
+
"c35c76052f76cb45a970fcb825d5ddc49f7e371441f0953735ffb9d072da2680",
|
|
572
|
+
"611279d799db865e5329ed8723d73ebd2d839c273b52aef12803b4b11a75a75a",
|
|
573
|
+
"28840c700bdf8968b6f02c6bbb9cf965643f30f0911b2622a9c01dfae233d8fb",
|
|
574
|
+
"947f39141a3f830cd29145a74058d48c2feb8fbcd958ea7f90522e46fb0c25c5",
|
|
575
|
+
"c8535a73997daf1800394626d0e4845c923544040bae85a724ca427f56ba9812",
|
|
576
|
+
"9486e4ae754782114b1ec7d22baf661a8f33413d01fcf3a0759f97f1eedd84c1",
|
|
577
|
+
"8453f7d9d818b101d0d7b0cf5d0985e57174285f4cb7899517d5af52bc6490d5",
|
|
578
|
+
"9a877468512ffa14e77940757b3532c20f6fda7878419c9986f6d9e03ca31081",
|
|
579
|
+
"db310ca8f9841b5937f475ab042d768f84bc00a29282fbcce159fc9bf7646921",
|
|
580
|
+
"052217cbd533ef7214bb55f9e7a7d8cb979f0a4b32e42f8b98b57ebd86935d25",
|
|
581
|
+
"0aab08e34dd433fd38fa3f4d6729d1a7a2f626387fdb2b9bc8a48bd0f84be2f3",
|
|
582
|
+
"4bdbc2837b195c529d83302bd3c830d7d669879757ac3f92ec1d1ac703b21522",
|
|
583
|
+
"744c0d44e26b8a8fb7272b07eff884da583a8b73a50f7a1e4a9be55ecb40b39e",
|
|
584
|
+
"7b791a2ec4ff31bb6f19d60bc19152fb1ee5139b56254b9a3ba783a7f1bf9016",
|
|
585
|
+
"7e5a4a5f88ee48f17fe40e66772da4816480b1fba5fff5a58026d05753614393",
|
|
586
|
+
"c0b51e50d6117ce597c096386a1928f803e3abf1a65f6948ff7b00583651db5e",
|
|
587
|
+
"d1c8ea35ae9bdb5dad47c3ab80d73d5a327a0379216bead38eda18c0f2836fe9",
|
|
588
|
+
"e299dd585ed6c37292758d2821663aa46a80d6c7964f67b3d1d3279cf746e764",
|
|
589
|
+
"51a5608322e14694fafad15cbb710663800dc315d4deb12516c1591ac94e3ed7",
|
|
590
|
+
"78d553f98cc172dd6f0f3b2e01056813a32a894f6bdca64e665265df84a8eb0b",
|
|
591
|
+
"90c466fbe5bf7e6f3936b8a46407fbd5d0d542582c39b697ecbb5ada1be482ce",
|
|
592
|
+
"d2f539aa6340b1e41f6f47d179a2c17666415b82e7bf02be9416061855b5534c",
|
|
593
|
+
"05034e22b01b830b1fe12df4834e6c57eb0b152539e469d8d4e393b2b61dd76d",
|
|
594
|
+
"3268c3549d9634aefe29e399961a3be0ebb6e205d454609411ea877da4552d51",
|
|
595
|
+
"5c583058ae2d35e9a650a7a0d2ee304be8e71e361b51ea6903b2cd6ac14fd6a1",
|
|
596
|
+
"7c3cb1f7f449b6a459532d1dc315d574b7148f0d373f3e3271a52ad0151e0eb4",
|
|
597
|
+
"1163b51a64118363c90db5f0b8f7280fcea335631768f83e64fdf1948b41df89",
|
|
598
|
+
"a1590ecae718e7c43f356ddfc76c983f499725970a1953bf6d4d2d4ebf8fa1dc",
|
|
599
|
+
"2b69c26c0dacd5596906178138f85b2b14076552e1995817ea64bf99f48e0ed2",
|
|
600
|
+
"6e3e62f4d47d66cc55f659cf37b7c1ff4f9b43581b9470e740d60768217c1a23",
|
|
601
|
+
"60a3ef8eddf0f262fce40a32b715ee4c2e68d52e18f74d790e68a0f54c8657f1",
|
|
602
|
+
"dfd40e3c2c62a2810030e21a78f71f2646eab19b3658e326ecb5cd8def258aad",
|
|
603
|
+
"ee5572cfba7b96285c433ea2f6e469a205c783fba216af6cf4aafefdbf33ff89",
|
|
604
|
+
"85cd5f00c51efcc263b45fe91d1e10278a866d9266392e0ed480cd8ef5da6cc1",
|
|
605
|
+
"8ea5a65412bf4b95fdbb57fcce7c1a046848f161cf8235a3d9b7e752068775a8",
|
|
606
|
+
"974b143673aa6bd202205264d82f30898777e5694d4269449f564fd536f402d7",
|
|
607
|
+
"2317949f51d8a9d31b700c3af60b6fd3bccff1a8520af7707d7909f42bc5cff2",
|
|
608
|
+
"18426bc3bc8fdf0ab7577d92e31310faf3b83001f8e6e6fe5ef1a1043230e178",
|
|
609
|
+
"24cc918e7ffa54df7f6007989fe62b83af1035c9bf6071cac8c4f848e28b04ca",
|
|
610
|
+
"76757eae42daccc0d82c9630eab31041c6d6ea8fe4b4a47843574a6057dd2a4b",
|
|
611
|
+
"88db17beb9ce2b95b2ce2c1df753b96933024a464cc847770d3f05cd7de2872c",
|
|
612
|
+
"71fff34e9392692d58f3dc92ed65d070f0b476446e0a183a8fbad66d46f3a785",
|
|
613
|
+
"73e3ca429cb522b0877f0d6d46bedbaf270f94bc63bb87f4e0fc7c512bf36e9c",
|
|
614
|
+
"9a61f7432cf66be53d42b5d6f3c67ea71dd5efa1cc18d77d996f08ffea873373",
|
|
615
|
+
"fd2a8867de62f83c89ae11295cae5b5699360b5205f9726c2c47c064318bd7a4",
|
|
616
|
+
"364126473e089ed09a71e3f9eed80b1d602b35b4baa669b0a4f4be0519a787f8",
|
|
617
|
+
"cb14c0162e66ac565679089a566a725b26989db3536b7dba89bff77cb6010969",
|
|
618
|
+
"ebf490086ea45a7b342b3ec7408c9a82b22031daaefddf4425b6e6e931f6d6c8",
|
|
619
|
+
"3077e013297c7dd1e32eb2fa86e1ffa1de7d8740058652782bb8d391782eed71",
|
|
620
|
+
"7e0fa1bb73c8b6f1358cae19477304d85edfb7d4d9a7faf37c00e0578ed79edf",
|
|
621
|
+
"c5f4ddb5dcf5f40919bedce89870af99422c6f3c9d540ca1f7554a66eaa2f2a8",
|
|
622
|
+
"62b744c1cc00f54601579b164d198838395e6ed8e4bcff67fdf55e0e1d9a7d9e",
|
|
623
|
+
"b1d129c5648014b97e7e1a8577b21b17d35d0bf84494f8be7cc142d51eb1da49",
|
|
624
|
+
"d05dfe1f6405f9d04c0f0113dbd34decf59b75840fb1d916b4c51c8961211b5f",
|
|
625
|
+
"4377b06a6ee0e44ce4a8125a0eba8e4c512a249533221570ac426308ba282c50",
|
|
626
|
+
"9cb8284762a05b4b67f8eb4a06d981bf574b30b02c30d23639a92ddfdeb838fc",
|
|
627
|
+
"bc71bb9c93cb9a4aaba901537681cdb81a5f2a9fd1e6f740eb54bca25b7b878e",
|
|
628
|
+
"f502f374f1d25cb20448aeebe678caa17a3c9cd0c683aaf8073878dda72e5375",
|
|
629
|
+
"5fb839c42331b9298302c374334c358a73ec58bb5bb5a6942847f9e49c154b3c",
|
|
630
|
+
"1782bf44268490c9e5465aa890447f01b1bc88e426dd8968186c5c9a7493086e",
|
|
631
|
+
"4ab0925a44544c1a43e5abc007a0e5ec2bd60353ec67ce82f8a68f2623dccac0",
|
|
632
|
+
"0970a3732ee6a869b5f96494d8e3a69850989745a8841dd64b96aa5f9d6e54d4",
|
|
633
|
+
"86cf6c8c0aa44c47736ebc741c2cd7d88c2566d4612859e873eb330613c2d0f4",
|
|
634
|
+
"38f1aafe4d1c6e3ec450c252acc4a02d963bd95eb8412481a466e07739aad08f",
|
|
635
|
+
"a56905278b2d5c31b253f08b8d352401a261556b0c1a9ddc3a825c95bd1c24d9",
|
|
636
|
+
"cdd8f7d7311ebc5c741011f8243c8bf4d569e5dfdeb1bc42cc63150fc691c0b1",
|
|
637
|
+
"a34699ec6ee5319095c1f942b2dda529267024731c1226af527b5e965fcb263a",
|
|
638
|
+
"d4fd6b07139c50f1279603b4043c7d3416fb28e5f4905d57246945fcb4155e46",
|
|
639
|
+
"41d37520284fea44e97215c11840919c7397bdee02d99995efc6fdd345aeb490",
|
|
640
|
+
"e4e9348c9733f2dbc4a51e5104724df223ce1c28bcc1c9c0d8f3fdb8d0636a18",
|
|
641
|
+
"faf23127658c7be0c654ddb4f1e59cbda3b6332098f4609ffb595f1ff3779093",
|
|
642
|
+
"4fc6a944e4dbb60f73d2806f92f0e9ee9a289768b774d57488f3ff2ea8a648ee",
|
|
643
|
+
"50e4c09c91871cf93eeb39a175271ab881da332d867c9e021912188c6daaff36",
|
|
644
|
+
"6b03e518bed270d22ccab3e31eac9a38b65aadb5ab2a9b94a5728bc98866d170",
|
|
645
|
+
"6e6ac653f78181274643c0195fd45e54b84a30f1d8c04ed162cb0c8413f6fd14",
|
|
646
|
+
"9d457611a5446552e339d6538cb72cb486bfece828b9c84901632a7f91af6f2d",
|
|
647
|
+
"beb9c3973c476f03270474b947843ebfa75e42f146ffefa36d5a8a9c421c3d48",
|
|
648
|
+
"b95d8a09adfdb8e4682fb465679eb08d8a0df12a98569314d1b9160a458c5fd2",
|
|
649
|
+
"8097f5120fe05288255fb2c6958bac3fe0dc656d5a47edc1b6034d708a1a66ad",
|
|
650
|
+
"4a576f4c99aa6f3cc3e5a5f3b2683092f906d2630a477b4ed25012bd78375cbc",
|
|
651
|
+
"0b938de3209ef379552b2bb318b87db37b624fcd70c54ce4ad4a236ce78fda7c",
|
|
652
|
+
"254385f5e8b81984432049bcc0b242f30ef19ebeb390b0ff0b5ee40cb685ab0f",
|
|
653
|
+
"36f3ada91168a220adddffc5ce854ce6b247b2b31d93a24ebad503f5f23b084e",
|
|
654
|
+
"78febafce5d57f070c48186073dff66bd760b93cf4cd062eab6011d28d2fdb35",
|
|
655
|
+
"e48c3f064baf8200c415b4eef0c8f7392ba028183c90f5c9cf27c11a64320506",
|
|
656
|
+
"16c82c42a411ae43a20058e3f7b0275ee28c4dcc29dbf60200df3f22e9a822f6",
|
|
657
|
+
"96ae34198c7272f870b948c70bcd0c5b08c3c107b8725114e49f81643f2cee2d",
|
|
658
|
+
"85fbe0b7c94becea111ca74d8d78af02946ca6ed92d37dc2acdb6a79cbe382e3",
|
|
659
|
+
"7bd09f38fa6eb0f10784a92a93126625e394ae7b3049663e1eef8fd813b36084",
|
|
660
|
+
"1edcd3a11466e0e0096a6f10c8c659ac854bff1da932f954eaf88155bee2664a",
|
|
661
|
+
"7a2b2fd9d04867fe1d81d703be6101e331072dc88f741c079a1db3ceb5b909e2",
|
|
662
|
+
"c01a56bde96881b970b1d8adfa591439e32d2d9757cd04b2c0aff9397d3b43ee",
|
|
663
|
+
"d285be59fa627135074bd0458071ff04ff7a5a645de021b9f2bdf6ca1e6ccac5",
|
|
664
|
+
"e76d2d2a02da56896e19d271b4242d89bb5be3688a474d5cedd02645625a1691",
|
|
665
|
+
"5f1a47074e04cb0ccb6c1afb124f8151b6744553719249e9a71709ca72c1dcc0",
|
|
666
|
+
"d665d93a388b2bc7847a34dcbf59da872249153f5790c93e474fda78567f69b2",
|
|
667
|
+
"daf55d66744175670f34c009b740c5d01ceeee226c0deeb57c076715c6f91698",
|
|
668
|
+
"40d896ae39cbb7aa4c514405bb4b30a02ef7f8d72496707052f9b356d3b592e7",
|
|
669
|
+
"ae489d7e19436f99c8a32040ca60fcf5ab885d7106003d163cde9b902a91754b",
|
|
670
|
+
"f2595c418fe8544bb031e8917dbcc1eedfbd8547cee64ab7c08c6af132868d45",
|
|
671
|
+
"3813489721d4ee4d5f0a7fa478e4fa29380b02771604f6547341bc95aa6d4464",
|
|
672
|
+
"401141ae7b12c8dbba15393b30f63c5a6da344a54efe74346041935aa3503f73",
|
|
673
|
+
"631423417bc9400db86f6d09d5e7eb72e71e1682bf300bac38fbf3c9343f13da",
|
|
674
|
+
"8e85854d78e7f05651994dc5a428e6025b535a2da80df198dedb8ed11cb9a88a",
|
|
675
|
+
"116ae95ddcf5e02553da516314b800a167244402582694134b3cbba68892fe51",
|
|
676
|
+
"43461708227d807baa4aec3df043ee0e1a715aa7e771a13d710e01029a0d933d",
|
|
677
|
+
"780b713d6ac68ba978497095e528e351e9963589937d22dbda5d21c8660cb1a4",
|
|
678
|
+
"41d3eac7f116ec22535d830149979fe0a8dbf44625dd841bc9785cbd7c5ddc95",
|
|
679
|
+
"80e11549ad3700d1e7345447aff1b3858e532e9347594ee4f028566c8c7b8a6a",
|
|
680
|
+
"1ffbfa48a76d39f78db66f4ea250c451ae335c31d7e45d0fdc4d99bc714bae33",
|
|
681
|
+
"19a5aa359e740fa18d7cc19f0b11243bc53d8d016545bce35837deac7fe2ef7e",
|
|
682
|
+
"f1c7beac6a619520d744fd984bc16b322f3d545b9d8490801aee628dabd94aff",
|
|
683
|
+
"14d919d01637aa6b5acc92804dbb4ab56cecc88281aedd5cb7b5dcf8f7da958e",
|
|
684
|
+
"a8decf7b78e2b2c833b0808c3e108322cfb895fadaec159467973a681028d92a"
|
|
685
|
+
]);
|
|
686
|
+
|
|
687
|
+
// src/lifecycle/paths.ts
|
|
688
|
+
import { lstat, realpath } from "fs/promises";
|
|
689
|
+
import path3 from "path";
|
|
690
|
+
function resolveContained(root, rel) {
|
|
691
|
+
const rootAbs = path3.resolve(root);
|
|
692
|
+
const candidate = path3.resolve(rootAbs, rel);
|
|
693
|
+
if (escapesRoot(rootAbs, candidate)) {
|
|
694
|
+
throw new Error(`Path escapes registry/project root: ${rel}`);
|
|
695
|
+
}
|
|
696
|
+
return candidate;
|
|
697
|
+
}
|
|
698
|
+
function escapesRoot(rootAbs, candidate) {
|
|
699
|
+
const relToRoot = path3.relative(rootAbs, candidate);
|
|
700
|
+
return relToRoot === ".." || relToRoot.startsWith(`..${path3.sep}`) || path3.isAbsolute(relToRoot);
|
|
701
|
+
}
|
|
702
|
+
async function assertRealContained(root, abs) {
|
|
703
|
+
const stat2 = await lstat(abs);
|
|
704
|
+
if (stat2.isSymbolicLink()) {
|
|
705
|
+
throw new Error(`Refusing to follow symlink: ${abs}`);
|
|
706
|
+
}
|
|
707
|
+
const [rootReal, absReal] = await Promise.all([realpath(root), realpath(abs)]);
|
|
708
|
+
if (escapesRoot(rootReal, absReal)) {
|
|
709
|
+
throw new Error(`Path resolves outside root via symlink: ${abs}`);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
async function assertRealParentContained(root, abs) {
|
|
713
|
+
let dir = path3.dirname(abs);
|
|
714
|
+
for (; ; ) {
|
|
715
|
+
try {
|
|
716
|
+
await lstat(dir);
|
|
717
|
+
break;
|
|
718
|
+
} catch {
|
|
719
|
+
const parent = path3.dirname(dir);
|
|
720
|
+
if (parent === dir) break;
|
|
721
|
+
dir = parent;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
const [rootReal, dirReal] = await Promise.all([realpath(root), realpath(dir)]);
|
|
725
|
+
if (escapesRoot(rootReal, dirReal)) {
|
|
726
|
+
throw new Error(`Parent directory resolves outside root via symlink: ${abs}`);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
async function isRealWriteTargetContained(root, abs) {
|
|
730
|
+
try {
|
|
731
|
+
let exists = true;
|
|
732
|
+
try {
|
|
733
|
+
await lstat(abs);
|
|
734
|
+
} catch {
|
|
735
|
+
exists = false;
|
|
736
|
+
}
|
|
737
|
+
if (exists) await assertRealContained(root, abs);
|
|
738
|
+
else await assertRealParentContained(root, abs);
|
|
739
|
+
return true;
|
|
740
|
+
} catch {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
function toPosixRel(root, absPath) {
|
|
745
|
+
return path3.relative(root, absPath).split(path3.sep).join("/");
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// src/lifecycle/overlay.ts
|
|
749
|
+
var MANAGED_HASHES_REL = ".cursor/agent-kit.managed-hashes.json";
|
|
750
|
+
var CONSUMER_OVERLAY_PREFIXES = [
|
|
751
|
+
".cursor/agents/",
|
|
752
|
+
".cursor/skills/",
|
|
753
|
+
".cursor/commands/",
|
|
754
|
+
".claude/commands/",
|
|
755
|
+
".cursor/hooks/",
|
|
756
|
+
".cursor/scripts/"
|
|
757
|
+
];
|
|
758
|
+
function isConsumerOverlayPath(relPath) {
|
|
759
|
+
const norm = relPath.split(path4.sep).join("/");
|
|
760
|
+
return CONSUMER_OVERLAY_PREFIXES.some((p) => norm.startsWith(p));
|
|
761
|
+
}
|
|
762
|
+
function contentHash(content) {
|
|
763
|
+
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
764
|
+
}
|
|
765
|
+
async function loadManagedHashLedger(projectRoot) {
|
|
766
|
+
const abs = resolveContained(projectRoot, MANAGED_HASHES_REL);
|
|
767
|
+
try {
|
|
768
|
+
const raw = await readFile(abs, "utf8");
|
|
769
|
+
const parsed = JSON.parse(raw);
|
|
770
|
+
if (parsed && typeof parsed === "object" && parsed.hashes && typeof parsed.hashes === "object") {
|
|
771
|
+
return { schemaVersion: 1, hashes: { ...parsed.hashes } };
|
|
772
|
+
}
|
|
773
|
+
} catch {
|
|
774
|
+
}
|
|
775
|
+
return { schemaVersion: 1, hashes: {} };
|
|
776
|
+
}
|
|
777
|
+
async function saveManagedHashLedger(projectRoot, ledger) {
|
|
778
|
+
const abs = resolveContained(projectRoot, MANAGED_HASHES_REL);
|
|
779
|
+
await mkdir(path4.dirname(abs), { recursive: true });
|
|
780
|
+
const payload = {
|
|
781
|
+
schemaVersion: 1,
|
|
782
|
+
hashes: { ...ledger.hashes }
|
|
783
|
+
};
|
|
784
|
+
await writeFile(abs, `${JSON.stringify(payload, null, 2)}
|
|
785
|
+
`, "utf8");
|
|
786
|
+
}
|
|
787
|
+
function shouldPreserveCustomizedOverlay(localContent, recordedHash, knownShippedHashes = KNOWN_SHIPPED_OVERLAY_HASHES) {
|
|
788
|
+
const localHash = contentHash(localContent);
|
|
789
|
+
if (!recordedHash) {
|
|
790
|
+
return !knownShippedHashes.has(localHash);
|
|
791
|
+
}
|
|
792
|
+
return localHash !== recordedHash;
|
|
793
|
+
}
|
|
794
|
+
async function seedManagedHashLedger(projectRoot) {
|
|
795
|
+
const ledger = await loadManagedHashLedger(projectRoot);
|
|
796
|
+
for (const prefix of CONSUMER_OVERLAY_PREFIXES) {
|
|
797
|
+
const prefixPath = resolveContained(projectRoot, prefix);
|
|
798
|
+
let entries;
|
|
799
|
+
try {
|
|
800
|
+
entries = await readdir(prefixPath, { withFileTypes: true, recursive: true });
|
|
801
|
+
} catch {
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
for (const entry of entries) {
|
|
805
|
+
if (!entry.isFile()) continue;
|
|
806
|
+
const parentPath = String(entry.parentPath);
|
|
807
|
+
const name = String(entry.name);
|
|
808
|
+
const rel = path4.relative(projectRoot, path4.join(parentPath, name));
|
|
809
|
+
const norm = rel.split(path4.sep).join("/");
|
|
810
|
+
if (ledger.hashes[norm]) continue;
|
|
811
|
+
try {
|
|
812
|
+
const content = await readFile(path4.join(parentPath, name), "utf8");
|
|
813
|
+
ledger.hashes[norm] = contentHash(content);
|
|
814
|
+
} catch {
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
await saveManagedHashLedger(projectRoot, ledger);
|
|
819
|
+
return ledger;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// src/lifecycle/apply.ts
|
|
823
|
+
import { copyFile, lstat as lstat2, mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
824
|
+
import path5 from "path";
|
|
825
|
+
function emptyStats() {
|
|
826
|
+
return {
|
|
827
|
+
written: [],
|
|
828
|
+
removed: [],
|
|
829
|
+
collisions: [],
|
|
830
|
+
skippedProtected: [],
|
|
831
|
+
missing: [],
|
|
832
|
+
unchanged: [],
|
|
833
|
+
preservedCustomized: [],
|
|
834
|
+
skippedSymlink: []
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
function mergeStats(into, from) {
|
|
838
|
+
into.written.push(...from.written);
|
|
839
|
+
into.removed.push(...from.removed);
|
|
840
|
+
into.collisions.push(...from.collisions);
|
|
841
|
+
into.skippedProtected.push(...from.skippedProtected);
|
|
842
|
+
into.missing.push(...from.missing);
|
|
843
|
+
into.unchanged.push(...from.unchanged);
|
|
844
|
+
into.preservedCustomized.push(...from.preservedCustomized);
|
|
845
|
+
into.skippedSymlink.push(...from.skippedSymlink);
|
|
846
|
+
return into;
|
|
847
|
+
}
|
|
848
|
+
async function copyRegistryFile(registryRoot, projectRoot, sourceRel, targetRel, protectedGlobs, options = {}) {
|
|
849
|
+
const targetNorm = targetRel.split(path5.sep).join("/");
|
|
850
|
+
if (isProtectedPath(targetNorm, protectedGlobs)) {
|
|
851
|
+
return "skipped-protected";
|
|
852
|
+
}
|
|
853
|
+
const sourceAbs = resolveContained(registryRoot, sourceRel);
|
|
854
|
+
const targetAbs = resolveContained(projectRoot, targetRel);
|
|
855
|
+
for (const [root, abs] of [
|
|
856
|
+
[registryRoot, sourceAbs],
|
|
857
|
+
[projectRoot, targetAbs]
|
|
858
|
+
]) {
|
|
859
|
+
const contained = await pathExists(abs) ? await isRealContained(root, abs) : await isRealParentContained(root, abs);
|
|
860
|
+
if (!contained) return "skipped-symlink";
|
|
861
|
+
}
|
|
862
|
+
try {
|
|
863
|
+
await readFile2(sourceAbs);
|
|
864
|
+
} catch {
|
|
865
|
+
return "missing-source";
|
|
866
|
+
}
|
|
867
|
+
let existing = null;
|
|
868
|
+
try {
|
|
869
|
+
existing = await readFile2(targetAbs, "utf8");
|
|
870
|
+
} catch {
|
|
871
|
+
existing = null;
|
|
872
|
+
}
|
|
873
|
+
const next = await readFile2(sourceAbs, "utf8");
|
|
874
|
+
if (existing === next) {
|
|
875
|
+
if (isConsumerOverlayPath(targetNorm)) {
|
|
876
|
+
await touchOverlayHash(projectRoot, targetNorm, next, options);
|
|
877
|
+
}
|
|
878
|
+
return "unchanged";
|
|
879
|
+
}
|
|
880
|
+
if (existing !== null && isConsumerOverlayPath(targetNorm)) {
|
|
881
|
+
const ledger = options.managedHashes ?? await loadManagedHashLedger(projectRoot);
|
|
882
|
+
const recorded = ledger.hashes[targetNorm];
|
|
883
|
+
if (shouldPreserveCustomizedOverlay(existing, recorded)) {
|
|
884
|
+
if (!recorded) {
|
|
885
|
+
const managedHash = contentHash(next);
|
|
886
|
+
ledger.hashes[targetNorm] = managedHash;
|
|
887
|
+
if (options.managedHashes) {
|
|
888
|
+
options.managedHashes.hashes[targetNorm] = managedHash;
|
|
889
|
+
}
|
|
890
|
+
if (options.persistManagedHashes !== false) {
|
|
891
|
+
await saveManagedHashLedger(projectRoot, ledger);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return "preserved-customized";
|
|
895
|
+
}
|
|
896
|
+
await mkdir2(path5.dirname(targetAbs), { recursive: true });
|
|
897
|
+
await copyFile(sourceAbs, targetAbs);
|
|
898
|
+
ledger.hashes[targetNorm] = contentHash(next);
|
|
899
|
+
if (options.managedHashes) {
|
|
900
|
+
options.managedHashes.hashes[targetNorm] = ledger.hashes[targetNorm];
|
|
901
|
+
}
|
|
902
|
+
if (options.persistManagedHashes !== false) {
|
|
903
|
+
await saveManagedHashLedger(projectRoot, ledger);
|
|
904
|
+
}
|
|
905
|
+
return "written";
|
|
906
|
+
}
|
|
907
|
+
await mkdir2(path5.dirname(targetAbs), { recursive: true });
|
|
908
|
+
await copyFile(sourceAbs, targetAbs);
|
|
909
|
+
if (isConsumerOverlayPath(targetNorm)) {
|
|
910
|
+
await touchOverlayHash(projectRoot, targetNorm, next, options);
|
|
911
|
+
}
|
|
912
|
+
return "written";
|
|
913
|
+
}
|
|
914
|
+
async function isRealContained(root, abs) {
|
|
915
|
+
try {
|
|
916
|
+
await assertRealContained(root, abs);
|
|
917
|
+
return true;
|
|
918
|
+
} catch {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
async function isRealParentContained(root, abs) {
|
|
923
|
+
try {
|
|
924
|
+
await assertRealParentContained(root, abs);
|
|
925
|
+
return true;
|
|
926
|
+
} catch {
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
async function pathExists(abs) {
|
|
931
|
+
try {
|
|
932
|
+
await lstat2(abs);
|
|
933
|
+
return true;
|
|
934
|
+
} catch {
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
async function touchOverlayHash(projectRoot, targetNorm, content, options) {
|
|
939
|
+
const ledger = options.managedHashes ?? await loadManagedHashLedger(projectRoot);
|
|
940
|
+
const hash = contentHash(content);
|
|
941
|
+
if (ledger.hashes[targetNorm] === hash) return;
|
|
942
|
+
ledger.hashes[targetNorm] = hash;
|
|
943
|
+
if (options.managedHashes) {
|
|
944
|
+
options.managedHashes.hashes[targetNorm] = hash;
|
|
945
|
+
}
|
|
946
|
+
if (options.persistManagedHashes !== false) {
|
|
947
|
+
await saveManagedHashLedger(projectRoot, ledger);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
function recordOutcome(stats, targetRel, outcome) {
|
|
951
|
+
const rel = targetRel.split(path5.sep).join("/");
|
|
952
|
+
switch (outcome) {
|
|
953
|
+
case "written":
|
|
954
|
+
stats.written.push(rel);
|
|
955
|
+
break;
|
|
956
|
+
case "skipped-protected":
|
|
957
|
+
stats.skippedProtected.push(rel);
|
|
958
|
+
break;
|
|
959
|
+
case "missing-source":
|
|
960
|
+
stats.missing.push(rel);
|
|
961
|
+
break;
|
|
962
|
+
case "unchanged":
|
|
963
|
+
stats.unchanged.push(rel);
|
|
964
|
+
break;
|
|
965
|
+
case "preserved-customized":
|
|
966
|
+
stats.preservedCustomized.push(rel);
|
|
967
|
+
break;
|
|
968
|
+
case "skipped-symlink":
|
|
969
|
+
stats.skippedSymlink.push(rel);
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
async function saveManifest(projectRoot, manifest) {
|
|
974
|
+
const target = path5.join(projectRoot, MANIFEST_RELATIVE_PATH);
|
|
975
|
+
const { unknownFields, ...known } = manifest;
|
|
976
|
+
const payload = {
|
|
977
|
+
...known,
|
|
978
|
+
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
979
|
+
// Preserve installedAt on no-op updates (ADR factory-pseudo-consumer
|
|
980
|
+
// decision 4); a version change earns a fresh install timestamp.
|
|
981
|
+
installedAt: manifest.installedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
982
|
+
};
|
|
983
|
+
for (const [key, value] of Object.entries(unknownFields ?? {})) {
|
|
984
|
+
if (!(key in payload)) payload[key] = value;
|
|
985
|
+
}
|
|
986
|
+
await writeJson(target, payload);
|
|
987
|
+
return toPosixRel(projectRoot, target);
|
|
988
|
+
}
|
|
989
|
+
function buildManifest(input) {
|
|
990
|
+
const manifest = {
|
|
991
|
+
schemaVersion: 1,
|
|
992
|
+
version: input.version,
|
|
993
|
+
protected: normalizeProtectedGlobs(input.protected ?? [...DEFAULT_PROTECTED_PATHS])
|
|
994
|
+
};
|
|
995
|
+
if (input.profile) manifest.profile = input.profile;
|
|
996
|
+
if (input.packs?.length) manifest.packs = [...new Set(input.packs)].sort();
|
|
997
|
+
if (input.skills?.length) manifest.skills = [...new Set(input.skills)].sort();
|
|
998
|
+
if (input.personalization) manifest.personalization = input.personalization;
|
|
999
|
+
if (input.registryUrl || input.registryRef) {
|
|
1000
|
+
manifest.registry = {};
|
|
1001
|
+
if (input.registryUrl) manifest.registry.url = input.registryUrl;
|
|
1002
|
+
if (input.registryRef) manifest.registry.ref = input.registryRef;
|
|
1003
|
+
}
|
|
1004
|
+
return manifest;
|
|
1005
|
+
}
|
|
1006
|
+
function upsertIdList(list, id) {
|
|
1007
|
+
return [.../* @__PURE__ */ new Set([...list ?? [], id])].sort();
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// src/registry/install.ts
|
|
1011
|
+
import { readFile as readFile3, readdir as readdir2 } from "fs/promises";
|
|
1012
|
+
import path6 from "path";
|
|
1013
|
+
function skillTargetDir(skillPath, skillId) {
|
|
1014
|
+
const category = skillPath.includes("/core/") ? "core" : "community";
|
|
1015
|
+
return path6.posix.join(".cursor", "skills", category, skillId);
|
|
1016
|
+
}
|
|
1017
|
+
async function skillFileTargets(registryRoot, skillPath, skillId) {
|
|
1018
|
+
const targetDir = skillTargetDir(skillPath, skillId);
|
|
1019
|
+
const pair = (rel) => ({
|
|
1020
|
+
sourceRel: path6.posix.join(skillPath, rel),
|
|
1021
|
+
targetRel: path6.posix.join(targetDir, rel)
|
|
1022
|
+
});
|
|
1023
|
+
let companions = [];
|
|
1024
|
+
try {
|
|
1025
|
+
const dirAbs = resolveContained(registryRoot, skillPath);
|
|
1026
|
+
const entries = await readdir2(dirAbs, { withFileTypes: true, recursive: true });
|
|
1027
|
+
companions = entries.filter((entry) => entry.isFile()).map((entry) => {
|
|
1028
|
+
const parent = path6.relative(dirAbs, entry.parentPath ?? dirAbs);
|
|
1029
|
+
return path6.join(parent, entry.name).split(path6.sep).join("/");
|
|
1030
|
+
}).filter((rel) => rel !== "SKILL.md" && !rel.split("/").some((seg) => seg.startsWith("."))).sort();
|
|
1031
|
+
} catch {
|
|
1032
|
+
companions = [];
|
|
1033
|
+
}
|
|
1034
|
+
return [pair("SKILL.md"), ...companions.map(pair)];
|
|
1035
|
+
}
|
|
1036
|
+
function targetForMember(member) {
|
|
1037
|
+
switch (member.kind) {
|
|
1038
|
+
case "skill":
|
|
1039
|
+
return {
|
|
1040
|
+
sourceRel: path6.posix.join(member.source, "SKILL.md"),
|
|
1041
|
+
targetRel: path6.posix.join(skillTargetDir(member.source, member.id), "SKILL.md")
|
|
1042
|
+
};
|
|
1043
|
+
case "rule":
|
|
1044
|
+
return {
|
|
1045
|
+
sourceRel: member.source,
|
|
1046
|
+
targetRel: path6.posix.join(".cursor", "rules", path6.posix.basename(member.source))
|
|
1047
|
+
};
|
|
1048
|
+
case "agent":
|
|
1049
|
+
return {
|
|
1050
|
+
sourceRel: member.source,
|
|
1051
|
+
targetRel: path6.posix.join(".cursor", "agents", path6.posix.basename(member.source))
|
|
1052
|
+
};
|
|
1053
|
+
case "command":
|
|
1054
|
+
return {
|
|
1055
|
+
sourceRel: member.source,
|
|
1056
|
+
targetRel: path6.posix.join(".cursor", "commands", path6.posix.basename(member.source))
|
|
1057
|
+
};
|
|
1058
|
+
case "hook": {
|
|
1059
|
+
const targetRel = member.source.startsWith(".cursor/") ? member.source : path6.posix.join(".cursor", "hooks", path6.posix.basename(member.source));
|
|
1060
|
+
return { sourceRel: member.source, targetRel };
|
|
1061
|
+
}
|
|
1062
|
+
case "template": {
|
|
1063
|
+
const base = path6.posix.basename(member.source);
|
|
1064
|
+
if (member.source.includes("/context-management/") || member.source.includes("/engineering-architecture/")) {
|
|
1065
|
+
return {
|
|
1066
|
+
sourceRel: member.source,
|
|
1067
|
+
targetRel: path6.posix.join(".cursor", "context", "templates", base)
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
return {
|
|
1071
|
+
sourceRel: member.source,
|
|
1072
|
+
targetRel: path6.posix.join("templates", base)
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1075
|
+
default: {
|
|
1076
|
+
const _exhaustive = member.kind;
|
|
1077
|
+
throw new Error(`Unsupported pack member kind: ${_exhaustive}`);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
async function installSkill(registryRoot, projectRoot, skill, options = {}) {
|
|
1082
|
+
const stats = emptyStats();
|
|
1083
|
+
const managedHashes = options.managedHashes ?? await loadManagedHashLedger(projectRoot);
|
|
1084
|
+
for (const { sourceRel, targetRel } of await skillFileTargets(
|
|
1085
|
+
registryRoot,
|
|
1086
|
+
skill.path,
|
|
1087
|
+
skill.id
|
|
1088
|
+
)) {
|
|
1089
|
+
const outcome = await copyRegistryFile(
|
|
1090
|
+
registryRoot,
|
|
1091
|
+
projectRoot,
|
|
1092
|
+
sourceRel,
|
|
1093
|
+
targetRel,
|
|
1094
|
+
options.protectedGlobs ?? [],
|
|
1095
|
+
{ managedHashes, persistManagedHashes: false }
|
|
1096
|
+
);
|
|
1097
|
+
recordOutcome(stats, targetRel, outcome);
|
|
1098
|
+
}
|
|
1099
|
+
if (!options.managedHashes) await saveManagedHashLedger(projectRoot, managedHashes);
|
|
1100
|
+
return stats;
|
|
1101
|
+
}
|
|
1102
|
+
async function installSkillsByIds(registryRoot, projectRoot, skillIds, options = {}) {
|
|
1103
|
+
const index = await readJson(path6.join(registryRoot, REGISTRY_INDEX_REL));
|
|
1104
|
+
const stats = emptyStats();
|
|
1105
|
+
if (!index) return stats;
|
|
1106
|
+
const pool = allSkills(index);
|
|
1107
|
+
const managedHashes = options.managedHashes ?? await loadManagedHashLedger(projectRoot);
|
|
1108
|
+
const skillOpts = { ...options, managedHashes };
|
|
1109
|
+
try {
|
|
1110
|
+
for (const id of skillIds) {
|
|
1111
|
+
const skill = pool.find((s) => s.id === id);
|
|
1112
|
+
if (!skill) {
|
|
1113
|
+
stats.missing.push(id);
|
|
1114
|
+
continue;
|
|
1115
|
+
}
|
|
1116
|
+
mergeStats(stats, await installSkill(registryRoot, projectRoot, skill, skillOpts));
|
|
1117
|
+
}
|
|
1118
|
+
} finally {
|
|
1119
|
+
if (!options.managedHashes) await saveManagedHashLedger(projectRoot, managedHashes);
|
|
1120
|
+
}
|
|
1121
|
+
return stats;
|
|
1122
|
+
}
|
|
1123
|
+
async function loadPackManifest(registryRoot, packId) {
|
|
1124
|
+
const summary = await findPack(registryRoot, packId);
|
|
1125
|
+
const manifestPath = resolveContained(registryRoot, path6.join(summary.path, "pack.json"));
|
|
1126
|
+
const manifest = await readJson(manifestPath);
|
|
1127
|
+
if (!manifest) throw new Error(`Pack manifest not found at ${manifestPath}`);
|
|
1128
|
+
return manifest;
|
|
1129
|
+
}
|
|
1130
|
+
async function installPack(registryRoot, projectRoot, packId, options = {}) {
|
|
1131
|
+
await loadRegistry(registryRoot);
|
|
1132
|
+
const packManifest = await loadPackManifest(registryRoot, packId);
|
|
1133
|
+
const stats = emptyStats();
|
|
1134
|
+
const protectedGlobs = options.protectedGlobs ?? [];
|
|
1135
|
+
const managedHashes = options.managedHashes ?? await loadManagedHashLedger(projectRoot);
|
|
1136
|
+
const copyOpts = { managedHashes, persistManagedHashes: false };
|
|
1137
|
+
for (const member of packManifest.members) {
|
|
1138
|
+
for (const { sourceRel, targetRel } of await packMemberFileTargets(registryRoot, member)) {
|
|
1139
|
+
const outcome = await copyRegistryFile(
|
|
1140
|
+
registryRoot,
|
|
1141
|
+
projectRoot,
|
|
1142
|
+
sourceRel,
|
|
1143
|
+
targetRel,
|
|
1144
|
+
protectedGlobs,
|
|
1145
|
+
copyOpts
|
|
1146
|
+
);
|
|
1147
|
+
recordOutcome(stats, targetRel, outcome);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
if (!options.managedHashes) await saveManagedHashLedger(projectRoot, managedHashes);
|
|
1151
|
+
return stats;
|
|
1152
|
+
}
|
|
1153
|
+
async function packMemberFileTargets(registryRoot, member) {
|
|
1154
|
+
return member.kind === "skill" ? skillFileTargets(registryRoot, member.source, member.id) : [targetForMember(member)];
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// src/registry/resolve.ts
|
|
1158
|
+
import { execFile } from "child_process";
|
|
1159
|
+
import { createHash as createHash2, randomUUID } from "crypto";
|
|
1160
|
+
import { mkdir as mkdir3, readFile as readFile4, rename, rm, stat, writeFile as writeFile2 } from "fs/promises";
|
|
1161
|
+
import { homedir } from "os";
|
|
1162
|
+
import path7 from "path";
|
|
1163
|
+
import { promisify } from "util";
|
|
1164
|
+
var execFileAsync = promisify(execFile);
|
|
1165
|
+
var LOCK_TIMEOUT_MS = 6e4;
|
|
1166
|
+
var LOCK_RETRY_MS = 200;
|
|
1167
|
+
var LOCK_STALE_MS = 5 * 6e4;
|
|
1168
|
+
var LOCK_REFRESH_MS = 1e4;
|
|
1169
|
+
function lockOwnerPath(lockDir) {
|
|
1170
|
+
return path7.join(lockDir, "owner.json");
|
|
1171
|
+
}
|
|
1172
|
+
function isProcessAlive(pid) {
|
|
1173
|
+
try {
|
|
1174
|
+
process.kill(pid, 0);
|
|
1175
|
+
return true;
|
|
1176
|
+
} catch {
|
|
1177
|
+
return false;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
async function readLockOwner(lockDir) {
|
|
1181
|
+
try {
|
|
1182
|
+
const raw = await readFile4(lockOwnerPath(lockDir), "utf8");
|
|
1183
|
+
const parsed = JSON.parse(raw);
|
|
1184
|
+
if (typeof parsed.pid === "number" && typeof parsed.uuid === "string") {
|
|
1185
|
+
return parsed;
|
|
1186
|
+
}
|
|
1187
|
+
} catch {
|
|
1188
|
+
}
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
async function writeLockOwner(lockDir, owner) {
|
|
1192
|
+
const finalPath = lockOwnerPath(lockDir);
|
|
1193
|
+
const tmpPath = path7.join(lockDir, `owner.${owner.uuid}.${randomUUID()}.tmp`);
|
|
1194
|
+
await writeFile2(tmpPath, JSON.stringify(owner), "utf8");
|
|
1195
|
+
await rename(tmpPath, finalPath);
|
|
1196
|
+
}
|
|
1197
|
+
async function refreshLockOwner(lockDir, uuid) {
|
|
1198
|
+
const owner = await readLockOwner(lockDir);
|
|
1199
|
+
if (owner && owner.uuid !== uuid) return;
|
|
1200
|
+
await writeLockOwner(lockDir, { pid: process.pid, uuid, updatedAt: Date.now() });
|
|
1201
|
+
}
|
|
1202
|
+
async function releaseCacheLock(lockDir, uuid) {
|
|
1203
|
+
const claimPath = path7.join(lockDir, `releasing.${uuid}`);
|
|
1204
|
+
try {
|
|
1205
|
+
await rename(lockOwnerPath(lockDir), claimPath);
|
|
1206
|
+
} catch {
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
let claimed = null;
|
|
1210
|
+
try {
|
|
1211
|
+
const raw = await readFile4(claimPath, "utf8");
|
|
1212
|
+
const parsed = JSON.parse(raw);
|
|
1213
|
+
if (typeof parsed.pid === "number" && typeof parsed.uuid === "string") {
|
|
1214
|
+
claimed = parsed;
|
|
1215
|
+
}
|
|
1216
|
+
} catch {
|
|
1217
|
+
}
|
|
1218
|
+
if (!claimed || claimed.uuid !== uuid) {
|
|
1219
|
+
try {
|
|
1220
|
+
await rename(claimPath, lockOwnerPath(lockDir));
|
|
1221
|
+
} catch {
|
|
1222
|
+
}
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
try {
|
|
1226
|
+
await rm(lockDir, { recursive: true, force: true });
|
|
1227
|
+
} catch {
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
async function tryReclaimStaleLock(lockDir) {
|
|
1231
|
+
let owner;
|
|
1232
|
+
let lockStat;
|
|
1233
|
+
try {
|
|
1234
|
+
lockStat = await stat(lockDir);
|
|
1235
|
+
owner = await readLockOwner(lockDir);
|
|
1236
|
+
} catch {
|
|
1237
|
+
return false;
|
|
1238
|
+
}
|
|
1239
|
+
const now = Date.now();
|
|
1240
|
+
if (owner) {
|
|
1241
|
+
const ownerFresh = now - owner.updatedAt < LOCK_STALE_MS;
|
|
1242
|
+
if (isProcessAlive(owner.pid) && ownerFresh) {
|
|
1243
|
+
return false;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (now - lockStat.mtimeMs > LOCK_STALE_MS) {
|
|
1247
|
+
try {
|
|
1248
|
+
await rm(lockDir, { recursive: true, force: true });
|
|
1249
|
+
return true;
|
|
1250
|
+
} catch {
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
return false;
|
|
1254
|
+
}
|
|
1255
|
+
async function acquireCacheLock(cacheDir) {
|
|
1256
|
+
const lockDir = `${cacheDir}.lock`;
|
|
1257
|
+
const deadline = Date.now() + LOCK_TIMEOUT_MS;
|
|
1258
|
+
const uuid = randomUUID();
|
|
1259
|
+
const owner = { pid: process.pid, uuid, updatedAt: Date.now() };
|
|
1260
|
+
await mkdir3(path7.dirname(lockDir), { recursive: true });
|
|
1261
|
+
let lastErrorCode;
|
|
1262
|
+
while (Date.now() < deadline) {
|
|
1263
|
+
try {
|
|
1264
|
+
await mkdir3(lockDir, { recursive: false });
|
|
1265
|
+
await writeLockOwner(lockDir, owner);
|
|
1266
|
+
let refreshing = false;
|
|
1267
|
+
const refreshInterval = setInterval(() => {
|
|
1268
|
+
if (refreshing) return;
|
|
1269
|
+
refreshing = true;
|
|
1270
|
+
refreshLockOwner(lockDir, uuid).catch(() => {
|
|
1271
|
+
}).finally(() => {
|
|
1272
|
+
refreshing = false;
|
|
1273
|
+
});
|
|
1274
|
+
}, LOCK_REFRESH_MS);
|
|
1275
|
+
return async () => {
|
|
1276
|
+
clearInterval(refreshInterval);
|
|
1277
|
+
await releaseCacheLock(lockDir, uuid);
|
|
1278
|
+
};
|
|
1279
|
+
} catch (err) {
|
|
1280
|
+
const code = err.code;
|
|
1281
|
+
lastErrorCode = code;
|
|
1282
|
+
if (code === "EEXIST") {
|
|
1283
|
+
if (await tryReclaimStaleLock(lockDir)) {
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
await new Promise((r) => setTimeout(r, LOCK_RETRY_MS + Math.random() * 100));
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
if (code === "ENOENT") {
|
|
1290
|
+
await mkdir3(path7.dirname(lockDir), { recursive: true });
|
|
1291
|
+
await new Promise((r) => setTimeout(r, LOCK_RETRY_MS + Math.random() * 100));
|
|
1292
|
+
continue;
|
|
1293
|
+
}
|
|
1294
|
+
throw err;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
throw new Error(
|
|
1298
|
+
lastErrorCode === "ENOENT" ? `Timed out acquiring cache lock on ${cacheDir}: the lock parent directory kept vanishing (concurrent cache clear?).` : `Timed out waiting for cache lock on ${cacheDir}. Another install may be stuck.`
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
var DEFAULT_REGISTRY_URL = "https://github.com/agent-kit-startup/agent-kit";
|
|
1302
|
+
var DEFAULT_REGISTRY_REF = "main";
|
|
1303
|
+
var SAFE_URL = /^https:\/\/[^\s]+$/;
|
|
1304
|
+
var SAFE_REF = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;
|
|
1305
|
+
function assertSafeRegistrySource(url, ref) {
|
|
1306
|
+
if (!SAFE_URL.test(url)) {
|
|
1307
|
+
throw new Error(
|
|
1308
|
+
`Refusing registry url "${url}": only https:// URLs are allowed. Use --registry <local-path> for local checkouts.`
|
|
1309
|
+
);
|
|
1310
|
+
}
|
|
1311
|
+
if (!SAFE_REF.test(ref)) {
|
|
1312
|
+
throw new Error(`Refusing registry ref "${ref}": invalid characters or leading "-".`);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
function gitEnv() {
|
|
1316
|
+
return { ...process.env, GIT_ALLOW_PROTOCOL: "https" };
|
|
1317
|
+
}
|
|
1318
|
+
function cacheKey(url, ref) {
|
|
1319
|
+
return createHash2("sha256").update(`${url}@${ref}`).digest("hex").slice(0, 16);
|
|
1320
|
+
}
|
|
1321
|
+
async function hasRegistryIndex(root) {
|
|
1322
|
+
return fileExists(path7.join(root, REGISTRY_INDEX_REL));
|
|
1323
|
+
}
|
|
1324
|
+
async function cloneRegistry(url, ref, dest) {
|
|
1325
|
+
const { mkdir: mkdir4, rm: rm2 } = await import("fs/promises");
|
|
1326
|
+
await mkdir4(path7.dirname(dest), { recursive: true });
|
|
1327
|
+
const clearPartial = () => rm2(dest, { recursive: true, force: true });
|
|
1328
|
+
await clearPartial();
|
|
1329
|
+
try {
|
|
1330
|
+
await execFileAsync("git", ["clone", "--depth", "1", "--branch", ref, "--", url, dest], {
|
|
1331
|
+
env: gitEnv()
|
|
1332
|
+
});
|
|
1333
|
+
} catch (firstErr) {
|
|
1334
|
+
try {
|
|
1335
|
+
await clearPartial();
|
|
1336
|
+
await execFileAsync("git", ["clone", "--depth", "1", "--", url, dest], { env: gitEnv() });
|
|
1337
|
+
await execFileAsync("git", ["checkout", ref, "--"], { cwd: dest, env: gitEnv() });
|
|
1338
|
+
} catch (secondErr) {
|
|
1339
|
+
const msg = secondErr instanceof Error ? secondErr.message : String(secondErr);
|
|
1340
|
+
if (/403|Authentication|could not read Username/i.test(msg)) {
|
|
1341
|
+
throw new Error(
|
|
1342
|
+
`Registry clone failed (auth/access): ${url}@${ref}. Check git credentials or use --registry <local-path> for a local checkout.`
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
if (/Could not resolve host|Network is unreachable|Connection refused/i.test(msg)) {
|
|
1346
|
+
throw new Error(
|
|
1347
|
+
`Registry clone failed (network): ${url}@${ref}. Check network/proxy settings or use --registry <local-path>.`
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
throw new Error(
|
|
1351
|
+
`Registry clone failed: ${url}@${ref}. ${msg}. Use --registry <local-path> if you have a local checkout.`
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
async function refreshCache(cacheDir, ref) {
|
|
1357
|
+
try {
|
|
1358
|
+
await execFileAsync("git", ["fetch", "--depth", "1", "origin", ref], {
|
|
1359
|
+
cwd: cacheDir,
|
|
1360
|
+
env: gitEnv()
|
|
1361
|
+
});
|
|
1362
|
+
await execFileAsync("git", ["reset", "--hard", "FETCH_HEAD"], {
|
|
1363
|
+
cwd: cacheDir,
|
|
1364
|
+
env: gitEnv()
|
|
1365
|
+
});
|
|
1366
|
+
} catch {
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
async function resolveRegistryRoot(options) {
|
|
1370
|
+
if (options.registryPath) {
|
|
1371
|
+
const root = path7.resolve(options.registryPath);
|
|
1372
|
+
if (!await hasRegistryIndex(root)) {
|
|
1373
|
+
throw new Error(`No ${REGISTRY_INDEX_REL} under --registry ${root}`);
|
|
1374
|
+
}
|
|
1375
|
+
return { root, source: "flag" };
|
|
1376
|
+
}
|
|
1377
|
+
const envPath = process.env.AGENT_KIT_REGISTRY;
|
|
1378
|
+
if (envPath) {
|
|
1379
|
+
const root = path7.resolve(envPath);
|
|
1380
|
+
if (!await hasRegistryIndex(root)) {
|
|
1381
|
+
throw new Error(`No ${REGISTRY_INDEX_REL} under AGENT_KIT_REGISTRY=${root}`);
|
|
1382
|
+
}
|
|
1383
|
+
return { root, source: "env", url: options.registryUrl, ref: options.registryRef };
|
|
1384
|
+
}
|
|
1385
|
+
if (await hasRegistryIndex(options.cwd)) {
|
|
1386
|
+
return {
|
|
1387
|
+
root: path7.resolve(options.cwd),
|
|
1388
|
+
source: "cwd",
|
|
1389
|
+
url: options.registryUrl,
|
|
1390
|
+
ref: options.registryRef
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
const url = options.registryUrl ?? DEFAULT_REGISTRY_URL;
|
|
1394
|
+
const ref = options.registryRef ?? DEFAULT_REGISTRY_REF;
|
|
1395
|
+
assertSafeRegistrySource(url, ref);
|
|
1396
|
+
const dest = path7.join(homedir(), ".cache", "agent-kit", "registry", cacheKey(url, ref));
|
|
1397
|
+
const unlock = await acquireCacheLock(dest);
|
|
1398
|
+
let ownershipTransferred = false;
|
|
1399
|
+
try {
|
|
1400
|
+
if (await hasRegistryIndex(dest)) {
|
|
1401
|
+
await refreshCache(dest, ref);
|
|
1402
|
+
} else {
|
|
1403
|
+
await cloneRegistry(url, ref, dest);
|
|
1404
|
+
if (!await hasRegistryIndex(dest)) {
|
|
1405
|
+
throw new Error(`Cloned ${url}@${ref} but ${REGISTRY_INDEX_REL} is missing`);
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
ownershipTransferred = true;
|
|
1409
|
+
return { root: dest, source: "remote-cache", url, ref, unlock };
|
|
1410
|
+
} finally {
|
|
1411
|
+
if (!ownershipTransferred) {
|
|
1412
|
+
await unlock();
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
export {
|
|
1418
|
+
MANIFEST_RELATIVE_PATH,
|
|
1419
|
+
DOMAIN_PACK_IDS,
|
|
1420
|
+
loadAgentKitManifest,
|
|
1421
|
+
DEFAULT_REGISTRY_URL,
|
|
1422
|
+
DEFAULT_REGISTRY_REF,
|
|
1423
|
+
assertSafeRegistrySource,
|
|
1424
|
+
resolveRegistryRoot,
|
|
1425
|
+
resolveContained,
|
|
1426
|
+
assertRealContained,
|
|
1427
|
+
assertRealParentContained,
|
|
1428
|
+
isRealWriteTargetContained,
|
|
1429
|
+
normalizeRelPath,
|
|
1430
|
+
resolveProtectedGlobs,
|
|
1431
|
+
isProtectedPath,
|
|
1432
|
+
loadRegistry,
|
|
1433
|
+
allSkills,
|
|
1434
|
+
allPacks,
|
|
1435
|
+
findSkill,
|
|
1436
|
+
findPack,
|
|
1437
|
+
contentHash,
|
|
1438
|
+
loadManagedHashLedger,
|
|
1439
|
+
saveManagedHashLedger,
|
|
1440
|
+
shouldPreserveCustomizedOverlay,
|
|
1441
|
+
seedManagedHashLedger,
|
|
1442
|
+
emptyStats,
|
|
1443
|
+
mergeStats,
|
|
1444
|
+
copyRegistryFile,
|
|
1445
|
+
recordOutcome,
|
|
1446
|
+
saveManifest,
|
|
1447
|
+
buildManifest,
|
|
1448
|
+
upsertIdList,
|
|
1449
|
+
skillTargetDir,
|
|
1450
|
+
skillFileTargets,
|
|
1451
|
+
installSkill,
|
|
1452
|
+
installSkillsByIds,
|
|
1453
|
+
loadPackManifest,
|
|
1454
|
+
installPack,
|
|
1455
|
+
packMemberFileTargets
|
|
1456
|
+
};
|