agentsmesh 0.36.0 → 0.37.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/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { z } from 'zod';
2
2
  import { stringify, parse, parseDocument, YAMLSeq, YAMLMap, isMap, Document, isSeq, isScalar, Scalar, Pair } from 'yaml';
3
3
  import { readFileSync, existsSync, mkdirSync, writeFileSync, constants, rmSync, renameSync, readdirSync, realpathSync, statSync } from 'fs';
4
- import { join, resolve, relative, sep, dirname, basename, win32, posix, extname } from 'path';
5
- import { mkdir, access, readdir, rm, readFile, writeFile, stat, lstat, unlink, rename, chmod, realpath, mkdtemp, cp } from 'fs/promises';
4
+ import { join, resolve, relative, sep, dirname, basename, extname, win32, posix } from 'path';
5
+ import { mkdir, access, readdir, rm, readFile, writeFile, stat, lstat, open, realpath, rename, mkdtemp, cp } from 'fs/promises';
6
6
  import { setTimeout as setTimeout$1 } from 'timers/promises';
7
+ import { createHash, randomUUID } from 'crypto';
7
8
  import { parse as parse$1, stringify as stringify$1 } from 'smol-toml';
8
9
  import { Buffer } from 'buffer';
9
10
  import { homedir, hostname, tmpdir } from 'os';
10
- import { createHash } from 'crypto';
11
11
  import { execFile } from 'child_process';
12
12
  import { fileURLToPath, pathToFileURL, URL as URL$1 } from 'url';
13
13
  import { promisify } from 'util';
@@ -894,6 +894,12 @@ function shouldNormalizeLineEndings(path) {
894
894
  const base = basename(path).toLowerCase();
895
895
  return TEXT_DOTFILES.has(base);
896
896
  }
897
+ function isBinaryPayloadPath(path) {
898
+ return BINARY_EXTENSIONS.has(extname(path).toLowerCase());
899
+ }
900
+ function payloadEncodingFor(path) {
901
+ return isBinaryPayloadPath(path) ? "latin1" : "utf-8";
902
+ }
897
903
  function normalizeLineEndings(content) {
898
904
  return content.replace(/\r\n?/g, "\n");
899
905
  }
@@ -905,7 +911,7 @@ function normalizeTextPayload(path, content) {
905
911
  const withoutBom = content.startsWith(UTF8_BOM) ? content.slice(UTF8_BOM.length) : content;
906
912
  return normalizeLineEndings(withoutBom);
907
913
  }
908
- var UTF8_BOM, TEXT_EXTENSIONS, TEXT_DOTFILES, EXECUTABLE_SCRIPT_EXTENSIONS;
914
+ var UTF8_BOM, TEXT_EXTENSIONS, TEXT_DOTFILES, BINARY_EXTENSIONS, EXECUTABLE_SCRIPT_EXTENSIONS;
909
915
  var init_fs_text_encoding = __esm({
910
916
  "src/utils/filesystem/fs-text-encoding.ts"() {
911
917
  UTF8_BOM = "\uFEFF";
@@ -950,9 +956,109 @@ var init_fs_text_encoding = __esm({
950
956
  ".rooignore",
951
957
  ".antigravityignore"
952
958
  ]);
959
+ BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
960
+ ".png",
961
+ ".jpg",
962
+ ".jpeg",
963
+ ".gif",
964
+ ".bmp",
965
+ ".ico",
966
+ ".webp",
967
+ ".avif",
968
+ ".tiff",
969
+ ".pdf",
970
+ ".zip",
971
+ ".gz",
972
+ ".tgz",
973
+ ".bz2",
974
+ ".xz",
975
+ ".7z",
976
+ ".rar",
977
+ ".jar",
978
+ ".woff",
979
+ ".woff2",
980
+ ".ttf",
981
+ ".otf",
982
+ ".eot",
983
+ ".mp3",
984
+ ".mp4",
985
+ ".wav",
986
+ ".ogg",
987
+ ".webm",
988
+ ".mov",
989
+ ".wasm",
990
+ ".bin",
991
+ ".dat",
992
+ ".db",
993
+ ".sqlite",
994
+ ".so",
995
+ ".dylib",
996
+ ".dll",
997
+ ".exe",
998
+ ".class",
999
+ ".pyc",
1000
+ // Office and design documents are zip or proprietary containers.
1001
+ ".xlsx",
1002
+ ".xls",
1003
+ ".docx",
1004
+ ".doc",
1005
+ ".pptx",
1006
+ ".ppt",
1007
+ ".odt",
1008
+ ".ods",
1009
+ ".psd",
1010
+ ".ai",
1011
+ ".sketch",
1012
+ ".fig",
1013
+ ".heic",
1014
+ ".heif",
1015
+ // Archives, columnar data, models and compressed payloads.
1016
+ ".tar",
1017
+ ".zst",
1018
+ ".br",
1019
+ ".lz4",
1020
+ ".parquet",
1021
+ ".avro",
1022
+ ".orc",
1023
+ ".pkl",
1024
+ ".npy",
1025
+ ".npz",
1026
+ ".onnx",
1027
+ ".pt",
1028
+ ".safetensors",
1029
+ ".gguf",
1030
+ ".sqlite3",
1031
+ ".avi",
1032
+ ".mkv",
1033
+ ".flac",
1034
+ ".aac",
1035
+ ".m4a",
1036
+ ".ttc"
1037
+ ]);
953
1038
  EXECUTABLE_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".sh", ".bash", ".zsh"]);
954
1039
  }
955
1040
  });
1041
+ async function renameWithRetry(from, to, options = {}) {
1042
+ const attempts = options.attempts ?? 5;
1043
+ const delayMs = options.delayMs ?? 50;
1044
+ for (let attempt = 0; ; attempt++) {
1045
+ try {
1046
+ await rename(from, to);
1047
+ return;
1048
+ } catch (err) {
1049
+ const code = err.code;
1050
+ const transient = code !== void 0 && TRANSIENT_RENAME_CODES.has(code);
1051
+ if (!transient || attempt >= attempts - 1) throw err;
1052
+ await setTimeout$1(delayMs * 2 ** attempt);
1053
+ }
1054
+ }
1055
+ }
1056
+ var TRANSIENT_RENAME_CODES;
1057
+ var init_rename_retry = __esm({
1058
+ "src/utils/filesystem/rename-retry.ts"() {
1059
+ TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY", "ENOTEMPTY", "EEXIST"]);
1060
+ }
1061
+ });
956
1062
  function shouldSkipRecursiveBranch(segments) {
957
1063
  if (segments.length > MAX_RECURSIVE_DEPTH) return true;
958
1064
  const counts = /* @__PURE__ */ new Map();
@@ -1043,30 +1149,10 @@ var init_fs_traverse = __esm({
1043
1149
  MAX_SEGMENT_REPETITIONS = 3;
1044
1150
  }
1045
1151
  });
1046
- async function renameWithRetry(from, to, options = {}) {
1047
- const attempts = options.attempts ?? 5;
1048
- const delayMs = options.delayMs ?? 50;
1049
- for (let attempt = 0; ; attempt++) {
1050
- try {
1051
- await rename(from, to);
1052
- return;
1053
- } catch (err) {
1054
- const code = err.code;
1055
- const transient = code !== void 0 && TRANSIENT_RENAME_CODES.has(code);
1056
- if (!transient || attempt >= attempts - 1) throw err;
1057
- await setTimeout$1(delayMs * 2 ** attempt);
1058
- }
1059
- }
1060
- }
1061
- var TRANSIENT_RENAME_CODES;
1062
- var init_rename_retry = __esm({
1063
- "src/utils/filesystem/rename-retry.ts"() {
1064
- TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY", "ENOTEMPTY", "EEXIST"]);
1065
- }
1066
- });
1067
1152
  async function readFileSafe(path) {
1068
1153
  try {
1069
- const data = await readFile(path, "utf-8");
1154
+ const data = await readFile(path, payloadEncodingFor(path));
1155
+ if (isBinaryPayloadPath(path)) return data;
1070
1156
  return data.startsWith(UTF8_BOM) ? data.slice(UTF8_BOM.length) : data;
1071
1157
  } catch (err) {
1072
1158
  const e = err;
@@ -1090,40 +1176,28 @@ async function writeFileAtomic(path, content, options) {
1090
1176
  { errnoCode: "EISDIR" }
1091
1177
  );
1092
1178
  }
1093
- if (info.isSymbolicLink()) {
1094
- await unlink(path).catch((e) => {
1095
- if (e.code !== "ENOENT") throw e;
1096
- });
1097
- }
1098
1179
  } catch (err) {
1099
1180
  if (err instanceof FileSystemError) throw err;
1100
1181
  const e = err;
1101
1182
  if (e.code !== "ENOENT") throw err;
1102
1183
  }
1103
- const tmpPath = `${path}.tmp`;
1184
+ const tmpPath = `${path}.tmp-${randomUUID()}`;
1104
1185
  const payload = shouldNormalizeLineEndings(path) ? normalizeLineEndings(content) : content;
1105
1186
  const mode = executableModeFor(path);
1187
+ let handle;
1188
+ let ownsTemporaryFile = false;
1106
1189
  try {
1107
- try {
1108
- const tmpInfo = await lstat(tmpPath);
1109
- if (tmpInfo.isSymbolicLink()) {
1110
- await unlink(tmpPath);
1111
- }
1112
- } catch (tmpErr) {
1113
- if (tmpErr.code !== "ENOENT") throw tmpErr;
1114
- }
1115
- const writeOpts = {
1116
- encoding: "utf-8",
1117
- flag: "w"
1118
- };
1119
- if (mode !== void 0) writeOpts.mode = mode;
1120
- await writeFile(tmpPath, payload, writeOpts);
1121
- await rename(tmpPath, path);
1122
- if (mode !== void 0) {
1123
- await chmod(path, mode);
1124
- }
1190
+ handle = await open(tmpPath, "wx", mode);
1191
+ ownsTemporaryFile = true;
1192
+ await handle.writeFile(payload, payloadEncodingFor(path));
1193
+ if (mode !== void 0) await handle.chmod(mode);
1194
+ await handle.close();
1195
+ handle = void 0;
1196
+ await renameWithRetry(tmpPath, path);
1125
1197
  } catch (err) {
1126
- await rm(tmpPath, { force: true }).catch(() => {
1198
+ await handle?.close().catch(() => {
1199
+ });
1200
+ if (ownsTemporaryFile) await rm(tmpPath, { force: true }).catch(() => {
1127
1201
  });
1128
1202
  const e = err;
1129
1203
  throw new FileSystemError(
@@ -1148,6 +1222,7 @@ var init_fs = __esm({
1148
1222
  "src/utils/filesystem/fs.ts"() {
1149
1223
  init_errors();
1150
1224
  init_fs_text_encoding();
1225
+ init_rename_retry();
1151
1226
  init_fs_traverse();
1152
1227
  init_fs_text_encoding();
1153
1228
  init_rename_retry();
@@ -2302,43 +2377,92 @@ function isGlobAdjacent(content, start, end) {
2302
2377
  const next = end < content.length ? content.at(end) : "";
2303
2378
  return prev === "*" || next === "*";
2304
2379
  }
2380
+ var NON_REWRITABLE_BARE_FILES, PATH_TOKEN, LINE_NUMBER_SUFFIX;
2381
+ var init_link_rebaser_helpers = __esm({
2382
+ "src/core/reference/link-rebaser-helpers.ts"() {
2383
+ init_path_helpers();
2384
+ init_link_format_registry();
2385
+ NON_REWRITABLE_BARE_FILES = /* @__PURE__ */ new Set([
2386
+ "AGENTS.md",
2387
+ "CLAUDE.md",
2388
+ "GEMINI.md",
2389
+ "codex.md",
2390
+ ".windsurfrules",
2391
+ ".cursorrules"
2392
+ ]);
2393
+ PATH_TOKEN = /(?:\.\.[\\/]|\.\/|\.\\|\/[A-Za-z0-9._-]|[A-Za-z]:[\\/][A-Za-z0-9._-]|\.agentsmesh[\\/]|\.claude[\\/]|\.cursor[\\/]|\.github[\\/]|\.continue[\\/]|\.junie[\\/]|\.kiro[\\/]|\.gemini[\\/]|\.clinerules[\\/]|\.cline[\\/]|\.codex[\\/]|\.agents[\\/]|\.windsurf[\\/]|\.roo[\\/]|(?:[A-Za-z0-9._-]+[\\/])+|[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+)[A-Za-z0-9._@%+~:\\/-]*/g;
2394
+ LINE_NUMBER_SUFFIX = /(?::(\d+)){1,2}$/;
2395
+ }
2396
+ });
2397
+
2398
+ // src/core/reference/protected-ranges.ts
2399
+ function inlineCodeRanges(content) {
2400
+ const ranges = [];
2401
+ let openStart = -1;
2402
+ let openLength = 0;
2403
+ for (const match of content.matchAll(/`+/g)) {
2404
+ const start = match.index;
2405
+ const length = match[0].length;
2406
+ if (openStart === -1) {
2407
+ openStart = start;
2408
+ openLength = length;
2409
+ continue;
2410
+ }
2411
+ if (length === openLength) {
2412
+ ranges.push([openStart, start + length]);
2413
+ openStart = -1;
2414
+ openLength = 0;
2415
+ }
2416
+ }
2417
+ return ranges;
2418
+ }
2419
+ function extendAcrossBalancedParens(content, end) {
2420
+ let cursor = end;
2421
+ while (content[cursor] === "(") {
2422
+ let depth = 0;
2423
+ let scan = cursor;
2424
+ while (scan < content.length) {
2425
+ const ch = content[scan];
2426
+ if (ch === "(") depth += 1;
2427
+ else if (ch === ")") {
2428
+ depth -= 1;
2429
+ if (depth === 0) break;
2430
+ } else if (ch === void 0 || /\s/.test(ch)) return cursor;
2431
+ scan += 1;
2432
+ }
2433
+ if (depth !== 0) return cursor;
2434
+ cursor = scan + 1;
2435
+ while (cursor < content.length && !/[\s<>()\]]/.test(content.charAt(cursor))) cursor += 1;
2436
+ }
2437
+ return cursor;
2438
+ }
2305
2439
  function protectedRanges(content) {
2306
2440
  const ranges = [];
2307
2441
  for (const pattern of getLinkFormatRegistry().protectedSchemes) {
2308
2442
  const globalPattern = pattern.flags.includes("g") ? pattern : new RegExp(pattern.source, `${pattern.flags}g`);
2309
2443
  for (const match of content.matchAll(globalPattern)) {
2310
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2444
+ const start = match.index;
2445
+ ranges.push([start, extendAcrossBalancedParens(content, start + match[0].length)]);
2311
2446
  }
2312
2447
  }
2313
2448
  for (const match of content.matchAll(FENCED_CODE_BLOCK)) {
2314
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2449
+ ranges.push([match.index, match.index + match[0].length]);
2315
2450
  }
2316
2451
  for (const match of content.matchAll(ROOT_GENERATION_CONTRACT_BLOCK)) {
2317
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2452
+ ranges.push([match.index, match.index + match[0].length]);
2318
2453
  }
2319
2454
  for (const match of content.matchAll(EMBEDDED_RULES_BLOCK)) {
2320
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2455
+ ranges.push([match.index, match.index + match[0].length]);
2321
2456
  }
2322
2457
  return ranges;
2323
2458
  }
2324
- var NON_REWRITABLE_BARE_FILES, FENCED_CODE_BLOCK, ROOT_GENERATION_CONTRACT_BLOCK, EMBEDDED_RULES_BLOCK, PATH_TOKEN, LINE_NUMBER_SUFFIX;
2325
- var init_link_rebaser_helpers = __esm({
2326
- "src/core/reference/link-rebaser-helpers.ts"() {
2327
- init_path_helpers();
2459
+ var FENCED_CODE_BLOCK, ROOT_GENERATION_CONTRACT_BLOCK, EMBEDDED_RULES_BLOCK;
2460
+ var init_protected_ranges = __esm({
2461
+ "src/core/reference/protected-ranges.ts"() {
2328
2462
  init_link_format_registry();
2329
- NON_REWRITABLE_BARE_FILES = /* @__PURE__ */ new Set([
2330
- "AGENTS.md",
2331
- "CLAUDE.md",
2332
- "GEMINI.md",
2333
- "codex.md",
2334
- ".windsurfrules",
2335
- ".cursorrules"
2336
- ]);
2337
2463
  FENCED_CODE_BLOCK = /^(?:```|~~~)[^\n]*\n[\s\S]*?^(?:```|~~~)/gm;
2338
2464
  ROOT_GENERATION_CONTRACT_BLOCK = /<!-- agentsmesh:root-generation-contract:start -->[\s\S]*?<!-- agentsmesh:root-generation-contract:end -->/g;
2339
2465
  EMBEDDED_RULES_BLOCK = /<!-- agentsmesh:embedded-rules:start -->[\s\S]*?<!-- agentsmesh:embedded-rules:end -->/g;
2340
- PATH_TOKEN = /(?:\.\.[\\/]|\.\/|\.\\|\/[A-Za-z0-9._-]|[A-Za-z]:[\\/][A-Za-z0-9._-]|\.agentsmesh[\\/]|\.claude[\\/]|\.cursor[\\/]|\.github[\\/]|\.continue[\\/]|\.junie[\\/]|\.kiro[\\/]|\.gemini[\\/]|\.clinerules[\\/]|\.cline[\\/]|\.codex[\\/]|\.agents[\\/]|\.windsurf[\\/]|\.roo[\\/]|(?:[A-Za-z0-9._-]+[\\/])+|[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+)[A-Za-z0-9._@%+~:\\/-]*/g;
2341
- LINE_NUMBER_SUFFIX = /(?::(\d+)){1,2}$/;
2342
2466
  }
2343
2467
  });
2344
2468
 
@@ -2831,6 +2955,7 @@ var init_link_rebaser = __esm({
2831
2955
  "src/core/reference/link-rebaser.ts"() {
2832
2956
  init_path_helpers();
2833
2957
  init_link_rebaser_helpers();
2958
+ init_protected_ranges();
2834
2959
  init_link_rebaser_output();
2835
2960
  init_link_rebaser_resolution();
2836
2961
  init_link_uri_encoding();
@@ -7254,6 +7379,60 @@ var init_embedded_rules = __esm({
7254
7379
  }
7255
7380
  });
7256
7381
 
7382
+ // src/utils/text/json-comments.ts
7383
+ function stripJsonComments(text) {
7384
+ let result2 = "";
7385
+ let i = 0;
7386
+ const len = text.length;
7387
+ while (i < len) {
7388
+ const ch = text[i];
7389
+ if (ch === '"') {
7390
+ result2 += ch;
7391
+ i++;
7392
+ while (i < len) {
7393
+ const sc = text[i];
7394
+ result2 += sc;
7395
+ if (sc === "\\") {
7396
+ i++;
7397
+ if (i < len) {
7398
+ result2 += text[i];
7399
+ }
7400
+ } else if (sc === '"') {
7401
+ break;
7402
+ }
7403
+ i++;
7404
+ }
7405
+ i++;
7406
+ continue;
7407
+ }
7408
+ if (ch === "/" && text[i + 1] === "*") {
7409
+ i += 2;
7410
+ while (i < len) {
7411
+ if (text[i] === "*" && text[i + 1] === "/") {
7412
+ i += 2;
7413
+ break;
7414
+ }
7415
+ i++;
7416
+ }
7417
+ continue;
7418
+ }
7419
+ if (ch === "/" && text[i + 1] === "/") {
7420
+ i += 2;
7421
+ while (i < len && text[i] !== "\n") {
7422
+ i++;
7423
+ }
7424
+ continue;
7425
+ }
7426
+ result2 += ch;
7427
+ i++;
7428
+ }
7429
+ return result2;
7430
+ }
7431
+ var init_json_comments = __esm({
7432
+ "src/utils/text/json-comments.ts"() {
7433
+ }
7434
+ });
7435
+
7257
7436
  // src/canonical/features/syntax-error.ts
7258
7437
  function failSyntax(filePath2, cause, onParseError) {
7259
7438
  const error = new CanonicalParseError(filePath2, cause);
@@ -7303,54 +7482,6 @@ function parseServer(raw) {
7303
7482
  env
7304
7483
  };
7305
7484
  }
7306
- function stripJsonComments(text) {
7307
- let result2 = "";
7308
- let i = 0;
7309
- const len = text.length;
7310
- while (i < len) {
7311
- const ch = text[i];
7312
- if (ch === '"') {
7313
- result2 += ch;
7314
- i++;
7315
- while (i < len) {
7316
- const sc = text[i];
7317
- result2 += sc;
7318
- if (sc === "\\") {
7319
- i++;
7320
- if (i < len) {
7321
- result2 += text[i];
7322
- }
7323
- } else if (sc === '"') {
7324
- break;
7325
- }
7326
- i++;
7327
- }
7328
- i++;
7329
- continue;
7330
- }
7331
- if (ch === "/" && text[i + 1] === "*") {
7332
- i += 2;
7333
- while (i < len) {
7334
- if (text[i] === "*" && text[i + 1] === "/") {
7335
- i += 2;
7336
- break;
7337
- }
7338
- i++;
7339
- }
7340
- continue;
7341
- }
7342
- if (ch === "/" && text[i + 1] === "/") {
7343
- i += 2;
7344
- while (i < len && text[i] !== "\n") {
7345
- i++;
7346
- }
7347
- continue;
7348
- }
7349
- result2 += ch;
7350
- i++;
7351
- }
7352
- return result2;
7353
- }
7354
7485
  async function parseMcp(mcpPath, onParseError) {
7355
7486
  const content = await readFileSafe(mcpPath);
7356
7487
  if (!content) return null;
@@ -7373,6 +7504,7 @@ async function parseMcp(mcpPath, onParseError) {
7373
7504
  }
7374
7505
  var init_mcp = __esm({
7375
7506
  "src/canonical/features/mcp.ts"() {
7507
+ init_json_comments();
7376
7508
  init_syntax_error();
7377
7509
  init_fs();
7378
7510
  }
@@ -8704,7 +8836,7 @@ ${rawBody}`;
8704
8836
  });
8705
8837
  }
8706
8838
  function generateMcp3(canonical) {
8707
- if (!canonical.mcp || Object.keys(canonical.mcp.mcpServers).length === 0) return [];
8839
+ if (!canonical.mcp) return [];
8708
8840
  const content = JSON.stringify({ mcpServers: canonical.mcp.mcpServers }, null, 2);
8709
8841
  return [{ path: CLAUDE_MCP_JSON, content }];
8710
8842
  }
@@ -8739,14 +8871,12 @@ function generatePermissions4(canonical) {
8739
8871
  if (!canonical.permissions) return [];
8740
8872
  const { allow, deny } = canonical.permissions;
8741
8873
  const ask = canonical.permissions.ask ?? [];
8742
- if (allow.length === 0 && deny.length === 0 && ask.length === 0) return [];
8743
8874
  const content = JSON.stringify({ permissions: { allow, deny, ask } }, null, 2);
8744
8875
  return [{ path: CLAUDE_SETTINGS, content }];
8745
8876
  }
8746
8877
  function generateHooks3(canonical) {
8747
- if (!canonical.hooks || Object.keys(canonical.hooks).length === 0) return [];
8878
+ if (!canonical.hooks) return [];
8748
8879
  const claudeHooks = buildClaudeHooksObjectFromCanonical(canonical);
8749
- if (Object.keys(claudeHooks).length === 0) return [];
8750
8880
  const content = JSON.stringify({ hooks: claudeHooks }, null, 2);
8751
8881
  return [{ path: CLAUDE_SETTINGS, content }];
8752
8882
  }
@@ -20564,9 +20694,9 @@ var init_config_toml = __esm({
20564
20694
  function isValidKimiPermissionPattern(pattern) {
20565
20695
  const trimmed = pattern.trim();
20566
20696
  if (trimmed.length === 0) return false;
20567
- const open = trimmed.indexOf("(");
20568
- if (open === -1) return true;
20569
- return trimmed.endsWith(")") && open > 0;
20697
+ const open2 = trimmed.indexOf("(");
20698
+ if (open2 === -1) return true;
20699
+ return trimmed.endsWith(")") && open2 > 0;
20570
20700
  }
20571
20701
  function listOf(permissions, key) {
20572
20702
  return permissions[key] ?? [];
@@ -29756,6 +29886,7 @@ function rewriteGeneratedReferences(results, canonical, config, projectRoot, sco
29756
29886
  // src/core/reference/validate-generated-markdown-links.ts
29757
29887
  init_path_helpers();
29758
29888
  init_link_rebaser_helpers();
29889
+ init_protected_ranges();
29759
29890
 
29760
29891
  // src/utils/output/color.ts
29761
29892
  function noColorRequested() {
@@ -29838,7 +29969,7 @@ var logger = {
29838
29969
 
29839
29970
  // src/core/reference/validate-generated-markdown-links.ts
29840
29971
  var INLINE_MD_LINK = /!?\[[^\]]*\]\(([^)]+)\)/g;
29841
- var REF_LINK_DEF = /^\s*\[[^\]\n]+\]:\s*(?:<([^>\n]*)>|(\S+))/gm;
29972
+ var REF_LINK_DEF = /^\s*\[(?!\^)[^\]\n]+\]:\s*(?:<([^>\n]*)>|(\S+))/gm;
29842
29973
  function isMarkdownLikeOutput(relativePath) {
29843
29974
  return relativePath.endsWith(".md") || relativePath.endsWith(".mdc");
29844
29975
  }
@@ -29971,7 +30102,7 @@ function findBrokenMarkdownLinks(results, projectRoot) {
29971
30102
  projectRoot,
29972
30103
  pathApi(projectRoot).join(projectRoot, result2.path)
29973
30104
  );
29974
- const protectedR = protectedRanges(result2.content);
30105
+ const protectedR = [...protectedRanges(result2.content), ...inlineCodeRanges(result2.content)];
29975
30106
  const visitDestination = (raw, matchIndex) => {
29976
30107
  if (isOffsetInRanges(matchIndex, protectedR)) return;
29977
30108
  const checked = resolveMarkdownLinkTargets(raw, projectRoot, destinationAbs);
@@ -30065,28 +30196,10 @@ function ruleNameFromSource(source) {
30065
30196
 
30066
30197
  // src/core/generate/collision.ts
30067
30198
  init_fs_text_encoding();
30199
+
30200
+ // src/core/generate/collision-agents.ts
30068
30201
  init_target_ids();
30069
30202
  var AGENTS_SUFFIX = "AGENTS.md";
30070
- function statusRank(status) {
30071
- switch (status) {
30072
- case "created":
30073
- return 3;
30074
- case "updated":
30075
- return 2;
30076
- case "unchanged":
30077
- return 1;
30078
- case "skipped":
30079
- return 0;
30080
- }
30081
- }
30082
- function mergeDuplicateMetadata(preferred, other) {
30083
- if (statusRank(other.status) <= statusRank(preferred.status)) return preferred;
30084
- return {
30085
- ...preferred,
30086
- status: other.status,
30087
- currentContent: other.currentContent ?? preferred.currentContent
30088
- };
30089
- }
30090
30203
  function trimmedContent(content) {
30091
30204
  return content.trim();
30092
30205
  }
@@ -30120,15 +30233,82 @@ function richerAgentsResult(left, right) {
30120
30233
  }
30121
30234
  return null;
30122
30235
  }
30236
+ function contentLines(content) {
30237
+ const lines = /* @__PURE__ */ new Set();
30238
+ for (const line of content.split("\n")) {
30239
+ const trimmed = line.trim();
30240
+ if (trimmed !== "") lines.add(trimmed);
30241
+ }
30242
+ return lines;
30243
+ }
30244
+ function covers(outer, inner) {
30245
+ for (const line of inner) {
30246
+ if (!outer.has(line)) return false;
30247
+ }
30248
+ return true;
30249
+ }
30250
+ var EMBEDDED_RULES_BLOCK2 = /(<!-- agentsmesh:embedded-rules:start -->)([\s\S]*?)(<!-- agentsmesh:embedded-rules:end -->)/;
30251
+ var EMBEDDED_RULE_UNIT = /<!-- agentsmesh:embedded-rule:start [\s\S]*?<!-- agentsmesh:embedded-rule:end -->/g;
30252
+ function embeddedRuleUnits(block) {
30253
+ return [...block.matchAll(EMBEDDED_RULE_UNIT)].map((m) => m[0]);
30254
+ }
30255
+ function mergedEmbeddedRulesResult(left, right) {
30256
+ if (!left.path.endsWith(AGENTS_SUFFIX) || left.path !== right.path) return null;
30257
+ if (normalizeAgentsContent(left.content) !== normalizeAgentsContent(right.content)) return null;
30258
+ const leftBlock = EMBEDDED_RULES_BLOCK2.exec(left.content);
30259
+ const rightBlock = EMBEDDED_RULES_BLOCK2.exec(right.content);
30260
+ if (!leftBlock?.[2] || !rightBlock?.[2]) return null;
30261
+ const leftUnits = embeddedRuleUnits(leftBlock[2]);
30262
+ const rightUnits = embeddedRuleUnits(rightBlock[2]);
30263
+ if (leftUnits.length === 0 && rightUnits.length === 0) return null;
30264
+ const added = rightUnits.filter((unit) => !leftUnits.includes(unit));
30265
+ if (added.length === 0) return left;
30266
+ const merged = [...leftUnits, ...added].join("\n\n");
30267
+ const content = left.content.replace(
30268
+ EMBEDDED_RULES_BLOCK2,
30269
+ (_full, start, _inner, end) => `${start}
30270
+
30271
+ ${merged}
30272
+
30273
+ ${end}`
30274
+ );
30275
+ logger.warn(
30276
+ `${left.path} is shared by ${left.target} and ${right.target}, so their target-scoped rules were combined into one file \u2014 every target reading it sees all of them.`
30277
+ );
30278
+ return { ...left, content };
30279
+ }
30123
30280
  function richerCodexAgentsResult(left, right) {
30124
30281
  if (!left.path.endsWith(AGENTS_SUFFIX) || left.path !== right.path) return null;
30125
30282
  const codex = left.target === CODEX_CLI_TARGET_ID ? left : right.target === CODEX_CLI_TARGET_ID ? right : null;
30126
30283
  const other = codex === left ? right : left;
30127
30284
  if (!codex) return null;
30128
- const codexLen = trimmedContent(codex.content).length;
30129
- const otherLen = trimmedContent(other.content).length;
30130
- if (codexLen === otherLen) return null;
30131
- return codexLen > otherLen ? codex : other;
30285
+ const codexLines = contentLines(codex.content);
30286
+ const otherLines = contentLines(other.content);
30287
+ if (covers(codexLines, otherLines)) return codex;
30288
+ if (covers(otherLines, codexLines)) return other;
30289
+ return null;
30290
+ }
30291
+
30292
+ // src/core/generate/collision.ts
30293
+ function statusRank(status) {
30294
+ switch (status) {
30295
+ case "created":
30296
+ return 3;
30297
+ case "updated":
30298
+ return 2;
30299
+ case "unchanged":
30300
+ return 1;
30301
+ case "skipped":
30302
+ return 0;
30303
+ }
30304
+ }
30305
+ function mergeDuplicateMetadata(preferred, other) {
30306
+ if (statusRank(other.status) <= statusRank(preferred.status)) return preferred;
30307
+ return {
30308
+ ...preferred,
30309
+ status: other.status,
30310
+ currentContent: other.currentContent ?? preferred.currentContent
30311
+ };
30132
30312
  }
30133
30313
  function resolveOutputCollisions(results) {
30134
30314
  const deduped = [];
@@ -30145,6 +30325,11 @@ function resolveOutputCollisions(results) {
30145
30325
  deduped[existingIdx] = richer;
30146
30326
  continue;
30147
30327
  }
30328
+ const mergedRules = mergedEmbeddedRulesResult(existing, result2);
30329
+ if (mergedRules) {
30330
+ deduped[existingIdx] = refreshResultStatus(mergedRules);
30331
+ continue;
30332
+ }
30148
30333
  const richerCodex = richerCodexAgentsResult(existing, result2);
30149
30334
  if (richerCodex) {
30150
30335
  deduped[existingIdx] = richerCodex;
@@ -30710,6 +30895,14 @@ function redactUrlSecrets(message) {
30710
30895
  }
30711
30896
  );
30712
30897
  }
30898
+ function stripUrlCredentials(url) {
30899
+ return url.replace(
30900
+ URL_WITH_CREDENTIALS,
30901
+ (_full, scheme, _userinfo, rest) => {
30902
+ return `${scheme}${rest}`;
30903
+ }
30904
+ );
30905
+ }
30713
30906
  function gitProtocolOptIns() {
30714
30907
  const on = (v) => v === "1" || v === "true";
30715
30908
  return {
@@ -31108,6 +31301,7 @@ async function sweepStaleCache(cacheDir, maxAgeMs) {
31108
31301
  var MAX_CACHE_KEY_LENGTH = 80;
31109
31302
  var CACHE_KEY_HASH_LENGTH = 12;
31110
31303
  function buildCacheKey(provider, identifier, ref) {
31304
+ identifier = stripUrlCredentials(identifier);
31111
31305
  const safe = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_").replace(/^\.+/, "_");
31112
31306
  const [org, repo] = provider === "github" ? identifier.split("/", 2) : [];
31113
31307
  const readable = org && repo ? `${safe(org)}--${safe(repo)}--${safe(ref)}` : `${safe(provider)}__${safe(identifier)}__${safe(ref)}`;
@@ -34466,8 +34660,59 @@ async function diffOutputChecksums(rootBase, lockOutputs) {
34466
34660
 
34467
34661
  // src/core/generate/stale-cleanup.ts
34468
34662
  init_fs();
34663
+ async function canonicalizePath(path) {
34664
+ try {
34665
+ return await realpath(path);
34666
+ } catch (error) {
34667
+ if (error.code !== "ENOENT") throw error;
34668
+ const parent = dirname(path);
34669
+ if (parent === path) return resolve(path);
34670
+ return join(await canonicalizePath(parent), basename(path));
34671
+ }
34672
+ }
34673
+ function isPathInside(target34, root) {
34674
+ return target34 === root || target34.startsWith(root.endsWith(sep) ? root : `${root}${sep}`);
34675
+ }
34676
+ var display = (path) => path.replaceAll("\\", "/");
34677
+ async function assertPathInsideRoot(root, target34) {
34678
+ const rootAbs = resolve(root);
34679
+ const targetAbs = resolve(target34);
34680
+ if (!isPathInside(targetAbs, rootAbs)) {
34681
+ throw new Error(`Unsafe filesystem path: ${display(target34)} is outside ${display(rootAbs)}`);
34682
+ }
34683
+ let realTarget;
34684
+ let realRoot;
34685
+ try {
34686
+ [realTarget, realRoot] = await Promise.all([
34687
+ canonicalizePath(targetAbs),
34688
+ canonicalizePath(rootAbs)
34689
+ ]);
34690
+ } catch (cause) {
34691
+ const detail = cause instanceof Error ? cause.message : String(cause);
34692
+ throw new Error(
34693
+ `Unsafe filesystem path: ${display(target34)} could not be resolved (${detail})`,
34694
+ { cause }
34695
+ );
34696
+ }
34697
+ if (isPathInside(realTarget, realRoot)) return;
34698
+ throw new Error(
34699
+ `Unsafe filesystem path: ${display(target34)} resolves to ${display(realTarget)} outside ${display(realRoot)}`
34700
+ );
34701
+ }
34702
+
34703
+ // src/core/generate/stale-cleanup.ts
34469
34704
  init_builtin_targets();
34470
34705
  init_registry();
34706
+ init_builtin_targets();
34707
+ function retainedDirs(inactiveTargets, scope) {
34708
+ const dirs = /* @__PURE__ */ new Set();
34709
+ for (const target34 of inactiveTargets) {
34710
+ for (const dir of getTargetManagedOutputs(target34, scope)?.dirs ?? []) dirs.add(dir);
34711
+ }
34712
+ return dirs;
34713
+ }
34714
+
34715
+ // src/core/generate/stale-cleanup.ts
34471
34716
  async function listFiles2(root, base = root) {
34472
34717
  const entries = await readdir(root, { withFileTypes: true });
34473
34718
  const files = [];
@@ -34481,13 +34726,6 @@ async function listFiles2(root, base = root) {
34481
34726
  }
34482
34727
  return files;
34483
34728
  }
34484
- function retainedDirs(inactiveTargets, scope) {
34485
- const dirs = /* @__PURE__ */ new Set();
34486
- for (const target34 of inactiveTargets) {
34487
- for (const dir of getTargetManagedOutputs(target34, scope)?.dirs ?? []) dirs.add(dir);
34488
- }
34489
- return dirs;
34490
- }
34491
34729
  function primaryEmitted(target34, scope, expected) {
34492
34730
  const descriptor34 = getBuiltinTargetDefinition(target34) ?? getDescriptor(target34);
34493
34731
  const primary = getTargetLayout(target34, scope)?.rootInstructionPath ?? descriptor34?.generators.primaryRootInstructionPath;
@@ -34514,6 +34752,7 @@ async function findStaleGeneratedOutputs(args) {
34514
34752
  for (const dir of managed.dirs) {
34515
34753
  if (retained.has(dir)) continue;
34516
34754
  const absDir = join(args.projectRoot, dir);
34755
+ await assertPathInsideRoot(args.projectRoot, absDir);
34517
34756
  if (!await exists(absDir)) continue;
34518
34757
  for (const file of await listFiles2(absDir)) {
34519
34758
  const relPath = `${dir}/${file}`.replace(/\/+/g, "/");
@@ -34525,6 +34764,7 @@ async function findStaleGeneratedOutputs(args) {
34525
34764
  const found = [];
34526
34765
  for (const relPath of stale) {
34527
34766
  if (expected.has(relPath) || coOwned.has(relPath)) continue;
34767
+ await assertPathInsideRoot(args.projectRoot, dirname(join(args.projectRoot, relPath)));
34528
34768
  if (await exists(join(args.projectRoot, relPath))) found.push(relPath);
34529
34769
  }
34530
34770
  return found.sort();
@@ -34538,6 +34778,7 @@ async function findUntrackedManagedDirFiles(args) {
34538
34778
  for (const dir of getTargetManagedOutputs(target34, scope)?.dirs ?? []) {
34539
34779
  if (retained.has(dir)) continue;
34540
34780
  const absDir = join(args.projectRoot, dir);
34781
+ await assertPathInsideRoot(args.projectRoot, absDir);
34541
34782
  if (!await exists(absDir)) continue;
34542
34783
  for (const file of await listFiles2(absDir)) {
34543
34784
  const relPath = `${dir}/${file}`.replace(/\/+/g, "/");
@@ -35084,8 +35325,8 @@ function isBroadGlob(pattern) {
35084
35325
  const p = pattern.trim();
35085
35326
  if (p === "*" || p === "**") return true;
35086
35327
  if (!p.includes("**")) return false;
35087
- const basename77 = p.slice(p.lastIndexOf("/") + 1);
35088
- return basename77.startsWith("*");
35328
+ const basename78 = p.slice(p.lastIndexOf("/") + 1);
35329
+ return basename78.startsWith("*");
35089
35330
  }
35090
35331
  function inspectCapturedLesson(graph, lessonId, knownPaths) {
35091
35332
  const lesson = graph.lessons[lessonId];
@@ -35191,8 +35432,7 @@ async function acquireProcessLock(lockPath, opts = {}) {
35191
35432
  if (acquired) return acquired;
35192
35433
  const existing = await inspectLock(lockPath);
35193
35434
  if (existing !== "young" && isStale(existing, stale)) {
35194
- await rm(lockPath, { recursive: true, force: true }).catch(() => {
35195
- });
35435
+ await rm(lockPath, { recursive: true, force: true });
35196
35436
  continue;
35197
35437
  }
35198
35438
  if (attempt >= retries) {
@@ -35216,7 +35456,13 @@ async function tryAcquire(lockPath) {
35216
35456
  started: Date.now(),
35217
35457
  hostname: getHostname()
35218
35458
  };
35219
- await writeFile(metadataPath, JSON.stringify(metadata), "utf-8");
35459
+ try {
35460
+ await writeFile(metadataPath, JSON.stringify(metadata), "utf-8");
35461
+ } catch (error) {
35462
+ await rm(lockPath, { recursive: true, force: true }).catch(() => {
35463
+ });
35464
+ throw error;
35465
+ }
35220
35466
  let released = false;
35221
35467
  const cleanup = () => {
35222
35468
  if (released) return;
@@ -35288,7 +35534,7 @@ function getHostname() {
35288
35534
  return hostname();
35289
35535
  }
35290
35536
  function sleep2(ms) {
35291
- return new Promise((resolve11) => setTimeout(resolve11, ms));
35537
+ return new Promise((resolve12) => setTimeout(resolve12, ms));
35292
35538
  }
35293
35539
 
35294
35540
  // src/lessons/lessons-lock.ts