agentsmesh 0.3.0 → 0.5.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/CHANGELOG.md +61 -1
- package/README.md +80 -12
- package/dist/canonical-types-gdrUi3bD.d.ts +146 -0
- package/dist/canonical.d.ts +23 -0
- package/dist/canonical.js +497 -0
- package/dist/canonical.js.map +1 -0
- package/dist/cli.js +8227 -4858
- package/dist/cli.js.map +1 -1
- package/dist/engine.d.ts +56 -0
- package/dist/engine.js +11155 -0
- package/dist/engine.js.map +1 -0
- package/dist/target-descriptor-D64xD0C2.d.ts +343 -0
- package/dist/targets.d.ts +17 -0
- package/dist/targets.js +10070 -0
- package/dist/targets.js.map +1 -0
- package/package.json +38 -15
- package/schemas/agentsmesh.json +248 -0
- package/schemas/hooks.json +47 -0
- package/schemas/mcp.json +119 -0
- package/schemas/pack.json +131 -0
- package/schemas/permissions.json +38 -0
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
// src/canonical/load/loader.ts
|
|
2
|
+
import { join as join3 } from "path";
|
|
3
|
+
|
|
4
|
+
// src/canonical/features/rules.ts
|
|
5
|
+
import { basename } from "path";
|
|
6
|
+
|
|
7
|
+
// src/utils/filesystem/fs.ts
|
|
8
|
+
import {
|
|
9
|
+
readFile,
|
|
10
|
+
writeFile,
|
|
11
|
+
access,
|
|
12
|
+
mkdir,
|
|
13
|
+
rename,
|
|
14
|
+
readdir,
|
|
15
|
+
copyFile,
|
|
16
|
+
stat,
|
|
17
|
+
symlink,
|
|
18
|
+
unlink,
|
|
19
|
+
lstat,
|
|
20
|
+
readlink,
|
|
21
|
+
realpath
|
|
22
|
+
} from "fs/promises";
|
|
23
|
+
import { dirname, join, resolve } from "path";
|
|
24
|
+
import { constants } from "fs";
|
|
25
|
+
var UTF8_BOM = "\uFEFF";
|
|
26
|
+
async function readFileSafe(path) {
|
|
27
|
+
try {
|
|
28
|
+
const data = await readFile(path, "utf-8");
|
|
29
|
+
return data.startsWith(UTF8_BOM) ? data.slice(UTF8_BOM.length) : data;
|
|
30
|
+
} catch (err) {
|
|
31
|
+
const e = err;
|
|
32
|
+
if (e.code === "ENOENT") return null;
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Failed to read ${path}: ${e.message}. Ensure the file exists and is readable.`,
|
|
35
|
+
{ cause: err }
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function exists(path) {
|
|
40
|
+
try {
|
|
41
|
+
await access(path, constants.F_OK);
|
|
42
|
+
return true;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function readDirRecursive(dir, visited) {
|
|
48
|
+
let canonicalDir;
|
|
49
|
+
try {
|
|
50
|
+
canonicalDir = await realpath(dir);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const e = err;
|
|
53
|
+
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "ELOOP") return [];
|
|
54
|
+
throw new Error(`Failed to read directory ${dir}: ${e.message}. Check permissions.`, {
|
|
55
|
+
cause: err
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const seen = visited ?? /* @__PURE__ */ new Set();
|
|
59
|
+
if (seen.has(canonicalDir)) return [];
|
|
60
|
+
seen.add(canonicalDir);
|
|
61
|
+
try {
|
|
62
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
63
|
+
const files = [];
|
|
64
|
+
for (const ent of entries) {
|
|
65
|
+
const full = join(dir, ent.name);
|
|
66
|
+
const walkChild = ent.isDirectory() || ent.isSymbolicLink() && await stat(full).then(
|
|
67
|
+
(s) => s.isDirectory(),
|
|
68
|
+
() => false
|
|
69
|
+
);
|
|
70
|
+
if (walkChild) {
|
|
71
|
+
files.push(...await readDirRecursive(full, seen));
|
|
72
|
+
} else {
|
|
73
|
+
files.push(full);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return files;
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const e = err;
|
|
79
|
+
if (e.code === "ENOENT" || e.code === "ENOTDIR" || e.code === "EACCES") return [];
|
|
80
|
+
throw new Error(`Failed to read directory ${dir}: ${e.message}. Check permissions.`, {
|
|
81
|
+
cause: err
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/utils/text/markdown.ts
|
|
87
|
+
import { parse as yamlParse, stringify as yamlStringify } from "yaml";
|
|
88
|
+
function parseFrontmatter(content) {
|
|
89
|
+
const open = content.indexOf("---");
|
|
90
|
+
if (open !== 0) {
|
|
91
|
+
return { frontmatter: {}, body: content.trim() };
|
|
92
|
+
}
|
|
93
|
+
const close = content.indexOf("---", 3);
|
|
94
|
+
if (close === -1) {
|
|
95
|
+
return { frontmatter: {}, body: content.trim() };
|
|
96
|
+
}
|
|
97
|
+
const yamlStr = content.slice(3, close).trim();
|
|
98
|
+
const body = content.slice(close + 3).trim();
|
|
99
|
+
const frontmatter = yamlStr === "" ? {} : yamlParse(yamlStr) ?? {};
|
|
100
|
+
return { frontmatter, body };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/canonical/features/rules.ts
|
|
104
|
+
var VALID_TRIGGERS = ["always_on", "model_decision", "glob", "manual"];
|
|
105
|
+
function toStrArray(v) {
|
|
106
|
+
if (Array.isArray(v)) return v.filter((x) => typeof x === "string");
|
|
107
|
+
if (typeof v === "string") return v ? [v] : [];
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
async function parseRules(rulesDir) {
|
|
111
|
+
const files = await readDirRecursive(rulesDir);
|
|
112
|
+
const mdFiles = files.filter((f) => {
|
|
113
|
+
if (!f.endsWith(".md")) return false;
|
|
114
|
+
const name = basename(f, ".md");
|
|
115
|
+
return name === "_root" || !name.startsWith("_");
|
|
116
|
+
});
|
|
117
|
+
const rules = [];
|
|
118
|
+
for (const path of mdFiles) {
|
|
119
|
+
const content = await readFileSafe(path);
|
|
120
|
+
if (!content) continue;
|
|
121
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
122
|
+
const name = basename(path, ".md");
|
|
123
|
+
const rootFromFilename = name === "_root";
|
|
124
|
+
const rootFromFm = frontmatter.root === true;
|
|
125
|
+
const triggerRaw = frontmatter.trigger;
|
|
126
|
+
const trigger = typeof triggerRaw === "string" && VALID_TRIGGERS.includes(triggerRaw) ? triggerRaw : void 0;
|
|
127
|
+
const codexEmitRaw = frontmatter.codex_emit;
|
|
128
|
+
const codexEmit = codexEmitRaw === "execution" ? "execution" : codexEmitRaw === "advisory" ? "advisory" : void 0;
|
|
129
|
+
const instrRaw = frontmatter.codex_instruction;
|
|
130
|
+
const codexInstructionVariant = instrRaw === "override" ? "override" : void 0;
|
|
131
|
+
rules.push({
|
|
132
|
+
source: path,
|
|
133
|
+
root: rootFromFilename || rootFromFm,
|
|
134
|
+
targets: toStrArray(frontmatter.targets),
|
|
135
|
+
description: typeof frontmatter.description === "string" ? frontmatter.description : "",
|
|
136
|
+
globs: toStrArray(frontmatter.globs),
|
|
137
|
+
body,
|
|
138
|
+
...trigger !== void 0 && { trigger },
|
|
139
|
+
...codexEmit !== void 0 && { codexEmit },
|
|
140
|
+
...codexInstructionVariant !== void 0 && { codexInstructionVariant }
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return rules;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/canonical/features/commands.ts
|
|
147
|
+
import { basename as basename2 } from "path";
|
|
148
|
+
function toBool(v) {
|
|
149
|
+
return v === true || v === "true" || v === 1 || v === "1";
|
|
150
|
+
}
|
|
151
|
+
function toToolsArray(v) {
|
|
152
|
+
if (Array.isArray(v)) {
|
|
153
|
+
return v.filter((x) => typeof x === "string").map((s) => s.trim()).filter(Boolean);
|
|
154
|
+
}
|
|
155
|
+
if (typeof v === "string") {
|
|
156
|
+
return v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
157
|
+
}
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
async function parseCommands(commandsDir) {
|
|
161
|
+
const files = await readDirRecursive(commandsDir);
|
|
162
|
+
const mdFiles = files.filter((f) => f.endsWith(".md") && !basename2(f).startsWith("_"));
|
|
163
|
+
const commands = [];
|
|
164
|
+
for (const path of mdFiles) {
|
|
165
|
+
const content = await readFileSafe(path);
|
|
166
|
+
if (!content) continue;
|
|
167
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
168
|
+
const name = basename2(path, ".md");
|
|
169
|
+
const fromCamel = toToolsArray(frontmatter.allowedTools);
|
|
170
|
+
const fromKebab = toToolsArray(frontmatter["allowed-tools"]);
|
|
171
|
+
const allowedTools = fromCamel.length > 0 ? fromCamel : fromKebab;
|
|
172
|
+
commands.push({
|
|
173
|
+
source: path,
|
|
174
|
+
name,
|
|
175
|
+
description: typeof frontmatter.description === "string" ? frontmatter.description : "",
|
|
176
|
+
allowedTools,
|
|
177
|
+
outputStyle: toBool(frontmatter.outputStyle) || toBool(frontmatter["output-style"]),
|
|
178
|
+
body
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return commands;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/canonical/features/agents.ts
|
|
185
|
+
import { basename as basename3 } from "path";
|
|
186
|
+
function toStrArray2(v) {
|
|
187
|
+
if (Array.isArray(v)) {
|
|
188
|
+
return v.filter((x) => typeof x === "string").map((s) => s.trim()).filter(Boolean);
|
|
189
|
+
}
|
|
190
|
+
if (typeof v === "string") {
|
|
191
|
+
return v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
192
|
+
}
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
function toBool2(v) {
|
|
196
|
+
return v === true || v === "true" || v === 1 || v === "1";
|
|
197
|
+
}
|
|
198
|
+
function toInt(v) {
|
|
199
|
+
if (typeof v === "number" && Number.isInteger(v) && v >= 0) return v;
|
|
200
|
+
if (typeof v === "string") {
|
|
201
|
+
const n = parseInt(v, 10);
|
|
202
|
+
return Number.isInteger(n) && n >= 0 ? n : 0;
|
|
203
|
+
}
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
function toHooks(v) {
|
|
207
|
+
if (v !== null && typeof v === "object" && !Array.isArray(v)) {
|
|
208
|
+
return v;
|
|
209
|
+
}
|
|
210
|
+
return {};
|
|
211
|
+
}
|
|
212
|
+
async function parseAgents(agentsDir) {
|
|
213
|
+
const files = await readDirRecursive(agentsDir);
|
|
214
|
+
const mdFiles = files.filter((f) => f.endsWith(".md") && !basename3(f).startsWith("_"));
|
|
215
|
+
const agents = [];
|
|
216
|
+
for (const path of mdFiles) {
|
|
217
|
+
const content = await readFileSafe(path);
|
|
218
|
+
if (!content) continue;
|
|
219
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
220
|
+
const name = basename3(path, ".md");
|
|
221
|
+
const toolsCamel = toStrArray2(frontmatter.tools);
|
|
222
|
+
const toolsKebab = toStrArray2(frontmatter["tools"]);
|
|
223
|
+
const tools = toolsCamel.length > 0 ? toolsCamel : toolsKebab;
|
|
224
|
+
const disallowedCamel = toStrArray2(frontmatter.disallowedTools);
|
|
225
|
+
const disallowedKebab = toStrArray2(frontmatter["disallowed-tools"]);
|
|
226
|
+
const disallowedTools = disallowedCamel.length > 0 ? disallowedCamel : disallowedKebab;
|
|
227
|
+
const mcpCamel = toStrArray2(frontmatter.mcpServers);
|
|
228
|
+
const mcpKebab = toStrArray2(frontmatter["mcp-servers"]);
|
|
229
|
+
const mcpServers = mcpCamel.length > 0 ? mcpCamel : mcpKebab;
|
|
230
|
+
const skills = toStrArray2(frontmatter.skills);
|
|
231
|
+
const maxTurnsCamel = toInt(frontmatter.maxTurns);
|
|
232
|
+
const maxTurnsKebab = toInt(frontmatter["max-turns"]);
|
|
233
|
+
const maxTurns = maxTurnsCamel > 0 ? maxTurnsCamel : maxTurnsKebab > 0 ? maxTurnsKebab : 0;
|
|
234
|
+
agents.push({
|
|
235
|
+
source: path,
|
|
236
|
+
name,
|
|
237
|
+
description: typeof frontmatter.description === "string" ? frontmatter.description : "",
|
|
238
|
+
tools,
|
|
239
|
+
disallowedTools,
|
|
240
|
+
model: typeof frontmatter.model === "string" ? frontmatter.model : "",
|
|
241
|
+
permissionMode: typeof frontmatter.permissionMode === "string" ? frontmatter.permissionMode : typeof frontmatter["permission-mode"] === "string" ? frontmatter["permission-mode"] : "",
|
|
242
|
+
maxTurns,
|
|
243
|
+
mcpServers,
|
|
244
|
+
hooks: toHooks(frontmatter.hooks),
|
|
245
|
+
skills,
|
|
246
|
+
memory: typeof frontmatter.memory === "string" ? frontmatter.memory : "",
|
|
247
|
+
outputStyle: toBool2(frontmatter.outputStyle) || toBool2(frontmatter["output-style"]),
|
|
248
|
+
body
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
return agents;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// src/canonical/features/skills.ts
|
|
255
|
+
import { basename as basename4, join as join2 } from "path";
|
|
256
|
+
import { readdir as readdir2 } from "fs/promises";
|
|
257
|
+
async function readContent(path) {
|
|
258
|
+
const c = await readFileSafe(path);
|
|
259
|
+
return c ?? "";
|
|
260
|
+
}
|
|
261
|
+
var SKILL_FILE = "SKILL.md";
|
|
262
|
+
var EXCLUDED_DIR_PREFIXES = [".git", "node_modules"];
|
|
263
|
+
async function listSupportingFiles(skillDir) {
|
|
264
|
+
const files = await readDirRecursive(skillDir);
|
|
265
|
+
const result = [];
|
|
266
|
+
for (const absPath of files) {
|
|
267
|
+
const raw = absPath.slice(skillDir.length + 1);
|
|
268
|
+
const name = raw.replace(/\\/g, "/");
|
|
269
|
+
if (name === SKILL_FILE || name.endsWith(`/${SKILL_FILE}`)) continue;
|
|
270
|
+
const firstSegment = name.split("/")[0];
|
|
271
|
+
if (EXCLUDED_DIR_PREFIXES.some((p) => firstSegment === p)) continue;
|
|
272
|
+
if (name === ".DS_Store" || name.endsWith("/.DS_Store")) continue;
|
|
273
|
+
const content = await readContent(absPath);
|
|
274
|
+
result.push({ relativePath: name, absolutePath: absPath, content });
|
|
275
|
+
}
|
|
276
|
+
return result.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
277
|
+
}
|
|
278
|
+
async function parseSkills(skillsDir) {
|
|
279
|
+
let entries;
|
|
280
|
+
try {
|
|
281
|
+
entries = await readdir2(skillsDir, { withFileTypes: true });
|
|
282
|
+
} catch {
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
const skills = [];
|
|
286
|
+
for (const ent of entries) {
|
|
287
|
+
if (!ent.isDirectory()) continue;
|
|
288
|
+
if (ent.name.startsWith("_")) continue;
|
|
289
|
+
const skillDir = join2(skillsDir, ent.name);
|
|
290
|
+
const skillPath = join2(skillDir, SKILL_FILE);
|
|
291
|
+
const content = await readFileSafe(skillPath);
|
|
292
|
+
if (!content) continue;
|
|
293
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
294
|
+
const supportingFiles = await listSupportingFiles(skillDir);
|
|
295
|
+
skills.push({
|
|
296
|
+
source: skillPath,
|
|
297
|
+
name: ent.name,
|
|
298
|
+
description: typeof frontmatter.description === "string" ? frontmatter.description : "",
|
|
299
|
+
body,
|
|
300
|
+
supportingFiles
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/canonical/features/mcp.ts
|
|
307
|
+
function parseStringMap(raw) {
|
|
308
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
309
|
+
return Object.fromEntries(
|
|
310
|
+
Object.entries(raw).filter((entry) => typeof entry[1] === "string")
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
function parseServer(raw) {
|
|
314
|
+
if (!raw || typeof raw !== "object") return null;
|
|
315
|
+
const obj = raw;
|
|
316
|
+
const type = typeof obj.type === "string" ? obj.type : "stdio";
|
|
317
|
+
const env = parseStringMap(obj.env);
|
|
318
|
+
const description = typeof obj.description === "string" ? obj.description : void 0;
|
|
319
|
+
const url = typeof obj.url === "string" ? obj.url : "";
|
|
320
|
+
if (url) {
|
|
321
|
+
return {
|
|
322
|
+
...description !== void 0 && { description },
|
|
323
|
+
type,
|
|
324
|
+
url,
|
|
325
|
+
headers: parseStringMap(obj.headers),
|
|
326
|
+
env
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
const command = typeof obj.command === "string" ? obj.command : "";
|
|
330
|
+
if (!command) return null;
|
|
331
|
+
const args = Array.isArray(obj.args) ? obj.args.filter((x) => typeof x === "string") : [];
|
|
332
|
+
return {
|
|
333
|
+
...description !== void 0 && { description },
|
|
334
|
+
type,
|
|
335
|
+
command,
|
|
336
|
+
args,
|
|
337
|
+
env
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
async function parseMcp(mcpPath) {
|
|
341
|
+
const content = await readFileSafe(mcpPath);
|
|
342
|
+
if (!content) return null;
|
|
343
|
+
let parsed;
|
|
344
|
+
try {
|
|
345
|
+
parsed = JSON.parse(content);
|
|
346
|
+
} catch {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
350
|
+
const mcpServersRaw = parsed.mcpServers;
|
|
351
|
+
if (mcpServersRaw === void 0) return null;
|
|
352
|
+
if (typeof mcpServersRaw !== "object" || mcpServersRaw === null) return null;
|
|
353
|
+
const mcpServers = {};
|
|
354
|
+
for (const [name, val] of Object.entries(mcpServersRaw)) {
|
|
355
|
+
const server = parseServer(val);
|
|
356
|
+
if (server) mcpServers[name] = server;
|
|
357
|
+
}
|
|
358
|
+
return { mcpServers };
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/canonical/features/permissions.ts
|
|
362
|
+
import { parse as parseYaml } from "yaml";
|
|
363
|
+
function ensureStringArray(val) {
|
|
364
|
+
if (!Array.isArray(val)) return [];
|
|
365
|
+
return val.filter((x) => typeof x === "string");
|
|
366
|
+
}
|
|
367
|
+
async function parsePermissions(permissionsPath) {
|
|
368
|
+
const content = await readFileSafe(permissionsPath);
|
|
369
|
+
if (content === null) return null;
|
|
370
|
+
if (!content.trim()) return { allow: [], deny: [], ask: [] };
|
|
371
|
+
let parsed;
|
|
372
|
+
try {
|
|
373
|
+
parsed = parseYaml(content);
|
|
374
|
+
} catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
378
|
+
const obj = parsed;
|
|
379
|
+
const allow = ensureStringArray(obj.allow);
|
|
380
|
+
const deny = ensureStringArray(obj.deny);
|
|
381
|
+
const ask = ensureStringArray(obj.ask);
|
|
382
|
+
return { allow, deny, ask };
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// src/canonical/features/hooks.ts
|
|
386
|
+
import { parse as parseYaml2 } from "yaml";
|
|
387
|
+
|
|
388
|
+
// src/core/hook-command.ts
|
|
389
|
+
function trimString(value) {
|
|
390
|
+
return typeof value === "string" ? value.trim() : "";
|
|
391
|
+
}
|
|
392
|
+
function getHookCommand(entry) {
|
|
393
|
+
return trimString(entry.command);
|
|
394
|
+
}
|
|
395
|
+
function getHookPrompt(entry) {
|
|
396
|
+
return trimString(entry.prompt);
|
|
397
|
+
}
|
|
398
|
+
function getHookText(entry) {
|
|
399
|
+
const command = getHookCommand(entry);
|
|
400
|
+
const prompt = getHookPrompt(entry);
|
|
401
|
+
return entry.type === "prompt" ? prompt || command : command || prompt;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// src/canonical/features/hooks.ts
|
|
405
|
+
var VALID_TYPES = ["command", "prompt"];
|
|
406
|
+
function toHookEntry(raw) {
|
|
407
|
+
if (!raw || typeof raw !== "object") return null;
|
|
408
|
+
const obj = raw;
|
|
409
|
+
const matcher = obj.matcher;
|
|
410
|
+
if (typeof matcher !== "string") return null;
|
|
411
|
+
const command = getHookText(obj);
|
|
412
|
+
if (!command) return null;
|
|
413
|
+
const type = typeof obj.type === "string" && VALID_TYPES.includes(obj.type) ? obj.type : void 0;
|
|
414
|
+
const timeout = typeof obj.timeout === "number" && Number.isFinite(obj.timeout) ? obj.timeout : void 0;
|
|
415
|
+
const prompt = getHookPrompt(obj) || void 0;
|
|
416
|
+
return {
|
|
417
|
+
matcher,
|
|
418
|
+
command,
|
|
419
|
+
...timeout !== void 0 && { timeout },
|
|
420
|
+
...type && { type },
|
|
421
|
+
...prompt && { prompt }
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
async function parseHooks(hooksPath) {
|
|
425
|
+
const content = await readFileSafe(hooksPath);
|
|
426
|
+
if (content === null) return null;
|
|
427
|
+
if (!content.trim()) return {};
|
|
428
|
+
let parsed;
|
|
429
|
+
try {
|
|
430
|
+
parsed = parseYaml2(content);
|
|
431
|
+
} catch {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
435
|
+
const result = {};
|
|
436
|
+
const obj = parsed;
|
|
437
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
438
|
+
if (!Array.isArray(val)) continue;
|
|
439
|
+
const entries = [];
|
|
440
|
+
for (const item of val) {
|
|
441
|
+
const entry = toHookEntry(item);
|
|
442
|
+
if (entry) entries.push(entry);
|
|
443
|
+
}
|
|
444
|
+
if (entries.length > 0) result[key] = entries;
|
|
445
|
+
}
|
|
446
|
+
return result;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// src/canonical/features/ignore.ts
|
|
450
|
+
async function parseIgnore(ignorePath) {
|
|
451
|
+
const content = await readFileSafe(ignorePath);
|
|
452
|
+
if (content === null || !content.trim()) return [];
|
|
453
|
+
const lines = content.split(/\r?\n/);
|
|
454
|
+
const patterns = [];
|
|
455
|
+
for (const line of lines) {
|
|
456
|
+
const trimmed = line.trim();
|
|
457
|
+
if (trimmed === "" || trimmed.startsWith("#")) continue;
|
|
458
|
+
patterns.push(trimmed);
|
|
459
|
+
}
|
|
460
|
+
return patterns;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/canonical/load/loader.ts
|
|
464
|
+
async function loadCanonicalFiles(canonicalDirOrProjectRoot) {
|
|
465
|
+
const nestedCanonicalDir = join3(canonicalDirOrProjectRoot, ".agentsmesh");
|
|
466
|
+
const canonicalDir = await exists(nestedCanonicalDir) ? nestedCanonicalDir : canonicalDirOrProjectRoot;
|
|
467
|
+
const [rules, commands, agents, skills, mcp, permissions, hooks, ignore] = await Promise.all([
|
|
468
|
+
parseRules(join3(canonicalDir, "rules")),
|
|
469
|
+
parseCommands(join3(canonicalDir, "commands")),
|
|
470
|
+
parseAgents(join3(canonicalDir, "agents")),
|
|
471
|
+
parseSkills(join3(canonicalDir, "skills")),
|
|
472
|
+
parseMcp(join3(canonicalDir, "mcp.json")),
|
|
473
|
+
parsePermissions(join3(canonicalDir, "permissions.yaml")),
|
|
474
|
+
parseHooks(join3(canonicalDir, "hooks.yaml")),
|
|
475
|
+
parseIgnore(join3(canonicalDir, "ignore"))
|
|
476
|
+
]);
|
|
477
|
+
return {
|
|
478
|
+
rules,
|
|
479
|
+
commands,
|
|
480
|
+
agents,
|
|
481
|
+
skills,
|
|
482
|
+
mcp,
|
|
483
|
+
permissions,
|
|
484
|
+
hooks,
|
|
485
|
+
ignore
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/public/canonical.ts
|
|
490
|
+
async function loadCanonical(projectRoot) {
|
|
491
|
+
return loadCanonicalFiles(projectRoot);
|
|
492
|
+
}
|
|
493
|
+
export {
|
|
494
|
+
loadCanonical,
|
|
495
|
+
loadCanonicalFiles
|
|
496
|
+
};
|
|
497
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/canonical/load/loader.ts","../src/canonical/features/rules.ts","../src/utils/filesystem/fs.ts","../src/utils/text/markdown.ts","../src/canonical/features/commands.ts","../src/canonical/features/agents.ts","../src/canonical/features/skills.ts","../src/canonical/features/mcp.ts","../src/canonical/features/permissions.ts","../src/canonical/features/hooks.ts","../src/core/hook-command.ts","../src/canonical/features/ignore.ts","../src/public/canonical.ts"],"sourcesContent":["/**\n * Load all canonical files from a canonical directory into CanonicalFiles.\n */\n\nimport { join } from 'node:path';\nimport type { CanonicalFiles } from '../../core/types.js';\nimport { parseRules } from '../features/rules.js';\nimport { parseCommands } from '../features/commands.js';\nimport { parseAgents } from '../features/agents.js';\nimport { parseSkills } from '../features/skills.js';\nimport { parseMcp } from '../features/mcp.js';\nimport { parsePermissions } from '../features/permissions.js';\nimport { parseHooks } from '../features/hooks.js';\nimport { parseIgnore } from '../features/ignore.js';\nimport { exists } from '../../utils/filesystem/fs.js';\n\n/**\n * Load all canonical files from a canonical directory or project root.\n * Missing directories/files yield empty arrays or null as per each parser.\n *\n * @param canonicalDirOrProjectRoot - Absolute path to canonical directory or project root\n * @returns CanonicalFiles with all parsed data\n */\nexport async function loadCanonicalFiles(\n canonicalDirOrProjectRoot: string,\n): Promise<CanonicalFiles> {\n const nestedCanonicalDir = join(canonicalDirOrProjectRoot, '.agentsmesh');\n const canonicalDir = (await exists(nestedCanonicalDir))\n ? nestedCanonicalDir\n : canonicalDirOrProjectRoot;\n\n const [rules, commands, agents, skills, mcp, permissions, hooks, ignore] = await Promise.all([\n parseRules(join(canonicalDir, 'rules')),\n parseCommands(join(canonicalDir, 'commands')),\n parseAgents(join(canonicalDir, 'agents')),\n parseSkills(join(canonicalDir, 'skills')),\n parseMcp(join(canonicalDir, 'mcp.json')),\n parsePermissions(join(canonicalDir, 'permissions.yaml')),\n parseHooks(join(canonicalDir, 'hooks.yaml')),\n parseIgnore(join(canonicalDir, 'ignore')),\n ]);\n\n return {\n rules,\n commands,\n agents,\n skills,\n mcp,\n permissions,\n hooks,\n ignore,\n };\n}\n","/**\n * Parse .agentsmesh/rules/*.md into CanonicalRule objects.\n */\n\nimport { basename } from 'node:path';\nimport type { CanonicalRule } from '../../core/types.js';\nimport { readFileSafe, readDirRecursive } from '../../utils/filesystem/fs.js';\nimport { parseFrontmatter } from '../../utils/text/markdown.js';\n\nconst VALID_TRIGGERS = ['always_on', 'model_decision', 'glob', 'manual'] as const;\ntype Trigger = (typeof VALID_TRIGGERS)[number];\n\n/**\n * Coerce value to string array. Handles string, string[], or invalid.\n * @param v - Raw value from YAML\n * @returns Normalized string array\n */\nfunction toStrArray(v: unknown): string[] {\n if (Array.isArray(v)) return v.filter((x): x is string => typeof x === 'string');\n if (typeof v === 'string') return v ? [v] : [];\n return [];\n}\n\n/**\n * Parse all rule files in a rules directory.\n * @param rulesDir - Absolute path to .agentsmesh/rules\n * @returns Array of parsed CanonicalRule, or [] if dir missing/empty\n */\nexport async function parseRules(rulesDir: string): Promise<CanonicalRule[]> {\n const files = await readDirRecursive(rulesDir);\n const mdFiles = files.filter((f) => {\n if (!f.endsWith('.md')) return false;\n const name = basename(f, '.md');\n return name === '_root' || !name.startsWith('_');\n });\n const rules: CanonicalRule[] = [];\n for (const path of mdFiles) {\n const content = await readFileSafe(path);\n if (!content) continue;\n const { frontmatter, body } = parseFrontmatter(content);\n const name = basename(path, '.md');\n const rootFromFilename = name === '_root';\n const rootFromFm = frontmatter.root === true;\n const triggerRaw = frontmatter.trigger;\n const trigger: Trigger | undefined =\n typeof triggerRaw === 'string' && VALID_TRIGGERS.includes(triggerRaw as Trigger)\n ? (triggerRaw as Trigger)\n : undefined;\n const codexEmitRaw = frontmatter.codex_emit;\n const codexEmit =\n codexEmitRaw === 'execution'\n ? ('execution' as const)\n : codexEmitRaw === 'advisory'\n ? ('advisory' as const)\n : undefined;\n const instrRaw = frontmatter.codex_instruction;\n const codexInstructionVariant = instrRaw === 'override' ? ('override' as const) : undefined;\n rules.push({\n source: path,\n root: rootFromFilename || rootFromFm,\n targets: toStrArray(frontmatter.targets),\n description: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n globs: toStrArray(frontmatter.globs),\n body,\n ...(trigger !== undefined && { trigger }),\n ...(codexEmit !== undefined && { codexEmit }),\n ...(codexInstructionVariant !== undefined && { codexInstructionVariant }),\n });\n }\n return rules;\n}\n","/**\n * File system helpers for agentsmesh.\n */\n\nimport {\n readFile,\n writeFile,\n access,\n mkdir,\n rename,\n readdir,\n copyFile,\n stat,\n symlink,\n unlink,\n lstat,\n readlink,\n realpath,\n} from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { constants } from 'node:fs';\n\nconst UTF8_BOM = '\\uFEFF';\n\ninterface ErrnoLike {\n code?: string;\n message: string;\n}\n\n/**\n * Read file as utf-8 string. Strips BOM. Returns null on ENOENT.\n * @param path - Absolute or relative file path\n * @returns File content or null if not found\n */\nexport async function readFileSafe(path: string): Promise<string | null> {\n try {\n const data = await readFile(path, 'utf-8');\n return data.startsWith(UTF8_BOM) ? data.slice(UTF8_BOM.length) : data;\n } catch (err) {\n const e = err as ErrnoLike;\n if (e.code === 'ENOENT') return null;\n throw new Error(\n `Failed to read ${path}: ${e.message}. Ensure the file exists and is readable.`,\n { cause: err },\n );\n }\n}\n\n/**\n * Write content atomically (write to .tmp, then rename).\n * Creates parent directories.\n * @param path - Target file path\n * @param content - Content to write\n */\nexport async function writeFileAtomic(path: string, content: string): Promise<void> {\n const dir = dirname(path);\n await mkdir(dir, { recursive: true });\n const tmpPath = `${path}.tmp`;\n try {\n await writeFile(tmpPath, content, 'utf-8');\n await rename(tmpPath, path);\n } catch (err) {\n const e = err as ErrnoLike;\n throw new Error(`Failed to write ${path}: ${e.message}. Check permissions and disk space.`, {\n cause: err,\n });\n }\n}\n\n/**\n * Check if path exists.\n * @param path - File or directory path\n * @returns true if exists, false otherwise\n */\nexport async function exists(path: string): Promise<boolean> {\n try {\n await access(path, constants.F_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Create directory recursively. No-op if already exists.\n * @param path - Directory path\n */\nexport async function mkdirp(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\n/**\n * List all files recursively under dir. Returns absolute paths only.\n * Skips revisiting the same real directory (breaks symlink cycles).\n * @param dir - Directory to scan\n * @returns Array of absolute file paths\n */\nexport async function readDirRecursive(dir: string, visited?: Set<string>): Promise<string[]> {\n let canonicalDir: string;\n try {\n canonicalDir = await realpath(dir);\n } catch (err) {\n const e = err as ErrnoLike;\n if (e.code === 'ENOENT' || e.code === 'ENOTDIR' || e.code === 'ELOOP') return [];\n throw new Error(`Failed to read directory ${dir}: ${e.message}. Check permissions.`, {\n cause: err,\n });\n }\n const seen = visited ?? new Set<string>();\n if (seen.has(canonicalDir)) return [];\n seen.add(canonicalDir);\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n for (const ent of entries) {\n const full = join(dir, ent.name);\n const walkChild =\n ent.isDirectory() ||\n (ent.isSymbolicLink() &&\n (await stat(full).then(\n (s) => s.isDirectory(),\n () => false,\n )));\n if (walkChild) {\n files.push(...(await readDirRecursive(full, seen)));\n } else {\n files.push(full);\n }\n }\n return files;\n } catch (err) {\n const e = err as ErrnoLike;\n if (e.code === 'ENOENT' || e.code === 'ENOTDIR' || e.code === 'EACCES') return [];\n throw new Error(`Failed to read directory ${dir}: ${e.message}. Check permissions.`, {\n cause: err,\n });\n }\n}\n\n/**\n * Copy directory recursively preserving structure.\n * @param src - Source directory\n * @param dest - Destination directory\n */\nexport async function copyDir(src: string, dest: string): Promise<void> {\n await mkdirp(dest);\n const entries = await readdir(src, { withFileTypes: true });\n for (const ent of entries) {\n const srcPath = join(src, ent.name);\n const destPath = join(dest, ent.name);\n const info = await stat(srcPath);\n if (info.isDirectory()) {\n await copyDir(srcPath, destPath);\n } else {\n await mkdirp(dirname(destPath));\n await copyFile(srcPath, destPath);\n }\n }\n}\n\n/**\n * Ensure .agentsmeshcache symlink exists pointing to the agentsmesh cache dir.\n * Creates or updates the symlink so devs can inspect cached remote extends.\n * @param cacheDir - Absolute path to the cache (e.g. ~/.agentsmesh/cache)\n * @param linkPath - Absolute path where the symlink should live\n */\nexport async function ensureCacheSymlink(cacheDir: string, linkPath: string): Promise<void> {\n const targetPath = resolve(cacheDir);\n try {\n const info = await lstat(linkPath);\n if (!info.isSymbolicLink()) return; // leave existing non-symlink alone\n const currentTarget = resolve(dirname(linkPath), await readlink(linkPath));\n if (currentTarget === targetPath) return;\n await unlink(linkPath);\n } catch (err) {\n const e = err as ErrnoLike;\n if (e.code !== 'ENOENT') throw err;\n }\n await symlink(targetPath, linkPath, 'dir');\n}\n","// Frontmatter parsing\n\nimport { parse as yamlParse, stringify as yamlStringify } from 'yaml';\n\n/**\n * Parse YAML frontmatter and body from markdown/MDC content.\n * @param content - Raw content with optional --- delimited frontmatter\n * @returns Parsed frontmatter object and trimmed body\n */\nexport function parseFrontmatter(content: string): {\n frontmatter: Record<string, unknown>;\n body: string;\n} {\n const open = content.indexOf('---');\n if (open !== 0) {\n return { frontmatter: {}, body: content.trim() };\n }\n const close = content.indexOf('---', 3);\n if (close === -1) {\n return { frontmatter: {}, body: content.trim() };\n }\n const yamlStr = content.slice(3, close).trim();\n const body = content.slice(close + 3).trim();\n const frontmatter = yamlStr === '' ? {} : ((yamlParse(yamlStr) as Record<string, unknown>) ?? {});\n return { frontmatter, body };\n}\n\n/**\n * Serialize frontmatter and body back to string.\n * @param frontmatter - Key-value pairs for YAML\n * @param body - Markdown body content\n * @returns Full content with --- delimiters when frontmatter has keys\n */\nexport function serializeFrontmatter(frontmatter: Record<string, unknown>, body: string): string {\n const keys = Object.keys(frontmatter);\n if (keys.length === 0) return body;\n const yamlStr = yamlStringify(frontmatter, { lineWidth: 0 }).trimEnd();\n return `---\\n${yamlStr}\\n---\\n\\n${body}`;\n}\n","/**\n * Parse .agentsmesh/commands/*.md into CanonicalCommand objects.\n */\n\nimport { basename } from 'node:path';\nimport type { CanonicalCommand } from '../../core/types.js';\nimport { readFileSafe, readDirRecursive } from '../../utils/filesystem/fs.js';\nimport { parseFrontmatter } from '../../utils/text/markdown.js';\n\n/**\n * Coerce value to tools array. Handles comma-separated string, string[], or invalid.\n * @param v - Raw value from YAML (e.g. \"Read, Grep\" or [\"Read\", \"Grep\"])\n * @returns Normalized string array\n */\nfunction toBool(v: unknown): boolean {\n return v === true || v === 'true' || v === 1 || v === '1';\n}\n\nfunction toToolsArray(v: unknown): string[] {\n if (Array.isArray(v)) {\n return v\n .filter((x): x is string => typeof x === 'string')\n .map((s) => s.trim())\n .filter(Boolean);\n }\n if (typeof v === 'string') {\n return v\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n }\n return [];\n}\n\n/**\n * Parse all command files in a commands directory.\n * @param commandsDir - Absolute path to .agentsmesh/commands\n * @returns Array of parsed CanonicalCommand, or [] if dir missing/empty\n */\nexport async function parseCommands(commandsDir: string): Promise<CanonicalCommand[]> {\n const files = await readDirRecursive(commandsDir);\n const mdFiles = files.filter((f) => f.endsWith('.md') && !basename(f).startsWith('_'));\n const commands: CanonicalCommand[] = [];\n for (const path of mdFiles) {\n const content = await readFileSafe(path);\n if (!content) continue;\n const { frontmatter, body } = parseFrontmatter(content);\n const name = basename(path, '.md');\n const fromCamel = toToolsArray(frontmatter.allowedTools);\n const fromKebab = toToolsArray(frontmatter['allowed-tools']);\n const allowedTools = fromCamel.length > 0 ? fromCamel : fromKebab;\n commands.push({\n source: path,\n name,\n description: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n allowedTools,\n outputStyle: toBool(frontmatter.outputStyle) || toBool(frontmatter['output-style']),\n body,\n });\n }\n return commands;\n}\n","/**\n * Parse .agentsmesh/agents/*.md into CanonicalAgent objects.\n */\n\nimport { basename } from 'node:path';\nimport type { CanonicalAgent, Hooks } from '../../core/types.js';\nimport { readFileSafe, readDirRecursive } from '../../utils/filesystem/fs.js';\nimport { parseFrontmatter } from '../../utils/text/markdown.js';\n\n/**\n * Coerce value to string array. Handles comma-separated string, YAML array, or invalid.\n * @param v - Raw value from YAML\n * @returns Normalized string array\n */\nfunction toStrArray(v: unknown): string[] {\n if (Array.isArray(v)) {\n return v\n .filter((x): x is string => typeof x === 'string')\n .map((s) => s.trim())\n .filter(Boolean);\n }\n if (typeof v === 'string') {\n return v\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n }\n return [];\n}\n\n/**\n * Coerce value to positive integer.\n * @param v - Raw value from YAML\n * @returns Number or 0 if invalid\n */\nfunction toBool(v: unknown): boolean {\n return v === true || v === 'true' || v === 1 || v === '1';\n}\n\nfunction toInt(v: unknown): number {\n if (typeof v === 'number' && Number.isInteger(v) && v >= 0) return v;\n if (typeof v === 'string') {\n const n = parseInt(v, 10);\n return Number.isInteger(n) && n >= 0 ? n : 0;\n }\n return 0;\n}\n\n/**\n * Extract hooks object from frontmatter. Must be a plain object.\n * @param v - Raw value\n * @returns Record or empty object\n */\nfunction toHooks(v: unknown): Hooks {\n if (v !== null && typeof v === 'object' && !Array.isArray(v)) {\n return v as Hooks;\n }\n return {};\n}\n\n/**\n * Parse all agent files in an agents directory.\n * @param agentsDir - Absolute path to .agentsmesh/agents\n * @returns Array of parsed CanonicalAgent, or [] if dir missing/empty\n */\nexport async function parseAgents(agentsDir: string): Promise<CanonicalAgent[]> {\n const files = await readDirRecursive(agentsDir);\n const mdFiles = files.filter((f) => f.endsWith('.md') && !basename(f).startsWith('_'));\n const agents: CanonicalAgent[] = [];\n for (const path of mdFiles) {\n const content = await readFileSafe(path);\n if (!content) continue;\n const { frontmatter, body } = parseFrontmatter(content);\n const name = basename(path, '.md');\n const toolsCamel = toStrArray(frontmatter.tools);\n const toolsKebab = toStrArray(frontmatter['tools']);\n const tools = toolsCamel.length > 0 ? toolsCamel : toolsKebab;\n const disallowedCamel = toStrArray(frontmatter.disallowedTools);\n const disallowedKebab = toStrArray(frontmatter['disallowed-tools']);\n const disallowedTools = disallowedCamel.length > 0 ? disallowedCamel : disallowedKebab;\n const mcpCamel = toStrArray(frontmatter.mcpServers);\n const mcpKebab = toStrArray(frontmatter['mcp-servers']);\n const mcpServers = mcpCamel.length > 0 ? mcpCamel : mcpKebab;\n const skills = toStrArray(frontmatter.skills);\n const maxTurnsCamel = toInt(frontmatter.maxTurns);\n const maxTurnsKebab = toInt(frontmatter['max-turns']);\n const maxTurns = maxTurnsCamel > 0 ? maxTurnsCamel : maxTurnsKebab > 0 ? maxTurnsKebab : 0;\n agents.push({\n source: path,\n name,\n description: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n tools,\n disallowedTools,\n model: typeof frontmatter.model === 'string' ? frontmatter.model : '',\n permissionMode:\n typeof frontmatter.permissionMode === 'string'\n ? frontmatter.permissionMode\n : typeof frontmatter['permission-mode'] === 'string'\n ? frontmatter['permission-mode']\n : '',\n maxTurns,\n mcpServers,\n hooks: toHooks(frontmatter.hooks),\n skills,\n memory: typeof frontmatter.memory === 'string' ? frontmatter.memory : '',\n outputStyle: toBool(frontmatter.outputStyle) || toBool(frontmatter['output-style']),\n body,\n });\n }\n return agents;\n}\n","/**\n * Parse .agentsmesh/skills/{name}/SKILL.md into CanonicalSkill objects.\n */\n\nimport { basename, join } from 'node:path';\nimport { readdir } from 'node:fs/promises';\nimport type { CanonicalSkill, SkillSupportingFile } from '../../core/types.js';\nimport { readFileSafe, readDirRecursive } from '../../utils/filesystem/fs.js';\nimport { parseFrontmatter } from '../../utils/text/markdown.js';\n\n/** Read file content; returns empty string if unreadable */\nasync function readContent(path: string): Promise<string> {\n const c = await readFileSafe(path);\n return c ?? '';\n}\n\nconst SKILL_FILE = 'SKILL.md';\n\n/** Directories that are never valid skill supporting content. */\nconst EXCLUDED_DIR_PREFIXES = ['.git', 'node_modules'];\n\n/** Sanitize a frontmatter name into a valid directory/skill name. */\nfunction sanitizeSkillName(raw: string): string {\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n}\n\n/**\n * List supporting files in a skill directory (all files except SKILL.md).\n * @param skillDir - Absolute path to skill directory\n * @returns Supporting files with relative and absolute paths\n */\nasync function listSupportingFiles(skillDir: string): Promise<SkillSupportingFile[]> {\n const files = await readDirRecursive(skillDir);\n const result: SkillSupportingFile[] = [];\n for (const absPath of files) {\n const raw = absPath.slice(skillDir.length + 1);\n const name = raw.replace(/\\\\/g, '/');\n if (name === SKILL_FILE || name.endsWith(`/${SKILL_FILE}`)) continue;\n const firstSegment = name.split('/')[0]!;\n if (EXCLUDED_DIR_PREFIXES.some((p) => firstSegment === p)) continue;\n if (name === '.DS_Store' || name.endsWith('/.DS_Store')) continue;\n const content = await readContent(absPath);\n result.push({ relativePath: name, absolutePath: absPath, content });\n }\n return result.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n}\n\n/**\n * Parse all skill directories under skillsDir.\n * Each skill lives in skillsDir/{name}/SKILL.md.\n * @param skillsDir - Absolute path to .agentsmesh/skills\n * @returns Array of parsed CanonicalSkill, or [] if dir missing/empty\n */\n/**\n * Parse a single skill directory containing SKILL.md (Anthropic-style leaf folder).\n */\nexport async function parseSkillDirectory(skillDir: string): Promise<CanonicalSkill | null> {\n const skillPath = join(skillDir, SKILL_FILE);\n const content = await readFileSafe(skillPath);\n if (!content) return null;\n const { frontmatter, body } = parseFrontmatter(content);\n const supportingFiles = await listSupportingFiles(skillDir);\n const fmName = typeof frontmatter.name === 'string' ? sanitizeSkillName(frontmatter.name) : '';\n return {\n source: skillPath,\n name: fmName || basename(skillDir),\n description: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n body,\n supportingFiles,\n };\n}\n\nexport async function parseSkills(skillsDir: string): Promise<CanonicalSkill[]> {\n let entries: { name: string; isDirectory: () => boolean }[];\n try {\n entries = await readdir(skillsDir, { withFileTypes: true });\n } catch {\n return [];\n }\n const skills: CanonicalSkill[] = [];\n for (const ent of entries) {\n if (!ent.isDirectory()) continue;\n if (ent.name.startsWith('_')) continue;\n const skillDir = join(skillsDir, ent.name);\n const skillPath = join(skillDir, SKILL_FILE);\n const content = await readFileSafe(skillPath);\n if (!content) continue;\n const { frontmatter, body } = parseFrontmatter(content);\n const supportingFiles = await listSupportingFiles(skillDir);\n skills.push({\n source: skillPath,\n name: ent.name,\n description: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n body,\n supportingFiles,\n });\n }\n return skills.sort((a, b) => a.name.localeCompare(b.name));\n}\n","/**\n * Parse .agentsmesh/mcp.json into McpConfig.\n */\n\nimport { readFileSafe } from '../../utils/filesystem/fs.js';\nimport type { McpConfig, McpServer } from '../../core/types.js';\n\nfunction parseStringMap(raw: unknown): Record<string, string> {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) return {};\n return Object.fromEntries(\n Object.entries(raw).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n}\n\nfunction parseServer(raw: unknown): McpServer | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const type = typeof obj.type === 'string' ? obj.type : 'stdio';\n const env = parseStringMap(obj.env);\n const description = typeof obj.description === 'string' ? obj.description : undefined;\n\n const url = typeof obj.url === 'string' ? obj.url : '';\n if (url) {\n return {\n ...(description !== undefined && { description }),\n type,\n url,\n headers: parseStringMap(obj.headers),\n env,\n };\n }\n\n const command = typeof obj.command === 'string' ? obj.command : '';\n if (!command) return null;\n\n const args = Array.isArray(obj.args)\n ? obj.args.filter((x): x is string => typeof x === 'string')\n : [];\n return {\n ...(description !== undefined && { description }),\n type,\n command,\n args,\n env,\n };\n}\n\n/**\n * Parse mcp.json at the given path.\n * @param mcpPath - Absolute path to .agentsmesh/mcp.json\n * @returns McpConfig or null if file missing, malformed, or lacks mcpServers\n */\nexport async function parseMcp(mcpPath: string): Promise<McpConfig | null> {\n const content = await readFileSafe(mcpPath);\n if (!content) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(content) as unknown;\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== 'object') return null;\n const mcpServersRaw = (parsed as Record<string, unknown>).mcpServers;\n if (mcpServersRaw === undefined) return null;\n if (typeof mcpServersRaw !== 'object' || mcpServersRaw === null) return null;\n const mcpServers: Record<string, McpServer> = {};\n for (const [name, val] of Object.entries(mcpServersRaw)) {\n const server = parseServer(val);\n if (server) mcpServers[name] = server;\n }\n return { mcpServers };\n}\n","/**\n * Parse .agentsmesh/permissions.yaml into Permissions.\n */\n\nimport { parse as parseYaml } from 'yaml';\nimport { readFileSafe } from '../../utils/filesystem/fs.js';\nimport type { Permissions } from '../../core/types.js';\n\nfunction ensureStringArray(val: unknown): string[] {\n if (!Array.isArray(val)) return [];\n return val.filter((x): x is string => typeof x === 'string');\n}\n\n/**\n * Parse permissions.yaml at the given path.\n * @param permissionsPath - Absolute path to .agentsmesh/permissions.yaml\n * @returns Permissions or null if file missing or malformed\n */\nexport async function parsePermissions(permissionsPath: string): Promise<Permissions | null> {\n const content = await readFileSafe(permissionsPath);\n if (content === null) return null;\n if (!content.trim()) return { allow: [], deny: [], ask: [] };\n let parsed: unknown;\n try {\n parsed = parseYaml(content) as unknown;\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== 'object') return null;\n const obj = parsed as Record<string, unknown>;\n const allow = ensureStringArray(obj.allow);\n const deny = ensureStringArray(obj.deny);\n const ask = ensureStringArray(obj.ask);\n return { allow, deny, ask };\n}\n","/**\n * Parse .agentsmesh/hooks.yaml into Hooks.\n */\n\nimport { parse as parseYaml } from 'yaml';\nimport { readFileSafe } from '../../utils/filesystem/fs.js';\nimport type { HookEntry, Hooks } from '../../core/types.js';\nimport { getHookText, getHookPrompt } from '../../core/hook-command.js';\n\nconst VALID_TYPES = ['command', 'prompt'] as const;\n\nfunction toHookEntry(raw: unknown): HookEntry | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const matcher = obj.matcher;\n if (typeof matcher !== 'string') return null;\n const command = getHookText(obj);\n if (!command) return null;\n const type =\n typeof obj.type === 'string' && VALID_TYPES.includes(obj.type as (typeof VALID_TYPES)[number])\n ? (obj.type as 'command' | 'prompt')\n : undefined;\n const timeout =\n typeof obj.timeout === 'number' && Number.isFinite(obj.timeout) ? obj.timeout : undefined;\n const prompt = getHookPrompt(obj) || undefined;\n return {\n matcher,\n command,\n ...(timeout !== undefined && { timeout }),\n ...(type && { type }),\n ...(prompt && { prompt }),\n };\n}\n\n/**\n * Parse hooks.yaml at the given path.\n * @param hooksPath - Absolute path to .agentsmesh/hooks.yaml\n * @returns Hooks or null if file missing or malformed\n */\nexport async function parseHooks(hooksPath: string): Promise<Hooks | null> {\n const content = await readFileSafe(hooksPath);\n if (content === null) return null;\n if (!content.trim()) return {};\n let parsed: unknown;\n try {\n parsed = parseYaml(content) as unknown;\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== 'object') return null;\n const result: Hooks = {};\n const obj = parsed as Record<string, unknown>;\n for (const [key, val] of Object.entries(obj)) {\n if (!Array.isArray(val)) continue;\n const entries: HookEntry[] = [];\n for (const item of val) {\n const entry = toHookEntry(item);\n if (entry) entries.push(entry);\n }\n if (entries.length > 0) result[key] = entries;\n }\n return result;\n}\n","type HookLike = {\n command?: unknown;\n prompt?: unknown;\n type?: unknown;\n};\n\nfunction trimString(value: unknown): string {\n return typeof value === 'string' ? value.trim() : '';\n}\n\nexport function getHookCommand(entry: HookLike): string {\n return trimString(entry.command);\n}\n\nexport function getHookPrompt(entry: HookLike): string {\n return trimString(entry.prompt);\n}\n\nexport function getHookText(entry: HookLike): string {\n const command = getHookCommand(entry);\n const prompt = getHookPrompt(entry);\n return entry.type === 'prompt' ? prompt || command : command || prompt;\n}\n\nexport function hasHookCommand(entry: HookLike): boolean {\n return getHookCommand(entry).length > 0;\n}\n\nexport function hasHookText(entry: HookLike): boolean {\n return getHookText(entry).length > 0;\n}\n","/**\n * Parse .agentsmesh/ignore into gitignore-style patterns.\n */\n\nimport { readFileSafe } from '../../utils/filesystem/fs.js';\nimport type { IgnorePatterns } from '../../core/types.js';\n\n/**\n * Parse ignore file at the given path.\n * @param ignorePath - Absolute path to .agentsmesh/ignore\n * @returns Array of ignore patterns (empty array if file missing or empty)\n */\nexport async function parseIgnore(ignorePath: string): Promise<IgnorePatterns> {\n const content = await readFileSafe(ignorePath);\n if (content === null || !content.trim()) return [];\n\n const lines = content.split(/\\r?\\n/);\n const patterns: string[] = [];\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed === '' || trimmed.startsWith('#')) continue;\n patterns.push(trimmed);\n }\n\n return patterns;\n}\n","/**\n * Public API — canonical loading (package.json \"exports\".\"./canonical\").\n */\n\nimport type { CanonicalFiles } from '../core/types.js';\nimport { loadCanonicalFiles } from '../canonical/load/loader.js';\n\nexport { loadCanonicalFiles };\n\n/** Load `.agentsmesh/` from a project root (or an explicit canonical directory). */\nexport async function loadCanonical(projectRoot: string): Promise<CanonicalFiles> {\n return loadCanonicalFiles(projectRoot);\n}\n"],"mappings":"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","names":["join","basename","basename","basename","toStrArray","toBool","basename","basename","join","readdir","readdir","join","parseYaml","parseYaml","join"]}
|