@modootoday/pmcp 0.9.2 → 0.10.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 +167 -2
- package/dist/attachment-tU5FZrgZ.d.ts +17 -0
- package/dist/chunk-HNAVQG6R.js +1198 -0
- package/dist/chunk-JRSR4JBR.js +88 -0
- package/dist/chunk-MSTKY33C.js +147 -0
- package/dist/{chunk-A5NOHVHN.js → chunk-VRZFM2M5.js} +18 -49
- package/dist/chunk-XEH4ZGGJ.js +336 -0
- package/dist/chunk-XOH2CW6P.js +297 -0
- package/dist/{chunk-D3OZVMHN.js → chunk-ZUFFVIHQ.js} +166 -117
- package/dist/cli.js +507 -74
- package/dist/config-CJ43_oBS.d.ts +49 -0
- package/dist/embed-BBhv3y5x.d.ts +53 -0
- package/dist/encoder-DGRy9skC.d.ts +36 -0
- package/dist/http.d.ts +7 -38
- package/dist/http.js +18 -7
- package/dist/index.d.ts +25 -44
- package/dist/index.js +31 -11
- package/dist/mailbox/index.d.ts +44 -0
- package/dist/mailbox/index.js +387 -0
- package/dist/{server-C9eO6LMI.d.ts → server-CwWcRjqz.d.ts} +122 -2
- package/dist/service-qpCsOXkQ.d.ts +116 -0
- package/dist/stdio.d.ts +10 -4
- package/dist/stdio.js +9 -4
- package/package.json +5 -1
- package/dist/catalog-BU5VLLyd.d.ts +0 -121
- package/dist/chunk-CMZ7OTQD.js +0 -134
- package/dist/chunk-EIHMCKY5.js +0 -41
- package/dist/chunk-KYW3VP3L.js +0 -160
|
@@ -1,68 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadEmbedder,
|
|
3
|
+
openEntryVectors
|
|
4
|
+
} from "./chunk-XEH4ZGGJ.js";
|
|
1
5
|
import {
|
|
2
6
|
frontmatterObject,
|
|
3
7
|
readCatalog,
|
|
4
8
|
specProblems
|
|
5
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VRZFM2M5.js";
|
|
10
|
+
import {
|
|
11
|
+
ConfigError
|
|
12
|
+
} from "./chunk-MSTKY33C.js";
|
|
13
|
+
import {
|
|
14
|
+
DEFAULT_MODEL_ID,
|
|
15
|
+
resolveEncoder
|
|
16
|
+
} from "./chunk-XOH2CW6P.js";
|
|
6
17
|
|
|
7
|
-
// src/
|
|
8
|
-
import { existsSync
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
-
var PATH_KEYS = ["roots", "workspaces", "packages", "marketplaces"];
|
|
19
|
-
var CATALOG_KEYS = /* @__PURE__ */ new Set([...PATH_KEYS, "scopes"]);
|
|
20
|
-
function findConfig(start) {
|
|
21
|
-
let dir = resolve(start);
|
|
22
|
-
for (; ; ) {
|
|
23
|
-
const candidate = join(dir, CONFIG_FILE);
|
|
24
|
-
if (existsSync(candidate)) return candidate;
|
|
25
|
-
const parent = dirname(dir);
|
|
26
|
-
if (parent === dir) return null;
|
|
27
|
-
dir = parent;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function stringList(path, key, value) {
|
|
31
|
-
if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
|
|
32
|
-
throw new ConfigError(path, `[catalog] ${key} must be a list of strings`);
|
|
33
|
-
}
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
function readConfig(path) {
|
|
37
|
-
const absolute = resolve(path);
|
|
38
|
-
const dir = dirname(absolute);
|
|
39
|
-
let raw;
|
|
18
|
+
// src/search.ts
|
|
19
|
+
import { existsSync } from "fs";
|
|
20
|
+
async function prepareSearch(catalog, options) {
|
|
21
|
+
const lexical = (reason) => ({
|
|
22
|
+
ranking: "lexical",
|
|
23
|
+
reason,
|
|
24
|
+
options: {}
|
|
25
|
+
});
|
|
26
|
+
if (!existsSync(options.indexPath)) return lexical("index_missing");
|
|
27
|
+
let store;
|
|
40
28
|
try {
|
|
41
|
-
|
|
42
|
-
} catch
|
|
43
|
-
|
|
44
|
-
throw new ConfigError(absolute, reason.split("\n")[0] ?? reason);
|
|
45
|
-
}
|
|
46
|
-
const section = raw["catalog"];
|
|
47
|
-
if (section === void 0) return { path: absolute, dir, catalog: {}, raw };
|
|
48
|
-
if (section === null || typeof section !== "object" || Array.isArray(section)) {
|
|
49
|
-
throw new ConfigError(absolute, "[catalog] must be a table");
|
|
29
|
+
store = await openEntryVectors(options.indexPath, { readOnly: true });
|
|
30
|
+
} catch {
|
|
31
|
+
return lexical("index_unavailable");
|
|
50
32
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
33
|
+
if (!store) return lexical("index_unavailable");
|
|
34
|
+
try {
|
|
35
|
+
const entries = (options.loadCatalog ?? readCatalog)(catalog);
|
|
36
|
+
const selected = resolveEncoder(
|
|
37
|
+
options.modelId ?? options.embedder?.modelId ?? DEFAULT_MODEL_ID,
|
|
38
|
+
options
|
|
39
|
+
);
|
|
40
|
+
const modelId = selected.modelId;
|
|
41
|
+
const key = selected.indexKey;
|
|
42
|
+
if (options.embedder?.indexKey !== void 0 && options.embedder.indexKey !== key)
|
|
43
|
+
return lexical("vector_mismatch");
|
|
44
|
+
const descriptions = new Map(
|
|
45
|
+
entries.map((entry2) => [entry2.name, entry2.description])
|
|
46
|
+
);
|
|
47
|
+
if (entries.length === 0 || store.stale(key, descriptions).length > 0)
|
|
48
|
+
return lexical("index_stale");
|
|
49
|
+
const vectors = store.read(key);
|
|
50
|
+
const embedder = options.embedder ?? await loadEmbedder(selected.modelId, {
|
|
51
|
+
...options,
|
|
52
|
+
localOnly: options.localOnly ?? true
|
|
53
|
+
});
|
|
54
|
+
if (!embedder || embedder.modelId !== modelId)
|
|
55
|
+
return lexical("encoder_unavailable");
|
|
56
|
+
if (embedder.indexKey !== void 0 && embedder.indexKey !== key)
|
|
57
|
+
return lexical("vector_mismatch");
|
|
58
|
+
const probe = await embedder.embed("pmcp");
|
|
59
|
+
if (probe.length === 0 || !entries.every(
|
|
60
|
+
(entry2) => vectors.get(entry2.name)?.length === probe.length
|
|
61
|
+
))
|
|
62
|
+
return lexical("vector_mismatch");
|
|
63
|
+
return {
|
|
64
|
+
ranking: "semantic",
|
|
65
|
+
options: { embedder, vectors, loadCatalog: () => entries }
|
|
66
|
+
};
|
|
67
|
+
} catch {
|
|
68
|
+
return lexical("encoder_unavailable");
|
|
69
|
+
} finally {
|
|
70
|
+
store.close();
|
|
58
71
|
}
|
|
59
|
-
return { path: absolute, dir, catalog, raw };
|
|
60
72
|
}
|
|
61
73
|
|
|
62
74
|
// src/project/package-rules.ts
|
|
63
75
|
import { execFileSync } from "child_process";
|
|
64
76
|
import { existsSync as existsSync2, lstatSync, readdirSync, readlinkSync } from "fs";
|
|
65
|
-
import { dirname
|
|
77
|
+
import { dirname, join, posix } from "path";
|
|
66
78
|
var ProjectError = class extends Error {
|
|
67
79
|
constructor(message) {
|
|
68
80
|
super(message);
|
|
@@ -107,11 +119,11 @@ function linkTarget(abs) {
|
|
|
107
119
|
}
|
|
108
120
|
function legacyLinks(root) {
|
|
109
121
|
const found = /* @__PURE__ */ new Map();
|
|
110
|
-
const dir =
|
|
122
|
+
const dir = join(root, RULES_DIR);
|
|
111
123
|
if (!existsSync2(dir)) return found;
|
|
112
124
|
for (const entry2 of readdirSync(dir).sort()) {
|
|
113
125
|
if (!entry2.endsWith(".md")) continue;
|
|
114
|
-
const target = linkTarget(
|
|
126
|
+
const target = linkTarget(join(dir, entry2));
|
|
115
127
|
if (target === null || !target.startsWith("../../")) continue;
|
|
116
128
|
found.set(entry2.slice(0, -3), target.slice("../../".length));
|
|
117
129
|
}
|
|
@@ -131,14 +143,14 @@ function packageRuleOutputs(root, spec, owned) {
|
|
|
131
143
|
const legacyByDir = /* @__PURE__ */ new Map();
|
|
132
144
|
for (const [name, target] of legacy) {
|
|
133
145
|
if (!byTarget.has(target)) byTarget.set(target, name);
|
|
134
|
-
const dir =
|
|
146
|
+
const dir = dirname(target);
|
|
135
147
|
if (!legacyByDir.has(dir)) legacyByDir.set(dir, name);
|
|
136
148
|
}
|
|
137
149
|
const outputs = [];
|
|
138
150
|
const taken = /* @__PURE__ */ new Map();
|
|
139
151
|
for (const file of files) {
|
|
140
152
|
const pkg = file.slice(0, -suffix.length);
|
|
141
|
-
const name = byTarget.get(file) ?? legacyByDir.get(
|
|
153
|
+
const name = byTarget.get(file) ?? legacyByDir.get(dirname(file)) ?? deriveName(pkg, spec.strip);
|
|
142
154
|
const other = taken.get(name);
|
|
143
155
|
if (other !== void 0) {
|
|
144
156
|
throw new ProjectError(
|
|
@@ -156,15 +168,15 @@ function packageRuleOutputs(root, spec, owned) {
|
|
|
156
168
|
}
|
|
157
169
|
|
|
158
170
|
// src/project/plan.ts
|
|
159
|
-
import { existsSync as existsSync3, readFileSync
|
|
160
|
-
import { join as
|
|
171
|
+
import { existsSync as existsSync3, readFileSync, readdirSync as readdirSync2 } from "fs";
|
|
172
|
+
import { join as join2 } from "path";
|
|
161
173
|
|
|
162
174
|
// src/project/frontmatter.ts
|
|
163
|
-
import { parse
|
|
175
|
+
import { parse } from "yaml";
|
|
164
176
|
function splitFrontmatter(source) {
|
|
165
177
|
const match = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/u.exec(source);
|
|
166
178
|
if (!match) return { meta: {}, body: source };
|
|
167
|
-
const meta =
|
|
179
|
+
const meta = parse(match[1] ?? "");
|
|
168
180
|
const object = meta !== null && typeof meta === "object" && !Array.isArray(meta) ? meta : {};
|
|
169
181
|
return { meta: object, body: match[2] ?? "" };
|
|
170
182
|
}
|
|
@@ -208,6 +220,20 @@ function splitKeyed(path) {
|
|
|
208
220
|
}
|
|
209
221
|
|
|
210
222
|
// src/project/mcp.ts
|
|
223
|
+
var runtimeByTool = {
|
|
224
|
+
claude: "claude-code",
|
|
225
|
+
codex: "codex-cli",
|
|
226
|
+
gemini: "gemini-cli",
|
|
227
|
+
grok: "grok-cli",
|
|
228
|
+
antigravity: "antigravity"
|
|
229
|
+
};
|
|
230
|
+
function launchForTool(server, tool) {
|
|
231
|
+
if (!server.mailbox) return launch(server);
|
|
232
|
+
return launch({
|
|
233
|
+
...server,
|
|
234
|
+
env: { ...server.env, PMCP_MAILBOX_RUNTIME: runtimeByTool[tool] }
|
|
235
|
+
});
|
|
236
|
+
}
|
|
211
237
|
var ROOT_VAR = "${PROJECT_ROOT}";
|
|
212
238
|
var quote = (text) => `'${text.replaceAll("'", "'\\''")}'`;
|
|
213
239
|
function shellWord(text) {
|
|
@@ -259,16 +285,18 @@ function tomlServers(servers) {
|
|
|
259
285
|
`;
|
|
260
286
|
}
|
|
261
287
|
function mcpOutputs(spec) {
|
|
262
|
-
const servers = Object.entries(spec.mcp)
|
|
263
|
-
([alias, server]) => [alias, launch(server)]
|
|
264
|
-
);
|
|
288
|
+
const servers = Object.entries(spec.mcp);
|
|
265
289
|
if (servers.length === 0) return [];
|
|
266
290
|
const outputs = [];
|
|
267
291
|
for (const [alias, server] of servers) {
|
|
268
292
|
const tools = spec.mcp[alias]?.tools;
|
|
269
293
|
if (spec.tools.has("claude")) {
|
|
270
294
|
outputs.push(
|
|
271
|
-
jsonOutput(
|
|
295
|
+
jsonOutput(
|
|
296
|
+
".mcp.json",
|
|
297
|
+
["mcpServers", alias],
|
|
298
|
+
entry(launchForTool(server, "claude"))
|
|
299
|
+
)
|
|
272
300
|
);
|
|
273
301
|
}
|
|
274
302
|
if (spec.tools.has("gemini")) {
|
|
@@ -277,7 +305,7 @@ function mcpOutputs(spec) {
|
|
|
277
305
|
jsonOutput(
|
|
278
306
|
".gemini/settings.json",
|
|
279
307
|
["mcpServers", alias],
|
|
280
|
-
entry(server, extra)
|
|
308
|
+
entry(launchForTool(server, "gemini"), extra)
|
|
281
309
|
)
|
|
282
310
|
);
|
|
283
311
|
}
|
|
@@ -286,16 +314,36 @@ function mcpOutputs(spec) {
|
|
|
286
314
|
jsonOutput(
|
|
287
315
|
".agents/mcp_config.json",
|
|
288
316
|
["mcpServers", alias],
|
|
289
|
-
entry(server)
|
|
317
|
+
entry(launchForTool(server, "antigravity"))
|
|
290
318
|
)
|
|
291
319
|
);
|
|
292
320
|
}
|
|
293
321
|
}
|
|
294
322
|
if (spec.tools.has("codex")) {
|
|
295
|
-
outputs.push(
|
|
323
|
+
outputs.push(
|
|
324
|
+
blockOutput(
|
|
325
|
+
".codex/config.toml",
|
|
326
|
+
tomlServers(
|
|
327
|
+
servers.map(([alias, server]) => [
|
|
328
|
+
alias,
|
|
329
|
+
launchForTool(server, "codex")
|
|
330
|
+
])
|
|
331
|
+
)
|
|
332
|
+
)
|
|
333
|
+
);
|
|
296
334
|
}
|
|
297
335
|
if (spec.tools.has("grok")) {
|
|
298
|
-
outputs.push(
|
|
336
|
+
outputs.push(
|
|
337
|
+
blockOutput(
|
|
338
|
+
".grok/config.toml",
|
|
339
|
+
tomlServers(
|
|
340
|
+
servers.map(([alias, server]) => [
|
|
341
|
+
alias,
|
|
342
|
+
launchForTool(server, "grok")
|
|
343
|
+
])
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
);
|
|
299
347
|
}
|
|
300
348
|
return outputs;
|
|
301
349
|
}
|
|
@@ -312,15 +360,15 @@ function listDirs(dir) {
|
|
|
312
360
|
}
|
|
313
361
|
var tomlString = (value) => JSON.stringify(typeof value === "string" ? value : String(value ?? ""));
|
|
314
362
|
function skillNames(root) {
|
|
315
|
-
const dir =
|
|
363
|
+
const dir = join2(root, ".agents/skills");
|
|
316
364
|
return listDirs(dir).filter(
|
|
317
|
-
(name) => existsSync3(
|
|
365
|
+
(name) => existsSync3(join2(dir, name, "SKILL.md"))
|
|
318
366
|
);
|
|
319
367
|
}
|
|
320
368
|
function agentNames(root) {
|
|
321
|
-
const dir =
|
|
369
|
+
const dir = join2(root, ".agents/agents");
|
|
322
370
|
return listDirs(dir).filter(
|
|
323
|
-
(name) => existsSync3(
|
|
371
|
+
(name) => existsSync3(join2(dir, name, "agent.md"))
|
|
324
372
|
);
|
|
325
373
|
}
|
|
326
374
|
function skillOutputs(spec) {
|
|
@@ -354,13 +402,13 @@ policy:
|
|
|
354
402
|
}
|
|
355
403
|
function ruleOutputs(spec) {
|
|
356
404
|
if (!spec.tools.has("claude")) return [];
|
|
357
|
-
const dir =
|
|
405
|
+
const dir = join2(spec.root, ".agents/rules");
|
|
358
406
|
if (!existsSync3(dir)) return [];
|
|
359
407
|
const outputs = [];
|
|
360
408
|
for (const file of readdirSync2(dir).filter((f) => f.endsWith(".md")).sort()) {
|
|
361
409
|
const rel = `.agents/rules/${file}`;
|
|
362
410
|
const { meta, body } = splitFrontmatter(
|
|
363
|
-
|
|
411
|
+
readFileSync(join2(spec.root, rel), "utf8")
|
|
364
412
|
);
|
|
365
413
|
const globs = [meta["globs"] ?? []].flat().filter((g) => typeof g === "string" && g !== "");
|
|
366
414
|
const head = globs.length > 0 ? renderFrontmatter({ paths: globs }) : "";
|
|
@@ -379,7 +427,7 @@ function agentOutputs(spec) {
|
|
|
379
427
|
for (const name of agentNames(spec.root)) {
|
|
380
428
|
const rel = `.agents/agents/${name}/agent.md`;
|
|
381
429
|
const { meta, body } = splitFrontmatter(
|
|
382
|
-
|
|
430
|
+
readFileSync(join2(spec.root, rel), "utf8")
|
|
383
431
|
);
|
|
384
432
|
const overrides = spec.agents[name] ?? {};
|
|
385
433
|
const note = `<!-- ${MARK} from ${rel} -->
|
|
@@ -453,14 +501,14 @@ import {
|
|
|
453
501
|
existsSync as existsSync4,
|
|
454
502
|
lstatSync as lstatSync2,
|
|
455
503
|
mkdirSync,
|
|
456
|
-
readFileSync as
|
|
504
|
+
readFileSync as readFileSync2,
|
|
457
505
|
readdirSync as readdirSync3,
|
|
458
506
|
readlinkSync as readlinkSync2,
|
|
459
507
|
rmSync,
|
|
460
508
|
symlinkSync,
|
|
461
509
|
writeFileSync
|
|
462
510
|
} from "fs";
|
|
463
|
-
import { dirname as
|
|
511
|
+
import { dirname as dirname2, join as join3, posix as posix2 } from "path";
|
|
464
512
|
var LOCK_FILE = "pmcp.lock";
|
|
465
513
|
var BEGIN = "# >>> pmcp project (edit pmcp.toml, not this block) >>>";
|
|
466
514
|
var END = "# <<< pmcp project <<<";
|
|
@@ -470,9 +518,9 @@ var PREDECESSORS = [
|
|
|
470
518
|
];
|
|
471
519
|
var sha = (text) => createHash("sha256").update(text).digest("hex");
|
|
472
520
|
function readLock(root) {
|
|
473
|
-
const path =
|
|
521
|
+
const path = join3(root, LOCK_FILE);
|
|
474
522
|
if (!existsSync4(path)) return [];
|
|
475
|
-
const lock = JSON.parse(
|
|
523
|
+
const lock = JSON.parse(readFileSync2(path, "utf8"));
|
|
476
524
|
return lock.outputs ?? [];
|
|
477
525
|
}
|
|
478
526
|
function linkOf(abs) {
|
|
@@ -485,7 +533,7 @@ function linkOf(abs) {
|
|
|
485
533
|
var exists = (abs) => existsSync4(abs) || linkOf(abs) !== null;
|
|
486
534
|
function readJson(abs) {
|
|
487
535
|
if (!existsSync4(abs)) return {};
|
|
488
|
-
const value = JSON.parse(
|
|
536
|
+
const value = JSON.parse(readFileSync2(abs, "utf8"));
|
|
489
537
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
490
538
|
}
|
|
491
539
|
function getKey(object, key) {
|
|
@@ -532,29 +580,29 @@ function withoutBlock(text) {
|
|
|
532
580
|
return `${text.slice(0, start).replace(/\n+$/u, "\n")}${after}`;
|
|
533
581
|
}
|
|
534
582
|
function present(root, output) {
|
|
535
|
-
const abs =
|
|
583
|
+
const abs = join3(root, "file" in output ? output.file : output.path);
|
|
536
584
|
switch (output.kind) {
|
|
537
585
|
case "link":
|
|
538
586
|
return linkOf(abs) === output.target;
|
|
539
587
|
case "file":
|
|
540
|
-
return existsSync4(abs) && linkOf(abs) === null &&
|
|
588
|
+
return existsSync4(abs) && linkOf(abs) === null && readFileSync2(abs, "utf8") === output.content;
|
|
541
589
|
case "json":
|
|
542
590
|
return same(getKey(readJson(abs), output.key), output.value);
|
|
543
591
|
case "block":
|
|
544
|
-
return existsSync4(abs) &&
|
|
592
|
+
return existsSync4(abs) && readFileSync2(abs, "utf8").includes(block(output.content));
|
|
545
593
|
}
|
|
546
594
|
}
|
|
547
595
|
function replaceable(root, output, owned) {
|
|
548
596
|
if (output.kind === "json" || output.kind === "block") return true;
|
|
549
597
|
if (owned.has(output.path)) return true;
|
|
550
|
-
const abs =
|
|
598
|
+
const abs = join3(root, output.path);
|
|
551
599
|
if (!exists(abs)) return true;
|
|
552
600
|
const target = linkOf(abs);
|
|
553
601
|
if (target !== null) {
|
|
554
602
|
return output.kind === "link" && target === output.target;
|
|
555
603
|
}
|
|
556
604
|
if (lstatSync2(abs).isDirectory()) return false;
|
|
557
|
-
const text =
|
|
605
|
+
const text = readFileSync2(abs, "utf8");
|
|
558
606
|
if (output.kind === "file" && text === output.content) return true;
|
|
559
607
|
return PREDECESSORS.some((mark) => text.includes(mark));
|
|
560
608
|
}
|
|
@@ -562,14 +610,14 @@ function undeclared(spec, outputs) {
|
|
|
562
610
|
const declared = new Set(outputs.map((o) => o.path));
|
|
563
611
|
const found = [];
|
|
564
612
|
for (const dir of censusDirs(spec)) {
|
|
565
|
-
const abs =
|
|
613
|
+
const abs = join3(spec.root, dir);
|
|
566
614
|
if (!existsSync4(abs)) continue;
|
|
567
615
|
for (const entry2 of readdirSync3(abs)) {
|
|
568
616
|
const path = `${dir}/${entry2}`;
|
|
569
617
|
if (!declared.has(path)) found.push(path);
|
|
570
618
|
}
|
|
571
619
|
}
|
|
572
|
-
const rules =
|
|
620
|
+
const rules = join3(spec.root, RULES_DIR);
|
|
573
621
|
if (spec.tools.has("grok") && existsSync4(rules)) {
|
|
574
622
|
for (const entry2 of readdirSync3(rules, { withFileTypes: true })) {
|
|
575
623
|
if (entry2.isDirectory()) continue;
|
|
@@ -597,9 +645,9 @@ function deadGlobs(root, outputs) {
|
|
|
597
645
|
if (rule.kind === "file") {
|
|
598
646
|
text = rule.content;
|
|
599
647
|
} else if (rule.kind === "link") {
|
|
600
|
-
const abs =
|
|
648
|
+
const abs = join3(root, posix2.join(posix2.dirname(rule.path), rule.target));
|
|
601
649
|
if (!existsSync4(abs)) continue;
|
|
602
|
-
text =
|
|
650
|
+
text = readFileSync2(abs, "utf8");
|
|
603
651
|
} else {
|
|
604
652
|
continue;
|
|
605
653
|
}
|
|
@@ -659,8 +707,8 @@ function project(spec, options) {
|
|
|
659
707
|
for (const output of outputs) {
|
|
660
708
|
if (output.kind !== "link" && output.kind !== "file") continue;
|
|
661
709
|
if (present(spec.root, output)) continue;
|
|
662
|
-
const abs =
|
|
663
|
-
mkdirSync(
|
|
710
|
+
const abs = join3(spec.root, output.path);
|
|
711
|
+
mkdirSync(dirname2(abs), { recursive: true });
|
|
664
712
|
rmSync(abs, { force: true, recursive: true });
|
|
665
713
|
if (output.kind === "link") symlinkSync(output.target, abs);
|
|
666
714
|
else writeFileSync(abs, output.content);
|
|
@@ -685,12 +733,12 @@ function project(spec, options) {
|
|
|
685
733
|
group.drops.push(keyed.key);
|
|
686
734
|
jsonFiles.set(keyed.file, group);
|
|
687
735
|
} else {
|
|
688
|
-
rmSync(
|
|
736
|
+
rmSync(join3(spec.root, entry2.path), { force: true, recursive: true });
|
|
689
737
|
}
|
|
690
738
|
pruned += 1;
|
|
691
739
|
}
|
|
692
740
|
for (const [file, { sets, drops }] of jsonFiles) {
|
|
693
|
-
const abs =
|
|
741
|
+
const abs = join3(spec.root, file);
|
|
694
742
|
const before = readJson(abs);
|
|
695
743
|
const after = structuredClone(before);
|
|
696
744
|
for (const key of drops) deleteKey(after, key);
|
|
@@ -699,20 +747,20 @@ function project(spec, options) {
|
|
|
699
747
|
}
|
|
700
748
|
if (same(before, after)) continue;
|
|
701
749
|
if (!existsSync4(abs) && Object.keys(after).length === 0) continue;
|
|
702
|
-
mkdirSync(
|
|
750
|
+
mkdirSync(dirname2(abs), { recursive: true });
|
|
703
751
|
writeFileSync(abs, `${JSON.stringify(after, null, 2)}
|
|
704
752
|
`);
|
|
705
753
|
}
|
|
706
754
|
for (const [file, content] of blockFiles) {
|
|
707
|
-
const abs =
|
|
708
|
-
const before = existsSync4(abs) ?
|
|
755
|
+
const abs = join3(spec.root, file);
|
|
756
|
+
const before = existsSync4(abs) ? readFileSync2(abs, "utf8") : "";
|
|
709
757
|
let after = withoutBlock(before);
|
|
710
758
|
if (content !== null) {
|
|
711
759
|
const sep = after === "" || after.endsWith("\n\n") ? "" : after.endsWith("\n") ? "\n" : "\n\n";
|
|
712
760
|
after = `${after}${sep}${block(content)}`;
|
|
713
761
|
}
|
|
714
762
|
if (after === before) continue;
|
|
715
|
-
mkdirSync(
|
|
763
|
+
mkdirSync(dirname2(abs), { recursive: true });
|
|
716
764
|
writeFileSync(abs, after);
|
|
717
765
|
}
|
|
718
766
|
if (spec.packageRules) {
|
|
@@ -724,7 +772,7 @@ function project(spec, options) {
|
|
|
724
772
|
)
|
|
725
773
|
);
|
|
726
774
|
for (const [name, target] of legacyLinks(spec.root)) {
|
|
727
|
-
const abs =
|
|
775
|
+
const abs = join3(spec.root, RULES_DIR, `${name}.md`);
|
|
728
776
|
const broken = !existsSync4(abs);
|
|
729
777
|
if (!broken && !linkedDirs.has(posix2.dirname(target))) continue;
|
|
730
778
|
rmSync(abs, { force: true });
|
|
@@ -732,7 +780,7 @@ function project(spec, options) {
|
|
|
732
780
|
}
|
|
733
781
|
}
|
|
734
782
|
writeFileSync(
|
|
735
|
-
|
|
783
|
+
join3(spec.root, LOCK_FILE),
|
|
736
784
|
`${JSON.stringify({ version: 1, outputs: outputs.map(lockEntry) }, null, 2)}
|
|
737
785
|
`
|
|
738
786
|
);
|
|
@@ -741,9 +789,9 @@ function project(spec, options) {
|
|
|
741
789
|
|
|
742
790
|
// src/project/doctor.ts
|
|
743
791
|
import { spawnSync } from "child_process";
|
|
744
|
-
import { existsSync as existsSync5, readFileSync as
|
|
745
|
-
import { join as
|
|
746
|
-
import { parse as
|
|
792
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
793
|
+
import { join as join4 } from "path";
|
|
794
|
+
import { parse as parse2 } from "smol-toml";
|
|
747
795
|
var spawnRunner = (command, args, cwd) => {
|
|
748
796
|
const result = spawnSync(command, [...args], {
|
|
749
797
|
cwd,
|
|
@@ -804,10 +852,10 @@ function claude(spec, o) {
|
|
|
804
852
|
}
|
|
805
853
|
function codex(spec, o) {
|
|
806
854
|
const findings = [];
|
|
807
|
-
const config =
|
|
855
|
+
const config = join4(o.home, ".codex/config.toml");
|
|
808
856
|
let trusted = false;
|
|
809
857
|
if (existsSync5(config)) {
|
|
810
|
-
const projects =
|
|
858
|
+
const projects = parse2(readFileSync3(config, "utf8")).projects ?? {};
|
|
811
859
|
const root = spec.root.replace(/\/$/u, "");
|
|
812
860
|
trusted = projects[root]?.trust_level === "trusted" || projects[`${root}/`]?.trust_level === "trusted";
|
|
813
861
|
}
|
|
@@ -934,8 +982,8 @@ function grok(spec, o) {
|
|
|
934
982
|
}
|
|
935
983
|
function antigravity(spec) {
|
|
936
984
|
const foreign = agentNames(spec.root).filter((name) => {
|
|
937
|
-
const text =
|
|
938
|
-
|
|
985
|
+
const text = readFileSync3(
|
|
986
|
+
join4(spec.root, ".agents/agents", name, "agent.md"),
|
|
939
987
|
"utf8"
|
|
940
988
|
);
|
|
941
989
|
return splitFrontmatter(text).meta["tools"] !== void 0;
|
|
@@ -1074,6 +1122,9 @@ function readSpec(config) {
|
|
|
1074
1122
|
throw new ConfigError(path, `${where} command is required`);
|
|
1075
1123
|
}
|
|
1076
1124
|
const env = {};
|
|
1125
|
+
if (entry2["mailbox"] !== void 0 && typeof entry2["mailbox"] !== "boolean") {
|
|
1126
|
+
throw new ConfigError(path, `${where} mailbox must be a boolean`);
|
|
1127
|
+
}
|
|
1077
1128
|
for (const [key, v] of Object.entries(
|
|
1078
1129
|
table(path, `${where} env`, entry2["env"])
|
|
1079
1130
|
)) {
|
|
@@ -1083,6 +1134,7 @@ function readSpec(config) {
|
|
|
1083
1134
|
env[key] = v;
|
|
1084
1135
|
}
|
|
1085
1136
|
mcp[named(path, "[mcp]", alias)] = {
|
|
1137
|
+
...entry2["mailbox"] === true ? { mailbox: true } : {},
|
|
1086
1138
|
command,
|
|
1087
1139
|
args: entry2["args"] === void 0 ? [] : strings(path, `${where} args`, entry2["args"]),
|
|
1088
1140
|
env,
|
|
@@ -1093,16 +1145,16 @@ function readSpec(config) {
|
|
|
1093
1145
|
}
|
|
1094
1146
|
|
|
1095
1147
|
// src/validate.ts
|
|
1096
|
-
import { existsSync as existsSync6, readFileSync as
|
|
1097
|
-
import { basename, join as
|
|
1148
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, statSync } from "fs";
|
|
1149
|
+
import { basename, join as join5, resolve } from "path";
|
|
1098
1150
|
function validateSkillDir(dir) {
|
|
1099
|
-
const root =
|
|
1100
|
-
const skillMd = basename(root) === "SKILL.md" ? root :
|
|
1151
|
+
const root = resolve(dir);
|
|
1152
|
+
const skillMd = basename(root) === "SKILL.md" ? root : join5(root, "SKILL.md");
|
|
1101
1153
|
if (!existsSync6(skillMd) || !statSync(skillMd).isFile()) {
|
|
1102
1154
|
return [{ path: root, reason: "no SKILL.md", level: "error" }];
|
|
1103
1155
|
}
|
|
1104
|
-
const front = frontmatterObject(
|
|
1105
|
-
const directory = basename(skillMd === root ?
|
|
1156
|
+
const front = frontmatterObject(readFileSync4(skillMd, "utf8"));
|
|
1157
|
+
const directory = basename(skillMd === root ? join5(root, "..") : root);
|
|
1106
1158
|
return specProblems(front, directory).map((reason) => ({
|
|
1107
1159
|
path: skillMd,
|
|
1108
1160
|
reason,
|
|
@@ -1120,10 +1172,7 @@ function validateCatalog(options) {
|
|
|
1120
1172
|
}
|
|
1121
1173
|
|
|
1122
1174
|
export {
|
|
1123
|
-
|
|
1124
|
-
ConfigError,
|
|
1125
|
-
findConfig,
|
|
1126
|
-
readConfig,
|
|
1175
|
+
prepareSearch,
|
|
1127
1176
|
splitFrontmatter,
|
|
1128
1177
|
renderFrontmatter,
|
|
1129
1178
|
ProjectError,
|
|
@@ -1139,4 +1188,4 @@ export {
|
|
|
1139
1188
|
validateSkillDir,
|
|
1140
1189
|
validateCatalog
|
|
1141
1190
|
};
|
|
1142
|
-
//# sourceMappingURL=chunk-
|
|
1191
|
+
//# sourceMappingURL=chunk-ZUFFVIHQ.js.map
|