agentsmesh 0.35.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/engine.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { z } from 'zod';
2
2
  import { parse, stringify, parseDocument, isMap, Document, isSeq, isScalar, Scalar, Pair, YAMLSeq } from 'yaml';
3
3
  import { existsSync, readFileSync, constants, readdirSync, realpathSync, statSync } from 'fs';
4
- import { basename, join, dirname, relative, win32, posix, sep, resolve, extname } from 'path';
5
- import { readFile, rm, mkdir, readdir, lstat, unlink, writeFile, rename, chmod, access, stat, realpath, mkdtemp, cp } from 'fs/promises';
4
+ import { basename, join, dirname, relative, extname, win32, posix, sep, resolve } from 'path';
5
+ import { readFile, rm, mkdir, readdir, lstat, open, access, stat, realpath, rename, writeFile, mkdtemp, cp } from 'fs/promises';
6
6
  import { setTimeout } from 'timers/promises';
7
+ import { randomUUID, createHash } 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, 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';
@@ -845,6 +845,12 @@ function shouldNormalizeLineEndings(path) {
845
845
  const base = basename(path).toLowerCase();
846
846
  return TEXT_DOTFILES.has(base);
847
847
  }
848
+ function isBinaryPayloadPath(path) {
849
+ return BINARY_EXTENSIONS.has(extname(path).toLowerCase());
850
+ }
851
+ function payloadEncodingFor(path) {
852
+ return isBinaryPayloadPath(path) ? "latin1" : "utf-8";
853
+ }
848
854
  function normalizeLineEndings(content) {
849
855
  return content.replace(/\r\n?/g, "\n");
850
856
  }
@@ -856,7 +862,7 @@ function normalizeTextPayload(path, content) {
856
862
  const withoutBom = content.startsWith(UTF8_BOM) ? content.slice(UTF8_BOM.length) : content;
857
863
  return normalizeLineEndings(withoutBom);
858
864
  }
859
- var UTF8_BOM, TEXT_EXTENSIONS, TEXT_DOTFILES, EXECUTABLE_SCRIPT_EXTENSIONS;
865
+ var UTF8_BOM, TEXT_EXTENSIONS, TEXT_DOTFILES, BINARY_EXTENSIONS, EXECUTABLE_SCRIPT_EXTENSIONS;
860
866
  var init_fs_text_encoding = __esm({
861
867
  "src/utils/filesystem/fs-text-encoding.ts"() {
862
868
  UTF8_BOM = "\uFEFF";
@@ -901,9 +907,109 @@ var init_fs_text_encoding = __esm({
901
907
  ".rooignore",
902
908
  ".antigravityignore"
903
909
  ]);
910
+ BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
911
+ ".png",
912
+ ".jpg",
913
+ ".jpeg",
914
+ ".gif",
915
+ ".bmp",
916
+ ".ico",
917
+ ".webp",
918
+ ".avif",
919
+ ".tiff",
920
+ ".pdf",
921
+ ".zip",
922
+ ".gz",
923
+ ".tgz",
924
+ ".bz2",
925
+ ".xz",
926
+ ".7z",
927
+ ".rar",
928
+ ".jar",
929
+ ".woff",
930
+ ".woff2",
931
+ ".ttf",
932
+ ".otf",
933
+ ".eot",
934
+ ".mp3",
935
+ ".mp4",
936
+ ".wav",
937
+ ".ogg",
938
+ ".webm",
939
+ ".mov",
940
+ ".wasm",
941
+ ".bin",
942
+ ".dat",
943
+ ".db",
944
+ ".sqlite",
945
+ ".so",
946
+ ".dylib",
947
+ ".dll",
948
+ ".exe",
949
+ ".class",
950
+ ".pyc",
951
+ // Office and design documents are zip or proprietary containers.
952
+ ".xlsx",
953
+ ".xls",
954
+ ".docx",
955
+ ".doc",
956
+ ".pptx",
957
+ ".ppt",
958
+ ".odt",
959
+ ".ods",
960
+ ".psd",
961
+ ".ai",
962
+ ".sketch",
963
+ ".fig",
964
+ ".heic",
965
+ ".heif",
966
+ // Archives, columnar data, models and compressed payloads.
967
+ ".tar",
968
+ ".zst",
969
+ ".br",
970
+ ".lz4",
971
+ ".parquet",
972
+ ".avro",
973
+ ".orc",
974
+ ".pkl",
975
+ ".npy",
976
+ ".npz",
977
+ ".onnx",
978
+ ".pt",
979
+ ".safetensors",
980
+ ".gguf",
981
+ ".sqlite3",
982
+ ".avi",
983
+ ".mkv",
984
+ ".flac",
985
+ ".aac",
986
+ ".m4a",
987
+ ".ttc"
988
+ ]);
904
989
  EXECUTABLE_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([".sh", ".bash", ".zsh"]);
905
990
  }
906
991
  });
992
+ async function renameWithRetry(from, to, options = {}) {
993
+ const attempts = options.attempts ?? 5;
994
+ const delayMs = options.delayMs ?? 50;
995
+ for (let attempt = 0; ; attempt++) {
996
+ try {
997
+ await rename(from, to);
998
+ return;
999
+ } catch (err) {
1000
+ const code = err.code;
1001
+ const transient = code !== void 0 && TRANSIENT_RENAME_CODES.has(code);
1002
+ if (!transient || attempt >= attempts - 1) throw err;
1003
+ await setTimeout(delayMs * 2 ** attempt);
1004
+ }
1005
+ }
1006
+ }
1007
+ var TRANSIENT_RENAME_CODES;
1008
+ var init_rename_retry = __esm({
1009
+ "src/utils/filesystem/rename-retry.ts"() {
1010
+ TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY", "ENOTEMPTY", "EEXIST"]);
1011
+ }
1012
+ });
907
1013
  function shouldSkipRecursiveBranch(segments) {
908
1014
  if (segments.length > MAX_RECURSIVE_DEPTH) return true;
909
1015
  const counts = /* @__PURE__ */ new Map();
@@ -994,30 +1100,10 @@ var init_fs_traverse = __esm({
994
1100
  MAX_SEGMENT_REPETITIONS = 3;
995
1101
  }
996
1102
  });
997
- async function renameWithRetry(from, to, options = {}) {
998
- const attempts = options.attempts ?? 5;
999
- const delayMs = options.delayMs ?? 50;
1000
- for (let attempt = 0; ; attempt++) {
1001
- try {
1002
- await rename(from, to);
1003
- return;
1004
- } catch (err) {
1005
- const code = err.code;
1006
- const transient = code !== void 0 && TRANSIENT_RENAME_CODES.has(code);
1007
- if (!transient || attempt >= attempts - 1) throw err;
1008
- await setTimeout(delayMs * 2 ** attempt);
1009
- }
1010
- }
1011
- }
1012
- var TRANSIENT_RENAME_CODES;
1013
- var init_rename_retry = __esm({
1014
- "src/utils/filesystem/rename-retry.ts"() {
1015
- TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY", "ENOTEMPTY", "EEXIST"]);
1016
- }
1017
- });
1018
1103
  async function readFileSafe(path) {
1019
1104
  try {
1020
- const data = await readFile(path, "utf-8");
1105
+ const data = await readFile(path, payloadEncodingFor(path));
1106
+ if (isBinaryPayloadPath(path)) return data;
1021
1107
  return data.startsWith(UTF8_BOM) ? data.slice(UTF8_BOM.length) : data;
1022
1108
  } catch (err) {
1023
1109
  const e = err;
@@ -1041,40 +1127,28 @@ async function writeFileAtomic(path, content, options) {
1041
1127
  { errnoCode: "EISDIR" }
1042
1128
  );
1043
1129
  }
1044
- if (info.isSymbolicLink()) {
1045
- await unlink(path).catch((e) => {
1046
- if (e.code !== "ENOENT") throw e;
1047
- });
1048
- }
1049
1130
  } catch (err) {
1050
1131
  if (err instanceof FileSystemError) throw err;
1051
1132
  const e = err;
1052
1133
  if (e.code !== "ENOENT") throw err;
1053
1134
  }
1054
- const tmpPath = `${path}.tmp`;
1135
+ const tmpPath = `${path}.tmp-${randomUUID()}`;
1055
1136
  const payload = shouldNormalizeLineEndings(path) ? normalizeLineEndings(content) : content;
1056
1137
  const mode = executableModeFor(path);
1138
+ let handle;
1139
+ let ownsTemporaryFile = false;
1057
1140
  try {
1058
- try {
1059
- const tmpInfo = await lstat(tmpPath);
1060
- if (tmpInfo.isSymbolicLink()) {
1061
- await unlink(tmpPath);
1062
- }
1063
- } catch (tmpErr) {
1064
- if (tmpErr.code !== "ENOENT") throw tmpErr;
1065
- }
1066
- const writeOpts = {
1067
- encoding: "utf-8",
1068
- flag: "w"
1069
- };
1070
- if (mode !== void 0) writeOpts.mode = mode;
1071
- await writeFile(tmpPath, payload, writeOpts);
1072
- await rename(tmpPath, path);
1073
- if (mode !== void 0) {
1074
- await chmod(path, mode);
1075
- }
1141
+ handle = await open(tmpPath, "wx", mode);
1142
+ ownsTemporaryFile = true;
1143
+ await handle.writeFile(payload, payloadEncodingFor(path));
1144
+ if (mode !== void 0) await handle.chmod(mode);
1145
+ await handle.close();
1146
+ handle = void 0;
1147
+ await renameWithRetry(tmpPath, path);
1076
1148
  } catch (err) {
1077
- await rm(tmpPath, { force: true }).catch(() => {
1149
+ await handle?.close().catch(() => {
1150
+ });
1151
+ if (ownsTemporaryFile) await rm(tmpPath, { force: true }).catch(() => {
1078
1152
  });
1079
1153
  const e = err;
1080
1154
  throw new FileSystemError(
@@ -1099,6 +1173,7 @@ var init_fs = __esm({
1099
1173
  "src/utils/filesystem/fs.ts"() {
1100
1174
  init_errors();
1101
1175
  init_fs_text_encoding();
1176
+ init_rename_retry();
1102
1177
  init_fs_traverse();
1103
1178
  init_fs_text_encoding();
1104
1179
  init_rename_retry();
@@ -2251,43 +2326,92 @@ function isGlobAdjacent(content, start, end) {
2251
2326
  const next = end < content.length ? content.at(end) : "";
2252
2327
  return prev === "*" || next === "*";
2253
2328
  }
2329
+ var NON_REWRITABLE_BARE_FILES, PATH_TOKEN, LINE_NUMBER_SUFFIX;
2330
+ var init_link_rebaser_helpers = __esm({
2331
+ "src/core/reference/link-rebaser-helpers.ts"() {
2332
+ init_path_helpers();
2333
+ init_link_format_registry();
2334
+ NON_REWRITABLE_BARE_FILES = /* @__PURE__ */ new Set([
2335
+ "AGENTS.md",
2336
+ "CLAUDE.md",
2337
+ "GEMINI.md",
2338
+ "codex.md",
2339
+ ".windsurfrules",
2340
+ ".cursorrules"
2341
+ ]);
2342
+ 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;
2343
+ LINE_NUMBER_SUFFIX = /(?::(\d+)){1,2}$/;
2344
+ }
2345
+ });
2346
+
2347
+ // src/core/reference/protected-ranges.ts
2348
+ function inlineCodeRanges(content) {
2349
+ const ranges = [];
2350
+ let openStart = -1;
2351
+ let openLength = 0;
2352
+ for (const match of content.matchAll(/`+/g)) {
2353
+ const start = match.index;
2354
+ const length = match[0].length;
2355
+ if (openStart === -1) {
2356
+ openStart = start;
2357
+ openLength = length;
2358
+ continue;
2359
+ }
2360
+ if (length === openLength) {
2361
+ ranges.push([openStart, start + length]);
2362
+ openStart = -1;
2363
+ openLength = 0;
2364
+ }
2365
+ }
2366
+ return ranges;
2367
+ }
2368
+ function extendAcrossBalancedParens(content, end) {
2369
+ let cursor = end;
2370
+ while (content[cursor] === "(") {
2371
+ let depth = 0;
2372
+ let scan = cursor;
2373
+ while (scan < content.length) {
2374
+ const ch = content[scan];
2375
+ if (ch === "(") depth += 1;
2376
+ else if (ch === ")") {
2377
+ depth -= 1;
2378
+ if (depth === 0) break;
2379
+ } else if (ch === void 0 || /\s/.test(ch)) return cursor;
2380
+ scan += 1;
2381
+ }
2382
+ if (depth !== 0) return cursor;
2383
+ cursor = scan + 1;
2384
+ while (cursor < content.length && !/[\s<>()\]]/.test(content.charAt(cursor))) cursor += 1;
2385
+ }
2386
+ return cursor;
2387
+ }
2254
2388
  function protectedRanges(content) {
2255
2389
  const ranges = [];
2256
2390
  for (const pattern of getLinkFormatRegistry().protectedSchemes) {
2257
2391
  const globalPattern = pattern.flags.includes("g") ? pattern : new RegExp(pattern.source, `${pattern.flags}g`);
2258
2392
  for (const match of content.matchAll(globalPattern)) {
2259
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2393
+ const start = match.index;
2394
+ ranges.push([start, extendAcrossBalancedParens(content, start + match[0].length)]);
2260
2395
  }
2261
2396
  }
2262
2397
  for (const match of content.matchAll(FENCED_CODE_BLOCK)) {
2263
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2398
+ ranges.push([match.index, match.index + match[0].length]);
2264
2399
  }
2265
2400
  for (const match of content.matchAll(ROOT_GENERATION_CONTRACT_BLOCK)) {
2266
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2401
+ ranges.push([match.index, match.index + match[0].length]);
2267
2402
  }
2268
2403
  for (const match of content.matchAll(EMBEDDED_RULES_BLOCK)) {
2269
- ranges.push([match.index ?? 0, (match.index ?? 0) + match[0].length]);
2404
+ ranges.push([match.index, match.index + match[0].length]);
2270
2405
  }
2271
2406
  return ranges;
2272
2407
  }
2273
- var NON_REWRITABLE_BARE_FILES, FENCED_CODE_BLOCK, ROOT_GENERATION_CONTRACT_BLOCK, EMBEDDED_RULES_BLOCK, PATH_TOKEN, LINE_NUMBER_SUFFIX;
2274
- var init_link_rebaser_helpers = __esm({
2275
- "src/core/reference/link-rebaser-helpers.ts"() {
2276
- init_path_helpers();
2408
+ var FENCED_CODE_BLOCK, ROOT_GENERATION_CONTRACT_BLOCK, EMBEDDED_RULES_BLOCK;
2409
+ var init_protected_ranges = __esm({
2410
+ "src/core/reference/protected-ranges.ts"() {
2277
2411
  init_link_format_registry();
2278
- NON_REWRITABLE_BARE_FILES = /* @__PURE__ */ new Set([
2279
- "AGENTS.md",
2280
- "CLAUDE.md",
2281
- "GEMINI.md",
2282
- "codex.md",
2283
- ".windsurfrules",
2284
- ".cursorrules"
2285
- ]);
2286
2412
  FENCED_CODE_BLOCK = /^(?:```|~~~)[^\n]*\n[\s\S]*?^(?:```|~~~)/gm;
2287
2413
  ROOT_GENERATION_CONTRACT_BLOCK = /<!-- agentsmesh:root-generation-contract:start -->[\s\S]*?<!-- agentsmesh:root-generation-contract:end -->/g;
2288
2414
  EMBEDDED_RULES_BLOCK = /<!-- agentsmesh:embedded-rules:start -->[\s\S]*?<!-- agentsmesh:embedded-rules:end -->/g;
2289
- 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;
2290
- LINE_NUMBER_SUFFIX = /(?::(\d+)){1,2}$/;
2291
2415
  }
2292
2416
  });
2293
2417
 
@@ -2780,6 +2904,7 @@ var init_link_rebaser = __esm({
2780
2904
  "src/core/reference/link-rebaser.ts"() {
2781
2905
  init_path_helpers();
2782
2906
  init_link_rebaser_helpers();
2907
+ init_protected_ranges();
2783
2908
  init_link_rebaser_output();
2784
2909
  init_link_rebaser_resolution();
2785
2910
  init_link_uri_encoding();
@@ -7203,6 +7328,60 @@ var init_embedded_rules = __esm({
7203
7328
  }
7204
7329
  });
7205
7330
 
7331
+ // src/utils/text/json-comments.ts
7332
+ function stripJsonComments(text) {
7333
+ let result2 = "";
7334
+ let i = 0;
7335
+ const len = text.length;
7336
+ while (i < len) {
7337
+ const ch = text[i];
7338
+ if (ch === '"') {
7339
+ result2 += ch;
7340
+ i++;
7341
+ while (i < len) {
7342
+ const sc = text[i];
7343
+ result2 += sc;
7344
+ if (sc === "\\") {
7345
+ i++;
7346
+ if (i < len) {
7347
+ result2 += text[i];
7348
+ }
7349
+ } else if (sc === '"') {
7350
+ break;
7351
+ }
7352
+ i++;
7353
+ }
7354
+ i++;
7355
+ continue;
7356
+ }
7357
+ if (ch === "/" && text[i + 1] === "*") {
7358
+ i += 2;
7359
+ while (i < len) {
7360
+ if (text[i] === "*" && text[i + 1] === "/") {
7361
+ i += 2;
7362
+ break;
7363
+ }
7364
+ i++;
7365
+ }
7366
+ continue;
7367
+ }
7368
+ if (ch === "/" && text[i + 1] === "/") {
7369
+ i += 2;
7370
+ while (i < len && text[i] !== "\n") {
7371
+ i++;
7372
+ }
7373
+ continue;
7374
+ }
7375
+ result2 += ch;
7376
+ i++;
7377
+ }
7378
+ return result2;
7379
+ }
7380
+ var init_json_comments = __esm({
7381
+ "src/utils/text/json-comments.ts"() {
7382
+ }
7383
+ });
7384
+
7206
7385
  // src/canonical/features/syntax-error.ts
7207
7386
  function failSyntax(filePath2, cause, onParseError) {
7208
7387
  const error = new CanonicalParseError(filePath2, cause);
@@ -7252,54 +7431,6 @@ function parseServer(raw) {
7252
7431
  env
7253
7432
  };
7254
7433
  }
7255
- function stripJsonComments(text) {
7256
- let result2 = "";
7257
- let i = 0;
7258
- const len = text.length;
7259
- while (i < len) {
7260
- const ch = text[i];
7261
- if (ch === '"') {
7262
- result2 += ch;
7263
- i++;
7264
- while (i < len) {
7265
- const sc = text[i];
7266
- result2 += sc;
7267
- if (sc === "\\") {
7268
- i++;
7269
- if (i < len) {
7270
- result2 += text[i];
7271
- }
7272
- } else if (sc === '"') {
7273
- break;
7274
- }
7275
- i++;
7276
- }
7277
- i++;
7278
- continue;
7279
- }
7280
- if (ch === "/" && text[i + 1] === "*") {
7281
- i += 2;
7282
- while (i < len) {
7283
- if (text[i] === "*" && text[i + 1] === "/") {
7284
- i += 2;
7285
- break;
7286
- }
7287
- i++;
7288
- }
7289
- continue;
7290
- }
7291
- if (ch === "/" && text[i + 1] === "/") {
7292
- i += 2;
7293
- while (i < len && text[i] !== "\n") {
7294
- i++;
7295
- }
7296
- continue;
7297
- }
7298
- result2 += ch;
7299
- i++;
7300
- }
7301
- return result2;
7302
- }
7303
7434
  async function parseMcp(mcpPath, onParseError) {
7304
7435
  const content = await readFileSafe(mcpPath);
7305
7436
  if (!content) return null;
@@ -7322,6 +7453,7 @@ async function parseMcp(mcpPath, onParseError) {
7322
7453
  }
7323
7454
  var init_mcp = __esm({
7324
7455
  "src/canonical/features/mcp.ts"() {
7456
+ init_json_comments();
7325
7457
  init_syntax_error();
7326
7458
  init_fs();
7327
7459
  }
@@ -8653,7 +8785,7 @@ ${rawBody}`;
8653
8785
  });
8654
8786
  }
8655
8787
  function generateMcp3(canonical) {
8656
- if (!canonical.mcp || Object.keys(canonical.mcp.mcpServers).length === 0) return [];
8788
+ if (!canonical.mcp) return [];
8657
8789
  const content = JSON.stringify({ mcpServers: canonical.mcp.mcpServers }, null, 2);
8658
8790
  return [{ path: CLAUDE_MCP_JSON, content }];
8659
8791
  }
@@ -8688,14 +8820,12 @@ function generatePermissions4(canonical) {
8688
8820
  if (!canonical.permissions) return [];
8689
8821
  const { allow, deny } = canonical.permissions;
8690
8822
  const ask = canonical.permissions.ask ?? [];
8691
- if (allow.length === 0 && deny.length === 0 && ask.length === 0) return [];
8692
8823
  const content = JSON.stringify({ permissions: { allow, deny, ask } }, null, 2);
8693
8824
  return [{ path: CLAUDE_SETTINGS, content }];
8694
8825
  }
8695
8826
  function generateHooks3(canonical) {
8696
- if (!canonical.hooks || Object.keys(canonical.hooks).length === 0) return [];
8827
+ if (!canonical.hooks) return [];
8697
8828
  const claudeHooks = buildClaudeHooksObjectFromCanonical(canonical);
8698
- if (Object.keys(claudeHooks).length === 0) return [];
8699
8829
  const content = JSON.stringify({ hooks: claudeHooks }, null, 2);
8700
8830
  return [{ path: CLAUDE_SETTINGS, content }];
8701
8831
  }
@@ -20513,9 +20643,9 @@ var init_config_toml = __esm({
20513
20643
  function isValidKimiPermissionPattern(pattern) {
20514
20644
  const trimmed = pattern.trim();
20515
20645
  if (trimmed.length === 0) return false;
20516
- const open = trimmed.indexOf("(");
20517
- if (open === -1) return true;
20518
- return trimmed.endsWith(")") && open > 0;
20646
+ const open2 = trimmed.indexOf("(");
20647
+ if (open2 === -1) return true;
20648
+ return trimmed.endsWith(")") && open2 > 0;
20519
20649
  }
20520
20650
  function listOf(permissions, key) {
20521
20651
  return permissions[key] ?? [];
@@ -29705,6 +29835,7 @@ function rewriteGeneratedReferences(results, canonical, config, projectRoot, sco
29705
29835
  // src/core/reference/validate-generated-markdown-links.ts
29706
29836
  init_path_helpers();
29707
29837
  init_link_rebaser_helpers();
29838
+ init_protected_ranges();
29708
29839
 
29709
29840
  // src/utils/output/color.ts
29710
29841
  function noColorRequested() {
@@ -29787,7 +29918,7 @@ var logger = {
29787
29918
 
29788
29919
  // src/core/reference/validate-generated-markdown-links.ts
29789
29920
  var INLINE_MD_LINK = /!?\[[^\]]*\]\(([^)]+)\)/g;
29790
- var REF_LINK_DEF = /^\s*\[[^\]\n]+\]:\s*(?:<([^>\n]*)>|(\S+))/gm;
29921
+ var REF_LINK_DEF = /^\s*\[(?!\^)[^\]\n]+\]:\s*(?:<([^>\n]*)>|(\S+))/gm;
29791
29922
  function isMarkdownLikeOutput(relativePath) {
29792
29923
  return relativePath.endsWith(".md") || relativePath.endsWith(".mdc");
29793
29924
  }
@@ -29920,7 +30051,7 @@ function findBrokenMarkdownLinks(results, projectRoot) {
29920
30051
  projectRoot,
29921
30052
  pathApi(projectRoot).join(projectRoot, result2.path)
29922
30053
  );
29923
- const protectedR = protectedRanges(result2.content);
30054
+ const protectedR = [...protectedRanges(result2.content), ...inlineCodeRanges(result2.content)];
29924
30055
  const visitDestination = (raw, matchIndex) => {
29925
30056
  if (isOffsetInRanges(matchIndex, protectedR)) return;
29926
30057
  const checked = resolveMarkdownLinkTargets(raw, projectRoot, destinationAbs);
@@ -30014,28 +30145,10 @@ function ruleNameFromSource(source) {
30014
30145
 
30015
30146
  // src/core/generate/collision.ts
30016
30147
  init_fs_text_encoding();
30148
+
30149
+ // src/core/generate/collision-agents.ts
30017
30150
  init_target_ids();
30018
30151
  var AGENTS_SUFFIX = "AGENTS.md";
30019
- function statusRank(status) {
30020
- switch (status) {
30021
- case "created":
30022
- return 3;
30023
- case "updated":
30024
- return 2;
30025
- case "unchanged":
30026
- return 1;
30027
- case "skipped":
30028
- return 0;
30029
- }
30030
- }
30031
- function mergeDuplicateMetadata(preferred, other) {
30032
- if (statusRank(other.status) <= statusRank(preferred.status)) return preferred;
30033
- return {
30034
- ...preferred,
30035
- status: other.status,
30036
- currentContent: other.currentContent ?? preferred.currentContent
30037
- };
30038
- }
30039
30152
  function trimmedContent(content) {
30040
30153
  return content.trim();
30041
30154
  }
@@ -30069,15 +30182,82 @@ function richerAgentsResult(left, right) {
30069
30182
  }
30070
30183
  return null;
30071
30184
  }
30185
+ function contentLines(content) {
30186
+ const lines = /* @__PURE__ */ new Set();
30187
+ for (const line of content.split("\n")) {
30188
+ const trimmed = line.trim();
30189
+ if (trimmed !== "") lines.add(trimmed);
30190
+ }
30191
+ return lines;
30192
+ }
30193
+ function covers(outer, inner) {
30194
+ for (const line of inner) {
30195
+ if (!outer.has(line)) return false;
30196
+ }
30197
+ return true;
30198
+ }
30199
+ var EMBEDDED_RULES_BLOCK2 = /(<!-- agentsmesh:embedded-rules:start -->)([\s\S]*?)(<!-- agentsmesh:embedded-rules:end -->)/;
30200
+ var EMBEDDED_RULE_UNIT = /<!-- agentsmesh:embedded-rule:start [\s\S]*?<!-- agentsmesh:embedded-rule:end -->/g;
30201
+ function embeddedRuleUnits(block) {
30202
+ return [...block.matchAll(EMBEDDED_RULE_UNIT)].map((m) => m[0]);
30203
+ }
30204
+ function mergedEmbeddedRulesResult(left, right) {
30205
+ if (!left.path.endsWith(AGENTS_SUFFIX) || left.path !== right.path) return null;
30206
+ if (normalizeAgentsContent(left.content) !== normalizeAgentsContent(right.content)) return null;
30207
+ const leftBlock = EMBEDDED_RULES_BLOCK2.exec(left.content);
30208
+ const rightBlock = EMBEDDED_RULES_BLOCK2.exec(right.content);
30209
+ if (!leftBlock?.[2] || !rightBlock?.[2]) return null;
30210
+ const leftUnits = embeddedRuleUnits(leftBlock[2]);
30211
+ const rightUnits = embeddedRuleUnits(rightBlock[2]);
30212
+ if (leftUnits.length === 0 && rightUnits.length === 0) return null;
30213
+ const added = rightUnits.filter((unit) => !leftUnits.includes(unit));
30214
+ if (added.length === 0) return left;
30215
+ const merged = [...leftUnits, ...added].join("\n\n");
30216
+ const content = left.content.replace(
30217
+ EMBEDDED_RULES_BLOCK2,
30218
+ (_full, start, _inner, end) => `${start}
30219
+
30220
+ ${merged}
30221
+
30222
+ ${end}`
30223
+ );
30224
+ logger.warn(
30225
+ `${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.`
30226
+ );
30227
+ return { ...left, content };
30228
+ }
30072
30229
  function richerCodexAgentsResult(left, right) {
30073
30230
  if (!left.path.endsWith(AGENTS_SUFFIX) || left.path !== right.path) return null;
30074
30231
  const codex = left.target === CODEX_CLI_TARGET_ID ? left : right.target === CODEX_CLI_TARGET_ID ? right : null;
30075
30232
  const other = codex === left ? right : left;
30076
30233
  if (!codex) return null;
30077
- const codexLen = trimmedContent(codex.content).length;
30078
- const otherLen = trimmedContent(other.content).length;
30079
- if (codexLen === otherLen) return null;
30080
- return codexLen > otherLen ? codex : other;
30234
+ const codexLines = contentLines(codex.content);
30235
+ const otherLines = contentLines(other.content);
30236
+ if (covers(codexLines, otherLines)) return codex;
30237
+ if (covers(otherLines, codexLines)) return other;
30238
+ return null;
30239
+ }
30240
+
30241
+ // src/core/generate/collision.ts
30242
+ function statusRank(status) {
30243
+ switch (status) {
30244
+ case "created":
30245
+ return 3;
30246
+ case "updated":
30247
+ return 2;
30248
+ case "unchanged":
30249
+ return 1;
30250
+ case "skipped":
30251
+ return 0;
30252
+ }
30253
+ }
30254
+ function mergeDuplicateMetadata(preferred, other) {
30255
+ if (statusRank(other.status) <= statusRank(preferred.status)) return preferred;
30256
+ return {
30257
+ ...preferred,
30258
+ status: other.status,
30259
+ currentContent: other.currentContent ?? preferred.currentContent
30260
+ };
30081
30261
  }
30082
30262
  function resolveOutputCollisions(results) {
30083
30263
  const deduped = [];
@@ -30094,6 +30274,11 @@ function resolveOutputCollisions(results) {
30094
30274
  deduped[existingIdx] = richer;
30095
30275
  continue;
30096
30276
  }
30277
+ const mergedRules = mergedEmbeddedRulesResult(existing, result2);
30278
+ if (mergedRules) {
30279
+ deduped[existingIdx] = refreshResultStatus(mergedRules);
30280
+ continue;
30281
+ }
30097
30282
  const richerCodex = richerCodexAgentsResult(existing, result2);
30098
30283
  if (richerCodex) {
30099
30284
  deduped[existingIdx] = richerCodex;
@@ -30659,6 +30844,14 @@ function redactUrlSecrets(message) {
30659
30844
  }
30660
30845
  );
30661
30846
  }
30847
+ function stripUrlCredentials(url) {
30848
+ return url.replace(
30849
+ URL_WITH_CREDENTIALS,
30850
+ (_full, scheme, _userinfo, rest) => {
30851
+ return `${scheme}${rest}`;
30852
+ }
30853
+ );
30854
+ }
30662
30855
  function gitProtocolOptIns() {
30663
30856
  const on = (v) => v === "1" || v === "true";
30664
30857
  return {
@@ -31057,6 +31250,7 @@ async function sweepStaleCache(cacheDir, maxAgeMs) {
31057
31250
  var MAX_CACHE_KEY_LENGTH = 80;
31058
31251
  var CACHE_KEY_HASH_LENGTH = 12;
31059
31252
  function buildCacheKey(provider, identifier, ref) {
31253
+ identifier = stripUrlCredentials(identifier);
31060
31254
  const safe = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_").replace(/^\.+/, "_");
31061
31255
  const [org, repo] = provider === "github" ? identifier.split("/", 2) : [];
31062
31256
  const readable = org && repo ? `${safe(org)}--${safe(repo)}--${safe(ref)}` : `${safe(provider)}__${safe(identifier)}__${safe(ref)}`;
@@ -34329,8 +34523,59 @@ async function diffOutputChecksums(rootBase, lockOutputs) {
34329
34523
 
34330
34524
  // src/core/generate/stale-cleanup.ts
34331
34525
  init_fs();
34526
+ async function canonicalizePath(path) {
34527
+ try {
34528
+ return await realpath(path);
34529
+ } catch (error) {
34530
+ if (error.code !== "ENOENT") throw error;
34531
+ const parent = dirname(path);
34532
+ if (parent === path) return resolve(path);
34533
+ return join(await canonicalizePath(parent), basename(path));
34534
+ }
34535
+ }
34536
+ function isPathInside(target34, root) {
34537
+ return target34 === root || target34.startsWith(root.endsWith(sep) ? root : `${root}${sep}`);
34538
+ }
34539
+ var display = (path) => path.replaceAll("\\", "/");
34540
+ async function assertPathInsideRoot(root, target34) {
34541
+ const rootAbs = resolve(root);
34542
+ const targetAbs = resolve(target34);
34543
+ if (!isPathInside(targetAbs, rootAbs)) {
34544
+ throw new Error(`Unsafe filesystem path: ${display(target34)} is outside ${display(rootAbs)}`);
34545
+ }
34546
+ let realTarget;
34547
+ let realRoot;
34548
+ try {
34549
+ [realTarget, realRoot] = await Promise.all([
34550
+ canonicalizePath(targetAbs),
34551
+ canonicalizePath(rootAbs)
34552
+ ]);
34553
+ } catch (cause) {
34554
+ const detail = cause instanceof Error ? cause.message : String(cause);
34555
+ throw new Error(
34556
+ `Unsafe filesystem path: ${display(target34)} could not be resolved (${detail})`,
34557
+ { cause }
34558
+ );
34559
+ }
34560
+ if (isPathInside(realTarget, realRoot)) return;
34561
+ throw new Error(
34562
+ `Unsafe filesystem path: ${display(target34)} resolves to ${display(realTarget)} outside ${display(realRoot)}`
34563
+ );
34564
+ }
34565
+
34566
+ // src/core/generate/stale-cleanup.ts
34332
34567
  init_builtin_targets();
34333
34568
  init_registry();
34569
+ init_builtin_targets();
34570
+ function retainedDirs(inactiveTargets, scope) {
34571
+ const dirs = /* @__PURE__ */ new Set();
34572
+ for (const target34 of inactiveTargets) {
34573
+ for (const dir of getTargetManagedOutputs(target34, scope)?.dirs ?? []) dirs.add(dir);
34574
+ }
34575
+ return dirs;
34576
+ }
34577
+
34578
+ // src/core/generate/stale-cleanup.ts
34334
34579
  async function listFiles2(root, base = root) {
34335
34580
  const entries = await readdir(root, { withFileTypes: true });
34336
34581
  const files = [];
@@ -34344,13 +34589,6 @@ async function listFiles2(root, base = root) {
34344
34589
  }
34345
34590
  return files;
34346
34591
  }
34347
- function retainedDirs(inactiveTargets, scope) {
34348
- const dirs = /* @__PURE__ */ new Set();
34349
- for (const target34 of inactiveTargets) {
34350
- for (const dir of getTargetManagedOutputs(target34, scope)?.dirs ?? []) dirs.add(dir);
34351
- }
34352
- return dirs;
34353
- }
34354
34592
  function primaryEmitted(target34, scope, expected) {
34355
34593
  const descriptor34 = getBuiltinTargetDefinition(target34) ?? getDescriptor(target34);
34356
34594
  const primary = getTargetLayout(target34, scope)?.rootInstructionPath ?? descriptor34?.generators.primaryRootInstructionPath;
@@ -34377,6 +34615,7 @@ async function findStaleGeneratedOutputs(args) {
34377
34615
  for (const dir of managed.dirs) {
34378
34616
  if (retained.has(dir)) continue;
34379
34617
  const absDir = join(args.projectRoot, dir);
34618
+ await assertPathInsideRoot(args.projectRoot, absDir);
34380
34619
  if (!await exists(absDir)) continue;
34381
34620
  for (const file of await listFiles2(absDir)) {
34382
34621
  const relPath = `${dir}/${file}`.replace(/\/+/g, "/");
@@ -34388,6 +34627,7 @@ async function findStaleGeneratedOutputs(args) {
34388
34627
  const found = [];
34389
34628
  for (const relPath of stale) {
34390
34629
  if (expected.has(relPath) || coOwned.has(relPath)) continue;
34630
+ await assertPathInsideRoot(args.projectRoot, dirname(join(args.projectRoot, relPath)));
34391
34631
  if (await exists(join(args.projectRoot, relPath))) found.push(relPath);
34392
34632
  }
34393
34633
  return found.sort();
@@ -34401,6 +34641,7 @@ async function findUntrackedManagedDirFiles(args) {
34401
34641
  for (const dir of getTargetManagedOutputs(target34, scope)?.dirs ?? []) {
34402
34642
  if (retained.has(dir)) continue;
34403
34643
  const absDir = join(args.projectRoot, dir);
34644
+ await assertPathInsideRoot(args.projectRoot, absDir);
34404
34645
  if (!await exists(absDir)) continue;
34405
34646
  for (const file of await listFiles2(absDir)) {
34406
34647
  const relPath = `${dir}/${file}`.replace(/\/+/g, "/");