homegraph 1.1.3 → 1.2.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.
Files changed (246) hide show
  1. package/README.md +43 -18
  2. package/dist/arkts/ohos-api-index.d.ts +15 -0
  3. package/dist/arkts/ohos-api-index.d.ts.map +1 -0
  4. package/dist/arkts/ohos-api-index.js +190 -0
  5. package/dist/arkts/ohos-api-index.js.map +1 -0
  6. package/dist/arkts/ohos-sdk-input.d.ts +36 -0
  7. package/dist/arkts/ohos-sdk-input.d.ts.map +1 -0
  8. package/dist/arkts/ohos-sdk-input.js +214 -0
  9. package/dist/arkts/ohos-sdk-input.js.map +1 -0
  10. package/dist/bin/command-supervision.d.ts +12 -0
  11. package/dist/bin/command-supervision.d.ts.map +1 -0
  12. package/dist/bin/command-supervision.js +86 -0
  13. package/dist/bin/command-supervision.js.map +1 -0
  14. package/dist/bin/homegraph.d.ts +1 -1
  15. package/dist/bin/homegraph.js +706 -168
  16. package/dist/bin/homegraph.js.map +1 -1
  17. package/dist/db/index.d.ts +20 -0
  18. package/dist/db/index.d.ts.map +1 -1
  19. package/dist/db/index.js +39 -0
  20. package/dist/db/index.js.map +1 -1
  21. package/dist/db/migrations.d.ts +1 -1
  22. package/dist/db/migrations.d.ts.map +1 -1
  23. package/dist/db/migrations.js +40 -1
  24. package/dist/db/migrations.js.map +1 -1
  25. package/dist/db/queries.d.ts +14 -0
  26. package/dist/db/queries.d.ts.map +1 -1
  27. package/dist/db/queries.js +174 -3
  28. package/dist/db/queries.js.map +1 -1
  29. package/dist/db/schema.sql +20 -0
  30. package/dist/directory.d.ts +32 -0
  31. package/dist/directory.d.ts.map +1 -1
  32. package/dist/directory.js +83 -0
  33. package/dist/directory.js.map +1 -1
  34. package/dist/extraction/arkts-batch-worker.d.ts +2 -0
  35. package/dist/extraction/arkts-batch-worker.d.ts.map +1 -0
  36. package/dist/extraction/arkts-batch-worker.js +28 -0
  37. package/dist/extraction/arkts-batch-worker.js.map +1 -0
  38. package/dist/extraction/context.d.ts +11 -0
  39. package/dist/extraction/context.d.ts.map +1 -1
  40. package/dist/extraction/context.js +20 -0
  41. package/dist/extraction/context.js.map +1 -1
  42. package/dist/extraction/index.d.ts +16 -2
  43. package/dist/extraction/index.d.ts.map +1 -1
  44. package/dist/extraction/index.js +619 -380
  45. package/dist/extraction/index.js.map +1 -1
  46. package/dist/extraction/languages/arkts-state-decorators.d.ts +13 -0
  47. package/dist/extraction/languages/arkts-state-decorators.d.ts.map +1 -0
  48. package/dist/extraction/languages/arkts-state-decorators.js +26 -0
  49. package/dist/extraction/languages/arkts-state-decorators.js.map +1 -0
  50. package/dist/extraction/languages/arkts-viewtree.d.ts +4 -2
  51. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
  52. package/dist/extraction/languages/arkts-viewtree.js +21 -6
  53. package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
  54. package/dist/extraction/languages/arkts.d.ts +98 -2
  55. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  56. package/dist/extraction/languages/arkts.js +1290 -61
  57. package/dist/extraction/languages/arkts.js.map +1 -1
  58. package/dist/extraction/languages/c-cpp.d.ts +56 -0
  59. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  60. package/dist/extraction/languages/c-cpp.js +198 -1
  61. package/dist/extraction/languages/c-cpp.js.map +1 -1
  62. package/dist/extraction/languages/ohos-api-consumer.d.ts +34 -0
  63. package/dist/extraction/languages/ohos-api-consumer.d.ts.map +1 -0
  64. package/dist/extraction/languages/ohos-api-consumer.js +283 -0
  65. package/dist/extraction/languages/ohos-api-consumer.js.map +1 -0
  66. package/dist/extraction/parse-pool.d.ts +126 -0
  67. package/dist/extraction/parse-pool.d.ts.map +1 -0
  68. package/dist/extraction/parse-pool.js +319 -0
  69. package/dist/extraction/parse-pool.js.map +1 -0
  70. package/dist/extraction/tree-sitter-types.d.ts +17 -0
  71. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  72. package/dist/extraction/tree-sitter.d.ts +21 -0
  73. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  74. package/dist/extraction/tree-sitter.js +198 -27
  75. package/dist/extraction/tree-sitter.js.map +1 -1
  76. package/dist/graph/traversal.d.ts.map +1 -1
  77. package/dist/graph/traversal.js +76 -17
  78. package/dist/graph/traversal.js.map +1 -1
  79. package/dist/index.d.ts +25 -0
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +78 -4
  82. package/dist/index.js.map +1 -1
  83. package/dist/mcp/daemon-paths.d.ts +30 -3
  84. package/dist/mcp/daemon-paths.d.ts.map +1 -1
  85. package/dist/mcp/daemon-paths.js +50 -10
  86. package/dist/mcp/daemon-paths.js.map +1 -1
  87. package/dist/mcp/daemon-registry.d.ts.map +1 -1
  88. package/dist/mcp/daemon-registry.js +7 -3
  89. package/dist/mcp/daemon-registry.js.map +1 -1
  90. package/dist/mcp/daemon.d.ts +48 -0
  91. package/dist/mcp/daemon.d.ts.map +1 -1
  92. package/dist/mcp/daemon.js +196 -32
  93. package/dist/mcp/daemon.js.map +1 -1
  94. package/dist/mcp/engine.d.ts +17 -0
  95. package/dist/mcp/engine.d.ts.map +1 -1
  96. package/dist/mcp/engine.js +73 -1
  97. package/dist/mcp/engine.js.map +1 -1
  98. package/dist/mcp/index.d.ts.map +1 -1
  99. package/dist/mcp/index.js +25 -43
  100. package/dist/mcp/index.js.map +1 -1
  101. package/dist/mcp/ppid-watchdog.d.ts +18 -0
  102. package/dist/mcp/ppid-watchdog.d.ts.map +1 -1
  103. package/dist/mcp/ppid-watchdog.js +37 -0
  104. package/dist/mcp/ppid-watchdog.js.map +1 -1
  105. package/dist/mcp/query-cache.d.ts +25 -0
  106. package/dist/mcp/query-cache.d.ts.map +1 -0
  107. package/dist/mcp/query-cache.js +191 -0
  108. package/dist/mcp/query-cache.js.map +1 -0
  109. package/dist/mcp/query-pool.d.ts +94 -0
  110. package/dist/mcp/query-pool.d.ts.map +1 -0
  111. package/dist/mcp/query-pool.js +297 -0
  112. package/dist/mcp/query-pool.js.map +1 -0
  113. package/dist/mcp/query-worker.d.ts +24 -0
  114. package/dist/mcp/query-worker.d.ts.map +1 -0
  115. package/dist/mcp/query-worker.js +87 -0
  116. package/dist/mcp/query-worker.js.map +1 -0
  117. package/dist/mcp/server-instructions.d.ts +5 -7
  118. package/dist/mcp/server-instructions.d.ts.map +1 -1
  119. package/dist/mcp/server-instructions.js +12 -14
  120. package/dist/mcp/server-instructions.js.map +1 -1
  121. package/dist/mcp/tools.d.ts +77 -0
  122. package/dist/mcp/tools.d.ts.map +1 -1
  123. package/dist/mcp/tools.js +696 -60
  124. package/dist/mcp/tools.js.map +1 -1
  125. package/dist/project-config.d.ts +20 -0
  126. package/dist/project-config.d.ts.map +1 -1
  127. package/dist/project-config.js +42 -2
  128. package/dist/project-config.js.map +1 -1
  129. package/dist/reasoning/login.js +1 -1
  130. package/dist/reasoning/login.js.map +1 -1
  131. package/dist/resolution/c-fnptr-synthesizer.d.ts +0 -28
  132. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  133. package/dist/resolution/c-fnptr-synthesizer.js +765 -79
  134. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  135. package/dist/resolution/callback-synthesizer.d.ts +1 -1
  136. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  137. package/dist/resolution/callback-synthesizer.js +72 -11
  138. package/dist/resolution/callback-synthesizer.js.map +1 -1
  139. package/dist/resolution/cooperative-yield.d.ts +32 -0
  140. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  141. package/dist/resolution/cooperative-yield.js +42 -0
  142. package/dist/resolution/cooperative-yield.js.map +1 -0
  143. package/dist/resolution/index.d.ts +11 -2
  144. package/dist/resolution/index.d.ts.map +1 -1
  145. package/dist/resolution/index.js +72 -4
  146. package/dist/resolution/index.js.map +1 -1
  147. package/dist/resolution/name-matcher.d.ts +22 -0
  148. package/dist/resolution/name-matcher.d.ts.map +1 -1
  149. package/dist/resolution/name-matcher.js +317 -20
  150. package/dist/resolution/name-matcher.js.map +1 -1
  151. package/dist/spec/config.d.ts +7 -11
  152. package/dist/spec/config.d.ts.map +1 -1
  153. package/dist/spec/config.js +77 -48
  154. package/dist/spec/config.js.map +1 -1
  155. package/dist/spec/db/fragment-node.d.ts +1 -0
  156. package/dist/spec/db/fragment-node.d.ts.map +1 -1
  157. package/dist/spec/db/fragment-node.js +8 -0
  158. package/dist/spec/db/fragment-node.js.map +1 -1
  159. package/dist/spec/db/fts.d.ts +14 -0
  160. package/dist/spec/db/fts.d.ts.map +1 -1
  161. package/dist/spec/db/fts.js +43 -4
  162. package/dist/spec/db/fts.js.map +1 -1
  163. package/dist/spec/db/schema.d.ts +6 -3
  164. package/dist/spec/db/schema.d.ts.map +1 -1
  165. package/dist/spec/db/schema.js +36 -4
  166. package/dist/spec/db/schema.js.map +1 -1
  167. package/dist/spec/db/schema.sql +11 -1
  168. package/dist/spec/evolve/logic-checker.d.ts +2 -2
  169. package/dist/spec/evolve/logic-checker.d.ts.map +1 -1
  170. package/dist/spec/evolve/logic-checker.js +3 -27
  171. package/dist/spec/evolve/logic-checker.js.map +1 -1
  172. package/dist/spec/evolve/pipeline.d.ts +21 -19
  173. package/dist/spec/evolve/pipeline.d.ts.map +1 -1
  174. package/dist/spec/evolve/pipeline.js +284 -31
  175. package/dist/spec/evolve/pipeline.js.map +1 -1
  176. package/dist/spec/evolve/spec-rewriter.d.ts +2 -2
  177. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
  178. package/dist/spec/evolve/spec-rewriter.js +7 -31
  179. package/dist/spec/evolve/spec-rewriter.js.map +1 -1
  180. package/dist/spec/graph/queries.d.ts +97 -0
  181. package/dist/spec/graph/queries.d.ts.map +1 -1
  182. package/dist/spec/graph/queries.js +225 -0
  183. package/dist/spec/graph/queries.js.map +1 -1
  184. package/dist/spec/llm/client.d.ts +29 -0
  185. package/dist/spec/llm/client.d.ts.map +1 -0
  186. package/dist/spec/llm/client.js +123 -0
  187. package/dist/spec/llm/client.js.map +1 -0
  188. package/dist/spec/llm/index.d.ts +3 -0
  189. package/dist/spec/llm/index.d.ts.map +1 -0
  190. package/dist/spec/llm/index.js +11 -0
  191. package/dist/spec/llm/index.js.map +1 -0
  192. package/dist/spec/llm/prompts.d.ts +13 -0
  193. package/dist/spec/llm/prompts.d.ts.map +1 -0
  194. package/dist/spec/llm/prompts.js +75 -0
  195. package/dist/spec/llm/prompts.js.map +1 -0
  196. package/dist/spec/mining/git-scanner.d.ts +12 -0
  197. package/dist/spec/mining/git-scanner.d.ts.map +1 -1
  198. package/dist/spec/mining/git-scanner.js +41 -0
  199. package/dist/spec/mining/git-scanner.js.map +1 -1
  200. package/dist/spec/mining/pipeline.d.ts.map +1 -1
  201. package/dist/spec/mining/pipeline.js +14 -1
  202. package/dist/spec/mining/pipeline.js.map +1 -1
  203. package/dist/spec/utils.d.ts +2 -1
  204. package/dist/spec/utils.d.ts.map +1 -1
  205. package/dist/spec/utils.js +3 -1
  206. package/dist/spec/utils.js.map +1 -1
  207. package/dist/sync/worktree.d.ts +9 -0
  208. package/dist/sync/worktree.d.ts.map +1 -1
  209. package/dist/sync/worktree.js +40 -0
  210. package/dist/sync/worktree.js.map +1 -1
  211. package/dist/types.d.ts +6 -1
  212. package/dist/types.d.ts.map +1 -1
  213. package/dist/ui/shimmer-progress.d.ts +2 -0
  214. package/dist/ui/shimmer-progress.d.ts.map +1 -1
  215. package/dist/ui/shimmer-progress.js +19 -2
  216. package/dist/ui/shimmer-progress.js.map +1 -1
  217. package/dist/upgrade/index.js +1 -1
  218. package/dist/upgrade/index.js.map +1 -1
  219. package/package.json +3 -3
  220. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  221. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  222. package/scripts/exp_boundary_eval/README.md +247 -0
  223. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  224. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  225. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
  226. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  227. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  228. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  229. package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -0
  230. package/scripts/exp_boundary_eval/_test_stdin.py +8 -0
  231. package/scripts/exp_boundary_eval/_utils.py +1116 -0
  232. package/scripts/exp_boundary_eval/analyze.py +1313 -0
  233. package/scripts/exp_boundary_eval/data/agents.json +109 -0
  234. package/scripts/exp_boundary_eval/data/experiments.json +140 -0
  235. package/scripts/exp_boundary_eval/deveco_arm.py +519 -0
  236. package/scripts/exp_boundary_eval/run_all.py +378 -0
  237. package/scripts/exp_boundary_eval/run_one.py +165 -0
  238. package/scripts/exp_boundary_eval/run_session.py +158 -0
  239. package/scripts/exp_boundary_eval/setup.py +120 -0
  240. package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -0
  241. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -0
  242. package/scripts/exp_boundary_eval/win_node_launcher.py +24 -0
  243. package/scripts/npm-shim.js +25 -3
  244. package/scripts/ohos-sdk-publish.mjs +133 -0
  245. package/scripts/qa_eval/README.md +1 -1
  246. package/scripts/qa_eval/agent_runner.py +1 -1
@@ -46,6 +46,7 @@ const tree_sitter_helpers_1 = require("./tree-sitter-helpers");
46
46
  const function_ref_1 = require("./function-ref");
47
47
  const generated_detection_1 = require("./generated-detection");
48
48
  const languages_1 = require("./languages");
49
+ const c_cpp_1 = require("./languages/c-cpp");
49
50
  const liquid_extractor_1 = require("./liquid-extractor");
50
51
  const razor_extractor_1 = require("./razor-extractor");
51
52
  const svelte_extractor_1 = require("./svelte-extractor");
@@ -81,20 +82,43 @@ const VUE_STORE_FILE_SIGNAL = /\bdefineStore\b|\bcreateStore\b|\bVuex\b|\bmutati
81
82
  * Extract the name from a node based on language
82
83
  */
83
84
  function extractName(node, source, extractor) {
85
+ const name = extractNameRaw(node, source, extractor);
86
+ // Universal fallback: recover a real identifier from a name still mangled by a
87
+ // macro the pre-parse didn't blank (C/C++ only — see recoverMangledName). A
88
+ // no-op on well-formed names, so a clean name is never altered.
89
+ return extractor.recoverMangledName ? extractor.recoverMangledName(name) : name;
90
+ }
91
+ function extractNameRaw(node, source, extractor) {
84
92
  const hookName = extractor.resolveName?.(node, source);
85
93
  if (hookName)
86
94
  return hookName;
87
95
  // Try field name first
88
96
  const nameNode = (0, tree_sitter_helpers_1.getChildByField)(node, extractor.nameField);
89
97
  if (nameNode) {
90
- // Unwrap pointer_declarator(s) for C/C++ pointer return types
98
+ // Unwrap pointer_declarator / reference_declarator for C/C++ pointer and
99
+ // reference return types (`int* f()`, `int& f()`, `int&& f()`). Without
100
+ // unwrapping the reference wrapper an inline reference-returning method is
101
+ // named "& f() const" instead of "f" — common in Unreal Engine gameplay
102
+ // headers (`const FGameplayTagContainer& GetActiveTags() const`). Out-of-line
103
+ // defs (`T& C::f()`) already resolve via the qualified-name hook. A
104
+ // pointer_declarator exposes its inner through a `declarator` field; a
105
+ // reference_declarator has none, so it's reached via namedChild(0).
91
106
  let resolved = nameNode;
92
- while (resolved.type === 'pointer_declarator') {
107
+ while (resolved.type === 'pointer_declarator' || resolved.type === 'reference_declarator') {
93
108
  const inner = (0, tree_sitter_helpers_1.getChildByField)(resolved, 'declarator') || resolved.namedChild(0);
94
109
  if (!inner)
95
110
  break;
96
111
  resolved = inner;
97
112
  }
113
+ // C++ user-defined conversion operator: the declarator is an `operator_cast`
114
+ // whose first child is the target type and second is the `() const` tail. Name
115
+ // it `operator <type>` (the conventional spelling) rather than the whole
116
+ // `operator EALSMovementState() const` declarator, so it matches symbolic
117
+ // overloads (`operator+`) and is findable by the type name.
118
+ if (resolved.type === 'operator_cast') {
119
+ const typeNode = resolved.namedChild(0);
120
+ return typeNode ? `operator ${(0, tree_sitter_helpers_1.getNodeText)(typeNode, source).trim()}` : (0, tree_sitter_helpers_1.getNodeText)(resolved, source);
121
+ }
98
122
  // Handle complex declarators (C/C++)
99
123
  if (resolved.type === 'function_declarator' || resolved.type === 'declarator') {
100
124
  const innerName = (0, tree_sitter_helpers_1.getChildByField)(resolved, 'declarator') || resolved.namedChild(0);
@@ -980,29 +1004,44 @@ class TreeSitterExtractor {
980
1004
  this.scanFnRefSubtree(node, 0);
981
1005
  skipChildren = true; // extractVariable handles children
982
1006
  }
983
- // Swift stored properties inside a type. Swift instance properties aren't
984
- // extracted as their own nodes, but a property's PROPERTY WRAPPER
985
- // (`@Argument`/`@Published`/`@State`/custom) and declared type ARE
986
- // dependencies attribute them to the enclosing type so the wrapper/type
987
- // files get dependents. Don't skipChildren: an initializer's calls still
988
- // matter. (Other languages extract properties via property/field types.)
1007
+ // Swift properties inside a type. A stored instance property becomes a `field`
1008
+ // node; a `static let`/`static var` member becomes `constant`/`variable`
1009
+ // (Swift's `static`-namespacing idiom value-reference edges can then target
1010
+ // it); a COMPUTED property (getter block, no stored value) becomes a `property`
1011
+ // node whose getter is walked below so its calls attribute to it. A property's
1012
+ // PROPERTY WRAPPER (`@Argument`/`@Published`/`@State`/custom) and declared type
1013
+ // are dependencies attributed to the enclosing type. (Other languages extract
1014
+ // properties via property/field types.)
989
1015
  else if (this.language === 'swift' &&
990
- nodeType === 'property_declaration' &&
1016
+ (nodeType === 'property_declaration' || nodeType === 'protocol_property_declaration') &&
991
1017
  this.isInsideClassLikeNode()) {
992
1018
  const ownerId = this.nodeStack[this.nodeStack.length - 1];
993
- // A `static let`/`static var` member is a SHARED constant of the type
994
- // (Swift's `static`-namespacing idiom, esp. in `enum`/`struct`) — extract
995
- // it as `constant`/`variable` so value-reference edges can target it. An
996
- // instance stored property stays a `field` (per-instance; Swift instance
997
- // properties otherwise aren't own nodes — that's unchanged). A *computed*
998
- // property (getter, no stored value) is never a constant — skip the node.
999
1019
  const { nameNode, isLet, isComputed } = swiftPropertyInfo(node, this.source);
1000
- if (nameNode && !isComputed) {
1001
- const isStatic = this.extractor.isStatic?.(node) ?? false;
1002
- this.createNode(isStatic ? (isLet ? 'constant' : 'variable') : 'field', (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source), node, {
1003
- visibility: this.extractor.getVisibility?.(node),
1004
- isStatic,
1005
- });
1020
+ let computedPropId;
1021
+ if (nameNode) {
1022
+ if (isComputed) {
1023
+ // Computed property — accessed like a property but its getter holds real
1024
+ // logic. Index as `property` so search/explore find it (#1020: computed
1025
+ // props such as a heavily-read `var isCloudProxy: Bool` returned "No
1026
+ // results found"); pushed below so the getter's calls attribute to it
1027
+ // rather than flattening onto the owning type (SwiftUI `var body: some
1028
+ // View { … }` — the whole subview tree — is the canonical case).
1029
+ const prop = this.createNode('property', (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source), node, {
1030
+ visibility: this.extractor.getVisibility?.(node),
1031
+ isStatic: this.extractor.isStatic?.(node) ?? false,
1032
+ });
1033
+ computedPropId = prop?.id;
1034
+ }
1035
+ else {
1036
+ // A `static let`/`static var` member is a SHARED constant of the type
1037
+ // (esp. in `enum`/`struct`); an instance stored property stays a `field`
1038
+ // (per-instance — Swift instance properties otherwise aren't own nodes).
1039
+ const isStatic = this.extractor.isStatic?.(node) ?? false;
1040
+ this.createNode(isStatic ? (isLet ? 'constant' : 'variable') : 'field', (0, tree_sitter_helpers_1.getNodeText)(nameNode, this.source), node, {
1041
+ visibility: this.extractor.getVisibility?.(node),
1042
+ isStatic,
1043
+ });
1044
+ }
1006
1045
  }
1007
1046
  if (ownerId) {
1008
1047
  this.extractDecoratorsFor(node, ownerId);
@@ -1028,6 +1067,20 @@ class TreeSitterExtractor {
1028
1067
  walkAttrArgs(modifiers);
1029
1068
  }
1030
1069
  }
1070
+ // A computed property's getter holds real logic — walk it with the property
1071
+ // node pushed so its calls/instantiations attribute to the property (a
1072
+ // SwiftUI `body`'s subview tree becomes the property's callees). skipChildren
1073
+ // then stops the generic walker from re-walking the getter (and the
1074
+ // modifiers/type annotation already handled above).
1075
+ if (computedPropId) {
1076
+ const getter = node.namedChildren.find((c) => c.type === 'computed_property' || c.type === 'protocol_property_requirements');
1077
+ if (getter) {
1078
+ this.nodeStack.push(computedPropId);
1079
+ this.visitFunctionBody(getter, '');
1080
+ this.nodeStack.pop();
1081
+ }
1082
+ skipChildren = true;
1083
+ }
1031
1084
  }
1032
1085
  // `export_statement` itself is not extracted — the walker descends
1033
1086
  // into children, where the inner declaration (lexical_declaration,
@@ -1455,6 +1508,15 @@ class TreeSitterExtractor {
1455
1508
  extractClass(node, kind = 'class') {
1456
1509
  if (!this.extractor)
1457
1510
  return;
1511
+ // Skip forward declarations / elaborated type references (`class Foo;`) in
1512
+ // languages that opt in — bodiless there means "not a definition", so it
1513
+ // would otherwise mint a phantom node competing with the real definition
1514
+ // (#1093). Languages where a bodiless class is complete (Kotlin, Scala)
1515
+ // leave the flag unset. Resolved once here and reused for the body walk.
1516
+ const resolvedBody = this.extractor.resolveBody?.(node, this.extractor.bodyField)
1517
+ ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
1518
+ if (this.extractor.skipBodilessClass && !resolvedBody)
1519
+ return;
1458
1520
  const name = extractName(node, this.source, this.extractor);
1459
1521
  const docstring = (0, tree_sitter_helpers_1.getPrecedingDocstring)(node, this.source);
1460
1522
  const visibility = this.extractor.getVisibility?.(node);
@@ -1474,10 +1536,7 @@ class TreeSitterExtractor {
1474
1536
  this.extractDecoratorsFor(node, classNode.id);
1475
1537
  // Push to stack and visit body
1476
1538
  this.nodeStack.push(classNode.id);
1477
- let body = this.extractor.resolveBody?.(node, this.extractor.bodyField)
1478
- ?? (0, tree_sitter_helpers_1.getChildByField)(node, this.extractor.bodyField);
1479
- if (!body)
1480
- body = node;
1539
+ const body = resolvedBody ?? node;
1481
1540
  // Visit all children for methods and properties
1482
1541
  for (let i = 0; i < body.namedChildCount; i++) {
1483
1542
  const child = body.namedChild(i);
@@ -3391,6 +3450,63 @@ class TreeSitterExtractor {
3391
3450
  const callerId = this.nodeStack[this.nodeStack.length - 1];
3392
3451
  if (!callerId)
3393
3452
  return;
3453
+ // Ruby `call` nodes use `receiver` + `method` fields (tree-sitter-ruby), not
3454
+ // the `object`/`name`/`function` fields the branches below expect — so
3455
+ // without this they fell through to the generic path, which took the
3456
+ // receiver as the callee and DROPPED the method name: `lg.log()` produced a
3457
+ // `calls` ref to `lg` (unresolvable) and no method edge was ever recorded,
3458
+ // so a Ruby method's callers/impact were invisible (#1108 follow-up). Build
3459
+ // `receiver.method` so the resolver — and local-variable type inference —
3460
+ // can link it; `Foo.new` stays an instantiation.
3461
+ if (this.language === 'ruby' && (node.type === 'call' || node.type === 'method_call')) {
3462
+ const methodNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'method');
3463
+ const methodName = methodNode ? (0, tree_sitter_helpers_1.getNodeText)(methodNode, this.source) : '';
3464
+ if (!methodName)
3465
+ return; // operator/element-reference call with no method name
3466
+ const receiverNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'receiver');
3467
+ const line = node.startPosition.row + 1;
3468
+ const column = node.startPosition.column;
3469
+ if (!receiverNode) {
3470
+ // Bare `foo(...)` — just the method name (unchanged behavior).
3471
+ this.unresolvedReferences.push({ fromNodeId: callerId, referenceName: methodName, referenceKind: 'calls', line, column });
3472
+ return;
3473
+ }
3474
+ const receiverName = (0, tree_sitter_helpers_1.getNodeText)(receiverNode, this.source);
3475
+ // `Foo.new` / `Foo::Bar.new` is construction — emit an `instantiates` ref to
3476
+ // the class (last `::` segment), preserving the "what creates X" edge.
3477
+ if (methodName === 'new') {
3478
+ const className = receiverName.includes('::')
3479
+ ? receiverName.slice(receiverName.lastIndexOf('::') + 2)
3480
+ : receiverName;
3481
+ if (/^[A-Z]/.test(className)) {
3482
+ this.unresolvedReferences.push({ fromNodeId: callerId, referenceName: className, referenceKind: 'instantiates', line, column });
3483
+ return;
3484
+ }
3485
+ }
3486
+ const SKIP_RECEIVERS = new Set(['self', 'super']);
3487
+ const skip = SKIP_RECEIVERS.has(receiverName);
3488
+ this.unresolvedReferences.push({
3489
+ fromNodeId: callerId,
3490
+ referenceName: skip ? methodName : `${receiverName}.${methodName}`,
3491
+ referenceKind: 'calls',
3492
+ line,
3493
+ column,
3494
+ });
3495
+ // A capitalized (constant) receiver — `Foo.bar`, a class/module method call
3496
+ // — is itself a dependency on that constant; emit a `references` ref so a
3497
+ // class used only via its class methods still records a dependent (the edge
3498
+ // the old receiver-only callee happened to provide, now made explicit).
3499
+ if (!skip && receiverNode.type === 'constant') {
3500
+ this.unresolvedReferences.push({
3501
+ fromNodeId: callerId,
3502
+ referenceName: receiverName,
3503
+ referenceKind: 'references',
3504
+ line: receiverNode.startPosition.row + 1,
3505
+ column: receiverNode.startPosition.column,
3506
+ });
3507
+ }
3508
+ return;
3509
+ }
3394
3510
  // Get the function/method being called
3395
3511
  let calleeName = '';
3396
3512
  // Java/Kotlin method_invocation has 'object' + 'name' fields instead of 'function'
@@ -3822,6 +3938,45 @@ class TreeSitterExtractor {
3822
3938
  });
3823
3939
  }
3824
3940
  }
3941
+ /**
3942
+ * Is this C++ `declaration` a stack/direct-initialization object construction
3943
+ * that invokes a constructor — `Calculator calc(0)` (direct-init) or
3944
+ * `Widget w{1, 2}` (brace-init) — as opposed to a plain variable or a
3945
+ * function declaration? Used to emit an `instantiates` edge for the
3946
+ * call-less construction syntax (#1035); heap `new T(...)` is handled
3947
+ * separately by INSTANTIATION_KINDS.
3948
+ *
3949
+ * Two signals, both required:
3950
+ * - the `type` field is a class-like NAMED type (`type_identifier`,
3951
+ * `template_type`, or `qualified_identifier`). Primitives (`int x(0)`),
3952
+ * `auto` (`placeholder_type_specifier` — that form always carries a real
3953
+ * `call_expression`, already handled), and sized specifiers are excluded —
3954
+ * they construct no class; and
3955
+ * - a declarator carries constructor arguments: an `init_declarator` whose
3956
+ * `value` is an `argument_list` (`(args)`) or `initializer_list` (`{args}`).
3957
+ * This skips default construction `Calculator c;` (no value) and the
3958
+ * most-vexing-parse `Calculator c();` (a bodyless `function_declarator`,
3959
+ * a function decl — not a construction).
3960
+ */
3961
+ isCppStackConstruction(node) {
3962
+ const typeNode = (0, tree_sitter_helpers_1.getChildByField)(node, 'type');
3963
+ if (!typeNode ||
3964
+ (typeNode.type !== 'type_identifier' &&
3965
+ typeNode.type !== 'template_type' &&
3966
+ typeNode.type !== 'qualified_identifier')) {
3967
+ return false;
3968
+ }
3969
+ for (let i = 0; i < node.namedChildCount; i++) {
3970
+ const child = node.namedChild(i);
3971
+ if (child?.type !== 'init_declarator')
3972
+ continue;
3973
+ const value = (0, tree_sitter_helpers_1.getChildByField)(child, 'value');
3974
+ if (value && (value.type === 'argument_list' || value.type === 'initializer_list')) {
3975
+ return true;
3976
+ }
3977
+ }
3978
+ return false;
3979
+ }
3825
3980
  /**
3826
3981
  * Static-member / value-read pass. A type/enum/class used only via a member
3827
3982
  * VALUE — `Enum.value`, `Type.CONST`, `Colors.red`, `Foo::BAR` — recorded no
@@ -4202,6 +4357,18 @@ class TreeSitterExtractor {
4202
4357
  }
4203
4358
  }
4204
4359
  }
4360
+ // C++ stack / direct-initialization construction — `Calculator calc(0)`
4361
+ // and `Widget w{1, 2}`. Unlike heap `new Calculator(0)` (a new_expression
4362
+ // handled above), these carry the constructor arguments directly on the
4363
+ // declarator with NO call/new node, so the body walker saw no constructor
4364
+ // invocation and recorded no `instantiates` edge (#1035). A declaration's
4365
+ // `type` field IS the constructed class name, so reuse extractInstantiation
4366
+ // (which strips template args / namespace and emits the `instantiates`
4367
+ // ref). Children still recurse below, so a nested ctor-arg call
4368
+ // (`Calculator calc(make())`) keeps its own `calls` ref.
4369
+ if (nodeType === 'declaration' && this.language === 'cpp' && this.isCppStackConstruction(node)) {
4370
+ this.extractInstantiation(node);
4371
+ }
4205
4372
  // Static-member / value-read: `Enum.value`, `Type.CONST`, `Foo::BAR`.
4206
4373
  this.extractStaticMemberRef(node);
4207
4374
  // Local variable type annotations inside a body — `const items: Foo[] = []`,
@@ -4396,7 +4563,11 @@ class TreeSitterExtractor {
4396
4563
  }
4397
4564
  // C++ base classes: `class Derived : public Base, private Other` →
4398
4565
  // base_class_clause holds access specifiers + base type(s). Emit an extends
4399
- // ref per base type (skip the public/private/protected keywords).
4566
+ // ref per base type (skip the public/private/protected keywords). A
4567
+ // templated base (`Base<int>`, `ns::Tpl<int>`) arrives as a `template_type`
4568
+ // or a `qualified_identifier` wrapping one; strip the `<…>` args so the ref
4569
+ // matches the bare class the template was defined as — `Base`, `ns::Tpl` —
4570
+ // instead of never resolving (#1043).
4400
4571
  if (child.type === 'base_class_clause') {
4401
4572
  for (const t of child.namedChildren) {
4402
4573
  if (t.type === 'type_identifier' ||
@@ -4404,7 +4575,7 @@ class TreeSitterExtractor {
4404
4575
  t.type === 'template_type') {
4405
4576
  this.unresolvedReferences.push({
4406
4577
  fromNodeId: classId,
4407
- referenceName: (0, tree_sitter_helpers_1.getNodeText)(t, this.source),
4578
+ referenceName: (0, c_cpp_1.stripCppTemplateArgs)((0, tree_sitter_helpers_1.getNodeText)(t, this.source)),
4408
4579
  referenceKind: 'extends',
4409
4580
  line: t.startPosition.row + 1,
4410
4581
  column: t.startPosition.column,