homegraph 1.5.1 → 1.5.3

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 (382) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/LICENSE +21 -21
  3. package/README.md +312 -305
  4. package/dist/arkui/index.d.ts +4 -0
  5. package/dist/arkui/index.d.ts.map +1 -0
  6. package/dist/arkui/index.js +23 -0
  7. package/dist/arkui/index.js.map +1 -0
  8. package/dist/arkui/migrate-passage.d.ts +28 -0
  9. package/dist/arkui/migrate-passage.d.ts.map +1 -0
  10. package/dist/arkui/migrate-passage.js +310 -0
  11. package/dist/arkui/migrate-passage.js.map +1 -0
  12. package/dist/arkui/migrate-semantics.d.ts +47 -0
  13. package/dist/arkui/migrate-semantics.d.ts.map +1 -0
  14. package/dist/arkui/migrate-semantics.js +229 -0
  15. package/dist/arkui/migrate-semantics.js.map +1 -0
  16. package/dist/arkui/migrate-snapshot.d.ts +79 -0
  17. package/dist/arkui/migrate-snapshot.d.ts.map +1 -0
  18. package/dist/arkui/migrate-snapshot.js +340 -0
  19. package/dist/arkui/migrate-snapshot.js.map +1 -0
  20. package/dist/bin/fatal-handler.js +2 -2
  21. package/dist/bin/homegraph.js +111 -162
  22. package/dist/bin/homegraph.js.map +1 -1
  23. package/dist/bin/node-version-check.d.ts +6 -15
  24. package/dist/bin/node-version-check.d.ts.map +1 -1
  25. package/dist/bin/node-version-check.js +8 -37
  26. package/dist/bin/node-version-check.js.map +1 -1
  27. package/dist/db/index.d.ts +36 -1
  28. package/dist/db/index.d.ts.map +1 -1
  29. package/dist/db/index.js +124 -38
  30. package/dist/db/index.js.map +1 -1
  31. package/dist/db/migrations.d.ts +1 -1
  32. package/dist/db/migrations.d.ts.map +1 -1
  33. package/dist/db/migrations.js +52 -38
  34. package/dist/db/migrations.js.map +1 -1
  35. package/dist/db/queries.d.ts +42 -0
  36. package/dist/db/queries.d.ts.map +1 -1
  37. package/dist/db/queries.js +330 -163
  38. package/dist/db/queries.js.map +1 -1
  39. package/dist/db/schema.sql +208 -203
  40. package/dist/db/sqlite-adapter.d.ts +8 -3
  41. package/dist/db/sqlite-adapter.d.ts.map +1 -1
  42. package/dist/db/sqlite-adapter.js +45 -3
  43. package/dist/db/sqlite-adapter.js.map +1 -1
  44. package/dist/directory.js +5 -5
  45. package/dist/extraction/extraction-version.d.ts +1 -1
  46. package/dist/extraction/extraction-version.js +1 -1
  47. package/dist/extraction/generated-detection.d.ts +42 -11
  48. package/dist/extraction/generated-detection.d.ts.map +1 -1
  49. package/dist/extraction/generated-detection.js +141 -20
  50. package/dist/extraction/generated-detection.js.map +1 -1
  51. package/dist/extraction/index.d.ts +43 -1
  52. package/dist/extraction/index.d.ts.map +1 -1
  53. package/dist/extraction/index.js +150 -43
  54. package/dist/extraction/index.js.map +1 -1
  55. package/dist/extraction/languages/arkts.d.ts +70 -6
  56. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  57. package/dist/extraction/languages/arkts.js +958 -108
  58. package/dist/extraction/languages/arkts.js.map +1 -1
  59. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  60. package/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  61. package/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  62. package/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  63. package/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  64. package/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  65. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  66. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  67. package/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  68. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
  69. package/dist/extraction/wasm-runtime-flags.js +9 -6
  70. package/dist/extraction/wasm-runtime-flags.js.map +1 -1
  71. package/dist/graph-sources.d.ts +41 -0
  72. package/dist/graph-sources.d.ts.map +1 -0
  73. package/dist/graph-sources.js +82 -0
  74. package/dist/graph-sources.js.map +1 -0
  75. package/dist/index.d.ts +19 -1
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +80 -9
  78. package/dist/index.js.map +1 -1
  79. package/dist/installer/index.d.ts.map +1 -1
  80. package/dist/installer/index.js +0 -48
  81. package/dist/installer/index.js.map +1 -1
  82. package/dist/installer/instructions-template.js +9 -9
  83. package/dist/installer/targets/antigravity.js +1 -1
  84. package/dist/installer/targets/antigravity.js.map +1 -1
  85. package/dist/installer/targets/deveco.js +1 -1
  86. package/dist/installer/targets/deveco.js.map +1 -1
  87. package/dist/installer/targets/hermes.d.ts +1 -1
  88. package/dist/installer/targets/hermes.js +2 -2
  89. package/dist/installer/targets/hermes.js.map +1 -1
  90. package/dist/installer/targets/opencode.js +1 -1
  91. package/dist/installer/targets/opencode.js.map +1 -1
  92. package/dist/installer/targets/shared.js +1 -1
  93. package/dist/installer/targets/shared.js.map +1 -1
  94. package/dist/mcp/daemon-paths.d.ts +5 -4
  95. package/dist/mcp/daemon-paths.d.ts.map +1 -1
  96. package/dist/mcp/daemon-paths.js +28 -13
  97. package/dist/mcp/daemon-paths.js.map +1 -1
  98. package/dist/mcp/daemon-registry.d.ts.map +1 -1
  99. package/dist/mcp/daemon-registry.js +4 -1
  100. package/dist/mcp/daemon-registry.js.map +1 -1
  101. package/dist/mcp/daemon.d.ts +1 -1
  102. package/dist/mcp/daemon.js +1 -1
  103. package/dist/mcp/diff-impact.d.ts +131 -0
  104. package/dist/mcp/diff-impact.d.ts.map +1 -0
  105. package/dist/mcp/diff-impact.js +385 -0
  106. package/dist/mcp/diff-impact.js.map +1 -0
  107. package/dist/mcp/engine.d.ts.map +1 -1
  108. package/dist/mcp/engine.js +12 -3
  109. package/dist/mcp/engine.js.map +1 -1
  110. package/dist/mcp/explore-dedup.d.ts +137 -0
  111. package/dist/mcp/explore-dedup.d.ts.map +1 -0
  112. package/dist/mcp/explore-dedup.js +236 -0
  113. package/dist/mcp/explore-dedup.js.map +1 -0
  114. package/dist/mcp/explore-session-state.d.ts +217 -0
  115. package/dist/mcp/explore-session-state.d.ts.map +1 -0
  116. package/dist/mcp/explore-session-state.js +322 -0
  117. package/dist/mcp/explore-session-state.js.map +1 -0
  118. package/dist/mcp/index.d.ts.map +1 -1
  119. package/dist/mcp/index.js +4 -7
  120. package/dist/mcp/index.js.map +1 -1
  121. package/dist/mcp/liveness-watchdog.js +51 -51
  122. package/dist/mcp/proxy.d.ts.map +1 -1
  123. package/dist/mcp/proxy.js +5 -14
  124. package/dist/mcp/proxy.js.map +1 -1
  125. package/dist/mcp/query-worker.d.ts +1 -1
  126. package/dist/mcp/query-worker.js +1 -1
  127. package/dist/mcp/server-instructions.d.ts +7 -2
  128. package/dist/mcp/server-instructions.d.ts.map +1 -1
  129. package/dist/mcp/server-instructions.js +125 -47
  130. package/dist/mcp/server-instructions.js.map +1 -1
  131. package/dist/mcp/session.d.ts +14 -3
  132. package/dist/mcp/session.d.ts.map +1 -1
  133. package/dist/mcp/session.js +17 -14
  134. package/dist/mcp/session.js.map +1 -1
  135. package/dist/mcp/startup-handshake.d.ts +1 -1
  136. package/dist/mcp/startup-handshake.js +1 -1
  137. package/dist/mcp/tools.d.ts +138 -12
  138. package/dist/mcp/tools.d.ts.map +1 -1
  139. package/dist/mcp/tools.js +3279 -476
  140. package/dist/mcp/tools.js.map +1 -1
  141. package/dist/resolution/callback-synthesizer.d.ts +2 -1
  142. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  143. package/dist/resolution/callback-synthesizer.js +153 -53
  144. package/dist/resolution/callback-synthesizer.js.map +1 -1
  145. package/dist/resolution/frameworks/arkts-entry.d.ts.map +1 -1
  146. package/dist/resolution/frameworks/arkts-entry.js +20 -9
  147. package/dist/resolution/frameworks/arkts-entry.js.map +1 -1
  148. package/dist/resolution/frameworks/arkts-napi.d.ts +14 -0
  149. package/dist/resolution/frameworks/arkts-napi.d.ts.map +1 -1
  150. package/dist/resolution/frameworks/arkts-napi.js +169 -49
  151. package/dist/resolution/frameworks/arkts-napi.js.map +1 -1
  152. package/dist/resolution/index.d.ts.map +1 -1
  153. package/dist/resolution/index.js +1 -1
  154. package/dist/resolution/index.js.map +1 -1
  155. package/dist/resolution/memory-budget.d.ts +33 -0
  156. package/dist/resolution/memory-budget.d.ts.map +1 -1
  157. package/dist/resolution/memory-budget.js +58 -0
  158. package/dist/resolution/memory-budget.js.map +1 -1
  159. package/dist/resolution/resolver-pool.d.ts +2 -0
  160. package/dist/resolution/resolver-pool.d.ts.map +1 -1
  161. package/dist/resolution/resolver-pool.js +4 -0
  162. package/dist/resolution/resolver-pool.js.map +1 -1
  163. package/dist/search/query-utils.d.ts +116 -4
  164. package/dist/search/query-utils.d.ts.map +1 -1
  165. package/dist/search/query-utils.js +869 -60
  166. package/dist/search/query-utils.js.map +1 -1
  167. package/dist/spec/db/commit-node.js +4 -4
  168. package/dist/spec/db/fragment-node.js +10 -10
  169. package/dist/spec/db/fts.js +8 -8
  170. package/dist/spec/db/relations.js +88 -88
  171. package/dist/spec/db/schema.js +6 -6
  172. package/dist/spec/db/schema.sql +121 -121
  173. package/dist/spec/db/spec-node.js +4 -4
  174. package/dist/spec/llm/prompts.js +53 -53
  175. package/dist/types.d.ts +8 -0
  176. package/dist/types.d.ts.map +1 -1
  177. package/dist/ui/shimmer-progress.d.ts.map +1 -1
  178. package/dist/ui/shimmer-progress.js +4 -1
  179. package/dist/ui/shimmer-progress.js.map +1 -1
  180. package/dist/upgrade/index.d.ts +14 -26
  181. package/dist/upgrade/index.d.ts.map +1 -1
  182. package/dist/upgrade/index.js +28 -123
  183. package/dist/upgrade/index.js.map +1 -1
  184. package/dist/upgrade/remove-binary.d.ts +19 -19
  185. package/dist/upgrade/remove-binary.d.ts.map +1 -1
  186. package/dist/upgrade/remove-binary.js +20 -21
  187. package/dist/upgrade/remove-binary.js.map +1 -1
  188. package/dist/upgrade/update-check.d.ts +4 -3
  189. package/dist/upgrade/update-check.d.ts.map +1 -1
  190. package/dist/upgrade/update-check.js +4 -3
  191. package/dist/upgrade/update-check.js.map +1 -1
  192. package/package.json +65 -62
  193. package/dist/extraction/languages/arkts-viewtree.d.ts +0 -22
  194. package/dist/extraction/languages/arkts-viewtree.d.ts.map +0 -1
  195. package/dist/extraction/languages/arkts-viewtree.js +0 -133
  196. package/dist/extraction/languages/arkts-viewtree.js.map +0 -1
  197. package/dist/reasoning/config.d.ts +0 -45
  198. package/dist/reasoning/config.d.ts.map +0 -1
  199. package/dist/reasoning/config.js +0 -171
  200. package/dist/reasoning/config.js.map +0 -1
  201. package/dist/reasoning/credentials.d.ts +0 -5
  202. package/dist/reasoning/credentials.d.ts.map +0 -1
  203. package/dist/reasoning/credentials.js +0 -83
  204. package/dist/reasoning/credentials.js.map +0 -1
  205. package/dist/reasoning/login.d.ts +0 -21
  206. package/dist/reasoning/login.d.ts.map +0 -1
  207. package/dist/reasoning/login.js +0 -85
  208. package/dist/reasoning/login.js.map +0 -1
  209. package/dist/reasoning/reasoner.d.ts +0 -43
  210. package/dist/reasoning/reasoner.d.ts.map +0 -1
  211. package/dist/reasoning/reasoner.js +0 -308
  212. package/dist/reasoning/reasoner.js.map +0 -1
  213. package/dist/spec/evolve/llm-client.d.ts +0 -50
  214. package/dist/spec/evolve/llm-client.d.ts.map +0 -1
  215. package/dist/spec/evolve/llm-client.js +0 -176
  216. package/dist/spec/evolve/llm-client.js.map +0 -1
  217. package/dist/spec/evolve/logic-checker.d.ts +0 -12
  218. package/dist/spec/evolve/logic-checker.d.ts.map +0 -1
  219. package/dist/spec/evolve/logic-checker.js +0 -24
  220. package/dist/spec/evolve/logic-checker.js.map +0 -1
  221. package/dist/spec/llm/index.d.ts +0 -3
  222. package/dist/spec/llm/index.d.ts.map +0 -1
  223. package/dist/spec/llm/index.js +0 -11
  224. package/dist/spec/llm/index.js.map +0 -1
  225. package/dist/spec/mining/diff-parser.d.ts +0 -33
  226. package/dist/spec/mining/diff-parser.d.ts.map +0 -1
  227. package/dist/spec/mining/diff-parser.js +0 -166
  228. package/dist/spec/mining/diff-parser.js.map +0 -1
  229. package/dist/spec/mining/git-scanner.d.ts +0 -103
  230. package/dist/spec/mining/git-scanner.d.ts.map +0 -1
  231. package/dist/spec/mining/git-scanner.js +0 -307
  232. package/dist/spec/mining/git-scanner.js.map +0 -1
  233. package/dist/spec/mining/pipeline.d.ts +0 -53
  234. package/dist/spec/mining/pipeline.d.ts.map +0 -1
  235. package/dist/spec/mining/pipeline.js +0 -178
  236. package/dist/spec/mining/pipeline.js.map +0 -1
  237. package/dist/spec/mining/scope-resolver.d.ts +0 -45
  238. package/dist/spec/mining/scope-resolver.d.ts.map +0 -1
  239. package/dist/spec/mining/scope-resolver.js +0 -103
  240. package/dist/spec/mining/scope-resolver.js.map +0 -1
  241. package/dist/spec/mining/spec-extractor.d.ts +0 -69
  242. package/dist/spec/mining/spec-extractor.d.ts.map +0 -1
  243. package/dist/spec/mining/spec-extractor.js +0 -369
  244. package/dist/spec/mining/spec-extractor.js.map +0 -1
  245. package/dist/spec/utils.d.ts +0 -167
  246. package/dist/spec/utils.d.ts.map +0 -1
  247. package/dist/spec/utils.js +0 -463
  248. package/dist/spec/utils.js.map +0 -1
  249. package/dist/telemetry/index.d.ts +0 -143
  250. package/dist/telemetry/index.d.ts.map +0 -1
  251. package/dist/telemetry/index.js +0 -541
  252. package/dist/telemetry/index.js.map +0 -1
  253. package/scripts/_tmp-cfwk-resolve.log +0 -0
  254. package/scripts/_tmp-cfwk-sig.log +0 -0
  255. package/scripts/_tmp-cfwk-vt.log +0 -0
  256. package/scripts/add-lang/bench.sh +0 -60
  257. package/scripts/add-lang/check-grammar.mjs +0 -75
  258. package/scripts/add-lang/dump-ast.mjs +0 -103
  259. package/scripts/add-lang/verify-extraction.mjs +0 -70
  260. package/scripts/agent-eval/ab-adoption.sh +0 -91
  261. package/scripts/agent-eval/ab-hook.sh +0 -86
  262. package/scripts/agent-eval/ab-impl.sh +0 -78
  263. package/scripts/agent-eval/ab-new-vs-baseline.sh +0 -102
  264. package/scripts/agent-eval/ab-sufficiency.sh +0 -78
  265. package/scripts/agent-eval/arms-F.sh +0 -21
  266. package/scripts/agent-eval/arms-matrix.sh +0 -37
  267. package/scripts/agent-eval/audit.sh +0 -68
  268. package/scripts/agent-eval/bench-readme.sh +0 -28
  269. package/scripts/agent-eval/bench-why-repo.sh +0 -22
  270. package/scripts/agent-eval/block-read-hook.sh +0 -19
  271. package/scripts/agent-eval/hook-settings.json +0 -15
  272. package/scripts/agent-eval/itrun.sh +0 -120
  273. package/scripts/agent-eval/offload-eval-3arm.sh +0 -72
  274. package/scripts/agent-eval/offload-eval-cost.mjs +0 -133
  275. package/scripts/agent-eval/offload-eval-effort.mjs +0 -108
  276. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +0 -25
  277. package/scripts/agent-eval/offload-eval-frontload.sh +0 -47
  278. package/scripts/agent-eval/offload-eval-ground-truth.json +0 -18
  279. package/scripts/agent-eval/offload-eval-hook.mjs +0 -84
  280. package/scripts/agent-eval/offload-eval-judge.mjs +0 -103
  281. package/scripts/agent-eval/offload-eval-matrix.sh +0 -20
  282. package/scripts/agent-eval/offload-eval-metrics.mjs +0 -94
  283. package/scripts/agent-eval/offload-eval-refs1.sh +0 -50
  284. package/scripts/agent-eval/offload-eval-setup.sh +0 -24
  285. package/scripts/agent-eval/offload-eval-styles.sh +0 -72
  286. package/scripts/agent-eval/offload-eval-summarize.mjs +0 -68
  287. package/scripts/agent-eval/offload-eval.md +0 -76
  288. package/scripts/agent-eval/parse-arms.mjs +0 -116
  289. package/scripts/agent-eval/parse-bench-readme.mjs +0 -84
  290. package/scripts/agent-eval/parse-run.mjs +0 -45
  291. package/scripts/agent-eval/parse-session.mjs +0 -93
  292. package/scripts/agent-eval/probe-context.mjs +0 -21
  293. package/scripts/agent-eval/probe-explore.mjs +0 -40
  294. package/scripts/agent-eval/probe-node.mjs +0 -20
  295. package/scripts/agent-eval/probe-sweep.mjs +0 -119
  296. package/scripts/agent-eval/probe-trace.mjs +0 -20
  297. package/scripts/agent-eval/redirect-read-hook.sh +0 -38
  298. package/scripts/agent-eval/repro-concurrent-explore.mjs +0 -119
  299. package/scripts/agent-eval/repro-daemon-clients.mjs +0 -125
  300. package/scripts/agent-eval/run-agent.sh +0 -34
  301. package/scripts/agent-eval/run-all.sh +0 -75
  302. package/scripts/agent-eval/run-arms.sh +0 -56
  303. package/scripts/agent-eval/seq-matrix.mjs +0 -137
  304. package/scripts/bench-arkts-init-rss.log +0 -0
  305. package/scripts/build-bundle.sh +0 -123
  306. package/scripts/exp_boundary_eval/README.md +0 -247
  307. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  308. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-38.pyc +0 -0
  309. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  310. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-38.pyc +0 -0
  311. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-38.pyc +0 -0
  312. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-310.pyc +0 -0
  313. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-38.pyc +0 -0
  314. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  315. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-38.pyc +0 -0
  316. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  317. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-38.pyc +0 -0
  318. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  319. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-38.pyc +0 -0
  320. package/scripts/exp_boundary_eval/__pycache__/win_mcp_launcher.cpython-38.pyc +0 -0
  321. package/scripts/exp_boundary_eval/_test_mcp_chain.py +0 -78
  322. package/scripts/exp_boundary_eval/_test_stdin.py +0 -8
  323. package/scripts/exp_boundary_eval/_utils.py +0 -1116
  324. package/scripts/exp_boundary_eval/analyze.py +0 -1313
  325. package/scripts/exp_boundary_eval/deveco_arm.py +0 -519
  326. package/scripts/exp_boundary_eval/run_all.py +0 -378
  327. package/scripts/exp_boundary_eval/run_one.py +0 -165
  328. package/scripts/exp_boundary_eval/run_session.py +0 -158
  329. package/scripts/exp_boundary_eval/setup.py +0 -120
  330. package/scripts/exp_boundary_eval/win_mcp_launcher.py +0 -73
  331. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +0 -36
  332. package/scripts/exp_boundary_eval/win_node_launcher.py +0 -24
  333. package/scripts/extract-release-notes.mjs +0 -130
  334. package/scripts/local-install.sh +0 -41
  335. package/scripts/npm-sdk.js +0 -75
  336. package/scripts/npm-shim.js +0 -275
  337. package/scripts/ohos-sdk-publish.mjs +0 -133
  338. package/scripts/pack-npm.sh +0 -119
  339. package/scripts/prepare-release.mjs +0 -270
  340. package/scripts/probe-arkts-mem-why-run.log +0 -0
  341. package/scripts/probe-banner-livecard-ir.log +0 -0
  342. package/scripts/probe-cfwk-ast.stderr.log +0 -0
  343. package/scripts/probe-cfwk-ast.stdout.log +0 -0
  344. package/scripts/probe-cfwk-attr-shape.log +0 -0
  345. package/scripts/probe-cfwk-cfgdump.stderr.log +0 -0
  346. package/scripts/probe-cfwk-cfgdump.stdout.log +0 -0
  347. package/scripts/probe-cfwk-cvc.stderr.log +0 -0
  348. package/scripts/probe-cfwk-cvc.stdout.log +0 -0
  349. package/scripts/probe-cfwk-diag2.log +0 -0
  350. package/scripts/probe-cfwk-diag3.log +0 -0
  351. package/scripts/probe-cfwk-fedbg.stderr.log +0 -0
  352. package/scripts/probe-cfwk-fedbg.stdout.log +0 -0
  353. package/scripts/probe-cfwk-fileresult.log +0 -0
  354. package/scripts/probe-cfwk-fix.stderr.log +0 -0
  355. package/scripts/probe-cfwk-fix.stdout.log +0 -0
  356. package/scripts/probe-cfwk-fix2.stderr.log +0 -0
  357. package/scripts/probe-cfwk-fix2.stdout.log +0 -0
  358. package/scripts/probe-cfwk-fix3.stderr.log +0 -0
  359. package/scripts/probe-cfwk-fix3.stdout.log +0 -0
  360. package/scripts/probe-cfwk-foreach.log +0 -0
  361. package/scripts/probe-cfwk-getmethod-throw.log +0 -0
  362. package/scripts/probe-cfwk-hg-extract.log +0 -0
  363. package/scripts/probe-cfwk-pr1003-noprior.stderr.log +0 -0
  364. package/scripts/probe-cfwk-pr1003-noprior.stdout.log +0 -0
  365. package/scripts/probe-cfwk-pr1003.stderr.log +0 -0
  366. package/scripts/probe-cfwk-pr1003.stdout.log +0 -0
  367. package/scripts/probe-cfwk-preroot-noprior.stderr.log +0 -0
  368. package/scripts/probe-cfwk-preroot-noprior.stdout.log +0 -0
  369. package/scripts/probe-cfwk-preroot-prior.stderr.log +0 -0
  370. package/scripts/probe-cfwk-preroot-prior.stdout.log +0 -0
  371. package/scripts/probe-cfwk-preroot-skipstate.stderr.log +0 -0
  372. package/scripts/probe-cfwk-preroot-skipstate.stdout.log +0 -0
  373. package/scripts/probe-cfwk-resolve-sim.log +0 -0
  374. package/scripts/probe-cfwk-tree-shape.log +0 -0
  375. package/scripts/probe-cfwk-walk-abort.log +0 -0
  376. package/scripts/probe-cfwk.log +0 -0
  377. package/scripts/probe-force-index.log +0 -0
  378. package/scripts/probe-no-force-index.log +0 -0
  379. package/scripts/probe-samefile-ir.stderr.log +0 -0
  380. package/scripts/probe-samefile-ir.stdout.log +0 -224
  381. package/scripts/probe-sdk-vs-project.log +0 -0
  382. package/scripts/probe-viewtree-downgrade.log +0 -0
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env node
2
- // Extract one eval run's metrics from its Claude stream-json transcript + the
3
- // offload usage sidecar log, emit ONE merged JSON line.
4
- //
5
- // Usage: extract-metrics.mjs --run <run.jsonl> --usage <usage.jsonl|-> \
6
- // --arm <a> --rep <n> --repo <r> --tier <t> --q <question>
7
- import { readFileSync, existsSync } from 'fs';
8
-
9
- const args = {};
10
- for (let i = 2; i < process.argv.length; i += 2) args[process.argv[i].replace(/^--/, '')] = process.argv[i + 1];
11
-
12
- const runFile = args.run;
13
- const lines = existsSync(runFile) ? readFileSync(runFile, 'utf8').split('\n').filter(Boolean) : [];
14
-
15
- const toolCounts = {};
16
- let result = null;
17
- const tok = { gen: 0, fresh: 0, cached: 0 };
18
- const offloadAnswers = [];
19
- let exploreResults = 0; // tool_results from explore (offload or raw)
20
- let lastAssistantText = '';
21
-
22
- for (const line of lines) {
23
- let ev; try { ev = JSON.parse(line); } catch { continue; }
24
-
25
- // per-turn token usage (authoritative token measure; result.usage is last-turn only)
26
- const u = ev.message?.usage;
27
- if (u) {
28
- tok.gen += u.output_tokens || 0;
29
- tok.fresh += (u.input_tokens || 0) + (u.cache_creation_input_tokens || 0);
30
- tok.cached += u.cache_read_input_tokens || 0;
31
- }
32
-
33
- if (ev.type === 'assistant' && Array.isArray(ev.message?.content)) {
34
- for (const b of ev.message.content) {
35
- if (b.type === 'tool_use') toolCounts[b.name] = (toolCounts[b.name] || 0) + 1;
36
- if (b.type === 'text' && b.text?.trim()) lastAssistantText = b.text.trim();
37
- }
38
- }
39
- // tool_results arrive in user messages
40
- if (ev.type === 'user' && Array.isArray(ev.message?.content)) {
41
- for (const b of ev.message.content) {
42
- if (b.type !== 'tool_result') continue;
43
- const text = Array.isArray(b.content)
44
- ? b.content.map(c => (typeof c === 'string' ? c : c.text || '')).join('')
45
- : (typeof b.content === 'string' ? b.content : '');
46
- // An offload answer is either the 'plain'/'report' synthesis (carries the
47
- // "Synthesized by HomeGraph" footer) or a 'refs' answer (carries the re-expanded
48
- // "### Referenced source — verbatim" appendix). A refs call that cited nothing
49
- // valid falls back to RAW source, which is correctly counted as a raw explore below.
50
- if (/Synthesized by HomeGraph|### Referenced source — verbatim/.test(text)) { offloadAnswers.push(text); exploreResults++; }
51
- else if (/Found \d+ symbols? across|\*\*Exploration:/.test(text)) exploreResults++;
52
- }
53
- }
54
- if (ev.type === 'result') result = ev;
55
- }
56
-
57
- // offload usage sidecar (HomeGraph AI tokens + cost) — one JSON line per offload call
58
- const ai = { calls: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, credits: 0, costUsd: 0, ms: 0 };
59
- if (args.usage && args.usage !== '-' && existsSync(args.usage)) {
60
- for (const line of readFileSync(args.usage, 'utf8').split('\n').filter(Boolean)) {
61
- let e; try { e = JSON.parse(line); } catch { continue; }
62
- ai.calls++;
63
- ai.promptTokens += e.promptTokens || 0;
64
- ai.completionTokens += e.completionTokens || 0;
65
- ai.totalTokens += e.totalTokens || 0;
66
- ai.credits += e.creditsCharged || 0;
67
- ai.costUsd += e.costUsd || 0;
68
- ai.ms += e.ms || 0;
69
- }
70
- }
71
-
72
- // front-load hook fired iff its injected header appears in the transcript
73
- const frontload = lines.some(l => l.includes('auto-retrieved for this question'));
74
- const get = (n) => toolCounts[n] || 0;
75
- const read = get('Read');
76
- const grep = get('Grep') + get('Bash') + get('Glob');
77
- const explore = get('mcp__homegraph__homegraph_explore');
78
- const cgAny = Object.keys(toolCounts).filter(k => /mcp__homegraph__/.test(k)).reduce((s, k) => s + toolCounts[k], 0);
79
-
80
- const out = {
81
- repo: args.repo, tier: args.tier, arm: args.arm, rep: Number(args.rep), question: args.q,
82
- ok: result?.subtype === 'success',
83
- durationSec: result ? +(result.duration_ms / 1000).toFixed(1) : null,
84
- numTurns: result?.num_turns ?? null,
85
- costUsdMain: result ? +(result.total_cost_usd || 0).toFixed(4) : null,
86
- tokGen: tok.gen, tokFresh: tok.fresh, tokCached: tok.cached, tokBillable: tok.gen + tok.fresh,
87
- read, grep, explore, cgAny, frontload,
88
- offloadFired: offloadAnswers.length,
89
- ai,
90
- // text payloads for the accuracy judge (kept separate; large)
91
- finalAnswer: (result?.result || lastAssistantText || '').slice(0, 8000),
92
- offloadAnswers: offloadAnswers.map(a => a.slice(0, 6000)),
93
- };
94
- process.stdout.write(JSON.stringify(out) + '\n');
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ONE offload run on ONE indexed repo at a given offload STYLE (plain|refs), so we can
3
- # watch a single agent transcript at a time (the user's one-run-at-a-time methodology).
4
- # The OFFLOAD reasoning runs in the prewarmed DAEMON process, so the style env must be
5
- # set on BOTH the daemon and the client MCP config. Writes one metrics line to RESULTS
6
- # and leaves the raw stream-json at $RUNS/<repo>-<style>-<n>.jsonl for inspection.
7
- #
8
- # Usage: offload-eval-refs1.sh <indexed-repo> <style> <n> "<question>"
9
- set -uo pipefail
10
- HERE="$(cd "$(dirname "$0")" && pwd)"; ENGINE="$(cd "$HERE/../.." && pwd)"; BIN="$ENGINE/dist/bin/homegraph.js"
11
- OUT="${AGENT_EVAL_OUT:-/tmp/cg-offload-eval}"; RUNS="$OUT/runs"; EXTRACT="$HERE/offload-eval-metrics.mjs"
12
- TARGET="${1:?repo}"; STYLE="${2:?style}"; N="${3:?run-tag}"; Q="${4:?question}"
13
- RESULTS="${RESULTS:-$OUT/results-refs.jsonl}"; REPO=$(basename "$TARGET"); TARGET=$(cd "$TARGET" && pwd -P)
14
- mkdir -p "$RUNS"; command -v claude >/dev/null || { echo "no claude"; exit 1; }
15
- USAGE="$RUNS/$REPO-$STYLE-usage.jsonl"; : > "$USAGE"
16
- CFG="$RUNS/mcp-$REPO-$STYLE.json"
17
- # `raw` is a pseudo-style: homegraph attached but the offload DISABLED (the ceiling —
18
- # verbatim source, no reasoning model). Any other value is an offload style (plain|refs).
19
- if [ "$STYLE" = "raw" ]; then
20
- DAEMON_ENV="HOMEGRAPH_OFFLOAD_DISABLE=1"
21
- printf '{"mcpServers":{"homegraph":{"command":"env","args":["HOMEGRAPH_WASM_RELAUNCHED=1","HOMEGRAPH_OFFLOAD_DISABLE=1","node","%s","serve","--mcp","--path","%s"]}}}' \
22
- "$BIN" "$TARGET" > "$CFG"
23
- USAGE="-"
24
- else
25
- DAEMON_ENV="HOMEGRAPH_OFFLOAD_STYLE=$STYLE HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE"
26
- printf '{"mcpServers":{"homegraph":{"command":"env","args":["HOMEGRAPH_WASM_RELAUNCHED=1","HOMEGRAPH_OFFLOAD_STYLE=%s","HOMEGRAPH_OFFLOAD_USAGE_LOG=%s","node","%s","serve","--mcp","--path","%s"]}}}' \
27
- "$STYLE" "$USAGE" "$BIN" "$TARGET" > "$CFG"
28
- fi
29
-
30
- # Prewarm a persistent daemon carrying the SAME offload config (it does the reasoning).
31
- pkill -9 -f "serve --mcp --path $TARGET" 2>/dev/null; rm -f "$TARGET/.homegraph/daemon.sock" 2>/dev/null; sleep 0.6
32
- env $DAEMON_ENV HOMEGRAPH_DAEMON_IDLE_TIMEOUT_MS=1800000 \
33
- node "$BIN" serve --mcp --path "$TARGET" </dev/null >/dev/null 2>&1 &
34
- node -e 'const fs=require("fs");let n=0;const t=setInterval(()=>{if(fs.existsSync(process.argv[1]+"/.homegraph/daemon.sock")){clearInterval(t);process.exit(0)}if(n++>150){clearInterval(t);process.exit(1)}},100)' "$TARGET" \
35
- && echo "daemon warm ($STYLE)" || echo "WARN daemon never bound"
36
-
37
- tag="$REPO-$STYLE-$N"
38
- echo "== run $tag =="
39
- # DISALLOW (optional): block tools that confound the offload-sufficiency signal —
40
- # chiefly "Agent" (sub-agent delegation: the spawned Explore subagent has low MCP
41
- # salience, ignores homegraph, and thrashes via Bash+Read, making the A/B noise).
42
- ( cd "$TARGET" && claude -p "$Q" --output-format stream-json --verbose --permission-mode bypassPermissions \
43
- --model "${MODEL:-sonnet}" --effort "${EFFORT:-high}" --max-budget-usd 4 \
44
- ${DISALLOW:+--disallowedTools "$DISALLOW"} \
45
- --strict-mcp-config --mcp-config "$CFG" </dev/null > "$RUNS/$tag.jsonl" 2>"$RUNS/$tag.err" )
46
- node "$EXTRACT" --run "$RUNS/$tag.jsonl" --usage "$USAGE" --arm "offload-$STYLE" --rep "$N" \
47
- --repo "$REPO" --tier "complex" --q "$Q" >> "$RESULTS"
48
- node -e 'const o=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8").trim().split("\n").pop());console.log(` [${o.arm} #${o.rep}] ${o.durationSec}s | main $${o.costUsdMain} ${o.tokBillable} tok | read=${o.read} grep=${o.grep} explore=${o.explore} offload=${o.offloadFired} | AI ${o.ai.calls}call/${o.ai.totalTokens}tok/$${o.ai.costUsd.toFixed(4)} | ok=${o.ok}`)' "$RESULTS"
49
- pkill -9 -f "serve --mcp --path $TARGET" 2>/dev/null; rm -f "$TARGET/.homegraph/daemon.sock" 2>/dev/null
50
- echo "raw transcript: $RUNS/$tag.jsonl"
@@ -1,24 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Clone + index the 4 "not-trained-on" eval repos into $AGENT_EVAL_OUT/repos. These were
3
- # selected via a no-tools memory-probe gate (Sonnet cannot answer their flow questions from
4
- # memory — so the no-homegraph baseline is honest). Env: AGENT_EVAL_OUT=<scratch dir>
5
- set -uo pipefail
6
- HERE="$(cd "$(dirname "$0")" && pwd)"
7
- ENGINE="$(cd "$HERE/../.." && pwd)"
8
- BIN="$ENGINE/dist/bin/homegraph.js"
9
- OUT="${AGENT_EVAL_OUT:-/tmp/cg-offload-eval}"
10
- ROOT="$OUT/repos"; mkdir -p "$ROOT"
11
- export HOMEGRAPH_TELEMETRY=0 DO_NOT_TRACK=1
12
- [ -f "$BIN" ] || { echo "engine not built: run 'npm run build' in $ENGINE first"; exit 1; }
13
-
14
- clone_index() { # url name
15
- echo "=== $2: clone ==="; rm -rf "$ROOT/$2"
16
- git clone --quiet --depth 1 "$1" "$ROOT/$2" || { echo " clone FAILED"; return 1; }
17
- echo "=== $2: index ==="
18
- node "$BIN" init "$ROOT/$2" 2>&1 | grep -iE 'indexed|nodes|edges|error' | tail -2
19
- }
20
- clone_index https://github.com/MTKruto/MTKruto.git mtkruto # small (~322 TS)
21
- clone_index https://github.com/mvdicarlo/postybirb-plus.git postybirb # medium (~608 TS)
22
- clone_index https://github.com/shapeshift/web.git shapeshift # complex (~3.2k TS, 35-pkg monorepo)
23
- clone_index https://github.com/trezor/trezor-suite.git trezor # large (~8k TS monorepo)
24
- echo "###### SETUP DONE -> $ROOT"
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Offload reasoning-OUTPUT-STYLE A/B — all homegraph-on, isolating the Worker's
3
- # output shape's effect on main-session tokens / latency / accuracy:
4
- # raw : HOMEGRAPH_OFFLOAD_DISABLE=1 (verbatim explore source, the floor)
5
- # refs : managed offload, default (Cerebras map re-expanded to verbatim, ~24K)
6
- # map : managed offload, STYLE=map (compact reasoned map + file:line anchors, ~1-3K)
7
- # src : managed offload, STYLE=src (map + cited line ranges only, ~1-5K)
8
- # Delegation BLOCKED by default (DISALLOW=Agent) so we measure the offload payload's
9
- # effect on the main Sonnet agent, not whether it spawns a Haiku Explore subagent.
10
- #
11
- # Usage: offload-eval-styles.sh <indexed-repo> <reps> "<question>"
12
- # Env: RESULTS=<file> AGENT_EVAL_OUT=<dir> REP_START=1 DISALLOW=Agent MODEL/EFFORT
13
- set -uo pipefail
14
- HERE="$(cd "$(dirname "$0")" && pwd)"
15
- ENGINE="$(cd "$HERE/../.." && pwd)"
16
- BIN="$ENGINE/dist/bin/homegraph.js"
17
- OUT="${AGENT_EVAL_OUT:-/tmp/cg-offload-eval}"
18
- TARGET="${1:?usage: offload-eval-styles.sh <indexed-repo> <reps> \"<question>\"}"
19
- REPS="${2:?reps}"; Q="${3:?question}"
20
- RUNS="$OUT/runs"; EXTRACT="$HERE/offload-eval-metrics.mjs"
21
- RESULTS="${RESULTS:-$OUT/results-styles.jsonl}"
22
- REPO=$(basename "$TARGET")
23
- DISALLOW="${DISALLOW-Agent}" # default: block delegation. `DISALLOW= ` to allow.
24
- START="${REP_START:-1}"; END=$((START + REPS - 1))
25
- mkdir -p "$RUNS"
26
- command -v claude >/dev/null || { echo "no claude on PATH"; exit 1; }
27
- [ -d "$TARGET/.homegraph" ] || { echo "not indexed: $TARGET"; exit 1; }
28
- TARGET=$(cd "$TARGET" && pwd -P)
29
-
30
- prewarm() { # path extra-env
31
- pkill -9 -f "serve --mcp --path $1" 2>/dev/null; rm -f "$1/.homegraph/daemon.sock" 2>/dev/null; sleep 0.6
32
- env ${2:-} HOMEGRAPH_DAEMON_IDLE_TIMEOUT_MS=1800000 node "$BIN" serve --mcp --path "$1" </dev/null >/dev/null 2>&1 &
33
- node -e 'const fs=require("fs");let n=0;const t=setInterval(()=>{if(fs.existsSync(process.argv[1]+"/.homegraph/daemon.sock")){clearInterval(t);process.exit(0)}if(n++>150){clearInterval(t);process.exit(1)}},100)' "$1" \
34
- && echo " daemon warm" || echo " WARN daemon never bound"
35
- }
36
- kill_daemon() { pkill -9 -f "serve --mcp --path $TARGET" 2>/dev/null; rm -f "$TARGET/.homegraph/daemon.sock" 2>/dev/null; sleep 1; }
37
-
38
- run() { # arm rep mcp-config usage-log-or-dash
39
- local arm="$1" rep="$2" cfg="$3" usage="$4" tag="$REPO-$1-$2"
40
- [ "$usage" != "-" ] && : > "$usage"
41
- ( cd "$TARGET" && claude -p "$Q" \
42
- --output-format stream-json --verbose --permission-mode bypassPermissions \
43
- --model "${MODEL:-sonnet}" --effort "${EFFORT:-high}" --max-budget-usd 4 \
44
- ${DISALLOW:+--disallowedTools "$DISALLOW"} \
45
- --strict-mcp-config --mcp-config "$cfg" \
46
- </dev/null > "$RUNS/$tag.jsonl" 2>"$RUNS/$tag.err" )
47
- node "$EXTRACT" --run "$RUNS/$tag.jsonl" --usage "$usage" --arm "$arm" --rep "$rep" \
48
- --repo "$REPO" --tier styles --q "$Q" >> "$RESULTS"
49
- node -e 'const o=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8").trim().split("\n").pop());console.log(` [${o.arm} #${o.rep}] ${o.durationSec}s | ${o.tokBillable} billable tok | read=${o.read} grep=${o.grep} explore=${o.explore} offload=${o.offloadFired} | AI ${o.ai.calls}c/${o.ai.totalTokens}t | ok=${o.ok}`)' "$RESULTS"
50
- }
51
-
52
- # MCP configs: env baked into the daemon-spawn command claude uses.
53
- USAGE="$RUNS/$REPO-usage.jsonl"
54
- mkcfg() { # file extra-env-pairs(JSON array entries, comma-led or empty)
55
- printf '{"mcpServers":{"homegraph":{"command":"env","args":["HOMEGRAPH_WASM_RELAUNCHED=1"%s,"node","%s","serve","--mcp","--path","%s"]}}}' "$1" "$BIN" "$TARGET"
56
- }
57
- CFG_RAW="$RUNS/mcp-sty-raw-$REPO.json"; mkcfg ',"HOMEGRAPH_OFFLOAD_DISABLE=1"' > "$CFG_RAW"
58
- CFG_REFS="$RUNS/mcp-sty-refs-$REPO.json"; mkcfg ",\"HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE\"" > "$CFG_REFS"
59
- CFG_MAP="$RUNS/mcp-sty-map-$REPO.json"; mkcfg ",\"HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE\",\"HOMEGRAPH_OFFLOAD_STYLE=map\"" > "$CFG_MAP"
60
- CFG_SRC="$RUNS/mcp-sty-src-$REPO.json"; mkcfg ",\"HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE\",\"HOMEGRAPH_OFFLOAD_STYLE=src\"" > "$CFG_SRC"
61
-
62
- echo "###### repo=$REPO reps=$START..$END model=${MODEL:-sonnet}/${EFFORT:-high} disallow=${DISALLOW:-<none>}"
63
- echo "###### Q=$Q"
64
- echo "== ARM raw =="; prewarm "$TARGET" "HOMEGRAPH_OFFLOAD_DISABLE=1"
65
- for r in $(seq "$START" "$END"); do run raw "$r" "$CFG_RAW" "-"; done; kill_daemon
66
- echo "== ARM refs =="; prewarm "$TARGET" "HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE"
67
- for r in $(seq "$START" "$END"); do run refs "$r" "$CFG_REFS" "$USAGE"; done; kill_daemon
68
- echo "== ARM map =="; prewarm "$TARGET" "HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE HOMEGRAPH_OFFLOAD_STYLE=map"
69
- for r in $(seq "$START" "$END"); do run map "$r" "$CFG_MAP" "$USAGE"; done; kill_daemon
70
- echo "== ARM src =="; prewarm "$TARGET" "HOMEGRAPH_OFFLOAD_USAGE_LOG=$USAGE HOMEGRAPH_OFFLOAD_STYLE=src"
71
- for r in $(seq "$START" "$END"); do run src "$r" "$CFG_SRC" "$USAGE"; done; kill_daemon
72
- echo "###### DONE $REPO — judge: node $HERE/offload-eval-judge.mjs --results $RESULTS --truth $HERE/offload-eval-ground-truth.json --out $OUT/judged-styles.jsonl"
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env node
2
- // Aggregate judged.jsonl (or results.jsonl) into a per-repo, per-arm report:
3
- // time, main tokens/cost, AI tokens/cost, total cost, tool mix, accuracy.
4
- // Usage: summarize.mjs <judged-or-results.jsonl>
5
- import { readFileSync } from 'fs';
6
- const rows = readFileSync(process.argv[2], 'utf8').split('\n').filter(Boolean).map(l => JSON.parse(l));
7
-
8
- const med = (xs) => { const a = xs.filter(x => x != null).sort((p, q) => p - q); if (!a.length) return null; const m = Math.floor(a.length / 2); return a.length % 2 ? a[m] : (a[m - 1] + a[m]) / 2; };
9
- const rng = (xs) => { const a = xs.filter(x => x != null); return a.length ? `${Math.min(...a)}–${Math.max(...a)}` : '—'; };
10
- const d2 = (x) => x == null ? '—' : (+x).toFixed(2);
11
- const d3 = (x) => x == null ? '—' : (+x).toFixed(3);
12
- const d4 = (x) => x == null ? '—' : (+x).toFixed(4);
13
-
14
- const ARM_ORDER = ['frontload', 'offload', 'raw', 'nocg'];
15
- const byRepo = {};
16
- for (const r of rows) (byRepo[r.repo] ??= {});
17
- for (const r of rows) ((byRepo[r.repo][r.arm] ??= []).push(r));
18
-
19
- const verdictTally = (rs, field) => {
20
- const t = { pass: 0, partial: 0, fail: 0, error: 0 };
21
- for (const r of rs) { const v = r[field]?.verdict; if (v in t) t[v]++; }
22
- return t;
23
- };
24
-
25
- for (const repo of Object.keys(byRepo)) {
26
- const tier = byRepo[repo][Object.keys(byRepo[repo])[0]][0].tier;
27
- console.log(`\n${'='.repeat(78)}\n${repo} [${tier}]\n${'='.repeat(78)}`);
28
- console.log(`${'arm'.padEnd(9)} n ${'time(s)'.padStart(9)} ${'mainCost'.padStart(9)} ${'aiCost'.padStart(8)} ${'totCost'.padStart(8)} ${'mainTok'.padStart(8)} ${'aiTok'.padStart(7)} ${'rd'.padStart(3)} ${'gr'.padStart(3)} ${'exp'.padStart(3)} ${'off'.padStart(3)} e2e(P/p/F) fidScore`);
29
- for (const arm of ARM_ORDER) {
30
- const rs = byRepo[repo][arm]; if (!rs) continue;
31
- const n = rs.length;
32
- const mainCost = med(rs.map(r => r.costUsdMain));
33
- const aiCost = med(rs.map(r => r.ai?.costUsd ?? 0));
34
- const totCost = (mainCost ?? 0) + (aiCost ?? 0);
35
- const e2e = verdictTally(rs, 'e2e');
36
- const fidScores = arm === 'offload' ? rs.flatMap(r => r.fidelity?.scores ?? []) : [];
37
- const fid = fidScores.length ? med(fidScores) : null;
38
- const fab = arm === 'offload' && rs.some(r => r.fidelity?.anyFabrication);
39
- const e2eScore = med(rs.map(r => r.e2e?.score).filter(x => x != null));
40
- console.log(
41
- `${arm.padEnd(9)} ${String(n).padStart(1)} ${String(med(rs.map(r => r.durationSec))).padStart(9)} ` +
42
- `${('$' + d3(mainCost)).padStart(9)} ${('$' + d3(aiCost)).padStart(8)} ${('$' + d3(totCost)).padStart(8)} ` +
43
- `${String(Math.round(med(rs.map(r => r.tokBillable)) / 1000) + 'k').padStart(8)} ${String(Math.round(med(rs.map(r => r.ai?.totalTokens ?? 0)) / 1000) + 'k').padStart(7)} ` +
44
- `${String(med(rs.map(r => r.read))).padStart(3)} ${String(med(rs.map(r => r.grep))).padStart(3)} ${String(med(rs.map(r => r.explore))).padStart(3)} ${String(med(rs.map(r => r.offloadFired))).padStart(3)} ` +
45
- `${(e2e.pass + '/' + e2e.partial + '/' + e2e.fail).padStart(9)} ${e2eScore != null ? 'e2e=' + e2eScore : ''} ${fid != null ? 'fid=' + fid + (fab ? ' FAB!' : '') : ''}`
46
- );
47
- }
48
- // ranges line for the two key metrics (variance matters)
49
- for (const arm of ARM_ORDER) {
50
- const rs = byRepo[repo][arm]; if (!rs) continue;
51
- console.log(` ${arm} ranges: time ${rng(rs.map(r => r.durationSec))}s · mainCost $${rng(rs.map(r => r.costUsdMain))} · read ${rng(rs.map(r => r.read))} · explore ${rng(rs.map(r => r.explore))} · offloadFired ${rng(rs.map(r => r.offloadFired))}`);
52
- }
53
- }
54
-
55
- // Cross-repo roll-up: offload vs raw vs nocg deltas
56
- console.log(`\n${'='.repeat(78)}\nCROSS-REPO SUMMARY (medians per repo, then averaged)\n${'='.repeat(78)}`);
57
- console.log(`${'repo'.padEnd(12)} ${'arm'.padEnd(8)} ${'time'.padStart(7)} ${'totCost'.padStart(8)} ${'read'.padStart(5)} ${'e2e pass%'.padStart(9)} ${'fid'.padStart(5)}`);
58
- for (const repo of Object.keys(byRepo)) {
59
- for (const arm of ARM_ORDER) {
60
- const rs = byRepo[repo][arm]; if (!rs) continue;
61
- const e2e = verdictTally(rs, 'e2e');
62
- const passPct = Math.round(100 * e2e.pass / rs.length);
63
- const totCost = (med(rs.map(r => r.costUsdMain)) ?? 0) + (med(rs.map(r => r.ai?.costUsd ?? 0)) ?? 0);
64
- const fid = arm === 'offload' ? med(rs.flatMap(r => r.fidelity?.scores ?? [])) : null;
65
- console.log(`${repo.padEnd(12)} ${arm.padEnd(8)} ${(med(rs.map(r => r.durationSec)) + 's').padStart(7)} ${('$' + d3(totCost)).padStart(8)} ${String(med(rs.map(r => r.read))).padStart(5)} ${(passPct + '%').padStart(9)} ${String(fid ?? '—').padStart(5)}`);
66
- }
67
- }
68
- console.log('');
@@ -1,76 +0,0 @@
1
- # HomeGraph AI offload — accuracy & adoption eval harness
2
-
3
- Measures the managed **offload** (`homegraph_explore` → reasoning model synthesis) and the
4
- **front-load hook** (approach 1) against plain homegraph and no-homegraph, across repo sizes,
5
- on **time · main-session tokens/cost · HomeGraph-AI tokens/cost · accuracy**.
6
-
7
- All agent arms run `claude -p --model sonnet --effort high` (the deliberate floor model — an
8
- affordance that lands on Sonnet generalizes up). Everything writes to a scratch dir
9
- (`AGENT_EVAL_OUT`, default `/tmp/cg-offload-eval`); nothing here is shipped to users.
10
-
11
- ## Repos (selected via a memory-probe gate — NOT trained on)
12
-
13
- Famous repos (express, excalidraw, n8n, …) are useless for *accuracy* evals: Sonnet answers their
14
- flow questions from memory, so the no-homegraph baseline is dishonest. These four passed a no-tools
15
- probe (Sonnet could not name their real flow internals) and are cloned fresh by `offload-eval-setup.sh`:
16
-
17
- | tier | repo | ~src files | canonical flow |
18
- |---|---|---|---|
19
- | small | MTKruto/MTKruto | 322 TS | `sendMessage` → invoke → TL serialize → transport |
20
- | medium | mvdicarlo/postybirb-plus | 608 TS | submission → queue → per-website `.post()` |
21
- | complex | shapeshift/web | 3.2k TS (35-pkg monorepo) | swap → swapper registry → concrete swapper |
22
- | large | trezor/trezor-suite | 8k TS monorepo | send-form → sign thunk → `@trezor/connect` |
23
-
24
- Verified ground-truth flows (the judge's reference) live in `offload-eval-ground-truth.json`.
25
-
26
- ## Arms
27
-
28
- - **offload** — homegraph + managed offload ON (requires `homegraph login`); records AI tokens/credits via `HOMEGRAPH_OFFLOAD_USAGE_LOG`.
29
- - **raw** — homegraph, `HOMEGRAPH_OFFLOAD_DISABLE=1` (returns raw source).
30
- - **nocg** — empty MCP config; Read/Grep baseline.
31
- - **frontload** — homegraph (offload-disabled) + a `UserPromptSubmit` hook (`offload-eval-hook.mjs`) that runs raw explore on the prompt and injects the result into context (approach 1).
32
-
33
- ## Run it
34
-
35
- ```bash
36
- npm run build # the harness shells out to dist/
37
- homegraph login # only needed for the offload arm
38
- export AGENT_EVAL_OUT=/tmp/cg-offload-eval
39
-
40
- bash scripts/agent-eval/offload-eval-setup.sh # clone + index the 4 repos
41
- bash scripts/agent-eval/offload-eval-matrix.sh # 3 arms × 4 tiers × REPS (default 3)
42
- node scripts/agent-eval/offload-eval-judge.mjs \
43
- --results $AGENT_EVAL_OUT/results.jsonl \
44
- --truth scripts/agent-eval/offload-eval-ground-truth.json \
45
- --out $AGENT_EVAL_OUT/judged.jsonl
46
- node scripts/agent-eval/offload-eval-summarize.mjs $AGENT_EVAL_OUT/judged.jsonl
47
-
48
- bash scripts/agent-eval/offload-eval-frontload-matrix.sh # frontload arm + judge + merged summary
49
- ```
50
-
51
- Single repo: `offload-eval-3arm.sh <indexed-repo> <tier> <reps> "<question>"` (or `-frontload.sh`).
52
-
53
- ## Files
54
-
55
- - `offload-eval-setup.sh` — clone + index the 4 repos.
56
- - `offload-eval-3arm.sh` / `-frontload.sh` — one repo, the arms.
57
- - `offload-eval-matrix.sh` / `-frontload-matrix.sh` — drive all 4 tiers.
58
- - `offload-eval-hook.mjs` — the front-load `UserPromptSubmit` hook (resolves its own engine; `CG_FRONTLOAD_DEBUG=<path>` to log injections; `CG_FRONTLOAD_BUDGET` to cap injected chars).
59
- - `offload-eval-metrics.mjs` — one run's stream-json + usage log → one JSON metrics line.
60
- - `offload-eval-judge.mjs` — Sonnet judge: end-to-end (agent final vs ground truth) + per-answer offload fidelity.
61
- - `offload-eval-summarize.mjs` — per-tier, per-arm table + cross-repo roll-up.
62
- - `offload-eval-ground-truth.json` — source-verified canonical flows.
63
-
64
- ## Findings (2026-06, n=3 — direction consistent, magnitudes noisy)
65
-
66
- - **Raw homegraph is the efficiency win** — ~nocg accuracy, fewer reads, faster, no AI cost.
67
- - **The offload is the least-accurate arm in all 4 tiers** — synthesized fidelity 12–27/100 with
68
- fabrication in 3/4 (e.g. invented website services; traced `ClientPlain`/`SessionPlain` instead of
69
- the real encrypted path). Its speed/cost win is narrow (medium-only) and inversely correlated with
70
- accuracy. **Use raw until offload fidelity is fixed.**
71
- - **The front-load hook SOLVES adoption** — reads → 0–1 in every tier (incl. large, where the agent
72
- otherwise read 12–24 files); fired 12/12, 0 errors. Wins on medium/complex (100% pass). But it
73
- **regresses small/large to partial** — it suppresses the reads that compensate for explore's gaps at
74
- **dynamic boundaries** (async queues, redux thunks, facade/factory indirection).
75
- - **Master lever for BOTH:** explore's dynamic-dispatch coverage. Fix it → front-load is complete
76
- everywhere and the offload has the full flow to synthesize.
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env node
2
- // Analyze the tool-surface ablation (/tmp/arms/<repo>/<arm>-r<n>.jsonl).
3
- // Compares arms A–E on trace adoption, Read/Grep fallback, homegraph payload,
4
- // round-trips, and duration — averaged across runs per arm.
5
- //
6
- // The decisive signal is READS: if removing a tool raises Reads on a question
7
- // class, that tool was load-bearing for it (not redundant). If removing it
8
- // changes nothing, it was redundant.
9
- //
10
- // A control all tools no steering (baseline)
11
- // B steer all tools trace-first (adoption)
12
- // C no-explore hide explore trace-first (is explore redundant?)
13
- // D trace-centric hide explore+context trace-first (is the survey pair redundant?)
14
- // E control-probe hide explore+context trace-first (NON-flow Q — should degrade)
15
- //
16
- // Usage: node scripts/agent-eval/parse-arms.mjs [/tmp/arms]
17
- import { readFileSync, readdirSync, existsSync, statSync } from 'fs';
18
- import { join } from 'path';
19
-
20
- const ROOT = process.argv[2] || '/tmp/arms';
21
- const cgShort = (n) => n.replace('mcp__homegraph__homegraph_', '').replace('mcp__homegraph__', '');
22
-
23
- function parse(file) {
24
- if (!existsSync(file)) return null;
25
- const lines = readFileSync(file, 'utf8').split('\n').filter(Boolean);
26
- const calls = []; let result = null, initCg = 0;
27
- for (const l of lines) {
28
- let ev; try { ev = JSON.parse(l); } catch { continue; }
29
- if (ev.type === 'system' && ev.subtype === 'init') initCg = (ev.tools || []).filter(t => /homegraph/.test(t)).length;
30
- if (ev.type === 'assistant') for (const b of (ev.message?.content || [])) if (b.type === 'tool_use')
31
- calls.push({ id: b.id, name: b.name, out: 0 });
32
- if (ev.type === 'user') for (const b of (ev.message?.content || [])) if (b.type === 'tool_result') {
33
- const c = b.content;
34
- const txt = typeof c === 'string' ? c : Array.isArray(c) ? c.map(x => x?.text || '').join('') : '';
35
- const call = calls.find(k => k.id === b.tool_use_id); if (call) call.out = txt.length;
36
- }
37
- if (ev.type === 'result') result = ev;
38
- }
39
- const cg = calls.filter(c => c.name.includes('homegraph'));
40
- return {
41
- initCg,
42
- reads: calls.filter(c => c.name === 'Read').length,
43
- greps: calls.filter(c => c.name === 'Grep').length + calls.filter(c => c.name === 'Glob').length,
44
- cgCalls: cg.length,
45
- cgSeq: cg.map(c => cgShort(c.name)),
46
- cgOut: cg.reduce((s, c) => s + c.out, 0),
47
- traceUsed: cg.some(c => c.name.includes('trace')),
48
- turns: result?.num_turns ?? null,
49
- dur: result?.duration_ms ? Math.round(result.duration_ms / 1000) : null,
50
- cost: result?.total_cost_usd || 0,
51
- ok: result?.subtype === 'success',
52
- };
53
- }
54
-
55
- // repo -> arm -> [runs]
56
- const data = {};
57
- if (!existsSync(ROOT)) { console.error(`no ${ROOT}`); process.exit(1); }
58
- for (const repo of readdirSync(ROOT)) {
59
- const rdir = join(ROOT, repo);
60
- if (!statSync(rdir).isDirectory()) continue;
61
- for (const f of readdirSync(rdir)) {
62
- const m = f.match(/^([A-I])-r(\d+)\.jsonl$/); if (!m) continue;
63
- const p = parse(join(rdir, f)); if (!p || !p.ok) continue;
64
- (((data[repo] ??= {})[m[1]]) ??= []).push(p);
65
- }
66
- }
67
-
68
- const avg = (a, f) => a.length ? a.reduce((s, x) => s + (f(x) || 0), 0) / a.length : 0;
69
- const k = (n) => (n / 1000).toFixed(1);
70
- const pad = (s, n) => String(s).padEnd(n);
71
- const ARMS = ['A', 'H', 'I', 'B', 'F', 'G', 'C', 'D', 'E'];
72
- const LABEL = { A: 'A all/none(old)', H: 'H body-trace/none', I: 'I bodytrace+dest', B: 'B all/steer(thin)', F: 'F all/steer(body)', G: 'G ported(noprompt)', C: 'C no-explore', D: 'D trace-centric', E: 'E nonflow-probe' };
73
-
74
- // ---- per repo × arm ----
75
- console.log('\n=== PER REPO × ARM (avg over runs) ===');
76
- console.log(pad('repo', 22), pad('arm', 16), 'tools', 'trace', pad('reads', 6), pad('cgOutK', 7), pad('turns', 6), 'dur');
77
- for (const repo of Object.keys(data).sort()) {
78
- for (const arm of ARMS) {
79
- const runs = data[repo][arm]; if (!runs?.length) continue;
80
- console.log(
81
- pad(repo, 22), pad(LABEL[arm], 16),
82
- pad(runs[0].initCg, 5),
83
- pad(runs.filter(r => r.traceUsed).length + '/' + runs.length, 5),
84
- pad(avg(runs, r => r.reads).toFixed(1), 6),
85
- pad(k(avg(runs, r => r.cgOut)), 7),
86
- pad(avg(runs, r => r.turns).toFixed(1), 6),
87
- avg(runs, r => r.dur).toFixed(0) + 's',
88
- );
89
- }
90
- }
91
-
92
- // ---- aggregate per arm (flow arms A–D over the flow repos; E shown apart) ----
93
- console.log('\n=== AGGREGATE PER ARM (mean across repos) ===');
94
- console.log(pad('arm', 16), pad('adoption', 9), pad('reads', 7), pad('greps', 7), pad('cgOutK', 8), pad('turns', 7), pad('dur', 6), 'cost');
95
- for (const arm of ARMS) {
96
- const all = [];
97
- for (const repo of Object.keys(data)) for (const r of (data[repo][arm] || [])) all.push({ ...r, repo });
98
- if (!all.length) continue;
99
- const repos = new Set(all.map(r => r.repo)).size;
100
- const adopt = all.filter(r => r.traceUsed).length;
101
- console.log(
102
- pad(LABEL[arm], 16),
103
- pad(`${adopt}/${all.length}`, 9),
104
- pad(avg(all, r => r.reads).toFixed(2), 7),
105
- pad(avg(all, r => r.greps).toFixed(2), 7),
106
- pad(k(avg(all, r => r.cgOut)), 8),
107
- pad(avg(all, r => r.turns).toFixed(1), 7),
108
- pad(avg(all, r => r.dur).toFixed(0) + 's', 6),
109
- '$' + avg(all, r => r.cost).toFixed(3),
110
- ` (${repos} repos)`,
111
- );
112
- }
113
-
114
- console.log('\nRead the signal: B vs A = does steering alone fix adoption + cut payload.');
115
- console.log('C vs B = is explore redundant (reads should NOT jump). D vs C = is context redundant.');
116
- console.log('E = non-flow under trace-centric; reads SHOULD jump (proves survey tools are load-bearing).');
@@ -1,84 +0,0 @@
1
- #!/usr/bin/env node
2
- // Aggregate the README A/B (bench-readme.sh output): per repo, median of N runs
3
- // per arm → time, tool calls, tokens, cost, and % saved. Plus an average row.
4
- //
5
- // Tokens = SUM of per-turn assistant `usage` (input + output + cache read +
6
- // cache creation) — the cumulative "total tokens processed". NOTE: `result.usage`
7
- // is last-turn-only in current Claude Code, so it under-counts badly; don't use it.
8
- // `total_cost_usd` and `duration_ms` are already cumulative.
9
- //
10
- // Usage: node parse-bench-readme.mjs [/tmp/ab-readme]
11
- import { readFileSync, existsSync, readdirSync } from 'fs';
12
- import { join } from 'path';
13
- const ROOT = process.argv[2] || '/tmp/ab-readme';
14
- const REPOS = ['vscode', 'excalidraw', 'django', 'tokio', 'okhttp', 'gin', 'alamofire'];
15
-
16
- function parse(file) {
17
- if (!existsSync(file)) return null;
18
- const L = readFileSync(file, 'utf8').split('\n').filter(Boolean);
19
- let tools = 0, reads = 0, grep = 0, cg = 0, tokens = 0, r = null, raced = false;
20
- for (const l of L) { let e; try { e = JSON.parse(l); } catch { continue; }
21
- if (e.type === 'assistant') {
22
- const u = e.message?.usage;
23
- if (u) tokens += (u.input_tokens || 0) + (u.output_tokens || 0) + (u.cache_read_input_tokens || 0) + (u.cache_creation_input_tokens || 0);
24
- for (const b of (e.message?.content || [])) if (b.type === 'tool_use') {
25
- const n = b.name;
26
- if (n === 'ToolSearch') continue;
27
- tools++;
28
- if (n === 'Read') reads++;
29
- else if (n === 'Grep' || n === 'Glob') grep++;
30
- else if (/homegraph/.test(n)) cg++;
31
- }
32
- }
33
- // MCP cold-start race: the headless agent fired before `homegraph serve --mcp`
34
- // finished registering its tools, so early calls returned "No such tool
35
- // available" and the agent floundered into grep/Read. That measures HomeGraph's
36
- // startup latency, NOT its steady-state value — flag the run so the aggregate
37
- // can exclude it (an artifact of headless first-turn timing, not the tool).
38
- if (e.type === 'user') for (const b of (Array.isArray(e.message?.content) ? e.message.content : [])) {
39
- if (b.type === 'tool_result') {
40
- const t = Array.isArray(b.content) ? b.content.map(c => c.text || '').join('') : (b.content || '');
41
- if (/No such tool available/.test(t)) raced = true;
42
- }
43
- }
44
- if (e.type === 'result') r = e;
45
- }
46
- if (!r || r.subtype !== 'success') return null;
47
- return { dur: r.duration_ms / 1000, tools, reads, grep, cg, tokens, cost: r.total_cost_usd || 0, raced };
48
- }
49
- const median = (arr) => { const v = [...arr].sort((a, b) => a - b); const n = v.length; return n === 0 ? 0 : n % 2 ? v[(n - 1) / 2] : (v[n / 2 - 1] + v[n / 2]) / 2; };
50
- const fmtTime = (s) => s >= 60 ? `${Math.floor(s / 60)}m ${Math.round(s % 60)}s` : `${Math.round(s)}s`;
51
- const fmtTok = (t) => t >= 1e6 ? `${(t / 1e6).toFixed(1)}M` : `${Math.round(t / 1000)}k`;
52
- const pct = (w, wo) => wo > 0 ? Math.round((1 - w / wo) * 100) : 0;
53
-
54
- console.log('repo n(w/wo) time WITH→WITHOUT tools W→WO tokens W→WO (saved) cost W→WO (saved)');
55
- const savings = { cost: [], tokens: [], time: [], tools: [] };
56
- for (const repo of REPOS) {
57
- const dir = join(ROOT, repo);
58
- const runDirs = existsSync(dir) ? readdirSync(dir).filter(d => /^run\d+$/.test(d)) : [];
59
- // Exclude MCP-cold-start-raced WITH runs by default — they measure a startup
60
- // race, not steady-state value. `CG_INCLUDE_RACED=1` keeps them (to see the raw
61
- // distribution). The WITHOUT arm has no MCP, so it's never raced.
62
- const includeRaced = process.env.CG_INCLUDE_RACED === '1';
63
- const W = [], WO = []; let racedExcluded = 0;
64
- for (const rd of runDirs) {
65
- const w = parse(join(dir, rd, 'run-headless-with.jsonl'));
66
- if (w) { if (w.raced && !includeRaced) racedExcluded++; else W.push(w); }
67
- const wo = parse(join(dir, rd, 'run-headless-without.jsonl')); if (wo) WO.push(wo);
68
- }
69
- if (!W.length || !WO.length) { console.log(`${repo.padEnd(11)} (incomplete: w=${W.length} wo=${WO.length})`); continue; }
70
- const m = (arr, k) => median(arr.map(x => x[k]));
71
- const wT = m(W, 'dur'), woT = m(WO, 'dur'), wTok = m(W, 'tokens'), woTok = m(WO, 'tokens');
72
- const wC = m(W, 'cost'), woC = m(WO, 'cost'), wTl = m(W, 'tools'), woTl = m(WO, 'tools');
73
- savings.time.push(pct(wT, woT)); savings.tokens.push(pct(wTok, woTok)); savings.cost.push(pct(wC, woC)); savings.tools.push(pct(wTl, woTl));
74
- console.log(
75
- `${repo.padEnd(11)} ${W.length}/${WO.length} ` +
76
- `${(fmtTime(wT) + '→' + fmtTime(woT)).padEnd(22)}` +
77
- `${(Math.round(wTl) + '→' + Math.round(woTl)).padEnd(12)}` +
78
- `${(fmtTok(wTok) + '→' + fmtTok(woTok) + ' (' + pct(wTok, woTok) + '%)').padEnd(24)}` +
79
- `$${wC.toFixed(2)}→$${woC.toFixed(2)} (${pct(wC, woC)}%)` +
80
- (racedExcluded ? ` [${racedExcluded} raced run${racedExcluded === 1 ? '' : 's'} excluded]` : '')
81
- );
82
- }
83
- const avg = (a) => a.length ? Math.round(a.reduce((s, x) => s + x, 0) / a.length) : 0;
84
- console.log(`\nAVERAGE saved: cost ${avg(savings.cost)}% · tokens ${avg(savings.tokens)}% · time ${avg(savings.time)}% · tool calls ${avg(savings.tools)}%`);
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env node
2
- // Parse a Claude Code stream-json run log: tool-call sequence + token usage.
3
- import { readFileSync } from 'fs';
4
- const file = process.argv[2];
5
- const lines = readFileSync(file, 'utf8').split('\n').filter(Boolean);
6
-
7
- const toolCalls = [];
8
- let result = null;
9
- let initTools = null;
10
-
11
- for (const line of lines) {
12
- let ev;
13
- try { ev = JSON.parse(line); } catch { continue; }
14
- if (ev.type === 'system' && ev.subtype === 'init') {
15
- initTools = (ev.tools || []).filter(t => /homegraph/.test(t));
16
- }
17
- if (ev.type === 'assistant' && ev.message?.content) {
18
- for (const block of ev.message.content) {
19
- if (block.type === 'tool_use') {
20
- let detail = '';
21
- if (block.name === 'Task') detail = ` [subagent_type=${block.input?.subagent_type ?? '?'}] ${(block.input?.description ?? '').slice(0,40)}`;
22
- else if (/homegraph/.test(block.name)) detail = ` ${JSON.stringify(block.input?.query ?? block.input?.task ?? block.input?.symbol ?? '').slice(0,60)}`;
23
- else if (block.name === 'Bash') detail = ` ${(block.input?.command ?? '').slice(0,50)}`;
24
- else if (block.name === 'Read') detail = ` ${(block.input?.file_path ?? '').split('/').slice(-1)[0]}`;
25
- toolCalls.push(`${block.name}${detail}`);
26
- }
27
- }
28
- }
29
- if (ev.type === 'result') result = ev;
30
- }
31
-
32
- console.log(`\n=== ${file.split('/').pop()} ===`);
33
- console.log(`homegraph tools exposed: ${initTools ? initTools.length : '?'}`);
34
- console.log(`\nTool calls (${toolCalls.length}):`);
35
- const counts = {};
36
- for (const tc of toolCalls) { const n = tc.split(' ')[0]; counts[n] = (counts[n]||0)+1; }
37
- console.log(' by type:', JSON.stringify(counts));
38
- toolCalls.forEach((tc, i) => console.log(` ${i+1}. ${tc}`));
39
-
40
- if (result) {
41
- const u = result.usage || {};
42
- const totalIn = (u.input_tokens||0) + (u.cache_read_input_tokens||0) + (u.cache_creation_input_tokens||0);
43
- console.log(`\nResult: ${result.subtype} | duration ${(result.duration_ms/1000).toFixed(0)}s | turns ${result.num_turns}`);
44
- console.log(` tokens: in=${totalIn} out=${u.output_tokens||0} | cost $${(result.total_cost_usd||0).toFixed(3)}`);
45
- }