agentsmesh 0.33.0 → 0.35.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/dist/targets.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod';
2
2
  import { stringify, parseDocument, parse, isMap, Document, isSeq, isScalar, Scalar, Pair, YAMLSeq } from 'yaml';
3
+ import { existsSync, realpathSync, readFileSync, constants, statSync } from 'fs';
3
4
  import { basename, win32, posix, join, relative, dirname, extname } from 'path';
4
5
  import { readFile, readdir, mkdir, lstat, unlink, writeFile, rename, chmod, rm, realpath, stat, access } from 'fs/promises';
5
6
  import 'timers/promises';
6
- import { existsSync, realpathSync, readFileSync, constants, statSync } from 'fs';
7
7
  import { parse as parse$1, stringify as stringify$1 } from 'smol-toml';
8
8
  import { Buffer } from 'buffer';
9
9
 
@@ -86,8 +86,17 @@ var init_target_descriptor_schema = __esm({
86
86
  managedOutputsSchema = z.object({
87
87
  dirs: z.array(z.string()),
88
88
  files: z.array(z.string()),
89
- coOwnedFiles: z.array(z.string()).optional()
89
+ coOwnedFiles: z.array(z.string()).optional(),
90
+ supersededFiles: z.array(z.string()).optional()
90
91
  }).passthrough().superRefine((value, ctx) => {
92
+ for (const file of value.supersededFiles ?? []) {
93
+ if (!value.files.includes(file) && !(value.coOwnedFiles ?? []).includes(file)) continue;
94
+ ctx.addIssue({
95
+ code: "custom",
96
+ path: ["supersededFiles"],
97
+ message: `"${file}" is in managedOutputs.supersededFiles and another managedOutputs list.`
98
+ });
99
+ }
91
100
  for (const file of value.coOwnedFiles ?? []) {
92
101
  if (!value.files.includes(file)) continue;
93
102
  ctx.addIssue({
@@ -375,24 +384,28 @@ var init_target_ids = __esm({
375
384
  }
376
385
  });
377
386
  function parseFrontmatter(content) {
378
- const open = content.indexOf("---");
379
- if (open !== 0) {
380
- return { frontmatter: {}, body: content.trim() };
381
- }
382
- const close = content.indexOf("---", 3);
383
- if (close === -1) {
384
- return { frontmatter: {}, body: content.trim() };
385
- }
386
- const yamlStr = content.slice(3, close).trim();
387
- const body = content.slice(close + 3).trim();
387
+ const split = splitFrontmatter(content);
388
+ if (split === null) return { frontmatter: {}, body: content.trim() };
389
+ const yamlStr = split.yaml.trim();
388
390
  const frontmatter = yamlStr === "" ? {} : parse(yamlStr) ?? {};
389
- return { frontmatter, body };
391
+ return { frontmatter, body: split.body };
392
+ }
393
+ function splitFrontmatter(content) {
394
+ const opener = OPENER.exec(content);
395
+ if (opener === null) return null;
396
+ const yamlStart = opener[0].length;
397
+ const closer = CLOSER.exec(content.slice(yamlStart));
398
+ if (closer === null) return null;
399
+ const closeStart = yamlStart + closer.index;
400
+ const closeEnd = closeStart + closer[0].length;
401
+ return {
402
+ yaml: content.slice(yamlStart, closeStart),
403
+ body: content.slice(closeEnd).trim(),
404
+ prefix: content.slice(0, closeEnd)
405
+ };
390
406
  }
391
407
  function extractBody(content) {
392
- if (content.indexOf("---") !== 0) return content.trim();
393
- const close = content.indexOf("---", 3);
394
- if (close === -1) return content.trim();
395
- return content.slice(close + 3).trim();
408
+ return splitFrontmatter(content)?.body ?? content.trim();
396
409
  }
397
410
  function tryParseFrontmatter(content, filePath2) {
398
411
  try {
@@ -415,8 +428,11 @@ ${yamlStr}
415
428
 
416
429
  ${body}`;
417
430
  }
431
+ var OPENER, CLOSER;
418
432
  var init_markdown = __esm({
419
433
  "src/utils/text/markdown.ts"() {
434
+ OPENER = /^---[ \t]*\r?\n/;
435
+ CLOSER = /^---[ \t]*\r?$/m;
420
436
  }
421
437
  });
422
438
 
@@ -476,11 +492,25 @@ var init_command_skill = __esm({
476
492
  LEGACY_CODEX_COMMAND_SKILL_PREFIX = "ab-command-";
477
493
  }
478
494
  });
495
+ var RECALL_HOOK_COMMAND;
496
+ var init_recall_hook_scaffold = __esm({
497
+ "src/lessons/recall-hook-scaffold.ts"() {
498
+ RECALL_HOOK_COMMAND = "agentsmesh lessons hook";
499
+ }
500
+ });
479
501
 
480
502
  // src/core/hook-types.ts
503
+ function isBestEffortHookEvent(event, entries) {
504
+ if (!BEST_EFFORT_HOOK_EVENTS.has(event)) return false;
505
+ if (!Array.isArray(entries)) return true;
506
+ return entries.every(
507
+ (entry) => typeof entry === "object" && entry !== null && typeof entry.command === "string" && entry.command.includes(RECALL_HOOK_COMMAND)
508
+ );
509
+ }
481
510
  var BEST_EFFORT_HOOK_EVENTS;
482
511
  var init_hook_types = __esm({
483
512
  "src/core/hook-types.ts"() {
513
+ init_recall_hook_scaffold();
484
514
  BEST_EFFORT_HOOK_EVENTS = /* @__PURE__ */ new Set([
485
515
  "UserPromptSubmit",
486
516
  "PostToolUseFailure",
@@ -666,7 +696,7 @@ var init_conf_merge = __esm({
666
696
  });
667
697
 
668
698
  // src/core/errors.ts
669
- var AgentsMeshError, FileSystemError;
699
+ var AgentsMeshError, CanonicalParseError, FileSystemError;
670
700
  var init_errors = __esm({
671
701
  "src/core/errors.ts"() {
672
702
  AgentsMeshError = class extends Error {
@@ -677,6 +707,21 @@ var init_errors = __esm({
677
707
  this.code = code;
678
708
  }
679
709
  };
710
+ CanonicalParseError = class extends AgentsMeshError {
711
+ path;
712
+ constructor(path, cause) {
713
+ const detail = cause instanceof Error ? cause.message : String(cause);
714
+ super(
715
+ "AM_CONFIG_INVALID",
716
+ `Invalid canonical file ${path}: ${detail}. Fix the syntax and try again.`,
717
+ {
718
+ cause
719
+ }
720
+ );
721
+ this.name = "CanonicalParseError";
722
+ this.path = path;
723
+ }
724
+ };
680
725
  FileSystemError = class extends AgentsMeshError {
681
726
  path;
682
727
  errnoCode;
@@ -1172,6 +1217,7 @@ function extractEmbeddedRules(content) {
1172
1217
  var ROOT_CONTRACT_START, ROOT_CONTRACT_END, EMBEDDED_RULES_START, EMBEDDED_RULES_END, EMBEDDED_RULE_END, EMBEDDED_RULE_START_PREFIX, EMBEDDED_RULE_START_SUFFIX;
1173
1218
  var init_managed_blocks = __esm({
1174
1219
  "src/targets/projection/managed-blocks.ts"() {
1220
+ init_markdown();
1175
1221
  ROOT_CONTRACT_START = "<!-- agentsmesh:root-generation-contract:start -->";
1176
1222
  ROOT_CONTRACT_END = "<!-- agentsmesh:root-generation-contract:end -->";
1177
1223
  EMBEDDED_RULES_START = "<!-- agentsmesh:embedded-rules:start -->";
@@ -1333,10 +1379,17 @@ async function serializeImportedCommandWithFallback(destinationPath, imported, b
1333
1379
  })();
1334
1380
  const description = imported.hasDescription ? imported.description ?? "" : typeof existingFrontmatter.description === "string" ? existingFrontmatter.description : "";
1335
1381
  const allowedTools = imported.hasAllowedTools ? imported.allowedTools ?? [] : existingAllowedTools;
1382
+ const {
1383
+ description: _d,
1384
+ "allowed-tools": _a,
1385
+ allowedTools: _c,
1386
+ ...preserved
1387
+ } = existingFrontmatter;
1336
1388
  return serializeFrontmatter(
1337
1389
  {
1338
1390
  description,
1339
- "allowed-tools": allowedTools
1391
+ "allowed-tools": allowedTools,
1392
+ ...preserved
1340
1393
  },
1341
1394
  body.trim() || ""
1342
1395
  );
@@ -2234,6 +2287,26 @@ var init_link_rebaser_resolution = __esm({
2234
2287
  }
2235
2288
  });
2236
2289
 
2290
+ // src/core/reference/link-uri-encoding.ts
2291
+ function decodeLinkPath(token, role) {
2292
+ if (role !== "markdown-link-dest" || !token.includes("%")) return token;
2293
+ try {
2294
+ return decodeURIComponent(token);
2295
+ } catch {
2296
+ return token;
2297
+ }
2298
+ }
2299
+ function encodeLinkPath(path, enabled) {
2300
+ if (!enabled) return path;
2301
+ return path.split("/").map(
2302
+ (segment) => segment === "" || segment === "." || segment === ".." ? segment : encodeURIComponent(segment)
2303
+ ).join("/");
2304
+ }
2305
+ var init_link_uri_encoding = __esm({
2306
+ "src/core/reference/link-uri-encoding.ts"() {
2307
+ }
2308
+ });
2309
+
2237
2310
  // src/core/reference/link-token-guards.ts
2238
2311
  function isTildeHomeRelativePathToken(fullContent, matchOffset, matchText) {
2239
2312
  if (matchOffset >= 2 && fullContent[matchOffset - 2] === "~" && fullContent[matchOffset - 1] === "/") {
@@ -2363,10 +2436,11 @@ function rewriteFileLinks(input) {
2363
2436
  const { candidate: punctStripped, suffix } = stripTrailingPunctuation(match);
2364
2437
  if (!punctStripped) return match;
2365
2438
  const lineNumMatch = LINE_NUMBER_SUFFIX.exec(punctStripped);
2366
- const candidate = lineNumMatch ? punctStripped.slice(0, lineNumMatch.index) : punctStripped;
2439
+ const rawCandidate = lineNumMatch ? punctStripped.slice(0, lineNumMatch.index) : punctStripped;
2367
2440
  const lineNumSuffix = lineNumMatch ? lineNumMatch[0] : "";
2368
- if (!candidate) return match;
2369
- const tokenContext = getTokenContext(fullContent, offset, offset + candidate.length);
2441
+ if (!rawCandidate) return match;
2442
+ const tokenContext = getTokenContext(fullContent, offset, offset + rawCandidate.length);
2443
+ const candidate = decodeLinkPath(rawCandidate, tokenContext.role);
2370
2444
  if (tokenContext.role !== "markdown-link-dest" && WINDOWS_ABSOLUTE_PATH.test(candidate)) {
2371
2445
  return match;
2372
2446
  }
@@ -2436,7 +2510,7 @@ function rewriteFileLinks(input) {
2436
2510
  const targetTop = targetFromRoot.split("/").filter(Boolean)[0] ?? "";
2437
2511
  const tokenIsCanonicalMesh = normalizeSeparators(candidate).startsWith(".agentsmesh/");
2438
2512
  const preferRelativeProseInSameSurface = !tokenIsCanonicalMesh && !targetIsDirectory && destTop.length > 0 && destTop === targetTop && destTop.startsWith(".") && destTop !== ".agentsmesh";
2439
- const forceRelative = preferRelativeProseInSameSurface || tokenContext.role === "markdown-link-dest" || isMarkdownLinkDestinationToken(fullContent, offset, candidate);
2513
+ const forceRelative = preferRelativeProseInSameSurface || tokenContext.role === "markdown-link-dest" || isMarkdownLinkDestinationToken(fullContent, offset, rawCandidate);
2440
2514
  const rewritten = formatLinkPathForDestination(
2441
2515
  input.projectRoot,
2442
2516
  input.destinationFile,
@@ -2453,7 +2527,7 @@ function rewriteFileLinks(input) {
2453
2527
  }
2454
2528
  );
2455
2529
  if (!rewritten) return match;
2456
- return `${rewritten}${lineNumSuffix}${suffix}`;
2530
+ return `${encodeLinkPath(rewritten, candidate !== rawCandidate)}${lineNumSuffix}${suffix}`;
2457
2531
  });
2458
2532
  return { content, missing: [...missing] };
2459
2533
  }
@@ -2463,6 +2537,7 @@ var init_link_rebaser = __esm({
2463
2537
  init_link_rebaser_helpers();
2464
2538
  init_link_rebaser_output();
2465
2539
  init_link_rebaser_resolution();
2540
+ init_link_uri_encoding();
2466
2541
  init_link_token_guards();
2467
2542
  init_link_token_context();
2468
2543
  }
@@ -3316,7 +3391,7 @@ function unsupportedHookEventNames(hooks, supportedEvents) {
3316
3391
  if (!hooks) return [];
3317
3392
  const supported = new Set(supportedEvents);
3318
3393
  return Object.keys(hooks).filter(
3319
- (event) => !supported.has(event) && !BEST_EFFORT_HOOK_EVENTS.has(event)
3394
+ (event) => !supported.has(event) && !isBestEffortHookEvent(event, hooks[event])
3320
3395
  );
3321
3396
  }
3322
3397
  function createUnsupportedHookWarning(event, target34, supportedEvents, options) {
@@ -6853,6 +6928,17 @@ var init_embedded_rules = __esm({
6853
6928
  }
6854
6929
  });
6855
6930
 
6931
+ // src/canonical/features/syntax-error.ts
6932
+ function failSyntax(filePath2, cause, onParseError) {
6933
+ const error = new CanonicalParseError(filePath2, cause);
6934
+ throw error;
6935
+ }
6936
+ var init_syntax_error = __esm({
6937
+ "src/canonical/features/syntax-error.ts"() {
6938
+ init_errors();
6939
+ }
6940
+ });
6941
+
6856
6942
  // src/canonical/features/mcp.ts
6857
6943
  function parseStringMap(raw) {
6858
6944
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return {};
@@ -6935,14 +7021,14 @@ function stripJsonComments(text) {
6935
7021
  }
6936
7022
  return result2;
6937
7023
  }
6938
- async function parseMcp(mcpPath) {
7024
+ async function parseMcp(mcpPath, onParseError) {
6939
7025
  const content = await readFileSafe(mcpPath);
6940
7026
  if (!content) return null;
6941
7027
  let parsed;
6942
7028
  try {
6943
7029
  parsed = JSON.parse(stripJsonComments(content));
6944
- } catch {
6945
- return null;
7030
+ } catch (err) {
7031
+ return failSyntax(mcpPath, err);
6946
7032
  }
6947
7033
  if (!parsed || typeof parsed !== "object") return null;
6948
7034
  const mcpServersRaw = parsed.mcpServers;
@@ -6957,6 +7043,7 @@ async function parseMcp(mcpPath) {
6957
7043
  }
6958
7044
  var init_mcp = __esm({
6959
7045
  "src/canonical/features/mcp.ts"() {
7046
+ init_syntax_error();
6960
7047
  init_fs();
6961
7048
  }
6962
7049
  });
@@ -8736,10 +8823,10 @@ var init_claude_code2 = __esm({
8736
8823
  skillDir: ".claude/skills",
8737
8824
  managedOutputs: {
8738
8825
  dirs: [".claude/agents", ".claude/commands", ".claude/rules", ".claude/skills"],
8739
- // CLAUDE_NESTED_ROOT is the pre-migration project location; listing it here lets
8740
- // `cleanupStaleGeneratedOutputs` evict a leftover `.claude/CLAUDE.md` once generation
8826
+ files: [CLAUDE_ROOT, ".claudeignore"],
8827
+ // CLAUDE_NESTED_ROOT is the pre-migration project location: evicted once a run
8741
8828
  // writes the root `CLAUDE.md`, so Claude Code never concatenates both into context.
8742
- files: [CLAUDE_ROOT, CLAUDE_NESTED_ROOT, ".claudeignore"],
8829
+ supersededFiles: [CLAUDE_NESTED_ROOT],
8743
8830
  // `.mcp.json` is the shared project MCP file teams hand-commit and
8744
8831
  // deepagents-cli writes too; agentsmesh owns only `mcpServers` in it.
8745
8832
  // `.claude/settings.json` is co-owned through the `SETTINGS_JSON_PATHS`
@@ -9970,9 +10057,8 @@ var init_cline2 = __esm({
9970
10057
  };
9971
10058
  }
9972
10059
  });
9973
- function ruleSlug2(source) {
9974
- return basename(source, ".md");
9975
- }
10060
+
10061
+ // src/targets/codex-cli/codex-rule-paths.ts
9976
10062
  function directoryFromGlob(glob) {
9977
10063
  let normalized = glob.trim();
9978
10064
  if (normalized.startsWith("./")) normalized = normalized.slice(2);
@@ -9993,12 +10079,12 @@ function codexRuleDirectory(rule) {
9993
10079
  const dir = directoryFromGlob(glob);
9994
10080
  if (dir) return dir;
9995
10081
  }
9996
- return ruleSlug2(rule.source);
10082
+ return null;
9997
10083
  }
9998
10084
  function codexNestedAgentsPath(rule) {
9999
10085
  const dir = codexRuleDirectory(rule);
10000
10086
  const filename = rule.codexInstructionVariant === "override" ? "AGENTS.override.md" : "AGENTS.md";
10001
- return `${dir}/${filename}`;
10087
+ return dir === null ? filename : `${dir}/${filename}`;
10002
10088
  }
10003
10089
  var GLOB_METACHAR;
10004
10090
  var init_codex_rule_paths = __esm({
@@ -10006,10 +10092,9 @@ var init_codex_rule_paths = __esm({
10006
10092
  GLOB_METACHAR = /[*?[\]]/;
10007
10093
  }
10008
10094
  });
10009
-
10010
- // src/targets/codebuff/rule-paths.ts
10011
10095
  function codebuffNestedKnowledgePath(rule) {
10012
- return `${codexRuleDirectory(rule)}/AGENTS.md`;
10096
+ const dir = codexRuleDirectory(rule) ?? basename(rule.source, ".md");
10097
+ return `${dir}/AGENTS.md`;
10013
10098
  }
10014
10099
  var init_rule_paths = __esm({
10015
10100
  "src/targets/codebuff/rule-paths.ts"() {
@@ -10620,6 +10705,9 @@ function eligibleAdvisoryRules(canonical) {
10620
10705
  return rule.targets.length === 0 || rule.targets.includes("codex-cli");
10621
10706
  });
10622
10707
  }
10708
+ function isRootEmbedded(rule) {
10709
+ return codexNestedAgentsPath(rule) === AGENTS_MD;
10710
+ }
10623
10711
  function groupByNestedPath2(rules) {
10624
10712
  const groups = /* @__PURE__ */ new Map();
10625
10713
  for (const rule of rules) {
@@ -10632,9 +10720,11 @@ function groupByNestedPath2(rules) {
10632
10720
  }
10633
10721
  function generateRules9(canonical) {
10634
10722
  const root = canonical.rules.find((r) => r.root);
10723
+ const advisory = eligibleAdvisoryRules(canonical);
10635
10724
  const outputs = [];
10636
10725
  if (root) {
10637
- outputs.push({ path: AGENTS_MD, content: root.body.trim() });
10726
+ const content = appendEmbeddedRulesBlock(root.body.trim(), advisory.filter(isRootEmbedded));
10727
+ outputs.push({ path: AGENTS_MD, content });
10638
10728
  }
10639
10729
  for (const rule of canonical.rules) {
10640
10730
  if (rule.root) continue;
@@ -10646,7 +10736,8 @@ function generateRules9(canonical) {
10646
10736
  content: toSafeCodexRulesContent(rule.body)
10647
10737
  });
10648
10738
  }
10649
- for (const [path, rules] of groupByNestedPath2(eligibleAdvisoryRules(canonical))) {
10739
+ const nested = advisory.filter((rule) => !isRootEmbedded(rule));
10740
+ for (const [path, rules] of groupByNestedPath2(nested)) {
10650
10741
  const content = rules.map((rule) => rule.body.trim()).filter((body) => body.length > 0).join("\n\n");
10651
10742
  outputs.push({ path, content });
10652
10743
  }
@@ -11471,6 +11562,23 @@ var init_linter9 = __esm({
11471
11562
  });
11472
11563
 
11473
11564
  // src/targets/codex-cli/lint.ts
11565
+ function lintAgents3(canonical) {
11566
+ const diagnostics = [];
11567
+ for (const agent of canonical.agents) {
11568
+ const dropped = CODEX_DROPPED_AGENT_FIELDS.filter(
11569
+ (field) => hasAgentValue(agent, field)
11570
+ ).sort();
11571
+ if (dropped.length === 0) continue;
11572
+ diagnostics.push(
11573
+ createWarning(
11574
+ agent.source,
11575
+ "codex-cli",
11576
+ `Codex agent TOML supports name, description, developer_instructions, model, sandbox_mode and mcp_servers; canonical ${dropped.join(", ")} are not projected to ${CODEX_AGENTS_DIR}/${agent.name}.toml.`
11577
+ )
11578
+ );
11579
+ }
11580
+ return diagnostics;
11581
+ }
11474
11582
  function lintMcp4(canonical) {
11475
11583
  if (!canonical.mcp || Object.keys(canonical.mcp.mcpServers).length === 0) return [];
11476
11584
  const diagnostics = [];
@@ -11502,11 +11610,21 @@ function lintHooks7(canonical) {
11502
11610
  (event) => createUnsupportedHookWarning(event, "codex-cli", CODEX_SUPPORTED_HOOK_EVENTS)
11503
11611
  );
11504
11612
  }
11613
+ var CODEX_DROPPED_AGENT_FIELDS;
11505
11614
  var init_lint8 = __esm({
11506
11615
  "src/targets/codex-cli/lint.ts"() {
11507
11616
  init_helpers();
11508
11617
  init_mcp_servers();
11618
+ init_agents_format();
11509
11619
  init_constants10();
11620
+ CODEX_DROPPED_AGENT_FIELDS = [
11621
+ "tools",
11622
+ "disallowedTools",
11623
+ "maxTurns",
11624
+ "hooks",
11625
+ "skills",
11626
+ "memory"
11627
+ ];
11510
11628
  }
11511
11629
  });
11512
11630
 
@@ -11581,6 +11699,7 @@ var init_codex_cli2 = __esm({
11581
11699
  generateMcp: generateMcp6,
11582
11700
  generateHooks: generateHooks6,
11583
11701
  generatePermissions: generatePermissions7,
11702
+ lint: lintAgents3,
11584
11703
  importFrom: importFromCodex
11585
11704
  };
11586
11705
  project6 = {
@@ -11628,7 +11747,7 @@ var init_codex_cli2 = __esm({
11628
11747
  },
11629
11748
  rewriteGeneratedPath(path) {
11630
11749
  if (path === AGENTS_MD) return CODEX_GLOBAL_AGENTS_MD;
11631
- if (/\/AGENTS(\.override)?\.md$/.test(path)) return null;
11750
+ if (/(^|\/)AGENTS(\.override)?\.md$/.test(path)) return null;
11632
11751
  if (path.startsWith(`${CODEX_INSTRUCTIONS_DIR}/`)) return null;
11633
11752
  return path;
11634
11753
  },
@@ -12284,7 +12403,7 @@ function hasValue(agent, field) {
12284
12403
  if (value && typeof value === "object") return Object.keys(value).length > 0;
12285
12404
  return false;
12286
12405
  }
12287
- function lintAgents3(canonical) {
12406
+ function lintAgents4(canonical) {
12288
12407
  const diagnostics = [];
12289
12408
  for (const agent of canonical.agents) {
12290
12409
  const dropped = DROPPED_FIELDS.filter((field) => hasValue(agent, field)).sort();
@@ -12452,7 +12571,7 @@ var init_continue2 = __esm({
12452
12571
  generateHooks: generateHooks7,
12453
12572
  generateIgnore: generateIgnore8,
12454
12573
  // Feature-independent lint hook: agent warnings must not hang off `rules`.
12455
- lint: lintAgents3,
12574
+ lint: lintAgents4,
12456
12575
  importFrom: importFromContinue
12457
12576
  };
12458
12577
  descriptor10 = {
@@ -12709,7 +12828,7 @@ var init_hook_format = __esm({
12709
12828
  init_hook_entry();
12710
12829
  }
12711
12830
  });
12712
- function ruleSlug3(source) {
12831
+ function ruleSlug2(source) {
12713
12832
  const name = basename(source, ".md");
12714
12833
  return name === "_root" ? "root" : name;
12715
12834
  }
@@ -12743,7 +12862,7 @@ function generateRules11(canonical) {
12743
12862
  if (rule.root) continue;
12744
12863
  if (rule.targets.length > 0 && !rule.targets.includes("copilot")) continue;
12745
12864
  if (rule.globs.length === 0) continue;
12746
- const slug = ruleSlug3(rule.source);
12865
+ const slug = ruleSlug2(rule.source);
12747
12866
  const frontmatter = {
12748
12867
  description: rule.description || void 0,
12749
12868
  applyTo: rule.globs.length === 1 ? rule.globs[0] : rule.globs
@@ -14232,13 +14351,18 @@ var init_rules2 = __esm({
14232
14351
 
14233
14352
  // src/targets/cursor/generator/commands.ts
14234
14353
  function generateCommands13(canonical) {
14235
- return canonical.commands.map((cmd) => ({
14236
- path: `${CURSOR_COMMANDS_DIR}/${cmd.name}.md`,
14237
- content: cmd.body.trim() || ""
14238
- }));
14354
+ return canonical.commands.map((cmd) => {
14355
+ const frontmatter = {};
14356
+ if (cmd.description) frontmatter.description = cmd.description;
14357
+ return {
14358
+ path: `${CURSOR_COMMANDS_DIR}/${cmd.name}.md`,
14359
+ content: serializeFrontmatter(frontmatter, cmd.body.trim() || "")
14360
+ };
14361
+ });
14239
14362
  }
14240
14363
  var init_commands = __esm({
14241
14364
  "src/targets/cursor/generator/commands.ts"() {
14365
+ init_markdown();
14242
14366
  init_constants13();
14243
14367
  }
14244
14368
  });
@@ -14333,7 +14457,7 @@ var init_permissions3 = __esm({
14333
14457
  // src/targets/cursor/hook-format.ts
14334
14458
  function unmappedCursorHookEvents(hooks) {
14335
14459
  return Object.keys(hooks).filter(
14336
- (event) => Array.isArray(hooks[event]) && hooks[event].length > 0 && !(event in CANONICAL_TO_CURSOR) && !BEST_EFFORT_HOOK_EVENTS.has(event)
14460
+ (event) => Array.isArray(hooks[event]) && hooks[event].length > 0 && !(event in CANONICAL_TO_CURSOR) && !isBestEffortHookEvent(event, hooks[event])
14337
14461
  );
14338
14462
  }
14339
14463
  function toCursorHooks(hooks) {
@@ -14771,14 +14895,11 @@ async function hasGlobalCursorArtifacts(projectRoot) {
14771
14895
  join(projectRoot, CURSOR_GLOBAL_USER_RULES),
14772
14896
  join(projectRoot, CURSOR_MCP),
14773
14897
  join(projectRoot, CURSOR_HOOKS),
14774
- join(projectRoot, CURSOR_IGNORE),
14775
- join(projectRoot, CURSOR_SKILLS_DIR),
14776
- join(projectRoot, CURSOR_AGENTS_DIR),
14777
- join(projectRoot, CURSOR_COMMANDS_DIR)
14898
+ join(projectRoot, CURSOR_IGNORE)
14778
14899
  ];
14779
14900
  for (const p of candidates) {
14780
- const stat4 = await readFileSafe(p);
14781
- if (stat4 !== null && stat4.trim() !== "") return true;
14901
+ const content = await readFileSafe(p);
14902
+ if (content !== null && content.trim() !== "") return true;
14782
14903
  }
14783
14904
  const skillFiles = await readDirRecursiveNoSymlinks(join(projectRoot, CURSOR_SKILLS_DIR));
14784
14905
  if (skillFiles.some((f) => f.endsWith(".md"))) return true;
@@ -15065,11 +15186,11 @@ function lintHooks10(canonical) {
15065
15186
  ];
15066
15187
  }
15067
15188
  function lintCommands6(canonical) {
15068
- return canonical.commands.filter((command) => command.description.length > 0 || command.allowedTools.length > 0).map(
15189
+ return canonical.commands.filter((command) => command.allowedTools.length > 0).map(
15069
15190
  (command) => createWarning(
15070
15191
  command.source,
15071
15192
  "cursor",
15072
- "Cursor command files are plain Markdown; command description and allowed-tools metadata are not projected."
15193
+ "Cursor command files project only description frontmatter; allowed-tools metadata is not projected."
15073
15194
  )
15074
15195
  );
15075
15196
  }
@@ -15402,7 +15523,7 @@ var init_mcp_merge4 = __esm({
15402
15523
  // src/targets/deepagents-cli/hooks-format.ts
15403
15524
  function unmappedDeepagentsHookEvents(hooks) {
15404
15525
  return Object.keys(hooks).filter(
15405
- (event) => Array.isArray(hooks[event]) && hooks[event].length > 0 && !(event in CANONICAL_TO_DEEPAGENTS) && !BEST_EFFORT_HOOK_EVENTS.has(event)
15526
+ (event) => Array.isArray(hooks[event]) && hooks[event].length > 0 && !(event in CANONICAL_TO_DEEPAGENTS) && !isBestEffortHookEvent(event, hooks[event])
15406
15527
  );
15407
15528
  }
15408
15529
  function toDeepagentsHooks(hooks) {
@@ -15970,7 +16091,8 @@ var init_deepagents_cli2 = __esm({
15970
16091
  }
15971
16092
  },
15972
16093
  buildImportPaths: buildDeepagentsCliImportPaths,
15973
- detectionPaths: [DEEPAGENTS_CLI_ROOT_FILE, DEEPAGENTS_CLI_MCP_FILE]
16094
+ // `.mcp.json` is co-owned with claude-code (agentsmesh writes it), so it must not enroll this target.
16095
+ detectionPaths: [DEEPAGENTS_CLI_ROOT_FILE]
15974
16096
  };
15975
16097
  }
15976
16098
  });
@@ -19948,7 +20070,8 @@ var init_layout8 = __esm({
19948
20070
  skillDir: KIMI_CODE_SKILLS_DIR,
19949
20071
  managedOutputs: {
19950
20072
  dirs: [KIMI_CODE_AGENTS_DIR, KIMI_CODE_SKILLS_DIR],
19951
- files: [KIMI_CODE_ROOT_FILE, KIMI_CODE_NESTED_ROOT_FILE],
20073
+ files: [KIMI_CODE_ROOT_FILE],
20074
+ supersededFiles: [KIMI_CODE_NESTED_ROOT_FILE],
19952
20075
  // Kimi Code's own MCP config, in the same directory as the credential-
19953
20076
  // bearing config.toml this layout already refuses to delete.
19954
20077
  coOwnedFiles: [KIMI_CODE_MCP_FILE]
@@ -20596,7 +20719,7 @@ function lintMcp9(canonical) {
20596
20719
  }
20597
20720
  return diagnostics;
20598
20721
  }
20599
- function lintAgents4(canonical) {
20722
+ function lintAgents5(canonical) {
20600
20723
  return canonical.agents.flatMap((agent) => {
20601
20724
  const dropped = DROPPED_AGENT_FIELDS.filter(([, has]) => has(agent)).map(([field]) => field);
20602
20725
  if (dropped.length === 0) return [];
@@ -20687,7 +20810,7 @@ var init_kimi_code2 = __esm({
20687
20810
  generateHooks: generateHooks14,
20688
20811
  generatePermissions: generatePermissions16,
20689
20812
  importFrom: importFromKimiCode,
20690
- lint: lintAgents4
20813
+ lint: lintAgents5
20691
20814
  };
20692
20815
  capabilities9 = {
20693
20816
  rules: "native",
@@ -22985,7 +23108,7 @@ function lintAgentFields(agent) {
22985
23108
  )
22986
23109
  ];
22987
23110
  }
22988
- function lintAgents5(canonical) {
23111
+ function lintAgents6(canonical) {
22989
23112
  const diagnostics = [];
22990
23113
  for (const agent of canonical.agents) {
22991
23114
  diagnostics.push(...lintAgentFields(agent));
@@ -23047,7 +23170,7 @@ var init_openhands2 = __esm({
23047
23170
  generatePermissions: generatePermissions19,
23048
23171
  importFrom: importFromOpenhands,
23049
23172
  // Ungated by feature, so agent-only feature sets still get the warning.
23050
- lint: lintAgents5
23173
+ lint: lintAgents6
23051
23174
  };
23052
23175
  descriptor24 = {
23053
23176
  id: OPENHANDS_TARGET,
@@ -26862,7 +26985,7 @@ var init_constants34 = __esm({
26862
26985
  WINDSURF_GLOBAL_AGENTS_SKILLS_DIR = ".agents/skills";
26863
26986
  }
26864
26987
  });
26865
- function ruleSlug4(source) {
26988
+ function ruleSlug3(source) {
26866
26989
  const name = basename(source, ".md");
26867
26990
  return name === "_root" ? "root" : name;
26868
26991
  }
@@ -26883,7 +27006,7 @@ function generateRules32(canonical) {
26883
27006
  for (const rule of canonical.rules) {
26884
27007
  if (rule.root) continue;
26885
27008
  if (rule.targets.length > 0 && !rule.targets.includes("windsurf")) continue;
26886
- const slug = ruleSlug4(rule.source);
27009
+ const slug = ruleSlug3(rule.source);
26887
27010
  const normalizedTrigger = rule.trigger || (rule.globs.length > 0 ? "glob" : void 0);
26888
27011
  const frontmatter = {
26889
27012
  description: rule.description || void 0,
@@ -26987,19 +27110,34 @@ var init_mcp4 = __esm({
26987
27110
  }
26988
27111
  });
26989
27112
 
26990
- // src/targets/windsurf/generator/hooks.ts
27113
+ // src/targets/windsurf/hook-events.ts
26991
27114
  function windsurfEventName(event) {
26992
- const explicit = {
26993
- PreToolUse: "pre_tool_use",
26994
- PostToolUse: "post_tool_use",
26995
- Notification: "notification",
26996
- UserPromptSubmit: "user_prompt_submit",
26997
- SubagentStart: "subagent_start",
26998
- SubagentStop: "subagent_stop"
26999
- };
27000
- if (explicit[event]) return explicit[event];
27001
27115
  return event.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase();
27002
27116
  }
27117
+ function canonicalHookEventName(event) {
27118
+ if (KNOWN_CANONICAL_HOOK_EVENTS.includes(event)) return event;
27119
+ return WINDSURF_TO_CANONICAL.get(event) ?? null;
27120
+ }
27121
+ var KNOWN_CANONICAL_HOOK_EVENTS, WINDSURF_TO_CANONICAL;
27122
+ var init_hook_events = __esm({
27123
+ "src/targets/windsurf/hook-events.ts"() {
27124
+ init_hook_types();
27125
+ KNOWN_CANONICAL_HOOK_EVENTS = [
27126
+ "PreToolUse",
27127
+ "PostToolUse",
27128
+ "Notification",
27129
+ "UserPromptSubmit",
27130
+ "SubagentStart",
27131
+ "SubagentStop",
27132
+ ...BEST_EFFORT_HOOK_EVENTS
27133
+ ];
27134
+ WINDSURF_TO_CANONICAL = new Map(
27135
+ KNOWN_CANONICAL_HOOK_EVENTS.map((event) => [windsurfEventName(event), event])
27136
+ );
27137
+ }
27138
+ });
27139
+
27140
+ // src/targets/windsurf/generator/hooks.ts
27003
27141
  function toWindsurfHooks(hooks) {
27004
27142
  const result2 = {};
27005
27143
  for (const [event, entries] of Object.entries(hooks)) {
@@ -27027,6 +27165,7 @@ var init_hooks4 = __esm({
27027
27165
  "src/targets/windsurf/generator/hooks.ts"() {
27028
27166
  init_hook_command();
27029
27167
  init_constants34();
27168
+ init_hook_events();
27030
27169
  }
27031
27170
  });
27032
27171
 
@@ -27158,6 +27297,57 @@ var init_skills_adapter5 = __esm({
27158
27297
  init_constants34();
27159
27298
  }
27160
27299
  });
27300
+ function toHookEntry(raw) {
27301
+ if (!raw || typeof raw !== "object") return null;
27302
+ const obj = raw;
27303
+ const matcher = obj.matcher;
27304
+ if (typeof matcher !== "string") return null;
27305
+ const command = getHookText(obj);
27306
+ if (!command) return null;
27307
+ const type = typeof obj.type === "string" && VALID_TYPES.includes(obj.type) ? obj.type : void 0;
27308
+ const timeout = typeof obj.timeout === "number" && Number.isFinite(obj.timeout) ? obj.timeout : void 0;
27309
+ const prompt = getHookPrompt(obj) || void 0;
27310
+ return {
27311
+ matcher,
27312
+ command,
27313
+ ...timeout !== void 0 && { timeout },
27314
+ ...type && { type },
27315
+ ...prompt && { prompt }
27316
+ };
27317
+ }
27318
+ async function parseHooks(hooksPath, onParseError) {
27319
+ const content = await readFileSafe(hooksPath);
27320
+ if (content === null) return null;
27321
+ if (!content.trim()) return {};
27322
+ let parsed;
27323
+ try {
27324
+ parsed = parse(content);
27325
+ } catch (err) {
27326
+ return failSyntax(hooksPath, err);
27327
+ }
27328
+ if (!parsed || typeof parsed !== "object") return null;
27329
+ const result2 = {};
27330
+ const obj = parsed;
27331
+ for (const [key, val] of Object.entries(obj)) {
27332
+ if (!Array.isArray(val)) continue;
27333
+ const entries = [];
27334
+ for (const item of val) {
27335
+ const entry = toHookEntry(item);
27336
+ if (entry) entries.push(entry);
27337
+ }
27338
+ if (entries.length > 0) result2[key] = entries;
27339
+ }
27340
+ return result2;
27341
+ }
27342
+ var VALID_TYPES;
27343
+ var init_hooks5 = __esm({
27344
+ "src/canonical/features/hooks.ts"() {
27345
+ init_syntax_error();
27346
+ init_fs();
27347
+ init_hook_command();
27348
+ VALID_TYPES = ["command", "prompt"];
27349
+ }
27350
+ });
27161
27351
  async function importWindsurfHooks(projectRoot, results) {
27162
27352
  const hooksPath = join(projectRoot, WINDSURF_HOOKS_FILE);
27163
27353
  const hooksContent = await readFileSafe(hooksPath);
@@ -27165,9 +27355,10 @@ async function importWindsurfHooks(projectRoot, results) {
27165
27355
  try {
27166
27356
  const parsed = JSON.parse(hooksContent);
27167
27357
  if (!parsed.hooks || typeof parsed.hooks !== "object" || Array.isArray(parsed.hooks)) return;
27168
- const canonical = windsurfHooksToCanonical(parsed.hooks);
27169
- if (Object.keys(canonical).length === 0) return;
27170
27358
  const destPath = join(projectRoot, WINDSURF_CANONICAL_HOOKS);
27359
+ const existing = await parseHooks(destPath) ?? {};
27360
+ const canonical = windsurfHooksToCanonical(parsed.hooks, existing);
27361
+ if (Object.keys(canonical).length === 0) return;
27171
27362
  await mkdirp(dirname(destPath));
27172
27363
  await writeFileAtomic(destPath, stringify(canonical));
27173
27364
  results.push({
@@ -27179,54 +27370,63 @@ async function importWindsurfHooks(projectRoot, results) {
27179
27370
  } catch {
27180
27371
  }
27181
27372
  }
27182
- function canonicalHookEventName(event) {
27183
- const explicit = {
27184
- pre_tool_use: "PreToolUse",
27185
- post_tool_use: "PostToolUse",
27186
- notification: "Notification",
27187
- user_prompt_submit: "UserPromptSubmit",
27188
- subagent_start: "SubagentStart",
27189
- subagent_stop: "SubagentStop"
27190
- };
27191
- return explicit[event] ?? event;
27373
+ function preservedMatcher(existing, event, command) {
27374
+ const match = existing[event]?.find((entry) => entry.command === command);
27375
+ return match?.matcher ?? WILDCARD_MATCHER;
27376
+ }
27377
+ function legacyEntries(entry) {
27378
+ const matcher = typeof entry.matcher === "string" && entry.matcher.trim() ? entry.matcher : WILDCARD_MATCHER;
27379
+ const hooksList = Array.isArray(entry.hooks) ? entry.hooks : [];
27380
+ const out = [];
27381
+ for (const item of hooksList) {
27382
+ if (!item || typeof item !== "object") continue;
27383
+ const hook = item;
27384
+ const command = typeof hook.command === "string" ? hook.command : typeof hook.prompt === "string" ? hook.prompt : "";
27385
+ if (!command.trim()) continue;
27386
+ const canonical = {
27387
+ matcher,
27388
+ type: hook.type === "prompt" ? "prompt" : "command",
27389
+ command
27390
+ };
27391
+ if (typeof hook.timeout === "number") canonical.timeout = hook.timeout;
27392
+ out.push(canonical);
27393
+ }
27394
+ return out;
27192
27395
  }
27193
- function windsurfHooksToCanonical(hooks) {
27396
+ function windsurfHooksToCanonical(hooks, existing) {
27194
27397
  const result2 = {};
27195
27398
  for (const [event, entries] of Object.entries(hooks)) {
27196
27399
  if (!Array.isArray(entries)) continue;
27197
27400
  const mappedEvent = canonicalHookEventName(event);
27401
+ if (mappedEvent === null) continue;
27198
27402
  const canonicalEntries = [];
27199
27403
  for (const entry of entries) {
27200
27404
  if (!entry || typeof entry !== "object") continue;
27201
27405
  const e = entry;
27202
27406
  if (typeof e.command === "string" && e.command.trim()) {
27203
27407
  canonicalEntries.push({
27204
- matcher: ".*",
27408
+ matcher: preservedMatcher(existing, mappedEvent, e.command),
27205
27409
  type: "command",
27206
27410
  command: e.command
27207
27411
  });
27208
27412
  continue;
27209
27413
  }
27210
- const matcher = typeof e.matcher === "string" && e.matcher.trim() ? e.matcher : ".*";
27211
- const hooksList = Array.isArray(e.hooks) ? e.hooks : [];
27212
- for (const item of hooksList) {
27213
- if (!item || typeof item !== "object") continue;
27214
- const hook = item;
27215
- const command = typeof hook.command === "string" ? hook.command : typeof hook.prompt === "string" ? hook.prompt : "";
27216
- if (!command.trim()) continue;
27217
- const canonical = {
27218
- matcher,
27219
- type: hook.type === "prompt" ? "prompt" : "command",
27220
- command
27221
- };
27222
- if (typeof hook.timeout === "number") canonical.timeout = hook.timeout;
27223
- canonicalEntries.push(canonical);
27224
- }
27414
+ canonicalEntries.push(...legacyEntries(e));
27225
27415
  }
27226
27416
  if (canonicalEntries.length > 0) result2[mappedEvent] = canonicalEntries;
27227
27417
  }
27228
27418
  return result2;
27229
27419
  }
27420
+ var WILDCARD_MATCHER;
27421
+ var init_importer_hooks2 = __esm({
27422
+ "src/targets/windsurf/importer-hooks.ts"() {
27423
+ init_hooks5();
27424
+ init_fs();
27425
+ init_constants34();
27426
+ init_hook_events();
27427
+ WILDCARD_MATCHER = "*";
27428
+ }
27429
+ });
27230
27430
  async function importWindsurfMcp(projectRoot, results) {
27231
27431
  const sourceCandidates = [WINDSURF_MCP_EXAMPLE_FILE, WINDSURF_MCP_CONFIG_FILE];
27232
27432
  for (const relPath of sourceCandidates) {
@@ -27250,8 +27450,8 @@ async function importWindsurfMcp(projectRoot, results) {
27250
27450
  }
27251
27451
  }
27252
27452
  }
27253
- var init_importer_hooks_mcp = __esm({
27254
- "src/targets/windsurf/importer-hooks-mcp.ts"() {
27453
+ var init_importer_mcp = __esm({
27454
+ "src/targets/windsurf/importer-mcp.ts"() {
27255
27455
  init_fs();
27256
27456
  init_constants34();
27257
27457
  }
@@ -27401,7 +27601,8 @@ var init_importer32 = __esm({
27401
27601
  init_constants34();
27402
27602
  init_importer_workflows();
27403
27603
  init_skills_adapter5();
27404
- init_importer_hooks_mcp();
27604
+ init_importer_hooks2();
27605
+ init_importer_mcp();
27405
27606
  }
27406
27607
  });
27407
27608
 
@@ -27486,9 +27687,28 @@ function lintPermissions22(canonical) {
27486
27687
  )
27487
27688
  ];
27488
27689
  }
27690
+ function lintHooks23(canonical) {
27691
+ if (!canonical.hooks) return [];
27692
+ const diagnostics = [];
27693
+ for (const [event, entries] of Object.entries(canonical.hooks)) {
27694
+ for (const entry of entries ?? []) {
27695
+ if (WILDCARD_MATCHERS.has(entry.matcher.trim())) continue;
27696
+ diagnostics.push(
27697
+ createWarning(
27698
+ ".agentsmesh/hooks.yaml",
27699
+ "windsurf",
27700
+ `Windsurf hooks have no matcher field; ${event} hook "${entry.command}" runs on every ${event} event (matcher "${entry.matcher}" is not projected).`
27701
+ )
27702
+ );
27703
+ }
27704
+ }
27705
+ return diagnostics;
27706
+ }
27707
+ var WILDCARD_MATCHERS;
27489
27708
  var init_lint31 = __esm({
27490
27709
  "src/targets/windsurf/lint.ts"() {
27491
27710
  init_helpers();
27711
+ WILDCARD_MATCHERS = /* @__PURE__ */ new Set(["", "*", ".*"]);
27492
27712
  }
27493
27713
  });
27494
27714
 
@@ -27644,6 +27864,7 @@ var init_windsurf2 = __esm({
27644
27864
  lintRules: lintRules32,
27645
27865
  lint: {
27646
27866
  commands: lintCommands10,
27867
+ hooks: lintHooks23,
27647
27868
  mcp: lintMcp13,
27648
27869
  permissions: lintPermissions22
27649
27870
  },