agentsmesh 0.41.0 → 0.42.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/canonical.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { join, basename, dirname, relative, extname, resolve, posix, win32 } from 'path';
2
- import { access, readdir, readFile, rm, mkdir, lstat, open, stat, realpath, rename, writeFile, mkdtemp, cp } from 'fs/promises';
2
+ import { access, readdir, readFile, lstat, rm, mkdir, open, stat, realpath, rename, writeFile, mkdtemp, cp } from 'fs/promises';
3
3
  import { setTimeout } from 'timers/promises';
4
4
  import { randomUUID, createHash } from 'crypto';
5
5
  import { constants, existsSync, readFileSync, realpathSync, statSync } from 'fs';
@@ -422,6 +422,77 @@ var init_fs = __esm({
422
422
  init_rename_retry();
423
423
  }
424
424
  });
425
+
426
+ // src/utils/output/color.ts
427
+ function noColorRequested() {
428
+ const value = process.env.NO_COLOR;
429
+ return value !== void 0 && value !== "";
430
+ }
431
+ function forceColorRequested() {
432
+ const value = process.env.FORCE_COLOR;
433
+ if (value === void 0) return void 0;
434
+ return value !== "0" && value !== "false";
435
+ }
436
+ function colorEnabled(stream = process.stdout) {
437
+ const forced = forceColorRequested();
438
+ if (forced !== void 0) return forced;
439
+ if (noColorRequested()) return false;
440
+ return stream.isTTY === true;
441
+ }
442
+ var init_color = __esm({
443
+ "src/utils/output/color.ts"() {
444
+ }
445
+ });
446
+
447
+ // src/utils/output/logger.ts
448
+ function outStream() {
449
+ return stdoutRedirectedToStderr ? process.stderr : process.stdout;
450
+ }
451
+ function out(text) {
452
+ outStream().write(text);
453
+ }
454
+ function c(code, text, stream) {
455
+ return colorEnabled(stream) ? `${code}${text}${C.reset}` : text;
456
+ }
457
+ var C, muted, stdoutRedirectedToStderr, logger;
458
+ var init_logger = __esm({
459
+ "src/utils/output/logger.ts"() {
460
+ init_color();
461
+ C = {
462
+ green: "\x1B[32m",
463
+ red: "\x1B[31m",
464
+ yellow: "\x1B[33m",
465
+ cyan: "\x1B[36m",
466
+ reset: "\x1B[0m"
467
+ };
468
+ muted = false;
469
+ stdoutRedirectedToStderr = false;
470
+ logger = {
471
+ info(msg) {
472
+ if (muted) return;
473
+ out(c(C.cyan, msg, outStream()) + "\n");
474
+ },
475
+ warn(msg) {
476
+ if (muted) return;
477
+ process.stderr.write(c(C.yellow, "\u26A0 ", process.stderr) + msg + "\n");
478
+ },
479
+ error(msg) {
480
+ if (muted) return;
481
+ process.stderr.write(c(C.red, "\u2717 ", process.stderr) + msg + "\n");
482
+ },
483
+ success(msg) {
484
+ if (muted) return;
485
+ out(c(C.green, "\u2713 ", outStream()) + msg + "\n");
486
+ },
487
+ debug(msg) {
488
+ if (muted) return;
489
+ if (process.env.AGENTSMESH_DEBUG === "1") {
490
+ out(c(C.cyan, "[debug] ", outStream()) + msg + "\n");
491
+ }
492
+ }
493
+ };
494
+ }
495
+ });
425
496
  function parseFrontmatter(content) {
426
497
  const split = splitFrontmatter(content);
427
498
  if (split === null) return { frontmatter: {}, body: content.trim() };
@@ -1575,12 +1646,6 @@ var init_no_outputs = __esm({
1575
1646
  function escapeRegExp(value) {
1576
1647
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1577
1648
  }
1578
- function managedBlockPattern(start, end) {
1579
- return new RegExp(`${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}`, "g");
1580
- }
1581
- function stripManagedBlock(content, start, end) {
1582
- return content.replace(managedBlockPattern(start, end), "").trim();
1583
- }
1584
1649
  function ruleSource(source) {
1585
1650
  const normalized = source.replace(/\\/g, "/");
1586
1651
  const meshIndex = normalized.lastIndexOf(".agentsmesh/");
@@ -1588,36 +1653,22 @@ function ruleSource(source) {
1588
1653
  if (normalized.startsWith("rules/")) return normalized;
1589
1654
  return join("rules", basename(normalized)).replace(/\\/g, "/");
1590
1655
  }
1591
- function markerForRule(rule) {
1592
- return {
1656
+ function renderEmbeddedRule(rule) {
1657
+ const marker = {
1593
1658
  source: ruleSource(rule.source),
1594
1659
  description: rule.description,
1595
1660
  globs: rule.globs,
1596
1661
  targets: rule.targets
1597
1662
  };
1598
- }
1599
- function embeddedRuleStart(rule) {
1600
- return `${EMBEDDED_RULE_START_PREFIX}${JSON.stringify(markerForRule(rule))}${EMBEDDED_RULE_START_SUFFIX}`;
1601
- }
1602
- function renderRule(rule) {
1603
- const parts = [embeddedRuleStart(rule)];
1663
+ const parts = [`${START_PREFIX}${JSON.stringify(marker)}${START_SUFFIX}`];
1604
1664
  if (rule.description.trim()) {
1605
1665
  parts.push(`## ${rule.description.trim()}`, "");
1606
1666
  }
1607
1667
  parts.push(rule.body.trim(), EMBEDDED_RULE_END);
1608
1668
  return parts.filter((part) => part.length > 0).join("\n");
1609
1669
  }
1610
- function renderEmbeddedRulesBlock(rules) {
1611
- if (rules.length === 0) return "";
1612
- return [EMBEDDED_RULES_START, ...rules.map(renderRule), EMBEDDED_RULES_END].join("\n");
1613
- }
1614
- function appendEmbeddedRulesBlock(content, rules) {
1615
- const block = renderEmbeddedRulesBlock(rules);
1616
- const withoutExisting = stripManagedBlock(content, EMBEDDED_RULES_START, EMBEDDED_RULES_END);
1617
- if (!block) return withoutExisting;
1618
- return withoutExisting ? `${withoutExisting}
1619
-
1620
- ${block}` : block;
1670
+ function renderEmbeddedRuleEntries(rules) {
1671
+ return rules.map(renderEmbeddedRule).join("\n\n");
1621
1672
  }
1622
1673
  function toStringArray2(value) {
1623
1674
  return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
@@ -1644,26 +1695,54 @@ function stripGeneratedHeading(body, description) {
1644
1695
  const heading = `## ${description.trim()}`;
1645
1696
  return trimmed.startsWith(heading) ? trimmed.slice(heading.length).trim() : trimmed;
1646
1697
  }
1698
+ function takeEmbeddedRuleEntries(text) {
1699
+ const rules = [];
1700
+ const entry = new RegExp(
1701
+ `${escapeRegExp(START_PREFIX)}([\\s\\S]*?)${escapeRegExp(START_SUFFIX)}([\\s\\S]*?)${escapeRegExp(EMBEDDED_RULE_END)}`,
1702
+ "g"
1703
+ );
1704
+ const rest = text.replace(entry, (whole, markerText, body) => {
1705
+ const marker = parseMarker(markerText);
1706
+ if (!marker) return whole;
1707
+ rules.push({ ...marker, body: stripGeneratedHeading(body, marker.description) });
1708
+ return "";
1709
+ });
1710
+ return { rest: rest.trim(), rules };
1711
+ }
1712
+ var EMBEDDED_RULE_END, START_PREFIX, START_SUFFIX;
1713
+ var init_embedded_rule_entries = __esm({
1714
+ "src/targets/projection/embedded-rule-entries.ts"() {
1715
+ EMBEDDED_RULE_END = "<!-- agentsmesh:embedded-rule:end -->";
1716
+ START_PREFIX = "<!-- agentsmesh:embedded-rule:start ";
1717
+ START_SUFFIX = " -->";
1718
+ }
1719
+ });
1720
+
1721
+ // src/targets/projection/managed-blocks.ts
1722
+ function managedBlockPattern(start, end) {
1723
+ return new RegExp(`${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}`, "g");
1724
+ }
1725
+ function stripManagedBlock(content, start, end) {
1726
+ return content.replace(managedBlockPattern(start, end), "").trim();
1727
+ }
1728
+ function renderEmbeddedRulesBlock(rules) {
1729
+ if (rules.length === 0) return "";
1730
+ return [EMBEDDED_RULES_START, ...rules.map(renderEmbeddedRule), EMBEDDED_RULES_END].join("\n");
1731
+ }
1732
+ function appendEmbeddedRulesBlock(content, rules) {
1733
+ const block = renderEmbeddedRulesBlock(rules);
1734
+ const withoutExisting = stripManagedBlock(content, EMBEDDED_RULES_START, EMBEDDED_RULES_END);
1735
+ if (!block) return withoutExisting;
1736
+ return withoutExisting ? `${withoutExisting}
1737
+
1738
+ ${block}` : block;
1739
+ }
1647
1740
  function extractEmbeddedRules(content) {
1648
1741
  const rules = [];
1649
1742
  const outerPattern = managedBlockPattern(EMBEDDED_RULES_START, EMBEDDED_RULES_END);
1650
1743
  const rootContent = content.replace(outerPattern, (block) => {
1651
- const inner = block.replace(EMBEDDED_RULES_START, "").replace(EMBEDDED_RULES_END, "").trim();
1652
- const entryPattern = new RegExp(
1653
- `${escapeRegExp(EMBEDDED_RULE_START_PREFIX)}([\\s\\S]*?)${escapeRegExp(EMBEDDED_RULE_START_SUFFIX)}([\\s\\S]*?)${escapeRegExp(EMBEDDED_RULE_END)}`,
1654
- "g"
1655
- );
1656
- for (const match of inner.matchAll(entryPattern)) {
1657
- const markerText = match[1];
1658
- const body = match[2];
1659
- if (markerText === void 0 || body === void 0) continue;
1660
- const marker = parseMarker(markerText);
1661
- if (!marker) continue;
1662
- rules.push({
1663
- ...marker,
1664
- body: stripGeneratedHeading(body, marker.description)
1665
- });
1666
- }
1744
+ const inner = block.replace(EMBEDDED_RULES_START, "").replace(EMBEDDED_RULES_END, "");
1745
+ rules.push(...takeEmbeddedRuleEntries(inner).rules);
1667
1746
  return "";
1668
1747
  });
1669
1748
  return { rootContent: rootContent.trim(), rules };
@@ -1676,17 +1755,16 @@ function embeddedRootRule(canonical, target34, rootFile) {
1676
1755
  const content = appendEmbeddedRulesBlock(rootBody, nonRootRules);
1677
1756
  return content ? [{ path: rootFile, content }] : [];
1678
1757
  }
1679
- var ROOT_CONTRACT_START, ROOT_CONTRACT_END, EMBEDDED_RULES_START, EMBEDDED_RULES_END, EMBEDDED_RULE_END, EMBEDDED_RULE_START_PREFIX, EMBEDDED_RULE_START_SUFFIX;
1758
+ var ROOT_CONTRACT_START, ROOT_CONTRACT_END, EMBEDDED_RULES_START, EMBEDDED_RULES_END;
1680
1759
  var init_managed_blocks = __esm({
1681
1760
  "src/targets/projection/managed-blocks.ts"() {
1682
1761
  init_markdown();
1762
+ init_embedded_rule_entries();
1763
+ init_embedded_rule_entries();
1683
1764
  ROOT_CONTRACT_START = "<!-- agentsmesh:root-generation-contract:start -->";
1684
1765
  ROOT_CONTRACT_END = "<!-- agentsmesh:root-generation-contract:end -->";
1685
1766
  EMBEDDED_RULES_START = "<!-- agentsmesh:embedded-rules:start -->";
1686
1767
  EMBEDDED_RULES_END = "<!-- agentsmesh:embedded-rules:end -->";
1687
- EMBEDDED_RULE_END = "<!-- agentsmesh:embedded-rule:end -->";
1688
- EMBEDDED_RULE_START_PREFIX = "<!-- agentsmesh:embedded-rule:start ";
1689
- EMBEDDED_RULE_START_SUFFIX = " -->";
1690
1768
  }
1691
1769
  });
1692
1770
 
@@ -2954,6 +3032,8 @@ function rewriteFileLinks(input) {
2954
3032
  const lineNumSuffix = lineNumMatch ? lineNumMatch[0] : "";
2955
3033
  if (!rawCandidate) return match;
2956
3034
  const tokenContext = getTokenContext(fullContent, offset, offset + rawCandidate.length);
3035
+ if (input.markdownLinksOnly === true && tokenContext.role !== "markdown-link-dest")
3036
+ return match;
2957
3037
  const candidate = decodeLinkPath(rawCandidate, tokenContext.role);
2958
3038
  if (tokenContext.role !== "markdown-link-dest" && WINDOWS_ABSOLUTE_PATH.test(candidate)) {
2959
3039
  return match;
@@ -3128,13 +3208,12 @@ var init_import_rewriter = __esm({
3128
3208
  });
3129
3209
  async function writeMcpWithMerge(projectRoot, canonicalPath, imported) {
3130
3210
  const destPath = join(projectRoot, canonicalPath);
3131
- const existing = await readExistingServers(destPath);
3211
+ const existing = parseMcpServers(await readFileSafe(destPath));
3132
3212
  const merged = { ...existing, ...imported };
3133
3213
  await mkdirp(dirname(destPath));
3134
3214
  await writeFileAtomic(destPath, JSON.stringify({ mcpServers: merged }, null, 2));
3135
3215
  }
3136
- async function readExistingServers(path) {
3137
- const content = await readFileSafe(path);
3216
+ function parseMcpServers(content) {
3138
3217
  if (content === null) return {};
3139
3218
  let parsed;
3140
3219
  try {
@@ -7093,12 +7172,14 @@ function canonicalRulePath(source) {
7093
7172
  }
7094
7173
  async function splitEmbeddedRulesToCanonical(input) {
7095
7174
  const extracted = extractEmbeddedRules(input.content);
7175
+ const results = await writeEmbeddedRules(extracted.rules, input);
7176
+ return { rootContent: extracted.rootContent, results };
7177
+ }
7178
+ async function writeEmbeddedRules(rules, input) {
7096
7179
  const results = [];
7097
- if (extracted.rules.length === 0) {
7098
- return { rootContent: extracted.rootContent, results };
7099
- }
7180
+ if (rules.length === 0) return results;
7100
7181
  await mkdirp(join(input.projectRoot, input.rulesDir));
7101
- for (const rule of extracted.rules) {
7182
+ for (const rule of rules) {
7102
7183
  const canonicalSource = canonicalRulePath(rule.source);
7103
7184
  if (canonicalSource === null || canonicalSource === "rules/_root.md") continue;
7104
7185
  const destPath = join(input.projectRoot, ".agentsmesh", canonicalSource);
@@ -7108,6 +7189,7 @@ async function splitEmbeddedRulesToCanonical(input) {
7108
7189
  destPath,
7109
7190
  {
7110
7191
  ...frontmatter,
7192
+ ...input.frontmatter,
7111
7193
  root: false,
7112
7194
  description: rule.description || void 0,
7113
7195
  globs: rule.globs.length > 0 ? rule.globs : void 0,
@@ -7123,13 +7205,19 @@ async function splitEmbeddedRulesToCanonical(input) {
7123
7205
  feature: "rules"
7124
7206
  });
7125
7207
  }
7126
- return { rootContent: extracted.rootContent, results };
7208
+ return results;
7209
+ }
7210
+ async function splitNestedAgentsFile(input, into) {
7211
+ const { rest, rules } = takeEmbeddedRuleEntries(input.content);
7212
+ into.push(...await writeEmbeddedRules(rules, input));
7213
+ return rest.length > 0 ? rest : null;
7127
7214
  }
7128
7215
  var init_embedded_rules = __esm({
7129
7216
  "src/targets/import/embedded-rules.ts"() {
7130
7217
  init_fs();
7131
7218
  init_markdown();
7132
7219
  init_managed_blocks();
7220
+ init_embedded_rule_entries();
7133
7221
  init_import_metadata();
7134
7222
  }
7135
7223
  });
@@ -8426,7 +8514,7 @@ function generateRules6(canonical) {
8426
8514
  const slug = basename(rule.source, ".md");
8427
8515
  const frontmatter = {};
8428
8516
  if (rule.description) frontmatter.description = rule.description;
8429
- if (rule.globs.length > 0) frontmatter.globs = rule.globs;
8517
+ if (rule.globs.length > 0) frontmatter.paths = rule.globs;
8430
8518
  const content = serializeFrontmatter(frontmatter, rule.body.trim() || "");
8431
8519
  outputs.push({ path: `${CLAUDE_RULES_DIR}/${slug}.md`, content });
8432
8520
  }
@@ -8808,12 +8896,14 @@ var init_import_mappers2 = __esm({
8808
8896
  }) => {
8809
8897
  const destPath = join(destDir, relativePath);
8810
8898
  const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
8899
+ const { paths: paths2, ...rest } = frontmatter;
8900
+ const scoped = paths2 === void 0 ? {} : { globs: toToolsArray2(paths2) };
8811
8901
  return {
8812
8902
  destPath,
8813
8903
  toPath: `${AB_RULES}/${relativePath}`,
8814
8904
  content: await serializeImportedRuleWithFallback(
8815
8905
  destPath,
8816
- { ...frontmatter, root: false },
8906
+ { ...rest, ...scoped, root: false },
8817
8907
  body
8818
8908
  )
8819
8909
  };
@@ -10318,7 +10408,7 @@ function generateRules8(canonical) {
10318
10408
  const rootBody = canonical.rules.find((rule) => rule.root)?.body.trim() ?? "";
10319
10409
  if (rootBody) outputs.push({ path: CODEBUFF_ROOT_FILE, content: rootBody });
10320
10410
  for (const [path, rules] of groupByNestedPath(eligibleRules(canonical))) {
10321
- const content = rules.map((rule) => rule.body.trim()).filter((body) => body.length > 0).join("\n\n");
10411
+ const content = renderEmbeddedRuleEntries(rules.filter((rule) => rule.body.trim().length > 0));
10322
10412
  if (content) outputs.push({ path, content });
10323
10413
  }
10324
10414
  return outputs;
@@ -10346,6 +10436,7 @@ var init_generator8 = __esm({
10346
10436
  init_no_outputs();
10347
10437
  init_embedded_skill();
10348
10438
  init_managed_blocks();
10439
+ init_embedded_rule_entries();
10349
10440
  init_command_skill();
10350
10441
  init_nested_rules();
10351
10442
  init_mcp_format2();
@@ -10395,33 +10486,47 @@ function isVendored(relDir) {
10395
10486
  }
10396
10487
  async function importNestedRules(projectRoot, normalize) {
10397
10488
  const destDir = join(projectRoot, AB_RULES);
10398
- return importFileDirectory({
10489
+ const embedded = [];
10490
+ const results = await importFileDirectory({
10399
10491
  srcDir: projectRoot,
10400
10492
  destDir,
10401
10493
  extensions: [CODEBUFF_ROOT_FILE],
10402
10494
  fromTool: CODEBUFF_TARGET,
10403
10495
  normalize,
10404
- mapEntry: ({ srcPath, normalizeTo }) => {
10496
+ mapEntry: async ({ srcPath, content, normalizeTo }) => {
10405
10497
  if (basename(srcPath) !== CODEBUFF_ROOT_FILE) return null;
10406
10498
  const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
10407
10499
  if (!relDir || relDir === ".") return null;
10408
10500
  if (!shouldImportScopedAgentsRule(relDir)) return null;
10409
10501
  if (isVendored(relDir)) return null;
10502
+ const ownText = await splitNestedAgentsFile(
10503
+ {
10504
+ content,
10505
+ projectRoot,
10506
+ rulesDir: AB_RULES,
10507
+ sourcePath: srcPath,
10508
+ fromTool: CODEBUFF_TARGET,
10509
+ normalize
10510
+ },
10511
+ embedded
10512
+ );
10513
+ if (ownText === null) return null;
10410
10514
  const ruleName2 = relDir.replace(/\//g, "-");
10411
10515
  const destPath = join(destDir, `${ruleName2}.md`);
10412
- const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
10413
- return serializeImportedRuleWithFallback(
10414
- destPath,
10415
- { ...frontmatter, root: false, globs: [`${relDir}/**`] },
10416
- body
10417
- ).then((content) => ({
10516
+ const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath, ownText));
10517
+ return {
10418
10518
  destPath,
10419
10519
  toPath: `${AB_RULES}/${ruleName2}.md`,
10420
10520
  feature: "rules",
10421
- content
10422
- }));
10521
+ content: await serializeImportedRuleWithFallback(
10522
+ destPath,
10523
+ { ...frontmatter, root: false, globs: [`${relDir}/**`] },
10524
+ body
10525
+ )
10526
+ };
10423
10527
  }
10424
10528
  });
10529
+ return [...results, ...embedded];
10425
10530
  }
10426
10531
  async function importCodebuffRules(projectRoot, scope, normalize) {
10427
10532
  const results = await importRootRule2(projectRoot, scope, normalize);
@@ -10854,7 +10959,7 @@ function generateRules9(canonical) {
10854
10959
  }
10855
10960
  const nested = advisory.filter((rule) => !isRootEmbedded(rule));
10856
10961
  for (const [path, rules] of groupByNestedPath2(nested)) {
10857
- const content = rules.map((rule) => rule.body.trim()).filter((body) => body.length > 0).join("\n\n");
10962
+ const content = renderEmbeddedRuleEntries(rules.filter((rule) => rule.body.trim().length > 0));
10858
10963
  outputs.push({ path, content });
10859
10964
  }
10860
10965
  return outputs;
@@ -10867,6 +10972,7 @@ function renderCodexGlobalInstructions(canonical) {
10867
10972
  var init_rules = __esm({
10868
10973
  "src/targets/codex-cli/generator/rules.ts"() {
10869
10974
  init_managed_blocks();
10975
+ init_embedded_rule_entries();
10870
10976
  init_constants10();
10871
10977
  init_codex_rule_paths();
10872
10978
  }
@@ -11496,6 +11602,7 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
11496
11602
  await importInstructionMirrors(projectRoot, destDir, results, normalize);
11497
11603
  results.push(...await importCodexNonRootRuleFiles(projectRoot, destDir, normalize));
11498
11604
  if (layoutScope !== "global") {
11605
+ const embedded = [];
11499
11606
  results.push(
11500
11607
  ...await importFileDirectory({
11501
11608
  srcDir: projectRoot,
@@ -11503,7 +11610,7 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
11503
11610
  extensions: ["AGENTS.md", "AGENTS.override.md"],
11504
11611
  fromTool: "codex-cli",
11505
11612
  normalize,
11506
- mapEntry: async ({ srcPath, normalizeTo }) => {
11613
+ mapEntry: async ({ srcPath, content: content2, normalizeTo }) => {
11507
11614
  const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
11508
11615
  const fileName = basename(srcPath);
11509
11616
  const isOverride = fileName === "AGENTS.override.md";
@@ -11514,26 +11621,36 @@ async function importCodexRules(projectRoot, results, normalize, normalizeWindsu
11514
11621
  await removePathIfExists(join(destDir, `${ruleName2}.md`));
11515
11622
  return null;
11516
11623
  }
11624
+ const variant = isOverride ? { codex_instruction: "override" } : {};
11625
+ const ownText = await splitNestedAgentsFile(
11626
+ {
11627
+ content: content2,
11628
+ projectRoot,
11629
+ rulesDir: AB_RULES,
11630
+ sourcePath: srcPath,
11631
+ fromTool: "codex-cli",
11632
+ normalize,
11633
+ frontmatter: variant
11634
+ },
11635
+ embedded
11636
+ );
11637
+ if (ownText === null) return null;
11517
11638
  const destPath = join(destDir, `${ruleName2}.md`);
11518
- const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
11639
+ const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath, ownText));
11519
11640
  return {
11520
11641
  destPath,
11521
11642
  toPath: `${AB_RULES}/${ruleName2}.md`,
11522
11643
  feature: "rules",
11523
11644
  content: await serializeImportedRuleWithFallback(
11524
11645
  destPath,
11525
- {
11526
- ...frontmatter,
11527
- root: false,
11528
- globs: [`${relDir}/**`],
11529
- ...isOverride ? { codex_instruction: "override" } : {}
11530
- },
11646
+ { ...frontmatter, root: false, globs: [`${relDir}/**`], ...variant },
11531
11647
  body
11532
11648
  )
11533
11649
  };
11534
11650
  }
11535
11651
  })
11536
11652
  );
11653
+ results.push(...embedded);
11537
11654
  }
11538
11655
  }
11539
11656
  async function importInstructionMirrors(projectRoot, destDir, results, normalize) {
@@ -18157,7 +18274,7 @@ function parseExtensions(content) {
18157
18274
  }
18158
18275
  return out2;
18159
18276
  }
18160
- async function readExistingServers2(destPath) {
18277
+ async function readExistingServers(destPath) {
18161
18278
  const content = await readFileSafe(destPath);
18162
18279
  if (content === null) return {};
18163
18280
  let parsed;
@@ -18180,7 +18297,7 @@ async function gooseMcpMap(ctx) {
18180
18297
  const imported = ctx.relativePath.endsWith(".mcp.json") ? parsePluginMcpJson(ctx.content) : parseExtensions(ctx.content);
18181
18298
  if (Object.keys(imported).length === 0) return null;
18182
18299
  const destPath = join(ctx.destDir, "mcp.json");
18183
- const existing = await readExistingServers2(destPath);
18300
+ const existing = await readExistingServers(destPath);
18184
18301
  const merged = { ...existing, ...imported };
18185
18302
  return {
18186
18303
  destPath,
@@ -26735,12 +26852,6 @@ function ruleSlug4(source) {
26735
26852
  const name = basename(source, ".md");
26736
26853
  return name === "_root" ? "root" : name;
26737
26854
  }
26738
- function directoryScopedRuleDir(globs) {
26739
- if (globs.length === 0) return null;
26740
- const dirs = globs.map((glob) => glob.split("/")[0] ?? "").filter((segment) => /^[A-Za-z0-9._-]+$/.test(segment));
26741
- if (dirs.length !== globs.length) return null;
26742
- return dirs.every((dir) => dir === dirs[0]) ? dirs[0] : null;
26743
- }
26744
26855
  function generateRules32(canonical) {
26745
26856
  const outputs = [];
26746
26857
  const root = canonical.rules.find((r) => r.root);
@@ -26757,21 +26868,14 @@ function generateRules32(canonical) {
26757
26868
  const frontmatter = {
26758
26869
  description: rule.description || void 0,
26759
26870
  trigger: normalizedTrigger,
26760
- glob: rule.globs.length === 1 ? rule.globs[0] : void 0,
26761
- globs: rule.globs.length > 1 ? rule.globs : void 0
26871
+ // Windsurf reads `globs` as one comma-joined string; it ignores `glob`.
26872
+ globs: rule.globs.length > 0 ? rule.globs.join(",") : void 0
26762
26873
  };
26763
26874
  Object.keys(frontmatter).forEach((k) => {
26764
26875
  if (frontmatter[k] === void 0) delete frontmatter[k];
26765
26876
  });
26766
26877
  const content = Object.keys(frontmatter).length > 0 ? serializeFrontmatter(frontmatter, rule.body.trim() || "") : rule.body.trim() || "";
26767
26878
  outputs.push({ path: `${WINDSURF_RULES_DIR}/${slug}.md`, content });
26768
- const dir = directoryScopedRuleDir(rule.globs);
26769
- if (dir) {
26770
- if (dir !== slug) {
26771
- outputs.push({ path: `${WINDSURF_RULES_DIR}/${dir}.md`, content });
26772
- }
26773
- outputs.push({ path: `${dir}/AGENTS.md`, content: rule.body.trim() || "" });
26774
- }
26775
26879
  }
26776
26880
  return outputs;
26777
26881
  }
@@ -26971,6 +27075,114 @@ var init_generator36 = __esm({
26971
27075
  init_generator35();
26972
27076
  }
26973
27077
  });
27078
+
27079
+ // src/targets/windsurf/rule-globs.ts
27080
+ function splitTopLevelCommas(value) {
27081
+ const parts = [];
27082
+ let depth = 0;
27083
+ let current = "";
27084
+ for (const char of value) {
27085
+ if (char === "{") depth++;
27086
+ else if (char === "}") depth = Math.max(0, depth - 1);
27087
+ if (char === "," && depth === 0) {
27088
+ parts.push(current);
27089
+ current = "";
27090
+ } else {
27091
+ current += char;
27092
+ }
27093
+ }
27094
+ parts.push(current);
27095
+ return parts.map((part) => part.trim()).filter(Boolean);
27096
+ }
27097
+ function parseWindsurfGlobs(value) {
27098
+ if (typeof value === "string") return splitTopLevelCommas(value);
27099
+ return Array.isArray(value) ? toToolsArray2(value) : [];
27100
+ }
27101
+ function quoteWindsurfGlobValues(content) {
27102
+ const lines = content.split("\n");
27103
+ if (lines[0]?.trim() !== "---") return content;
27104
+ for (let i = 1; i < lines.length; i++) {
27105
+ if (lines[i].trim() === "---") break;
27106
+ const match = UNQUOTED_GLOBS_LINE.exec(lines[i]);
27107
+ if (match !== null) lines[i] = `${match[1]}${JSON.stringify(match[2])}${match[3]}`;
27108
+ }
27109
+ return lines.join("\n");
27110
+ }
27111
+ var UNQUOTED_GLOBS_LINE;
27112
+ var init_rule_globs = __esm({
27113
+ "src/targets/windsurf/rule-globs.ts"() {
27114
+ init_shared_import_helpers();
27115
+ UNQUOTED_GLOBS_LINE = /^(\s*globs?\s*:[ \t]*)([^\s"'[{|>#][^\r\n]*?)[ \t]*(\r?)$/;
27116
+ }
27117
+ });
27118
+ async function windsurfRuleBodies(projectRoot) {
27119
+ const files = await readDirRecursiveNoSymlinks(join(projectRoot, WINDSURF_RULES_DIR));
27120
+ const bodies = /* @__PURE__ */ new Set();
27121
+ for (const file of files.filter((path) => path.endsWith(".md"))) {
27122
+ const content = await readFileSafe(file);
27123
+ if (content !== null) bodies.add(bodyKey(splitFrontmatter(content)?.body ?? content));
27124
+ }
27125
+ return bodies;
27126
+ }
27127
+ async function importWindsurfNestedAgents(projectRoot, normalize) {
27128
+ const destRulesDir = join(projectRoot, AB_RULES);
27129
+ const embedded = [];
27130
+ const ruleBodies = await windsurfRuleBodies(projectRoot);
27131
+ const results = await importFileDirectory({
27132
+ srcDir: projectRoot,
27133
+ destDir: destRulesDir,
27134
+ extensions: ["AGENTS.md"],
27135
+ fromTool: "windsurf",
27136
+ normalize,
27137
+ mapEntry: async ({ srcPath, content, normalizeTo }) => {
27138
+ const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
27139
+ if (!relDir || relDir === "." || basename(srcPath) !== "AGENTS.md") return null;
27140
+ const ruleName2 = relDir.replace(/\//g, "-");
27141
+ if (!shouldImportScopedAgentsRule(relDir)) {
27142
+ await removePathIfExists(join(destRulesDir, `${ruleName2}.md`));
27143
+ return null;
27144
+ }
27145
+ const ownText = await splitNestedAgentsFile(
27146
+ {
27147
+ content,
27148
+ projectRoot,
27149
+ rulesDir: AB_RULES,
27150
+ sourcePath: srcPath,
27151
+ fromTool: "windsurf",
27152
+ normalize
27153
+ },
27154
+ embedded
27155
+ );
27156
+ if (ownText === null || ruleBodies.has(bodyKey(ownText))) return null;
27157
+ const destPath = join(destRulesDir, `${ruleName2}.md`);
27158
+ return {
27159
+ destPath,
27160
+ toPath: `${AB_RULES}/${ruleName2}.md`,
27161
+ feature: "rules",
27162
+ content: await serializeImportedRuleWithFallback(
27163
+ destPath,
27164
+ { root: false, globs: [`${relDir}/**`] },
27165
+ normalizeTo(destPath, ownText)
27166
+ )
27167
+ };
27168
+ }
27169
+ });
27170
+ return [...results, ...embedded];
27171
+ }
27172
+ var bodyKey;
27173
+ var init_import_nested_agents = __esm({
27174
+ "src/targets/windsurf/import-nested-agents.ts"() {
27175
+ init_canonical_paths();
27176
+ init_embedded_rules();
27177
+ init_import_metadata();
27178
+ init_import_orchestrator();
27179
+ init_scoped_agents_import();
27180
+ init_fs();
27181
+ init_markdown();
27182
+ init_constants34();
27183
+ bodyKey = (text) => text.replace(/\r\n?/g, "\n").trim();
27184
+ }
27185
+ });
26974
27186
  function toStringArray3(value) {
26975
27187
  if (Array.isArray(value)) {
26976
27188
  return value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
@@ -27188,35 +27400,7 @@ async function importFromWindsurf(projectRoot, options) {
27188
27400
  }
27189
27401
  }
27190
27402
  if (layoutScope !== "global") {
27191
- results.push(
27192
- ...await importFileDirectory({
27193
- srcDir: projectRoot,
27194
- destDir: destRulesDir,
27195
- extensions: ["AGENTS.md"],
27196
- fromTool: "windsurf",
27197
- normalize,
27198
- mapEntry: async ({ srcPath, normalizeTo }) => {
27199
- const relDir = relative(projectRoot, dirname(srcPath)).replace(/\\/g, "/");
27200
- if (!relDir || relDir === "." || basename(srcPath) !== "AGENTS.md") return null;
27201
- const ruleName2 = relDir.replace(/\//g, "-");
27202
- if (!shouldImportScopedAgentsRule(relDir)) {
27203
- await removePathIfExists(join(destRulesDir, `${ruleName2}.md`));
27204
- return null;
27205
- }
27206
- const destPath = join(destRulesDir, `${ruleName2}.md`);
27207
- return {
27208
- destPath,
27209
- toPath: `${AB_RULES}/${ruleName2}.md`,
27210
- feature: "rules",
27211
- content: await serializeImportedRuleWithFallback(
27212
- destPath,
27213
- { root: false, globs: [`${relDir}/**`] },
27214
- normalizeTo(destPath)
27215
- )
27216
- };
27217
- }
27218
- })
27219
- );
27403
+ results.push(...await importWindsurfNestedAgents(projectRoot, normalize));
27220
27404
  }
27221
27405
  const rulesDir = join(projectRoot, WINDSURF_RULES_DIR);
27222
27406
  results.push(
@@ -27226,15 +27410,22 @@ async function importFromWindsurf(projectRoot, options) {
27226
27410
  extensions: [".md"],
27227
27411
  fromTool: "windsurf",
27228
27412
  normalize,
27229
- mapEntry: async ({ relativePath, normalizeTo }) => {
27413
+ mapEntry: async ({ relativePath, content, normalizeTo }) => {
27230
27414
  if (relativePath === "_root.md" && rootContent !== null) return null;
27231
27415
  const destPath = join(destRulesDir, relativePath);
27232
- const { frontmatter, body } = parseFrontmatter(normalizeTo(destPath));
27233
- const normalizedFrontmatter = { ...frontmatter };
27234
- if (typeof normalizedFrontmatter.glob === "string" && normalizedFrontmatter.glob.trim()) {
27235
- normalizedFrontmatter.globs = [normalizedFrontmatter.glob];
27236
- delete normalizedFrontmatter.glob;
27416
+ const sourceLabel = `${WINDSURF_RULES_DIR}/${relativePath}`;
27417
+ const parsed = tryParseFrontmatter(
27418
+ normalizeTo(destPath, quoteWindsurfGlobValues(content)),
27419
+ sourceLabel
27420
+ );
27421
+ if (!parsed.ok) {
27422
+ logger.warn(`Skipping ${sourceLabel}: ${parsed.error.message}`);
27423
+ return null;
27237
27424
  }
27425
+ const { frontmatter, body } = parsed.value;
27426
+ const { glob, ...normalizedFrontmatter } = frontmatter;
27427
+ const globs = parseWindsurfGlobs(frontmatter.globs ?? glob);
27428
+ if (globs.length > 0) normalizedFrontmatter.globs = globs;
27238
27429
  return {
27239
27430
  destPath,
27240
27431
  toPath: `${AB_RULES}/${relativePath}`,
@@ -27285,9 +27476,11 @@ var init_importer32 = __esm({
27285
27476
  init_import_rewriter();
27286
27477
  init_fs();
27287
27478
  init_markdown();
27479
+ init_logger();
27480
+ init_rule_globs();
27288
27481
  init_import_metadata();
27289
27482
  init_import_orchestrator();
27290
- init_scoped_agents_import();
27483
+ init_import_nested_agents();
27291
27484
  init_constants34();
27292
27485
  init_importer_workflows();
27293
27486
  init_skills_adapter5();
@@ -27392,12 +27585,6 @@ var init_lint31 = __esm({
27392
27585
  });
27393
27586
 
27394
27587
  // src/targets/windsurf/index.ts
27395
- function directoryScopedRuleDir2(globs) {
27396
- if (globs.length === 0) return null;
27397
- const dirs = globs.map((glob) => glob.split("/")[0] ?? "").filter((segment) => /^[A-Za-z0-9._-]+$/.test(segment));
27398
- if (dirs.length !== globs.length) return null;
27399
- return dirs.every((dir) => dir === dirs[0]) ? dirs[0] : null;
27400
- }
27401
27588
  var target32, project24, globalLayout30, globalCapabilities25, descriptor32;
27402
27589
  var init_windsurf2 = __esm({
27403
27590
  "src/targets/windsurf/index.ts"() {
@@ -27429,9 +27616,7 @@ var init_windsurf2 = __esm({
27429
27616
  project24 = {
27430
27617
  rootInstructionPath: WINDSURF_AGENTS_MD,
27431
27618
  extraRuleOutputPaths(rule) {
27432
- if (rule.root) return [WINDSURF_AGENTS_MD];
27433
- const dir = directoryScopedRuleDir2(rule.globs);
27434
- return dir !== null ? [`${dir}/AGENTS.md`] : [];
27619
+ return rule.root ? [WINDSURF_AGENTS_MD] : [];
27435
27620
  },
27436
27621
  skillDir: WINDSURF_SKILLS_DIR,
27437
27622
  managedOutputs: {
@@ -29243,61 +29428,8 @@ async function resolveExtendPaths(config, configDir, options = {}) {
29243
29428
  return result2;
29244
29429
  }
29245
29430
 
29246
- // src/utils/output/color.ts
29247
- function noColorRequested() {
29248
- const value = process.env.NO_COLOR;
29249
- return value !== void 0 && value !== "";
29250
- }
29251
- function forceColorRequested() {
29252
- const value = process.env.FORCE_COLOR;
29253
- if (value === void 0) return void 0;
29254
- return value !== "0" && value !== "false";
29255
- }
29256
- function colorEnabled(stream = process.stdout) {
29257
- const forced = forceColorRequested();
29258
- if (forced !== void 0) return forced;
29259
- if (noColorRequested()) return false;
29260
- return stream.isTTY === true;
29261
- }
29262
-
29263
- // src/utils/output/logger.ts
29264
- var C = {
29265
- green: "\x1B[32m",
29266
- red: "\x1B[31m",
29267
- yellow: "\x1B[33m",
29268
- cyan: "\x1B[36m",
29269
- reset: "\x1B[0m"
29270
- };
29271
- function outStream() {
29272
- return process.stdout;
29273
- }
29274
- function out(text) {
29275
- outStream().write(text);
29276
- }
29277
- function c(code, text, stream) {
29278
- return colorEnabled(stream) ? `${code}${text}${C.reset}` : text;
29279
- }
29280
- var logger = {
29281
- info(msg) {
29282
- out(c(C.cyan, msg, outStream()) + "\n");
29283
- },
29284
- warn(msg) {
29285
- process.stderr.write(c(C.yellow, "\u26A0 ", process.stderr) + msg + "\n");
29286
- },
29287
- error(msg) {
29288
- process.stderr.write(c(C.red, "\u2717 ", process.stderr) + msg + "\n");
29289
- },
29290
- success(msg) {
29291
- out(c(C.green, "\u2713 ", outStream()) + msg + "\n");
29292
- },
29293
- debug(msg) {
29294
- if (process.env.AGENTSMESH_DEBUG === "1") {
29295
- out(c(C.cyan, "[debug] ", outStream()) + msg + "\n");
29296
- }
29297
- }
29298
- };
29299
-
29300
29431
  // src/canonical/features/empty-file.ts
29432
+ init_logger();
29301
29433
  function isEmptyCanonicalFile(content, path) {
29302
29434
  if (content.trim() !== "") return false;
29303
29435
  logger.warn(`Skipping empty canonical file ${path.replaceAll("\\", "/")}`);
@@ -29399,6 +29531,9 @@ function assertNoBasenameCollisions(feature, paths2, stripExt) {
29399
29531
  seen.set(key, { path: p, slug });
29400
29532
  }
29401
29533
  }
29534
+
29535
+ // src/canonical/features/unrecognized-files-warning.ts
29536
+ init_logger();
29402
29537
  var ALTERNATE_RESOURCE_FORMATS = /* @__PURE__ */ new Set([".toml", ".yaml", ".yml", ".json"]);
29403
29538
  function warnIfUnrecognizedResourceFormats(featureLabel, dir, allFiles, parsedFiles, opts = {}) {
29404
29539
  if (allFiles.length === 0) return;
@@ -29607,6 +29742,14 @@ async function readContent(path) {
29607
29742
  return c2 ?? "";
29608
29743
  }
29609
29744
  var SKILL_FILE = "SKILL.md";
29745
+ async function readSkillFile(skillPath) {
29746
+ try {
29747
+ if ((await lstat(skillPath)).isSymbolicLink()) return null;
29748
+ } catch {
29749
+ return null;
29750
+ }
29751
+ return readFileSafe(skillPath);
29752
+ }
29610
29753
  var DOC_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".mdx", ".rst", ".txt"]);
29611
29754
  function isMarkdownLikeDoc(name) {
29612
29755
  const dot = name.lastIndexOf(".");
@@ -29636,7 +29779,7 @@ async function listSupportingFiles(skillDir) {
29636
29779
  }
29637
29780
  async function parseSkillDirectory(skillDir, opts = {}) {
29638
29781
  const skillPath = join(skillDir, SKILL_FILE);
29639
- const content = await readFileSafe(skillPath);
29782
+ const content = await readSkillFile(skillPath);
29640
29783
  if (!content) return null;
29641
29784
  const parsed = parseOrSkipFrontmatter(content, skillPath, opts.onParseError);
29642
29785
  if (!parsed) return null;
@@ -29667,7 +29810,7 @@ async function parseSkills(skillsDir, opts = {}) {
29667
29810
  assertCanonicalName("skill", ent.name);
29668
29811
  const skillDir = join(skillsDir, ent.name);
29669
29812
  const skillPath = join(skillDir, SKILL_FILE);
29670
- const content = await readFileSafe(skillPath);
29813
+ const content = await readSkillFile(skillPath);
29671
29814
  if (!content) continue;
29672
29815
  const parsed = parseOrSkipFrontmatter(content, skillPath, opts.onParseError);
29673
29816
  if (!parsed) continue;
@@ -29697,6 +29840,9 @@ function ensureStringArray(val) {
29697
29840
  async function parsePermissions(permissionsPath, onParseError) {
29698
29841
  const content = await readFileSafe(permissionsPath);
29699
29842
  if (content === null) return null;
29843
+ return parsePermissionsContent(content, permissionsPath, onParseError);
29844
+ }
29845
+ function parsePermissionsContent(content, permissionsPath, onParseError) {
29700
29846
  if (!content.trim()) return { allow: [], deny: [], ask: [] };
29701
29847
  let parsed;
29702
29848
  try {
@@ -29829,6 +29975,20 @@ function hookEvents(a, b) {
29829
29975
  function hookKey(entry) {
29830
29976
  return JSON.stringify([entry.type ?? "command", entry.matcher, entry.command]);
29831
29977
  }
29978
+ function settleRootRule(merged, local, packs) {
29979
+ const roots = merged.filter((rule) => rule.root);
29980
+ const root = roots.find((rule) => local.includes(rule)) ?? roots.find((rule) => packs.includes(rule)) ?? roots[0];
29981
+ const demoted = roots.filter((rule) => rule !== root);
29982
+ return {
29983
+ rules: merged.map((rule) => demoted.includes(rule) ? { ...rule, root: false } : rule),
29984
+ root,
29985
+ demoted
29986
+ };
29987
+ }
29988
+ function demotedRootMessage(rule, root, baseDir) {
29989
+ const shown = (r) => relative(baseDir, r.source).replaceAll("\\", "/");
29990
+ return `[agentsmesh] Rule "${shown(rule)}" also says root: true, but "${shown(root)}" is the root rule (the project's own root wins over installed packs, and packs over extends), so it is used as a normal rule.`;
29991
+ }
29832
29992
 
29833
29993
  // src/config/resolve/native-format-detector.ts
29834
29994
  init_fs();
@@ -29874,6 +30034,7 @@ var KNOWN_NATIVE_PATHS = BUILTIN_TARGETS.map(
29874
30034
 
29875
30035
  // src/canonical/extends/extend-load.ts
29876
30036
  init_fs();
30037
+ init_logger();
29877
30038
 
29878
30039
  // src/canonical/extends/native-extends-importer.ts
29879
30040
  init_registry();
@@ -30500,6 +30661,9 @@ Expected one of: .agentsmesh/, ${KNOWN_NATIVE_PATHS.join(", ")}.`
30500
30661
  throw wrapped;
30501
30662
  }
30502
30663
  }
30664
+
30665
+ // src/canonical/extends/extend-pick.ts
30666
+ init_logger();
30503
30667
  function applyExtendPick(canonical, features, pick, extendName) {
30504
30668
  if (!pick) return canonical;
30505
30669
  let next = { ...canonical };
@@ -30775,6 +30939,7 @@ async function loadPacksCanonical(abDir) {
30775
30939
  }
30776
30940
 
30777
30941
  // src/canonical/extends/extends.ts
30942
+ init_logger();
30778
30943
  var FEATURE_TO_KEYS = {
30779
30944
  rules: ["rules"],
30780
30945
  commands: ["commands"],
@@ -30823,12 +30988,22 @@ async function loadCanonicalWithExtends(config, configDir, options = {}, canonic
30823
30988
  merged = mergeCanonicalFiles(merged, packsCanonical, { hooks: "combine" });
30824
30989
  const localCanonical = await loadCanonicalFiles(canonicalDir);
30825
30990
  merged = mergeCanonicalFiles(merged, localCanonical);
30991
+ const { rules, root, demoted } = settleRootRule(
30992
+ merged.rules,
30993
+ localCanonical.rules,
30994
+ packsCanonical.rules
30995
+ );
30996
+ if (root !== void 0) {
30997
+ for (const rule of demoted) logger.warn(demotedRootMessage(rule, root, configDir));
30998
+ }
30999
+ merged = { ...merged, rules };
30826
31000
  merged = { ...merged, hooks: combineHooks(merged.hooks, packsCanonical.hooks) };
30827
31001
  return { canonical: merged, resolvedExtends };
30828
31002
  }
30829
31003
 
30830
31004
  // src/config/core/loader.ts
30831
31005
  init_fs();
31006
+ init_logger();
30832
31007
  init_errors();
30833
31008
  var CONFIG_FILENAME = "agentsmesh.yaml";
30834
31009
  var LOCAL_CONFIG_FILENAME = "agentsmesh.local.yaml";