@nanonets/graft 0.9.1 → 0.10.1

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.
Files changed (94) hide show
  1. package/README.md +49 -45
  2. package/dist/ask/fuse.d.ts.map +1 -1
  3. package/dist/ask/fuse.js +32 -14
  4. package/dist/ask/fuse.js.map +1 -1
  5. package/dist/claude/hooks.d.ts +13 -0
  6. package/dist/claude/hooks.d.ts.map +1 -1
  7. package/dist/claude/hooks.js +26 -2
  8. package/dist/claude/hooks.js.map +1 -1
  9. package/dist/claude/init.d.ts.map +1 -1
  10. package/dist/claude/init.js +6 -3
  11. package/dist/claude/init.js.map +1 -1
  12. package/dist/cli.js +93 -39
  13. package/dist/cli.js.map +1 -1
  14. package/dist/engine.d.ts +6 -2
  15. package/dist/engine.d.ts.map +1 -1
  16. package/dist/engine.js +4 -1
  17. package/dist/engine.js.map +1 -1
  18. package/dist/graph/bindings.d.ts.map +1 -1
  19. package/dist/graph/bindings.js +80 -0
  20. package/dist/graph/bindings.js.map +1 -1
  21. package/dist/graph/build.d.ts +5 -0
  22. package/dist/graph/build.d.ts.map +1 -1
  23. package/dist/graph/build.js +21 -2
  24. package/dist/graph/build.js.map +1 -1
  25. package/dist/graph/check.d.ts +1 -1
  26. package/dist/graph/check.d.ts.map +1 -1
  27. package/dist/graph/check.js +13 -3
  28. package/dist/graph/check.js.map +1 -1
  29. package/dist/graph/extract.d.ts +6 -1
  30. package/dist/graph/extract.d.ts.map +1 -1
  31. package/dist/graph/extract.js +192 -10
  32. package/dist/graph/extract.js.map +1 -1
  33. package/dist/graph/generic.d.ts +25 -0
  34. package/dist/graph/generic.d.ts.map +1 -0
  35. package/dist/graph/generic.js +341 -0
  36. package/dist/graph/generic.js.map +1 -0
  37. package/dist/graph/invariants.d.ts +32 -0
  38. package/dist/graph/invariants.d.ts.map +1 -0
  39. package/dist/graph/invariants.js +49 -0
  40. package/dist/graph/invariants.js.map +1 -0
  41. package/dist/graph/lsp/client.d.ts +43 -0
  42. package/dist/graph/lsp/client.d.ts.map +1 -0
  43. package/dist/graph/lsp/client.js +179 -0
  44. package/dist/graph/lsp/client.js.map +1 -0
  45. package/dist/graph/lsp/enrich.d.ts +11 -0
  46. package/dist/graph/lsp/enrich.d.ts.map +1 -0
  47. package/dist/graph/lsp/enrich.js +155 -0
  48. package/dist/graph/lsp/enrich.js.map +1 -0
  49. package/dist/graph/lsp/registry.d.ts +15 -0
  50. package/dist/graph/lsp/registry.d.ts.map +1 -0
  51. package/dist/graph/lsp/registry.js +46 -0
  52. package/dist/graph/lsp/registry.js.map +1 -0
  53. package/dist/graph/queries/c.scm +13 -0
  54. package/dist/graph/queries/c_sharp.scm +19 -0
  55. package/dist/graph/queries/cpp.scm +23 -0
  56. package/dist/graph/queries/elixir.scm +54 -0
  57. package/dist/graph/queries/java.scm +20 -0
  58. package/dist/graph/queries/kotlin.scm +43 -0
  59. package/dist/graph/queries/php.scm +40 -0
  60. package/dist/graph/queries/ruby.scm +65 -0
  61. package/dist/graph/queries/rust.scm +41 -0
  62. package/dist/graph/queries/scala.scm +66 -0
  63. package/dist/graph/queries/solidity.scm +43 -0
  64. package/dist/graph/queries/swift.scm +51 -0
  65. package/dist/graph/resolve.d.ts.map +1 -1
  66. package/dist/graph/resolve.js +124 -18
  67. package/dist/graph/resolve.js.map +1 -1
  68. package/dist/graph/root.d.ts +11 -0
  69. package/dist/graph/root.d.ts.map +1 -0
  70. package/dist/graph/root.js +40 -0
  71. package/dist/graph/root.js.map +1 -0
  72. package/dist/graph/source-files.d.ts.map +1 -1
  73. package/dist/graph/source-files.js +5 -1
  74. package/dist/graph/source-files.js.map +1 -1
  75. package/dist/graph/types.d.ts +14 -7
  76. package/dist/graph/types.d.ts.map +1 -1
  77. package/dist/graph/types.js +2 -2
  78. package/dist/graph/workspace-cli.d.ts +1 -1
  79. package/dist/graph/workspace-cli.d.ts.map +1 -1
  80. package/dist/graph/workspace-cli.js +2 -2
  81. package/dist/graph/workspace-cli.js.map +1 -1
  82. package/dist/graph/workspace.d.ts +2 -2
  83. package/dist/graph/workspace.d.ts.map +1 -1
  84. package/dist/graph/workspace.js +2 -2
  85. package/dist/graph/workspace.js.map +1 -1
  86. package/dist/hosts/codex-hooks.d.ts +3 -3
  87. package/dist/hosts/codex-hooks.d.ts.map +1 -1
  88. package/dist/hosts/codex-hooks.js +27 -21
  89. package/dist/hosts/codex-hooks.js.map +1 -1
  90. package/dist/mcp/tools.js +6 -6
  91. package/dist/mcp/tools.js.map +1 -1
  92. package/package.json +15 -2
  93. package/scripts/build-viewer.mjs +17 -1
  94. package/scripts/graph-quality.mjs +117 -0
@@ -4,7 +4,7 @@
4
4
  * so `graft viz` needs no install or build step at runtime.
5
5
  */
6
6
  import { build } from "esbuild";
7
- import { mkdirSync, copyFileSync } from "node:fs";
7
+ import { mkdirSync, copyFileSync, readdirSync } from "node:fs";
8
8
  import { dirname, join } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
 
@@ -26,3 +26,19 @@ for (const asset of ["index.html", "style.css"]) {
26
26
  }
27
27
 
28
28
  console.log("viewer bundle → dist/viewer/");
29
+
30
+ // The generic (breadth) tier's tags.scm query files are runtime assets — tsc
31
+ // doesn't emit non-TS files, so copy them into dist so the published package
32
+ // (which ships `dist` only) can load them. generic.ts resolves dist/graph/queries
33
+ // first, then falls back to src/graph/queries for local dev.
34
+ const scmSrc = join(root, "src", "graph", "queries");
35
+ const scmOut = join(root, "dist", "graph", "queries");
36
+ mkdirSync(scmOut, { recursive: true });
37
+ let scmCount = 0;
38
+ for (const f of readdirSync(scmSrc)) {
39
+ if (f.endsWith(".scm")) {
40
+ copyFileSync(join(scmSrc, f), join(scmOut, f));
41
+ scmCount++;
42
+ }
43
+ }
44
+ console.log(`grammar queries → dist/graph/queries/ (${scmCount} .scm)`);
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Graph-quality report + invariant check for a built graph (`graft/.graph/wiring.json`).
3
+ *
4
+ * node scripts/graph-quality.mjs <repo-dir-or-wiring.json> [--json] [--strict]
5
+ *
6
+ * Tier-0 of the quality strategy: needs no external oracle. Reports the graph's
7
+ * shape (nodes by kind/origin, edges by relation/confidence, resolution rate) and
8
+ * asserts structural INVARIANTS that must always hold:
9
+ * - no dangling edge endpoints (every source is a node; every target is a node
10
+ * or a deliberately-unresolved external string)
11
+ * - valid spans (`Lx-Ly`, x<=y, within file line count where known)
12
+ * - unique node ids; non-empty names; kinds in the allowed set
13
+ * - no self-loop call edges
14
+ * Exits non-zero with --strict when any invariant fails (CI gate).
15
+ */
16
+ import { readFileSync, existsSync } from "node:fs";
17
+ import { join } from "node:path";
18
+
19
+ const KINDS = new Set(["file","class","function","method","interface","type","enum","struct","module","constant","variable"]);
20
+ const RELATIONS = new Set(["contains","calls","imports","references","implements","extends"]);
21
+ const CONFIDENCE = new Set(["lsp_resolved","lsp_dispatch","extracted","inferred"]);
22
+
23
+ const arg = process.argv[2] ?? ".";
24
+ const json = process.argv.includes("--json");
25
+ const strict = process.argv.includes("--strict");
26
+ const wpath = arg.endsWith(".json") ? arg
27
+ : [join(arg, "graft", ".graph", "wiring.json"), join(arg, "graft", "wiring.json")].find(existsSync);
28
+ if (!wpath || !existsSync(wpath)) { console.error(`no graph found at ${arg} (run \`graft build\` first)`); process.exit(2); }
29
+
30
+ const g = JSON.parse(readFileSync(wpath, "utf8"));
31
+ const nodes = g.nodes ?? [], edges = g.edges ?? [];
32
+ const ids = new Set(nodes.map((n) => n.id));
33
+
34
+ const bump = (m, k) => m.set(k, (m.get(k) ?? 0) + 1);
35
+ const byKind = new Map(), byOrigin = new Map(), byRel = new Map(), byConf = new Map();
36
+ for (const n of nodes) { bump(byKind, n.kind); bump(byOrigin, n.origin ?? "?"); }
37
+ for (const e of edges) { bump(byRel, e.relation); bump(byConf, e.confidence); }
38
+
39
+ // ── invariants ──
40
+ const problems = [];
41
+ const seen = new Set();
42
+ for (const n of nodes) {
43
+ if (seen.has(n.id)) problems.push(`dup id: ${n.id}`); seen.add(n.id);
44
+ if (!n.name || !String(n.name).trim()) problems.push(`empty name: ${n.id}`);
45
+ if (!KINDS.has(n.kind)) problems.push(`bad kind '${n.kind}': ${n.id}`);
46
+ const m = /^L(\d+)-L(\d+)$/.exec(n.span ?? "");
47
+ if (!m) problems.push(`bad span '${n.span}': ${n.id}`);
48
+ else if (Number(m[1]) > Number(m[2])) problems.push(`inverted span ${n.span}: ${n.id}`);
49
+ }
50
+ // an edge target may be a node id OR a deliberately-unresolved external string
51
+ // (import specifier / bare heritage name); only calls/references/contains must
52
+ // point at real nodes.
53
+ let dangling = 0, selfLoops = 0, unresolvedExternal = 0;
54
+ for (const e of edges) {
55
+ if (!RELATIONS.has(e.relation)) problems.push(`bad relation '${e.relation}'`);
56
+ if (!CONFIDENCE.has(e.confidence)) problems.push(`bad confidence '${e.confidence}'`);
57
+ if (!ids.has(e.source)) { problems.push(`dangling source: ${e.source}`); dangling++; }
58
+ const targetIsNode = ids.has(e.target);
59
+ if (!targetIsNode) {
60
+ if (e.relation === "imports" || e.relation === "extends" || e.relation === "implements") unresolvedExternal++;
61
+ else { problems.push(`dangling ${e.relation} target: ${e.source} → ${e.target}`); dangling++; }
62
+ }
63
+ if (e.relation === "calls" && e.source === e.target) selfLoops++;
64
+ }
65
+
66
+ // ── resolution / connectivity metrics ──
67
+ const calls = edges.filter((e) => e.relation === "calls");
68
+ const resolvedCalls = calls.filter((e) => ids.has(e.target)).length;
69
+ const withEdge = new Set();
70
+ for (const e of edges) { if (e.relation !== "contains") { withEdge.add(e.source); if (ids.has(e.target)) withEdge.add(e.target); } }
71
+ const symbolNodes = nodes.filter((n) => n.kind !== "file");
72
+ const orphans = symbolNodes.filter((n) => !withEdge.has(n.id)).length;
73
+
74
+ const report = {
75
+ graph: wpath,
76
+ nodes: nodes.length,
77
+ symbolNodes: symbolNodes.length,
78
+ edges: edges.length,
79
+ byKind: Object.fromEntries([...byKind].sort((a,b)=>b[1]-a[1])),
80
+ byOrigin: Object.fromEntries(byOrigin),
81
+ byRelation: Object.fromEntries(byRel),
82
+ byConfidence: Object.fromEntries(byConf),
83
+ resolution: {
84
+ calls: calls.length,
85
+ resolvedToNode: resolvedCalls,
86
+ resolvedPct: calls.length ? Math.round((resolvedCalls / calls.length) * 100) : null,
87
+ unresolvedExternalImports: unresolvedExternal,
88
+ },
89
+ connectivity: {
90
+ orphanSymbolNodes: orphans,
91
+ orphanPct: symbolNodes.length ? Math.round((orphans / symbolNodes.length) * 100) : null,
92
+ },
93
+ invariants: {
94
+ ok: problems.length === 0,
95
+ danglingEdges: dangling,
96
+ selfLoopCalls: selfLoops,
97
+ violations: problems.length,
98
+ sample: problems.slice(0, 15),
99
+ },
100
+ };
101
+
102
+ if (json) { console.log(JSON.stringify(report, null, 2)); }
103
+ else {
104
+ const p = report;
105
+ console.log(`graph-quality — ${p.graph}`);
106
+ console.log(` nodes ${p.nodes} (${p.symbolNodes} symbols) · edges ${p.edges}`);
107
+ console.log(` kinds: ${Object.entries(p.byKind).map(([k,v])=>`${k}=${v}`).join(" ")}`);
108
+ console.log(` origin: ${Object.entries(p.byOrigin).map(([k,v])=>`${k}=${v}`).join(" ")}`);
109
+ console.log(` relations: ${Object.entries(p.byRelation).map(([k,v])=>`${k}=${v}`).join(" ")}`);
110
+ console.log(` confidence: ${Object.entries(p.byConfidence).map(([k,v])=>`${k}=${v}`).join(" ")}`);
111
+ console.log(` calls resolved: ${p.resolution.resolvedToNode}/${p.resolution.calls} (${p.resolution.resolvedPct}%)`);
112
+ console.log(` orphan symbols: ${p.connectivity.orphanSymbolNodes}/${p.symbolNodes} (${p.connectivity.orphanPct}%)`);
113
+ console.log(` INVARIANTS: ${p.invariants.ok ? "OK ✓" : `FAIL ✗ (${p.invariants.violations} violations, ${p.invariants.danglingEdges} dangling)`}`);
114
+ if (!p.invariants.ok) for (const s of p.invariants.sample) console.log(` - ${s}`);
115
+ if (p.invariants.selfLoopCalls) console.log(` note: ${p.invariants.selfLoopCalls} self-loop calls`);
116
+ }
117
+ if (strict && !report.invariants.ok) process.exit(1);