artifact-graph 0.8.4 → 0.9.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.cjs CHANGED
@@ -362,6 +362,41 @@ var init_glob_matcher = __esm({
362
362
  }
363
363
  });
364
364
 
365
+ // src/file-walker.ts
366
+ async function walkFiles(root, current = root, readDirectory = defaultReadDirectory) {
367
+ let entries;
368
+ try {
369
+ entries = await readDirectory(current, { withFileTypes: true });
370
+ } catch (error) {
371
+ if (current !== root && error.code === "ENOENT") {
372
+ return [];
373
+ }
374
+ throw error;
375
+ }
376
+ const files = [];
377
+ for (const entry of entries) {
378
+ if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === ".artifact-graph") {
379
+ continue;
380
+ }
381
+ const fullPath = (0, import_node_path.join)(current, entry.name);
382
+ if (entry.isDirectory()) {
383
+ files.push(...await walkFiles(root, fullPath, readDirectory));
384
+ } else {
385
+ files.push((0, import_node_path.relative)(root, fullPath).split("\\").join("/"));
386
+ }
387
+ }
388
+ return files;
389
+ }
390
+ var import_promises, import_node_path, defaultReadDirectory;
391
+ var init_file_walker = __esm({
392
+ "src/file-walker.ts"() {
393
+ "use strict";
394
+ import_promises = require("fs/promises");
395
+ import_node_path = require("path");
396
+ defaultReadDirectory = import_promises.readdir;
397
+ }
398
+ });
399
+
365
400
  // src/target-selector.ts
366
401
  function parseTargetSelector(value) {
367
402
  const separator = value.indexOf(":");
@@ -965,14 +1000,14 @@ async function auditSingleTarget(target, graph, options) {
965
1000
  const fmt = options.format ?? "markdown";
966
1001
  const ext = fmt === "json" ? "json" : "md";
967
1002
  const filename = `${target.type}-${target.id}.packet.${ext}`;
968
- const outPath = (0, import_node_path.join)(options.outDir, filename);
1003
+ const outPath = (0, import_node_path2.join)(options.outDir, filename);
969
1004
  let content;
970
1005
  if (fmt === "json") {
971
1006
  content = JSON.stringify(packet, null, 2) + "\n";
972
1007
  } else {
973
1008
  content = renderPacketMarkdown(packet);
974
1009
  }
975
- await (0, import_promises.writeFile)(outPath, content, "utf-8");
1010
+ await (0, import_promises2.writeFile)(outPath, content, "utf-8");
976
1011
  entry.outputPath = outPath;
977
1012
  }
978
1013
  } catch (error) {
@@ -993,7 +1028,7 @@ async function auditPackets(root, targets, options, graph) {
993
1028
  }
994
1029
  }
995
1030
  if (options.outDir) {
996
- await (0, import_promises.mkdir)(options.outDir, { recursive: true });
1031
+ await (0, import_promises2.mkdir)(options.outDir, { recursive: true });
997
1032
  }
998
1033
  const sampleSet = options.sampleTargets ? new Set(options.sampleTargets) : null;
999
1034
  const sampleOutputPaths = [];
@@ -1045,8 +1080,8 @@ async function auditPackets(root, targets, options, graph) {
1045
1080
  ...isCompact ? { summaryDetail: "compact", countsByType } : {}
1046
1081
  };
1047
1082
  if (options.outDir) {
1048
- const summaryPath = (0, import_node_path.join)(options.outDir, "summary.json");
1049
- await (0, import_promises.writeFile)(summaryPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
1083
+ const summaryPath = (0, import_node_path2.join)(options.outDir, "summary.json");
1084
+ await (0, import_promises2.writeFile)(summaryPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
1050
1085
  }
1051
1086
  return summary;
1052
1087
  }
@@ -1072,14 +1107,14 @@ async function discoverAndAuditPackets(root, options) {
1072
1107
  universalBaseline: effectiveBaseline
1073
1108
  }, graph);
1074
1109
  }
1075
- var import_promises, import_node_path, VALID_TYPES, VALID_TYPES_LABEL;
1110
+ var import_promises2, import_node_path2, VALID_TYPES, VALID_TYPES_LABEL;
1076
1111
  var init_packet_audit = __esm({
1077
1112
  "src/packet-audit.ts"() {
1078
1113
  "use strict";
1079
1114
  init_index();
1080
1115
  init_packet_validator();
1081
- import_promises = require("fs/promises");
1082
- import_node_path = require("path");
1116
+ import_promises2 = require("fs/promises");
1117
+ import_node_path2 = require("path");
1083
1118
  VALID_TYPES = new Set(VALID_PACKET_TARGET_TYPES);
1084
1119
  VALID_TYPES_LABEL = VALID_PACKET_TARGET_TYPES.join(", ");
1085
1120
  }
@@ -1551,7 +1586,7 @@ async function auditVersionLock(root, lockPath = VERSION_LOCK_PATH, graph, confi
1551
1586
  for (const entry of lock.locks) {
1552
1587
  if (entry.kind !== "verifies") continue;
1553
1588
  const sourcePath = entry.source.path;
1554
- const fullSourcePath = (0, import_node_path2.join)(root, sourcePath);
1589
+ const fullSourcePath = (0, import_node_path3.join)(root, sourcePath);
1555
1590
  if (!(0, import_node_fs.existsSync)(fullSourcePath)) continue;
1556
1591
  let liveness = livenessCache.get(sourcePath);
1557
1592
  if (liveness === void 0) {
@@ -1646,14 +1681,14 @@ async function auditVersionLock(root, lockPath = VERSION_LOCK_PATH, graph, confi
1646
1681
  currentArtifactHash: targetNode.contentHash
1647
1682
  });
1648
1683
  }
1649
- if (!(0, import_node_fs.existsSync)((0, import_node_path2.join)(root, sourceNode.path))) {
1684
+ if (!(0, import_node_fs.existsSync)((0, import_node_path3.join)(root, sourceNode.path))) {
1650
1685
  entryIssues.push({
1651
1686
  status: "orphan_lock",
1652
1687
  edgeId: relEdgeId,
1653
1688
  message: `Artifact relation source file ${sourceNode.path} no longer exists`
1654
1689
  });
1655
1690
  }
1656
- if (!(0, import_node_fs.existsSync)((0, import_node_path2.join)(root, targetNode.path))) {
1691
+ if (!(0, import_node_fs.existsSync)((0, import_node_path3.join)(root, targetNode.path))) {
1657
1692
  entryIssues.push({
1658
1693
  status: "orphan_lock",
1659
1694
  edgeId: relEdgeId,
@@ -2226,7 +2261,7 @@ function renderTraceVersionMarkdown(result) {
2226
2261
  async function readVersionLock(root, lockPath) {
2227
2262
  const safeLockPath = normalizeRelativePath(root, lockPath);
2228
2263
  try {
2229
- const raw = await (0, import_promises2.readFile)((0, import_node_path2.join)(root, safeLockPath), "utf-8");
2264
+ const raw = await (0, import_promises3.readFile)((0, import_node_path3.join)(root, safeLockPath), "utf-8");
2230
2265
  let parsed;
2231
2266
  try {
2232
2267
  parsed = JSON.parse(raw);
@@ -2385,9 +2420,9 @@ function requireSafeRelativePath(value, path) {
2385
2420
  }
2386
2421
  async function writeVersionLock(root, lockPath, lock) {
2387
2422
  const safeLockPath = normalizeRelativePath(root, lockPath);
2388
- const fullPath = (0, import_node_path2.join)(root, safeLockPath);
2389
- await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(fullPath), { recursive: true });
2390
- await (0, import_promises2.writeFile)(fullPath, `${JSON.stringify(lock, null, 2)}
2423
+ const fullPath = (0, import_node_path3.join)(root, safeLockPath);
2424
+ await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(fullPath), { recursive: true });
2425
+ await (0, import_promises3.writeFile)(fullPath, `${JSON.stringify(lock, null, 2)}
2391
2426
  `);
2392
2427
  }
2393
2428
  function implementationEdges(index) {
@@ -2568,14 +2603,14 @@ async function hashRelativePath(root, path, cache) {
2568
2603
  const normalized = normalizeRelativePath(root, path);
2569
2604
  const cached = cache.get(normalized);
2570
2605
  if (cached) return cached;
2571
- const content = await (0, import_promises2.readFile)((0, import_node_path2.join)(root, normalized));
2606
+ const content = await (0, import_promises3.readFile)((0, import_node_path3.join)(root, normalized));
2572
2607
  const hash = `sha256:${(0, import_node_crypto.createHash)("sha256").update(content).digest("hex")}`;
2573
2608
  cache.set(normalized, hash);
2574
2609
  return hash;
2575
2610
  }
2576
2611
  function normalizeRelativePath(root, path) {
2577
2612
  const normalized = path.replace(/\\/g, "/");
2578
- const relativePath = normalized.startsWith("/") ? (0, import_node_path2.relative)(root, normalized).replace(/\\/g, "/") : normalized.replace(/^\.\//, "");
2613
+ const relativePath = normalized.startsWith("/") ? (0, import_node_path3.relative)(root, normalized).replace(/\\/g, "/") : normalized.replace(/^\.\//, "");
2579
2614
  if (relativePath === ".." || relativePath.startsWith("../")) {
2580
2615
  throw new Error(`Path is outside root: ${path}`);
2581
2616
  }
@@ -2591,10 +2626,10 @@ async function getTestFileRunnerLiveness(root, filePath, config) {
2591
2626
  if (!/e2e/i.test(filePath) && !/\.e2e\./i.test(filePath)) {
2592
2627
  return "active";
2593
2628
  }
2594
- const fullSourcePath = (0, import_node_path2.join)(root, filePath);
2629
+ const fullSourcePath = (0, import_node_path3.join)(root, filePath);
2595
2630
  if (!(0, import_node_fs.existsSync)(fullSourcePath)) return "inactive";
2596
2631
  try {
2597
- const content = await (0, import_promises2.readFile)(fullSourcePath, "utf-8");
2632
+ const content = await (0, import_promises3.readFile)(fullSourcePath, "utf-8");
2598
2633
  return /\/\/!?\s*@(?:e2e_test|tc)\s+/.test(content) ? "active" : "inactive";
2599
2634
  } catch {
2600
2635
  return "inactive";
@@ -2634,14 +2669,14 @@ async function isFileActiveInRunner(root, filePath, runner) {
2634
2669
  function sortUnique(items) {
2635
2670
  return [...new Set(items)].sort((left, right) => left.localeCompare(right));
2636
2671
  }
2637
- var import_node_crypto, import_node_fs, import_promises2, import_node_path2, VERSION_LOCK_PATH, VERSION_INDEX_SCHEMA_VERSION, VERSION_LOCK_SCHEMA_VERSION, LIVENESS_MESSAGE_PREFIX, VERSION_LOCK_STATUS_LABELS;
2672
+ var import_node_crypto, import_node_fs, import_promises3, import_node_path3, VERSION_LOCK_PATH, VERSION_INDEX_SCHEMA_VERSION, VERSION_LOCK_SCHEMA_VERSION, LIVENESS_MESSAGE_PREFIX, VERSION_LOCK_STATUS_LABELS;
2638
2673
  var init_versioned_traceability = __esm({
2639
2674
  "src/versioned-traceability.ts"() {
2640
2675
  "use strict";
2641
2676
  import_node_crypto = require("crypto");
2642
2677
  import_node_fs = require("fs");
2643
- import_promises2 = require("fs/promises");
2644
- import_node_path2 = require("path");
2678
+ import_promises3 = require("fs/promises");
2679
+ import_node_path3 = require("path");
2645
2680
  init_index();
2646
2681
  init_glob_matcher();
2647
2682
  VERSION_LOCK_PATH = "artifacts/traceability-version-lock.json";
@@ -2667,7 +2702,7 @@ async function resolveArtifactGraphCli(root, options = {}) {
2667
2702
  const candidates = [
2668
2703
  {
2669
2704
  source: "node_modules",
2670
- path: (0, import_node_path3.join)(root, "node_modules/.bin/artifact-graph"),
2705
+ path: (0, import_node_path4.join)(root, "node_modules/.bin/artifact-graph"),
2671
2706
  exists: false
2672
2707
  },
2673
2708
  {
@@ -2700,8 +2735,8 @@ async function resolveArtifactGraphCli(root, options = {}) {
2700
2735
  }
2701
2736
  async function doctorArtifactChain(root, options = {}) {
2702
2737
  const cli = await resolveArtifactGraphCli(root, options);
2703
- const configPath = (0, import_node_path3.join)(root, "artifact-graph.config.yaml");
2704
- const lockPath = (0, import_node_path3.join)(root, VERSION_LOCK_PATH);
2738
+ const configPath = (0, import_node_path4.join)(root, "artifact-graph.config.yaml");
2739
+ const lockPath = (0, import_node_path4.join)(root, VERSION_LOCK_PATH);
2705
2740
  const supportedCommands = cli.path ? await detectSupportedCommands(cli.path) : [];
2706
2741
  const nodeCompatible = isNodeCompatible(process.versions.node);
2707
2742
  const warnings = [
@@ -2774,7 +2809,7 @@ ${maybe.stderr ?? ""}`;
2774
2809
  }
2775
2810
  async function pathExists(path) {
2776
2811
  try {
2777
- await (0, import_promises3.access)(path, import_node_fs2.constants.R_OK);
2812
+ await (0, import_promises4.access)(path, import_node_fs2.constants.R_OK);
2778
2813
  return true;
2779
2814
  } catch {
2780
2815
  return false;
@@ -2790,20 +2825,20 @@ async function findCommandOnPath(command) {
2790
2825
  }
2791
2826
  }
2792
2827
  function resolveCandidatePath(root, candidatePath) {
2793
- return (0, import_node_path3.isAbsolute)(candidatePath) ? candidatePath : (0, import_node_path3.resolve)(root, candidatePath);
2828
+ return (0, import_node_path4.isAbsolute)(candidatePath) ? candidatePath : (0, import_node_path4.resolve)(root, candidatePath);
2794
2829
  }
2795
2830
  function isNodeCompatible(version) {
2796
2831
  const major = Number(version.split(".")[0]);
2797
2832
  return Number.isFinite(major) && major >= 22;
2798
2833
  }
2799
- var import_node_child_process, import_node_fs2, import_promises3, import_node_path3, import_node_util, execFileAsync, KNOWN_COMMANDS;
2834
+ var import_node_child_process, import_node_fs2, import_promises4, import_node_path4, import_node_util, execFileAsync, KNOWN_COMMANDS;
2800
2835
  var init_cli_resolver = __esm({
2801
2836
  "src/cli-resolver.ts"() {
2802
2837
  "use strict";
2803
2838
  import_node_child_process = require("child_process");
2804
2839
  import_node_fs2 = require("fs");
2805
- import_promises3 = require("fs/promises");
2806
- import_node_path3 = require("path");
2840
+ import_promises4 = require("fs/promises");
2841
+ import_node_path4 = require("path");
2807
2842
  import_node_util = require("util");
2808
2843
  init_versioned_traceability();
2809
2844
  execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
@@ -2914,14 +2949,14 @@ async function resolveGitHookPath(root, hookName) {
2914
2949
  ]);
2915
2950
  const value = stdout.trim();
2916
2951
  if (!value) throw new Error(`Git returned an empty hook path for ${hookName}`);
2917
- return (0, import_node_path4.isAbsolute)(value) ? (0, import_node_path4.resolve)(value) : (0, import_node_path4.resolve)(root, value);
2952
+ return (0, import_node_path5.isAbsolute)(value) ? (0, import_node_path5.resolve)(value) : (0, import_node_path5.resolve)(root, value);
2918
2953
  }
2919
- var import_node_child_process3, import_node_path4, import_node_util3, execFileAsync3;
2954
+ var import_node_child_process3, import_node_path5, import_node_util3, execFileAsync3;
2920
2955
  var init_git_hook_path = __esm({
2921
2956
  "src/git-hook-path.ts"() {
2922
2957
  "use strict";
2923
2958
  import_node_child_process3 = require("child_process");
2924
- import_node_path4 = require("path");
2959
+ import_node_path5 = require("path");
2925
2960
  import_node_util3 = require("util");
2926
2961
  execFileAsync3 = (0, import_node_util3.promisify)(import_node_child_process3.execFile);
2927
2962
  }
@@ -3144,7 +3179,7 @@ async function readHookSnapshot(hookPath) {
3144
3179
  for (let attempt = 0; attempt < 3; attempt += 1) {
3145
3180
  let metadata;
3146
3181
  try {
3147
- metadata = await (0, import_promises4.lstat)(hookPath, { bigint: true });
3182
+ metadata = await (0, import_promises5.lstat)(hookPath, { bigint: true });
3148
3183
  } catch (error) {
3149
3184
  if (error.code === "ENOENT") {
3150
3185
  return { kind: "missing", bytes: Buffer.alloc(0) };
@@ -3160,7 +3195,7 @@ async function readHookSnapshot(hookPath) {
3160
3195
  size: metadata.size,
3161
3196
  mtimeNs: metadata.mtimeNs,
3162
3197
  mode: metadata.mode,
3163
- linkTarget: await (0, import_promises4.readlink)(hookPath)
3198
+ linkTarget: await (0, import_promises5.readlink)(hookPath)
3164
3199
  };
3165
3200
  }
3166
3201
  if (!metadata.isFile()) {
@@ -3176,7 +3211,7 @@ async function readHookSnapshot(hookPath) {
3176
3211
  }
3177
3212
  let handle;
3178
3213
  try {
3179
- handle = await (0, import_promises4.open)(hookPath, import_node_fs3.constants.O_RDONLY | (import_node_fs3.constants.O_NOFOLLOW ?? 0));
3214
+ handle = await (0, import_promises5.open)(hookPath, import_node_fs3.constants.O_RDONLY | (import_node_fs3.constants.O_NOFOLLOW ?? 0));
3180
3215
  const opened = await handle.stat({ bigint: true });
3181
3216
  if (opened.dev !== metadata.dev || opened.ino !== metadata.ino) {
3182
3217
  await handle.close();
@@ -3234,15 +3269,15 @@ async function removeHookAtomically(hookPath, snapshot) {
3234
3269
  throw new ConcurrentHookModificationError(hookPath);
3235
3270
  }
3236
3271
  if (current.kind !== "missing") {
3237
- await (0, import_promises4.unlink)(hookPath);
3272
+ await (0, import_promises5.unlink)(hookPath);
3238
3273
  }
3239
3274
  }
3240
3275
  async function writeHookAtomically(hookPath, content, snapshot, mode) {
3241
- await (0, import_promises4.mkdir)((0, import_node_path5.dirname)(hookPath), { recursive: true });
3242
- const temporaryPath = (0, import_node_path5.join)((0, import_node_path5.dirname)(hookPath), `.${(0, import_node_path5.basename)(hookPath)}.${(0, import_node_crypto2.randomUUID)()}.tmp`);
3276
+ await (0, import_promises5.mkdir)((0, import_node_path6.dirname)(hookPath), { recursive: true });
3277
+ const temporaryPath = (0, import_node_path6.join)((0, import_node_path6.dirname)(hookPath), `.${(0, import_node_path6.basename)(hookPath)}.${(0, import_node_crypto2.randomUUID)()}.tmp`);
3243
3278
  let temporaryExists = false;
3244
3279
  try {
3245
- const temporary = await (0, import_promises4.open)(temporaryPath, "wx", mode);
3280
+ const temporary = await (0, import_promises5.open)(temporaryPath, "wx", mode);
3246
3281
  temporaryExists = true;
3247
3282
  try {
3248
3283
  await temporary.writeFile(content);
@@ -3255,11 +3290,11 @@ async function writeHookAtomically(hookPath, content, snapshot, mode) {
3255
3290
  if (!sameHookSnapshot(snapshot, current)) {
3256
3291
  throw new ConcurrentHookModificationError(hookPath);
3257
3292
  }
3258
- await (0, import_promises4.rename)(temporaryPath, hookPath);
3293
+ await (0, import_promises5.rename)(temporaryPath, hookPath);
3259
3294
  temporaryExists = false;
3260
3295
  } finally {
3261
3296
  if (temporaryExists) {
3262
- await (0, import_promises4.unlink)(temporaryPath).catch((error) => {
3297
+ await (0, import_promises5.unlink)(temporaryPath).catch((error) => {
3263
3298
  if (error.code !== "ENOENT") {
3264
3299
  throw error;
3265
3300
  }
@@ -3285,14 +3320,14 @@ function findManagedRange(content, begin, end) {
3285
3320
  end: endLine < 0 ? content.length : endLine + 1
3286
3321
  };
3287
3322
  }
3288
- var import_node_fs3, import_node_crypto2, import_promises4, import_node_path5, DEFAULT_MARKER_ID, MANAGED_STATE_PREFIX, UnsupportedHookInterpreterError, SymlinkHookUnsupportedError, UnsupportedHookTypeError, InvalidManagedHookStateError, ConcurrentHookModificationError, HookTransactionRollbackError;
3323
+ var import_node_fs3, import_node_crypto2, import_promises5, import_node_path6, DEFAULT_MARKER_ID, MANAGED_STATE_PREFIX, UnsupportedHookInterpreterError, SymlinkHookUnsupportedError, UnsupportedHookTypeError, InvalidManagedHookStateError, ConcurrentHookModificationError, HookTransactionRollbackError;
3289
3324
  var init_hook_installer = __esm({
3290
3325
  "src/hook-installer.ts"() {
3291
3326
  "use strict";
3292
3327
  import_node_fs3 = require("fs");
3293
3328
  import_node_crypto2 = require("crypto");
3294
- import_promises4 = require("fs/promises");
3295
- import_node_path5 = require("path");
3329
+ import_promises5 = require("fs/promises");
3330
+ import_node_path6 = require("path");
3296
3331
  DEFAULT_MARKER_ID = "artifact-chain-assistant";
3297
3332
  MANAGED_STATE_PREFIX = "# artifact-chain-assistant managed state v1:";
3298
3333
  UnsupportedHookInterpreterError = class extends Error {
@@ -3959,7 +3994,7 @@ function validatePolicyCompatibility(policy, baseContract) {
3959
3994
  };
3960
3995
  }
3961
3996
  async function loadContract(contractPath, options) {
3962
- const rawContent = await (0, import_promises5.readFile)(contractPath, "utf-8");
3997
+ const rawContent = await (0, import_promises6.readFile)(contractPath, "utf-8");
3963
3998
  let schema;
3964
3999
  try {
3965
4000
  schema = JSON.parse(rawContent);
@@ -4007,10 +4042,10 @@ async function loadContract(contractPath, options) {
4007
4042
  }
4008
4043
  async function loadContractsFromDirectory(contractsDir, options) {
4009
4044
  const contracts = [];
4010
- const entries = await (0, import_promises5.readdir)(contractsDir, { withFileTypes: true });
4045
+ const entries = await (0, import_promises6.readdir)(contractsDir, { withFileTypes: true });
4011
4046
  for (const entry of entries) {
4012
4047
  if (entry.isDirectory()) {
4013
- const schemaPath = (0, import_node_path6.join)(contractsDir, entry.name, "schema.json");
4048
+ const schemaPath = (0, import_node_path7.join)(contractsDir, entry.name, "schema.json");
4014
4049
  const contract = await loadContract(schemaPath, options);
4015
4050
  contracts.push(contract);
4016
4051
  }
@@ -4125,13 +4160,13 @@ async function loadContractCatalog(contractsDir, options) {
4125
4160
  }
4126
4161
  return catalog;
4127
4162
  }
4128
- var import_node_crypto3, import_promises5, import_node_path6, import_ajv, CONTRACT_ERROR_CODES, ContractError, OFFICIAL_AUTHORITY, OFFICIAL_NAMESPACE_PATTERN, ContractRegistry, _validatorCache, E2E_NORMALIZER_CONFIG, ContractCatalog;
4163
+ var import_node_crypto3, import_promises6, import_node_path7, import_ajv, CONTRACT_ERROR_CODES, ContractError, OFFICIAL_AUTHORITY, OFFICIAL_NAMESPACE_PATTERN, ContractRegistry, _validatorCache, E2E_NORMALIZER_CONFIG, ContractCatalog;
4129
4164
  var init_contract_kernel = __esm({
4130
4165
  "src/contract-kernel.ts"() {
4131
4166
  "use strict";
4132
4167
  import_node_crypto3 = require("crypto");
4133
- import_promises5 = require("fs/promises");
4134
- import_node_path6 = require("path");
4168
+ import_promises6 = require("fs/promises");
4169
+ import_node_path7 = require("path");
4135
4170
  import_ajv = __toESM(require("ajv"), 1);
4136
4171
  CONTRACT_ERROR_CODES = {
4137
4172
  /** Contract identity not found */
@@ -4484,11 +4519,11 @@ __export(index_exports, {
4484
4519
  collectChangedPaths: () => collectChangedPaths,
4485
4520
  computeE2eCoverageStats: () => computeE2eCoverageStats,
4486
4521
  computeRevisionDigest: () => computeRevisionDigest,
4487
- dirname: () => import_node_path7.dirname,
4522
+ dirname: () => import_node_path8.dirname,
4488
4523
  discoverAndAuditPackets: () => discoverAndAuditPackets,
4489
4524
  discoverTargets: () => discoverTargets,
4490
4525
  doctorArtifactChain: () => doctorArtifactChain,
4491
- extname: () => import_node_path7.extname,
4526
+ extname: () => import_node_path8.extname,
4492
4527
  formatContextMarkdown: () => formatContextMarkdown,
4493
4528
  generateE2eRegistry: () => generateE2eRegistry,
4494
4529
  getArtifactTypeMetadata: () => getArtifactTypeMetadata,
@@ -4503,6 +4538,7 @@ __export(index_exports, {
4503
4538
  loadContract: () => loadContract,
4504
4539
  loadContractCatalog: () => loadContractCatalog,
4505
4540
  loadContractsFromDirectory: () => loadContractsFromDirectory,
4541
+ matchesConfiguredArtifactPath: () => matchesConfiguredArtifactPath,
4506
4542
  nextId: () => nextId,
4507
4543
  normalizeE2eLegacyArtifact: () => normalizeE2eLegacyArtifact,
4508
4544
  normalizeToCanonical: () => normalizeToCanonical,
@@ -4584,10 +4620,10 @@ function resolveArtifactTypeName(schema, token) {
4584
4620
  return void 0;
4585
4621
  }
4586
4622
  async function loadConfig(root) {
4587
- const configPath = (0, import_node_path7.join)(root, "artifact-graph.config.yaml");
4623
+ const configPath = (0, import_node_path8.join)(root, "artifact-graph.config.yaml");
4588
4624
  let parsed = {};
4589
4625
  try {
4590
- const raw = await (0, import_promises6.readFile)(configPath, "utf-8");
4626
+ const raw = await (0, import_promises7.readFile)(configPath, "utf-8");
4591
4627
  parsed = import_js_yaml.default.load(raw) ?? {};
4592
4628
  } catch (error) {
4593
4629
  if (error.code !== "ENOENT") {
@@ -4677,7 +4713,7 @@ function validateE2eConfig(e2e) {
4677
4713
  if (typeof runner.root !== "string" || !runner.root.trim()) {
4678
4714
  throw new Error(`Invalid e2e.runners[${runner.name}].root: must be a non-empty string.`);
4679
4715
  }
4680
- if ((0, import_node_path7.isAbsolute)(runner.root)) {
4716
+ if ((0, import_node_path8.isAbsolute)(runner.root)) {
4681
4717
  throw new Error(`Invalid e2e.runners[${runner.name}].root: "${runner.root}" must not be an absolute path.`);
4682
4718
  }
4683
4719
  if (runner.root.replace(/\\/g, "/").split("/").includes("..")) {
@@ -4761,14 +4797,14 @@ async function scanArtifacts(root, schema) {
4761
4797
  continue;
4762
4798
  }
4763
4799
  scannedFiles.set(file, type);
4764
- const raw = await (0, import_promises6.readFile)((0, import_node_path7.join)(root, file), "utf-8");
4800
+ const raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(root, file), "utf-8");
4765
4801
  const parsed = parseFile(type, file, raw, config);
4766
4802
  nodes.push(...parsed.nodes);
4767
4803
  edges.push(...parsed.edges);
4768
4804
  scanDiagnostics.push(...parsed.diagnostics);
4769
4805
  }
4770
4806
  }
4771
- const absoluteRoot = (0, import_node_path7.isAbsolute)(root) ? root : (0, import_node_path7.resolve)(root);
4807
+ const absoluteRoot = (0, import_node_path8.isAbsolute)(root) ? root : (0, import_node_path8.resolve)(root);
4772
4808
  const graph = buildGraph(nodes, edges, scanDiagnostics, absoluteRoot);
4773
4809
  return resolveMatrixEdges(graph);
4774
4810
  }
@@ -5073,7 +5109,7 @@ async function validateScenarioPrdLinkIndex(root, graph) {
5073
5109
  const indexPath = "artifacts/prd/feature-index.md";
5074
5110
  let raw = "";
5075
5111
  try {
5076
- raw = await (0, import_promises6.readFile)((0, import_node_path7.join)(root, indexPath), "utf-8");
5112
+ raw = await (0, import_promises7.readFile)((0, import_node_path8.join)(root, indexPath), "utf-8");
5077
5113
  } catch (error) {
5078
5114
  if (error.code === "ENOENT") {
5079
5115
  return [];
@@ -5263,11 +5299,11 @@ function nextId(graph, schema, type, rangeName) {
5263
5299
  throw new Error(`ID range ${type}.${rangeName} is exhausted`);
5264
5300
  }
5265
5301
  async function writeGraphCache(root, graph) {
5266
- const cacheDir = (0, import_node_path7.join)(root, ".artifact-graph");
5267
- await (0, import_promises6.mkdir)(cacheDir, { recursive: true });
5268
- await (0, import_promises6.writeFile)((0, import_node_path7.join)(cacheDir, "index.json"), `${JSON.stringify(graph, null, 2)}
5302
+ const cacheDir = (0, import_node_path8.join)(root, ".artifact-graph");
5303
+ await (0, import_promises7.mkdir)(cacheDir, { recursive: true });
5304
+ await (0, import_promises7.writeFile)((0, import_node_path8.join)(cacheDir, "index.json"), `${JSON.stringify(graph, null, 2)}
5269
5305
  `);
5270
- const db = new import_better_sqlite3.default((0, import_node_path7.join)(cacheDir, "graph.sqlite"));
5306
+ const db = new import_better_sqlite3.default((0, import_node_path8.join)(cacheDir, "graph.sqlite"));
5271
5307
  try {
5272
5308
  db.exec(`
5273
5309
  DROP TABLE IF EXISTS nodes;
@@ -5378,7 +5414,7 @@ function parseFile(type, path, raw, schema = DEFAULT_SCHEMA) {
5378
5414
  }
5379
5415
  function parseGenericMarkdown(type, path, raw, schema) {
5380
5416
  const diagnostics = [];
5381
- const ext = (0, import_node_path7.extname)(path).toLowerCase();
5417
+ const ext = (0, import_node_path8.extname)(path).toLowerCase();
5382
5418
  if (ext !== ".md" && ext !== ".markdown") {
5383
5419
  diagnostics.push(issue(
5384
5420
  "UNSUPPORTED_FORMAT",
@@ -5605,7 +5641,7 @@ function parseDecisions(path, raw) {
5605
5641
  }
5606
5642
  function isTestFile(filePath) {
5607
5643
  const normalized = filePath.replace(/\\/g, "/");
5608
- const name = (0, import_node_path7.basename)(normalized);
5644
+ const name = (0, import_node_path8.basename)(normalized);
5609
5645
  if (/\.(test|spec)\.[^.]+$/.test(name)) return true;
5610
5646
  if (/(^|\/)(tests|test|__tests__)\//.test(normalized)) return true;
5611
5647
  if (/\w+Tests?\.java$/.test(name)) return true;
@@ -5896,7 +5932,7 @@ function parseE2eTest(path, raw) {
5896
5932
  });
5897
5933
  const nodes = [];
5898
5934
  const edges = [];
5899
- const batch = String(data.test_batch ?? (0, import_node_path7.basename)(path, (0, import_node_path7.extname)(path))).trim();
5935
+ const batch = String(data.test_batch ?? (0, import_node_path8.basename)(path, (0, import_node_path8.extname)(path))).trim();
5900
5936
  const frontmatterScenarios = toArray(data.related_scenarios).map((value) => String(value).trim()).filter(Boolean);
5901
5937
  const scopeFeatures = extractCodes(String(data.scope ?? ""), "feature");
5902
5938
  const frontmatterFeatures = [.../* @__PURE__ */ new Set([...Object.keys(asRecord(data.ac_coverage)), ...scopeFeatures])];
@@ -5969,7 +6005,7 @@ function parseE2eRegistry(path, raw) {
5969
6005
  data = { parseError: error.message };
5970
6006
  }
5971
6007
  return {
5972
- nodes: [{ type: "e2e_registry", code: (0, import_node_path7.basename)(path, (0, import_node_path7.extname)(path)), title: "E2E Test Registry", path, line: 1, attrs: data }],
6008
+ nodes: [{ type: "e2e_registry", code: (0, import_node_path8.basename)(path, (0, import_node_path8.extname)(path)), title: "E2E Test Registry", path, line: 1, attrs: data }],
5973
6009
  edges: []
5974
6010
  };
5975
6011
  }
@@ -6950,10 +6986,10 @@ function validateE2eRegistry(graph) {
6950
6986
  async function validateExecutableTraceability(root, config) {
6951
6987
  const issues = [];
6952
6988
  const schema = config ?? await loadConfig(root);
6953
- const e2eDir = (0, import_node_path7.join)(root, "artifacts", "tests", "e2e");
6989
+ const e2eDir = (0, import_node_path8.join)(root, "artifacts", "tests", "e2e");
6954
6990
  let e2eFiles;
6955
6991
  try {
6956
- e2eFiles = (await (0, import_promises6.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path7.join)(e2eDir, name));
6992
+ e2eFiles = (await (0, import_promises7.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path8.join)(e2eDir, name));
6957
6993
  } catch {
6958
6994
  return [];
6959
6995
  }
@@ -6962,11 +6998,11 @@ async function validateExecutableTraceability(root, config) {
6962
6998
  const tcKeyToFields = /* @__PURE__ */ new Map();
6963
6999
  const mdBatches = /* @__PURE__ */ new Set();
6964
7000
  for (const filePath of e2eFiles) {
6965
- const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
6966
- const relPath = (0, import_node_path7.relative)(root, filePath).split("\\").join("/");
7001
+ const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
7002
+ const relPath = (0, import_node_path8.relative)(root, filePath).split("\\").join("/");
6967
7003
  const parsed = (0, import_gray_matter.default)(raw);
6968
7004
  const data = parsed.data;
6969
- const batch = String(data.test_batch ?? (0, import_node_path7.basename)(filePath, (0, import_node_path7.extname)(filePath))).trim();
7005
+ const batch = String(data.test_batch ?? (0, import_node_path8.basename)(filePath, (0, import_node_path8.extname)(filePath))).trim();
6970
7006
  const lines = raw.split(/\r?\n/);
6971
7007
  const tcStarts = [];
6972
7008
  lines.forEach((line, index) => {
@@ -6991,7 +7027,7 @@ async function validateExecutableTraceability(root, config) {
6991
7027
  }
6992
7028
  }
6993
7029
  }
6994
- const allFiles = await walk(root);
7030
+ const allFiles = await walkFiles(root);
6995
7031
  const specFiles = /* @__PURE__ */ new Set();
6996
7032
  const configuredRunners = schema.e2e?.runners ?? [];
6997
7033
  if (configuredRunners.length > 0) {
@@ -7011,23 +7047,25 @@ async function validateExecutableTraceability(root, config) {
7011
7047
  const tcAnnotationRegex = /\/\/!?\s*@(?:e2e_test|tc)\s+(\S+?)\s+\[(\w+)\]/;
7012
7048
  const tcAnnotationNoLevelRegex = /\/\/!?\s*@(?:e2e_test|tc)\s+(\S+)/;
7013
7049
  for (const specFile of specFiles) {
7014
- const fullSpecPath = (0, import_node_path7.join)(root, specFile);
7050
+ const fullSpecPath = (0, import_node_path8.join)(root, specFile);
7015
7051
  let content;
7016
7052
  try {
7017
- content = await (0, import_promises6.readFile)(fullSpecPath, "utf-8");
7053
+ content = await (0, import_promises7.readFile)(fullSpecPath, "utf-8");
7018
7054
  } catch {
7019
7055
  continue;
7020
7056
  }
7021
7057
  const level = detectTestLevel(specFile, content);
7022
7058
  const specLines = content.split(/\r?\n/);
7023
- for (let lineIndex = 0; lineIndex < specLines.length; lineIndex += 1) {
7024
- const line = specLines[lineIndex];
7025
- let match = tcAnnotationRegex.exec(line);
7059
+ const lineComments = scanCodeComments(content).filter((comment) => comment.kind === "line" && comment.standalone);
7060
+ for (const comment of lineComments) {
7061
+ const lineIndex = comment.lineNumber - 1;
7062
+ const commentText = comment.text.replace(/^!/, "");
7063
+ let match = tcAnnotationRegex.exec(`//${commentText}`);
7026
7064
  let annotatedLevel = "";
7027
7065
  if (match) {
7028
7066
  annotatedLevel = match[2];
7029
7067
  } else {
7030
- match = tcAnnotationNoLevelRegex.exec(line);
7068
+ match = tcAnnotationNoLevelRegex.exec(`//${commentText}`);
7031
7069
  }
7032
7070
  if (!match) {
7033
7071
  continue;
@@ -7054,7 +7092,7 @@ async function validateExecutableTraceability(root, config) {
7054
7092
  level: effectiveLevel,
7055
7093
  file: specFile,
7056
7094
  testName,
7057
- line: lineIndex + 1
7095
+ line: comment.lineNumber
7058
7096
  };
7059
7097
  const key = `${batch}:${tcId}`;
7060
7098
  const existing = refToSource.get(key) ?? [];
@@ -7091,7 +7129,7 @@ async function validateExecutableTraceability(root, config) {
7091
7129
  if (entry.testId) {
7092
7130
  let content;
7093
7131
  try {
7094
- content = await (0, import_promises6.readFile)((0, import_node_path7.join)(root, normalizedRefFile), "utf-8");
7132
+ content = await (0, import_promises7.readFile)((0, import_node_path8.join)(root, normalizedRefFile), "utf-8");
7095
7133
  } catch {
7096
7134
  continue;
7097
7135
  }
@@ -7268,16 +7306,16 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
7268
7306
  let withExecutableRef = 0;
7269
7307
  const statusBreakdown = {};
7270
7308
  const chainTypeBreakdown = {};
7271
- const e2eDir = (0, import_node_path7.join)(root, "artifacts", "tests", "e2e");
7309
+ const e2eDir = (0, import_node_path8.join)(root, "artifacts", "tests", "e2e");
7272
7310
  const tcFieldsMap = /* @__PURE__ */ new Map();
7273
7311
  let e2eFiles;
7274
7312
  try {
7275
- e2eFiles = (await (0, import_promises6.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path7.join)(e2eDir, name));
7313
+ e2eFiles = (await (0, import_promises7.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).map((name) => (0, import_node_path8.join)(e2eDir, name));
7276
7314
  } catch {
7277
7315
  e2eFiles = [];
7278
7316
  }
7279
7317
  for (const filePath of e2eFiles) {
7280
- const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
7318
+ const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
7281
7319
  const lines = raw.split(/\r?\n/);
7282
7320
  const tcStarts = [];
7283
7321
  lines.forEach((line, index) => {
@@ -7287,7 +7325,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
7287
7325
  }
7288
7326
  });
7289
7327
  const parsed = (0, import_gray_matter.default)(raw);
7290
- const batch = String(parsed.data.test_batch ?? (0, import_node_path7.basename)(filePath, (0, import_node_path7.extname)(filePath))).trim();
7328
+ const batch = String(parsed.data.test_batch ?? (0, import_node_path8.basename)(filePath, (0, import_node_path8.extname)(filePath))).trim();
7291
7329
  for (let i = 0; i < tcStarts.length; i++) {
7292
7330
  const start = tcStarts[i];
7293
7331
  const end = tcStarts[i + 1]?.index ?? lines.length;
@@ -7339,7 +7377,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
7339
7377
  }
7340
7378
  }
7341
7379
  const runners = (await loadConfig(root)).e2e?.runners ?? [];
7342
- const allProjectFiles = await walk(root);
7380
+ const allProjectFiles = await walkFiles(root);
7343
7381
  for (const node of e2eNodes) {
7344
7382
  const fields = tcFieldsMap.get(node.code) ?? asRecord(node.attrs?.tcFields);
7345
7383
  const status = String(fields["status"] ?? "").trim().toLowerCase();
@@ -7350,7 +7388,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
7350
7388
  let hasActiveE2eRef = false;
7351
7389
  for (const entry of parseExecutableRefLines(execRef)) {
7352
7390
  const normalized = resolveExecutableRefFile(entry.file, allProjectFiles);
7353
- if (!normalized || !(0, import_node_fs4.existsSync)((0, import_node_path7.join)(root, normalized))) continue;
7391
+ if (!normalized || !(0, import_node_fs4.existsSync)((0, import_node_path8.join)(root, normalized))) continue;
7354
7392
  const accepting = await getAcceptingRunners(root, normalized, runners);
7355
7393
  if (accepting.some((runner) => runner.kind === "e2e")) {
7356
7394
  hasActiveE2eRef = true;
@@ -7409,7 +7447,7 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
7409
7447
  const acCoverageRateByFeature = {};
7410
7448
  const featureAcMap = /* @__PURE__ */ new Map();
7411
7449
  for (const node of featureNodes) {
7412
- const acs = parseAcceptanceCriteria(await (0, import_promises6.readFile)((0, import_node_path7.join)(root, node.path), "utf-8"));
7450
+ const acs = parseAcceptanceCriteria(await (0, import_promises7.readFile)((0, import_node_path8.join)(root, node.path), "utf-8"));
7413
7451
  featureAcMap.set(node.code, new Set(acs));
7414
7452
  }
7415
7453
  const coveredAcByFeature = /* @__PURE__ */ new Map();
@@ -7451,10 +7489,10 @@ async function computeE2eCoverageStats(graph, root, thresholds = {}) {
7451
7489
  };
7452
7490
  }
7453
7491
  async function generateE2eRegistry(root, opts) {
7454
- const e2eDir = (0, import_node_path7.join)(root, "artifacts", "tests", "e2e");
7492
+ const e2eDir = (0, import_node_path8.join)(root, "artifacts", "tests", "e2e");
7455
7493
  let files;
7456
7494
  try {
7457
- files = (await (0, import_promises6.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).sort();
7495
+ files = (await (0, import_promises7.readdir)(e2eDir)).filter((name) => /^test-.*\.md$/.test(name)).sort();
7458
7496
  } catch {
7459
7497
  return {
7460
7498
  registry_version: "1.0",
@@ -7467,11 +7505,11 @@ async function generateE2eRegistry(root, opts) {
7467
7505
  const batches = [];
7468
7506
  let totalTestCases = 0;
7469
7507
  for (const file of files) {
7470
- const filePath = (0, import_node_path7.join)(e2eDir, file);
7471
- const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
7508
+ const filePath = (0, import_node_path8.join)(e2eDir, file);
7509
+ const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
7472
7510
  const parsed = (0, import_gray_matter.default)(raw);
7473
7511
  const data = parsed.data;
7474
- const batch = String(data.test_batch ?? (0, import_node_path7.basename)(file, (0, import_node_path7.extname)(file))).trim();
7512
+ const batch = String(data.test_batch ?? (0, import_node_path8.basename)(file, (0, import_node_path8.extname)(file))).trim();
7475
7513
  const relPath = `artifacts/tests/e2e/${file}`;
7476
7514
  const scope = String(data.scope ?? "").trim();
7477
7515
  const acCoverage = normalizeAcCoverageForRegistry(data.ac_coverage);
@@ -7595,10 +7633,10 @@ async function validatePartialRustEvidence(tcFields, tcKey, root, allFiles) {
7595
7633
  if (!normalizedPath) {
7596
7634
  return { hasValidPartialRust: false, detail: `partial_rust file not found: ${ref.file}` };
7597
7635
  }
7598
- const fullPath = (0, import_node_path7.join)(root, normalizedPath);
7636
+ const fullPath = (0, import_node_path8.join)(root, normalizedPath);
7599
7637
  let content;
7600
7638
  try {
7601
- content = await (0, import_promises6.readFile)(fullPath, "utf-8");
7639
+ content = await (0, import_promises7.readFile)(fullPath, "utf-8");
7602
7640
  } catch {
7603
7641
  return { hasValidPartialRust: false, detail: `partial_rust file not found: ${ref.file}` };
7604
7642
  }
@@ -7632,7 +7670,7 @@ function detectTestLevel(specFile, content) {
7632
7670
  }
7633
7671
  function resolveExecutableRefFile(refFile, allFiles) {
7634
7672
  const normalized = refFile.replace(/\\/g, "/").replace(/^\.\//, "");
7635
- if (!normalized || (0, import_node_path7.isAbsolute)(refFile) || normalized.split("/").includes("..")) {
7673
+ if (!normalized || (0, import_node_path8.isAbsolute)(refFile) || normalized.split("/").includes("..")) {
7636
7674
  return void 0;
7637
7675
  }
7638
7676
  if (allFiles.includes(normalized)) {
@@ -7707,9 +7745,9 @@ function escapeRegExp(value) {
7707
7745
  }
7708
7746
  async function hasMarkdownTc(tcKey, e2eDir) {
7709
7747
  const [batch, tcId] = tcKey.split(":");
7710
- const filePath = (0, import_node_path7.join)(e2eDir, `${batch}.md`);
7748
+ const filePath = (0, import_node_path8.join)(e2eDir, `${batch}.md`);
7711
7749
  try {
7712
- const raw = await (0, import_promises6.readFile)(filePath, "utf-8");
7750
+ const raw = await (0, import_promises7.readFile)(filePath, "utf-8");
7713
7751
  const tcRegex = new RegExp(`^#{2,3}\\s+${escapeRegExp(tcId)}\\s*[:\uFF1A]?`, "m");
7714
7752
  return tcRegex.test(raw);
7715
7753
  } catch {
@@ -7717,7 +7755,7 @@ async function hasMarkdownTc(tcKey, e2eDir) {
7717
7755
  }
7718
7756
  }
7719
7757
  async function findFiles(root, patterns) {
7720
- const all = await walk(root);
7758
+ const all = await walkFiles(root);
7721
7759
  const matched = /* @__PURE__ */ new Set();
7722
7760
  for (const pattern of patterns) {
7723
7761
  for (const file of all) {
@@ -7728,21 +7766,9 @@ async function findFiles(root, patterns) {
7728
7766
  }
7729
7767
  return [...matched].sort();
7730
7768
  }
7731
- async function walk(root, current = root) {
7732
- const entries = await (0, import_promises6.readdir)(current, { withFileTypes: true });
7733
- const files = [];
7734
- for (const entry of entries) {
7735
- if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === ".artifact-graph") {
7736
- continue;
7737
- }
7738
- const fullPath = (0, import_node_path7.join)(current, entry.name);
7739
- if (entry.isDirectory()) {
7740
- files.push(...await walk(root, fullPath));
7741
- } else {
7742
- files.push((0, import_node_path7.relative)(root, fullPath).split("\\").join("/"));
7743
- }
7744
- }
7745
- return files;
7769
+ function matchesConfiguredArtifactPath(path, schema) {
7770
+ const normalizedPath = path.replace(/\\/g, "/").replace(/^\.\//, "");
7771
+ return Object.values(schema.types).some((definition) => definition.paths.some((pattern) => matchesPattern(normalizedPath, pattern)));
7746
7772
  }
7747
7773
  function matchesPattern(file, pattern) {
7748
7774
  if (!pattern.includes("*")) {
@@ -7954,7 +7980,7 @@ function normalizeDesignCode(value) {
7954
7980
  if (!raw) {
7955
7981
  return "";
7956
7982
  }
7957
- return (0, import_node_path7.basename)(raw, (0, import_node_path7.extname)(raw));
7983
+ return (0, import_node_path8.basename)(raw, (0, import_node_path8.extname)(raw));
7958
7984
  }
7959
7985
  function toUid(type, code) {
7960
7986
  return `${type}:${code}`;
@@ -8219,7 +8245,7 @@ function resolveArtifactContext(graph, opts) {
8219
8245
  }
8220
8246
  if (root) {
8221
8247
  for (const ap of ALWAYS_PRESENT_ITEMS) {
8222
- const fullPath = (0, import_node_path7.join)(root, ap.path);
8248
+ const fullPath = (0, import_node_path8.join)(root, ap.path);
8223
8249
  let stat;
8224
8250
  try {
8225
8251
  stat = (0, import_node_fs4.statSync)(fullPath);
@@ -8449,18 +8475,19 @@ function formatContextMarkdown(manifest) {
8449
8475
  }
8450
8476
  return lines.join("\n");
8451
8477
  }
8452
- var import_better_sqlite3, import_gray_matter, import_js_yaml, import_node_fs4, import_promises6, import_node_path7, TARGET_ARTIFACT_TYPES, NON_TARGET_ROLES, DEFAULT_SCHEMA, VALID_TC_STATUSES, VALID_CHAIN_TYPES, DEPRECATED_CHAIN_TYPE_ALIASES, CONTEXT_CATEGORIES, TIER_ORDER;
8478
+ var import_better_sqlite3, import_gray_matter, import_js_yaml, import_node_fs4, import_promises7, import_node_path8, TARGET_ARTIFACT_TYPES, NON_TARGET_ROLES, DEFAULT_SCHEMA, VALID_TC_STATUSES, VALID_CHAIN_TYPES, DEPRECATED_CHAIN_TYPE_ALIASES, CONTEXT_CATEGORIES, TIER_ORDER;
8453
8479
  var init_index = __esm({
8454
8480
  "src/index.ts"() {
8455
8481
  import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
8456
8482
  import_gray_matter = __toESM(require("gray-matter"), 1);
8457
8483
  import_js_yaml = __toESM(require("js-yaml"), 1);
8458
8484
  import_node_fs4 = require("fs");
8459
- import_promises6 = require("fs/promises");
8460
- import_node_path7 = require("path");
8485
+ import_promises7 = require("fs/promises");
8486
+ import_node_path8 = require("path");
8461
8487
  init_packet_constants();
8462
8488
  init_packet_validator();
8463
8489
  init_glob_matcher();
8490
+ init_file_walker();
8464
8491
  init_packet_constants();
8465
8492
  init_target_selector();
8466
8493
  init_packet_assembler();
@@ -8611,6 +8638,7 @@ init_index();
8611
8638
  loadContract,
8612
8639
  loadContractCatalog,
8613
8640
  loadContractsFromDirectory,
8641
+ matchesConfiguredArtifactPath,
8614
8642
  nextId,
8615
8643
  normalizeE2eLegacyArtifact,
8616
8644
  normalizeToCanonical,