@fraziym/axoniz 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (512) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -0
  3. package/dist/agents/definition.d.ts +15 -0
  4. package/dist/agents/definition.d.ts.map +1 -0
  5. package/dist/agents/definition.js +41 -0
  6. package/dist/agents/definition.js.map +1 -0
  7. package/dist/agents/index.d.ts +12 -0
  8. package/dist/agents/index.d.ts.map +1 -0
  9. package/dist/agents/index.js +11 -0
  10. package/dist/agents/index.js.map +1 -0
  11. package/dist/agents/registry.d.ts +17 -0
  12. package/dist/agents/registry.d.ts.map +1 -0
  13. package/dist/agents/registry.js +23 -0
  14. package/dist/agents/registry.js.map +1 -0
  15. package/dist/agents/specialized.d.ts +31 -0
  16. package/dist/agents/specialized.d.ts.map +1 -0
  17. package/dist/agents/specialized.js +75 -0
  18. package/dist/agents/specialized.js.map +1 -0
  19. package/dist/awareness/index.d.ts +14 -0
  20. package/dist/awareness/index.d.ts.map +1 -0
  21. package/dist/awareness/index.js +22 -0
  22. package/dist/awareness/index.js.map +1 -0
  23. package/dist/awareness/service.d.ts +180 -0
  24. package/dist/awareness/service.d.ts.map +1 -0
  25. package/dist/awareness/service.js +789 -0
  26. package/dist/awareness/service.js.map +1 -0
  27. package/dist/cli/entry.d.ts +13 -0
  28. package/dist/cli/entry.d.ts.map +1 -0
  29. package/dist/cli/entry.js +35 -0
  30. package/dist/cli/entry.js.map +1 -0
  31. package/dist/comms/telegram.d.ts +41 -0
  32. package/dist/comms/telegram.d.ts.map +1 -0
  33. package/dist/comms/telegram.js +332 -0
  34. package/dist/comms/telegram.js.map +1 -0
  35. package/dist/core/agent.d.ts +252 -0
  36. package/dist/core/agent.d.ts.map +1 -0
  37. package/dist/core/agent.js +1399 -0
  38. package/dist/core/agent.js.map +1 -0
  39. package/dist/core/auth.d.ts +23 -0
  40. package/dist/core/auth.d.ts.map +1 -0
  41. package/dist/core/auth.js +113 -0
  42. package/dist/core/auth.js.map +1 -0
  43. package/dist/core/authority.d.ts +118 -0
  44. package/dist/core/authority.d.ts.map +1 -0
  45. package/dist/core/authority.js +402 -0
  46. package/dist/core/authority.js.map +1 -0
  47. package/dist/core/backend/async_queue.d.ts +17 -0
  48. package/dist/core/backend/async_queue.d.ts.map +1 -0
  49. package/dist/core/backend/async_queue.js +66 -0
  50. package/dist/core/backend/async_queue.js.map +1 -0
  51. package/dist/core/backend/index.d.ts +24 -0
  52. package/dist/core/backend/index.d.ts.map +1 -0
  53. package/dist/core/backend/index.js +128 -0
  54. package/dist/core/backend/index.js.map +1 -0
  55. package/dist/core/backend/llama_server.d.ts +39 -0
  56. package/dist/core/backend/llama_server.d.ts.map +1 -0
  57. package/dist/core/backend/llama_server.js +182 -0
  58. package/dist/core/backend/llama_server.js.map +1 -0
  59. package/dist/core/backend/llamacpp.d.ts +40 -0
  60. package/dist/core/backend/llamacpp.d.ts.map +1 -0
  61. package/dist/core/backend/llamacpp.js +200 -0
  62. package/dist/core/backend/llamacpp.js.map +1 -0
  63. package/dist/core/backend/lmstudio.d.ts +53 -0
  64. package/dist/core/backend/lmstudio.d.ts.map +1 -0
  65. package/dist/core/backend/lmstudio.js +274 -0
  66. package/dist/core/backend/lmstudio.js.map +1 -0
  67. package/dist/core/backend/ollama.d.ts +25 -0
  68. package/dist/core/backend/ollama.d.ts.map +1 -0
  69. package/dist/core/backend/ollama.js +86 -0
  70. package/dist/core/backend/ollama.js.map +1 -0
  71. package/dist/core/backend/openai.d.ts +27 -0
  72. package/dist/core/backend/openai.d.ts.map +1 -0
  73. package/dist/core/backend/openai.js +84 -0
  74. package/dist/core/backend/openai.js.map +1 -0
  75. package/dist/core/backend/types.d.ts +73 -0
  76. package/dist/core/backend/types.d.ts.map +1 -0
  77. package/dist/core/backend/types.js +137 -0
  78. package/dist/core/backend/types.js.map +1 -0
  79. package/dist/core/chat_store.d.ts +77 -0
  80. package/dist/core/chat_store.d.ts.map +1 -0
  81. package/dist/core/chat_store.js +332 -0
  82. package/dist/core/chat_store.js.map +1 -0
  83. package/dist/core/cli.d.ts +82 -0
  84. package/dist/core/cli.d.ts.map +1 -0
  85. package/dist/core/cli.js +602 -0
  86. package/dist/core/cli.js.map +1 -0
  87. package/dist/core/config.d.ts +127 -0
  88. package/dist/core/config.d.ts.map +1 -0
  89. package/dist/core/config.js +295 -0
  90. package/dist/core/config.js.map +1 -0
  91. package/dist/core/debug.d.ts +8 -0
  92. package/dist/core/debug.d.ts.map +1 -0
  93. package/dist/core/debug.js +8 -0
  94. package/dist/core/debug.js.map +1 -0
  95. package/dist/core/downloader.d.ts +31 -0
  96. package/dist/core/downloader.d.ts.map +1 -0
  97. package/dist/core/downloader.js +180 -0
  98. package/dist/core/downloader.js.map +1 -0
  99. package/dist/core/errors.d.ts +80 -0
  100. package/dist/core/errors.d.ts.map +1 -0
  101. package/dist/core/errors.js +134 -0
  102. package/dist/core/errors.js.map +1 -0
  103. package/dist/core/extras.d.ts +160 -0
  104. package/dist/core/extras.d.ts.map +1 -0
  105. package/dist/core/extras.js +553 -0
  106. package/dist/core/extras.js.map +1 -0
  107. package/dist/core/health.d.ts +27 -0
  108. package/dist/core/health.d.ts.map +1 -0
  109. package/dist/core/health.js +96 -0
  110. package/dist/core/health.js.map +1 -0
  111. package/dist/core/history.d.ts +50 -0
  112. package/dist/core/history.d.ts.map +1 -0
  113. package/dist/core/history.js +276 -0
  114. package/dist/core/history.js.map +1 -0
  115. package/dist/core/index.d.ts +6 -0
  116. package/dist/core/index.d.ts.map +1 -0
  117. package/dist/core/index.js +6 -0
  118. package/dist/core/index.js.map +1 -0
  119. package/dist/core/intelligence/ast_index.d.ts +255 -0
  120. package/dist/core/intelligence/ast_index.d.ts.map +1 -0
  121. package/dist/core/intelligence/ast_index.js +1369 -0
  122. package/dist/core/intelligence/ast_index.js.map +1 -0
  123. package/dist/core/intelligence/confidence.d.ts +113 -0
  124. package/dist/core/intelligence/confidence.d.ts.map +1 -0
  125. package/dist/core/intelligence/confidence.js +298 -0
  126. package/dist/core/intelligence/confidence.js.map +1 -0
  127. package/dist/core/intelligence/context_compressor.d.ts +80 -0
  128. package/dist/core/intelligence/context_compressor.d.ts.map +1 -0
  129. package/dist/core/intelligence/context_compressor.js +245 -0
  130. package/dist/core/intelligence/context_compressor.js.map +1 -0
  131. package/dist/core/intelligence/daemon.d.ts +247 -0
  132. package/dist/core/intelligence/daemon.d.ts.map +1 -0
  133. package/dist/core/intelligence/daemon.js +842 -0
  134. package/dist/core/intelligence/daemon.js.map +1 -0
  135. package/dist/core/intelligence/index.d.ts +60 -0
  136. package/dist/core/intelligence/index.d.ts.map +1 -0
  137. package/dist/core/intelligence/index.js +101 -0
  138. package/dist/core/intelligence/index.js.map +1 -0
  139. package/dist/core/intelligence/predictor.d.ts +246 -0
  140. package/dist/core/intelligence/predictor.d.ts.map +1 -0
  141. package/dist/core/intelligence/predictor.js +590 -0
  142. package/dist/core/intelligence/predictor.js.map +1 -0
  143. package/dist/core/intelligence/reflex.d.ts +84 -0
  144. package/dist/core/intelligence/reflex.d.ts.map +1 -0
  145. package/dist/core/intelligence/reflex.js +344 -0
  146. package/dist/core/intelligence/reflex.js.map +1 -0
  147. package/dist/core/intelligence/self_correction.d.ts +121 -0
  148. package/dist/core/intelligence/self_correction.d.ts.map +1 -0
  149. package/dist/core/intelligence/self_correction.js +327 -0
  150. package/dist/core/intelligence/self_correction.js.map +1 -0
  151. package/dist/core/intelligence/skill_distiller.d.ts +100 -0
  152. package/dist/core/intelligence/skill_distiller.d.ts.map +1 -0
  153. package/dist/core/intelligence/skill_distiller.js +246 -0
  154. package/dist/core/intelligence/skill_distiller.js.map +1 -0
  155. package/dist/core/intelligence/swarm.d.ts +330 -0
  156. package/dist/core/intelligence/swarm.d.ts.map +1 -0
  157. package/dist/core/intelligence/swarm.js +1064 -0
  158. package/dist/core/intelligence/swarm.js.map +1 -0
  159. package/dist/core/intelligence/trajectory.d.ts +107 -0
  160. package/dist/core/intelligence/trajectory.d.ts.map +1 -0
  161. package/dist/core/intelligence/trajectory.js +330 -0
  162. package/dist/core/intelligence/trajectory.js.map +1 -0
  163. package/dist/core/logger.d.ts +111 -0
  164. package/dist/core/logger.d.ts.map +1 -0
  165. package/dist/core/logger.js +640 -0
  166. package/dist/core/logger.js.map +1 -0
  167. package/dist/core/loop.d.ts +123 -0
  168. package/dist/core/loop.d.ts.map +1 -0
  169. package/dist/core/loop.js +423 -0
  170. package/dist/core/loop.js.map +1 -0
  171. package/dist/core/memory.d.ts +81 -0
  172. package/dist/core/memory.d.ts.map +1 -0
  173. package/dist/core/memory.js +328 -0
  174. package/dist/core/memory.js.map +1 -0
  175. package/dist/core/metrics.d.ts +29 -0
  176. package/dist/core/metrics.d.ts.map +1 -0
  177. package/dist/core/metrics.js +109 -0
  178. package/dist/core/metrics.js.map +1 -0
  179. package/dist/core/models.d.ts +51 -0
  180. package/dist/core/models.d.ts.map +1 -0
  181. package/dist/core/models.js +146 -0
  182. package/dist/core/models.js.map +1 -0
  183. package/dist/core/optimizer.d.ts +34 -0
  184. package/dist/core/optimizer.d.ts.map +1 -0
  185. package/dist/core/optimizer.js +131 -0
  186. package/dist/core/optimizer.js.map +1 -0
  187. package/dist/core/persona.d.ts +35 -0
  188. package/dist/core/persona.d.ts.map +1 -0
  189. package/dist/core/persona.js +126 -0
  190. package/dist/core/persona.js.map +1 -0
  191. package/dist/core/rate_limit.d.ts +23 -0
  192. package/dist/core/rate_limit.d.ts.map +1 -0
  193. package/dist/core/rate_limit.js +62 -0
  194. package/dist/core/rate_limit.js.map +1 -0
  195. package/dist/core/runner.d.ts +63 -0
  196. package/dist/core/runner.d.ts.map +1 -0
  197. package/dist/core/runner.js +671 -0
  198. package/dist/core/runner.js.map +1 -0
  199. package/dist/core/stream_parser.d.ts +43 -0
  200. package/dist/core/stream_parser.d.ts.map +1 -0
  201. package/dist/core/stream_parser.js +140 -0
  202. package/dist/core/stream_parser.js.map +1 -0
  203. package/dist/core/tool_schemas.d.ts +26 -0
  204. package/dist/core/tool_schemas.d.ts.map +1 -0
  205. package/dist/core/tool_schemas.js +124 -0
  206. package/dist/core/tool_schemas.js.map +1 -0
  207. package/dist/core/which.d.ts +2 -0
  208. package/dist/core/which.d.ts.map +1 -0
  209. package/dist/core/which.js +35 -0
  210. package/dist/core/which.js.map +1 -0
  211. package/dist/goals/index.d.ts +9 -0
  212. package/dist/goals/index.d.ts.map +1 -0
  213. package/dist/goals/index.js +17 -0
  214. package/dist/goals/index.js.map +1 -0
  215. package/dist/goals/service.d.ts +115 -0
  216. package/dist/goals/service.d.ts.map +1 -0
  217. package/dist/goals/service.js +415 -0
  218. package/dist/goals/service.js.map +1 -0
  219. package/dist/goals/types.d.ts +47 -0
  220. package/dist/goals/types.d.ts.map +1 -0
  221. package/dist/goals/types.js +66 -0
  222. package/dist/goals/types.js.map +1 -0
  223. package/dist/index.d.ts +22 -0
  224. package/dist/index.d.ts.map +1 -0
  225. package/dist/index.js +22 -0
  226. package/dist/index.js.map +1 -0
  227. package/dist/integrations/autonomous_startup.d.ts +51 -0
  228. package/dist/integrations/autonomous_startup.d.ts.map +1 -0
  229. package/dist/integrations/autonomous_startup.js +419 -0
  230. package/dist/integrations/autonomous_startup.js.map +1 -0
  231. package/dist/integrations/goose.d.ts +105 -0
  232. package/dist/integrations/goose.d.ts.map +1 -0
  233. package/dist/integrations/goose.js +408 -0
  234. package/dist/integrations/goose.js.map +1 -0
  235. package/dist/integrations/index.d.ts +21 -0
  236. package/dist/integrations/index.d.ts.map +1 -0
  237. package/dist/integrations/index.js +17 -0
  238. package/dist/integrations/index.js.map +1 -0
  239. package/dist/integrations/mcp.d.ts +73 -0
  240. package/dist/integrations/mcp.d.ts.map +1 -0
  241. package/dist/integrations/mcp.js +307 -0
  242. package/dist/integrations/mcp.js.map +1 -0
  243. package/dist/integrations/mempalace.d.ts +18 -0
  244. package/dist/integrations/mempalace.d.ts.map +1 -0
  245. package/dist/integrations/mempalace.js +25 -0
  246. package/dist/integrations/mempalace.js.map +1 -0
  247. package/dist/integrations/multi_agent.d.ts +82 -0
  248. package/dist/integrations/multi_agent.d.ts.map +1 -0
  249. package/dist/integrations/multi_agent.js +280 -0
  250. package/dist/integrations/multi_agent.js.map +1 -0
  251. package/dist/integrations/unified_memory.d.ts +415 -0
  252. package/dist/integrations/unified_memory.d.ts.map +1 -0
  253. package/dist/integrations/unified_memory.js +1489 -0
  254. package/dist/integrations/unified_memory.js.map +1 -0
  255. package/dist/roles/beru.yaml +48 -0
  256. package/dist/sidecar/client.d.ts +63 -0
  257. package/dist/sidecar/client.d.ts.map +1 -0
  258. package/dist/sidecar/client.js +222 -0
  259. package/dist/sidecar/client.js.map +1 -0
  260. package/dist/sidecar/index.d.ts +7 -0
  261. package/dist/sidecar/index.d.ts.map +1 -0
  262. package/dist/sidecar/index.js +6 -0
  263. package/dist/sidecar/index.js.map +1 -0
  264. package/dist/startup.d.ts +22 -0
  265. package/dist/startup.d.ts.map +1 -0
  266. package/dist/startup.js +194 -0
  267. package/dist/startup.js.map +1 -0
  268. package/dist/tools/_internal.d.ts +90 -0
  269. package/dist/tools/_internal.d.ts.map +1 -0
  270. package/dist/tools/_internal.js +375 -0
  271. package/dist/tools/_internal.js.map +1 -0
  272. package/dist/tools/_smoke.d.ts +2 -0
  273. package/dist/tools/_smoke.d.ts.map +1 -0
  274. package/dist/tools/_smoke.js +203 -0
  275. package/dist/tools/_smoke.js.map +1 -0
  276. package/dist/tools/axodex_tools.d.ts +51 -0
  277. package/dist/tools/axodex_tools.d.ts.map +1 -0
  278. package/dist/tools/axodex_tools.js +181 -0
  279. package/dist/tools/axodex_tools.js.map +1 -0
  280. package/dist/tools/code_tools.d.ts +33 -0
  281. package/dist/tools/code_tools.d.ts.map +1 -0
  282. package/dist/tools/code_tools.js +191 -0
  283. package/dist/tools/code_tools.js.map +1 -0
  284. package/dist/tools/computer_tools.d.ts +59 -0
  285. package/dist/tools/computer_tools.d.ts.map +1 -0
  286. package/dist/tools/computer_tools.js +348 -0
  287. package/dist/tools/computer_tools.js.map +1 -0
  288. package/dist/tools/file_tools.d.ts +51 -0
  289. package/dist/tools/file_tools.d.ts.map +1 -0
  290. package/dist/tools/file_tools.js +424 -0
  291. package/dist/tools/file_tools.js.map +1 -0
  292. package/dist/tools/index.d.ts +13 -0
  293. package/dist/tools/index.d.ts.map +1 -0
  294. package/dist/tools/index.js +13 -0
  295. package/dist/tools/index.js.map +1 -0
  296. package/dist/tools/shell_tools.d.ts +39 -0
  297. package/dist/tools/shell_tools.d.ts.map +1 -0
  298. package/dist/tools/shell_tools.js +163 -0
  299. package/dist/tools/shell_tools.js.map +1 -0
  300. package/dist/tools/web_tools.d.ts +31 -0
  301. package/dist/tools/web_tools.d.ts.map +1 -0
  302. package/dist/tools/web_tools.js +117 -0
  303. package/dist/tools/web_tools.js.map +1 -0
  304. package/dist/voice/index.d.ts +41 -0
  305. package/dist/voice/index.d.ts.map +1 -0
  306. package/dist/voice/index.js +58 -0
  307. package/dist/voice/index.js.map +1 -0
  308. package/dist/voice/light_daemon.d.ts +197 -0
  309. package/dist/voice/light_daemon.d.ts.map +1 -0
  310. package/dist/voice/light_daemon.js +746 -0
  311. package/dist/voice/light_daemon.js.map +1 -0
  312. package/dist/voice/setup.d.ts +63 -0
  313. package/dist/voice/setup.d.ts.map +1 -0
  314. package/dist/voice/setup.js +443 -0
  315. package/dist/voice/setup.js.map +1 -0
  316. package/dist/voice/stt.d.ts +148 -0
  317. package/dist/voice/stt.d.ts.map +1 -0
  318. package/dist/voice/stt.js +361 -0
  319. package/dist/voice/stt.js.map +1 -0
  320. package/dist/voice/tts.d.ts +168 -0
  321. package/dist/voice/tts.d.ts.map +1 -0
  322. package/dist/voice/tts.js +698 -0
  323. package/dist/voice/tts.js.map +1 -0
  324. package/dist/voice/voice_loop.d.ts +101 -0
  325. package/dist/voice/voice_loop.d.ts.map +1 -0
  326. package/dist/voice/voice_loop.js +463 -0
  327. package/dist/voice/voice_loop.js.map +1 -0
  328. package/dist/voice/wake_word.d.ts +153 -0
  329. package/dist/voice/wake_word.d.ts.map +1 -0
  330. package/dist/voice/wake_word.js +458 -0
  331. package/dist/voice/wake_word.js.map +1 -0
  332. package/dist/voice/wav.d.ts +99 -0
  333. package/dist/voice/wav.d.ts.map +1 -0
  334. package/dist/voice/wav.js +306 -0
  335. package/dist/voice/wav.js.map +1 -0
  336. package/dist/web/broker.d.ts +33 -0
  337. package/dist/web/broker.d.ts.map +1 -0
  338. package/dist/web/broker.js +58 -0
  339. package/dist/web/broker.js.map +1 -0
  340. package/dist/web/open_browser.d.ts +2 -0
  341. package/dist/web/open_browser.d.ts.map +1 -0
  342. package/dist/web/open_browser.js +42 -0
  343. package/dist/web/open_browser.js.map +1 -0
  344. package/dist/web/server.d.ts +54 -0
  345. package/dist/web/server.d.ts.map +1 -0
  346. package/dist/web/server.js +831 -0
  347. package/dist/web/server.js.map +1 -0
  348. package/dist/web/static/app.js +4121 -0
  349. package/dist/web/static/index.html +2281 -0
  350. package/dist/web/static/js/MODULE_SUMMARY.md +124 -0
  351. package/dist/web/static/js/a11y.js +165 -0
  352. package/dist/web/static/js/admin.js +2145 -0
  353. package/dist/web/static/js/assistant.js +475 -0
  354. package/dist/web/static/js/calendar/reminders.js +114 -0
  355. package/dist/web/static/js/calendar/utils.js +166 -0
  356. package/dist/web/static/js/calendar.js +3348 -0
  357. package/dist/web/static/js/censor.js +356 -0
  358. package/dist/web/static/js/chat.js +4546 -0
  359. package/dist/web/static/js/chatRenderer.js +2294 -0
  360. package/dist/web/static/js/chatStream.js +276 -0
  361. package/dist/web/static/js/codeRunner.js +398 -0
  362. package/dist/web/static/js/color/hex.js +14 -0
  363. package/dist/web/static/js/colorPicker.js +453 -0
  364. package/dist/web/static/js/compare/icons.js +77 -0
  365. package/dist/web/static/js/compare/index.js +1482 -0
  366. package/dist/web/static/js/compare/models.js +104 -0
  367. package/dist/web/static/js/compare/panes.js +817 -0
  368. package/dist/web/static/js/compare/probe.js +78 -0
  369. package/dist/web/static/js/compare/scoreboard.js +223 -0
  370. package/dist/web/static/js/compare/selector.js +1335 -0
  371. package/dist/web/static/js/compare/state.js +58 -0
  372. package/dist/web/static/js/compare/stream.js +695 -0
  373. package/dist/web/static/js/compare/vote.js +254 -0
  374. package/dist/web/static/js/cookbook-diagnosis.js +694 -0
  375. package/dist/web/static/js/cookbook-hwfit.js +1888 -0
  376. package/dist/web/static/js/cookbook.js +2093 -0
  377. package/dist/web/static/js/cookbookDownload.js +633 -0
  378. package/dist/web/static/js/cookbookProgressSignal.js +29 -0
  379. package/dist/web/static/js/cookbookRunning.js +3506 -0
  380. package/dist/web/static/js/cookbookServe.js +2128 -0
  381. package/dist/web/static/js/document.js +9731 -0
  382. package/dist/web/static/js/documentLibrary.js +3376 -0
  383. package/dist/web/static/js/dragSort.js +265 -0
  384. package/dist/web/static/js/editor/ai-inpaint.js +374 -0
  385. package/dist/web/static/js/editor/ai-models.js +273 -0
  386. package/dist/web/static/js/editor/ai-rembg.js +230 -0
  387. package/dist/web/static/js/editor/ai-tool-runner.js +147 -0
  388. package/dist/web/static/js/editor/ai-tools-misc.js +216 -0
  389. package/dist/web/static/js/editor/build/controls.js +366 -0
  390. package/dist/web/static/js/editor/build/popups.js +112 -0
  391. package/dist/web/static/js/editor/build/right-panel.js +200 -0
  392. package/dist/web/static/js/editor/build/toolbar.js +73 -0
  393. package/dist/web/static/js/editor/build/topbar.js +131 -0
  394. package/dist/web/static/js/editor/build/transform-popup.js +109 -0
  395. package/dist/web/static/js/editor/canvas-coords.js +21 -0
  396. package/dist/web/static/js/editor/canvas-events.js +197 -0
  397. package/dist/web/static/js/editor/canvas-transforms.js +132 -0
  398. package/dist/web/static/js/editor/checkerboard.js +24 -0
  399. package/dist/web/static/js/editor/clipboard-and-drop.js +133 -0
  400. package/dist/web/static/js/editor/composite-helpers.js +83 -0
  401. package/dist/web/static/js/editor/filters/blur.js +118 -0
  402. package/dist/web/static/js/editor/filters/edge-feather.js +70 -0
  403. package/dist/web/static/js/editor/fx/adj-popup.js +677 -0
  404. package/dist/web/static/js/editor/fx/filter-string.js +38 -0
  405. package/dist/web/static/js/editor/fx/histogram.js +67 -0
  406. package/dist/web/static/js/editor/fx/pixel-pass.js +249 -0
  407. package/dist/web/static/js/editor/harmonize-masks.js +116 -0
  408. package/dist/web/static/js/editor/history-panel.js +176 -0
  409. package/dist/web/static/js/editor/keyboard-shortcuts.js +271 -0
  410. package/dist/web/static/js/editor/layer-helpers.js +131 -0
  411. package/dist/web/static/js/editor/layer-panel.js +600 -0
  412. package/dist/web/static/js/editor/mask-utils.js +91 -0
  413. package/dist/web/static/js/editor/shortcuts-popover.js +149 -0
  414. package/dist/web/static/js/editor/slider-ux.js +191 -0
  415. package/dist/web/static/js/editor/snap.js +107 -0
  416. package/dist/web/static/js/editor/state.js +257 -0
  417. package/dist/web/static/js/editor/stroke-pipeline.js +162 -0
  418. package/dist/web/static/js/editor/stroke-tool-sliders.js +64 -0
  419. package/dist/web/static/js/editor/tools/clone.js +81 -0
  420. package/dist/web/static/js/editor/tools/crop.js +137 -0
  421. package/dist/web/static/js/editor/tools/flood-fill.js +72 -0
  422. package/dist/web/static/js/editor/tools/lasso-mask.js +171 -0
  423. package/dist/web/static/js/editor/tools/lasso.js +65 -0
  424. package/dist/web/static/js/editor/tools/move.js +79 -0
  425. package/dist/web/static/js/editor/tools/stroke.js +123 -0
  426. package/dist/web/static/js/editor/tools/transform-drag.js +174 -0
  427. package/dist/web/static/js/editor/tools/transform-handles.js +271 -0
  428. package/dist/web/static/js/editor/tools/transform-session.js +381 -0
  429. package/dist/web/static/js/editor/tools/wand.js +46 -0
  430. package/dist/web/static/js/editor/wire-import.js +148 -0
  431. package/dist/web/static/js/editor/wire-inpaint-controls.js +164 -0
  432. package/dist/web/static/js/editor/wire-merge-buttons.js +103 -0
  433. package/dist/web/static/js/editor/wire-selection-controls.js +170 -0
  434. package/dist/web/static/js/editor/wire-topbar-menus.js +174 -0
  435. package/dist/web/static/js/editor/wire-topbar-overflow.js +49 -0
  436. package/dist/web/static/js/editor/wire-topbar.js +188 -0
  437. package/dist/web/static/js/emailInbox.js +1245 -0
  438. package/dist/web/static/js/emailLibrary/replyRecipients.js +27 -0
  439. package/dist/web/static/js/emailLibrary/signatureFold.js +339 -0
  440. package/dist/web/static/js/emailLibrary/state.js +34 -0
  441. package/dist/web/static/js/emailLibrary/utils.js +202 -0
  442. package/dist/web/static/js/emailLibrary.js +5217 -0
  443. package/dist/web/static/js/emojiPicker.js +311 -0
  444. package/dist/web/static/js/escMenuStack.js +102 -0
  445. package/dist/web/static/js/fileHandler.js +295 -0
  446. package/dist/web/static/js/gallery.js +2835 -0
  447. package/dist/web/static/js/galleryEditor.js +3798 -0
  448. package/dist/web/static/js/group.js +955 -0
  449. package/dist/web/static/js/init.js +405 -0
  450. package/dist/web/static/js/keyboard-shortcuts.js +292 -0
  451. package/dist/web/static/js/langIcons.js +187 -0
  452. package/dist/web/static/js/markdown/tableRow.js +19 -0
  453. package/dist/web/static/js/markdown.js +806 -0
  454. package/dist/web/static/js/memory.js +1418 -0
  455. package/dist/web/static/js/modalManager.js +1552 -0
  456. package/dist/web/static/js/modalSnap.js +782 -0
  457. package/dist/web/static/js/model/matchKey.js +19 -0
  458. package/dist/web/static/js/modelPicker.js +695 -0
  459. package/dist/web/static/js/modelSort.js +33 -0
  460. package/dist/web/static/js/models.js +642 -0
  461. package/dist/web/static/js/notes.js +5054 -0
  462. package/dist/web/static/js/package.json +1 -0
  463. package/dist/web/static/js/platform.js +47 -0
  464. package/dist/web/static/js/presets.js +1110 -0
  465. package/dist/web/static/js/providers.js +93 -0
  466. package/dist/web/static/js/rag.js +177 -0
  467. package/dist/web/static/js/research/jobs.js +335 -0
  468. package/dist/web/static/js/research/panel.js +1233 -0
  469. package/dist/web/static/js/researchSynapse.js +225 -0
  470. package/dist/web/static/js/search-chat.js +201 -0
  471. package/dist/web/static/js/search.js +52 -0
  472. package/dist/web/static/js/section-management.js +260 -0
  473. package/dist/web/static/js/sessions.js +3108 -0
  474. package/dist/web/static/js/settings.js +4991 -0
  475. package/dist/web/static/js/sidebar-layout.js +573 -0
  476. package/dist/web/static/js/signature.js +504 -0
  477. package/dist/web/static/js/skills.js +1908 -0
  478. package/dist/web/static/js/slashAutocomplete.js +267 -0
  479. package/dist/web/static/js/slashCommands.js +6099 -0
  480. package/dist/web/static/js/spinner.js +406 -0
  481. package/dist/web/static/js/storage.js +123 -0
  482. package/dist/web/static/js/tasks.js +2699 -0
  483. package/dist/web/static/js/theme.js +2086 -0
  484. package/dist/web/static/js/tileManager.js +386 -0
  485. package/dist/web/static/js/tourAutoplay.js +133 -0
  486. package/dist/web/static/js/tourHints.js +179 -0
  487. package/dist/web/static/js/tts-ai.js +521 -0
  488. package/dist/web/static/js/ui.js +1288 -0
  489. package/dist/web/static/js/util/ordinal.js +13 -0
  490. package/dist/web/static/js/voiceRecorder.js +283 -0
  491. package/dist/web/static/js/windowDrag.js +326 -0
  492. package/dist/web/static/js/windowResize.js +233 -0
  493. package/dist/web/static/landing.html +824 -0
  494. package/dist/web/static/lib/docx.umd.min.js +20116 -0
  495. package/dist/web/static/lib/highlight.min.js +1213 -0
  496. package/dist/web/static/lib/html2pdf.bundle.min.js +3 -0
  497. package/dist/web/static/lib/mammoth.browser.min.js +21 -0
  498. package/dist/web/static/lib/qrcode.min.js +8 -0
  499. package/dist/web/static/lib/xlsx.full.min.js +24 -0
  500. package/dist/web/static/login.html +582 -0
  501. package/dist/web/static/manifest.json +15 -0
  502. package/dist/web/static/style.css +35733 -0
  503. package/dist/web/static/sw.js +144 -0
  504. package/dist/workflows/engine.d.ts +162 -0
  505. package/dist/workflows/engine.d.ts.map +1 -0
  506. package/dist/workflows/engine.js +625 -0
  507. package/dist/workflows/engine.js.map +1 -0
  508. package/dist/workflows/index.d.ts +8 -0
  509. package/dist/workflows/index.d.ts.map +1 -0
  510. package/dist/workflows/index.js +14 -0
  511. package/dist/workflows/index.js.map +1 -0
  512. package/package.json +112 -0
@@ -0,0 +1,1369 @@
1
+ /**
2
+ * axoniz.core.intelligence.ast_index
3
+ * =====================================
4
+ * Phase 3 — Living Codebase Understanding
5
+ *
6
+ * Cursor and Copilot do text search. They're glorified grep.
7
+ * axoniz builds a real AST index of your entire workspace:
8
+ * - Every class, function, method, variable
9
+ * - Every import and what imports what
10
+ * - Every call site (who calls what)
11
+ * - Symbol cross-references
12
+ * - "What will break if I change X?"
13
+ *
14
+ * Before editing anything, axoniz knows what will break.
15
+ * After editing, it compares semantic meaning, not just text.
16
+ *
17
+ * Storage: SQLite at ~/.axoniz/ast_indexes/ast_<hash>.db (per workspace)
18
+ * Incremental: only re-indexes changed files (mtime-based)
19
+ *
20
+ * ────────────────────────────────────────────────────────────────────────────
21
+ * PORT DESIGN DECISION — how Python's `ast` module was replaced
22
+ * ────────────────────────────────────────────────────────────────────────────
23
+ * Python parsed source with `ast.parse()` and an `ast.NodeVisitor`. Node has no
24
+ * built-in parser and the brief forbids adding a parser dependency
25
+ * (`typescript` is a devDependency and must not be imported from `src/`), so
26
+ * this module ships a **heuristic symbol/relationship extractor** that produces
27
+ * the *same output shape*: the same `symbols` / `imports` / `calls` tables, the
28
+ * same `Symbol` / `CallSite` / `ImpactAnalysis` objects and the same query
29
+ * results.
30
+ *
31
+ * • Python files use an indentation-driven scanner (`class` / `def` / `async
32
+ * def` / `import` / `from ... import` / module- and class-level
33
+ * assignments / dotted call chains).
34
+ * • TypeScript/JavaScript files use a brace-driven scanner (classes,
35
+ * interfaces/type/enum, function declarations, arrow & function
36
+ * expressions, class methods, ESM/CJS imports, call chains). Python's
37
+ * indexer only globbed `.py`; the port indexes TS/JS as well because the
38
+ * ported codebase *is* TypeScript — without it the index would be empty and
39
+ * `impact_analysis` useless. `_find_python_files()` is kept for callers that
40
+ * want the original `.py`-only behaviour.
41
+ *
42
+ * Fidelity that is LOST versus `ast`:
43
+ * 1. No true parse tree. Anything that needs real syntax resolution is
44
+ * approximate: multi-line call argument lists are under-counted
45
+ * (`args_count`), calls hidden inside f-strings/comprehensions may be
46
+ * missed, and decorators are attributed to the decorated definition's line
47
+ * (Python reported the `def` line too, so this matches).
48
+ * 2. `def`/`class` body extents (`line_end`) come from indentation (Python) or
49
+ * brace matching (TS) rather than `node.end_lineno`.
50
+ * 3. Docstrings are detected only when the first statement of a body is a
51
+ * string literal; `inspect.cleandoc` de-denting is approximated.
52
+ * 4. `parent` attribution uses the innermost enclosing class found by
53
+ * indentation/braces; Python used the visitor's `_current_class`.
54
+ * 5. TypeScript `interface` / `type` / `enum` declarations are recorded with
55
+ * kind `"class"` so the `by_kind` histogram keeps exactly Python's kind set
56
+ * (class/function/method/variable).
57
+ * 6. The `symbol_refs` table is created, per-file cleared and indexed but left
58
+ * unpopulated — exactly as in `ast_index.py` (its `_ASTVisitor` never
59
+ * appended to `symbol_refs`).
60
+ *
61
+ * `index_workspace()` stays synchronous so its callers (the `ast_reindex` tool,
62
+ * `_t_reindex`) keep returning a value rather than a Promise. Background use
63
+ * goes through `index_workspace_async()`, which drives the same work in bounded
64
+ * batches and yields to the event loop between them.
65
+ */
66
+ import { createHash } from "node:crypto";
67
+ import fs from "node:fs";
68
+ import path from "node:path";
69
+ import { DatabaseSync } from "node:sqlite";
70
+ import { AXONIZ_HOME } from "../config.js";
71
+ import { debug, warn } from "../debug.js";
72
+ export const AST_INDEX_DIR = path.join(AXONIZ_HOME, "ast_indexes");
73
+ try {
74
+ fs.mkdirSync(AST_INDEX_DIR, { recursive: true });
75
+ }
76
+ catch {
77
+ /* best effort, mirrors makedirs(exist_ok=True) */
78
+ }
79
+ const _SCHEMA = `
80
+ PRAGMA journal_mode=WAL;
81
+ PRAGMA foreign_keys=ON;
82
+
83
+ CREATE TABLE IF NOT EXISTS files (
84
+ path TEXT PRIMARY KEY,
85
+ mtime REAL,
86
+ size INTEGER,
87
+ hash TEXT,
88
+ language TEXT DEFAULT 'python',
89
+ indexed_at REAL
90
+ );
91
+
92
+ CREATE TABLE IF NOT EXISTS symbols (
93
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
94
+ file_path TEXT NOT NULL,
95
+ name TEXT NOT NULL,
96
+ kind TEXT NOT NULL, -- class/function/method/variable/import
97
+ line_start INTEGER,
98
+ line_end INTEGER,
99
+ parent TEXT, -- class name if method
100
+ signature TEXT, -- full def line
101
+ docstring TEXT,
102
+ is_public INTEGER DEFAULT 1
103
+ );
104
+
105
+ CREATE TABLE IF NOT EXISTS imports (
106
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
107
+ file_path TEXT NOT NULL,
108
+ module TEXT NOT NULL,
109
+ names TEXT, -- JSON list of imported names
110
+ alias TEXT,
111
+ line INTEGER,
112
+ is_from INTEGER DEFAULT 0
113
+ );
114
+
115
+ CREATE TABLE IF NOT EXISTS calls (
116
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
117
+ file_path TEXT NOT NULL,
118
+ caller TEXT, -- function/method making the call
119
+ callee TEXT NOT NULL, -- function/attribute being called
120
+ line INTEGER,
121
+ args_count INTEGER DEFAULT 0
122
+ );
123
+
124
+ CREATE TABLE IF NOT EXISTS symbol_refs (
125
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
126
+ file_path TEXT NOT NULL,
127
+ symbol_name TEXT NOT NULL,
128
+ line INTEGER,
129
+ context TEXT
130
+ );
131
+
132
+ CREATE INDEX IF NOT EXISTS idx_sym_name ON symbols(name);
133
+ CREATE INDEX IF NOT EXISTS idx_sym_kind ON symbols(kind);
134
+ CREATE INDEX IF NOT EXISTS idx_sym_file ON symbols(file_path);
135
+ CREATE INDEX IF NOT EXISTS idx_imp_module ON imports(module);
136
+ CREATE INDEX IF NOT EXISTS idx_calls_callee ON calls(callee);
137
+ CREATE INDEX IF NOT EXISTS idx_ref_symbol ON symbol_refs(symbol_name);
138
+ `;
139
+ /** Extension → language label written into `files.language`. */
140
+ export const INDEX_EXTENSIONS = {
141
+ ".py": "python",
142
+ ".ts": "typescript",
143
+ ".tsx": "typescript",
144
+ ".js": "javascript",
145
+ ".jsx": "javascript",
146
+ ".mjs": "javascript",
147
+ ".cjs": "javascript",
148
+ };
149
+ const SKIP_DIRS = new Set([
150
+ ".git",
151
+ "__pycache__",
152
+ "node_modules",
153
+ ".egg-info",
154
+ "dist",
155
+ "build",
156
+ ".axoniz",
157
+ "venv",
158
+ "env",
159
+ ".venv",
160
+ ]);
161
+ export class Symbol {
162
+ name;
163
+ kind;
164
+ file_path;
165
+ line;
166
+ signature;
167
+ docstring;
168
+ parent;
169
+ constructor(init, kind, file_path, line, signature = "", docstring = "", parent = "") {
170
+ const o = typeof init === "string"
171
+ ? {
172
+ name: init,
173
+ kind: kind ?? "",
174
+ file_path: file_path ?? "",
175
+ line: line ?? 0,
176
+ signature,
177
+ docstring,
178
+ parent,
179
+ }
180
+ : init;
181
+ this.name = o.name;
182
+ this.kind = o.kind;
183
+ this.file_path = o.file_path;
184
+ this.line = o.line;
185
+ this.signature = o.signature ?? "";
186
+ this.docstring = o.docstring ?? "";
187
+ this.parent = o.parent ?? "";
188
+ }
189
+ get filePath() {
190
+ return this.file_path;
191
+ }
192
+ }
193
+ export class CallSite {
194
+ file_path;
195
+ caller;
196
+ callee;
197
+ line;
198
+ constructor(init, caller, callee, line) {
199
+ const o = typeof init === "string"
200
+ ? { file_path: init, caller: caller ?? "", callee: callee ?? "", line: line ?? 0 }
201
+ : init;
202
+ this.file_path = o.file_path;
203
+ this.caller = o.caller;
204
+ this.callee = o.callee;
205
+ this.line = o.line;
206
+ }
207
+ get filePath() {
208
+ return this.file_path;
209
+ }
210
+ }
211
+ export class ImpactAnalysis {
212
+ symbol;
213
+ direct_calls;
214
+ affected_files;
215
+ risk_level;
216
+ summary;
217
+ constructor(init) {
218
+ this.symbol = init.symbol;
219
+ this.direct_calls = init.direct_calls;
220
+ this.affected_files = init.affected_files;
221
+ this.risk_level = init.risk_level;
222
+ this.summary = init.summary;
223
+ }
224
+ get directCalls() {
225
+ return this.direct_calls;
226
+ }
227
+ get affectedFiles() {
228
+ return this.affected_files;
229
+ }
230
+ get riskLevel() {
231
+ return this.risk_level;
232
+ }
233
+ }
234
+ /** Identifiers that look like calls but are language keywords, not functions. */
235
+ const NOT_CALLS = new Set([
236
+ "if",
237
+ "for",
238
+ "while",
239
+ "switch",
240
+ "catch",
241
+ "return",
242
+ "typeof",
243
+ "await",
244
+ "function",
245
+ "class",
246
+ "import",
247
+ "export",
248
+ "delete",
249
+ "void",
250
+ "in",
251
+ "of",
252
+ "do",
253
+ "else",
254
+ "try",
255
+ "finally",
256
+ "throw",
257
+ "case",
258
+ "default",
259
+ "const",
260
+ "let",
261
+ "var",
262
+ "new",
263
+ "yield",
264
+ "with",
265
+ "elif",
266
+ "except",
267
+ "lambda",
268
+ "and",
269
+ "or",
270
+ "not",
271
+ "is",
272
+ "assert",
273
+ "del",
274
+ "global",
275
+ "nonlocal",
276
+ "def",
277
+ "raise",
278
+ "pass",
279
+ "break",
280
+ "continue",
281
+ "assert",
282
+ ]);
283
+ /**
284
+ * Rough replacement for `len(call_node.args)`: count top-level argument
285
+ * segments, ignoring keyword arguments (`name=value`) and `**kwargs`, which
286
+ * Python's AST stores outside `node.args`.
287
+ */
288
+ function _countArgs(text) {
289
+ const body = text.trim();
290
+ if (!body)
291
+ return 0;
292
+ const segments = [];
293
+ let depth = 0;
294
+ let quote = "";
295
+ let current = "";
296
+ for (let i = 0; i < body.length; i++) {
297
+ const ch = body[i];
298
+ if (quote) {
299
+ current += ch;
300
+ if (ch === quote && body[i - 1] !== "\\")
301
+ quote = "";
302
+ continue;
303
+ }
304
+ if (ch === '"' || ch === "'" || ch === "`") {
305
+ quote = ch;
306
+ current += ch;
307
+ continue;
308
+ }
309
+ if (ch === "(" || ch === "[" || ch === "{")
310
+ depth++;
311
+ if (ch === ")" || ch === "]" || ch === "}")
312
+ depth--;
313
+ if (ch === "," && depth === 0) {
314
+ segments.push(current);
315
+ current = "";
316
+ continue;
317
+ }
318
+ current += ch;
319
+ }
320
+ segments.push(current);
321
+ return segments.filter((s) => {
322
+ const t = s.trim();
323
+ if (!t)
324
+ return false;
325
+ if (t.startsWith("**"))
326
+ return false; // Python: keywords, not args
327
+ if (/^[A-Za-z_$][\w$]*\s*=(?!=)/.test(t))
328
+ return false; // keyword argument
329
+ return true;
330
+ }).length;
331
+ }
332
+ /** Extract the parenthesised argument text that follows `(` at `openIdx`. */
333
+ function _argTextAfter(line, openIdx) {
334
+ let depth = 0;
335
+ for (let i = openIdx; i < line.length; i++) {
336
+ const ch = line[i];
337
+ if (ch === "(")
338
+ depth++;
339
+ else if (ch === ")") {
340
+ depth--;
341
+ if (depth === 0)
342
+ return line.slice(openIdx + 1, i);
343
+ }
344
+ }
345
+ return line.slice(openIdx + 1);
346
+ }
347
+ function _indentWidth(line) {
348
+ let n = 0;
349
+ while (n < line.length && (line[n] === " " || line[n] === "\t"))
350
+ n++;
351
+ return n;
352
+ }
353
+ function _extractPython(lines) {
354
+ const symbols = [];
355
+ const imports = [];
356
+ const calls = [];
357
+ const stack = [];
358
+ const classOf = () => {
359
+ for (let i = stack.length - 1; i >= 0; i--)
360
+ if (stack[i].kind === "class")
361
+ return stack[i].name;
362
+ return "";
363
+ };
364
+ const functionOf = () => {
365
+ for (let i = stack.length - 1; i >= 0; i--)
366
+ if (stack[i].kind === "function")
367
+ return stack[i].name;
368
+ return "";
369
+ };
370
+ /** `node.end_lineno`: last line still inside the indented block. */
371
+ const blockEnd = (startIdx, indent) => {
372
+ let end = startIdx;
373
+ for (let i = startIdx + 1; i < lines.length; i++) {
374
+ const raw = lines[i];
375
+ const stripped = raw.trim();
376
+ if (!stripped || stripped.startsWith("#"))
377
+ continue;
378
+ if (_indentWidth(raw) <= indent)
379
+ break;
380
+ end = i;
381
+ }
382
+ return end + 1;
383
+ };
384
+ /** `ast.get_docstring(node)`, approximated (first statement string literal). */
385
+ const docstringOf = (startIdx, indent) => {
386
+ for (let i = startIdx + 1; i < lines.length; i++) {
387
+ const raw = lines[i];
388
+ const stripped = raw.trim();
389
+ if (!stripped)
390
+ continue;
391
+ if (stripped.startsWith("#"))
392
+ continue;
393
+ if (_indentWidth(raw) <= indent)
394
+ return "";
395
+ const m = /^(?:[rRbBfFuU]{0,2})("""|'''|"|')/.exec(stripped);
396
+ if (!m)
397
+ return "";
398
+ const delim = m[1];
399
+ let body = stripped.slice(m[0].length);
400
+ if (!body.endsWith(delim) || body.length === 0) {
401
+ const collected = [body];
402
+ for (let j = i + 1; j < lines.length; j++) {
403
+ const l = lines[j];
404
+ const close = l.indexOf(delim);
405
+ if (close >= 0) {
406
+ collected.push(l.slice(0, close));
407
+ break;
408
+ }
409
+ collected.push(l);
410
+ }
411
+ body = collected.join("\n");
412
+ }
413
+ else {
414
+ body = body.slice(0, body.length - delim.length);
415
+ }
416
+ // `inspect.cleandoc`: drop the first line's indent, de-indent the rest.
417
+ const parts = body.replace(/\\n/g, "\n").split("\n");
418
+ const first = (parts.shift() ?? "").trim();
419
+ const rest = parts.map((l) => l.replace(/^\s+/, ""));
420
+ return [first, ...rest].join("\n").trim().slice(0, 300);
421
+ }
422
+ return "";
423
+ };
424
+ // Remove string literals then comments, so call scanning never sees text.
425
+ const codeOnly = (line) => line
426
+ .replace(/'''[\s\S]*?'''|"""[\s\S]*?"""/g, "")
427
+ .replace(/'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"/g, '""')
428
+ .split("#")[0];
429
+ const callRe = /([A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)\s*\(/g;
430
+ const kwRe = /^(?:if|for|while|with|return|elif|except|lambda|assert|del|yield|await|not|and|or|in|is|print)\b/;
431
+ for (let i = 0; i < lines.length; i++) {
432
+ const raw = lines[i];
433
+ const stripped = raw.trim();
434
+ if (!stripped || stripped.startsWith("#"))
435
+ continue;
436
+ const indent = _indentWidth(raw);
437
+ while (stack.length > 0 && indent <= stack[stack.length - 1].indent)
438
+ stack.pop();
439
+ const line = i + 1;
440
+ // ── class ─────────────────────────────────────────────────────────────
441
+ const cm = /^class\s+([A-Za-z_]\w*)\s*[:(]/.exec(stripped);
442
+ if (cm) {
443
+ const name = cm[1];
444
+ symbols.push({
445
+ name,
446
+ kind: "class",
447
+ line,
448
+ line_end: blockEnd(i, indent),
449
+ parent: classOf(),
450
+ signature: stripped,
451
+ docstring: docstringOf(i, indent),
452
+ });
453
+ stack.push({ indent, name, kind: "class" });
454
+ continue;
455
+ }
456
+ // ── def / async def ───────────────────────────────────────────────────
457
+ const dm = /^(?:async\s+)?def\s+([A-Za-z_]\w*)\s*\(/.exec(stripped);
458
+ if (dm) {
459
+ const name = dm[1];
460
+ const parent = classOf();
461
+ symbols.push({
462
+ name,
463
+ kind: parent ? "method" : "function",
464
+ line,
465
+ line_end: blockEnd(i, indent),
466
+ parent,
467
+ signature: stripped,
468
+ docstring: docstringOf(i, indent),
469
+ });
470
+ stack.push({ indent, name, kind: "function" });
471
+ continue;
472
+ }
473
+ // ── import / from ... import ──────────────────────────────────────────
474
+ const im = /^import\s+(.+)$/.exec(stripped);
475
+ if (im) {
476
+ for (const part of im[1].split(",")) {
477
+ const p = part.trim();
478
+ if (!p)
479
+ continue;
480
+ const asM = /^([\w.]+)\s+as\s+([A-Za-z_]\w*)$/.exec(p);
481
+ imports.push({
482
+ module: asM ? asM[1] : p,
483
+ names: [],
484
+ alias: asM ? asM[2] : "",
485
+ line,
486
+ is_from: false,
487
+ });
488
+ }
489
+ continue;
490
+ }
491
+ const fm = /^from\s+([.\w]*)\s+import\s+(.+)$/.exec(stripped);
492
+ if (fm) {
493
+ // Python's visitor ignores relative imports with no module name.
494
+ const mod = fm[1].replace(/^\.+/, "");
495
+ let clause = fm[2].trim();
496
+ if (clause.startsWith("(") && !clause.includes(")")) {
497
+ for (let j = i + 1; j < lines.length; j++) {
498
+ clause += " " + lines[j].trim();
499
+ if (clause.includes(")"))
500
+ break;
501
+ }
502
+ }
503
+ clause = clause.replace(/[()]/g, " ").trim();
504
+ if (mod) {
505
+ const names = clause
506
+ .split(",")
507
+ .map((s) => s.trim().replace(/\s+as\s+[A-Za-z_]\w*$/, "").trim())
508
+ .filter(Boolean);
509
+ imports.push({ module: mod, names, alias: "", line, is_from: true });
510
+ }
511
+ continue;
512
+ }
513
+ // Calls + module/class level assignments, from the same code view.
514
+ const code = codeOnly(raw);
515
+ // ── variable assignment (visit_Assign at non-function scope) ─────────
516
+ if (!functionOf() && !kwRe.test(stripped)) {
517
+ let rest = code;
518
+ const names = [];
519
+ for (;;) {
520
+ const vm = /^\s*([A-Za-z_]\w*)\s*=(?!=)\s*/.exec(rest);
521
+ if (!vm)
522
+ break;
523
+ names.push(vm[1]);
524
+ rest = rest.slice(vm[0].length);
525
+ }
526
+ for (const name of names) {
527
+ symbols.push({
528
+ name,
529
+ kind: "variable",
530
+ line,
531
+ line_end: line,
532
+ parent: classOf(),
533
+ signature: "",
534
+ docstring: "",
535
+ });
536
+ }
537
+ }
538
+ // ── call sites ────────────────────────────────────────────────────────
539
+ const caller = functionOf();
540
+ callRe.lastIndex = 0;
541
+ let m;
542
+ while ((m = callRe.exec(code)) !== null) {
543
+ const chain = m[1];
544
+ const head = chain.split(".")[0];
545
+ if (NOT_CALLS.has(chain) || NOT_CALLS.has(head))
546
+ continue;
547
+ const openIdx = m.index + m[0].length - 1;
548
+ calls.push({
549
+ caller,
550
+ callee: chain,
551
+ line,
552
+ args_count: _countArgs(_argTextAfter(code, openIdx)),
553
+ });
554
+ }
555
+ }
556
+ return { symbols, imports, calls };
557
+ }
558
+ /**
559
+ * Strip block comments, line comments and string/template literals while
560
+ * tracking multi-line state, so brace counting and call detection see code only.
561
+ * String bodies are replaced by `""` (not deleted) to keep the code balanced.
562
+ */
563
+ function _jsCleanLines(lines) {
564
+ const out = [];
565
+ let inBlockComment = false;
566
+ let inTemplate = false;
567
+ for (const raw of lines) {
568
+ let code = "";
569
+ let i = 0;
570
+ while (i < raw.length) {
571
+ const ch = raw[i];
572
+ const next = raw[i + 1];
573
+ if (inBlockComment) {
574
+ if (ch === "*" && next === "/") {
575
+ inBlockComment = false;
576
+ i += 2;
577
+ }
578
+ else
579
+ i++;
580
+ continue;
581
+ }
582
+ if (inTemplate) {
583
+ if (ch === "\\") {
584
+ i += 2;
585
+ continue;
586
+ }
587
+ if (ch === "`") {
588
+ inTemplate = false;
589
+ code += '""';
590
+ i++;
591
+ continue;
592
+ }
593
+ i++;
594
+ continue;
595
+ }
596
+ if (ch === "/" && next === "*") {
597
+ inBlockComment = true;
598
+ i += 2;
599
+ continue;
600
+ }
601
+ if (ch === "/" && next === "/")
602
+ break; // line comment
603
+ if (ch === "`") {
604
+ inTemplate = true;
605
+ i++;
606
+ continue;
607
+ }
608
+ if (ch === '"' || ch === "'") {
609
+ const quote = ch;
610
+ i++;
611
+ while (i < raw.length) {
612
+ if (raw[i] === "\\") {
613
+ i += 2;
614
+ continue;
615
+ }
616
+ if (raw[i] === quote) {
617
+ i++;
618
+ break;
619
+ }
620
+ i++;
621
+ }
622
+ code += '""';
623
+ continue;
624
+ }
625
+ code += ch;
626
+ i++;
627
+ }
628
+ let braceDelta = 0;
629
+ for (const c of code) {
630
+ if (c === "{")
631
+ braceDelta++;
632
+ else if (c === "}")
633
+ braceDelta--;
634
+ }
635
+ out.push({ raw, code, braceDelta });
636
+ }
637
+ return out;
638
+ }
639
+ function _extractJs(lines) {
640
+ const cleaned = _jsCleanLines(lines);
641
+ const symbols = [];
642
+ const imports = [];
643
+ const calls = [];
644
+ const stack = [];
645
+ const classOf = () => {
646
+ for (let i = stack.length - 1; i >= 0; i--)
647
+ if (stack[i].kind === "class")
648
+ return stack[i].name;
649
+ return "";
650
+ };
651
+ const functionOf = () => {
652
+ for (let i = stack.length - 1; i >= 0; i--)
653
+ if (stack[i].kind === "function")
654
+ return stack[i].name;
655
+ return "";
656
+ };
657
+ // Pass 1: brace depth per line (depth *before* the line's own braces).
658
+ const depthBefore = [];
659
+ let depth = 0;
660
+ for (const l of cleaned) {
661
+ depthBefore.push(depth);
662
+ depth += l.braceDelta;
663
+ }
664
+ /**
665
+ * End line (1-based) of the brace-delimited block that starts on line
666
+ * `startIdx` (0-based), given the depth in effect before that line.
667
+ * A declaration whose net brace delta never goes positive (e.g.
668
+ * `type X = string;`) ends on its own line.
669
+ */
670
+ const braceEnd = (startIdx, baseDepth) => {
671
+ let d = baseDepth;
672
+ for (let i = startIdx; i < cleaned.length; i++) {
673
+ d += cleaned[i].braceDelta;
674
+ if (d <= baseDepth)
675
+ return i + 1;
676
+ }
677
+ return cleaned.length;
678
+ };
679
+ const callRe = /([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\s*\(/g;
680
+ for (let i = 0; i < cleaned.length; i++) {
681
+ const { raw, code } = cleaned[i];
682
+ const stripped = raw.trim();
683
+ const decl = code.trim();
684
+ if (!decl)
685
+ continue;
686
+ const depthHere = depthBefore[i];
687
+ // Close finished blocks.
688
+ while (stack.length > 0 && depthHere <= stack[stack.length - 1].depth)
689
+ stack.pop();
690
+ const line = i + 1;
691
+ // ── class / interface / type / enum ───────────────────────────────────
692
+ const cm = /^(?:export\s+)?(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?class\s+([A-Za-z_$][\w$]*)/.exec(decl) ??
693
+ /^(?:export\s+)?(?:declare\s+)?(?:interface|enum)\s+([A-Za-z_$][\w$]*)/.exec(decl) ??
694
+ /^(?:export\s+)?(?:declare\s+)?type\s+([A-Za-z_$][\w$]*)\s*[=<]/.exec(decl);
695
+ if (cm) {
696
+ const name = cm[1];
697
+ symbols.push({
698
+ name,
699
+ kind: "class",
700
+ line,
701
+ line_end: braceEnd(i, depthHere),
702
+ parent: classOf(),
703
+ signature: stripped,
704
+ docstring: "",
705
+ });
706
+ if (decl.includes("{"))
707
+ stack.push({ name, kind: "class", depth: depthHere });
708
+ continue;
709
+ }
710
+ // ── function declarations ─────────────────────────────────────────────
711
+ const fnm = /^(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/.exec(decl);
712
+ if (fnm) {
713
+ const name = fnm[1];
714
+ const inClass = classOf() !== "";
715
+ symbols.push({
716
+ name,
717
+ kind: inClass ? "method" : "function",
718
+ line,
719
+ line_end: braceEnd(i, depthHere),
720
+ parent: classOf(),
721
+ signature: stripped,
722
+ docstring: "",
723
+ });
724
+ stack.push({ name, kind: "function", depth: depthHere });
725
+ continue;
726
+ }
727
+ // ── methods inside a class body ───────────────────────────────────────
728
+ if (classOf() && depthHere === classBodyDepth(stack)) {
729
+ const mm = /^(?:(?:public|private|protected|static|async|readonly|override|abstract|declare|get|set)\s+)*([A-Za-z_$#][\w$]*)\s*(?:<[^>]*>)?\s*\(/.exec(decl) ??
730
+ // `name = (a) => ...` class property arrow functions
731
+ /^(?:(?:public|private|protected|static|readonly|override|declare)\s+)*([A-Za-z_$#][\w$]*)\s*(?::[^=]+)?=\s*(?:async\s*)?(?:\([^)]*\)|[A-Za-z_$][\w$]*)\s*(?::[^=]+)?=>/.exec(decl);
732
+ if (mm && !NOT_CALLS.has(mm[1])) {
733
+ const name = mm[1];
734
+ symbols.push({
735
+ name,
736
+ kind: "method",
737
+ line,
738
+ line_end: braceEnd(i, depthHere),
739
+ parent: classOf(),
740
+ signature: stripped,
741
+ docstring: "",
742
+ });
743
+ stack.push({ name, kind: "function", depth: depthHere });
744
+ continue;
745
+ }
746
+ }
747
+ // ── arrow / function expressions and variables ────────────────────────
748
+ const vm = /^(?:export\s+)?(?:declare\s+)?(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*/.exec(decl);
749
+ if (vm) {
750
+ const name = vm[1];
751
+ const after = decl.slice(vm[0].length);
752
+ const isFunction = after.startsWith("function") ||
753
+ after.startsWith("async function") ||
754
+ /^(?:async\s*)?\([^)]*\)\s*(?::[^=]+)?=>/.test(after) ||
755
+ /^[A-Za-z_$][\w$]*\s*=>/.test(after) ||
756
+ /^(?:async\s*)?<[^>]*>\s*\(/.test(after);
757
+ if (!functionOf()) {
758
+ if (isFunction) {
759
+ symbols.push({
760
+ name,
761
+ kind: classOf() ? "method" : "function",
762
+ line,
763
+ line_end: braceEnd(i, depthHere),
764
+ parent: classOf(),
765
+ signature: stripped,
766
+ docstring: "",
767
+ });
768
+ if (decl.includes("{"))
769
+ stack.push({ name, kind: "function", depth: depthHere });
770
+ continue;
771
+ }
772
+ symbols.push({
773
+ name,
774
+ kind: "variable",
775
+ line,
776
+ line_end: line,
777
+ parent: classOf(),
778
+ signature: "",
779
+ docstring: "",
780
+ });
781
+ }
782
+ }
783
+ // ── imports / requires ────────────────────────────────────────────────
784
+ const fromM = /^(?:import|export)\s+(?:type\s+)?([\s\S]*?)\s*from\s*['"]([^'"]+)['"]/.exec(stripped);
785
+ if (fromM) {
786
+ const clause = fromM[1].trim().replace(/[{}]/g, " ");
787
+ const names = clause
788
+ .split(",")
789
+ .map((s) => s.trim().replace(/^\*\s*as\s+/, "").replace(/\s+as\s+.*$/, "").trim())
790
+ .filter(Boolean);
791
+ imports.push({ module: fromM[2], names, alias: "", line, is_from: true });
792
+ continue;
793
+ }
794
+ const bareM = /^import\s+['"]([^'"]+)['"]/.exec(stripped);
795
+ if (bareM) {
796
+ imports.push({ module: bareM[1], names: [], alias: "", line, is_from: false });
797
+ continue;
798
+ }
799
+ for (const rm of stripped.matchAll(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g)) {
800
+ imports.push({ module: rm[1], names: [], alias: "", line, is_from: false });
801
+ }
802
+ // ── call sites ────────────────────────────────────────────────────────
803
+ const caller = functionOf();
804
+ callRe.lastIndex = 0;
805
+ let m;
806
+ while ((m = callRe.exec(code)) !== null) {
807
+ const chain = m[1];
808
+ const head = chain.split(".")[0];
809
+ if (NOT_CALLS.has(chain) || NOT_CALLS.has(head))
810
+ continue;
811
+ const openIdx = m.index + m[0].length - 1;
812
+ calls.push({
813
+ caller,
814
+ callee: chain,
815
+ line,
816
+ args_count: _countArgs(_argTextAfter(code, openIdx)),
817
+ });
818
+ }
819
+ }
820
+ return { symbols, imports, calls };
821
+ }
822
+ /**
823
+ * Brace depth at which the innermost enclosing class body's members live.
824
+ * A block pushed at declaration depth `d` has its body at `d + 1`.
825
+ */
826
+ function classBodyDepth(stack) {
827
+ for (let i = stack.length - 1; i >= 0; i--) {
828
+ if (stack[i].kind === "class")
829
+ return stack[i].depth + 1;
830
+ }
831
+ return -1;
832
+ }
833
+ /* ── ASTIndexer ───────────────────────────────────────────────────────────── */
834
+ /**
835
+ * Builds and queries a real AST index of a workspace.
836
+ *
837
+ * The key capability:
838
+ * "Before you edit function X, here's everything that calls it,
839
+ * everything it imports, and what will break."
840
+ */
841
+ export class ASTIndexer {
842
+ workspace;
843
+ _conn;
844
+ /** Python kept a `_index_thread`; Node keeps the in-flight background promise. */
845
+ _index_task = null;
846
+ constructor(workspace) {
847
+ this.workspace = path.resolve(workspace);
848
+ const ws_hash = createHash("md5").update(this.workspace).digest("hex").slice(0, 8);
849
+ const db_path = path.join(AST_INDEX_DIR, `ast_${ws_hash}.db`);
850
+ this._conn = new DatabaseSync(db_path, { timeout: 10000 });
851
+ this._init_schema();
852
+ }
853
+ _init_schema() {
854
+ this._conn.exec(_SCHEMA);
855
+ }
856
+ /* ── Indexing ────────────────────────────────────────────────────────────── */
857
+ /**
858
+ * Index all source files in the workspace. Only re-indexes changed files.
859
+ * Returns stats dict.
860
+ *
861
+ * Synchronous on purpose: it is driven by the `ast_reindex` tool, which
862
+ * returns a string. Use `index_workspace_async()` for background indexing.
863
+ */
864
+ index_workspace(max_files = 500, force = false) {
865
+ const files = this._find_source_files(max_files);
866
+ let new_count = 0;
867
+ let changed_count = 0;
868
+ let skipped_count = 0;
869
+ for (const fpath of files) {
870
+ try {
871
+ const mtime = fs.statSync(fpath).mtimeMs / 1000;
872
+ const row = this._conn.prepare("SELECT mtime FROM files WHERE path=?").get(fpath);
873
+ if (row && Number(row["mtime"]) === mtime && !force) {
874
+ skipped_count += 1;
875
+ continue;
876
+ }
877
+ this._index_file(fpath, mtime);
878
+ if (row) {
879
+ changed_count += 1;
880
+ }
881
+ else {
882
+ new_count += 1;
883
+ }
884
+ }
885
+ catch (e) {
886
+ debug(`[AST] Failed to index ${fpath}: ${e instanceof Error ? e.message : String(e)}`);
887
+ }
888
+ }
889
+ return {
890
+ files_indexed: new_count + changed_count,
891
+ files_new: new_count,
892
+ files_changed: changed_count,
893
+ files_skipped: skipped_count,
894
+ total: files.length,
895
+ };
896
+ }
897
+ /** camelCase alias. */
898
+ indexWorkspace(max_files = 500, force = false) {
899
+ return this.index_workspace(max_files, force);
900
+ }
901
+ /**
902
+ * Background indexing — doesn't block the agent.
903
+ * Bounded-concurrency batches with an event-loop yield between them, which is
904
+ * the async analogue of Python's `threading.Thread(target=..., daemon=True)`.
905
+ */
906
+ index_workspace_async() {
907
+ if (this._index_task)
908
+ return;
909
+ this._index_task = this._index_workspace_pooled()
910
+ .then(() => undefined)
911
+ .catch((e) => {
912
+ warn(`[AST] Background indexing failed: ${e instanceof Error ? e.message : String(e)}`);
913
+ })
914
+ .finally(() => {
915
+ this._index_task = null;
916
+ });
917
+ }
918
+ /** camelCase alias. */
919
+ indexWorkspaceAsyncStart() {
920
+ this.index_workspace_async();
921
+ }
922
+ /** Awaitable form of the background indexer. */
923
+ async indexWorkspaceAsync(max_files = 500, force = false) {
924
+ return this._index_workspace_pooled(max_files, force);
925
+ }
926
+ async _index_workspace_pooled(max_files = 500, force = false) {
927
+ const files = this._find_source_files(max_files);
928
+ let new_count = 0;
929
+ let changed_count = 0;
930
+ let skipped_count = 0;
931
+ const concurrency = 8;
932
+ for (let i = 0; i < files.length; i += concurrency) {
933
+ const batch = files.slice(i, i + concurrency);
934
+ const results = await Promise.allSettled(batch.map(async (fpath) => {
935
+ try {
936
+ const mtime = fs.statSync(fpath).mtimeMs / 1000;
937
+ const row = this._conn.prepare("SELECT mtime FROM files WHERE path=?").get(fpath);
938
+ if (row && Number(row["mtime"]) === mtime && !force)
939
+ return "skipped";
940
+ this._index_file(fpath, mtime);
941
+ return row ? "changed" : "new";
942
+ }
943
+ catch (e) {
944
+ debug(`[AST] Failed to index ${fpath}: ${e instanceof Error ? e.message : String(e)}`);
945
+ return "failed";
946
+ }
947
+ }));
948
+ for (const r of results) {
949
+ if (r.status !== "fulfilled")
950
+ continue;
951
+ if (r.value === "new")
952
+ new_count += 1;
953
+ else if (r.value === "changed")
954
+ changed_count += 1;
955
+ else if (r.value === "skipped")
956
+ skipped_count += 1;
957
+ }
958
+ // Yield so the agent's event loop is never starved by a large workspace.
959
+ await new Promise((resolve) => setImmediate(resolve));
960
+ }
961
+ return {
962
+ files_indexed: new_count + changed_count,
963
+ files_new: new_count,
964
+ files_changed: changed_count,
965
+ files_skipped: skipped_count,
966
+ total: files.length,
967
+ };
968
+ }
969
+ /** Python's `.py`-only discovery, kept for API compatibility. */
970
+ _find_python_files(max_files) {
971
+ return this._find_files(max_files, new Set([".py"]));
972
+ }
973
+ /** All indexable source files (Python behaviour → .py; port adds TS/JS). */
974
+ _find_source_files(max_files) {
975
+ return this._find_files(max_files, new Set(Object.keys(INDEX_EXTENSIONS)));
976
+ }
977
+ _find_files(max_files, exts) {
978
+ const files = [];
979
+ const walk = (dir) => {
980
+ let entries;
981
+ try {
982
+ entries = fs.readdirSync(dir, { withFileTypes: true });
983
+ }
984
+ catch {
985
+ return false;
986
+ }
987
+ const dirs = entries.filter((e) => e.isDirectory() && !SKIP_DIRS.has(e.name));
988
+ for (const fn of entries) {
989
+ if (fn.isDirectory())
990
+ continue;
991
+ if (exts.has(path.extname(fn.name).toLowerCase())) {
992
+ files.push(path.join(dir, fn.name));
993
+ if (files.length >= max_files)
994
+ return true;
995
+ }
996
+ }
997
+ for (const d of dirs) {
998
+ if (walk(path.join(dir, d.name)))
999
+ return true;
1000
+ }
1001
+ return false;
1002
+ };
1003
+ walk(this.workspace);
1004
+ return files;
1005
+ }
1006
+ /** Parse one source file and update all tables. */
1007
+ _index_file(fpath, mtime) {
1008
+ let source;
1009
+ try {
1010
+ source = fs.readFileSync(fpath, "utf-8");
1011
+ }
1012
+ catch {
1013
+ return;
1014
+ }
1015
+ const language = INDEX_EXTENSIONS[path.extname(fpath).toLowerCase()] ?? "python";
1016
+ const lines = source.split(/\r?\n/);
1017
+ const extraction = language === "python" ? _extractPython(lines) : _extractJs(lines);
1018
+ const file_hash = createHash("md5").update(source, "utf-8").digest("hex");
1019
+ // Clear old data for this file
1020
+ for (const tbl of ["symbols", "imports", "calls", "symbol_refs"]) {
1021
+ this._conn.prepare(`DELETE FROM ${tbl} WHERE file_path=?`).run(fpath);
1022
+ }
1023
+ const symStmt = this._conn.prepare("INSERT INTO symbols(file_path,name,kind,line_start,line_end,parent,signature,docstring,is_public)" +
1024
+ " VALUES(?,?,?,?,?,?,?,?,?)");
1025
+ for (const sym of extraction.symbols) {
1026
+ symStmt.run(fpath, sym.name, sym.kind, sym.line, sym.line_end, sym.parent, sym.signature, (sym.docstring ?? "").slice(0, 300), sym.name.startsWith("_") ? 0 : 1);
1027
+ }
1028
+ const impStmt = this._conn.prepare("INSERT INTO imports(file_path,module,names,alias,line,is_from) VALUES(?,?,?,?,?,?)");
1029
+ for (const imp of extraction.imports) {
1030
+ impStmt.run(fpath, imp.module, JSON.stringify(imp.names ?? []), imp.alias ?? "", imp.line, imp.is_from ? 1 : 0);
1031
+ }
1032
+ const callStmt = this._conn.prepare("INSERT INTO calls(file_path,caller,callee,line,args_count) VALUES(?,?,?,?,?)");
1033
+ for (const call of extraction.calls) {
1034
+ callStmt.run(fpath, call.caller ?? "", call.callee, call.line, call.args_count ?? 0);
1035
+ }
1036
+ this._conn
1037
+ .prepare("INSERT OR REPLACE INTO files(path,mtime,size,hash,language,indexed_at) VALUES(?,?,?,?,?,?)")
1038
+ .run(fpath, mtime, source.length, file_hash, language, Date.now() / 1000);
1039
+ }
1040
+ /* ── Queries ─────────────────────────────────────────────────────────────── */
1041
+ /** Find where a class/function/variable is defined. */
1042
+ find_symbol(name, kind = null) {
1043
+ let q = "SELECT * FROM symbols WHERE name LIKE ?";
1044
+ const params = [`%${name}%`];
1045
+ if (kind) {
1046
+ q += " AND kind=?";
1047
+ params.push(kind);
1048
+ }
1049
+ q += " ORDER BY is_public DESC, name LIMIT 20";
1050
+ const rows = this._conn.prepare(q).all(...params);
1051
+ return rows.map((r) => new Symbol({
1052
+ name: String(r["name"]),
1053
+ kind: String(r["kind"]),
1054
+ file_path: String(r["file_path"]),
1055
+ line: Number(r["line_start"]),
1056
+ signature: r["signature"] ? String(r["signature"]) : "",
1057
+ docstring: r["docstring"] ? String(r["docstring"]) : "",
1058
+ parent: r["parent"] ? String(r["parent"]) : "",
1059
+ }));
1060
+ }
1061
+ /** Find all places that call a function — "who calls X?" */
1062
+ find_callers(function_name) {
1063
+ const rows = this._conn
1064
+ .prepare("SELECT * FROM calls WHERE callee LIKE ? ORDER BY file_path, line")
1065
+ .all(`%${function_name}%`);
1066
+ return rows.map((r) => new CallSite({
1067
+ file_path: String(r["file_path"]),
1068
+ caller: r["caller"] ? String(r["caller"]) : "",
1069
+ callee: String(r["callee"]),
1070
+ line: Number(r["line"]),
1071
+ }));
1072
+ }
1073
+ /** Where is a symbol used? Combines calls + imports. */
1074
+ find_usages(symbol_name) {
1075
+ const calls = this.find_callers(symbol_name);
1076
+ const imp_rows = this._conn
1077
+ .prepare("SELECT file_path, line FROM imports WHERE names LIKE ? OR module LIKE ?")
1078
+ .all(`%${symbol_name}%`, `%${symbol_name}%`);
1079
+ const usages = calls.map((c) => ({
1080
+ type: "call",
1081
+ file: c.file_path,
1082
+ line: c.line,
1083
+ caller: c.caller,
1084
+ via: c.callee,
1085
+ }));
1086
+ usages.push(...imp_rows.map((r) => ({
1087
+ type: "import",
1088
+ file: String(r["file_path"]),
1089
+ line: Number(r["line"]),
1090
+ })));
1091
+ return usages;
1092
+ }
1093
+ /** Which files import a given module? */
1094
+ what_imports(module_name) {
1095
+ const rows = this._conn
1096
+ .prepare("SELECT DISTINCT file_path FROM imports WHERE module LIKE ?")
1097
+ .all(`%${module_name}%`);
1098
+ return rows.map((r) => String(r["file_path"]));
1099
+ }
1100
+ /**
1101
+ * Before editing symbol_name, what will break?
1102
+ * Returns an ImpactAnalysis with call sites, affected files, risk level.
1103
+ */
1104
+ impact_analysis(symbol_name) {
1105
+ const callers = this.find_callers(symbol_name);
1106
+ const affected = [...new Set(callers.map((c) => c.file_path).filter((f) => f !== ""))];
1107
+ // Risk scoring
1108
+ const n_callers = callers.length;
1109
+ const n_files = affected.length;
1110
+ let risk;
1111
+ if (n_callers === 0 && n_files === 0) {
1112
+ risk = "low";
1113
+ }
1114
+ else if (n_callers < 3) {
1115
+ risk = "low";
1116
+ }
1117
+ else if (n_callers < 8 || n_files < 3) {
1118
+ risk = "medium";
1119
+ }
1120
+ else if (n_callers < 20) {
1121
+ risk = "high";
1122
+ }
1123
+ else {
1124
+ risk = "critical";
1125
+ }
1126
+ const parts = [];
1127
+ if (callers.length > 0) {
1128
+ parts.push(`Called ${n_callers}x across ${n_files} file(s)`);
1129
+ }
1130
+ if (callers.length === 0) {
1131
+ parts.push("Not called anywhere — safe to edit");
1132
+ }
1133
+ const summary = `Impact of changing '${symbol_name}': ${parts.join(", ") || "minimal"}`;
1134
+ return new ImpactAnalysis({
1135
+ symbol: symbol_name,
1136
+ direct_calls: callers,
1137
+ affected_files: affected,
1138
+ risk_level: risk,
1139
+ summary,
1140
+ });
1141
+ }
1142
+ /** camelCase alias. */
1143
+ impactAnalysis(symbol_name) {
1144
+ return this.impact_analysis(symbol_name);
1145
+ }
1146
+ /**
1147
+ * Before editing a file, get full context:
1148
+ * what's defined, what's imported, what calls what.
1149
+ */
1150
+ get_file_context(file_path) {
1151
+ const abs_path = path.isAbsolute(file_path) ? file_path : path.join(this.workspace, file_path);
1152
+ const syms = this._conn
1153
+ .prepare("SELECT name, kind, line_start, signature FROM symbols WHERE file_path=? ORDER BY line_start")
1154
+ .all(abs_path);
1155
+ const imps = this._conn
1156
+ .prepare("SELECT module, names FROM imports WHERE file_path=? ORDER BY line")
1157
+ .all(abs_path);
1158
+ const lines = [`[AST Context: ${path.relative(this.workspace, abs_path)}]`];
1159
+ if (imps.length > 0) {
1160
+ lines.push("Imports:");
1161
+ for (const r of imps.slice(0, 10)) {
1162
+ let names = [];
1163
+ try {
1164
+ const parsed = JSON.parse(String(r["names"] ?? "[]"));
1165
+ if (Array.isArray(parsed))
1166
+ names = parsed.map((x) => String(x));
1167
+ }
1168
+ catch {
1169
+ names = [];
1170
+ }
1171
+ if (names.length > 0) {
1172
+ lines.push(` from ${String(r["module"])} import ${names.slice(0, 4).join(", ")}`);
1173
+ }
1174
+ else {
1175
+ lines.push(` import ${String(r["module"])}`);
1176
+ }
1177
+ }
1178
+ }
1179
+ if (syms.length > 0) {
1180
+ lines.push("Symbols:");
1181
+ for (const r of syms.slice(0, 20)) {
1182
+ const indent = String(r["kind"]) === "method" ? " " : "";
1183
+ lines.push(` ${indent}${String(r["kind"])} ${String(r["name"])} (line ${Number(r["line_start"])})`);
1184
+ }
1185
+ }
1186
+ return lines.join("\n");
1187
+ }
1188
+ /** camelCase alias. */
1189
+ getFileContext(file_path) {
1190
+ return this.get_file_context(file_path);
1191
+ }
1192
+ /** Index statistics. */
1193
+ stats() {
1194
+ const n_files = this._conn.prepare("SELECT COUNT(*) FROM files").get();
1195
+ const n_symbols = this._conn.prepare("SELECT COUNT(*) FROM symbols").get();
1196
+ const n_calls = this._conn.prepare("SELECT COUNT(*) FROM calls").get();
1197
+ const n_imports = this._conn.prepare("SELECT COUNT(*) FROM imports").get();
1198
+ const kindRows = this._conn
1199
+ .prepare("SELECT kind, COUNT(*) as cnt FROM symbols GROUP BY kind")
1200
+ .all();
1201
+ const kinds = {};
1202
+ for (const r of kindRows)
1203
+ kinds[String(r["kind"])] = Number(r["cnt"]);
1204
+ return {
1205
+ files_indexed: _firstValue(n_files),
1206
+ symbols: _firstValue(n_symbols),
1207
+ calls: _firstValue(n_calls),
1208
+ imports: _firstValue(n_imports),
1209
+ by_kind: kinds,
1210
+ };
1211
+ }
1212
+ /** Format impact analysis as a readable string for the agent. */
1213
+ format_impact(ia, max_callers = 10) {
1214
+ const lines = [
1215
+ `Impact Analysis: '${ia.symbol}'`,
1216
+ ` Risk level: ${ia.risk_level.toUpperCase()}`,
1217
+ ` ${ia.summary}`,
1218
+ ];
1219
+ if (ia.direct_calls.length > 0) {
1220
+ lines.push(` Callers (${ia.direct_calls.length} total):`);
1221
+ for (const c of ia.direct_calls.slice(0, max_callers)) {
1222
+ const rel = path.relative(this.workspace, c.file_path);
1223
+ lines.push(` ${rel}:${c.line} ${c.caller || "?"} → ${c.callee}`);
1224
+ }
1225
+ if (ia.direct_calls.length > max_callers) {
1226
+ lines.push(` ... and ${ia.direct_calls.length - max_callers} more`);
1227
+ }
1228
+ }
1229
+ if (ia.direct_calls.length === 0) {
1230
+ lines.push(" No callers found — safe to modify");
1231
+ }
1232
+ return lines.join("\n");
1233
+ }
1234
+ /** camelCase alias. */
1235
+ formatImpact(ia, max_callers = 10) {
1236
+ return this.format_impact(ia, max_callers);
1237
+ }
1238
+ /**
1239
+ * One-line summary for swarm orchestrator context injection.
1240
+ *
1241
+ * Byte-identical to Python on a Python-only workspace. When the index also
1242
+ * covers TypeScript/JavaScript (the port indexes those extensions) the
1243
+ * language word becomes "code" rather than claiming everything is Python.
1244
+ */
1245
+ summary() {
1246
+ const s = this.stats();
1247
+ if (s.files_indexed === 0) {
1248
+ return "";
1249
+ }
1250
+ const langs = new Set(this._conn
1251
+ .prepare("SELECT DISTINCT language FROM files")
1252
+ .all()
1253
+ .map((r) => String(r["language"] ?? "python")));
1254
+ const langLabel = langs.size === 1 && langs.has("python") ? "Python" : "code";
1255
+ return (`${s.files_indexed} ${langLabel} files | ` +
1256
+ `${s.symbols ?? 0} symbols | ` +
1257
+ `${s.calls ?? 0} call sites`);
1258
+ }
1259
+ /** Inject AST tools into agent._tool_map. */
1260
+ as_tool_map() {
1261
+ return {
1262
+ ast_find_symbol: _tool(["name", "kind"], (a) => this._t_find_symbol(String(a["name"] ?? ""), a["kind"] === undefined || a["kind"] === null ? null : String(a["kind"]))),
1263
+ ast_find_callers: _tool(["function_name"], (a) => this._t_find_callers(String(a["function_name"] ?? ""))),
1264
+ ast_impact: _tool(["symbol_name"], (a) => this._t_impact(String(a["symbol_name"] ?? ""))),
1265
+ ast_file_context: _tool(["path"], (a) => this._t_file_context(String(a["path"] ?? ""))),
1266
+ ast_stats: _tool([], () => this._t_stats()),
1267
+ ast_reindex: _tool(["force"], (a) => this._t_reindex(Boolean(a["force"]))),
1268
+ };
1269
+ }
1270
+ /** camelCase alias. */
1271
+ asToolMap() {
1272
+ return this.as_tool_map();
1273
+ }
1274
+ /* ── Tool implementations ────────────────────────────────────────────────── */
1275
+ _t_find_symbol(name, kind = null) {
1276
+ const syms = this.find_symbol(name, kind);
1277
+ if (syms.length === 0) {
1278
+ return `Symbol '${name}' not found in index.`;
1279
+ }
1280
+ const lines = [`Found ${syms.length} match(es) for '${name}':`];
1281
+ for (const s of syms) {
1282
+ const rel = path.relative(this.workspace, s.file_path);
1283
+ const parent = s.parent ? ` (in ${s.parent})` : "";
1284
+ lines.push(` ${s.kind} ${s.name}${parent} — ${rel}:${s.line}`);
1285
+ if (s.signature) {
1286
+ lines.push(` ${s.signature.slice(0, 100)}`);
1287
+ }
1288
+ }
1289
+ return lines.join("\n");
1290
+ }
1291
+ _t_find_callers(function_name) {
1292
+ const callers = this.find_callers(function_name);
1293
+ if (callers.length === 0) {
1294
+ return `No callers found for '${function_name}'.`;
1295
+ }
1296
+ const lines = [`'${function_name}' is called ${callers.length}x:`];
1297
+ for (const c of callers.slice(0, 15)) {
1298
+ const rel = path.relative(this.workspace, c.file_path);
1299
+ lines.push(` ${rel}:${c.line} (in ${c.caller || "module level"})`);
1300
+ }
1301
+ return lines.join("\n");
1302
+ }
1303
+ _t_impact(symbol_name) {
1304
+ const ia = this.impact_analysis(symbol_name);
1305
+ return this.format_impact(ia);
1306
+ }
1307
+ _t_file_context(p) {
1308
+ return this.get_file_context(p);
1309
+ }
1310
+ _t_stats() {
1311
+ const s = this.stats();
1312
+ return (`AST Index: ${s.files_indexed} files | ` +
1313
+ `${s.symbols} symbols | ${s.calls} calls | ` +
1314
+ `${s.imports} imports\n` +
1315
+ `By kind: ` +
1316
+ Object.entries(s.by_kind)
1317
+ .map(([k, v]) => `${k}=${v}`)
1318
+ .join(", "));
1319
+ }
1320
+ _t_reindex(force = false) {
1321
+ const stats = this.index_workspace(500, force);
1322
+ return (`Re-indexed: ${stats.files_indexed} files ` +
1323
+ `(${stats.files_new} new, ${stats.files_changed} changed, ` +
1324
+ `${stats.files_skipped} unchanged)`);
1325
+ }
1326
+ /** Close the underlying handle. */
1327
+ close() {
1328
+ try {
1329
+ this._conn.close();
1330
+ }
1331
+ catch {
1332
+ /* already closed */
1333
+ }
1334
+ }
1335
+ }
1336
+ /** `SELECT COUNT(*)` returns one unnamed column; read it positionally. */
1337
+ function _firstValue(row) {
1338
+ if (!row)
1339
+ return 0;
1340
+ const values = Object.values(row);
1341
+ return values.length > 0 ? Number(values[0]) : 0;
1342
+ }
1343
+ /**
1344
+ * Tool-map adapter. Python tools took keyword arguments (`f(**args)`) and the
1345
+ * Node tool ports take either a single args object or positional parameters, so
1346
+ * the returned handler accepts both call styles.
1347
+ */
1348
+ function _tool(paramNames, impl) {
1349
+ return (...received) => {
1350
+ if (received.length === 1) {
1351
+ const only = received[0];
1352
+ if (only !== null && typeof only === "object" && !Array.isArray(only)) {
1353
+ return impl(only);
1354
+ }
1355
+ }
1356
+ const args = {};
1357
+ paramNames.forEach((n, i) => {
1358
+ if (received[i] !== undefined)
1359
+ args[n] = received[i];
1360
+ });
1361
+ return impl(args);
1362
+ };
1363
+ }
1364
+ /** Exported for tests/debugging: the raw heuristic extractor. */
1365
+ export function _extract_symbols(source, language = "python") {
1366
+ const lines = source.split(/\r?\n/);
1367
+ return language === "python" ? _extractPython(lines) : _extractJs(lines);
1368
+ }
1369
+ //# sourceMappingURL=ast_index.js.map