homegraph 1.1.2 → 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 (361) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +268 -243
  3. package/dist/arkts/ohos-api-index.d.ts +15 -0
  4. package/dist/arkts/ohos-api-index.d.ts.map +1 -0
  5. package/dist/arkts/ohos-api-index.js +190 -0
  6. package/dist/arkts/ohos-api-index.js.map +1 -0
  7. package/dist/arkts/ohos-sdk-input.d.ts +36 -0
  8. package/dist/arkts/ohos-sdk-input.d.ts.map +1 -0
  9. package/dist/arkts/ohos-sdk-input.js +214 -0
  10. package/dist/arkts/ohos-sdk-input.js.map +1 -0
  11. package/dist/bin/command-supervision.d.ts +12 -0
  12. package/dist/bin/command-supervision.d.ts.map +1 -0
  13. package/dist/bin/command-supervision.js +86 -0
  14. package/dist/bin/command-supervision.js.map +1 -0
  15. package/dist/bin/homegraph.d.ts +1 -1
  16. package/dist/bin/homegraph.js +971 -71
  17. package/dist/bin/homegraph.js.map +1 -1
  18. package/dist/db/index.d.ts +20 -0
  19. package/dist/db/index.d.ts.map +1 -1
  20. package/dist/db/index.js +39 -0
  21. package/dist/db/index.js.map +1 -1
  22. package/dist/db/migrations.d.ts +1 -1
  23. package/dist/db/migrations.d.ts.map +1 -1
  24. package/dist/db/migrations.js +58 -19
  25. package/dist/db/migrations.js.map +1 -1
  26. package/dist/db/queries.d.ts +14 -0
  27. package/dist/db/queries.d.ts.map +1 -1
  28. package/dist/db/queries.js +314 -143
  29. package/dist/db/queries.js.map +1 -1
  30. package/dist/db/schema.sql +172 -152
  31. package/dist/directory.d.ts +32 -0
  32. package/dist/directory.d.ts.map +1 -1
  33. package/dist/directory.js +88 -5
  34. package/dist/directory.js.map +1 -1
  35. package/dist/extraction/arkts-batch-worker.d.ts +2 -0
  36. package/dist/extraction/arkts-batch-worker.d.ts.map +1 -0
  37. package/dist/extraction/arkts-batch-worker.js +28 -0
  38. package/dist/extraction/arkts-batch-worker.js.map +1 -0
  39. package/dist/extraction/context.d.ts +11 -0
  40. package/dist/extraction/context.d.ts.map +1 -1
  41. package/dist/extraction/context.js +20 -0
  42. package/dist/extraction/context.js.map +1 -1
  43. package/dist/extraction/index.d.ts +16 -2
  44. package/dist/extraction/index.d.ts.map +1 -1
  45. package/dist/extraction/index.js +619 -380
  46. package/dist/extraction/index.js.map +1 -1
  47. package/dist/extraction/languages/arkts-state-decorators.d.ts +13 -0
  48. package/dist/extraction/languages/arkts-state-decorators.d.ts.map +1 -0
  49. package/dist/extraction/languages/arkts-state-decorators.js +26 -0
  50. package/dist/extraction/languages/arkts-state-decorators.js.map +1 -0
  51. package/dist/extraction/languages/arkts-viewtree.d.ts +4 -2
  52. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
  53. package/dist/extraction/languages/arkts-viewtree.js +21 -6
  54. package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
  55. package/dist/extraction/languages/arkts.d.ts +98 -2
  56. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  57. package/dist/extraction/languages/arkts.js +1290 -61
  58. package/dist/extraction/languages/arkts.js.map +1 -1
  59. package/dist/extraction/languages/c-cpp.d.ts +56 -0
  60. package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  61. package/dist/extraction/languages/c-cpp.js +198 -1
  62. package/dist/extraction/languages/c-cpp.js.map +1 -1
  63. package/dist/extraction/languages/ohos-api-consumer.d.ts +34 -0
  64. package/dist/extraction/languages/ohos-api-consumer.d.ts.map +1 -0
  65. package/dist/extraction/languages/ohos-api-consumer.js +283 -0
  66. package/dist/extraction/languages/ohos-api-consumer.js.map +1 -0
  67. package/dist/extraction/parse-pool.d.ts +126 -0
  68. package/dist/extraction/parse-pool.d.ts.map +1 -0
  69. package/dist/extraction/parse-pool.js +319 -0
  70. package/dist/extraction/parse-pool.js.map +1 -0
  71. package/dist/extraction/tree-sitter-types.d.ts +17 -0
  72. package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  73. package/dist/extraction/tree-sitter.d.ts +21 -0
  74. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  75. package/dist/extraction/tree-sitter.js +198 -27
  76. package/dist/extraction/tree-sitter.js.map +1 -1
  77. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  78. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  79. package/dist/graph/traversal.d.ts.map +1 -1
  80. package/dist/graph/traversal.js +76 -17
  81. package/dist/graph/traversal.js.map +1 -1
  82. package/dist/index.d.ts +25 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +78 -4
  85. package/dist/index.js.map +1 -1
  86. package/dist/installer/instructions-template.js +9 -9
  87. package/dist/installer/targets/shared.d.ts +5 -6
  88. package/dist/installer/targets/shared.d.ts.map +1 -1
  89. package/dist/installer/targets/shared.js +5 -6
  90. package/dist/installer/targets/shared.js.map +1 -1
  91. package/dist/mcp/daemon-paths.d.ts +30 -3
  92. package/dist/mcp/daemon-paths.d.ts.map +1 -1
  93. package/dist/mcp/daemon-paths.js +50 -10
  94. package/dist/mcp/daemon-paths.js.map +1 -1
  95. package/dist/mcp/daemon-registry.d.ts.map +1 -1
  96. package/dist/mcp/daemon-registry.js +7 -3
  97. package/dist/mcp/daemon-registry.js.map +1 -1
  98. package/dist/mcp/daemon.d.ts +48 -0
  99. package/dist/mcp/daemon.d.ts.map +1 -1
  100. package/dist/mcp/daemon.js +196 -32
  101. package/dist/mcp/daemon.js.map +1 -1
  102. package/dist/mcp/engine.d.ts +17 -0
  103. package/dist/mcp/engine.d.ts.map +1 -1
  104. package/dist/mcp/engine.js +73 -1
  105. package/dist/mcp/engine.js.map +1 -1
  106. package/dist/mcp/index.d.ts.map +1 -1
  107. package/dist/mcp/index.js +25 -43
  108. package/dist/mcp/index.js.map +1 -1
  109. package/dist/mcp/liveness-watchdog.js +16 -16
  110. package/dist/mcp/ppid-watchdog.d.ts +18 -0
  111. package/dist/mcp/ppid-watchdog.d.ts.map +1 -1
  112. package/dist/mcp/ppid-watchdog.js +37 -0
  113. package/dist/mcp/ppid-watchdog.js.map +1 -1
  114. package/dist/mcp/query-cache.d.ts +25 -0
  115. package/dist/mcp/query-cache.d.ts.map +1 -0
  116. package/dist/mcp/query-cache.js +191 -0
  117. package/dist/mcp/query-cache.js.map +1 -0
  118. package/dist/mcp/query-pool.d.ts +94 -0
  119. package/dist/mcp/query-pool.d.ts.map +1 -0
  120. package/dist/mcp/query-pool.js +297 -0
  121. package/dist/mcp/query-pool.js.map +1 -0
  122. package/dist/mcp/query-worker.d.ts +24 -0
  123. package/dist/mcp/query-worker.d.ts.map +1 -0
  124. package/dist/mcp/query-worker.js +87 -0
  125. package/dist/mcp/query-worker.js.map +1 -0
  126. package/dist/mcp/server-instructions.d.ts +5 -7
  127. package/dist/mcp/server-instructions.d.ts.map +1 -1
  128. package/dist/mcp/server-instructions.js +72 -74
  129. package/dist/mcp/server-instructions.js.map +1 -1
  130. package/dist/mcp/tools.d.ts +94 -4
  131. package/dist/mcp/tools.d.ts.map +1 -1
  132. package/dist/mcp/tools.js +877 -71
  133. package/dist/mcp/tools.js.map +1 -1
  134. package/dist/project-config.d.ts +20 -0
  135. package/dist/project-config.d.ts.map +1 -1
  136. package/dist/project-config.js +42 -2
  137. package/dist/project-config.js.map +1 -1
  138. package/dist/reasoning/login.js +1 -1
  139. package/dist/reasoning/login.js.map +1 -1
  140. package/dist/reasoning/reasoner.js +32 -32
  141. package/dist/resolution/c-fnptr-synthesizer.d.ts +0 -28
  142. package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
  143. package/dist/resolution/c-fnptr-synthesizer.js +765 -79
  144. package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
  145. package/dist/resolution/callback-synthesizer.d.ts +1 -1
  146. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  147. package/dist/resolution/callback-synthesizer.js +72 -11
  148. package/dist/resolution/callback-synthesizer.js.map +1 -1
  149. package/dist/resolution/cooperative-yield.d.ts +32 -0
  150. package/dist/resolution/cooperative-yield.d.ts.map +1 -0
  151. package/dist/resolution/cooperative-yield.js +42 -0
  152. package/dist/resolution/cooperative-yield.js.map +1 -0
  153. package/dist/resolution/index.d.ts +11 -2
  154. package/dist/resolution/index.d.ts.map +1 -1
  155. package/dist/resolution/index.js +72 -4
  156. package/dist/resolution/index.js.map +1 -1
  157. package/dist/resolution/name-matcher.d.ts +22 -0
  158. package/dist/resolution/name-matcher.d.ts.map +1 -1
  159. package/dist/resolution/name-matcher.js +317 -20
  160. package/dist/resolution/name-matcher.js.map +1 -1
  161. package/dist/spec/config.d.ts +39 -0
  162. package/dist/spec/config.d.ts.map +1 -0
  163. package/dist/spec/config.js +304 -0
  164. package/dist/spec/config.js.map +1 -0
  165. package/dist/spec/db/commit-node.d.ts +23 -0
  166. package/dist/spec/db/commit-node.d.ts.map +1 -0
  167. package/dist/spec/db/commit-node.js +62 -0
  168. package/dist/spec/db/commit-node.js.map +1 -0
  169. package/dist/spec/db/fragment-node.d.ts +24 -0
  170. package/dist/spec/db/fragment-node.d.ts.map +1 -0
  171. package/dist/spec/db/fragment-node.js +128 -0
  172. package/dist/spec/db/fragment-node.js.map +1 -0
  173. package/dist/spec/db/fts.d.ts +74 -0
  174. package/dist/spec/db/fts.d.ts.map +1 -0
  175. package/dist/spec/db/fts.js +324 -0
  176. package/dist/spec/db/fts.js.map +1 -0
  177. package/dist/spec/db/index.d.ts +13 -0
  178. package/dist/spec/db/index.d.ts.map +1 -0
  179. package/dist/spec/db/index.js +50 -0
  180. package/dist/spec/db/index.js.map +1 -0
  181. package/dist/spec/db/relations.d.ts +55 -0
  182. package/dist/spec/db/relations.d.ts.map +1 -0
  183. package/dist/spec/db/relations.js +158 -0
  184. package/dist/spec/db/relations.js.map +1 -0
  185. package/dist/spec/db/schema.d.ts +33 -0
  186. package/dist/spec/db/schema.d.ts.map +1 -0
  187. package/dist/spec/db/schema.js +119 -0
  188. package/dist/spec/db/schema.js.map +1 -0
  189. package/dist/spec/db/schema.sql +117 -0
  190. package/dist/spec/db/spec-node.d.ts +41 -0
  191. package/dist/spec/db/spec-node.d.ts.map +1 -0
  192. package/dist/spec/db/spec-node.js +114 -0
  193. package/dist/spec/db/spec-node.js.map +1 -0
  194. package/dist/spec/evolve/impact-locator.d.ts +13 -0
  195. package/dist/spec/evolve/impact-locator.d.ts.map +1 -0
  196. package/dist/spec/evolve/impact-locator.js +25 -0
  197. package/dist/spec/evolve/impact-locator.js.map +1 -0
  198. package/dist/spec/evolve/llm-client.d.ts +50 -0
  199. package/dist/spec/evolve/llm-client.d.ts.map +1 -0
  200. package/dist/spec/evolve/llm-client.js +176 -0
  201. package/dist/spec/evolve/llm-client.js.map +1 -0
  202. package/dist/spec/evolve/logic-checker.d.ts +12 -0
  203. package/dist/spec/evolve/logic-checker.d.ts.map +1 -0
  204. package/dist/spec/evolve/logic-checker.js +24 -0
  205. package/dist/spec/evolve/logic-checker.js.map +1 -0
  206. package/dist/spec/evolve/pipeline.d.ts +42 -0
  207. package/dist/spec/evolve/pipeline.d.ts.map +1 -0
  208. package/dist/spec/evolve/pipeline.js +567 -0
  209. package/dist/spec/evolve/pipeline.js.map +1 -0
  210. package/dist/spec/evolve/spec-rewriter.d.ts +42 -0
  211. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -0
  212. package/dist/spec/evolve/spec-rewriter.js +230 -0
  213. package/dist/spec/evolve/spec-rewriter.js.map +1 -0
  214. package/dist/spec/graph/queries.d.ts +155 -0
  215. package/dist/spec/graph/queries.d.ts.map +1 -0
  216. package/dist/spec/graph/queries.js +440 -0
  217. package/dist/spec/graph/queries.js.map +1 -0
  218. package/dist/spec/llm/client.d.ts +29 -0
  219. package/dist/spec/llm/client.d.ts.map +1 -0
  220. package/dist/spec/llm/client.js +123 -0
  221. package/dist/spec/llm/client.js.map +1 -0
  222. package/dist/spec/llm/index.d.ts +3 -0
  223. package/dist/spec/llm/index.d.ts.map +1 -0
  224. package/dist/spec/llm/index.js +11 -0
  225. package/dist/spec/llm/index.js.map +1 -0
  226. package/dist/spec/llm/prompts.d.ts +13 -0
  227. package/dist/spec/llm/prompts.d.ts.map +1 -0
  228. package/dist/spec/llm/prompts.js +75 -0
  229. package/dist/spec/llm/prompts.js.map +1 -0
  230. package/dist/spec/mining/diff-parser.d.ts +33 -0
  231. package/dist/spec/mining/diff-parser.d.ts.map +1 -0
  232. package/dist/spec/mining/diff-parser.js +166 -0
  233. package/dist/spec/mining/diff-parser.js.map +1 -0
  234. package/dist/spec/mining/git-scanner.d.ts +103 -0
  235. package/dist/spec/mining/git-scanner.d.ts.map +1 -0
  236. package/dist/spec/mining/git-scanner.js +307 -0
  237. package/dist/spec/mining/git-scanner.js.map +1 -0
  238. package/dist/spec/mining/pipeline.d.ts +53 -0
  239. package/dist/spec/mining/pipeline.d.ts.map +1 -0
  240. package/dist/spec/mining/pipeline.js +178 -0
  241. package/dist/spec/mining/pipeline.js.map +1 -0
  242. package/dist/spec/mining/scope-resolver.d.ts +45 -0
  243. package/dist/spec/mining/scope-resolver.d.ts.map +1 -0
  244. package/dist/spec/mining/scope-resolver.js +103 -0
  245. package/dist/spec/mining/scope-resolver.js.map +1 -0
  246. package/dist/spec/mining/spec-extractor.d.ts +69 -0
  247. package/dist/spec/mining/spec-extractor.d.ts.map +1 -0
  248. package/dist/spec/mining/spec-extractor.js +369 -0
  249. package/dist/spec/mining/spec-extractor.js.map +1 -0
  250. package/dist/spec/types.d.ts +149 -0
  251. package/dist/spec/types.d.ts.map +1 -0
  252. package/dist/spec/types.js +15 -0
  253. package/dist/spec/types.js.map +1 -0
  254. package/dist/spec/utils.d.ts +167 -0
  255. package/dist/spec/utils.d.ts.map +1 -0
  256. package/dist/spec/utils.js +463 -0
  257. package/dist/spec/utils.js.map +1 -0
  258. package/dist/sync/worktree.d.ts +9 -0
  259. package/dist/sync/worktree.d.ts.map +1 -1
  260. package/dist/sync/worktree.js +40 -0
  261. package/dist/sync/worktree.js.map +1 -1
  262. package/dist/types.d.ts +6 -1
  263. package/dist/types.d.ts.map +1 -1
  264. package/dist/ui/shimmer-progress.d.ts +2 -0
  265. package/dist/ui/shimmer-progress.d.ts.map +1 -1
  266. package/dist/ui/shimmer-progress.js +19 -2
  267. package/dist/ui/shimmer-progress.js.map +1 -1
  268. package/dist/upgrade/index.js +1 -1
  269. package/dist/upgrade/index.js.map +1 -1
  270. package/package.json +58 -57
  271. package/scripts/add-lang/bench.sh +60 -60
  272. package/scripts/add-lang/check-grammar.mjs +75 -75
  273. package/scripts/add-lang/dump-ast.mjs +103 -103
  274. package/scripts/add-lang/verify-extraction.mjs +70 -70
  275. package/scripts/agent-eval/ab-adoption.sh +91 -91
  276. package/scripts/agent-eval/ab-hook.sh +86 -86
  277. package/scripts/agent-eval/ab-impl.sh +78 -78
  278. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  279. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  280. package/scripts/agent-eval/arms-F.sh +21 -21
  281. package/scripts/agent-eval/arms-matrix.sh +37 -37
  282. package/scripts/agent-eval/audit.sh +68 -68
  283. package/scripts/agent-eval/bench-readme.sh +28 -28
  284. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  285. package/scripts/agent-eval/block-read-hook.sh +19 -19
  286. package/scripts/agent-eval/hook-settings.json +15 -15
  287. package/scripts/agent-eval/itrun.sh +120 -120
  288. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  289. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  290. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  291. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  292. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  293. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  294. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  295. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  296. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  297. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  298. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  299. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  300. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  301. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  302. package/scripts/agent-eval/offload-eval.md +76 -76
  303. package/scripts/agent-eval/parse-arms.mjs +116 -116
  304. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  305. package/scripts/agent-eval/parse-run.mjs +45 -45
  306. package/scripts/agent-eval/parse-session.mjs +93 -93
  307. package/scripts/agent-eval/probe-context.mjs +21 -21
  308. package/scripts/agent-eval/probe-explore.mjs +40 -40
  309. package/scripts/agent-eval/probe-node.mjs +20 -20
  310. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  311. package/scripts/agent-eval/probe-trace.mjs +20 -20
  312. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  313. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
  314. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
  315. package/scripts/agent-eval/run-agent.sh +34 -34
  316. package/scripts/agent-eval/run-all.sh +69 -69
  317. package/scripts/agent-eval/run-arms.sh +56 -56
  318. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  319. package/scripts/build-bundle.sh +118 -118
  320. package/scripts/exp_boundary_eval/README.md +247 -0
  321. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  322. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  323. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
  324. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  325. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  326. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  327. package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -0
  328. package/scripts/exp_boundary_eval/_test_stdin.py +8 -0
  329. package/scripts/exp_boundary_eval/_utils.py +1116 -0
  330. package/scripts/exp_boundary_eval/analyze.py +1313 -0
  331. package/scripts/exp_boundary_eval/data/agents.json +109 -0
  332. package/scripts/exp_boundary_eval/data/experiments.json +140 -0
  333. package/scripts/exp_boundary_eval/deveco_arm.py +519 -0
  334. package/scripts/exp_boundary_eval/run_all.py +378 -0
  335. package/scripts/exp_boundary_eval/run_one.py +165 -0
  336. package/scripts/exp_boundary_eval/run_session.py +158 -0
  337. package/scripts/exp_boundary_eval/setup.py +120 -0
  338. package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -0
  339. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -0
  340. package/scripts/exp_boundary_eval/win_node_launcher.py +24 -0
  341. package/scripts/extract-release-notes.mjs +130 -130
  342. package/scripts/local-install.sh +41 -41
  343. package/scripts/npm-sdk.js +75 -75
  344. package/scripts/npm-shim.js +268 -246
  345. package/scripts/ohos-sdk-publish.mjs +133 -0
  346. package/scripts/pack-npm.sh +119 -119
  347. package/scripts/prepare-release.mjs +270 -270
  348. package/scripts/qa_eval/README.md +407 -404
  349. package/scripts/qa_eval/_test_deveco_probe.py +41 -41
  350. package/scripts/qa_eval/agent_runner.py +526 -526
  351. package/scripts/qa_eval/data/.gitignore +4 -4
  352. package/scripts/qa_eval/data/test-set.jsonl +2 -22
  353. package/scripts/qa_eval/eval_metrics.py +274 -233
  354. package/scripts/qa_eval/external_agent.py +976 -671
  355. package/scripts/qa_eval/llm_config.py +92 -92
  356. package/scripts/qa_eval/memory_monitor.py +132 -132
  357. package/scripts/qa_eval/my_answer_accuracy.py +187 -187
  358. package/scripts/qa_eval/requirements.txt +2 -2
  359. package/scripts/qa_eval/run_pipeline.py +804 -711
  360. package/scripts/qa_eval/stats_efficiency.py +279 -279
  361. package/scripts/qa_eval/stats_scores.py +207 -207
@@ -42,18 +42,248 @@ var __importStar = (this && this.__importStar) || (function () {
42
42
  };
43
43
  })();
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.ArkTSExtractor = void 0;
45
+ exports.OHOS_API_DB_PATH_META = exports.OHOS_API_VERSION_META = exports.OHOS_API_FILE_PREFIX = exports.OhosSdkInputError = exports.ArkTSExtractor = void 0;
46
+ exports.cleanArkTypeString = cleanArkTypeString;
47
+ exports.normalizeArktsReturnType = normalizeArktsReturnType;
48
+ exports.buildArkMethodSignatureFields = buildArkMethodSignatureFields;
49
+ exports.isArkAnalyzerSourcePath = isArkAnalyzerSourcePath;
50
+ exports.runIsolatedArkTSBatchEntry = runIsolatedArkTSBatchEntry;
51
+ exports.primeArkTSBatch = primeArkTSBatch;
52
+ exports.isArkTSBatchPersisted = isArkTSBatchPersisted;
46
53
  exports.resetArkTSBatch = resetArkTSBatch;
54
+ exports.stateDecoratorKinds = stateDecoratorKinds;
55
+ exports.stateTransferViaForField = stateTransferViaForField;
56
+ exports.drainArkTSIndexNotices = drainArkTSIndexNotices;
57
+ exports.parseOhosToolsVersionFromName = parseOhosToolsVersionFromName;
58
+ exports.isArchivePath = isArchivePath;
59
+ exports.findOhosSdkHome = findOhosSdkHome;
60
+ exports.hasOpenHarmonyEts = hasOpenHarmonyEts;
61
+ exports.listOhosApiEtsRoots = listOhosApiEtsRoots;
62
+ exports.resolveOhosSdkInput = resolveOhosSdkInput;
63
+ exports.ohosApiDbFilename = ohosApiDbFilename;
64
+ exports.ohosApiDbPackageName = ohosApiDbPackageName;
65
+ exports.ohosApiDbInstallPath = ohosApiDbInstallPath;
66
+ exports.indexOhosApiDb = indexOhosApiDb;
67
+ exports.markOhosApiFilePath = markOhosApiFilePath;
68
+ exports.isOhosApiFilePath = isOhosApiFilePath;
69
+ exports.parseJson5Minimal = parseJson5Minimal;
70
+ exports.normalizeOhosApiVersion = normalizeOhosApiVersion;
71
+ exports.detectOhosCompileSdkVersion = detectOhosCompileSdkVersion;
72
+ exports.isOhosArktsProject = isOhosArktsProject;
73
+ exports.ensureOhosApiDb = ensureOhosApiDb;
74
+ exports.bindOhosApiDbForProject = bindOhosApiDbForProject;
75
+ exports.restoreOhosApiDbAttach = restoreOhosApiDbAttach;
47
76
  const crypto = __importStar(require("crypto"));
48
77
  const fs = __importStar(require("fs"));
78
+ const fsp = __importStar(require("fs/promises"));
79
+ const os = __importStar(require("os"));
49
80
  const path = __importStar(require("path"));
81
+ const child_process_1 = require("child_process");
50
82
  const arkanalyzer_1 = require("arkanalyzer");
51
- const tree_sitter_helpers_1 = require("../tree-sitter-helpers");
83
+ const db_1 = require("../../db");
84
+ const queries_1 = require("../../db/queries");
52
85
  const context_1 = require("../context");
53
- const arkts_viewtree_1 = require("./arkts-viewtree");
86
+ const extraction_version_1 = require("../extraction-version");
87
+ const version_1 = require("../../mcp/version");
88
+ const tree_sitter_helpers_1 = require("../tree-sitter-helpers");
89
+ const wasm_runtime_flags_1 = require("../wasm-runtime-flags");
90
+ /** Primitive / void return types — not stored in nodes.return_type (inference-only column). */
91
+ const ARKTS_NON_CLASS_RETURN = new Set([
92
+ 'void',
93
+ 'number',
94
+ 'string',
95
+ 'boolean',
96
+ 'bigint',
97
+ 'undefined',
98
+ 'null',
99
+ 'never',
100
+ 'any',
101
+ 'unknown',
102
+ 'Object',
103
+ ]);
104
+ /** Strip arkanalyzer file-location prefixes from type text (`@proj/file.ets: Foo` → `Foo`). */
105
+ function cleanArkTypeString(raw) {
106
+ return raw.replace(/@[^/\s]+\/[^\s:]*:\s*/g, '').trim();
107
+ }
108
+ /**
109
+ * Normalize an ArkTS method return type to a bare class name for receiver inference
110
+ * (aligned with C++/Java `return_type` usage elsewhere in HomeGraph).
111
+ */
112
+ function normalizeArktsReturnType(raw) {
113
+ if (!raw)
114
+ return undefined;
115
+ let t = cleanArkTypeString(raw);
116
+ if (!t || ARKTS_NON_CLASS_RETURN.has(t))
117
+ return undefined;
118
+ // Unwrap common wrappers to the pointee (`Promise<Foo>` → `Foo`).
119
+ const wrapper = t.match(/\b(?:Promise|Array|ReadonlyArray|Set|Map)\s*<\s*([^,>]+?)\s*>/);
120
+ if (wrapper?.[1])
121
+ t = wrapper[1].trim();
122
+ t = t.replace(/<[^>]*>/g, ' ').replace(/\[\]/g, ' ').replace(/\s+/g, ' ').trim();
123
+ if (!t || ARKTS_NON_CLASS_RETURN.has(t))
124
+ return undefined;
125
+ const last = t.split('.').filter(Boolean).pop() ?? t;
126
+ return last || undefined;
127
+ }
128
+ function formatArkMethodSignatureLine(method, sig, useParamNames) {
129
+ const sub = sig.getMethodSubSignature();
130
+ const name = sub.getMethodName();
131
+ const ret = cleanArkTypeString(sub.getReturnType()?.toString() ?? 'void');
132
+ const paramTypes = sub.getParameterTypes();
133
+ let params;
134
+ if (useParamNames) {
135
+ const named = method.getParameters();
136
+ if (named.length > 0 && named.length === paramTypes.length) {
137
+ params = named
138
+ .map((p, i) => {
139
+ const rest = p.isRest?.() ? '...' : '';
140
+ const optional = p.isOptional?.() ? '?' : '';
141
+ const typeStr = cleanArkTypeString(p.getType()?.toString() ?? paramTypes[i]?.toString() ?? 'unknown');
142
+ return `${rest}${p.getName()}${optional}: ${typeStr}`;
143
+ })
144
+ .join(', ');
145
+ }
146
+ else {
147
+ params = paramTypes
148
+ .map((t) => cleanArkTypeString(t?.toString() ?? 'unknown'))
149
+ .join(', ');
150
+ }
151
+ }
152
+ else {
153
+ params = paramTypes
154
+ .map((t) => cleanArkTypeString(t?.toString() ?? 'unknown'))
155
+ .join(', ');
156
+ }
157
+ const prefix = sub.isStatic() ? 'static ' : '';
158
+ return `${prefix}${name}(${params}): ${ret}`;
159
+ }
160
+ /** Collect human-readable signature lines (canonical first, overloads on following lines). */
161
+ function buildArkMethodSignatureFields(method) {
162
+ const impl = method.getImplementationSignature();
163
+ const declares = method.getDeclareSignatures();
164
+ const primary = impl ?? method.getSignature();
165
+ if (!primary && (!declares || declares.length === 0))
166
+ return {};
167
+ const lines = [];
168
+ const seen = new Set();
169
+ const push = (line) => {
170
+ const trimmed = line.trim();
171
+ if (!trimmed || seen.has(trimmed))
172
+ return;
173
+ seen.add(trimmed);
174
+ lines.push(trimmed);
175
+ };
176
+ if (impl) {
177
+ push(formatArkMethodSignatureLine(method, impl, true));
178
+ }
179
+ if (declares?.length) {
180
+ for (const d of declares) {
181
+ push(formatArkMethodSignatureLine(method, d, false));
182
+ }
183
+ }
184
+ else if (!impl && primary) {
185
+ push(formatArkMethodSignatureLine(method, primary, true));
186
+ }
187
+ if (lines.length === 0)
188
+ return {};
189
+ const canonicalSig = impl ?? declares?.[0] ?? primary;
190
+ const retRaw = canonicalSig.getMethodSubSignature().getReturnType()?.toString();
191
+ return {
192
+ signature: lines.join('\n'),
193
+ returnType: normalizeArktsReturnType(retRaw),
194
+ };
195
+ }
196
+ /** Parallel read chunk size during ArkTS batch persist (writes stay sequential for SQLite). */
197
+ function resolveArkTSPersistParallel(etsFileCount) {
198
+ const raw = process.env.HOMEGRAPH_ARKTS_PERSIST_PARALLEL?.trim();
199
+ if (raw !== undefined && raw !== '') {
200
+ const n = parseInt(raw, 10);
201
+ if (!Number.isNaN(n) && n >= 1)
202
+ return n;
203
+ }
204
+ // Large repos: serial reads — slower but stable on Windows / huge trees.
205
+ if (etsFileCount >= 500)
206
+ return 1;
207
+ return 8;
208
+ }
209
+ /** Stack sizes (KB) for isolated ArkTS worker retries (Windows native stack overflow). */
210
+ function resolveArkTSWorkerStackSizesKb() {
211
+ const raw = process.env.HOMEGRAPH_ARKTS_STACK_SIZES_KB?.trim();
212
+ if (raw) {
213
+ const parsed = raw.split(',').map((s) => parseInt(s.trim(), 10)).filter((n) => n > 0);
214
+ if (parsed.length > 0)
215
+ return parsed;
216
+ }
217
+ return [32768, 65536, 131072, 262144];
218
+ }
219
+ /** Windows STATUS_STACK_OVERFLOW — process killed during deep native/JS recursion. */
220
+ function isStackOverflowExitCode(code) {
221
+ if (code === null)
222
+ return false;
223
+ return code === 3221225725 || code === -1073741571;
224
+ }
225
+ function shouldUseIsolatedArkTSBuild(etsCount) {
226
+ const mode = process.env.HOMEGRAPH_ARKTS_ISOLATED?.trim();
227
+ if (mode === '1' || mode === 'true')
228
+ return true;
229
+ if (mode === '0' || mode === 'false')
230
+ return false;
231
+ // Photos-scale repos on Windows: build Scene in a child with a larger stack.
232
+ if (process.platform === 'win32' && etsCount >= 500)
233
+ return true;
234
+ return false;
235
+ }
236
+ function homegraphDbPath(rootDir) {
237
+ return path.join(rootDir, '.homegraph', 'homegraph.db');
238
+ }
54
239
  const ARK_PROVENANCE = 'heuristic';
55
240
  /** Virtual file path for ArkAnalyzer's in-scene dummy entry (not on disk). */
56
241
  const ARKANALYZER_DUMMY_FILE = '@dummyFile.ets';
242
+ /** HarmonyOS sources indexed via ArkAnalyzer Scene batch (`.ets`, `.ts`, `.d.ts`). */
243
+ function isArkAnalyzerSourcePath(filePath) {
244
+ const base = path.basename(filePath);
245
+ // `.d.ts` ends with `.ts` (Node extname) — one `.ts` suffix covers both.
246
+ return base.endsWith('.ets') || base.endsWith('.ts');
247
+ }
248
+ function isEtsFileName(name) {
249
+ return name.endsWith('.ets');
250
+ }
251
+ function isCoLocatedArkTsFileName(name) {
252
+ return isArkAnalyzerSourcePath(name) && !isEtsFileName(name);
253
+ }
254
+ /** True when the tree looks like a HarmonyOS / ArkTS project (not a generic TS repo). */
255
+ function hasHarmonyProjectMarkers(rootDir) {
256
+ const found = [];
257
+ function walk(dir) {
258
+ if (found.length > 0)
259
+ return;
260
+ let entries;
261
+ try {
262
+ entries = fs.readdirSync(dir, { withFileTypes: true });
263
+ }
264
+ catch {
265
+ return;
266
+ }
267
+ for (const entry of entries) {
268
+ const full = path.join(dir, entry.name);
269
+ if (entry.isDirectory()) {
270
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.homegraph') {
271
+ continue;
272
+ }
273
+ walk(full);
274
+ }
275
+ else if (entry.isFile() && (isEtsFileName(entry.name) || entry.name === 'module.json5')) {
276
+ found.push(full);
277
+ return;
278
+ }
279
+ }
280
+ }
281
+ walk(rootDir);
282
+ return found.length > 0;
283
+ }
284
+ function normIndexPath(filePath) {
285
+ return filePath.replace(/\\/g, '/');
286
+ }
57
287
  /** Member calls through a native `.so` binding: `sdk.Asset_setCropRect(`. */
58
288
  const NAPI_MEMBER_CALL_RE = /\.\s*([A-Z][A-Za-z0-9_]*(?:_[A-Za-z0-9_]+)+)\s*\(/g;
59
289
  function isNapiSymbolName(name) {
@@ -62,6 +292,8 @@ function isNapiSymbolName(name) {
62
292
  let persistedBatch = null;
63
293
  /** File that triggered the most recent batch persist (for indexAll edge stats). */
64
294
  let batchTriggerFile = null;
295
+ /** Paths written by the current in-memory batch (fast skip for later .ets hits). */
296
+ let batchPersistedPaths = new Set();
65
297
  function hashContent(content) {
66
298
  return crypto.createHash('sha256').update(content).digest('hex');
67
299
  }
@@ -75,7 +307,8 @@ function emptyResult(filePath, message, severity) {
75
307
  };
76
308
  }
77
309
  function scanEtsFiles(rootDir) {
78
- const found = [];
310
+ const etsFiles = [];
311
+ const coLocated = [];
79
312
  function walk(dir) {
80
313
  let entries;
81
314
  try {
@@ -91,25 +324,40 @@ function scanEtsFiles(rootDir) {
91
324
  continue;
92
325
  walk(full);
93
326
  }
94
- else if (entry.isFile() && entry.name.endsWith('.ets')) {
95
- found.push(path.relative(rootDir, full).replace(/\\/g, '/'));
327
+ else if (entry.isFile()) {
328
+ const rel = path.relative(rootDir, full).replace(/\\/g, '/');
329
+ if (isEtsFileName(entry.name)) {
330
+ etsFiles.push(rel);
331
+ }
332
+ else if (isCoLocatedArkTsFileName(entry.name)) {
333
+ coLocated.push(rel);
334
+ }
96
335
  }
97
336
  }
98
337
  }
99
338
  walk(rootDir);
339
+ if (etsFiles.length === 0 && !hasHarmonyProjectMarkers(rootDir)) {
340
+ return [];
341
+ }
342
+ const found = etsFiles.length > 0 ? [...etsFiles, ...coLocated] : coLocated;
100
343
  found.sort();
101
344
  return found;
102
345
  }
103
346
  function computeBatchKey(rootDir, etsFiles) {
347
+ // mtime + size only — full content hashes happen per-file at persist time.
104
348
  return etsFiles
105
349
  .map((rel) => {
106
350
  const full = path.join(rootDir, rel);
107
351
  const stat = fs.statSync(full);
108
- const content = fs.readFileSync(full, 'utf-8');
109
- return `${rel}:${stat.mtimeMs}:${hashContent(content)}`;
352
+ return `${rel}:${stat.mtimeMs}:${stat.size}`;
110
353
  })
111
354
  .join('\0');
112
355
  }
356
+ /** True when a full ArkTS batch has been committed for this index run. */
357
+ let batchBuildCommitted = false;
358
+ function reportBatchProgress(subphase, current, total, currentFile) {
359
+ (0, context_1.reportArkTSBatchProgress)({ subphase, current, total, currentFile });
360
+ }
113
361
  function persistFileResult(queries, filePath, content, stats, result) {
114
362
  const contentHash = hashContent(content);
115
363
  const existingFile = queries.getFileByPath(filePath);
@@ -155,18 +403,128 @@ function persistFileResult(queries, filePath, content, stats, result) {
155
403
  };
156
404
  queries.upsertFile(fileRecord);
157
405
  }
158
- /** Build Scene, run RTA, and write every `.ets` file + cross-file edges to the DB. */
159
- function runArkTSBatch(rootDir, queries, triggerFile) {
160
- const etsFiles = scanEtsFiles(rootDir);
406
+ async function persistBatchResultsAsync(rootDir, queries, index) {
407
+ const entries = [...index.fileResults.entries()];
408
+ const persistTotal = entries.length;
409
+ const parallel = resolveArkTSPersistParallel(persistTotal);
410
+ for (let start = 0; start < entries.length; start += parallel) {
411
+ const chunk = entries.slice(start, start + parallel);
412
+ const prepared = await Promise.all(chunk.map(async ([filePath, fileResult]) => {
413
+ const isVirtual = filePath.startsWith('@');
414
+ if (isVirtual) {
415
+ return {
416
+ filePath,
417
+ fileResult,
418
+ content: '',
419
+ stats: { size: 0, mtimeMs: Date.now() },
420
+ };
421
+ }
422
+ const full = path.join(rootDir, filePath);
423
+ const [content, stats] = await Promise.all([
424
+ fsp.readFile(full, 'utf-8'),
425
+ fsp.stat(full),
426
+ ]);
427
+ return { filePath, fileResult, content, stats };
428
+ }));
429
+ for (let i = 0; i < prepared.length; i++) {
430
+ const persistIndex = start + i + 1;
431
+ const item = prepared[i];
432
+ reportBatchProgress('persist', persistIndex, persistTotal, item.filePath);
433
+ persistFileResult(queries, item.filePath, item.content, item.stats, item.fileResult);
434
+ }
435
+ }
436
+ }
437
+ function persistBatchResultsSync(rootDir, queries, index) {
438
+ const persistTotal = index.fileResults.size;
439
+ let persistIndex = 0;
440
+ for (const [filePath, fileResult] of index.fileResults) {
441
+ persistIndex++;
442
+ reportBatchProgress('persist', persistIndex, persistTotal, filePath);
443
+ const isVirtual = filePath.startsWith('@');
444
+ const full = path.join(rootDir, filePath);
445
+ const content = isVirtual ? '' : fs.readFileSync(full, 'utf-8');
446
+ const stats = isVirtual
447
+ ? { size: 0, mtimeMs: Date.now() }
448
+ : fs.statSync(full);
449
+ persistFileResult(queries, filePath, content, stats, fileResult);
450
+ }
451
+ }
452
+ function commitArkTSBatch(rootDir, batchKey, etsFiles, index, triggerFile) {
453
+ batchPersistedPaths = new Set([...index.fileResults.keys()].map(normIndexPath));
454
+ persistedBatch = { ...index, rootDir, batchKey, etsFiles };
455
+ batchTriggerFile = normIndexPath(triggerFile);
456
+ if (index.fileResults.size > 0) {
457
+ batchBuildCommitted = true;
458
+ }
459
+ return persistedBatch;
460
+ }
461
+ function tryReturnCachedBatch(rootDir, triggerFile, etsFiles) {
462
+ const normalizedTrigger = normIndexPath(triggerFile);
463
+ if (persistedBatch &&
464
+ persistedBatch.rootDir === rootDir &&
465
+ batchPersistedPaths.has(normalizedTrigger)) {
466
+ return persistedBatch;
467
+ }
161
468
  const batchKey = etsFiles.length > 0 ? computeBatchKey(rootDir, etsFiles) : '';
162
469
  if (persistedBatch &&
163
470
  persistedBatch.rootDir === rootDir &&
471
+ persistedBatch.batchKey === batchKey &&
472
+ persistedBatch.fileResults.size > 0) {
473
+ batchPersistedPaths = new Set([...persistedBatch.fileResults.keys()].map(normIndexPath));
474
+ return persistedBatch;
475
+ }
476
+ if (batchBuildCommitted &&
477
+ persistedBatch &&
478
+ persistedBatch.rootDir === rootDir &&
479
+ persistedBatch.fileResults.size > 0 &&
164
480
  persistedBatch.batchKey === batchKey) {
165
481
  return persistedBatch;
166
482
  }
483
+ return null;
484
+ }
485
+ function markBatchCommittedAfterWorker(rootDir, triggerFile, etsFiles, batchKey) {
486
+ batchTriggerFile = normIndexPath(triggerFile);
487
+ batchPersistedPaths = new Set(etsFiles.map(normIndexPath));
488
+ batchBuildCommitted = true;
489
+ persistedBatch = {
490
+ fileResults: new Map(),
491
+ crossFileEdges: [],
492
+ nodeIds: new Set(),
493
+ errors: [],
494
+ rootDir,
495
+ batchKey,
496
+ etsFiles,
497
+ };
498
+ return persistedBatch;
499
+ }
500
+ function spawnIsolatedArkTSBatchWorker(rootDir, dbPath, triggerFile) {
501
+ const workerPath = path.join(__dirname, '..', 'arkts-batch-worker.js');
502
+ let lastCode = null;
503
+ for (const stackKb of resolveArkTSWorkerStackSizesKb()) {
504
+ process.stderr.write(`\n\x1b[33m ArkTS: full Scene build in isolated process (--stack-size=${stackKb} KB, enableMethodBodyBuild=true)...\x1b[0m\n`);
505
+ const argv = (0, wasm_runtime_flags_1.buildRelaunchArgv)(workerPath, [rootDir, dbPath, triggerFile], [`--stack-size=${stackKb}`]);
506
+ const result = (0, child_process_1.spawnSync)(process.execPath, argv, {
507
+ stdio: 'inherit',
508
+ env: process.env,
509
+ timeout: 60 * 60 * 1000,
510
+ windowsHide: true,
511
+ });
512
+ lastCode = result.status;
513
+ if (result.status === 0) {
514
+ return { ok: true, lastCode };
515
+ }
516
+ if (!isStackOverflowExitCode(result.status)) {
517
+ break;
518
+ }
519
+ }
520
+ return { ok: false, lastCode };
521
+ }
522
+ function runArkTSBatchFullCore(rootDir, queries, triggerFile, etsFiles, batchKey) {
167
523
  batchTriggerFile = null;
524
+ batchPersistedPaths = new Set();
168
525
  if (etsFiles.length === 0) {
169
526
  persistedBatch = null;
527
+ batchBuildCommitted = false;
170
528
  return {
171
529
  fileResults: new Map(),
172
530
  crossFileEdges: [],
@@ -174,33 +532,131 @@ function runArkTSBatch(rootDir, queries, triggerFile) {
174
532
  errors: [],
175
533
  rootDir,
176
534
  batchKey: '',
535
+ etsFiles: [],
177
536
  };
178
537
  }
179
- const index = buildArkTSIndex(rootDir, etsFiles);
180
- queries.deleteArkTSCrossFileCallEdges();
181
- for (const [filePath, fileResult] of index.fileResults) {
182
- const isVirtual = filePath.startsWith('@');
183
- const full = path.join(rootDir, filePath);
184
- const content = isVirtual ? '' : fs.readFileSync(full, 'utf-8');
185
- const stats = isVirtual
186
- ? { size: 0, mtimeMs: Date.now() }
187
- : fs.statSync(full);
188
- persistFileResult(queries, filePath, content, stats, fileResult);
538
+ (0, context_1.setArktsBatchRunning)(true);
539
+ try {
540
+ reportBatchProgress('scene', 0, etsFiles.length);
541
+ const index = buildArkTSIndex(rootDir, etsFiles);
542
+ if (index.fileResults.size === 0) {
543
+ const fatal = index.errors.find((e) => e.severity === 'error');
544
+ throw new Error(fatal?.message ?? 'ArkTS batch produced no indexed files');
545
+ }
546
+ queries.deleteArkTSCrossFileCallEdges();
547
+ persistBatchResultsSync(rootDir, queries, index);
548
+ if (index.crossFileEdges.length > 0) {
549
+ const valid = index.crossFileEdges.filter((e) => index.nodeIds.has(e.source) && index.nodeIds.has(e.target));
550
+ if (valid.length > 0) {
551
+ queries.insertEdges(valid);
552
+ }
553
+ }
554
+ return commitArkTSBatch(rootDir, batchKey, etsFiles, index, triggerFile);
555
+ }
556
+ finally {
557
+ (0, context_1.setArktsBatchRunning)(false);
189
558
  }
190
- if (index.crossFileEdges.length > 0) {
191
- const valid = index.crossFileEdges.filter((e) => index.nodeIds.has(e.source) && index.nodeIds.has(e.target));
192
- if (valid.length > 0) {
193
- queries.insertEdges(valid);
559
+ }
560
+ function runArkTSBatchFull(rootDir, queries, triggerFile, etsFiles, batchKey) {
561
+ if (shouldUseIsolatedArkTSBuild(etsFiles.length)) {
562
+ const dbPath = homegraphDbPath(rootDir);
563
+ if (!fs.existsSync(dbPath)) {
564
+ throw new Error(`ArkTS isolated build requires ${dbPath}`);
565
+ }
566
+ (0, context_1.setArktsBatchRunning)(true);
567
+ try {
568
+ reportBatchProgress('scene', 0, etsFiles.length);
569
+ const spawned = spawnIsolatedArkTSBatchWorker(rootDir, dbPath, triggerFile);
570
+ if (!spawned.ok) {
571
+ throw new Error(`ArkTS isolated Scene build failed (exit ${spawned.lastCode ?? 'unknown'}). ` +
572
+ 'Try HOMEGRAPH_ARKTS_STACK_SIZES_KB=65536,131072,262144');
573
+ }
574
+ return markBatchCommittedAfterWorker(rootDir, triggerFile, etsFiles, batchKey);
575
+ }
576
+ finally {
577
+ (0, context_1.setArktsBatchRunning)(false);
194
578
  }
195
579
  }
196
- persistedBatch = { ...index, rootDir, batchKey };
197
- batchTriggerFile = triggerFile;
198
- return persistedBatch;
580
+ return runArkTSBatchFullCore(rootDir, queries, triggerFile, etsFiles, batchKey);
199
581
  }
200
- /** Clear cached batch state (tests). */
582
+ /** Worker entry — full batch in an isolated process (no nested spawn). */
583
+ function runIsolatedArkTSBatchEntry(rootDir, dbPath, triggerFile) {
584
+ const db = db_1.DatabaseConnection.open(dbPath);
585
+ try {
586
+ const queries = new queries_1.QueryBuilder(db.getDb());
587
+ (0, context_1.bindExtractionContext)(rootDir, queries);
588
+ const etsFiles = scanEtsFiles(rootDir);
589
+ const batchKey = etsFiles.length > 0 ? computeBatchKey(rootDir, etsFiles) : '';
590
+ runArkTSBatchFullCore(rootDir, queries, normIndexPath(triggerFile), etsFiles, batchKey);
591
+ }
592
+ finally {
593
+ db.close();
594
+ }
595
+ }
596
+ /** Build Scene, run RTA, and write every `.ets` file + cross-file edges to the DB. */
597
+ function runArkTSBatch(rootDir, queries, triggerFile) {
598
+ const normalizedTrigger = normIndexPath(triggerFile);
599
+ const etsFiles = scanEtsFiles(rootDir);
600
+ const cached = tryReturnCachedBatch(rootDir, normalizedTrigger, etsFiles);
601
+ if (cached) {
602
+ return cached;
603
+ }
604
+ const batchKey = etsFiles.length > 0 ? computeBatchKey(rootDir, etsFiles) : '';
605
+ return runArkTSBatchFull(rootDir, queries, normalizedTrigger, etsFiles, batchKey);
606
+ }
607
+ /** Async batch build with parallel file reads during persist (used by indexAll). */
608
+ async function primeArkTSBatch(rootDir, queries, triggerFile) {
609
+ const normalizedTrigger = normIndexPath(triggerFile);
610
+ const etsFiles = scanEtsFiles(rootDir);
611
+ const cached = tryReturnCachedBatch(rootDir, normalizedTrigger, etsFiles);
612
+ if (cached) {
613
+ return;
614
+ }
615
+ const batchKey = etsFiles.length > 0 ? computeBatchKey(rootDir, etsFiles) : '';
616
+ batchTriggerFile = null;
617
+ batchPersistedPaths = new Set();
618
+ if (etsFiles.length === 0) {
619
+ persistedBatch = null;
620
+ batchBuildCommitted = false;
621
+ return;
622
+ }
623
+ if (shouldUseIsolatedArkTSBuild(etsFiles.length)) {
624
+ runArkTSBatchFull(rootDir, queries, normalizedTrigger, etsFiles, batchKey);
625
+ return;
626
+ }
627
+ (0, context_1.setArktsBatchRunning)(true);
628
+ try {
629
+ reportBatchProgress('scene', 0, etsFiles.length);
630
+ const index = buildArkTSIndex(rootDir, etsFiles);
631
+ if (index.fileResults.size === 0) {
632
+ const fatal = index.errors.find((e) => e.severity === 'error');
633
+ throw new Error(fatal?.message ?? 'ArkTS batch produced no indexed files');
634
+ }
635
+ queries.deleteArkTSCrossFileCallEdges();
636
+ await persistBatchResultsAsync(rootDir, queries, index);
637
+ if (index.crossFileEdges.length > 0) {
638
+ const valid = index.crossFileEdges.filter((e) => index.nodeIds.has(e.source) && index.nodeIds.has(e.target));
639
+ if (valid.length > 0) {
640
+ queries.insertEdges(valid);
641
+ }
642
+ }
643
+ commitArkTSBatch(rootDir, batchKey, etsFiles, index, normalizedTrigger);
644
+ }
645
+ finally {
646
+ (0, context_1.setArktsBatchRunning)(false);
647
+ }
648
+ }
649
+ /** True when this `.ets` file was already written by the in-memory ArkTS batch. */
650
+ function isArkTSBatchPersisted(filePath) {
651
+ return batchPersistedPaths.has(normIndexPath(filePath));
652
+ }
653
+ /** Clear cached batch state (tests and full re-index). */
201
654
  function resetArkTSBatch() {
202
655
  persistedBatch = null;
203
656
  batchTriggerFile = null;
657
+ batchPersistedPaths = new Set();
658
+ batchBuildCommitted = false;
659
+ arktsIndexNotices = [];
204
660
  }
205
661
  class ArkTSExtractor {
206
662
  filePath;
@@ -217,21 +673,21 @@ class ArkTSExtractor {
217
673
  durationMs: Date.now() - startTime,
218
674
  };
219
675
  }
220
- const batch = runArkTSBatch(rootDir, queries, this.filePath);
676
+ const batch = runArkTSBatch(rootDir, queries, normIndexPath(this.filePath));
221
677
  if (batch.fileResults.size === 0) {
222
678
  return {
223
679
  ...emptyResult(this.filePath, 'No .ets files in project', 'warning'),
224
680
  durationMs: Date.now() - startTime,
225
681
  };
226
682
  }
227
- const cached = batch.fileResults.get(this.filePath);
683
+ const cached = batch.fileResults.get(normIndexPath(this.filePath));
228
684
  if (!cached) {
229
685
  return {
230
686
  ...emptyResult(this.filePath, 'File not present in ArkTS index', 'warning'),
231
687
  durationMs: Date.now() - startTime,
232
688
  };
233
689
  }
234
- const edges = this.filePath === batchTriggerFile
690
+ const edges = normIndexPath(this.filePath) === batchTriggerFile
235
691
  ? [...cached.edges, ...batch.crossFileEdges]
236
692
  : cached.edges;
237
693
  return {
@@ -305,10 +761,13 @@ function anonymousClassDisplayName(cls) {
305
761
  function classDisplayName(cls) {
306
762
  return cls.isAnonymousClass() ? anonymousClassDisplayName(cls) : cls.getName();
307
763
  }
764
+ function isAnonymousArkMethod(method) {
765
+ return method.isAnonymousMethod?.() === true || method.getName().startsWith(arkanalyzer_1.ANONYMOUS_METHOD_PREFIX);
766
+ }
308
767
  function shouldSkipArkMethod(method) {
309
768
  if (method.isDefaultArkMethod())
310
769
  return true;
311
- if (method.isAnonymousMethod())
770
+ if (isAnonymousArkMethod(method))
312
771
  return true;
313
772
  const name = method.getName();
314
773
  if (name === arkanalyzer_1.DEFAULT_ARK_METHOD_NAME)
@@ -321,6 +780,15 @@ function shouldSkipArkMethod(method) {
321
780
  return true;
322
781
  return false;
323
782
  }
783
+ /** User-facing or ArkAnalyzer-stable name for graph nodes (includes `%AMn` for anonymous). */
784
+ function arkMethodDisplayName(method) {
785
+ const resolved = resolveMethodDisplayName(method);
786
+ if (resolved)
787
+ return resolved;
788
+ if (isAnonymousArkMethod(method))
789
+ return method.getName();
790
+ return null;
791
+ }
324
792
  /** Decode ArkAnalyzer nested-method encoding (`%inner$outer`) to the user-visible name. */
325
793
  function resolveMethodDisplayName(method) {
326
794
  const name = method.getName();
@@ -371,11 +839,11 @@ function buildMethodQualifiedName(method, displayName) {
371
839
  }
372
840
  const outer = method.getOuterMethod();
373
841
  if (outer) {
374
- const outerName = resolveMethodDisplayName(outer);
842
+ const outerName = arkMethodDisplayName(outer);
375
843
  if (outerName)
376
844
  parts.push(outerName);
377
845
  }
378
- parts.push(displayName ?? resolveMethodDisplayName(method) ?? method.getName());
846
+ parts.push(displayName ?? arkMethodDisplayName(method) ?? method.getName());
379
847
  return buildQualifiedName(parts);
380
848
  }
381
849
  function buildClassQualifiedName(cls) {
@@ -558,6 +1026,138 @@ function sceneHasArkUiEntries(scene) {
558
1026
  }
559
1027
  return false;
560
1028
  }
1029
+ // =============================================================================
1030
+ // ArkUI ViewTree — component tree, @Prop/@Link transfer, event bindings
1031
+ // =============================================================================
1032
+ const VIEWTREE_CALLBACK_ATTRS = new Set(arkanalyzer_1.CALLBACK_METHOD_NAME);
1033
+ /** State decorator kinds on a field (@State, @Prop, @Link, …) from arkanalyzer. */
1034
+ function stateDecoratorKinds(field) {
1035
+ const decs = field.getStateDecorators?.();
1036
+ if (!decs)
1037
+ return [];
1038
+ return [...decs].map((d) => d.getKind()).filter(Boolean);
1039
+ }
1040
+ /** Child @Prop / @Link — edge `via` uses the decorator name as-is. */
1041
+ function stateTransferViaForField(field) {
1042
+ for (const kind of stateDecoratorKinds(field)) {
1043
+ if (kind === 'Prop' || kind === 'Link')
1044
+ return kind;
1045
+ }
1046
+ return null;
1047
+ }
1048
+ function viewTreeLineFromStmt(stmt) {
1049
+ return stmt?.getOriginFullPosition()?.getFirstLine() ?? 1;
1050
+ }
1051
+ function isViewTreeClassSignature(sig) {
1052
+ return sig instanceof arkanalyzer_1.ClassSignature;
1053
+ }
1054
+ function walkViewTree(node, visit) {
1055
+ visit(node);
1056
+ for (const child of node.children) {
1057
+ walkViewTree(child, visit);
1058
+ }
1059
+ }
1060
+ function indexViewTreeForClass(ctx, cls, result, relativePath) {
1061
+ if (!cls.hasViewTree())
1062
+ return;
1063
+ const viewTree = cls.getViewTree();
1064
+ if (!viewTree)
1065
+ return;
1066
+ const root = viewTree.getRoot();
1067
+ if (!root)
1068
+ return;
1069
+ const classNodeId = ctx.resolveClassNodeId(cls);
1070
+ if (!classNodeId)
1071
+ return;
1072
+ const buildMethod = cls.getMethods(true).find((m) => m.getName() === 'build');
1073
+ if (!buildMethod)
1074
+ return;
1075
+ const buildId = ctx.ensureMethodNode(buildMethod, relativePath, result, classNodeId);
1076
+ if (!buildId)
1077
+ return;
1078
+ const seen = new Set();
1079
+ const link = (source, target, kind, via, line) => {
1080
+ const key = `${source}>${target}>${kind}>${via}`;
1081
+ if (seen.has(key))
1082
+ return;
1083
+ seen.add(key);
1084
+ ctx.addEdge(result, source, target, kind, relativePath, via, line);
1085
+ };
1086
+ for (const [field] of viewTree.getStateValues()) {
1087
+ const fieldId = ctx.fieldToId.get(field);
1088
+ if (fieldId) {
1089
+ ctx.markFieldStateDecorators?.(field, fieldId, result);
1090
+ const line = field.getOriginFullPosition?.()?.getFirstLine?.() ??
1091
+ buildMethod.getImplOriginFullPosition()?.getFirstLine() ??
1092
+ 1;
1093
+ link(fieldId, buildId, 'references', 'state-binding', line);
1094
+ }
1095
+ }
1096
+ walkViewTree(root, (node) => {
1097
+ const sig = node.signature;
1098
+ if (sig) {
1099
+ if (isViewTreeClassSignature(sig)) {
1100
+ const childCls = ctx.scene.getClass(sig);
1101
+ if (childCls) {
1102
+ const childId = ctx.resolveClassNodeId(childCls);
1103
+ if (childId) {
1104
+ const firstAttr = node.attributes.values().next().value;
1105
+ const line = firstAttr
1106
+ ? viewTreeLineFromStmt(firstAttr[0])
1107
+ : buildMethod.getImplOriginFullPosition()?.getFirstLine() ?? 1;
1108
+ link(buildId, childId, 'references', 'child-component', line);
1109
+ }
1110
+ }
1111
+ }
1112
+ else {
1113
+ const builderMethod = ctx.scene.getMethod(sig);
1114
+ if (builderMethod) {
1115
+ const builderId = ctx.ensureMethodNode(builderMethod, relativePath, result, classNodeId);
1116
+ if (builderId) {
1117
+ link(buildId, builderId, 'references', 'builder', builderMethod.getImplOriginFullPosition()?.getFirstLine() ?? 1);
1118
+ }
1119
+ }
1120
+ }
1121
+ }
1122
+ if (node.stateValuesTransfer) {
1123
+ for (const [childField, parentValue] of node.stateValuesTransfer) {
1124
+ const childFieldId = ctx.fieldToId.get(childField);
1125
+ if (parentValue instanceof arkanalyzer_1.ArkField) {
1126
+ const via = stateTransferViaForField(childField);
1127
+ if (!via || !childFieldId)
1128
+ continue;
1129
+ ctx.markFieldStateDecorators?.(childField, childFieldId, result);
1130
+ const parentFieldId = ctx.fieldToId.get(parentValue);
1131
+ if (parentFieldId) {
1132
+ ctx.markFieldStateDecorators?.(parentValue, parentFieldId, result);
1133
+ link(parentFieldId, childFieldId, 'references', via, childField.getOriginFullPosition()?.getFirstLine() ?? 1);
1134
+ }
1135
+ }
1136
+ else if (parentValue instanceof arkanalyzer_1.ArkMethod) {
1137
+ const builderId = ctx.ensureMethodNode(parentValue, relativePath, result, classNodeId);
1138
+ if (childFieldId && builderId) {
1139
+ link(builderId, childFieldId, 'references', 'builder-param', childField.getOriginFullPosition()?.getFirstLine() ?? 1);
1140
+ }
1141
+ }
1142
+ }
1143
+ }
1144
+ for (const [attr, [stmt, values]] of node.attributes) {
1145
+ if (!VIEWTREE_CALLBACK_ATTRS.has(attr))
1146
+ continue;
1147
+ const line = viewTreeLineFromStmt(stmt);
1148
+ for (const v of values) {
1149
+ if (!(v instanceof arkanalyzer_1.MethodSignature))
1150
+ continue;
1151
+ const handler = ctx.scene.getMethod(v);
1152
+ if (!handler)
1153
+ continue;
1154
+ const handlerId = ctx.ensureMethodNode(handler, relativePath, result, classNodeId);
1155
+ if (handlerId)
1156
+ link(buildId, handlerId, 'references', attr, line);
1157
+ }
1158
+ }
1159
+ });
1160
+ }
561
1161
  class ArkTSAdapter {
562
1162
  rootDir;
563
1163
  scanned;
@@ -580,7 +1180,7 @@ class ArkTSAdapter {
580
1180
  const relativePath = normalizeRelPath(this.rootDir, arkFile.getFilePath());
581
1181
  if (!this.scanned.has(relativePath))
582
1182
  continue;
583
- if (!relativePath.endsWith('.ets'))
1183
+ if (!isArkAnalyzerSourcePath(relativePath))
584
1184
  continue;
585
1185
  this.indexFile(arkFile);
586
1186
  }
@@ -589,12 +1189,22 @@ class ArkTSAdapter {
589
1189
  continue;
590
1190
  const arkFile = cls.getDeclaringArkFile();
591
1191
  const relativePath = normalizeRelPath(this.rootDir, arkFile.getFilePath());
592
- if (!this.scanned.has(relativePath) || !relativePath.endsWith('.ets'))
1192
+ if (!this.scanned.has(relativePath) || !isArkAnalyzerSourcePath(relativePath))
593
1193
  continue;
594
1194
  const result = this.fileResults.get(relativePath);
595
1195
  if (!result)
596
1196
  continue;
597
- (0, arkts_viewtree_1.indexViewTreeForClass)(this.viewTreeContext(), cls, result, relativePath);
1197
+ try {
1198
+ indexViewTreeForClass(this.viewTreeContext(), cls, result, relativePath);
1199
+ }
1200
+ catch (e) {
1201
+ const message = e instanceof Error ? e.message : String(e);
1202
+ result.errors.push({
1203
+ message: `ViewTree indexing skipped for ${cls.getName()}: ${message}`,
1204
+ filePath: relativePath,
1205
+ severity: 'warning',
1206
+ });
1207
+ }
598
1208
  }
599
1209
  if (dummyMain) {
600
1210
  this.indexArkanalyzerDummyMain(dummyMain);
@@ -614,12 +1224,13 @@ class ArkTSAdapter {
614
1224
  if (!caller || !callee)
615
1225
  continue;
616
1226
  if (shouldSkipArkMethod(caller) &&
1227
+ !isAnonymousArkMethod(caller) &&
617
1228
  !caller.getDeclaringArkClass().isDefaultArkClass() &&
618
1229
  !caller.isGenerated()) {
619
1230
  continue;
620
1231
  }
621
- const callerId = this.methodToId.get(caller);
622
- const calleeId = this.methodToId.get(callee);
1232
+ const callerId = this.resolveMethodNodeId(caller);
1233
+ const calleeId = this.resolveMethodNodeId(callee);
623
1234
  if (!callerId || !calleeId)
624
1235
  continue;
625
1236
  const callerFile = relPathForArkFile(this.rootDir, caller.getDeclaringArkFile());
@@ -899,8 +1510,10 @@ class ArkTSAdapter {
899
1510
  return;
900
1511
  const { line, endLine, col } = linesFromPosition(field.getOriginFullPosition());
901
1512
  const qn = buildFieldQualifiedName(field);
1513
+ const stateDecs = stateDecoratorKinds(field);
902
1514
  const fieldNode = makeNode(relativePath, language, kind, name, qn, line, endLine, col, {
903
1515
  signature: field.getType()?.toString(),
1516
+ ...(stateDecs.length > 0 ? { decorators: stateDecs } : {}),
904
1517
  ...modelModifiersToNodeExtras(field),
905
1518
  });
906
1519
  this.addNode(result, fieldNode);
@@ -923,11 +1536,63 @@ class ArkTSAdapter {
923
1536
  addEdge: (result, source, target, kind, callerFile, via, line) => this.addViewTreeEdge(result, source, target, kind, callerFile, via, line),
924
1537
  ensureMethodNode: (method, relativePath, result, parentId) => this.ensureMethodNode(method, relativePath, result, parentId),
925
1538
  resolveClassNodeId: (cls) => this.resolveClassNodeId(cls),
1539
+ markFieldStateDecorators: (field, fieldNodeId, result) => {
1540
+ const kinds = stateDecoratorKinds(field);
1541
+ if (kinds.length === 0)
1542
+ return;
1543
+ const node = result.nodes.find((n) => n.id === fieldNodeId);
1544
+ if (node)
1545
+ node.decorators = kinds;
1546
+ },
926
1547
  };
927
1548
  }
928
1549
  resolveClassNodeId(cls) {
929
1550
  return this.componentToId.get(cls) ?? this.classToId.get(cls) ?? null;
930
1551
  }
1552
+ /** Parent node id for a method: owning class/component, or file for default-class methods. */
1553
+ resolveMethodParentId(method, relativePath, result) {
1554
+ const cls = method.getDeclaringArkClass();
1555
+ if (cls.isDefaultArkClass()) {
1556
+ return `file:${relativePath}`;
1557
+ }
1558
+ const classId = this.resolveClassNodeId(cls);
1559
+ if (classId)
1560
+ return classId;
1561
+ const fileId = `file:${relativePath}`;
1562
+ this.indexClass(relativePath, 'arkts', result, cls, fileId);
1563
+ return this.resolveClassNodeId(cls) ?? fileId;
1564
+ }
1565
+ /**
1566
+ * Resolve a method to a graph node id, lazily indexing anonymous ArkMethods
1567
+ * that RTA / ViewTree reference but the main file walk skipped.
1568
+ */
1569
+ resolveMethodNodeId(method) {
1570
+ const existing = this.methodToId.get(method);
1571
+ if (existing)
1572
+ return existing;
1573
+ if (shouldSkipArkMethod(method) && !isAnonymousArkMethod(method))
1574
+ return null;
1575
+ const displayName = arkMethodDisplayName(method);
1576
+ if (!displayName)
1577
+ return null;
1578
+ const arkFile = method.getDeclaringArkFile();
1579
+ const relativePath = normalizeRelPath(this.rootDir, arkFile.getFilePath());
1580
+ if (!this.scanned.has(relativePath) || !isArkAnalyzerSourcePath(relativePath))
1581
+ return null;
1582
+ let lineCount = 1;
1583
+ try {
1584
+ lineCount = arkFile.getCode()?.split('\n').length ?? 1;
1585
+ }
1586
+ catch {
1587
+ // use default
1588
+ }
1589
+ const result = this.fileResults.get(relativePath) ?? this.ensureFileResult(relativePath, lineCount);
1590
+ const parentId = this.resolveMethodParentId(method, relativePath, result);
1591
+ const cls = method.getDeclaringArkClass();
1592
+ const kind = cls.isDefaultArkClass() ? 'function' : 'method';
1593
+ this.indexMethod(relativePath, 'arkts', result, method, parentId, kind, displayName);
1594
+ return this.methodToId.get(method) ?? null;
1595
+ }
931
1596
  addViewTreeEdge(result, source, target, kind, callerFile, via, line) {
932
1597
  const edge = arkEdge(source, target, kind, {
933
1598
  metadata: {
@@ -947,14 +1612,14 @@ class ArkTSAdapter {
947
1612
  const existing = this.methodToId.get(method);
948
1613
  if (existing)
949
1614
  return existing;
950
- if (method.isAnonymousMethod?.() || method.getName().startsWith(arkanalyzer_1.ANONYMOUS_METHOD_PREFIX)) {
951
- const line = method.getImplOriginFullPosition()?.getFirstLine() ?? 1;
952
- this.indexMethod(relativePath, 'arkts', result, method, parentId, 'method', `@callback:${line}`);
953
- return this.methodToId.get(method) ?? null;
954
- }
955
- if (shouldSkipArkMethod(method))
1615
+ if (shouldSkipArkMethod(method) && !isAnonymousArkMethod(method))
1616
+ return null;
1617
+ const displayName = arkMethodDisplayName(method);
1618
+ if (!displayName)
956
1619
  return null;
957
- this.indexMethod(relativePath, 'arkts', result, method, parentId);
1620
+ const cls = method.getDeclaringArkClass();
1621
+ const kind = cls.isDefaultArkClass() ? 'function' : 'method';
1622
+ this.indexMethod(relativePath, 'arkts', result, method, parentId, kind, displayName);
958
1623
  return this.methodToId.get(method) ?? null;
959
1624
  }
960
1625
  indexMethod(relativePath, language, result, method, parentId, forcedKind, forcedDisplayName) {
@@ -965,9 +1630,10 @@ class ArkTSAdapter {
965
1630
  const kind = forcedKind ?? (cls.isDefaultArkClass() ? 'function' : 'method');
966
1631
  const qn = buildMethodQualifiedName(method, displayName);
967
1632
  const { line, endLine, col } = linesFromPosition(method.getImplOriginFullPosition());
968
- const sig = method.getSignature()?.toString();
1633
+ const { signature, returnType } = buildArkMethodSignatureFields(method);
969
1634
  const methodNode = makeNode(relativePath, language, kind, displayName, qn, line, endLine, col, {
970
- signature: sig,
1635
+ ...(signature ? { signature } : {}),
1636
+ ...(returnType ? { returnType } : {}),
971
1637
  ...modelModifiersToNodeExtras(method),
972
1638
  });
973
1639
  this.addNode(result, methodNode);
@@ -1040,30 +1706,593 @@ class ArkTSAdapter {
1040
1706
  }
1041
1707
  }
1042
1708
  }
1043
- function buildArkTSIndex(rootDir, scannedFiles) {
1044
- const errors = [];
1045
- const config = (0, arkanalyzer_1.buildSceneConfigFromProject)(rootDir, process.env.OHOS_SDK_HOME, {
1046
- supportFileExts: ['.ets'],
1709
+ /** User-visible notices from the most recent ArkTS batch (surfaced in CLI / IndexResult). */
1710
+ let arktsIndexNotices = [];
1711
+ /** Drain notices for merging into IndexResult.errors (clears the buffer). */
1712
+ function drainArkTSIndexNotices() {
1713
+ const out = arktsIndexNotices;
1714
+ arktsIndexNotices = [];
1715
+ return out;
1716
+ }
1717
+ function buildSceneConfig(rootDir) {
1718
+ return (0, arkanalyzer_1.buildSceneConfigFromProject)(rootDir, process.env.OHOS_SDK_HOME, {
1719
+ supportFileExts: ['.ets', '.ts', '.d.ts'],
1047
1720
  enableMethodBodyBuild: true,
1048
1721
  });
1722
+ }
1723
+ function tryBuildArkScene(rootDir) {
1724
+ const errors = [];
1049
1725
  const scene = new arkanalyzer_1.Scene();
1050
1726
  try {
1051
- scene.buildSceneFromProjectDir(config);
1727
+ scene.buildSceneFromProjectDir(buildSceneConfig(rootDir));
1052
1728
  scene.inferTypes();
1729
+ return { scene, errors };
1053
1730
  }
1054
1731
  catch (e) {
1055
1732
  const message = e instanceof Error ? e.message : String(e);
1056
1733
  errors.push({ message: `ArkTS Scene build failed: ${message}`, severity: 'error' });
1734
+ return { scene: null, errors };
1735
+ }
1736
+ }
1737
+ function emptyArkTSBatchIndex(errors) {
1738
+ return {
1739
+ fileResults: new Map(),
1740
+ crossFileEdges: [],
1741
+ nodeIds: new Set(),
1742
+ errors,
1743
+ };
1744
+ }
1745
+ function buildArkTSIndex(rootDir, scannedFiles) {
1746
+ const { scene, errors } = tryBuildArkScene(rootDir);
1747
+ if (!scene) {
1748
+ return emptyArkTSBatchIndex(errors);
1749
+ }
1750
+ try {
1751
+ const adapter = new ArkTSAdapter(rootDir, scannedFiles);
1752
+ const index = adapter.build(scene);
1753
+ index.errors.push(...errors);
1754
+ return index;
1755
+ }
1756
+ catch (e) {
1757
+ const message = e instanceof Error ? e.message : String(e);
1758
+ errors.push({ message: `ArkTS adapter failed: ${message}`, severity: 'error' });
1759
+ return emptyArkTSBatchIndex(errors);
1760
+ }
1761
+ }
1762
+ // =============================================================================
1763
+ // OHOS SDK input resolution + prebuilt API database indexing
1764
+ // =============================================================================
1765
+ const OHOS_ARCHIVE_EXTENSIONS = ['.tar.gz', '.tgz', '.zip', '.tar'];
1766
+ class OhosSdkInputError extends Error {
1767
+ constructor(message) {
1768
+ super(message);
1769
+ this.name = 'OhosSdkInputError';
1770
+ }
1771
+ }
1772
+ exports.OhosSdkInputError = OhosSdkInputError;
1773
+ /** Parse `6.1.1.290` or `commandline-tools-linux-x64-6.1.1.290.zip` → `6.1.1`. */
1774
+ function parseOhosToolsVersionFromName(name) {
1775
+ const base = path.basename(name);
1776
+ const withoutExt = stripOhosArchiveExtension(base);
1777
+ const match = withoutExt.match(/(\d+\.\d+\.\d+)(?:\.\d+)?$/);
1778
+ return match?.[1] ?? null;
1779
+ }
1780
+ function stripOhosArchiveExtension(filename) {
1781
+ for (const ext of OHOS_ARCHIVE_EXTENSIONS) {
1782
+ if (filename.toLowerCase().endsWith(ext)) {
1783
+ return filename.slice(0, -ext.length);
1784
+ }
1785
+ }
1786
+ return filename;
1787
+ }
1788
+ function isArchivePath(inputPath) {
1789
+ const lower = inputPath.toLowerCase();
1790
+ return OHOS_ARCHIVE_EXTENSIONS.some((ext) => lower.endsWith(ext));
1791
+ }
1792
+ /** Locate `sdk/default` that contains `openharmony/ets` under an extracted tree. */
1793
+ function findOhosSdkHome(searchRoot) {
1794
+ const resolved = path.resolve(searchRoot);
1795
+ const direct = [
1796
+ path.join(resolved, 'sdk', 'default'),
1797
+ path.join(resolved, 'command-line-tools', 'sdk', 'default'),
1798
+ ];
1799
+ for (const candidate of direct) {
1800
+ if (hasOpenHarmonyEts(candidate)) {
1801
+ return candidate;
1802
+ }
1803
+ }
1804
+ const queue = [{ dir: resolved, depth: 0 }];
1805
+ const seen = new Set();
1806
+ while (queue.length > 0) {
1807
+ const { dir, depth } = queue.shift();
1808
+ if (seen.has(dir) || depth > 5)
1809
+ continue;
1810
+ seen.add(dir);
1811
+ const sdkDefault = path.join(dir, 'sdk', 'default');
1812
+ if (hasOpenHarmonyEts(sdkDefault)) {
1813
+ return sdkDefault;
1814
+ }
1815
+ if (depth >= 5)
1816
+ continue;
1817
+ let entries;
1818
+ try {
1819
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1820
+ }
1821
+ catch {
1822
+ continue;
1823
+ }
1824
+ for (const entry of entries) {
1825
+ if (!entry.isDirectory())
1826
+ continue;
1827
+ if (entry.name === 'node_modules' || entry.name === '.git')
1828
+ continue;
1829
+ queue.push({ dir: path.join(dir, entry.name), depth: depth + 1 });
1830
+ }
1831
+ }
1832
+ return null;
1833
+ }
1834
+ function hasOpenHarmonyEts(sdkHome) {
1835
+ return fs.existsSync(path.join(sdkHome, 'openharmony', 'ets'));
1836
+ }
1837
+ function listOhosApiEtsRoots(sdkHome) {
1838
+ const roots = [];
1839
+ const openharmony = path.join(sdkHome, 'openharmony', 'ets');
1840
+ if (fs.existsSync(openharmony)) {
1841
+ roots.push(openharmony);
1842
+ }
1843
+ const hms = path.join(sdkHome, 'hms', 'ets');
1844
+ if (fs.existsSync(hms)) {
1845
+ roots.push(hms);
1846
+ }
1847
+ return roots;
1848
+ }
1849
+ /** Resolve a command-line-tools archive or directory to an SDK home + API db version. */
1850
+ function resolveOhosSdkInput(options) {
1851
+ const inputPath = path.resolve(options.inputPath);
1852
+ if (!fs.existsSync(inputPath)) {
1853
+ throw new OhosSdkInputError(`Path does not exist: ${inputPath}`);
1854
+ }
1855
+ let searchRoot = inputPath;
1856
+ let cleanup;
1857
+ if (fs.statSync(inputPath).isFile()) {
1858
+ if (!isArchivePath(inputPath)) {
1859
+ throw new OhosSdkInputError(`Unsupported file type: ${path.basename(inputPath)} (expected .zip, .tar.gz, .tgz, or .tar)`);
1860
+ }
1861
+ const extracted = extractOhosSdkArchive(inputPath);
1862
+ searchRoot = extracted.dir;
1863
+ cleanup = extracted.cleanup;
1864
+ }
1865
+ const sdkHome = findOhosSdkHome(searchRoot);
1866
+ if (!sdkHome) {
1867
+ cleanup?.();
1868
+ throw new OhosSdkInputError(`Could not find sdk/default/openharmony/ets under ${inputPath}. ` +
1869
+ 'Expected HarmonyOS command-line-tools layout.');
1870
+ }
1871
+ const version = options.versionOverride?.trim() ||
1872
+ parseOhosToolsVersionFromName(inputPath) ||
1873
+ parseOhosToolsVersionFromName(searchRoot);
1874
+ if (!version) {
1875
+ cleanup?.();
1876
+ throw new OhosSdkInputError('Could not determine API db version. Use a path like commandline-tools-linux-x64-6.1.1.290.zip ' +
1877
+ 'or pass the version as the second argument.');
1878
+ }
1879
+ return {
1880
+ sdkHome,
1881
+ version,
1882
+ sourcePath: inputPath,
1883
+ cleanup,
1884
+ };
1885
+ }
1886
+ function extractOhosSdkArchive(archivePath) {
1887
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'homegraph-ohos-sdk-'));
1888
+ const lower = archivePath.toLowerCase();
1889
+ try {
1890
+ if (lower.endsWith('.zip')) {
1891
+ (0, child_process_1.execFileSync)('unzip', ['-q', archivePath, '-d', tempDir], { stdio: 'pipe' });
1892
+ }
1893
+ else if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {
1894
+ (0, child_process_1.execFileSync)('tar', ['-xzf', archivePath, '-C', tempDir], { stdio: 'pipe' });
1895
+ }
1896
+ else if (lower.endsWith('.tar')) {
1897
+ (0, child_process_1.execFileSync)('tar', ['-xf', archivePath, '-C', tempDir], { stdio: 'pipe' });
1898
+ }
1899
+ else {
1900
+ throw new OhosSdkInputError(`Unsupported archive: ${path.basename(archivePath)}`);
1901
+ }
1902
+ }
1903
+ catch (err) {
1904
+ fs.rmSync(tempDir, { recursive: true, force: true });
1905
+ const msg = err instanceof Error ? err.message : String(err);
1906
+ throw new OhosSdkInputError(`Failed to extract ${archivePath}: ${msg}`);
1907
+ }
1908
+ return {
1909
+ dir: tempDir,
1910
+ cleanup: () => {
1911
+ fs.rmSync(tempDir, { recursive: true, force: true });
1912
+ },
1913
+ };
1914
+ }
1915
+ /** Default filename for a versioned OHOS API db. */
1916
+ function ohosApiDbFilename(version) {
1917
+ return `ohos-api-${version}.db`;
1918
+ }
1919
+ /** npm package name — one package per API version (e.g. homegraph-ohos-api-db-6.0.1). */
1920
+ function ohosApiDbPackageName(version) {
1921
+ return `homegraph-ohos-api-db-${version}`;
1922
+ }
1923
+ /** Target path under ~/.homegraph/api/ for a versioned db. */
1924
+ function ohosApiDbInstallPath(version) {
1925
+ return path.join(os.homedir(), '.homegraph', 'api', ohosApiDbFilename(version));
1926
+ }
1927
+ function scanFirstOhosApiTriggerFile(etsRoot) {
1928
+ let found = null;
1929
+ function walk(dir) {
1930
+ if (found)
1931
+ return;
1932
+ let entries;
1933
+ try {
1934
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1935
+ }
1936
+ catch {
1937
+ return;
1938
+ }
1939
+ for (const entry of entries) {
1940
+ const full = path.join(dir, entry.name);
1941
+ if (entry.isDirectory()) {
1942
+ if (entry.name === 'node_modules' || entry.name === '.git')
1943
+ continue;
1944
+ walk(full);
1945
+ }
1946
+ else if (entry.isFile()) {
1947
+ const lower = entry.name.toLowerCase();
1948
+ if (lower.endsWith('.ets') ||
1949
+ lower.endsWith('.d.ts') ||
1950
+ lower.endsWith('.d.ets') ||
1951
+ (lower.endsWith('.ts') && !lower.endsWith('.d.ts'))) {
1952
+ found = path.relative(etsRoot, full).replace(/\\/g, '/');
1953
+ return;
1954
+ }
1955
+ }
1956
+ }
1957
+ }
1958
+ walk(etsRoot);
1959
+ return found;
1960
+ }
1961
+ function countOhosApiSources(etsRoot) {
1962
+ let count = 0;
1963
+ function walk(dir) {
1964
+ let entries;
1965
+ try {
1966
+ entries = fs.readdirSync(dir, { withFileTypes: true });
1967
+ }
1968
+ catch {
1969
+ return;
1970
+ }
1971
+ for (const entry of entries) {
1972
+ const full = path.join(dir, entry.name);
1973
+ if (entry.isDirectory()) {
1974
+ if (entry.name === 'node_modules' || entry.name === '.git')
1975
+ continue;
1976
+ walk(full);
1977
+ }
1978
+ else if (entry.isFile()) {
1979
+ const lower = entry.name.toLowerCase();
1980
+ if (lower.endsWith('.ets') ||
1981
+ lower.endsWith('.d.ts') ||
1982
+ lower.endsWith('.d.ets') ||
1983
+ (lower.endsWith('.ts') && !lower.endsWith('.d.ts'))) {
1984
+ count++;
1985
+ }
1986
+ }
1987
+ }
1988
+ }
1989
+ walk(etsRoot);
1990
+ return count;
1991
+ }
1992
+ /** Index OpenHarmony (and optional HMS) SDK API declarations into a SQLite db. */
1993
+ async function indexOhosApiDb(options) {
1994
+ const sdkHome = path.resolve(options.sdkHome);
1995
+ if (!hasOpenHarmonyEts(sdkHome)) {
1996
+ throw new Error(`SDK home is missing openharmony/ets: ${sdkHome}`);
1997
+ }
1998
+ const etsRoots = listOhosApiEtsRoots(sdkHome);
1999
+ if (etsRoots.length === 0) {
2000
+ throw new Error(`No API ets roots found under ${sdkHome}`);
2001
+ }
2002
+ const outputPath = path.resolve(options.outputPath ?? path.join(process.cwd(), ohosApiDbFilename(options.version)));
2003
+ if (fs.existsSync(outputPath)) {
2004
+ fs.unlinkSync(outputPath);
2005
+ }
2006
+ const startTime = Date.now();
2007
+ const errors = [];
2008
+ let filesIndexed = 0;
2009
+ const db = db_1.DatabaseConnection.initialize(outputPath);
2010
+ const queries = new queries_1.QueryBuilder(db.getDb());
2011
+ try {
2012
+ for (const etsRoot of etsRoots) {
2013
+ const trigger = scanFirstOhosApiTriggerFile(etsRoot);
2014
+ if (!trigger) {
2015
+ errors.push({
2016
+ message: `No ArkTS sources under ${etsRoot}`,
2017
+ severity: 'warning',
2018
+ });
2019
+ continue;
2020
+ }
2021
+ const total = countOhosApiSources(etsRoot);
2022
+ options.onProgress?.({
2023
+ phase: 'arkts-batch',
2024
+ current: 0,
2025
+ total,
2026
+ currentFile: etsRoot,
2027
+ subphase: 'scene',
2028
+ });
2029
+ resetArkTSBatch();
2030
+ (0, context_1.resetExtractionContext)();
2031
+ (0, context_1.bindExtractionContext)(etsRoot, queries);
2032
+ await primeArkTSBatch(etsRoot, queries, trigger);
2033
+ filesIndexed += total;
2034
+ options.onProgress?.({
2035
+ phase: 'arkts-batch',
2036
+ current: total,
2037
+ total,
2038
+ currentFile: etsRoot,
2039
+ subphase: 'persist',
2040
+ });
2041
+ }
2042
+ const counts = queries.getNodeAndEdgeCount();
2043
+ queries.setMetadata('ohos_api_version', options.version);
2044
+ queries.setMetadata('ohos_api_sdk_home', sdkHome);
2045
+ queries.setMetadata('ohos_api_db_kind', ohosApiDbPackageName(options.version));
2046
+ queries.setMetadata('indexed_with_version', version_1.HomeGraphPackageVersion);
2047
+ queries.setMetadata('indexed_with_extraction_version', String(extraction_version_1.EXTRACTION_VERSION));
2048
+ db.runMaintenance();
1057
2049
  return {
1058
- fileResults: new Map(),
1059
- crossFileEdges: [],
1060
- nodeIds: new Set(),
2050
+ success: errors.every((e) => e.severity !== 'error'),
2051
+ filesIndexed,
2052
+ filesSkipped: 0,
2053
+ filesErrored: errors.filter((e) => e.severity === 'error').length,
2054
+ nodesCreated: counts.nodes,
2055
+ edgesCreated: counts.edges,
1061
2056
  errors,
2057
+ durationMs: Date.now() - startTime,
2058
+ };
2059
+ }
2060
+ finally {
2061
+ resetArkTSBatch();
2062
+ (0, context_1.resetExtractionContext)();
2063
+ db.close();
2064
+ }
2065
+ }
2066
+ // =============================================================================
2067
+ // OHOS API db consumer: compileSdkVersion detect, npm fetch, ATTACH for queries
2068
+ // =============================================================================
2069
+ exports.OHOS_API_FILE_PREFIX = 'ohos-sdk:';
2070
+ exports.OHOS_API_VERSION_META = 'ohos_api_version';
2071
+ exports.OHOS_API_DB_PATH_META = 'ohos_api_db_path';
2072
+ /** Prefix applied to API db node file paths so explore can render without disk reads. */
2073
+ function markOhosApiFilePath(relativePath) {
2074
+ return `${exports.OHOS_API_FILE_PREFIX}${relativePath.replace(/\\/g, '/')}`;
2075
+ }
2076
+ function isOhosApiFilePath(filePath) {
2077
+ return filePath.startsWith(exports.OHOS_API_FILE_PREFIX);
2078
+ }
2079
+ /** Strip json5 comments/trailing commas enough for compileSdkVersion extraction. */
2080
+ function parseJson5Minimal(text) {
2081
+ const stripped = text
2082
+ .replace(/\/\/.*$/gm, '')
2083
+ .replace(/\/\*[\s\S]*?\*\//g, '')
2084
+ .replace(/,(\s*[}\]])/g, '$1');
2085
+ return JSON.parse(stripped);
2086
+ }
2087
+ /** Normalize compileSdkVersion values like "6.0.1(21)" → "6.0.1". */
2088
+ function normalizeOhosApiVersion(raw) {
2089
+ if (raw == null)
2090
+ return null;
2091
+ if (typeof raw === 'number') {
2092
+ const s = String(raw);
2093
+ if (/^\d+$/.test(s) && s.length >= 8) {
2094
+ const major = Math.floor(Number(s) / 1_000_000);
2095
+ const minor = Math.floor((Number(s) % 1_000_000) / 1000);
2096
+ const patch = Number(s) % 1000;
2097
+ return `${major}.${minor}.${patch}`;
2098
+ }
2099
+ return null;
2100
+ }
2101
+ const match = String(raw).match(/(\d+\.\d+\.\d+)/);
2102
+ return match?.[1] ?? null;
2103
+ }
2104
+ function findBuildProfileFiles(projectRoot) {
2105
+ const found = [];
2106
+ const rootProfile = path.join(projectRoot, 'build-profile.json5');
2107
+ if (fs.existsSync(rootProfile))
2108
+ found.push(rootProfile);
2109
+ let entries;
2110
+ try {
2111
+ entries = fs.readdirSync(projectRoot, { withFileTypes: true });
2112
+ }
2113
+ catch {
2114
+ return found;
2115
+ }
2116
+ for (const entry of entries) {
2117
+ if (!entry.isDirectory())
2118
+ continue;
2119
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.homegraph')
2120
+ continue;
2121
+ const nested = path.join(projectRoot, entry.name, 'build-profile.json5');
2122
+ if (fs.existsSync(nested))
2123
+ found.push(nested);
2124
+ }
2125
+ return found;
2126
+ }
2127
+ function extractCompileSdkFromObject(obj) {
2128
+ if (!obj || typeof obj !== 'object')
2129
+ return null;
2130
+ const record = obj;
2131
+ for (const key of ['compileSdkVersion', 'compileSdk', 'targetSdkVersion']) {
2132
+ const v = normalizeOhosApiVersion(record[key]);
2133
+ if (v)
2134
+ return v;
2135
+ }
2136
+ const app = record.app;
2137
+ if (app && typeof app === 'object') {
2138
+ const products = app.products;
2139
+ if (Array.isArray(products)) {
2140
+ for (const product of products) {
2141
+ const v = extractCompileSdkFromObject(product);
2142
+ if (v)
2143
+ return v;
2144
+ }
2145
+ }
2146
+ }
2147
+ for (const value of Object.values(record)) {
2148
+ if (value && typeof value === 'object') {
2149
+ const v = extractCompileSdkFromObject(value);
2150
+ if (v)
2151
+ return v;
2152
+ }
2153
+ }
2154
+ return null;
2155
+ }
2156
+ /** Read compileSdkVersion from build-profile.json5 (root or module). */
2157
+ function detectOhosCompileSdkVersion(projectRoot) {
2158
+ const envOverride = process.env.HOMEGRAPH_OHOS_API_VERSION?.trim();
2159
+ if (envOverride) {
2160
+ return normalizeOhosApiVersion(envOverride) ?? envOverride;
2161
+ }
2162
+ for (const profilePath of findBuildProfileFiles(projectRoot)) {
2163
+ try {
2164
+ const text = fs.readFileSync(profilePath, 'utf-8');
2165
+ const parsed = parseJson5Minimal(text);
2166
+ const version = extractCompileSdkFromObject(parsed);
2167
+ if (version)
2168
+ return version;
2169
+ }
2170
+ catch {
2171
+ const match = fs.readFileSync(profilePath, 'utf-8').match(/compileSdkVersion\s*:\s*['"]?([^'"\s,)]+)/);
2172
+ const v = normalizeOhosApiVersion(match?.[1]);
2173
+ if (v)
2174
+ return v;
2175
+ }
2176
+ }
2177
+ return null;
2178
+ }
2179
+ function isOhosArktsProject(projectRoot, languages) {
2180
+ if (languages?.includes('arkts'))
2181
+ return true;
2182
+ if (findBuildProfileFiles(projectRoot).length > 0)
2183
+ return true;
2184
+ return hasEtsUnder(projectRoot, 0);
2185
+ }
2186
+ function hasEtsUnder(dir, depth) {
2187
+ if (depth > 4)
2188
+ return false;
2189
+ let entries;
2190
+ try {
2191
+ entries = fs.readdirSync(dir, { withFileTypes: true });
2192
+ }
2193
+ catch {
2194
+ return false;
2195
+ }
2196
+ for (const entry of entries) {
2197
+ const full = path.join(dir, entry.name);
2198
+ if (entry.isFile() && entry.name.endsWith('.ets'))
2199
+ return true;
2200
+ if (entry.isDirectory()) {
2201
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.homegraph')
2202
+ continue;
2203
+ if (hasEtsUnder(full, depth + 1))
2204
+ return true;
2205
+ }
2206
+ }
2207
+ return false;
2208
+ }
2209
+ /** Install npm package if local db is missing; non-throwing on failure. */
2210
+ function ensureOhosApiDb(version) {
2211
+ const dbPath = ohosApiDbInstallPath(version);
2212
+ if (fs.existsSync(dbPath)) {
2213
+ return {
2214
+ version,
2215
+ dbPath,
2216
+ packageName: ohosApiDbPackageName(version),
2217
+ installed: false,
1062
2218
  };
1063
2219
  }
1064
- const adapter = new ArkTSAdapter(rootDir, scannedFiles);
1065
- const index = adapter.build(scene);
1066
- index.errors.push(...errors);
1067
- return index;
2220
+ const packageName = ohosApiDbPackageName(version);
2221
+ const installDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hg-ohos-npm-'));
2222
+ try {
2223
+ (0, child_process_1.execFileSync)('npm', ['install', '--no-save', packageName], {
2224
+ cwd: installDir,
2225
+ stdio: 'pipe',
2226
+ timeout: 180_000,
2227
+ env: { ...process.env, npm_config_loglevel: 'error' },
2228
+ });
2229
+ }
2230
+ catch (err) {
2231
+ const msg = err instanceof Error ? err.message : String(err);
2232
+ return {
2233
+ code: 'ohos_api_install_failed',
2234
+ message: `Could not fetch ${packageName} (${msg}). ` +
2235
+ 'Explore will use project code only until the matching API db is available.',
2236
+ };
2237
+ }
2238
+ finally {
2239
+ fs.rmSync(installDir, { recursive: true, force: true });
2240
+ }
2241
+ if (!fs.existsSync(dbPath)) {
2242
+ return {
2243
+ code: 'ohos_api_db_missing',
2244
+ message: `${packageName} was fetched but ${ohosApiDbFilename(version)} is missing under ~/.homegraph/api/. ` +
2245
+ 'Explore will use project code only.',
2246
+ };
2247
+ }
2248
+ return { version, dbPath, packageName, installed: true };
2249
+ }
2250
+ /** Detect version, ensure db, persist metadata, ATTACH — never throws. */
2251
+ function bindOhosApiDbForProject(projectRoot, queries, languages) {
2252
+ if (!isOhosArktsProject(projectRoot, languages))
2253
+ return null;
2254
+ const version = detectOhosCompileSdkVersion(projectRoot);
2255
+ if (!version) {
2256
+ return {
2257
+ code: 'ohos_api_version_unknown',
2258
+ message: 'HarmonyOS project detected but compileSdkVersion not found in build-profile.json5. ' +
2259
+ 'SDK API lookup disabled; project indexing continues normally.',
2260
+ };
2261
+ }
2262
+ const ensured = ensureOhosApiDb(version);
2263
+ if ('code' in ensured)
2264
+ return ensured;
2265
+ try {
2266
+ queries.attachOhosApiDb(ensured.dbPath);
2267
+ queries.setMetadata(exports.OHOS_API_VERSION_META, ensured.version);
2268
+ queries.setMetadata(exports.OHOS_API_DB_PATH_META, ensured.dbPath);
2269
+ }
2270
+ catch (err) {
2271
+ const msg = err instanceof Error ? err.message : String(err);
2272
+ return {
2273
+ code: 'ohos_api_db_missing',
2274
+ message: `Failed to attach OHOS API db at ${ensured.dbPath}: ${msg}`,
2275
+ };
2276
+ }
2277
+ return ensured;
2278
+ }
2279
+ /** Re-ATTACH from project metadata after reopen / new QueryBuilder. */
2280
+ function restoreOhosApiDbAttach(queries) {
2281
+ const dbPath = queries.getMetadata(exports.OHOS_API_DB_PATH_META);
2282
+ const version = queries.getMetadata(exports.OHOS_API_VERSION_META);
2283
+ if (!dbPath || !version || !fs.existsSync(dbPath))
2284
+ return null;
2285
+ try {
2286
+ queries.attachOhosApiDb(dbPath);
2287
+ return {
2288
+ version,
2289
+ dbPath,
2290
+ packageName: ohosApiDbPackageName(version),
2291
+ installed: false,
2292
+ };
2293
+ }
2294
+ catch {
2295
+ return null;
2296
+ }
1068
2297
  }
1069
2298
  //# sourceMappingURL=arkts.js.map