contract-driven-delivery 2.0.21 → 2.1.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/cli/index.js CHANGED
@@ -2774,7 +2774,7 @@ var require_fast_deep_equal = __commonJS({
2774
2774
  var require_json_schema_traverse = __commonJS({
2775
2775
  "node_modules/json-schema-traverse/index.js"(exports, module) {
2776
2776
  "use strict";
2777
- var traverse = module.exports = function(schema, opts, cb) {
2777
+ var traverse2 = module.exports = function(schema, opts, cb) {
2778
2778
  if (typeof opts == "function") {
2779
2779
  cb = opts;
2780
2780
  opts = {};
@@ -2786,7 +2786,7 @@ var require_json_schema_traverse = __commonJS({
2786
2786
  };
2787
2787
  _traverse(opts, pre, post, schema, "", schema);
2788
2788
  };
2789
- traverse.keywords = {
2789
+ traverse2.keywords = {
2790
2790
  additionalItems: true,
2791
2791
  items: true,
2792
2792
  contains: true,
@@ -2797,20 +2797,20 @@ var require_json_schema_traverse = __commonJS({
2797
2797
  then: true,
2798
2798
  else: true
2799
2799
  };
2800
- traverse.arrayKeywords = {
2800
+ traverse2.arrayKeywords = {
2801
2801
  items: true,
2802
2802
  allOf: true,
2803
2803
  anyOf: true,
2804
2804
  oneOf: true
2805
2805
  };
2806
- traverse.propsKeywords = {
2806
+ traverse2.propsKeywords = {
2807
2807
  $defs: true,
2808
2808
  definitions: true,
2809
2809
  properties: true,
2810
2810
  patternProperties: true,
2811
2811
  dependencies: true
2812
2812
  };
2813
- traverse.skipKeywords = {
2813
+ traverse2.skipKeywords = {
2814
2814
  default: true,
2815
2815
  enum: true,
2816
2816
  const: true,
@@ -2836,16 +2836,16 @@ var require_json_schema_traverse = __commonJS({
2836
2836
  for (var key in schema) {
2837
2837
  var sch = schema[key];
2838
2838
  if (Array.isArray(sch)) {
2839
- if (key in traverse.arrayKeywords) {
2839
+ if (key in traverse2.arrayKeywords) {
2840
2840
  for (var i = 0; i < sch.length; i++)
2841
2841
  _traverse(opts, pre, post, sch[i], jsonPtr + "/" + key + "/" + i, rootSchema, jsonPtr, key, schema, i);
2842
2842
  }
2843
- } else if (key in traverse.propsKeywords) {
2843
+ } else if (key in traverse2.propsKeywords) {
2844
2844
  if (sch && typeof sch == "object") {
2845
2845
  for (var prop in sch)
2846
2846
  _traverse(opts, pre, post, sch[prop], jsonPtr + "/" + key + "/" + escapeJsonPtr(prop), rootSchema, jsonPtr, key, schema, prop);
2847
2847
  }
2848
- } else if (key in traverse.keywords || opts.allKeys && !(key in traverse.skipKeywords)) {
2848
+ } else if (key in traverse2.keywords || opts.allKeys && !(key in traverse2.skipKeywords)) {
2849
2849
  _traverse(opts, pre, post, sch, jsonPtr + "/" + key, rootSchema, jsonPtr, key, schema);
2850
2850
  }
2851
2851
  }
@@ -2866,7 +2866,7 @@ var require_resolve = __commonJS({
2866
2866
  exports.getSchemaRefs = exports.resolveUrl = exports.normalizeId = exports._getFullPath = exports.getFullPath = exports.inlineRef = void 0;
2867
2867
  var util_1 = require_util();
2868
2868
  var equal = require_fast_deep_equal();
2869
- var traverse = require_json_schema_traverse();
2869
+ var traverse2 = require_json_schema_traverse();
2870
2870
  var SIMPLE_INLINED = /* @__PURE__ */ new Set([
2871
2871
  "type",
2872
2872
  "format",
@@ -2962,7 +2962,7 @@ var require_resolve = __commonJS({
2962
2962
  const pathPrefix = getFullPath(uriResolver, schId, false);
2963
2963
  const localRefs = {};
2964
2964
  const schemaRefs = /* @__PURE__ */ new Set();
2965
- traverse(schema, { allKeys: true }, (sch, jsonPtr, _, parentJsonPtr) => {
2965
+ traverse2(schema, { allKeys: true }, (sch, jsonPtr, _, parentJsonPtr) => {
2966
2966
  if (parentJsonPtr === void 0)
2967
2967
  return;
2968
2968
  const fullPath = pathPrefix + jsonPtr;
@@ -8608,6 +8608,351 @@ var init_index_reader = __esm({
8608
8608
  }
8609
8609
  });
8610
8610
 
8611
+ // src/code-graph/builder.ts
8612
+ import { createHash as createHash5 } from "crypto";
8613
+ import { posix } from "path";
8614
+ function stableId(parts) {
8615
+ return createHash5("sha1").update(parts.join("\0")).digest("hex").slice(0, 16);
8616
+ }
8617
+ function nodeId(filePath, kind, name, startLine) {
8618
+ return `n:${stableId([filePath, kind, name, String(startLine)])}`;
8619
+ }
8620
+ function edgeId(source, target, kind, line, name) {
8621
+ return `e:${stableId([source, target, kind, String(line ?? 0), name ?? ""])}`;
8622
+ }
8623
+ function fileNode(path, totalLines) {
8624
+ return {
8625
+ id: nodeId(path, "file", path, 1),
8626
+ kind: "file",
8627
+ name: posix.basename(path),
8628
+ qualified_name: path,
8629
+ file_path: path,
8630
+ start_line: totalLines > 0 ? 1 : 0,
8631
+ end_line: totalLines
8632
+ };
8633
+ }
8634
+ function symbolNode(filePath, kind, name, lines, exported) {
8635
+ const start = lines[0] ?? 1;
8636
+ const end = lines[1] ?? start;
8637
+ return {
8638
+ id: nodeId(filePath, kind, name, start),
8639
+ kind,
8640
+ name,
8641
+ qualified_name: `${filePath}::${name}`,
8642
+ file_path: filePath,
8643
+ start_line: start,
8644
+ end_line: end,
8645
+ ...exported !== void 0 ? { exported } : {}
8646
+ };
8647
+ }
8648
+ function addEdge(edges, source, target, kind, line, provenance, metadata) {
8649
+ edges.push({
8650
+ id: edgeId(source, target, kind, line, metadata?.name),
8651
+ source,
8652
+ target,
8653
+ kind,
8654
+ ...line ? { line } : {},
8655
+ provenance,
8656
+ ...metadata ? { metadata } : {}
8657
+ });
8658
+ }
8659
+ function isLocalImport(moduleName) {
8660
+ return moduleName.startsWith(".");
8661
+ }
8662
+ function resolvePythonRelativeImport(importerPath, moduleName) {
8663
+ const match = moduleName.match(/^(\.+)(.*)$/);
8664
+ if (!match)
8665
+ return moduleName;
8666
+ const upLevels = Math.max(0, match[1].length - 1);
8667
+ let baseDir = posix.dirname(importerPath);
8668
+ for (let i = 0; i < upLevels; i++) {
8669
+ baseDir = posix.dirname(baseDir);
8670
+ }
8671
+ const rest = match[2].replace(/^\./, "").replace(/\./g, "/");
8672
+ return rest ? posix.normalize(posix.join(baseDir, rest)) : baseDir;
8673
+ }
8674
+ function resolutionCandidates(base) {
8675
+ const ext = posix.extname(base);
8676
+ const candidates = [];
8677
+ if (ext) {
8678
+ candidates.push(base);
8679
+ const withoutExt = base.slice(0, -ext.length);
8680
+ if ([".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
8681
+ candidates.push(`${withoutExt}.ts`, `${withoutExt}.tsx`, `${withoutExt}.vue`);
8682
+ }
8683
+ } else {
8684
+ for (const candidateExt of RESOLUTION_EXTENSIONS) {
8685
+ candidates.push(`${base}${candidateExt}`);
8686
+ }
8687
+ }
8688
+ for (const candidateExt of RESOLUTION_EXTENSIONS) {
8689
+ candidates.push(posix.join(base, `index${candidateExt}`));
8690
+ }
8691
+ candidates.push(posix.join(base, "__init__.py"));
8692
+ return [...new Set(candidates)];
8693
+ }
8694
+ function resolveLocalModule(importerPath, moduleName, pathSet) {
8695
+ if (!isLocalImport(moduleName))
8696
+ return void 0;
8697
+ const base = moduleName.startsWith("./") || moduleName.startsWith("../") ? posix.normalize(posix.join(posix.dirname(importerPath), moduleName)) : resolvePythonRelativeImport(importerPath, moduleName);
8698
+ for (const candidate of resolutionCandidates(base)) {
8699
+ if (pathSet.has(candidate))
8700
+ return candidate;
8701
+ }
8702
+ return void 0;
8703
+ }
8704
+ function importedBindings(imp, resolvedPath) {
8705
+ const out = [];
8706
+ for (const item of imp.items ?? []) {
8707
+ if (item.startsWith("default:")) {
8708
+ const local = item.slice("default:".length);
8709
+ out.push({ local, imported: "default", ...resolvedPath ? { resolvedPath } : {} });
8710
+ } else if (item.startsWith("*:")) {
8711
+ const local = item.slice("*:".length);
8712
+ out.push({ local, imported: "*", ...resolvedPath ? { resolvedPath } : {} });
8713
+ } else if (/^[A-Za-z_$][\w$]*:[A-Za-z_$][\w$]*$/.test(item)) {
8714
+ const [imported, local] = item.split(":");
8715
+ out.push({ local, imported, ...resolvedPath ? { resolvedPath } : {} });
8716
+ } else {
8717
+ out.push({ local: item, imported: item, ...resolvedPath ? { resolvedPath } : {} });
8718
+ }
8719
+ }
8720
+ return out;
8721
+ }
8722
+ function simpleName(name) {
8723
+ return name.replace(/^async\s+/, "").split(".").pop() ?? name;
8724
+ }
8725
+ function isWithin(node, line) {
8726
+ return node.start_line <= line && line <= node.end_line;
8727
+ }
8728
+ function findCallerNode(nodes, caller, line) {
8729
+ const exact = nodes.find((n) => n.name === caller || n.qualified_name.endsWith(`::${caller}`));
8730
+ if (exact)
8731
+ return exact;
8732
+ return nodes.filter((n) => (n.kind === "function" || n.kind === "method") && isWithin(n, line)).sort((a, b) => a.end_line - a.start_line - (b.end_line - b.start_line))[0];
8733
+ }
8734
+ function buildCodeGraph(entries, opts) {
8735
+ const nodes = [];
8736
+ const edges = [];
8737
+ const unresolved = [];
8738
+ const files = [];
8739
+ const pathSet = new Set(entries.map((e) => e.path));
8740
+ const fileNodes = /* @__PURE__ */ new Map();
8741
+ const nodesByFile = /* @__PURE__ */ new Map();
8742
+ const symbolsByFile = /* @__PURE__ */ new Map();
8743
+ const globalSymbols = /* @__PURE__ */ new Map();
8744
+ const registerSymbol = (filePath, node, exported) => {
8745
+ nodes.push(node);
8746
+ const fileMap = symbolsByFile.get(filePath) ?? /* @__PURE__ */ new Map();
8747
+ const target = { node, exported };
8748
+ fileMap.set(node.name, [...fileMap.get(node.name) ?? [], target]);
8749
+ const shortName = simpleName(node.name);
8750
+ if (shortName !== node.name) {
8751
+ fileMap.set(shortName, [...fileMap.get(shortName) ?? [], target]);
8752
+ }
8753
+ symbolsByFile.set(filePath, fileMap);
8754
+ globalSymbols.set(node.name, [...globalSymbols.get(node.name) ?? [], target]);
8755
+ if (shortName !== node.name) {
8756
+ globalSymbols.set(shortName, [...globalSymbols.get(shortName) ?? [], target]);
8757
+ }
8758
+ };
8759
+ for (const entry of entries) {
8760
+ const file = fileNode(entry.path, entry.total_lines);
8761
+ fileNodes.set(entry.path, file);
8762
+ nodesByFile.set(entry.path, [file]);
8763
+ nodes.push(file);
8764
+ }
8765
+ for (const entry of entries) {
8766
+ const file = fileNodes.get(entry.path);
8767
+ const localNodes = nodesByFile.get(entry.path);
8768
+ for (const c of entry.classes) {
8769
+ const n = symbolNode(entry.path, "class", c.name, c.lines, c.exported);
8770
+ localNodes.push(n);
8771
+ registerSymbol(entry.path, n, c.exported === true);
8772
+ addEdge(edges, file.id, n.id, "contains", c.lines[0], "codemap");
8773
+ for (const m of c.methods ?? []) {
8774
+ const methodName = `${c.name}.${m.name}`;
8775
+ const mn = symbolNode(entry.path, "method", methodName, m.lines);
8776
+ localNodes.push(mn);
8777
+ registerSymbol(entry.path, mn, false);
8778
+ addEdge(edges, n.id, mn.id, "contains", m.lines[0], "codemap");
8779
+ }
8780
+ }
8781
+ for (const f of entry.functions) {
8782
+ const n = symbolNode(entry.path, "function", f.name, f.lines, f.exported);
8783
+ localNodes.push(n);
8784
+ registerSymbol(entry.path, n, f.exported === true);
8785
+ addEdge(edges, file.id, n.id, "contains", f.lines[0], "codemap");
8786
+ }
8787
+ for (const t of entry.interfaces ?? []) {
8788
+ const n = symbolNode(entry.path, "interface", t.name, t.lines, t.exported);
8789
+ localNodes.push(n);
8790
+ registerSymbol(entry.path, n, t.exported === true);
8791
+ addEdge(edges, file.id, n.id, "contains", t.lines[0], "codemap");
8792
+ }
8793
+ for (const t of entry.types ?? []) {
8794
+ const n = symbolNode(entry.path, "type_alias", t.name, t.lines, t.exported);
8795
+ localNodes.push(n);
8796
+ registerSymbol(entry.path, n, t.exported === true);
8797
+ addEdge(edges, file.id, n.id, "contains", t.lines[0], "codemap");
8798
+ }
8799
+ for (const e of entry.enums ?? []) {
8800
+ const n = symbolNode(entry.path, "enum", e.name, e.lines, e.exported);
8801
+ localNodes.push(n);
8802
+ registerSymbol(entry.path, n, e.exported === true);
8803
+ addEdge(edges, file.id, n.id, "contains", e.lines[0], "codemap");
8804
+ }
8805
+ for (const c of entry.constants) {
8806
+ const n = symbolNode(entry.path, "constant", c.name, [c.line, c.line], true);
8807
+ localNodes.push(n);
8808
+ registerSymbol(entry.path, n, true);
8809
+ addEdge(edges, file.id, n.id, "contains", c.line, "codemap");
8810
+ }
8811
+ }
8812
+ const importBindingsByFile = /* @__PURE__ */ new Map();
8813
+ for (const entry of entries) {
8814
+ const file = fileNodes.get(entry.path);
8815
+ const bindings = /* @__PURE__ */ new Map();
8816
+ importBindingsByFile.set(entry.path, bindings);
8817
+ for (const imp of entry.imports) {
8818
+ const resolved = resolveLocalModule(entry.path, imp.module, pathSet);
8819
+ if (resolved) {
8820
+ addEdge(edges, file.id, fileNodes.get(resolved).id, "imports", imp.line, "ast", { module: imp.module });
8821
+ }
8822
+ for (const binding of importedBindings(imp, resolved)) {
8823
+ if (!binding.resolvedPath)
8824
+ continue;
8825
+ const fileSymbols = symbolsByFile.get(binding.resolvedPath);
8826
+ const candidates = binding.imported === "*" ? Array.from(fileSymbols?.values() ?? []).flat() : fileSymbols?.get(binding.imported) ?? [];
8827
+ const exported = candidates.filter((c) => c.exported || candidates.length === 1);
8828
+ if (exported.length > 0) {
8829
+ bindings.set(binding.local, [...bindings.get(binding.local) ?? [], ...exported]);
8830
+ }
8831
+ }
8832
+ }
8833
+ }
8834
+ for (const entry of entries) {
8835
+ const localNodes = nodesByFile.get(entry.path) ?? [];
8836
+ const localSymbols = symbolsByFile.get(entry.path) ?? /* @__PURE__ */ new Map();
8837
+ const importBindings = importBindingsByFile.get(entry.path) ?? /* @__PURE__ */ new Map();
8838
+ for (const c of entry.classes) {
8839
+ const source = localSymbols.get(c.name)?.[0]?.node;
8840
+ if (!source)
8841
+ continue;
8842
+ for (const base of c.extends ?? []) {
8843
+ const target = resolveSymbol(base, entry.path, localSymbols, importBindings, globalSymbols);
8844
+ if (target)
8845
+ addEdge(edges, source.id, target.node.id, "extends", c.lines[0], "ast", { name: base });
8846
+ else
8847
+ unresolved.push({ from: source.id, kind: "extends", name: base, line: c.lines[0], file_path: entry.path });
8848
+ }
8849
+ for (const iface of c.implements ?? []) {
8850
+ const target = resolveSymbol(iface, entry.path, localSymbols, importBindings, globalSymbols);
8851
+ if (target)
8852
+ addEdge(edges, source.id, target.node.id, "implements", c.lines[0], "ast", { name: iface });
8853
+ else
8854
+ unresolved.push({ from: source.id, kind: "implements", name: iface, line: c.lines[0], file_path: entry.path });
8855
+ }
8856
+ }
8857
+ for (const call of entry.calls ?? []) {
8858
+ const caller = findCallerNode(localNodes, call.caller, call.line);
8859
+ if (!caller)
8860
+ continue;
8861
+ const target = resolveSymbol(call.callee, entry.path, localSymbols, importBindings, globalSymbols);
8862
+ if (target) {
8863
+ addEdge(edges, caller.id, target.node.id, "calls", call.line, "ast", { name: call.callee });
8864
+ } else {
8865
+ unresolved.push({ from: caller.id, kind: "calls", name: call.callee, line: call.line, file_path: entry.path });
8866
+ }
8867
+ }
8868
+ }
8869
+ const uniqueNodes = dedupeBy(nodes, (n) => n.id);
8870
+ const uniqueEdges = dedupeBy(edges, (e) => e.id);
8871
+ for (const entry of entries) {
8872
+ files.push({
8873
+ path: entry.path,
8874
+ total_lines: entry.total_lines,
8875
+ node_count: uniqueNodes.filter((n) => n.file_path === entry.path).length
8876
+ });
8877
+ }
8878
+ return {
8879
+ schema_version: "1.0",
8880
+ generator: opts.generator,
8881
+ sources_digest: opts.sourcesDigest,
8882
+ files,
8883
+ nodes: uniqueNodes.sort((a, b) => a.file_path.localeCompare(b.file_path) || a.start_line - b.start_line || a.kind.localeCompare(b.kind) || a.name.localeCompare(b.name)),
8884
+ edges: uniqueEdges.sort((a, b) => a.source.localeCompare(b.source) || a.kind.localeCompare(b.kind) || a.target.localeCompare(b.target)),
8885
+ unresolved: unresolved.sort((a, b) => a.file_path.localeCompare(b.file_path) || a.line - b.line || a.name.localeCompare(b.name))
8886
+ };
8887
+ }
8888
+ function resolveSymbol(rawName, filePath, localSymbols, importBindings, globalSymbols) {
8889
+ const candidates = symbolLookupNames(rawName);
8890
+ for (const name of candidates) {
8891
+ const imported = importBindings.get(name);
8892
+ if (imported?.length === 1)
8893
+ return imported[0];
8894
+ }
8895
+ for (const name of candidates) {
8896
+ const local = localSymbols.get(name);
8897
+ if (local?.length === 1)
8898
+ return local[0];
8899
+ }
8900
+ for (const name of candidates) {
8901
+ const global = (globalSymbols.get(name) ?? []).filter((t) => t.node.file_path !== filePath || t.exported);
8902
+ if (global.length === 1)
8903
+ return global[0];
8904
+ }
8905
+ return void 0;
8906
+ }
8907
+ function symbolLookupNames(name) {
8908
+ const cleaned = name.replace(/^this\./, "").replace(/^self\./, "");
8909
+ const parts = cleaned.split(".").filter(Boolean);
8910
+ return [.../* @__PURE__ */ new Set([cleaned, parts[parts.length - 1] ?? cleaned])];
8911
+ }
8912
+ function dedupeBy(items, key) {
8913
+ const seen = /* @__PURE__ */ new Set();
8914
+ const out = [];
8915
+ for (const item of items) {
8916
+ const k = key(item);
8917
+ if (seen.has(k))
8918
+ continue;
8919
+ seen.add(k);
8920
+ out.push(item);
8921
+ }
8922
+ return out;
8923
+ }
8924
+ var RESOLUTION_EXTENSIONS;
8925
+ var init_builder = __esm({
8926
+ "src/code-graph/builder.ts"() {
8927
+ "use strict";
8928
+ RESOLUTION_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".vue", ".py"];
8929
+ }
8930
+ });
8931
+
8932
+ // src/code-graph/reader.ts
8933
+ import { existsSync as existsSync18, readFileSync as readFileSync17 } from "fs";
8934
+ function graphPathFor(mapPath) {
8935
+ const match = mapPath.match(/^(.*?)(?:code-map)(.*)\.ya?ml$/i);
8936
+ if (match)
8937
+ return `${match[1]}code-graph${match[2]}.index.json`;
8938
+ return `${mapPath.replace(/\.ya?ml$/i, "")}.graph.json`;
8939
+ }
8940
+ function loadCodeGraph(graphPath) {
8941
+ if (!existsSync18(graphPath)) {
8942
+ throw new Error(`${graphPath} is missing; run \`cdd-kit code-map\` first.`);
8943
+ }
8944
+ const raw = JSON.parse(readFileSync17(graphPath, "utf8"));
8945
+ if (!raw || raw.schema_version !== "1.0" || !Array.isArray(raw.nodes) || !Array.isArray(raw.edges)) {
8946
+ throw new Error(`${graphPath} is not a cdd-kit code graph v1 index.`);
8947
+ }
8948
+ return raw;
8949
+ }
8950
+ var init_reader = __esm({
8951
+ "src/code-graph/reader.ts"() {
8952
+ "use strict";
8953
+ }
8954
+ });
8955
+
8611
8956
  // src/code-map/worker-dispatch.ts
8612
8957
  var worker_dispatch_exports = {};
8613
8958
  __export(worker_dispatch_exports, {
@@ -8864,14 +9209,20 @@ var init_python = __esm({
8864
9209
  name: m.name,
8865
9210
  lines: [m.lines[0], m.lines[1]],
8866
9211
  async: m.async
8867
- }))
9212
+ })),
9213
+ extends: c.extends ?? [],
9214
+ implements: c.implements ?? [],
9215
+ exported: c.exported
8868
9216
  })),
8869
9217
  functions: (r.functions ?? []).map((f) => ({
8870
9218
  name: f.name,
8871
9219
  lines: [f.lines[0], f.lines[1]],
8872
9220
  decorators: f.decorators ?? [],
8873
- async: f.async
8874
- }))
9221
+ async: f.async,
9222
+ exported: f.exported
9223
+ })),
9224
+ calls: r.calls ?? [],
9225
+ exports: r.exports ?? []
8875
9226
  });
8876
9227
  }
8877
9228
  if (exitCode === 2) {
@@ -8897,7 +9248,7 @@ __export(javascript_exports, {
8897
9248
  parseJsSource: () => parseJsSource,
8898
9249
  parseSourceWithPlugins: () => parseSourceWithPlugins
8899
9250
  });
8900
- import { readFileSync as readFileSync18 } from "fs";
9251
+ import { readFileSync as readFileSync19 } from "fs";
8901
9252
  import { parse } from "@babel/parser";
8902
9253
  function parseSourceWithPlugins(source, plugins) {
8903
9254
  return parse(source, {
@@ -8930,6 +9281,51 @@ function getLineRange(node) {
8930
9281
  const end = node.loc?.end.line ?? start;
8931
9282
  return [start, end];
8932
9283
  }
9284
+ function expressionName(node) {
9285
+ if (!node)
9286
+ return null;
9287
+ if (node.type === "Identifier")
9288
+ return node.name;
9289
+ if (node.type === "ThisExpression")
9290
+ return "this";
9291
+ if (node.type === "Super")
9292
+ return "super";
9293
+ if (node.type === "PrivateName")
9294
+ return `#${node.id?.name ?? "private"}`;
9295
+ if (node.type === "StringLiteral")
9296
+ return node.value;
9297
+ if (node.type === "MemberExpression" || node.type === "OptionalMemberExpression") {
9298
+ const object = expressionName(node.object);
9299
+ const prop = node.computed ? expressionName(node.property) : expressionName(node.property);
9300
+ if (object && prop)
9301
+ return `${object}.${prop}`;
9302
+ return prop ?? object;
9303
+ }
9304
+ if (node.type === "CallExpression" || node.type === "OptionalCallExpression")
9305
+ return expressionName(node.callee);
9306
+ if (node.type === "TSExpressionWithTypeArguments")
9307
+ return expressionName(node.expression);
9308
+ return null;
9309
+ }
9310
+ function collectCalls(node, caller, calls) {
9311
+ if (!node || typeof node !== "object")
9312
+ return;
9313
+ if (node.type === "CallExpression" || node.type === "OptionalCallExpression" || node.type === "NewExpression") {
9314
+ const callee = expressionName(node.callee);
9315
+ if (callee)
9316
+ calls.push({ caller, callee, line: node.loc?.start.line ?? 1 });
9317
+ }
9318
+ for (const value of Object.values(node)) {
9319
+ if (!value)
9320
+ continue;
9321
+ if (Array.isArray(value)) {
9322
+ for (const item of value)
9323
+ collectCalls(item, caller, calls);
9324
+ } else if (typeof value === "object" && "type" in value) {
9325
+ collectCalls(value, caller, calls);
9326
+ }
9327
+ }
9328
+ }
8933
9329
  function processImportDeclaration(node) {
8934
9330
  const items = [];
8935
9331
  for (const spec of node.specifiers) {
@@ -8939,7 +9335,8 @@ function processImportDeclaration(node) {
8939
9335
  items.push(`*:${spec.local.name}`);
8940
9336
  } else if (spec.type === "ImportSpecifier") {
8941
9337
  const imported = spec.imported;
8942
- items.push(imported.type === "Identifier" ? imported.name : spec.local.name);
9338
+ const importedName = imported.type === "Identifier" ? imported.name : imported.value;
9339
+ items.push(spec.local.name !== importedName ? `${importedName}:${spec.local.name}` : importedName);
8943
9340
  }
8944
9341
  }
8945
9342
  return {
@@ -8948,7 +9345,7 @@ function processImportDeclaration(node) {
8948
9345
  line: node.loc?.start.line ?? 1
8949
9346
  };
8950
9347
  }
8951
- function processFunctionDeclaration(node, nameOverride) {
9348
+ function processFunctionDeclaration(node, nameOverride, exported = false) {
8952
9349
  const name = nameOverride ?? node.id?.name;
8953
9350
  if (!name)
8954
9351
  return null;
@@ -8956,10 +9353,11 @@ function processFunctionDeclaration(node, nameOverride) {
8956
9353
  name,
8957
9354
  lines: getLineRange(node),
8958
9355
  decorators: [],
8959
- async: node.async
9356
+ async: node.async,
9357
+ exported
8960
9358
  };
8961
9359
  }
8962
- function processClassDeclaration(node, nameOverride) {
9360
+ function processClassDeclaration(node, nameOverride, exported = false) {
8963
9361
  const name = nameOverride ?? node.id?.name;
8964
9362
  if (!name)
8965
9363
  return null;
@@ -8985,10 +9383,13 @@ function processClassDeclaration(node, nameOverride) {
8985
9383
  return {
8986
9384
  name,
8987
9385
  lines: getLineRange(node),
8988
- methods
9386
+ methods,
9387
+ extends: node.superClass ? [expressionName(node.superClass) ?? "<computed>"] : [],
9388
+ implements: (node.implements ?? []).map((impl) => impl?.expression ? expressionName(impl.expression) : impl?.id?.name).filter(Boolean),
9389
+ exported
8989
9390
  };
8990
9391
  }
8991
- function processVariableDeclaration(node, imports, constants, functions) {
9392
+ function processVariableDeclaration(node, imports, constants, functions, calls, exports, exportedFromWrapper = false) {
8992
9393
  for (const decl of node.declarations) {
8993
9394
  if (!decl.id || decl.id.type !== "Identifier")
8994
9395
  continue;
@@ -9003,6 +9404,8 @@ function processVariableDeclaration(node, imports, constants, functions) {
9003
9404
  }
9004
9405
  if (isAllCapsConst(varName) && init2 !== null && init2 !== void 0) {
9005
9406
  constants.push({ name: varName, line: node.loc?.start.line ?? 1 });
9407
+ if (exportedFromWrapper)
9408
+ exports.push({ name: varName, kind: "constant", line: node.loc?.start.line ?? 1 });
9006
9409
  continue;
9007
9410
  }
9008
9411
  if (init2 && (init2.type === "ArrowFunctionExpression" || init2.type === "FunctionExpression")) {
@@ -9010,15 +9413,23 @@ function processVariableDeclaration(node, imports, constants, functions) {
9010
9413
  name: varName,
9011
9414
  lines: getLineRange(node),
9012
9415
  decorators: [],
9013
- async: init2.async
9416
+ async: init2.async,
9417
+ exported: exportedFromWrapper
9014
9418
  });
9419
+ collectCalls(init2.body, varName, calls);
9420
+ if (exportedFromWrapper)
9421
+ exports.push({ name: varName, kind: "function", line: node.loc?.start.line ?? 1 });
9015
9422
  } else if (init2 && init2.type === "CallExpression" && /^[A-Z]/.test(varName)) {
9016
9423
  functions.push({
9017
9424
  name: varName,
9018
9425
  lines: getLineRange(node),
9019
9426
  decorators: [],
9020
- async: false
9427
+ async: false,
9428
+ exported: exportedFromWrapper
9021
9429
  });
9430
+ collectCalls(init2, varName, calls);
9431
+ if (exportedFromWrapper)
9432
+ exports.push({ name: varName, kind: "function", line: node.loc?.start.line ?? 1 });
9022
9433
  }
9023
9434
  }
9024
9435
  }
@@ -9070,16 +9481,31 @@ function processStatement(stmt, buckets, extractTsTypes, exportedFromWrapper = f
9070
9481
  processStatement(stmt.declaration, buckets, extractTsTypes, true);
9071
9482
  return;
9072
9483
  }
9484
+ if (stmt.type === "ExportNamedDeclaration" && !stmt.declaration) {
9485
+ for (const spec of stmt.specifiers ?? []) {
9486
+ if (spec.type === "ExportSpecifier") {
9487
+ const exported = spec.exported.type === "Identifier" ? spec.exported.name : spec.exported.value;
9488
+ buckets.exports.push({ name: exported, kind: "unknown", line: stmt.loc?.start.line ?? 1 });
9489
+ }
9490
+ }
9491
+ return;
9492
+ }
9073
9493
  if (stmt.type === "ExportDefaultDeclaration") {
9074
9494
  const decl = stmt.declaration;
9075
9495
  if (decl.type === "FunctionDeclaration") {
9076
- const fe = processFunctionDeclaration(decl, decl.id?.name ?? "default");
9496
+ const fe = processFunctionDeclaration(decl, decl.id?.name ?? "default", true);
9077
9497
  if (fe)
9078
9498
  buckets.functions.push(fe);
9499
+ if (fe)
9500
+ buckets.exports.push({ name: fe.name, kind: "function", line: fe.lines[0] });
9501
+ if (fe)
9502
+ collectCalls(decl.body, fe.name, buckets.calls);
9079
9503
  } else if (decl.type === "ClassDeclaration") {
9080
- const ce = processClassDeclaration(decl, decl.id?.name ?? "default");
9504
+ const ce = processClassDeclaration(decl, decl.id?.name ?? "default", true);
9081
9505
  if (ce)
9082
9506
  buckets.classes.push(ce);
9507
+ if (ce)
9508
+ buckets.exports.push({ name: ce.name, kind: "class", line: ce.lines[0] });
9083
9509
  }
9084
9510
  return;
9085
9511
  }
@@ -9088,19 +9514,35 @@ function processStatement(stmt, buckets, extractTsTypes, exportedFromWrapper = f
9088
9514
  return;
9089
9515
  }
9090
9516
  if (stmt.type === "FunctionDeclaration") {
9091
- const fe = processFunctionDeclaration(stmt);
9517
+ const fe = processFunctionDeclaration(stmt, void 0, exportedFromWrapper);
9092
9518
  if (fe)
9093
9519
  buckets.functions.push(fe);
9520
+ if (fe) {
9521
+ collectCalls(stmt.body, fe.name, buckets.calls);
9522
+ if (exportedFromWrapper)
9523
+ buckets.exports.push({ name: fe.name, kind: "function", line: fe.lines[0] });
9524
+ }
9094
9525
  return;
9095
9526
  }
9096
9527
  if (stmt.type === "ClassDeclaration") {
9097
- const ce = processClassDeclaration(stmt);
9528
+ const ce = processClassDeclaration(stmt, void 0, exportedFromWrapper);
9098
9529
  if (ce)
9099
9530
  buckets.classes.push(ce);
9531
+ if (ce && exportedFromWrapper)
9532
+ buckets.exports.push({ name: ce.name, kind: "class", line: ce.lines[0] });
9533
+ if (ce) {
9534
+ for (const member of stmt.body.body) {
9535
+ if (member.type === "ClassMethod" || member.type === "ClassPrivateMethod") {
9536
+ const method = ce.methods.find((m) => m.lines[0] === (member.loc?.start.line ?? 0));
9537
+ if (method)
9538
+ collectCalls(member.body, `${ce.name}.${method.name}`, buckets.calls);
9539
+ }
9540
+ }
9541
+ }
9100
9542
  return;
9101
9543
  }
9102
9544
  if (stmt.type === "VariableDeclaration") {
9103
- processVariableDeclaration(stmt, buckets.imports, buckets.constants, buckets.functions);
9545
+ processVariableDeclaration(stmt, buckets.imports, buckets.constants, buckets.functions, buckets.calls, buckets.exports, exportedFromWrapper);
9104
9546
  return;
9105
9547
  }
9106
9548
  if (extractTsTypes) {
@@ -9109,18 +9551,24 @@ function processStatement(stmt, buckets, extractTsTypes, exportedFromWrapper = f
9109
9551
  const e = processTsInterfaceDeclaration(anyStmt, exportedFromWrapper);
9110
9552
  if (e)
9111
9553
  buckets.interfaces.push(e);
9554
+ if (e && exportedFromWrapper)
9555
+ buckets.exports.push({ name: e.name, kind: "interface", line: e.lines[0] });
9112
9556
  return;
9113
9557
  }
9114
9558
  if (anyStmt.type === "TSTypeAliasDeclaration") {
9115
9559
  const e = processTsTypeAliasDeclaration(anyStmt, exportedFromWrapper);
9116
9560
  if (e)
9117
9561
  buckets.types.push(e);
9562
+ if (e && exportedFromWrapper)
9563
+ buckets.exports.push({ name: e.name, kind: "type", line: e.lines[0] });
9118
9564
  return;
9119
9565
  }
9120
9566
  if (anyStmt.type === "TSEnumDeclaration") {
9121
9567
  const e = processTsEnumDeclaration(anyStmt, exportedFromWrapper);
9122
9568
  if (e)
9123
9569
  buckets.enums.push(e);
9570
+ if (e && exportedFromWrapper)
9571
+ buckets.exports.push({ name: e.name, kind: "enum", line: e.lines[0] });
9124
9572
  return;
9125
9573
  }
9126
9574
  }
@@ -9148,7 +9596,9 @@ function parseAndExtract(source, opts) {
9148
9596
  classes: [],
9149
9597
  interfaces: [],
9150
9598
  types: [],
9151
- enums: []
9599
+ enums: [],
9600
+ calls: [],
9601
+ exports: []
9152
9602
  };
9153
9603
  for (const stmt of ast.program.body) {
9154
9604
  processStatement(stmt, buckets, !!opts.extractTsTypes);
@@ -9171,7 +9621,9 @@ function parseJsSource(source, relPath) {
9171
9621
  imports: r.imports,
9172
9622
  constants: r.constants,
9173
9623
  classes: r.classes,
9174
- functions: r.functions
9624
+ functions: r.functions,
9625
+ calls: r.calls,
9626
+ exports: r.exports
9175
9627
  };
9176
9628
  }
9177
9629
  var COMMON_PLUGINS, JS_PLUGINS, JavaScriptScanner, jsScanner;
@@ -9199,7 +9651,7 @@ var init_javascript = __esm({
9199
9651
  async scan(absolutePath, repoRoot) {
9200
9652
  let source;
9201
9653
  try {
9202
- source = readFileSync18(absolutePath, "utf8");
9654
+ source = readFileSync19(absolutePath, "utf8");
9203
9655
  } catch (err) {
9204
9656
  throw err;
9205
9657
  }
@@ -9219,7 +9671,7 @@ var typescript_exports = {};
9219
9671
  __export(typescript_exports, {
9220
9672
  tsScanner: () => tsScanner
9221
9673
  });
9222
- import { readFileSync as readFileSync19 } from "fs";
9674
+ import { readFileSync as readFileSync20 } from "fs";
9223
9675
  var TypeScriptScanner, tsScanner;
9224
9676
  var init_typescript = __esm({
9225
9677
  "src/code-map/scanners/typescript.ts"() {
@@ -9231,7 +9683,7 @@ var init_typescript = __esm({
9231
9683
  async scan(absolutePath, repoRoot) {
9232
9684
  let source;
9233
9685
  try {
9234
- source = readFileSync19(absolutePath, "utf8");
9686
+ source = readFileSync20(absolutePath, "utf8");
9235
9687
  } catch (err) {
9236
9688
  throw err;
9237
9689
  }
@@ -9252,6 +9704,8 @@ var init_typescript = __esm({
9252
9704
  constants: r.constants,
9253
9705
  classes: r.classes,
9254
9706
  functions: r.functions,
9707
+ calls: r.calls,
9708
+ exports: r.exports,
9255
9709
  interfaces: r.interfaces,
9256
9710
  types: r.types,
9257
9711
  enums: r.enums
@@ -9267,7 +9721,7 @@ var vue_exports = {};
9267
9721
  __export(vue_exports, {
9268
9722
  vueScanner: () => vueScanner
9269
9723
  });
9270
- import { readFileSync as readFileSync20 } from "fs";
9724
+ import { readFileSync as readFileSync21 } from "fs";
9271
9725
  import { parse as parse2 } from "@vue/compiler-sfc";
9272
9726
  var VueScanner, vueScanner;
9273
9727
  var init_vue = __esm({
@@ -9280,7 +9734,7 @@ var init_vue = __esm({
9280
9734
  async scan(absolutePath, repoRoot) {
9281
9735
  let source;
9282
9736
  try {
9283
- source = readFileSync20(absolutePath, "utf8");
9737
+ source = readFileSync21(absolutePath, "utf8");
9284
9738
  } catch (err) {
9285
9739
  throw err;
9286
9740
  }
@@ -9294,6 +9748,8 @@ var init_vue = __esm({
9294
9748
  const allConstants = [];
9295
9749
  const allFunctions = [];
9296
9750
  const allClasses = [];
9751
+ const allCalls = [];
9752
+ const allExports = [];
9297
9753
  const warnings = [];
9298
9754
  const scriptBlocks = [descriptor.script, descriptor.scriptSetup].filter(Boolean);
9299
9755
  if (scriptBlocks.length === 0) {
@@ -9346,6 +9802,12 @@ var init_vue = __esm({
9346
9802
  }))
9347
9803
  });
9348
9804
  }
9805
+ for (const call of scriptEntry.calls ?? []) {
9806
+ allCalls.push({ ...call, line: call.line + offset });
9807
+ }
9808
+ for (const exp of scriptEntry.exports ?? []) {
9809
+ allExports.push({ ...exp, line: exp.line + offset });
9810
+ }
9349
9811
  }
9350
9812
  return {
9351
9813
  path: relPath,
@@ -9353,7 +9815,9 @@ var init_vue = __esm({
9353
9815
  imports: allImports,
9354
9816
  constants: allConstants,
9355
9817
  classes: allClasses,
9356
- functions: allFunctions
9818
+ functions: allFunctions,
9819
+ calls: allCalls,
9820
+ exports: allExports
9357
9821
  };
9358
9822
  }
9359
9823
  };
@@ -9367,9 +9831,9 @@ __export(code_map_exports, {
9367
9831
  codeMap: () => codeMap,
9368
9832
  computeSourcesDigest: () => computeSourcesDigest
9369
9833
  });
9370
- import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync21, writeFileSync as writeFileSync11 } from "fs";
9834
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, readFileSync as readFileSync22, writeFileSync as writeFileSync11 } from "fs";
9371
9835
  import { resolve, dirname as dirname5, relative as relative6 } from "path";
9372
- import { createHash as createHash5 } from "crypto";
9836
+ import { createHash as createHash6 } from "crypto";
9373
9837
  import { createRequire } from "module";
9374
9838
  import { fileURLToPath as fileURLToPath2 } from "url";
9375
9839
  import { join as join21 } from "path";
@@ -9379,7 +9843,7 @@ function computeSourcesDigest(absolutePaths, cwd) {
9379
9843
  const contentHash = sha256OfFileNormalized(p) || "missing";
9380
9844
  return `${rel}:${contentHash}`;
9381
9845
  });
9382
- return createHash5("sha256").update(lines.join("\n")).digest("hex");
9846
+ return createHash6("sha256").update(lines.join("\n")).digest("hex");
9383
9847
  }
9384
9848
  function slugifySurface(surface) {
9385
9849
  return surface.replace(/^[./]+/, "").replace(/\/+$/, "").replace(/[\\/]+/g, "-") || "root";
@@ -9388,7 +9852,7 @@ async function codeMap(opts) {
9388
9852
  const start = Date.now();
9389
9853
  if (opts.surface) {
9390
9854
  const resolvedSurface = resolve(process.cwd(), opts.surface);
9391
- if (!existsSync18(resolvedSurface)) {
9855
+ if (!existsSync19(resolvedSurface)) {
9392
9856
  log.error(`code-map --surface path not found: ${opts.surface}`);
9393
9857
  return 1;
9394
9858
  }
@@ -9473,7 +9937,7 @@ async function codeMap(opts) {
9473
9937
  log.warn(`${w.path}: ${w.message}`);
9474
9938
  }
9475
9939
  if (opts.check) {
9476
- const existing = existsSync18(out) ? readFileSync21(out, "utf8") : "";
9940
+ const existing = existsSync19(out) ? readFileSync22(out, "utf8") : "";
9477
9941
  const normalize = (s) => s.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/^# generated: [^\n]+\n/m, "# generated: <normalized>\n");
9478
9942
  if (normalize(existing) !== normalize(yamlBody)) {
9479
9943
  if (!opts.silent)
@@ -9493,6 +9957,16 @@ async function codeMap(opts) {
9493
9957
  if (!rel.startsWith("..")) {
9494
9958
  ensureGitignoreEntry(process.cwd(), rel, "cdd-kit local cache (do not commit)");
9495
9959
  }
9960
+ const graphPath = graphPathFor(out);
9961
+ const graph2 = buildCodeGraph(result.entries, {
9962
+ generator: `cdd-kit ${_pkg.version}`,
9963
+ sourcesDigest
9964
+ });
9965
+ writeFileSync11(graphPath, JSON.stringify(graph2, null, 2) + "\n", "utf8");
9966
+ const graphRel = relative6(process.cwd(), graphPath).replace(/\\/g, "/");
9967
+ if (!graphRel.startsWith("..")) {
9968
+ ensureGitignoreEntry(process.cwd(), graphRel, "cdd-kit local cache (do not commit)");
9969
+ }
9496
9970
  } catch {
9497
9971
  }
9498
9972
  if (!opts.silent)
@@ -9508,11 +9982,13 @@ var init_code_map = __esm({
9508
9982
  init_orchestrator();
9509
9983
  init_config();
9510
9984
  init_index_reader();
9985
+ init_builder();
9986
+ init_reader();
9511
9987
  init_digest();
9512
9988
  init_gitignore();
9513
9989
  _require = createRequire(import.meta.url);
9514
9990
  _pkgPath = join21(fileURLToPath2(import.meta.url), "..", "..", "..", "package.json");
9515
- _pkg = JSON.parse(readFileSync21(_pkgPath, "utf8"));
9991
+ _pkg = JSON.parse(readFileSync22(_pkgPath, "utf8"));
9516
9992
  }
9517
9993
  });
9518
9994
 
@@ -9521,15 +9997,15 @@ var refresh_exports = {};
9521
9997
  __export(refresh_exports, {
9522
9998
  refresh: () => refresh
9523
9999
  });
9524
- import { existsSync as existsSync19, mkdirSync as mkdirSync9, readdirSync as readdirSync10, copyFileSync as copyFileSync4, readFileSync as readFileSync22, writeFileSync as writeFileSync12 } from "fs";
10000
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, readdirSync as readdirSync10, copyFileSync as copyFileSync4, readFileSync as readFileSync23, writeFileSync as writeFileSync12 } from "fs";
9525
10001
  import { dirname as dirname6, join as join22, relative as relative7 } from "path";
9526
- import { createHash as createHash6 } from "crypto";
10002
+ import { createHash as createHash7 } from "crypto";
9527
10003
  function fileHash2(filePath) {
9528
- return createHash6("sha256").update(readFileSync22(filePath)).digest("hex");
10004
+ return createHash7("sha256").update(readFileSync23(filePath)).digest("hex");
9529
10005
  }
9530
10006
  function planForceRefresh(srcDir, destDir, sectionLabel) {
9531
10007
  const plan = [];
9532
- if (!existsSync19(srcDir))
10008
+ if (!existsSync20(srcDir))
9533
10009
  return plan;
9534
10010
  function walk(curSrc, curDest) {
9535
10011
  let items;
@@ -9548,7 +10024,7 @@ function planForceRefresh(srcDir, destDir, sectionLabel) {
9548
10024
  if (!item.isFile())
9549
10025
  continue;
9550
10026
  const rel = join22(sectionLabel, relative7(srcDir, sp)).replace(/\\/g, "/");
9551
- if (!existsSync19(dp)) {
10027
+ if (!existsSync20(dp)) {
9552
10028
  plan.push({ src: sp, dest: dp, rel, action: "add" });
9553
10029
  } else if (fileHash2(sp) !== fileHash2(dp)) {
9554
10030
  plan.push({ src: sp, dest: dp, rel, action: "overwrite" });
@@ -9561,9 +10037,9 @@ function planForceRefresh(srcDir, destDir, sectionLabel) {
9561
10037
  return plan;
9562
10038
  }
9563
10039
  function planSingleFile(src, dest, rel) {
9564
- if (!existsSync19(src))
10040
+ if (!existsSync20(src))
9565
10041
  return null;
9566
- if (!existsSync19(dest))
10042
+ if (!existsSync20(dest))
9567
10043
  return { src, dest, rel, action: "add" };
9568
10044
  if (fileHash2(src) !== fileHash2(dest))
9569
10045
  return { src, dest, rel, action: "overwrite" };
@@ -9607,12 +10083,12 @@ function parseAgentFrontmatter(content) {
9607
10083
  function resyncModelPolicy(cwd) {
9608
10084
  const policyPath = join22(cwd, ".cdd", "model-policy.json");
9609
10085
  const result = { changed: false, diff: [], policyPath };
9610
- if (!existsSync19(AGENTS_HOME))
10086
+ if (!existsSync20(AGENTS_HOME))
9611
10087
  return result;
9612
10088
  const desired = {};
9613
10089
  const agentFiles = readdirSync10(AGENTS_HOME, { withFileTypes: true }).filter((d) => d.isFile() && d.name.endsWith(".md"));
9614
10090
  for (const f of agentFiles) {
9615
- const content = readFileSync22(join22(AGENTS_HOME, f.name), "utf8");
10091
+ const content = readFileSync23(join22(AGENTS_HOME, f.name), "utf8");
9616
10092
  const fm = parseAgentFrontmatter(content);
9617
10093
  if (fm.name && fm.model)
9618
10094
  desired[fm.name] = fm.model;
@@ -9620,9 +10096,9 @@ function resyncModelPolicy(cwd) {
9620
10096
  if (Object.keys(desired).length === 0)
9621
10097
  return result;
9622
10098
  let existing = {};
9623
- if (existsSync19(policyPath)) {
10099
+ if (existsSync20(policyPath)) {
9624
10100
  try {
9625
- existing = JSON.parse(readFileSync22(policyPath, "utf8"));
10101
+ existing = JSON.parse(readFileSync23(policyPath, "utf8"));
9626
10102
  } catch {
9627
10103
  }
9628
10104
  }
@@ -9658,7 +10134,7 @@ function planTemplateRefresh(cwd) {
9658
10134
  plan: planForceRefresh(ASSET.testsTemplates, join22(cwd, "tests", "templates"), "tests/templates")
9659
10135
  });
9660
10136
  const ciTemplatesAsset = join22(ASSET.ci, "..", "ci-templates");
9661
- if (existsSync19(ciTemplatesAsset)) {
10137
+ if (existsSync20(ciTemplatesAsset)) {
9662
10138
  sections.push({
9663
10139
  name: "ci-templates",
9664
10140
  plan: planForceRefresh(ciTemplatesAsset, join22(cwd, "ci-templates"), "ci-templates")
@@ -9741,7 +10217,7 @@ async function refresh(opts) {
9741
10217
  log.blank();
9742
10218
  if (!opts.noHooks) {
9743
10219
  const markerPath = join22(cwd, HOOKS_MARKER_PATH);
9744
- if (existsSync19(markerPath)) {
10220
+ if (existsSync20(markerPath)) {
9745
10221
  log.info("[4/6] re-install code-map pre-commit hook (marker found)");
9746
10222
  if (apply) {
9747
10223
  try {
@@ -9834,7 +10310,7 @@ __export(lint_agents_exports, {
9834
10310
  lintAgentContent: () => lintAgentContent,
9835
10311
  lintAgents: () => lintAgents
9836
10312
  });
9837
- import { readdirSync as readdirSync11, readFileSync as readFileSync23 } from "fs";
10313
+ import { readdirSync as readdirSync11, readFileSync as readFileSync24 } from "fs";
9838
10314
  import { join as join23 } from "path";
9839
10315
  import { load as yamlLoad2 } from "js-yaml";
9840
10316
  function extractRequiredArtifactsSection(content) {
@@ -9975,7 +10451,7 @@ function collectAgentViolations(cwd, opts = {}) {
9975
10451
  for (const filename of files) {
9976
10452
  let content;
9977
10453
  try {
9978
- content = readFileSync23(join23(agentsDir, filename), "utf8");
10454
+ content = readFileSync24(join23(agentsDir, filename), "utf8");
9979
10455
  } catch {
9980
10456
  violations.push({
9981
10457
  file: filename,
@@ -10024,14 +10500,14 @@ var doctor_exports = {};
10024
10500
  __export(doctor_exports, {
10025
10501
  doctor: () => doctor
10026
10502
  });
10027
- import { existsSync as existsSync20, readdirSync as readdirSync12, readFileSync as readFileSync24 } from "fs";
10028
- import { createHash as createHash7 } from "crypto";
10503
+ import { existsSync as existsSync21, readdirSync as readdirSync12, readFileSync as readFileSync25 } from "fs";
10504
+ import { createHash as createHash8 } from "crypto";
10029
10505
  import { join as join24, relative as relative8 } from "path";
10030
10506
  function fileExists(cwd, relPath) {
10031
- return existsSync20(join24(cwd, relPath));
10507
+ return existsSync21(join24(cwd, relPath));
10032
10508
  }
10033
10509
  function findFiles(dir, predicate, found = []) {
10034
- if (!existsSync20(dir))
10510
+ if (!existsSync21(dir))
10035
10511
  return found;
10036
10512
  for (const entry of readdirSync12(dir, { withFileTypes: true })) {
10037
10513
  const fullPath = join24(dir, entry.name);
@@ -10047,12 +10523,12 @@ function inputDigest(paths, cwd) {
10047
10523
  const rel = relative8(cwd, p).replace(/\\/g, "/");
10048
10524
  return `${rel}:${sha256OfFileNormalized(p)}`;
10049
10525
  }).join("\n");
10050
- return createHash7("sha256").update(combined).digest("hex");
10526
+ return createHash8("sha256").update(combined).digest("hex");
10051
10527
  }
10052
10528
  function readContextIndexMetadata(filePath) {
10053
- if (!existsSync20(filePath))
10529
+ if (!existsSync21(filePath))
10054
10530
  return {};
10055
- const text = readFileSync24(filePath, "utf8");
10531
+ const text = readFileSync25(filePath, "utf8");
10056
10532
  const out = {};
10057
10533
  const digestMatch = text.match(/^inputs-digest:\s*([a-f0-9]+)/m);
10058
10534
  if (digestMatch)
@@ -10071,7 +10547,7 @@ function checkContextFreshness(cwd) {
10071
10547
  join24(cwd, "contracts"),
10072
10548
  (name) => name.endsWith(".md") && name !== "INDEX.md" && name !== "CHANGELOG.md"
10073
10549
  );
10074
- if (!existsSync20(projectMap) || !existsSync20(contractsIndex)) {
10550
+ if (!existsSync21(projectMap) || !existsSync21(contractsIndex)) {
10075
10551
  findings.push({
10076
10552
  level: "warning",
10077
10553
  message: "specs/context indexes are missing; run cdd-kit context-scan before classification"
@@ -10080,7 +10556,7 @@ function checkContextFreshness(cwd) {
10080
10556
  }
10081
10557
  const projectMapMeta = readContextIndexMetadata(projectMap);
10082
10558
  const contractsIndexMeta = readContextIndexMetadata(contractsIndex);
10083
- const projectInputDigest = inputDigest([contextPolicy].filter(existsSync20), cwd);
10559
+ const projectInputDigest = inputDigest([contextPolicy].filter(existsSync21), cwd);
10084
10560
  if (projectMapMeta.inputsDigest === void 0) {
10085
10561
  findings.push({
10086
10562
  level: "warning",
@@ -10117,7 +10593,7 @@ function checkContextFreshness(cwd) {
10117
10593
  }
10118
10594
  function readAgentModel(path) {
10119
10595
  try {
10120
- const text = readFileSync24(path, "utf8");
10596
+ const text = readFileSync25(path, "utf8");
10121
10597
  const m = text.match(/^model:\s*(\S+)/m);
10122
10598
  return m ? m[1] : null;
10123
10599
  } catch {
@@ -10126,11 +10602,11 @@ function readAgentModel(path) {
10126
10602
  }
10127
10603
  function checkModelPolicyDrift(cwd) {
10128
10604
  const policyPath = join24(cwd, ".cdd", "model-policy.json");
10129
- if (!existsSync20(policyPath))
10605
+ if (!existsSync21(policyPath))
10130
10606
  return [];
10131
10607
  let policy;
10132
10608
  try {
10133
- policy = JSON.parse(readFileSync24(policyPath, "utf8"));
10609
+ policy = JSON.parse(readFileSync25(policyPath, "utf8"));
10134
10610
  } catch {
10135
10611
  return [{ level: "warning", message: ".cdd/model-policy.json is not valid JSON" }];
10136
10612
  }
@@ -10145,7 +10621,7 @@ function checkModelPolicyDrift(cwd) {
10145
10621
  join24(cwd, ".claude", "agents"),
10146
10622
  process.env.HOME ? join24(process.env.HOME, ".claude", "agents") : "",
10147
10623
  process.env.USERPROFILE ? join24(process.env.USERPROFILE, ".claude", "agents") : ""
10148
- ].filter((p) => p && existsSync20(p));
10624
+ ].filter((p) => p && existsSync21(p));
10149
10625
  if (candidateDirs.length === 0)
10150
10626
  return [];
10151
10627
  const findings = [];
@@ -10153,7 +10629,7 @@ function checkModelPolicyDrift(cwd) {
10153
10629
  let foundAny = false;
10154
10630
  for (const dir of candidateDirs) {
10155
10631
  const path = join24(dir, `${role}.md`);
10156
- if (!existsSync20(path))
10632
+ if (!existsSync21(path))
10157
10633
  continue;
10158
10634
  foundAny = true;
10159
10635
  const actual = readAgentModel(path);
@@ -10174,7 +10650,7 @@ function checkModelPolicyDrift(cwd) {
10174
10650
  }
10175
10651
  function checkAgentLint(cwd) {
10176
10652
  const agentsDir = join24(cwd, ".claude", "agents");
10177
- if (!existsSync20(agentsDir))
10653
+ if (!existsSync21(agentsDir))
10178
10654
  return [];
10179
10655
  const violations = collectAgentViolations(cwd);
10180
10656
  if (violations === null) {
@@ -10195,7 +10671,7 @@ function checkAgentLint(cwd) {
10195
10671
  function checkCodeMap(cwd) {
10196
10672
  const findings = [];
10197
10673
  const mapPath = join24(cwd, ".cdd", "code-map.yml");
10198
- if (!existsSync20(mapPath)) {
10674
+ if (!existsSync21(mapPath)) {
10199
10675
  const probe2 = checkCodeMapFreshness(cwd);
10200
10676
  if (probe2.status === "config-error") {
10201
10677
  findings.push({ level: "warning", message: `.cdd/code-map-config.yml is invalid: ${probe2.configError}` });
@@ -10214,7 +10690,7 @@ function checkCodeMap(cwd) {
10214
10690
  const more = probe.staleCount > 3 ? ` (+${probe.staleCount - 3} more)` : "";
10215
10691
  findings.push({ level: "warning", message: `code-map stale: ${top}${more}; run \`cdd-kit code-map\`` });
10216
10692
  }
10217
- const text = readFileSync24(mapPath, "utf8");
10693
+ const text = readFileSync25(mapPath, "utf8");
10218
10694
  const m = text.match(/^# files: (\d+), src-lines: (\d+), map-lines: (\d+), compression: ([\d.]+)x/m);
10219
10695
  if (m) {
10220
10696
  findings.push({ level: "ok", message: `code-map: ${m[1]} files, ${m[4]}x compression` });
@@ -10294,7 +10770,7 @@ async function attemptAutoFixes(cwd, report) {
10294
10770
  try {
10295
10771
  let existing = {};
10296
10772
  try {
10297
- existing = JSON.parse(readFileSync24(policyPath, "utf8"));
10773
+ existing = JSON.parse(readFileSync25(policyPath, "utf8"));
10298
10774
  } catch {
10299
10775
  }
10300
10776
  const merged = {
@@ -10305,6 +10781,7 @@ async function attemptAutoFixes(cwd, report) {
10305
10781
  "qa-reviewer": "opus",
10306
10782
  "contract-reviewer": "sonnet",
10307
10783
  "test-strategist": "sonnet",
10784
+ "bug-fix-engineer": "sonnet",
10308
10785
  "backend-engineer": "sonnet",
10309
10786
  "frontend-engineer": "sonnet",
10310
10787
  "ci-cd-gatekeeper": "sonnet",
@@ -10397,7 +10874,7 @@ var code_map_scan_worker_exports = {};
10397
10874
  __export(code_map_scan_worker_exports, {
10398
10875
  runScanWorker: () => runScanWorker
10399
10876
  });
10400
- import { readFileSync as readFileSync25 } from "fs";
10877
+ import { readFileSync as readFileSync26 } from "fs";
10401
10878
  async function runScanWorker(opts) {
10402
10879
  let scanner;
10403
10880
  switch (opts.lang) {
@@ -10417,7 +10894,7 @@ async function runScanWorker(opts) {
10417
10894
  }
10418
10895
  let files;
10419
10896
  try {
10420
- files = readFileSync25(opts.batchFile, "utf8").split("\n").map((s) => s.trim()).filter(Boolean);
10897
+ files = readFileSync26(opts.batchFile, "utf8").split("\n").map((s) => s.trim()).filter(Boolean);
10421
10898
  } catch (err) {
10422
10899
  process.stderr.write(`__code-map-scan: cannot read --batch-file: ${err.message}
10423
10900
  `);
@@ -10437,9 +10914,10 @@ var init_code_map_scan_worker = __esm({
10437
10914
  // src/commands/index-query.ts
10438
10915
  var index_query_exports = {};
10439
10916
  __export(index_query_exports, {
10440
- indexQuery: () => indexQuery
10917
+ indexQuery: () => indexQuery,
10918
+ queryEntries: () => queryEntries
10441
10919
  });
10442
- import { existsSync as existsSync21 } from "fs";
10920
+ import { existsSync as existsSync22 } from "fs";
10443
10921
  async function indexQuery(term, opts) {
10444
10922
  const mapPath = opts.map || ".cdd/code-map.yml";
10445
10923
  const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 10;
@@ -10449,7 +10927,7 @@ async function indexQuery(term, opts) {
10449
10927
  return printFailure(freshness.error, opts.json);
10450
10928
  }
10451
10929
  refreshed = freshness.refreshed;
10452
- if (!existsSync21(mapPath)) {
10930
+ if (!existsSync22(mapPath)) {
10453
10931
  return printFailure(`${mapPath} is missing; run \`cdd-kit code-map\` first.`, opts.json);
10454
10932
  }
10455
10933
  let entries;
@@ -10617,8 +11095,8 @@ var index_impact_exports = {};
10617
11095
  __export(index_impact_exports, {
10618
11096
  indexImpact: () => indexImpact
10619
11097
  });
10620
- import { existsSync as existsSync22 } from "fs";
10621
- import { posix } from "path";
11098
+ import { existsSync as existsSync23 } from "fs";
11099
+ import { posix as posix2 } from "path";
10622
11100
  async function indexImpact(term, opts) {
10623
11101
  const mapPath = opts.map || ".cdd/code-map.yml";
10624
11102
  const limit = Number.isFinite(opts.limit) && opts.limit > 0 ? Math.floor(opts.limit) : 20;
@@ -10626,7 +11104,7 @@ async function indexImpact(term, opts) {
10626
11104
  if (freshness.error) {
10627
11105
  return printFailure2(freshness.error, opts.json);
10628
11106
  }
10629
- if (!existsSync22(mapPath)) {
11107
+ if (!existsSync23(mapPath)) {
10630
11108
  return printFailure2(`${mapPath} is missing; run \`cdd-kit code-map\` first.`, opts.json);
10631
11109
  }
10632
11110
  let entries;
@@ -10643,7 +11121,7 @@ async function indexImpact(term, opts) {
10643
11121
  const target = targetResult.entry;
10644
11122
  const targetImports = target.imports.map((imp) => resolveImport(target.path, imp, pathSet));
10645
11123
  const imports = targetImports.filter((imp) => imp.resolved);
10646
- const unresolvedLocalImports = targetImports.filter((imp) => !imp.resolved && isLocalImport(imp.module));
11124
+ const unresolvedLocalImports = targetImports.filter((imp) => !imp.resolved && isLocalImport2(imp.module));
10647
11125
  const dependents = entries.filter((entry) => entry.path !== target.path).map((entry) => ({
10648
11126
  entry,
10649
11127
  imports: entry.imports.map((imp) => resolveImport(entry.path, imp, pathSet)).filter((imp) => imp.resolved === target.path)
@@ -10679,7 +11157,7 @@ function findTarget(entries, term) {
10679
11157
  if (exact)
10680
11158
  return { entry: exact };
10681
11159
  const pathMatches2 = entries.filter(
10682
- (entry) => entry.path.toLowerCase().includes(query.toLowerCase()) || posix.basename(entry.path).toLowerCase() === query.toLowerCase()
11160
+ (entry) => entry.path.toLowerCase().includes(query.toLowerCase()) || posix2.basename(entry.path).toLowerCase() === query.toLowerCase()
10683
11161
  );
10684
11162
  if (pathMatches2.length === 1)
10685
11163
  return { entry: pathMatches2[0] };
@@ -10715,7 +11193,7 @@ function normalizeQueryPath(term) {
10715
11193
  return term.trim().replace(/\\/g, "/").replace(/^\.\//, "");
10716
11194
  }
10717
11195
  function resolveImport(importerPath, imp, pathSet) {
10718
- const resolved = resolveLocalModule(importerPath, imp.module, pathSet);
11196
+ const resolved = resolveLocalModule2(importerPath, imp.module, pathSet);
10719
11197
  return {
10720
11198
  module: imp.module,
10721
11199
  items: Array.isArray(imp.items) ? imp.items : [],
@@ -10723,30 +11201,30 @@ function resolveImport(importerPath, imp, pathSet) {
10723
11201
  ...resolved ? { resolved } : {}
10724
11202
  };
10725
11203
  }
10726
- function resolveLocalModule(importerPath, moduleName, pathSet) {
10727
- if (!isLocalImport(moduleName))
11204
+ function resolveLocalModule2(importerPath, moduleName, pathSet) {
11205
+ if (!isLocalImport2(moduleName))
10728
11206
  return void 0;
10729
- const base = moduleName.startsWith("./") || moduleName.startsWith("../") ? posix.normalize(posix.join(posix.dirname(importerPath), moduleName)) : resolvePythonRelativeImport(importerPath, moduleName);
10730
- for (const candidate of resolutionCandidates(base)) {
11207
+ const base = moduleName.startsWith("./") || moduleName.startsWith("../") ? posix2.normalize(posix2.join(posix2.dirname(importerPath), moduleName)) : resolvePythonRelativeImport2(importerPath, moduleName);
11208
+ for (const candidate of resolutionCandidates2(base)) {
10731
11209
  if (pathSet.has(candidate))
10732
11210
  return candidate;
10733
11211
  }
10734
11212
  return void 0;
10735
11213
  }
10736
- function resolvePythonRelativeImport(importerPath, moduleName) {
11214
+ function resolvePythonRelativeImport2(importerPath, moduleName) {
10737
11215
  const match = moduleName.match(/^(\.+)(.*)$/);
10738
11216
  if (!match)
10739
11217
  return moduleName;
10740
11218
  const upLevels = Math.max(0, match[1].length - 1);
10741
- let baseDir = posix.dirname(importerPath);
11219
+ let baseDir = posix2.dirname(importerPath);
10742
11220
  for (let i = 0; i < upLevels; i++) {
10743
- baseDir = posix.dirname(baseDir);
11221
+ baseDir = posix2.dirname(baseDir);
10744
11222
  }
10745
11223
  const rest = match[2].replace(/^\./, "").replace(/\./g, "/");
10746
- return rest ? posix.normalize(posix.join(baseDir, rest)) : baseDir;
11224
+ return rest ? posix2.normalize(posix2.join(baseDir, rest)) : baseDir;
10747
11225
  }
10748
- function resolutionCandidates(base) {
10749
- const ext = posix.extname(base);
11226
+ function resolutionCandidates2(base) {
11227
+ const ext = posix2.extname(base);
10750
11228
  const candidates = [];
10751
11229
  if (ext) {
10752
11230
  candidates.push(base);
@@ -10755,17 +11233,17 @@ function resolutionCandidates(base) {
10755
11233
  candidates.push(`${withoutExt}.ts`, `${withoutExt}.tsx`, `${withoutExt}.vue`);
10756
11234
  }
10757
11235
  } else {
10758
- for (const candidateExt of RESOLUTION_EXTENSIONS) {
11236
+ for (const candidateExt of RESOLUTION_EXTENSIONS2) {
10759
11237
  candidates.push(`${base}${candidateExt}`);
10760
11238
  }
10761
11239
  }
10762
- for (const candidateExt of RESOLUTION_EXTENSIONS) {
10763
- candidates.push(posix.join(base, `index${candidateExt}`));
11240
+ for (const candidateExt of RESOLUTION_EXTENSIONS2) {
11241
+ candidates.push(posix2.join(base, `index${candidateExt}`));
10764
11242
  }
10765
- candidates.push(posix.join(base, "__init__.py"));
11243
+ candidates.push(posix2.join(base, "__init__.py"));
10766
11244
  return [...new Set(candidates)];
10767
11245
  }
10768
- function isLocalImport(moduleName) {
11246
+ function isLocalImport2(moduleName) {
10769
11247
  return moduleName.startsWith(".");
10770
11248
  }
10771
11249
  function summarizeSymbols(entry) {
@@ -10855,12 +11333,486 @@ function printFailure2(message, json) {
10855
11333
  }
10856
11334
  return 1;
10857
11335
  }
10858
- var RESOLUTION_EXTENSIONS;
11336
+ var RESOLUTION_EXTENSIONS2;
10859
11337
  var init_index_impact = __esm({
10860
11338
  "src/commands/index-impact.ts"() {
10861
11339
  "use strict";
10862
11340
  init_index_reader();
10863
- RESOLUTION_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".vue", ".py"];
11341
+ RESOLUTION_EXTENSIONS2 = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".vue", ".py"];
11342
+ }
11343
+ });
11344
+
11345
+ // src/code-graph/queries.ts
11346
+ function searchGraph(graph2, term, limit) {
11347
+ const query = term.trim().toLowerCase();
11348
+ if (!query)
11349
+ return [];
11350
+ return graph2.nodes.map((node) => {
11351
+ const score = Math.max(
11352
+ scoreText2(node.name, query, 120),
11353
+ scoreText2(node.qualified_name, query, 100),
11354
+ scoreText2(node.file_path, query, 80)
11355
+ );
11356
+ return {
11357
+ node,
11358
+ score,
11359
+ edges: {
11360
+ incoming: graph2.edges.filter((e) => e.target === node.id).length,
11361
+ outgoing: graph2.edges.filter((e) => e.source === node.id).length
11362
+ }
11363
+ };
11364
+ }).filter((result) => result.score > 0).sort((a, b) => b.score - a.score || a.node.file_path.localeCompare(b.node.file_path) || a.node.start_line - b.node.start_line).slice(0, limit);
11365
+ }
11366
+ function findGraphNode(graph2, term) {
11367
+ const query = term.trim().toLowerCase().replace(/\\/g, "/").replace(/^\.\//, "");
11368
+ const exact = graph2.nodes.find((n) => n.id === term || n.qualified_name.toLowerCase() === query || n.file_path.toLowerCase() === query);
11369
+ if (exact)
11370
+ return exact;
11371
+ const pathMatches2 = graph2.nodes.filter((n) => n.kind === "file" && n.file_path.toLowerCase().includes(query));
11372
+ if (pathMatches2.length === 1)
11373
+ return pathMatches2[0];
11374
+ const symbolMatches = graph2.nodes.filter((n) => n.name.toLowerCase() === query || n.qualified_name.toLowerCase().endsWith(`::${query}`));
11375
+ if (symbolMatches.length === 1)
11376
+ return symbolMatches[0];
11377
+ return searchGraph(graph2, term, 1)[0]?.node;
11378
+ }
11379
+ function graphImpact(graph2, term, depth, limit) {
11380
+ const target = findGraphNode(graph2, term);
11381
+ if (!target)
11382
+ return void 0;
11383
+ return traverse(graph2, target, ["calls", "imports", "references", "extends", "implements"], "both", depth, limit);
11384
+ }
11385
+ function graphContext(graph2, task, maxNodes) {
11386
+ const entryPoints = searchGraph(graph2, task, Math.min(maxNodes, 10));
11387
+ const nodeIds = new Set(entryPoints.map((r) => r.node.id));
11388
+ const edgeMap = /* @__PURE__ */ new Map();
11389
+ for (const entry of entryPoints) {
11390
+ const neighborhood = traverse(graph2, entry.node, ["contains", "calls", "imports", "references", "extends", "implements"], "both", 1, maxNodes);
11391
+ for (const node of neighborhood.nodes)
11392
+ nodeIds.add(node.id);
11393
+ for (const edge of neighborhood.edges)
11394
+ edgeMap.set(edge.id, edge);
11395
+ }
11396
+ const nodes = graph2.nodes.filter((n) => nodeIds.has(n.id)).slice(0, maxNodes);
11397
+ return { query: task, entry_points: entryPoints, nodes, edges: [...edgeMap.values()] };
11398
+ }
11399
+ function traverse(graph2, target, kinds, direction, depth, limit) {
11400
+ const maxDepth = Math.max(1, depth || 1);
11401
+ const maxNodes = Math.max(1, limit || 50);
11402
+ const nodeById = new Map(graph2.nodes.map((n) => [n.id, n]));
11403
+ const visited = /* @__PURE__ */ new Set([target.id]);
11404
+ const keptEdges = /* @__PURE__ */ new Map();
11405
+ let frontier = [target.id];
11406
+ for (let d = 0; d < maxDepth && frontier.length > 0 && visited.size < maxNodes; d++) {
11407
+ const next = [];
11408
+ for (const nodeId2 of frontier) {
11409
+ const edges = graph2.edges.filter(
11410
+ (e) => kinds.includes(e.kind) && (direction === "both" ? e.source === nodeId2 || e.target === nodeId2 : direction === "incoming" ? e.target === nodeId2 : e.source === nodeId2)
11411
+ );
11412
+ for (const edge of edges) {
11413
+ const other = edge.source === nodeId2 ? edge.target : edge.source;
11414
+ if (!nodeById.has(other))
11415
+ continue;
11416
+ keptEdges.set(edge.id, edge);
11417
+ if (!visited.has(other)) {
11418
+ visited.add(other);
11419
+ next.push(other);
11420
+ if (visited.size >= maxNodes)
11421
+ break;
11422
+ }
11423
+ }
11424
+ }
11425
+ frontier = next;
11426
+ }
11427
+ return {
11428
+ target,
11429
+ depth: maxDepth,
11430
+ nodes: [...visited].map((id) => nodeById.get(id)).filter((node) => !!node),
11431
+ edges: [...keptEdges.values()]
11432
+ };
11433
+ }
11434
+ function scoreText2(text, query, weight) {
11435
+ const haystack = text.toLowerCase();
11436
+ if (haystack === query)
11437
+ return weight + 40;
11438
+ if (haystack.endsWith(`/${query}`) || haystack.endsWith(`.${query}`) || haystack.endsWith(`::${query}`))
11439
+ return weight + 30;
11440
+ if (haystack.startsWith(query))
11441
+ return weight + 20;
11442
+ if (haystack.includes(query))
11443
+ return weight;
11444
+ return 0;
11445
+ }
11446
+ var init_queries = __esm({
11447
+ "src/code-graph/queries.ts"() {
11448
+ "use strict";
11449
+ }
11450
+ });
11451
+
11452
+ // src/commands/graph.ts
11453
+ var graph_exports = {};
11454
+ __export(graph_exports, {
11455
+ graphContext: () => graphContext2,
11456
+ graphImpact: () => graphImpact2,
11457
+ graphQuery: () => graphQuery,
11458
+ graphStatus: () => graphStatus,
11459
+ graphSync: () => graphSync
11460
+ });
11461
+ import { existsSync as existsSync24 } from "fs";
11462
+ import { join as join25 } from "path";
11463
+ import { spawnSync as spawnSync3 } from "child_process";
11464
+ function codeGraphCommand() {
11465
+ return process.env.CDD_CODEGRAPH_BIN || "codegraph";
11466
+ }
11467
+ function runCodeGraph(args, cwd = process.cwd()) {
11468
+ const command = codeGraphCommand();
11469
+ if (command.toLowerCase().endsWith(".js")) {
11470
+ return spawnSync3(process.execPath, [command, ...args], { cwd, encoding: "buffer" });
11471
+ }
11472
+ return spawnSync3(command, args, { cwd, encoding: "buffer" });
11473
+ }
11474
+ function probeCodeGraph(cwd = process.cwd()) {
11475
+ const command = codeGraphCommand();
11476
+ const initialized = existsSync24(join25(cwd, ".codegraph"));
11477
+ const version = runCodeGraph(["--version"], cwd);
11478
+ if (version.error) {
11479
+ return {
11480
+ available: false,
11481
+ command,
11482
+ initialized,
11483
+ reason: version.error.message
11484
+ };
11485
+ }
11486
+ if (version.status !== 0) {
11487
+ return {
11488
+ available: false,
11489
+ command,
11490
+ initialized,
11491
+ reason: (version.stderr?.toString("utf8") || version.stdout?.toString("utf8") || `exit ${version.status}`).trim()
11492
+ };
11493
+ }
11494
+ return { available: true, command, initialized };
11495
+ }
11496
+ function selectEngine(opts, cwd = process.cwd()) {
11497
+ const requested = opts.engine ?? "auto";
11498
+ const probe = probeCodeGraph(cwd);
11499
+ if (!["auto", "native", "codegraph", "codemap"].includes(requested)) {
11500
+ return { error: `Invalid graph engine: ${requested}. Use auto, native, codegraph, or codemap.`, probe };
11501
+ }
11502
+ if (requested === "codemap")
11503
+ return { engine: "codemap", probe };
11504
+ if (requested === "native" || requested === "auto")
11505
+ return { engine: "native", probe };
11506
+ if (requested === "codegraph") {
11507
+ if (!probe.available) {
11508
+ return {
11509
+ error: `CodeGraph is not available (${probe.command}): ${probe.reason ?? "command not found"}`,
11510
+ probe
11511
+ };
11512
+ }
11513
+ return { engine: "codegraph", probe };
11514
+ }
11515
+ return { engine: "native", probe };
11516
+ }
11517
+ function writeJson(value) {
11518
+ process.stdout.write(`${JSON.stringify(value, null, 2)}
11519
+ `);
11520
+ }
11521
+ function pipeResult(result) {
11522
+ if (result.stdout?.length)
11523
+ process.stdout.write(result.stdout);
11524
+ if (result.stderr?.length)
11525
+ process.stderr.write(result.stderr);
11526
+ if (result.error) {
11527
+ process.stderr.write(`${result.error.message}
11528
+ `);
11529
+ return 1;
11530
+ }
11531
+ return result.status ?? 1;
11532
+ }
11533
+ function printEngineError(message, json, probe) {
11534
+ if (json) {
11535
+ writeJson({ error: message, codegraph: probe });
11536
+ } else {
11537
+ console.error(message);
11538
+ }
11539
+ return 1;
11540
+ }
11541
+ async function ensureNativeGraph(mapPath, refresh2) {
11542
+ const freshness = await ensureCodeMapFresh(mapPath, refresh2);
11543
+ if (freshness.error)
11544
+ return { graphPath: graphPathFor(mapPath), refreshed: freshness.refreshed, error: freshness.error };
11545
+ const graphPath = graphPathFor(mapPath);
11546
+ if (!existsSync24(graphPath) && refresh2) {
11547
+ const { codeMap: codeMap2 } = await Promise.resolve().then(() => (init_code_map(), code_map_exports));
11548
+ const exit = await codeMap2({
11549
+ path: ".",
11550
+ out: mapPath,
11551
+ include: [],
11552
+ exclude: [],
11553
+ check: false,
11554
+ maxLines: 1e5,
11555
+ silent: true
11556
+ });
11557
+ if (exit !== 0) {
11558
+ return { graphPath, refreshed: freshness.refreshed, error: `could not refresh ${graphPath}; run \`cdd-kit code-map\` for details.` };
11559
+ }
11560
+ return { graphPath, refreshed: true };
11561
+ }
11562
+ return { graphPath, refreshed: freshness.refreshed };
11563
+ }
11564
+ async function graphStatus(opts = {}) {
11565
+ const cwd = process.cwd();
11566
+ const selected = selectEngine(opts, cwd);
11567
+ if ("error" in selected)
11568
+ return printEngineError(selected.error, opts.json, selected.probe);
11569
+ if (selected.engine === "codegraph") {
11570
+ const args = ["status"];
11571
+ if (opts.path)
11572
+ args.push(opts.path);
11573
+ return pipeResult(runCodeGraph(args, cwd));
11574
+ }
11575
+ const mapPath = opts.map || ".cdd/code-map.yml";
11576
+ const graphPath = graphPathFor(mapPath);
11577
+ const freshness = checkCodeMapFreshness(cwd, mapPath);
11578
+ let graphStats;
11579
+ if (existsSync24(graphPath)) {
11580
+ try {
11581
+ const graph2 = loadCodeGraph(graphPath);
11582
+ graphStats = { graph: graphPath, nodes: graph2.nodes.length, edges: graph2.edges.length, unresolved: graph2.unresolved.length };
11583
+ } catch {
11584
+ graphStats = { graph: graphPath, nodes: 0, edges: 0, unresolved: 0 };
11585
+ }
11586
+ }
11587
+ const payload = {
11588
+ engine: selected.engine,
11589
+ codegraph: selected.probe,
11590
+ code_map: {
11591
+ map: mapPath,
11592
+ status: freshness.status,
11593
+ stale_count: "staleCount" in freshness ? freshness.staleCount : 0,
11594
+ stale_files: "staleFiles" in freshness ? freshness.staleFiles.slice(0, 10) : [],
11595
+ config_error: "configError" in freshness ? freshness.configError : void 0
11596
+ },
11597
+ native_graph: graphStats ?? { graph: graphPath, missing: true }
11598
+ };
11599
+ if (opts.json) {
11600
+ writeJson(payload);
11601
+ } else {
11602
+ console.log(`graph engine: ${selected.engine === "native" ? "native cdd-kit graph" : "code-map fallback"}`);
11603
+ console.log(`code-map: ${payload.code_map.status}`);
11604
+ if (graphStats) {
11605
+ console.log(`code-graph: ${graphStats.nodes} nodes, ${graphStats.edges} edges, ${graphStats.unresolved} unresolved`);
11606
+ } else {
11607
+ console.log(`code-graph: missing (${graphPath}); run cdd-kit code-map`);
11608
+ }
11609
+ if (!selected.probe.available) {
11610
+ console.log(`CodeGraph: unavailable (${selected.probe.command})`);
11611
+ } else if (!selected.probe.initialized) {
11612
+ console.log("CodeGraph: available but project is not initialized (.codegraph/ missing)");
11613
+ }
11614
+ console.log("Next: run `codegraph init -i` to enable semantic graph queries, or continue with code-map fallback.");
11615
+ }
11616
+ return freshness.status === "config-error" ? 1 : 0;
11617
+ }
11618
+ async function graphSync(opts = {}) {
11619
+ const selected = selectEngine({ ...opts, engine: opts.engine ?? "codegraph" });
11620
+ if ("error" in selected)
11621
+ return printEngineError(selected.error, opts.json, selected.probe);
11622
+ if (selected.engine !== "codegraph") {
11623
+ return printEngineError("graph sync requires CodeGraph; code-map fallback refreshes during query/impact.", opts.json, selected.probe);
11624
+ }
11625
+ const args = ["sync"];
11626
+ if (opts.path)
11627
+ args.push(opts.path);
11628
+ return pipeResult(runCodeGraph(args));
11629
+ }
11630
+ async function graphQuery(term, opts) {
11631
+ const selected = selectEngine(opts);
11632
+ if ("error" in selected)
11633
+ return printEngineError(selected.error, opts.json, selected.probe);
11634
+ if (selected.engine === "codegraph") {
11635
+ const args = ["query", term, "--limit", String(opts.limit)];
11636
+ if (opts.json)
11637
+ args.push("--json");
11638
+ return pipeResult(runCodeGraph(args));
11639
+ }
11640
+ if (selected.engine === "native") {
11641
+ const mapPath = opts.map || ".cdd/code-map.yml";
11642
+ const ensured = await ensureNativeGraph(mapPath, opts.refresh !== false);
11643
+ if (ensured.error)
11644
+ return printEngineError(ensured.error, opts.json, selected.probe);
11645
+ try {
11646
+ const graph2 = loadCodeGraph(ensured.graphPath);
11647
+ const results = searchGraph(graph2, term, opts.limit);
11648
+ if (opts.json) {
11649
+ writeJson({ engine: "native", graph: ensured.graphPath, query: term, refreshed: ensured.refreshed, results });
11650
+ } else {
11651
+ console.log(`graph: ${ensured.graphPath}${ensured.refreshed ? " (refreshed)" : ""}`);
11652
+ console.log(`query: ${term}`);
11653
+ console.log(`results: ${results.length}`);
11654
+ for (const result of results) {
11655
+ const n = result.node;
11656
+ console.log(`- ${n.kind}: ${n.qualified_name} lines ${n.start_line}-${n.end_line}`);
11657
+ console.log(` edges: ${result.edges.incoming} incoming, ${result.edges.outgoing} outgoing`);
11658
+ }
11659
+ console.log("Next: run cdd-kit graph impact <node/file/symbol> before editing.");
11660
+ }
11661
+ return results.length === 0 ? 1 : 0;
11662
+ } catch (err) {
11663
+ return printEngineError(err.message, opts.json, selected.probe);
11664
+ }
11665
+ }
11666
+ return indexQuery(term, {
11667
+ map: opts.map || ".cdd/code-map.yml",
11668
+ limit: opts.limit,
11669
+ json: opts.json === true,
11670
+ refresh: opts.refresh !== false
11671
+ });
11672
+ }
11673
+ async function graphImpact2(term, opts) {
11674
+ const selected = selectEngine(opts);
11675
+ if ("error" in selected)
11676
+ return printEngineError(selected.error, opts.json, selected.probe);
11677
+ if (selected.engine === "codegraph") {
11678
+ const args = ["impact", term, "--depth", String(opts.depth)];
11679
+ if (opts.json)
11680
+ args.push("--json");
11681
+ return pipeResult(runCodeGraph(args));
11682
+ }
11683
+ if (selected.engine === "native") {
11684
+ const mapPath = opts.map || ".cdd/code-map.yml";
11685
+ const ensured = await ensureNativeGraph(mapPath, opts.refresh !== false);
11686
+ if (ensured.error)
11687
+ return printEngineError(ensured.error, opts.json, selected.probe);
11688
+ try {
11689
+ const graph2 = loadCodeGraph(ensured.graphPath);
11690
+ const impact = graphImpact(graph2, term, opts.depth, opts.limit);
11691
+ if (!impact)
11692
+ return printEngineError(`No graph node matched "${term}". Try \`cdd-kit graph query "${term}"\` first.`, opts.json, selected.probe);
11693
+ if (opts.json) {
11694
+ writeJson({ engine: "native", graph: ensured.graphPath, query: term, refreshed: ensured.refreshed, ...impact });
11695
+ } else {
11696
+ console.log(`graph: ${ensured.graphPath}${ensured.refreshed ? " (refreshed)" : ""}`);
11697
+ console.log(`target: ${impact.target.qualified_name} (${impact.target.kind})`);
11698
+ console.log(`impact depth: ${impact.depth}`);
11699
+ console.log("nodes:");
11700
+ for (const node of impact.nodes) {
11701
+ console.log(`- ${node.kind}: ${node.qualified_name} lines ${node.start_line}-${node.end_line}`);
11702
+ }
11703
+ console.log("edges:");
11704
+ for (const edge of impact.edges.slice(0, opts.limit)) {
11705
+ const source = graph2.nodes.find((n) => n.id === edge.source)?.qualified_name ?? edge.source;
11706
+ const target = graph2.nodes.find((n) => n.id === edge.target)?.qualified_name ?? edge.target;
11707
+ console.log(`- ${edge.kind}: ${source} -> ${target}${edge.line ? ` line ${edge.line}` : ""} (${edge.provenance})`);
11708
+ }
11709
+ console.log("Next: inspect target plus listed callers/callees/imports before editing.");
11710
+ }
11711
+ return 0;
11712
+ } catch (err) {
11713
+ return printEngineError(err.message, opts.json, selected.probe);
11714
+ }
11715
+ }
11716
+ if (!opts.json && opts.depth > 1) {
11717
+ console.log("graph engine: code-map fallback (depth is limited to direct imports/dependents)");
11718
+ }
11719
+ return indexImpact(term, {
11720
+ map: opts.map || ".cdd/code-map.yml",
11721
+ limit: opts.limit,
11722
+ json: opts.json === true,
11723
+ refresh: opts.refresh !== false
11724
+ });
11725
+ }
11726
+ async function graphContext2(task, opts) {
11727
+ const selected = selectEngine(opts);
11728
+ if ("error" in selected)
11729
+ return printEngineError(selected.error, opts.json, selected.probe);
11730
+ if (selected.engine === "codegraph") {
11731
+ const args = ["context", task, "--max-nodes", String(opts.maxNodes), "--format", opts.json ? "json" : "markdown"];
11732
+ return pipeResult(runCodeGraph(args));
11733
+ }
11734
+ if (selected.engine === "native") {
11735
+ const mapPath2 = opts.map || ".cdd/code-map.yml";
11736
+ const ensured = await ensureNativeGraph(mapPath2, opts.refresh !== false);
11737
+ if (ensured.error)
11738
+ return printEngineError(ensured.error, opts.json, selected.probe);
11739
+ try {
11740
+ const graph2 = loadCodeGraph(ensured.graphPath);
11741
+ const context2 = graphContext(graph2, task, opts.maxNodes);
11742
+ if (opts.json) {
11743
+ writeJson({ engine: "native", graph: ensured.graphPath, refreshed: ensured.refreshed, ...context2 });
11744
+ } else {
11745
+ console.log(`graph: ${ensured.graphPath}${ensured.refreshed ? " (refreshed)" : ""}`);
11746
+ console.log(`task: ${task}`);
11747
+ console.log("entry-points:");
11748
+ for (const entry of context2.entry_points) {
11749
+ console.log(`- ${entry.node.kind}: ${entry.node.qualified_name} lines ${entry.node.start_line}-${entry.node.end_line}`);
11750
+ }
11751
+ console.log("related edges:");
11752
+ for (const edge of context2.edges.slice(0, opts.maxNodes)) {
11753
+ const source = graph2.nodes.find((n) => n.id === edge.source)?.qualified_name ?? edge.source;
11754
+ const target = graph2.nodes.find((n) => n.id === edge.target)?.qualified_name ?? edge.target;
11755
+ console.log(`- ${edge.kind}: ${source} -> ${target}${edge.line ? ` line ${edge.line}` : ""}`);
11756
+ }
11757
+ console.log("Next: run cdd-kit graph impact on the most relevant entry point before editing.");
11758
+ }
11759
+ return context2.entry_points.length === 0 ? 1 : 0;
11760
+ } catch (err) {
11761
+ return printEngineError(err.message, opts.json, selected.probe);
11762
+ }
11763
+ }
11764
+ const mapPath = opts.map || ".cdd/code-map.yml";
11765
+ const freshness = await ensureCodeMapFresh(mapPath, opts.refresh !== false);
11766
+ if (freshness.error)
11767
+ return printEngineError(freshness.error, opts.json, selected.probe);
11768
+ if (!existsSync24(mapPath))
11769
+ return printEngineError(`${mapPath} is missing; run \`cdd-kit code-map\` first.`, opts.json, selected.probe);
11770
+ let entries;
11771
+ try {
11772
+ entries = loadCodeMapEntries(mapPath);
11773
+ } catch (err) {
11774
+ return printEngineError(`${mapPath} is not readable YAML: ${err.message}`, opts.json, selected.probe);
11775
+ }
11776
+ const results = queryEntries(entries, task).slice(0, opts.maxNodes);
11777
+ const payload = {
11778
+ engine: "codemap",
11779
+ query: task,
11780
+ refreshed: freshness.refreshed,
11781
+ warning: "CodeGraph is not active; context is built from code-map symbol/file matches only.",
11782
+ candidates: results,
11783
+ next: results.length > 0 ? "Run cdd-kit graph impact <candidate path or symbol> before editing." : "Try a symbol name, file stem, route/component name, or initialize CodeGraph for semantic context."
11784
+ };
11785
+ if (opts.json) {
11786
+ writeJson(payload);
11787
+ } else {
11788
+ console.log(`graph engine: code-map fallback${freshness.refreshed ? " (refreshed)" : ""}`);
11789
+ console.log(`task: ${task}`);
11790
+ if (results.length === 0) {
11791
+ console.log("candidates: none");
11792
+ console.log(payload.next);
11793
+ return 1;
11794
+ }
11795
+ console.log("candidates:");
11796
+ for (const result of results) {
11797
+ console.log(`- ${result.path} (${result.total_lines} lines)`);
11798
+ for (const match of result.matches.slice(0, 5)) {
11799
+ const loc = match.lines ? ` lines ${match.lines}` : match.line ? ` line ${match.line}` : "";
11800
+ console.log(` - ${match.kind}: ${match.name}${loc}`);
11801
+ }
11802
+ }
11803
+ console.log(payload.next);
11804
+ }
11805
+ return results.length === 0 ? 1 : 0;
11806
+ }
11807
+ var init_graph = __esm({
11808
+ "src/commands/graph.ts"() {
11809
+ "use strict";
11810
+ init_freshness();
11811
+ init_index_reader();
11812
+ init_reader();
11813
+ init_queries();
11814
+ init_index_query();
11815
+ init_index_impact();
10864
11816
  }
10865
11817
  });
10866
11818
 
@@ -10869,28 +11821,28 @@ var archive_exports = {};
10869
11821
  __export(archive_exports, {
10870
11822
  archive: () => archive
10871
11823
  });
10872
- import { join as join25 } from "path";
10873
- import { existsSync as existsSync23, mkdirSync as mkdirSync10, renameSync as renameSync2, readFileSync as readFileSync26, writeFileSync as writeFileSync13, appendFileSync, cpSync as cpSync3, rmSync as rmSync3 } from "fs";
11824
+ import { join as join26 } from "path";
11825
+ import { existsSync as existsSync25, mkdirSync as mkdirSync10, renameSync as renameSync2, readFileSync as readFileSync27, writeFileSync as writeFileSync13, appendFileSync, cpSync as cpSync3, rmSync as rmSync3 } from "fs";
10874
11826
  import yaml4 from "js-yaml";
10875
11827
  async function archive(changeId) {
10876
11828
  const cwd = process.cwd();
10877
- const changeDir = join25(cwd, "specs", "changes", changeId);
11829
+ const changeDir = join26(cwd, "specs", "changes", changeId);
10878
11830
  const archiveYear = (/* @__PURE__ */ new Date()).getFullYear().toString();
10879
- const archiveBase = join25(cwd, "specs", "archive", archiveYear);
10880
- const archiveDir = join25(archiveBase, changeId);
10881
- const indexPath = join25(cwd, "specs", "archive", "INDEX.md");
10882
- if (!existsSync23(changeDir)) {
11831
+ const archiveBase = join26(cwd, "specs", "archive", archiveYear);
11832
+ const archiveDir = join26(archiveBase, changeId);
11833
+ const indexPath = join26(cwd, "specs", "archive", "INDEX.md");
11834
+ if (!existsSync25(changeDir)) {
10883
11835
  log.error(`Change not found: specs/changes/${changeId}`);
10884
11836
  process.exit(1);
10885
11837
  }
10886
- if (existsSync23(archiveDir)) {
11838
+ if (existsSync25(archiveDir)) {
10887
11839
  log.error(`Already archived: specs/archive/${archiveYear}/${changeId}`);
10888
11840
  process.exit(1);
10889
11841
  }
10890
- const tasksPath = join25(changeDir, "tasks.yml");
10891
- if (existsSync23(tasksPath)) {
11842
+ const tasksPath = join26(changeDir, "tasks.yml");
11843
+ if (existsSync25(tasksPath)) {
10892
11844
  try {
10893
- const raw = readFileSync26(tasksPath, "utf8");
11845
+ const raw = readFileSync27(tasksPath, "utf8");
10894
11846
  const data = yaml4.load(raw);
10895
11847
  if (data?.status === "gate-blocked") {
10896
11848
  log.warn("tasks.yml has status: gate-blocked \u2014 archiving anyway (change was paused).");
@@ -10903,7 +11855,7 @@ async function archive(changeId) {
10903
11855
  log.warn("tasks.yml could not be parsed \u2014 archiving anyway.");
10904
11856
  }
10905
11857
  }
10906
- if (!existsSync23(archiveBase)) {
11858
+ if (!existsSync25(archiveBase)) {
10907
11859
  mkdirSync10(archiveBase, { recursive: true });
10908
11860
  }
10909
11861
  try {
@@ -10920,7 +11872,7 @@ async function archive(changeId) {
10920
11872
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
10921
11873
  const indexLine = `| ${changeId} | ${archiveYear} | ${today} | specs/archive/${archiveYear}/${changeId}/ |
10922
11874
  `;
10923
- if (!existsSync23(indexPath)) {
11875
+ if (!existsSync25(indexPath)) {
10924
11876
  writeFileSync13(indexPath, `# Archive Index
10925
11877
 
10926
11878
  | change-id | year | archived-date | path |
@@ -10945,19 +11897,19 @@ var abandon_exports = {};
10945
11897
  __export(abandon_exports, {
10946
11898
  abandon: () => abandon
10947
11899
  });
10948
- import { join as join26 } from "path";
10949
- import { existsSync as existsSync24, readFileSync as readFileSync27, writeFileSync as writeFileSync14, appendFileSync as appendFileSync2, mkdirSync as mkdirSync11 } from "fs";
11900
+ import { join as join27 } from "path";
11901
+ import { existsSync as existsSync26, readFileSync as readFileSync28, writeFileSync as writeFileSync14, appendFileSync as appendFileSync2, mkdirSync as mkdirSync11 } from "fs";
10950
11902
  import yaml5 from "js-yaml";
10951
11903
  async function abandon(changeId, opts) {
10952
11904
  const cwd = process.cwd();
10953
- const changeDir = join26(cwd, "specs", "changes", changeId);
10954
- const tasksPath = join26(changeDir, "tasks.yml");
10955
- if (!existsSync24(changeDir)) {
11905
+ const changeDir = join27(cwd, "specs", "changes", changeId);
11906
+ const tasksPath = join27(changeDir, "tasks.yml");
11907
+ if (!existsSync26(changeDir)) {
10956
11908
  log.error(`Change not found: specs/changes/${changeId}`);
10957
11909
  process.exit(1);
10958
11910
  }
10959
- if (existsSync24(tasksPath)) {
10960
- const raw = readFileSync27(tasksPath, "utf8");
11911
+ if (existsSync26(tasksPath)) {
11912
+ const raw = readFileSync28(tasksPath, "utf8");
10961
11913
  const data = yaml5.load(raw) ?? {};
10962
11914
  data["status"] = "abandoned";
10963
11915
  if (!data["change-id"]) {
@@ -10966,15 +11918,15 @@ async function abandon(changeId, opts) {
10966
11918
  writeFileSync14(tasksPath, yaml5.dump(data, { lineWidth: -1, noRefs: true }), "utf8");
10967
11919
  }
10968
11920
  const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
10969
- const archiveDir = join26(cwd, "specs", "archive");
10970
- const indexPath = join26(archiveDir, "INDEX.md");
11921
+ const archiveDir = join27(cwd, "specs", "archive");
11922
+ const indexPath = join27(archiveDir, "INDEX.md");
10971
11923
  const reason = opts.reason ?? "no reason given";
10972
11924
  const indexLine = `| ${changeId} | abandoned | ${today} | ${reason} |
10973
11925
  `;
10974
- if (!existsSync24(archiveDir)) {
11926
+ if (!existsSync26(archiveDir)) {
10975
11927
  mkdirSync11(archiveDir, { recursive: true });
10976
11928
  }
10977
- if (!existsSync24(indexPath)) {
11929
+ if (!existsSync26(indexPath)) {
10978
11930
  writeFileSync14(indexPath, `# Archive Index
10979
11931
 
10980
11932
  | change-id | status | date | notes |
@@ -10999,15 +11951,15 @@ var list_changes_exports = {};
10999
11951
  __export(list_changes_exports, {
11000
11952
  listChanges: () => listChanges
11001
11953
  });
11002
- import { join as join27 } from "path";
11003
- import { existsSync as existsSync25, readdirSync as readdirSync13, readFileSync as readFileSync28 } from "fs";
11954
+ import { join as join28 } from "path";
11955
+ import { existsSync as existsSync27, readdirSync as readdirSync13, readFileSync as readFileSync29 } from "fs";
11004
11956
  import yaml6 from "js-yaml";
11005
11957
  async function listChanges() {
11006
11958
  const cwd = process.cwd();
11007
- const changesDir = join27(cwd, "specs", "changes");
11959
+ const changesDir = join28(cwd, "specs", "changes");
11008
11960
  log.blank();
11009
11961
  const active = [];
11010
- if (existsSync25(changesDir)) {
11962
+ if (existsSync27(changesDir)) {
11011
11963
  active.push(...readdirSync13(changesDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name));
11012
11964
  }
11013
11965
  if (active.length === 0) {
@@ -11015,12 +11967,12 @@ async function listChanges() {
11015
11967
  } else {
11016
11968
  log.info("Active changes:");
11017
11969
  for (const id of active) {
11018
- const tasksPath = join27(changesDir, id, "tasks.yml");
11970
+ const tasksPath = join28(changesDir, id, "tasks.yml");
11019
11971
  let status = "in-progress";
11020
11972
  let pending = 0;
11021
- if (existsSync25(tasksPath)) {
11973
+ if (existsSync27(tasksPath)) {
11022
11974
  try {
11023
- const raw = readFileSync28(tasksPath, "utf8");
11975
+ const raw = readFileSync29(tasksPath, "utf8");
11024
11976
  const data = yaml6.load(raw);
11025
11977
  if (data?.status)
11026
11978
  status = data.status;
@@ -11052,8 +12004,8 @@ __export(context_exports, {
11052
12004
  rejectContextExpansion: () => rejectContextExpansion,
11053
12005
  requestContextExpansion: () => requestContextExpansion
11054
12006
  });
11055
- import { existsSync as existsSync26, readFileSync as readFileSync29, writeFileSync as writeFileSync15 } from "fs";
11056
- import { join as join28 } from "path";
12007
+ import { existsSync as existsSync28, readFileSync as readFileSync30, writeFileSync as writeFileSync15 } from "fs";
12008
+ import { join as join29 } from "path";
11057
12009
  import picomatch2 from "picomatch";
11058
12010
  function normalizePath(path) {
11059
12011
  return path.replace(/\\/g, "/").replace(/^\.\//, "").trim();
@@ -11068,15 +12020,15 @@ function validateRepoRelativePath(path) {
11068
12020
  return null;
11069
12021
  }
11070
12022
  function manifestPathFor(changeId) {
11071
- return join28(process.cwd(), "specs", "changes", changeId, "context-manifest.md");
12023
+ return join29(process.cwd(), "specs", "changes", changeId, "context-manifest.md");
11072
12024
  }
11073
12025
  function readManifest(changeId) {
11074
12026
  const manifestPath = manifestPathFor(changeId);
11075
- if (!existsSync26(manifestPath)) {
12027
+ if (!existsSync28(manifestPath)) {
11076
12028
  log.error(`context manifest not found: specs/changes/${changeId}/context-manifest.md`);
11077
12029
  process.exit(1);
11078
12030
  }
11079
- return readFileSync29(manifestPath, "utf8");
12031
+ return readFileSync30(manifestPath, "utf8");
11080
12032
  }
11081
12033
  function writeManifest(changeId, content) {
11082
12034
  writeFileSync15(manifestPathFor(changeId), content.endsWith("\n") ? content : `${content}
@@ -11118,11 +12070,11 @@ function pathMatches(relPath, patterns, currentChangeId) {
11118
12070
  });
11119
12071
  }
11120
12072
  function loadContextPolicy() {
11121
- const policyPath = join28(process.cwd(), ".cdd", "context-policy.json");
11122
- if (!existsSync26(policyPath))
12073
+ const policyPath = join29(process.cwd(), ".cdd", "context-policy.json");
12074
+ if (!existsSync28(policyPath))
11123
12075
  return { forbiddenPaths: DEFAULT_FORBIDDEN_PATHS };
11124
12076
  try {
11125
- const custom = JSON.parse(readFileSync29(policyPath, "utf8"));
12077
+ const custom = JSON.parse(readFileSync30(policyPath, "utf8"));
11126
12078
  return {
11127
12079
  forbiddenPaths: Array.from(/* @__PURE__ */ new Set([
11128
12080
  ...DEFAULT_FORBIDDEN_PATHS,
@@ -11404,10 +12356,10 @@ var init_context = __esm({
11404
12356
  });
11405
12357
 
11406
12358
  // src/cli/index.ts
11407
- import { readFileSync as readFileSync30 } from "fs";
12359
+ import { readFileSync as readFileSync31 } from "fs";
11408
12360
  import os from "os";
11409
12361
  import { fileURLToPath as fileURLToPath3 } from "url";
11410
- import { dirname as dirname7, join as join29 } from "path";
12362
+ import { dirname as dirname7, join as join30 } from "path";
11411
12363
  import { Command } from "commander";
11412
12364
 
11413
12365
  // src/commands/init.ts
@@ -12513,7 +13465,7 @@ async function installHooks() {
12513
13465
 
12514
13466
  // src/cli/index.ts
12515
13467
  var __dirname2 = dirname7(fileURLToPath3(import.meta.url));
12516
- var pkg = JSON.parse(readFileSync30(join29(__dirname2, "..", "..", "package.json"), "utf8"));
13468
+ var pkg = JSON.parse(readFileSync31(join30(__dirname2, "..", "..", "package.json"), "utf8"));
12517
13469
  var program = new Command();
12518
13470
  program.name("cdd-kit").description("Contract-Driven Delivery Kit CLI").version(pkg.version);
12519
13471
  program.command("init").description(
@@ -12625,6 +13577,51 @@ index.command("impact <path-or-symbol>").description("Show indexed local imports
12625
13577
  });
12626
13578
  process.exit(exit);
12627
13579
  });
13580
+ var graph = program.command("graph").description("Query native cdd-kit code graph context with optional CodeGraph adapter and code-map fallback");
13581
+ graph.command("status [path]").description("Show active graph engine and index health").option("--engine <engine>", "Graph engine: auto, native, codegraph, or codemap", "auto").option("--map <path>", "Code-map YAML path for fallback status", ".cdd/code-map.yml").option("--json", "Print machine-readable JSON", false).action(async (path, opts) => {
13582
+ const { graphStatus: graphStatus2 } = await Promise.resolve().then(() => (init_graph(), graph_exports));
13583
+ const exit = await graphStatus2({ path, engine: opts.engine, map: opts.map, json: opts.json === true });
13584
+ process.exit(exit);
13585
+ });
13586
+ graph.command("sync [path]").description("Run CodeGraph incremental sync (requires CodeGraph)").option("--engine <engine>", "Graph engine: codegraph", "codegraph").option("--json", "Print machine-readable JSON on errors", false).action(async (path, opts) => {
13587
+ const { graphSync: graphSync2 } = await Promise.resolve().then(() => (init_graph(), graph_exports));
13588
+ const exit = await graphSync2({ path, engine: opts.engine, json: opts.json === true });
13589
+ process.exit(exit);
13590
+ });
13591
+ graph.command("query <term>").description("Search native graph symbols, optionally delegating to CodeGraph or code-map").option("--engine <engine>", "Graph engine: auto, native, codegraph, or codemap", "auto").option("--map <path>", "Code-map YAML path for fallback", ".cdd/code-map.yml").option("--limit <n>", "Maximum results to print", "10").option("--json", "Print machine-readable JSON", false).option("--no-refresh", "Do not auto-regenerate stale or missing fallback code-map").action(async (term, opts) => {
13592
+ const { graphQuery: graphQuery2 } = await Promise.resolve().then(() => (init_graph(), graph_exports));
13593
+ const exit = await graphQuery2(term, {
13594
+ engine: opts.engine,
13595
+ map: opts.map,
13596
+ limit: parseInt(opts.limit, 10),
13597
+ json: opts.json === true,
13598
+ refresh: opts.refresh !== false
13599
+ });
13600
+ process.exit(exit);
13601
+ });
13602
+ graph.command("impact <path-or-symbol>").description("Analyze impact radius with native graph calls/imports, CodeGraph, or code-map fallback").option("--engine <engine>", "Graph engine: auto, native, codegraph, or codemap", "auto").option("--map <path>", "Code-map YAML path for fallback", ".cdd/code-map.yml").option("--limit <n>", "Maximum fallback dependent files to print", "20").option("--depth <n>", "CodeGraph traversal depth (fallback is direct only)", "2").option("--json", "Print machine-readable JSON", false).option("--no-refresh", "Do not auto-regenerate stale or missing fallback code-map").action(async (term, opts) => {
13603
+ const { graphImpact: graphImpact3 } = await Promise.resolve().then(() => (init_graph(), graph_exports));
13604
+ const exit = await graphImpact3(term, {
13605
+ engine: opts.engine,
13606
+ map: opts.map,
13607
+ limit: parseInt(opts.limit, 10),
13608
+ depth: parseInt(opts.depth, 10),
13609
+ json: opts.json === true,
13610
+ refresh: opts.refresh !== false
13611
+ });
13612
+ process.exit(exit);
13613
+ });
13614
+ graph.command("context <task>").description("Build task context with native graph, CodeGraph, or code-map candidates").option("--engine <engine>", "Graph engine: auto, native, codegraph, or codemap", "auto").option("--map <path>", "Code-map YAML path for fallback", ".cdd/code-map.yml").option("--max-nodes <n>", "Maximum context candidates/nodes", "20").option("--json", "Print machine-readable JSON", false).option("--no-refresh", "Do not auto-regenerate stale or missing fallback code-map").action(async (task, opts) => {
13615
+ const { graphContext: graphContext3 } = await Promise.resolve().then(() => (init_graph(), graph_exports));
13616
+ const exit = await graphContext3(task, {
13617
+ engine: opts.engine,
13618
+ map: opts.map,
13619
+ maxNodes: parseInt(opts.maxNodes, 10),
13620
+ json: opts.json === true,
13621
+ refresh: opts.refresh !== false
13622
+ });
13623
+ process.exit(exit);
13624
+ });
12628
13625
  program.command("gate <change-id>").description("Run delivery-quality gate for a change (required artifacts, tasks, tier, contracts)").option("--strict", "Treat pending tasks (except section 7) as errors", false).action(async (id, opts) => {
12629
13626
  await gate(id, { strict: opts.strict });
12630
13627
  });