homegraph 1.4.1 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +305 -268
  3. package/dist/bin/command-supervision.d.ts.map +1 -1
  4. package/dist/bin/command-supervision.js +7 -4
  5. package/dist/bin/command-supervision.js.map +1 -1
  6. package/dist/bin/homegraph.js +304 -81
  7. package/dist/bin/homegraph.js.map +1 -1
  8. package/dist/context/index.d.ts.map +1 -1
  9. package/dist/context/index.js +32 -11
  10. package/dist/context/index.js.map +1 -1
  11. package/dist/db/index.d.ts +143 -1
  12. package/dist/db/index.d.ts.map +1 -1
  13. package/dist/db/index.js +305 -28
  14. package/dist/db/index.js.map +1 -1
  15. package/dist/db/migrations.js +37 -37
  16. package/dist/db/queries.d.ts +43 -4
  17. package/dist/db/queries.d.ts.map +1 -1
  18. package/dist/db/queries.js +294 -170
  19. package/dist/db/queries.js.map +1 -1
  20. package/dist/db/schema.sql +203 -203
  21. package/dist/db/sqlite-adapter.d.ts +24 -17
  22. package/dist/db/sqlite-adapter.d.ts.map +1 -1
  23. package/dist/db/sqlite-adapter.js +292 -36
  24. package/dist/db/sqlite-adapter.js.map +1 -1
  25. package/dist/db/wal-valve.d.ts +15 -2
  26. package/dist/db/wal-valve.d.ts.map +1 -1
  27. package/dist/db/wal-valve.js +88 -6
  28. package/dist/db/wal-valve.js.map +1 -1
  29. package/dist/directory.js +5 -5
  30. package/dist/extraction/arkts-batch-worker.js +3 -2
  31. package/dist/extraction/arkts-batch-worker.js.map +1 -1
  32. package/dist/extraction/default-ignore.d.ts +39 -0
  33. package/dist/extraction/default-ignore.d.ts.map +1 -0
  34. package/dist/extraction/default-ignore.js +221 -0
  35. package/dist/extraction/default-ignore.js.map +1 -0
  36. package/dist/extraction/index.d.ts +9 -10
  37. package/dist/extraction/index.d.ts.map +1 -1
  38. package/dist/extraction/index.js +227 -323
  39. package/dist/extraction/index.js.map +1 -1
  40. package/dist/extraction/languages/arkts-viewtree.d.ts +2 -4
  41. package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
  42. package/dist/extraction/languages/arkts-viewtree.js +6 -21
  43. package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
  44. package/dist/extraction/languages/arkts.d.ts +100 -6
  45. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  46. package/dist/extraction/languages/arkts.js +1777 -173
  47. package/dist/extraction/languages/arkts.js.map +1 -1
  48. package/dist/extraction/store-worker.d.ts +20 -0
  49. package/dist/extraction/store-worker.d.ts.map +1 -0
  50. package/dist/extraction/store-worker.js +102 -0
  51. package/dist/extraction/store-worker.js.map +1 -0
  52. package/dist/extraction/store-writer.d.ts +48 -0
  53. package/dist/extraction/store-writer.d.ts.map +1 -0
  54. package/dist/extraction/store-writer.js +167 -0
  55. package/dist/extraction/store-writer.js.map +1 -0
  56. package/dist/extraction/tree-sitter.d.ts.map +1 -1
  57. package/dist/extraction/tree-sitter.js +47 -0
  58. package/dist/extraction/tree-sitter.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 +14 -4
  69. package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
  70. package/dist/extraction/wasm-runtime-flags.js +55 -7
  71. package/dist/extraction/wasm-runtime-flags.js.map +1 -1
  72. package/dist/index.d.ts +16 -5
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +135 -97
  75. package/dist/index.js.map +1 -1
  76. package/dist/installer/instructions-template.js +9 -9
  77. package/dist/mcp/liveness-watchdog.d.ts +18 -0
  78. package/dist/mcp/liveness-watchdog.d.ts.map +1 -1
  79. package/dist/mcp/liveness-watchdog.js +185 -73
  80. package/dist/mcp/liveness-watchdog.js.map +1 -1
  81. package/dist/mcp/query-worker.d.ts +2 -2
  82. package/dist/mcp/query-worker.js +2 -2
  83. package/dist/mcp/server-instructions.js +47 -47
  84. package/dist/mcp/tools.d.ts.map +1 -1
  85. package/dist/mcp/tools.js +42 -26
  86. package/dist/mcp/tools.js.map +1 -1
  87. package/dist/reasoning/reasoner.js +32 -32
  88. package/dist/resolution/callback-synthesizer.d.ts +52 -16
  89. package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  90. package/dist/resolution/callback-synthesizer.js +234 -180
  91. package/dist/resolution/callback-synthesizer.js.map +1 -1
  92. package/dist/resolution/cooperative-yield.d.ts +10 -2
  93. package/dist/resolution/cooperative-yield.d.ts.map +1 -1
  94. package/dist/resolution/cooperative-yield.js +6 -4
  95. package/dist/resolution/cooperative-yield.js.map +1 -1
  96. package/dist/resolution/frameworks/go.d.ts.map +1 -1
  97. package/dist/resolution/frameworks/go.js +29 -6
  98. package/dist/resolution/frameworks/go.js.map +1 -1
  99. package/dist/resolution/import-resolver.d.ts +2 -3
  100. package/dist/resolution/import-resolver.d.ts.map +1 -1
  101. package/dist/resolution/import-resolver.js +166 -7
  102. package/dist/resolution/import-resolver.js.map +1 -1
  103. package/dist/resolution/index.d.ts +87 -2
  104. package/dist/resolution/index.d.ts.map +1 -1
  105. package/dist/resolution/index.js +739 -131
  106. package/dist/resolution/index.js.map +1 -1
  107. package/dist/resolution/memory-budget.d.ts +48 -0
  108. package/dist/resolution/memory-budget.d.ts.map +1 -0
  109. package/dist/resolution/memory-budget.js +162 -0
  110. package/dist/resolution/memory-budget.js.map +1 -0
  111. package/dist/resolution/name-matcher.d.ts +12 -1
  112. package/dist/resolution/name-matcher.d.ts.map +1 -1
  113. package/dist/resolution/name-matcher.js +439 -97
  114. package/dist/resolution/name-matcher.js.map +1 -1
  115. package/dist/resolution/resolver-pool.d.ts +106 -0
  116. package/dist/resolution/resolver-pool.d.ts.map +1 -0
  117. package/dist/resolution/resolver-pool.js +344 -0
  118. package/dist/resolution/resolver-pool.js.map +1 -0
  119. package/dist/resolution/resolver-worker.d.ts +17 -0
  120. package/dist/resolution/resolver-worker.d.ts.map +1 -0
  121. package/dist/resolution/resolver-worker.js +141 -0
  122. package/dist/resolution/resolver-worker.js.map +1 -0
  123. package/dist/resolution/types.d.ts +3 -0
  124. package/dist/resolution/types.d.ts.map +1 -1
  125. package/dist/spec/build/diff-parser.d.ts +55 -0
  126. package/dist/spec/build/diff-parser.d.ts.map +1 -0
  127. package/dist/spec/build/diff-parser.js +205 -0
  128. package/dist/spec/build/diff-parser.js.map +1 -0
  129. package/dist/spec/build/pipeline.d.ts +54 -0
  130. package/dist/spec/build/pipeline.d.ts.map +1 -0
  131. package/dist/spec/build/pipeline.js +170 -0
  132. package/dist/spec/build/pipeline.js.map +1 -0
  133. package/dist/spec/build/scan.d.ts +48 -0
  134. package/dist/spec/build/scan.d.ts.map +1 -0
  135. package/dist/spec/build/scan.js +89 -0
  136. package/dist/spec/build/scan.js.map +1 -0
  137. package/dist/spec/build/scope-resolver.d.ts +50 -0
  138. package/dist/spec/build/scope-resolver.d.ts.map +1 -0
  139. package/dist/spec/build/scope-resolver.js +105 -0
  140. package/dist/spec/build/scope-resolver.js.map +1 -0
  141. package/dist/spec/build/spec-extractor.d.ts +74 -0
  142. package/dist/spec/build/spec-extractor.d.ts.map +1 -0
  143. package/dist/spec/build/spec-extractor.js +344 -0
  144. package/dist/spec/build/spec-extractor.js.map +1 -0
  145. package/dist/spec/config.d.ts +35 -1
  146. package/dist/spec/config.d.ts.map +1 -1
  147. package/dist/spec/config.js +30 -5
  148. package/dist/spec/config.js.map +1 -1
  149. package/dist/spec/db/commit-node.js +4 -4
  150. package/dist/spec/db/fragment-node.js +10 -10
  151. package/dist/spec/db/fts.d.ts.map +1 -1
  152. package/dist/spec/db/fts.js +27 -58
  153. package/dist/spec/db/fts.js.map +1 -1
  154. package/dist/spec/db/index.d.ts +5 -3
  155. package/dist/spec/db/index.d.ts.map +1 -1
  156. package/dist/spec/db/index.js +16 -1
  157. package/dist/spec/db/index.js.map +1 -1
  158. package/dist/spec/db/persist.d.ts +45 -0
  159. package/dist/spec/db/persist.d.ts.map +1 -0
  160. package/dist/spec/db/persist.js +66 -0
  161. package/dist/spec/db/persist.js.map +1 -0
  162. package/dist/spec/db/relations.d.ts +80 -1
  163. package/dist/spec/db/relations.d.ts.map +1 -1
  164. package/dist/spec/db/relations.js +218 -47
  165. package/dist/spec/db/relations.js.map +1 -1
  166. package/dist/spec/db/schema.d.ts +4 -0
  167. package/dist/spec/db/schema.d.ts.map +1 -1
  168. package/dist/spec/db/schema.js +10 -6
  169. package/dist/spec/db/schema.js.map +1 -1
  170. package/dist/spec/db/schema.sql +121 -117
  171. package/dist/spec/db/spec-node.d.ts +5 -0
  172. package/dist/spec/db/spec-node.d.ts.map +1 -1
  173. package/dist/spec/db/spec-node.js +15 -9
  174. package/dist/spec/db/spec-node.js.map +1 -1
  175. package/dist/spec/db/sql-utils.d.ts +11 -0
  176. package/dist/spec/db/sql-utils.d.ts.map +1 -0
  177. package/dist/spec/db/sql-utils.js +19 -0
  178. package/dist/spec/db/sql-utils.js.map +1 -0
  179. package/dist/spec/evolve/cluster-context.d.ts +30 -0
  180. package/dist/spec/evolve/cluster-context.d.ts.map +1 -0
  181. package/dist/spec/evolve/cluster-context.js +78 -0
  182. package/dist/spec/evolve/cluster-context.js.map +1 -0
  183. package/dist/spec/evolve/commit-spec-analyzer.d.ts +51 -0
  184. package/dist/spec/evolve/commit-spec-analyzer.d.ts.map +1 -0
  185. package/dist/spec/evolve/commit-spec-analyzer.js +88 -0
  186. package/dist/spec/evolve/commit-spec-analyzer.js.map +1 -0
  187. package/dist/spec/evolve/commit-spec-persister.d.ts +53 -0
  188. package/dist/spec/evolve/commit-spec-persister.d.ts.map +1 -0
  189. package/dist/spec/evolve/commit-spec-persister.js +93 -0
  190. package/dist/spec/evolve/commit-spec-persister.js.map +1 -0
  191. package/dist/spec/evolve/impact-locator.d.ts +23 -7
  192. package/dist/spec/evolve/impact-locator.d.ts.map +1 -1
  193. package/dist/spec/evolve/impact-locator.js +58 -14
  194. package/dist/spec/evolve/impact-locator.js.map +1 -1
  195. package/dist/spec/evolve/pipeline.d.ts +62 -25
  196. package/dist/spec/evolve/pipeline.d.ts.map +1 -1
  197. package/dist/spec/evolve/pipeline.js +436 -457
  198. package/dist/spec/evolve/pipeline.js.map +1 -1
  199. package/dist/spec/evolve/spec-rewriter.d.ts +13 -13
  200. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
  201. package/dist/spec/evolve/spec-rewriter.js +45 -45
  202. package/dist/spec/evolve/spec-rewriter.js.map +1 -1
  203. package/dist/spec/git/commits.d.ts +85 -0
  204. package/dist/spec/git/commits.d.ts.map +1 -0
  205. package/dist/spec/git/commits.js +218 -0
  206. package/dist/spec/git/commits.js.map +1 -0
  207. package/dist/spec/git/exec.d.ts +13 -0
  208. package/dist/spec/git/exec.d.ts.map +1 -0
  209. package/dist/spec/git/exec.js +19 -0
  210. package/dist/spec/git/exec.js.map +1 -0
  211. package/dist/spec/git/index.d.ts +9 -0
  212. package/dist/spec/git/index.d.ts.map +1 -0
  213. package/dist/spec/git/index.js +22 -0
  214. package/dist/spec/git/index.js.map +1 -0
  215. package/dist/spec/graph/index.d.ts +8 -0
  216. package/dist/spec/graph/index.d.ts.map +1 -0
  217. package/dist/spec/graph/index.js +17 -0
  218. package/dist/spec/graph/index.js.map +1 -0
  219. package/dist/spec/graph/queries.d.ts +6 -35
  220. package/dist/spec/graph/queries.d.ts.map +1 -1
  221. package/dist/spec/graph/queries.js +71 -248
  222. package/dist/spec/graph/queries.js.map +1 -1
  223. package/dist/spec/llm/agent-client.d.ts +59 -0
  224. package/dist/spec/llm/agent-client.d.ts.map +1 -0
  225. package/dist/spec/llm/agent-client.js +213 -0
  226. package/dist/spec/llm/agent-client.js.map +1 -0
  227. package/dist/spec/llm/agents/claude-code.d.ts +32 -0
  228. package/dist/spec/llm/agents/claude-code.d.ts.map +1 -0
  229. package/dist/spec/llm/agents/claude-code.js +125 -0
  230. package/dist/spec/llm/agents/claude-code.js.map +1 -0
  231. package/dist/spec/llm/agents/codex.d.ts +32 -0
  232. package/dist/spec/llm/agents/codex.d.ts.map +1 -0
  233. package/dist/spec/llm/agents/codex.js +145 -0
  234. package/dist/spec/llm/agents/codex.js.map +1 -0
  235. package/dist/spec/llm/agents/detect-utils.d.ts +28 -0
  236. package/dist/spec/llm/agents/detect-utils.d.ts.map +1 -0
  237. package/dist/spec/llm/agents/detect-utils.js +91 -0
  238. package/dist/spec/llm/agents/detect-utils.js.map +1 -0
  239. package/dist/spec/llm/agents/deveco-code.d.ts +33 -0
  240. package/dist/spec/llm/agents/deveco-code.d.ts.map +1 -0
  241. package/dist/spec/llm/agents/deveco-code.js +165 -0
  242. package/dist/spec/llm/agents/deveco-code.js.map +1 -0
  243. package/dist/spec/llm/agents/index.d.ts +31 -0
  244. package/dist/spec/llm/agents/index.d.ts.map +1 -0
  245. package/dist/spec/llm/agents/index.js +65 -0
  246. package/dist/spec/llm/agents/index.js.map +1 -0
  247. package/dist/spec/llm/agents/types.d.ts +76 -0
  248. package/dist/spec/llm/agents/types.d.ts.map +1 -0
  249. package/dist/spec/llm/agents/types.js +15 -0
  250. package/dist/spec/llm/agents/types.js.map +1 -0
  251. package/dist/spec/llm/client.d.ts +31 -11
  252. package/dist/spec/llm/client.d.ts.map +1 -1
  253. package/dist/spec/llm/client.js +143 -81
  254. package/dist/spec/llm/client.js.map +1 -1
  255. package/dist/spec/llm/factory.d.ts +41 -0
  256. package/dist/spec/llm/factory.d.ts.map +1 -0
  257. package/dist/spec/llm/factory.js +80 -0
  258. package/dist/spec/llm/factory.js.map +1 -0
  259. package/dist/spec/llm/prompts.d.ts +24 -8
  260. package/dist/spec/llm/prompts.d.ts.map +1 -1
  261. package/dist/spec/llm/prompts.js +112 -62
  262. package/dist/spec/llm/prompts.js.map +1 -1
  263. package/dist/spec/llm/retry.d.ts +53 -0
  264. package/dist/spec/llm/retry.d.ts.map +1 -0
  265. package/dist/spec/llm/retry.js +153 -0
  266. package/dist/spec/llm/retry.js.map +1 -0
  267. package/dist/spec/mine/clustering/features.d.ts +38 -0
  268. package/dist/spec/mine/clustering/features.d.ts.map +1 -0
  269. package/dist/spec/mine/clustering/features.js +108 -0
  270. package/dist/spec/mine/clustering/features.js.map +1 -0
  271. package/dist/spec/mine/clustering/index.d.ts +62 -0
  272. package/dist/spec/mine/clustering/index.d.ts.map +1 -0
  273. package/dist/spec/mine/clustering/index.js +259 -0
  274. package/dist/spec/mine/clustering/index.js.map +1 -0
  275. package/dist/spec/mine/clustering/leiden.d.ts +61 -0
  276. package/dist/spec/mine/clustering/leiden.d.ts.map +1 -0
  277. package/dist/spec/mine/clustering/leiden.js +489 -0
  278. package/dist/spec/mine/clustering/leiden.js.map +1 -0
  279. package/dist/spec/mine/clustering/text-similarity.d.ts +22 -0
  280. package/dist/spec/mine/clustering/text-similarity.d.ts.map +1 -0
  281. package/dist/spec/mine/clustering/text-similarity.js +98 -0
  282. package/dist/spec/mine/clustering/text-similarity.js.map +1 -0
  283. package/dist/spec/mine/generator.d.ts +54 -0
  284. package/dist/spec/mine/generator.d.ts.map +1 -0
  285. package/dist/spec/mine/generator.js +267 -0
  286. package/dist/spec/mine/generator.js.map +1 -0
  287. package/dist/spec/mine/persist.d.ts +37 -0
  288. package/dist/spec/mine/persist.d.ts.map +1 -0
  289. package/dist/spec/mine/persist.js +170 -0
  290. package/dist/spec/mine/persist.js.map +1 -0
  291. package/dist/spec/mine/pipeline.d.ts +41 -0
  292. package/dist/spec/mine/pipeline.d.ts.map +1 -0
  293. package/dist/spec/mine/pipeline.js +236 -0
  294. package/dist/spec/mine/pipeline.js.map +1 -0
  295. package/dist/spec/mine/scanner.d.ts +59 -0
  296. package/dist/spec/mine/scanner.d.ts.map +1 -0
  297. package/dist/spec/mine/scanner.js +383 -0
  298. package/dist/spec/mine/scanner.js.map +1 -0
  299. package/dist/spec/types.d.ts +32 -0
  300. package/dist/spec/types.d.ts.map +1 -1
  301. package/dist/spec/ui/index.d.ts +9 -0
  302. package/dist/spec/ui/index.d.ts.map +1 -0
  303. package/dist/spec/ui/index.js +16 -0
  304. package/dist/spec/ui/index.js.map +1 -0
  305. package/dist/spec/ui/progress-handler.d.ts +33 -0
  306. package/dist/spec/ui/progress-handler.d.ts.map +1 -0
  307. package/dist/spec/ui/progress-handler.js +132 -0
  308. package/dist/spec/ui/progress-handler.js.map +1 -0
  309. package/dist/spec/ui/progress.d.ts +24 -0
  310. package/dist/spec/ui/progress.d.ts.map +1 -0
  311. package/dist/spec/ui/progress.js +13 -0
  312. package/dist/spec/ui/progress.js.map +1 -0
  313. package/dist/spec/utils/fs.d.ts +45 -0
  314. package/dist/spec/utils/fs.d.ts.map +1 -0
  315. package/dist/spec/utils/fs.js +163 -0
  316. package/dist/spec/utils/fs.js.map +1 -0
  317. package/dist/spec/utils/index.d.ts +12 -0
  318. package/dist/spec/utils/index.d.ts.map +1 -0
  319. package/dist/spec/utils/index.js +26 -0
  320. package/dist/spec/utils/index.js.map +1 -0
  321. package/dist/spec/utils/meta.d.ts +32 -0
  322. package/dist/spec/utils/meta.d.ts.map +1 -0
  323. package/dist/spec/utils/meta.js +122 -0
  324. package/dist/spec/utils/meta.js.map +1 -0
  325. package/dist/spec/utils/truncate.d.ts +86 -0
  326. package/dist/spec/utils/truncate.d.ts.map +1 -0
  327. package/dist/spec/utils/truncate.js +172 -0
  328. package/dist/spec/utils/truncate.js.map +1 -0
  329. package/dist/sync/watcher.d.ts +25 -1
  330. package/dist/sync/watcher.d.ts.map +1 -1
  331. package/dist/sync/watcher.js +76 -3
  332. package/dist/sync/watcher.js.map +1 -1
  333. package/dist/telemetry/index.js +3 -3
  334. package/dist/telemetry/index.js.map +1 -1
  335. package/dist/types.d.ts +3 -0
  336. package/dist/types.d.ts.map +1 -1
  337. package/package.json +62 -58
  338. package/scripts/_tmp-cfwk-resolve.log +0 -0
  339. package/scripts/_tmp-cfwk-sig.log +0 -0
  340. package/scripts/_tmp-cfwk-vt.log +0 -0
  341. package/scripts/add-lang/bench.sh +60 -60
  342. package/scripts/add-lang/check-grammar.mjs +75 -75
  343. package/scripts/add-lang/dump-ast.mjs +103 -103
  344. package/scripts/add-lang/verify-extraction.mjs +70 -70
  345. package/scripts/agent-eval/ab-adoption.sh +91 -91
  346. package/scripts/agent-eval/ab-hook.sh +86 -86
  347. package/scripts/agent-eval/ab-impl.sh +78 -78
  348. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  349. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  350. package/scripts/agent-eval/arms-F.sh +21 -21
  351. package/scripts/agent-eval/arms-matrix.sh +37 -37
  352. package/scripts/agent-eval/audit.sh +68 -68
  353. package/scripts/agent-eval/bench-readme.sh +28 -28
  354. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  355. package/scripts/agent-eval/block-read-hook.sh +19 -19
  356. package/scripts/agent-eval/hook-settings.json +15 -15
  357. package/scripts/agent-eval/itrun.sh +120 -120
  358. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  359. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  360. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  361. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  362. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  363. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  364. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  365. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  366. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  367. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  368. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  369. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  370. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  371. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  372. package/scripts/agent-eval/offload-eval.md +76 -76
  373. package/scripts/agent-eval/parse-arms.mjs +116 -116
  374. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  375. package/scripts/agent-eval/parse-run.mjs +45 -45
  376. package/scripts/agent-eval/parse-session.mjs +93 -93
  377. package/scripts/agent-eval/probe-context.mjs +21 -21
  378. package/scripts/agent-eval/probe-explore.mjs +40 -40
  379. package/scripts/agent-eval/probe-node.mjs +20 -20
  380. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  381. package/scripts/agent-eval/probe-trace.mjs +20 -20
  382. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  383. package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -119
  384. package/scripts/agent-eval/repro-daemon-clients.mjs +125 -125
  385. package/scripts/agent-eval/run-agent.sh +34 -34
  386. package/scripts/agent-eval/run-all.sh +75 -75
  387. package/scripts/agent-eval/run-arms.sh +56 -56
  388. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  389. package/scripts/bench-arkts-init-rss.log +0 -0
  390. package/scripts/build-bundle.sh +123 -123
  391. package/scripts/exp_boundary_eval/README.md +247 -247
  392. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
  393. package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-38.pyc +0 -0
  394. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
  395. package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-38.pyc +0 -0
  396. package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-38.pyc +0 -0
  397. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-310.pyc +0 -0
  398. package/scripts/exp_boundary_eval/__pycache__/run_all.cpython-38.pyc +0 -0
  399. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
  400. package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-38.pyc +0 -0
  401. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
  402. package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-38.pyc +0 -0
  403. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
  404. package/scripts/exp_boundary_eval/__pycache__/setup.cpython-38.pyc +0 -0
  405. package/scripts/exp_boundary_eval/__pycache__/win_mcp_launcher.cpython-38.pyc +0 -0
  406. package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -78
  407. package/scripts/exp_boundary_eval/_test_stdin.py +8 -8
  408. package/scripts/exp_boundary_eval/_utils.py +1116 -1116
  409. package/scripts/exp_boundary_eval/analyze.py +1313 -1313
  410. package/scripts/exp_boundary_eval/deveco_arm.py +519 -519
  411. package/scripts/exp_boundary_eval/run_all.py +378 -378
  412. package/scripts/exp_boundary_eval/run_one.py +165 -165
  413. package/scripts/exp_boundary_eval/run_session.py +158 -158
  414. package/scripts/exp_boundary_eval/setup.py +120 -120
  415. package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -73
  416. package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -36
  417. package/scripts/exp_boundary_eval/win_node_launcher.py +24 -24
  418. package/scripts/extract-release-notes.mjs +130 -130
  419. package/scripts/local-install.sh +41 -41
  420. package/scripts/npm-sdk.js +75 -75
  421. package/scripts/npm-shim.js +275 -275
  422. package/scripts/ohos-sdk-publish.mjs +133 -133
  423. package/scripts/pack-npm.sh +119 -119
  424. package/scripts/prepare-release.mjs +270 -270
  425. package/scripts/probe-arkts-mem-why-run.log +0 -0
  426. package/scripts/probe-banner-livecard-ir.log +0 -0
  427. package/scripts/probe-cfwk-ast.stderr.log +0 -0
  428. package/scripts/probe-cfwk-ast.stdout.log +0 -0
  429. package/scripts/probe-cfwk-attr-shape.log +0 -0
  430. package/scripts/probe-cfwk-cfgdump.stderr.log +0 -0
  431. package/scripts/probe-cfwk-cfgdump.stdout.log +0 -0
  432. package/scripts/probe-cfwk-cvc.stderr.log +0 -0
  433. package/scripts/probe-cfwk-cvc.stdout.log +0 -0
  434. package/scripts/probe-cfwk-diag2.log +0 -0
  435. package/scripts/probe-cfwk-diag3.log +0 -0
  436. package/scripts/probe-cfwk-fedbg.stderr.log +0 -0
  437. package/scripts/probe-cfwk-fedbg.stdout.log +0 -0
  438. package/scripts/probe-cfwk-fileresult.log +0 -0
  439. package/scripts/probe-cfwk-fix.stderr.log +0 -0
  440. package/scripts/probe-cfwk-fix.stdout.log +0 -0
  441. package/scripts/probe-cfwk-fix2.stderr.log +0 -0
  442. package/scripts/probe-cfwk-fix2.stdout.log +0 -0
  443. package/scripts/probe-cfwk-fix3.stderr.log +0 -0
  444. package/scripts/probe-cfwk-fix3.stdout.log +0 -0
  445. package/scripts/probe-cfwk-foreach.log +0 -0
  446. package/scripts/probe-cfwk-getmethod-throw.log +0 -0
  447. package/scripts/probe-cfwk-hg-extract.log +0 -0
  448. package/scripts/probe-cfwk-pr1003-noprior.stderr.log +0 -0
  449. package/scripts/probe-cfwk-pr1003-noprior.stdout.log +0 -0
  450. package/scripts/probe-cfwk-pr1003.stderr.log +0 -0
  451. package/scripts/probe-cfwk-pr1003.stdout.log +0 -0
  452. package/scripts/probe-cfwk-preroot-noprior.stderr.log +0 -0
  453. package/scripts/probe-cfwk-preroot-noprior.stdout.log +0 -0
  454. package/scripts/probe-cfwk-preroot-prior.stderr.log +0 -0
  455. package/scripts/probe-cfwk-preroot-prior.stdout.log +0 -0
  456. package/scripts/probe-cfwk-preroot-skipstate.stderr.log +0 -0
  457. package/scripts/probe-cfwk-preroot-skipstate.stdout.log +0 -0
  458. package/scripts/probe-cfwk-resolve-sim.log +0 -0
  459. package/scripts/probe-cfwk-tree-shape.log +0 -0
  460. package/scripts/probe-cfwk-walk-abort.log +0 -0
  461. package/scripts/probe-cfwk.log +0 -0
  462. package/scripts/probe-force-index.log +0 -0
  463. package/scripts/probe-no-force-index.log +0 -0
  464. package/scripts/probe-samefile-ir.stderr.log +0 -0
  465. package/scripts/probe-samefile-ir.stdout.log +224 -0
  466. package/scripts/probe-sdk-vs-project.log +0 -0
  467. package/scripts/probe-viewtree-downgrade.log +0 -0
  468. package/dist/arkts/ohos-api-index.d.ts +0 -15
  469. package/dist/arkts/ohos-api-index.d.ts.map +0 -1
  470. package/dist/arkts/ohos-api-index.js +0 -190
  471. package/dist/arkts/ohos-api-index.js.map +0 -1
  472. package/dist/arkts/ohos-sdk-input.d.ts +0 -36
  473. package/dist/arkts/ohos-sdk-input.d.ts.map +0 -1
  474. package/dist/arkts/ohos-sdk-input.js +0 -214
  475. package/dist/arkts/ohos-sdk-input.js.map +0 -1
  476. package/dist/extraction/languages/arkts-state-decorators.d.ts +0 -13
  477. package/dist/extraction/languages/arkts-state-decorators.d.ts.map +0 -1
  478. package/dist/extraction/languages/arkts-state-decorators.js +0 -26
  479. package/dist/extraction/languages/arkts-state-decorators.js.map +0 -1
  480. package/dist/extraction/languages/ohos-api-consumer.d.ts +0 -34
  481. package/dist/extraction/languages/ohos-api-consumer.d.ts.map +0 -1
  482. package/dist/extraction/languages/ohos-api-consumer.js +0 -283
  483. package/dist/extraction/languages/ohos-api-consumer.js.map +0 -1
@@ -1,378 +1,378 @@
1
- #!/usr/bin/env python3
2
- """
3
- Run boundary-eval experiments sequentially. Multi-agent + HomeGraph A/B arm support.
4
-
5
- Usage:
6
- python run_all.py --both-arms --agent deveco # 一条命令跑 baseline + homegraph
7
- python run_all.py --agent deveco --arm homegraph
8
- python run_all.py --agent deveco --arm baseline
9
- python run_all.py 1-1 1-2 1-3
10
- python run_all.py --repo-path /path/to/photos
11
- python run_all.py --both-arms --agent deveco --repo-path /path/to/photos --skip-index
12
- """
13
-
14
- import argparse
15
- import json
16
- import os
17
- import shutil
18
- import subprocess
19
- import sys
20
- from pathlib import Path
21
- from typing import Optional, Tuple
22
-
23
- import run_one
24
- import run_session
25
- import analyze
26
- from _utils import (DATA_DIR, EVAL_ROOT, LOG_DIR, OUTPUT_DIR, GREEN, NC, append_run_log,
27
- current_time_ms, create_output_dirs, error, get_agent, header,
28
- info, load_config, log, subprocess_no_window_kwargs, verify_agent_binary, warn)
29
- from deveco_arm import (ensure_homegraph_index, git_clean_repo,
30
- write_deveco_project_config)
31
-
32
- DEFAULT_EXPERIMENTS = ["1-1", "1-2", "1-3"]
33
- SHARED_CLONE_DIR = DATA_DIR / "clone"
34
-
35
-
36
- _NW = subprocess_no_window_kwargs()
37
-
38
-
39
- def clone_repo(url: str, branch: str, clone_dir: Path) -> bool:
40
- clone_dir = Path(clone_dir)
41
- if (clone_dir / ".git").is_dir():
42
- log(f"Clone exists, updating: {clone_dir}")
43
- subprocess.run(["git", "fetch", "origin", branch], cwd=clone_dir, capture_output=True, text=True, **_NW)
44
- subprocess.run(["git", "checkout", branch], cwd=clone_dir, capture_output=True, text=True, **_NW)
45
- subprocess.run(["git", "reset", "--hard", f"origin/{branch}"], cwd=clone_dir, capture_output=True, text=True, **_NW)
46
- return True
47
- log(f"Cloning {url} (branch: {branch})...")
48
- if clone_dir.exists():
49
- shutil.rmtree(clone_dir)
50
- clone_dir.parent.mkdir(parents=True, exist_ok=True)
51
- r = subprocess.run(
52
- ["git", "clone", "--depth", "1", "--branch", branch, url, str(clone_dir)],
53
- capture_output=True, text=True,
54
- **_NW,
55
- )
56
- if r.returncode != 0:
57
- error(f"Clone failed: {r.stderr}")
58
- return False
59
- r2 = subprocess.run(["git", "rev-parse", "--short", "HEAD"], capture_output=True, text=True, cwd=clone_dir, **_NW)
60
- log(f"Clone complete: {r2.stdout.strip()}")
61
- return True
62
-
63
-
64
- def reset_clone(clone_dir: Path, branch: str, arm: str = "baseline"):
65
- subprocess.run(["git", "checkout", branch], cwd=clone_dir, capture_output=True, text=True, **_NW)
66
- subprocess.run(["git", "checkout", "."], cwd=clone_dir, capture_output=True, text=True, **_NW)
67
- git_clean_repo(clone_dir, arm)
68
-
69
-
70
- def reset_local(work_dir: Path, arm: str = "baseline"):
71
- subprocess.run(["git", "checkout", "."], cwd=work_dir, capture_output=True, text=True, **_NW)
72
- git_clean_repo(work_dir, arm)
73
-
74
-
75
- def ensure_homegraph_index_for_arm(
76
- repo_root: Path, arm: str, *, skip_index: bool = False,
77
- ) -> dict:
78
- """Index repo when running the homegraph arm."""
79
- if arm != "homegraph":
80
- return {"homegraph_index_ms": 0, "homegraph_index_success": None}
81
- return ensure_homegraph_index(repo_root, skip=skip_index)
82
-
83
-
84
- def write_run_manifest(state_dir: Path, results_dir: Path, meta: dict):
85
- manifest = {
86
- **meta,
87
- "results_dir": str(results_dir),
88
- "state_dir": str(state_dir),
89
- }
90
- for d in (state_dir, results_dir):
91
- d.mkdir(parents=True, exist_ok=True)
92
- (d / "run_manifest.json").write_text(
93
- json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8"
94
- )
95
-
96
-
97
- def resolve_work_dir(args, state_dir: Path) -> Tuple[Path, Optional[Path], bool]:
98
- """Return (work_dir, ephemeral_clone_dir_or_none, owns_ephemeral_clone)."""
99
- if args.repo_path:
100
- work_dir = Path(args.repo_path).resolve()
101
- if not (work_dir / ".git").is_dir():
102
- error(f"--repo-path 不是 git 仓库: {work_dir}")
103
- sys.exit(1)
104
- os.environ["REPO_PATH"] = str(work_dir)
105
- os.environ.pop("REPO_CLONE", None)
106
- log(f"使用本地仓库: {work_dir}")
107
- return work_dir, None, False
108
-
109
- if args.both_arms:
110
- clone_dir = SHARED_CLONE_DIR
111
- if not clone_repo(args.repo_url, args.branch, clone_dir):
112
- error("Clone 失败。请检查网络,或改用 --repo-path。")
113
- sys.exit(1)
114
- os.environ["REPO_PATH"] = str(clone_dir)
115
- os.environ.pop("REPO_CLONE", None)
116
- log(f"A/B 共用仓库: {clone_dir}")
117
- return clone_dir, None, False
118
-
119
- clone_dir = state_dir / "clone"
120
- if not clone_repo(args.repo_url, args.branch, clone_dir):
121
- error("Clone 失败。请改用 --repo-path 指定本地 checkout。")
122
- sys.exit(1)
123
- os.environ["REPO_CLONE"] = str(clone_dir)
124
- os.environ.pop("REPO_PATH", None)
125
- return clone_dir, clone_dir, True
126
-
127
-
128
- def run_suite(
129
- args, arm: str, *, prebuilt_index_meta: Optional[dict] = None,
130
- ) -> dict:
131
- """Run one arm (baseline or homegraph). Returns summary dict."""
132
- agent = get_agent(args.agent)
133
- skip_perms = not args.no_skip_permissions
134
- experiments = args.experiments or DEFAULT_EXPERIMENTS
135
- total = len(experiments)
136
- passed = 0
137
- failed = 0
138
-
139
- results_dir, state_dir = create_output_dirs(args.agent or "default", arm)
140
- work_dir, ephemeral_clone, owns_clone = resolve_work_dir(args, state_dir)
141
-
142
- if arm == "baseline":
143
- hg_dir = work_dir / ".homegraph"
144
- if hg_dir.exists():
145
- log("Baseline: 保留 .homegraph(A/B 共用仓库;baseline 通过 deveco.jsonc deny homegraph_* 隔离)")
146
-
147
- if prebuilt_index_meta is not None:
148
- index_meta = prebuilt_index_meta
149
- else:
150
- index_meta = ensure_homegraph_index_for_arm(
151
- work_dir, arm, skip_index=getattr(args, "skip_index", False),
152
- )
153
-
154
- if arm == "homegraph" and not index_meta.get("homegraph_index_success"):
155
- error("HomeGraph 索引失败,homegraph 组无法评测。")
156
- err = index_meta.get("homegraph_index_error", "")
157
- if err:
158
- error(f" 原因: {err}")
159
- error(" 请先在 homegraph 仓库执行 npm run build,再重试 run_all.py --arm homegraph")
160
- append_run_log(state_dir, f"ABORT: homegraph index failed: {err}")
161
- write_run_manifest(state_dir, results_dir, {
162
- "arm": arm, "agent": agent["name"], "agent_key": args.agent,
163
- "branch": args.branch, "repo_url": args.repo_url,
164
- "repo_root": str(work_dir), "experiments": experiments,
165
- "aborted": True, **index_meta,
166
- })
167
- sys.exit(1)
168
-
169
- if agent.get("binary") == "deveco":
170
- write_deveco_project_config(work_dir, arm)
171
-
172
- write_run_manifest(state_dir, results_dir, {
173
- "arm": arm,
174
- "agent": agent["name"],
175
- "agent_key": args.agent,
176
- "branch": args.branch,
177
- "repo_url": args.repo_url,
178
- "repo_root": str(work_dir),
179
- "experiments": experiments,
180
- **index_meta,
181
- })
182
- append_run_log(state_dir, f"开始: arm={arm}, agent={agent['name']}, exps={experiments}")
183
-
184
- os.environ["EVAL_ARM"] = arm
185
-
186
- header(f"边界评测 — 档位切换 ({arm})")
187
- print(f"组别 : {arm}")
188
- print(f"Agent : {agent['name']} ({agent['binary']})")
189
- print(f"仓库 : {work_dir}")
190
- print(f"分支 : {args.branch}")
191
- print(f"权限 : {'跳过确认' if skip_perms else '需确认'}")
192
- print(f"实验数 : {total}")
193
- print(f"输出 : {results_dir}")
194
- print(f"日志 : {state_dir}\n")
195
-
196
- overall_start = current_time_ms()
197
-
198
- for exp_id in experiments:
199
- header(f"实验 {exp_id}")
200
- append_run_log(state_dir, f"开始实验 {exp_id}")
201
-
202
- if ephemeral_clone:
203
- log("重置 clone 到干净状态...")
204
- reset_clone(ephemeral_clone, args.branch, arm)
205
- else:
206
- log("重置本地仓库...")
207
- reset_local(work_dir, arm)
208
-
209
- if exp_id == "5":
210
- ok = run_session.run_session("5", skip_perms, args.agent,
211
- results_dir=results_dir, state_dir=state_dir)
212
- else:
213
- ok = run_one.run_experiment(exp_id, skip_perms, args.agent,
214
- results_dir=results_dir, state_dir=state_dir)
215
-
216
- if ok:
217
- passed += 1
218
- else:
219
- failed += 1
220
- error(f"实验 {exp_id} 失败")
221
- print()
222
-
223
- overall_end = current_time_ms()
224
- duration = (overall_end - overall_start) // 1000
225
-
226
- append_run_log(state_dir, f"完成: passed={passed}, failed={failed}, duration_s={duration}")
227
-
228
- header(f"组别完成 — {arm}")
229
- print(f" 通过 : {passed} / {total}")
230
- print(f" 失败 : {failed} / {total}")
231
- print(f" 耗时 : {duration // 60}m {duration % 60}s")
232
- print(f" 输出 : {results_dir}")
233
- print(f" 日志 : {state_dir}")
234
-
235
- if owns_clone and ephemeral_clone and not args.keep_clone and ephemeral_clone.exists():
236
- warn(f"删除临时 clone: {ephemeral_clone}")
237
- shutil.rmtree(ephemeral_clone)
238
-
239
- return {
240
- "arm": arm,
241
- "results_dir": results_dir,
242
- "state_dir": state_dir,
243
- "passed": passed,
244
- "failed": failed,
245
- "duration_s": duration,
246
- "homegraph_index_ms": index_meta.get("homegraph_index_ms", 0),
247
- }
248
-
249
-
250
- def _generate_reports(summaries: list, agent_key: str):
251
- """Run analyze.py logic after experiments; print report paths."""
252
- reports = []
253
- for s in summaries:
254
- try:
255
- path = analyze.analyze_run(s["results_dir"], verbose=False)
256
- reports.append((s["arm"], path))
257
- except ValueError as e:
258
- warn(f"分析 {s['arm']} 失败: {e}")
259
-
260
- compare_path = None
261
- if len(summaries) == 2 and len(reports) == 2:
262
- try:
263
- baseline_s = next(s for s in summaries if s["arm"] == "baseline")
264
- homegraph_s = next(s for s in summaries if s["arm"] == "homegraph")
265
- compare_path = analyze.compare_runs(
266
- baseline_s["results_dir"],
267
- homegraph_s["results_dir"],
268
- agent=agent_key,
269
- baseline_wall_s=baseline_s["duration_s"],
270
- homegraph_wall_s=homegraph_s["duration_s"],
271
- verbose=True,
272
- )
273
- except ValueError as e:
274
- warn(f"A/B 对比报告失败: {e}")
275
-
276
- baseline_report = next((p for arm, p in reports if arm == "baseline"), None)
277
- homegraph_report = next((p for arm, p in reports if arm == "homegraph"), None)
278
- single_report = reports[0][1] if len(reports) == 1 else None
279
-
280
- analyze.print_report_locations(
281
- baseline_report=baseline_report,
282
- homegraph_report=homegraph_report,
283
- compare_report=compare_path,
284
- single_report=single_report,
285
- )
286
- return reports, compare_path
287
-
288
-
289
- def _blocking_homegraph_index(work_dir: Path, *, skip_index: bool = False) -> dict:
290
- """Run full ``homegraph index`` and block until complete (or validate existing index)."""
291
- if skip_index:
292
- header("HomeGraph 索引检查(--skip-index,不执行 index)")
293
- else:
294
- header("HomeGraph 全量 index(阻塞,Photos 约 15–30 分钟)")
295
- log(f"仓库: {work_dir}")
296
- if skip_index:
297
- log("模式: 仅校验已有 .homegraph/(可从同 commit 的其他机器复制整个目录)")
298
- else:
299
- log("命令: node --stack-size=8192 … homegraph index(见 deveco_arm.HOMEGRAPH_NODE_STACK_SIZE_KB)")
300
- meta = ensure_homegraph_index(work_dir, skip=skip_index)
301
- if not meta.get("homegraph_index_success"):
302
- error("HomeGraph index 失败,中止。")
303
- err = meta.get("homegraph_index_error", "")
304
- if err:
305
- error(f" 原因: {err}")
306
- sys.exit(1)
307
- return meta
308
-
309
-
310
- def main():
311
- analyze._configure_stdout()
312
- cfg = load_config()
313
- meta = cfg.get("meta", {})
314
-
315
- parser = argparse.ArgumentParser(description="HomeGraph 档位切换边界评测")
316
- parser.add_argument("--agent", default=os.environ.get("EVAL_AGENT", "deveco"),
317
- help="Agent:claude / cursor / codex / opencode / deveco")
318
- parser.add_argument("--arm", default=os.environ.get("EVAL_ARM", "baseline"),
319
- choices=["baseline", "homegraph"],
320
- help="baseline=不带 HomeGraph;homegraph=带 HomeGraph")
321
- parser.add_argument("--both-arms", action="store_true",
322
- help="一条命令依次跑 baseline 和 homegraph 两组 A/B")
323
- parser.add_argument("--repo-path", default=os.environ.get("REPO_PATH", ""),
324
- help="使用已有本地 clone,跳过 git clone")
325
- parser.add_argument("--keep-clone", action="store_true")
326
- parser.add_argument(
327
- "--skip-index",
328
- action="store_true",
329
- help="不跑 homegraph init/index;要求仓库根目录已有健康的 .homegraph/(可复制自同 commit 的其他 checkout)",
330
- )
331
- parser.add_argument("--no-skip-permissions", action="store_true")
332
- parser.add_argument("--branch", default=os.environ.get("BRANCH", meta.get("default_branch", "weekly_20260601")))
333
- parser.add_argument("--repo-url", default=os.environ.get("REPO_URL", meta.get("repo_url", "")))
334
- parser.add_argument("experiments", nargs="*")
335
- args = parser.parse_args()
336
-
337
- if not args.experiments:
338
- args.experiments = DEFAULT_EXPERIMENTS
339
-
340
- agent = get_agent(args.agent)
341
- ok, resolved, err_msg = verify_agent_binary(agent)
342
- if not ok:
343
- error(err_msg)
344
- sys.exit(1)
345
- log(f"Agent CLI: {resolved}")
346
-
347
- if args.both_arms and args.arm != "baseline":
348
- warn("--both-arms 已指定,忽略 --arm")
349
-
350
- if args.both_arms:
351
- _rd, _sd = create_output_dirs(args.agent or "default", "baseline")
352
- work_dir, _, _ = resolve_work_dir(args, _sd)
353
-
354
- # Index FIRST so the user sees it immediately (15–30 min); baseline does not use MCP.
355
- index_meta = _blocking_homegraph_index(work_dir, skip_index=args.skip_index)
356
-
357
- summaries = []
358
- print(f"\n{'=' * 60}\n 开始 homegraph 组(先看 HomeGraph 是否生效)\n{'=' * 60}\n")
359
- summaries.append(run_suite(args, "homegraph", prebuilt_index_meta=index_meta))
360
-
361
- print(f"\n{'=' * 60}\n 开始 baseline 组(无 HomeGraph)\n{'=' * 60}\n")
362
- summaries.append(run_suite(args, "baseline"))
363
-
364
- header("A/B 全部完成")
365
- for s in summaries:
366
- print(f" [{s['arm']}] 通过 {s['passed']},失败 {s['failed']},"
367
- f"耗时 {s['duration_s'] // 60}m{s['duration_s'] % 60}s")
368
- print(f" 输出 → {s['results_dir']}")
369
- _generate_reports(summaries, args.agent or "default")
370
- sys.exit(0 if all(s["failed"] == 0 for s in summaries) else 1)
371
-
372
- summary = run_suite(args, args.arm)
373
- _generate_reports([summary], args.agent or "default")
374
- sys.exit(0 if summary["failed"] == 0 else 1)
375
-
376
-
377
- if __name__ == "__main__":
378
- main()
1
+ #!/usr/bin/env python3
2
+ """
3
+ Run boundary-eval experiments sequentially. Multi-agent + HomeGraph A/B arm support.
4
+
5
+ Usage:
6
+ python run_all.py --both-arms --agent deveco # 一条命令跑 baseline + homegraph
7
+ python run_all.py --agent deveco --arm homegraph
8
+ python run_all.py --agent deveco --arm baseline
9
+ python run_all.py 1-1 1-2 1-3
10
+ python run_all.py --repo-path /path/to/photos
11
+ python run_all.py --both-arms --agent deveco --repo-path /path/to/photos --skip-index
12
+ """
13
+
14
+ import argparse
15
+ import json
16
+ import os
17
+ import shutil
18
+ import subprocess
19
+ import sys
20
+ from pathlib import Path
21
+ from typing import Optional, Tuple
22
+
23
+ import run_one
24
+ import run_session
25
+ import analyze
26
+ from _utils import (DATA_DIR, EVAL_ROOT, LOG_DIR, OUTPUT_DIR, GREEN, NC, append_run_log,
27
+ current_time_ms, create_output_dirs, error, get_agent, header,
28
+ info, load_config, log, subprocess_no_window_kwargs, verify_agent_binary, warn)
29
+ from deveco_arm import (ensure_homegraph_index, git_clean_repo,
30
+ write_deveco_project_config)
31
+
32
+ DEFAULT_EXPERIMENTS = ["1-1", "1-2", "1-3"]
33
+ SHARED_CLONE_DIR = DATA_DIR / "clone"
34
+
35
+
36
+ _NW = subprocess_no_window_kwargs()
37
+
38
+
39
+ def clone_repo(url: str, branch: str, clone_dir: Path) -> bool:
40
+ clone_dir = Path(clone_dir)
41
+ if (clone_dir / ".git").is_dir():
42
+ log(f"Clone exists, updating: {clone_dir}")
43
+ subprocess.run(["git", "fetch", "origin", branch], cwd=clone_dir, capture_output=True, text=True, **_NW)
44
+ subprocess.run(["git", "checkout", branch], cwd=clone_dir, capture_output=True, text=True, **_NW)
45
+ subprocess.run(["git", "reset", "--hard", f"origin/{branch}"], cwd=clone_dir, capture_output=True, text=True, **_NW)
46
+ return True
47
+ log(f"Cloning {url} (branch: {branch})...")
48
+ if clone_dir.exists():
49
+ shutil.rmtree(clone_dir)
50
+ clone_dir.parent.mkdir(parents=True, exist_ok=True)
51
+ r = subprocess.run(
52
+ ["git", "clone", "--depth", "1", "--branch", branch, url, str(clone_dir)],
53
+ capture_output=True, text=True,
54
+ **_NW,
55
+ )
56
+ if r.returncode != 0:
57
+ error(f"Clone failed: {r.stderr}")
58
+ return False
59
+ r2 = subprocess.run(["git", "rev-parse", "--short", "HEAD"], capture_output=True, text=True, cwd=clone_dir, **_NW)
60
+ log(f"Clone complete: {r2.stdout.strip()}")
61
+ return True
62
+
63
+
64
+ def reset_clone(clone_dir: Path, branch: str, arm: str = "baseline"):
65
+ subprocess.run(["git", "checkout", branch], cwd=clone_dir, capture_output=True, text=True, **_NW)
66
+ subprocess.run(["git", "checkout", "."], cwd=clone_dir, capture_output=True, text=True, **_NW)
67
+ git_clean_repo(clone_dir, arm)
68
+
69
+
70
+ def reset_local(work_dir: Path, arm: str = "baseline"):
71
+ subprocess.run(["git", "checkout", "."], cwd=work_dir, capture_output=True, text=True, **_NW)
72
+ git_clean_repo(work_dir, arm)
73
+
74
+
75
+ def ensure_homegraph_index_for_arm(
76
+ repo_root: Path, arm: str, *, skip_index: bool = False,
77
+ ) -> dict:
78
+ """Index repo when running the homegraph arm."""
79
+ if arm != "homegraph":
80
+ return {"homegraph_index_ms": 0, "homegraph_index_success": None}
81
+ return ensure_homegraph_index(repo_root, skip=skip_index)
82
+
83
+
84
+ def write_run_manifest(state_dir: Path, results_dir: Path, meta: dict):
85
+ manifest = {
86
+ **meta,
87
+ "results_dir": str(results_dir),
88
+ "state_dir": str(state_dir),
89
+ }
90
+ for d in (state_dir, results_dir):
91
+ d.mkdir(parents=True, exist_ok=True)
92
+ (d / "run_manifest.json").write_text(
93
+ json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8"
94
+ )
95
+
96
+
97
+ def resolve_work_dir(args, state_dir: Path) -> Tuple[Path, Optional[Path], bool]:
98
+ """Return (work_dir, ephemeral_clone_dir_or_none, owns_ephemeral_clone)."""
99
+ if args.repo_path:
100
+ work_dir = Path(args.repo_path).resolve()
101
+ if not (work_dir / ".git").is_dir():
102
+ error(f"--repo-path 不是 git 仓库: {work_dir}")
103
+ sys.exit(1)
104
+ os.environ["REPO_PATH"] = str(work_dir)
105
+ os.environ.pop("REPO_CLONE", None)
106
+ log(f"使用本地仓库: {work_dir}")
107
+ return work_dir, None, False
108
+
109
+ if args.both_arms:
110
+ clone_dir = SHARED_CLONE_DIR
111
+ if not clone_repo(args.repo_url, args.branch, clone_dir):
112
+ error("Clone 失败。请检查网络,或改用 --repo-path。")
113
+ sys.exit(1)
114
+ os.environ["REPO_PATH"] = str(clone_dir)
115
+ os.environ.pop("REPO_CLONE", None)
116
+ log(f"A/B 共用仓库: {clone_dir}")
117
+ return clone_dir, None, False
118
+
119
+ clone_dir = state_dir / "clone"
120
+ if not clone_repo(args.repo_url, args.branch, clone_dir):
121
+ error("Clone 失败。请改用 --repo-path 指定本地 checkout。")
122
+ sys.exit(1)
123
+ os.environ["REPO_CLONE"] = str(clone_dir)
124
+ os.environ.pop("REPO_PATH", None)
125
+ return clone_dir, clone_dir, True
126
+
127
+
128
+ def run_suite(
129
+ args, arm: str, *, prebuilt_index_meta: Optional[dict] = None,
130
+ ) -> dict:
131
+ """Run one arm (baseline or homegraph). Returns summary dict."""
132
+ agent = get_agent(args.agent)
133
+ skip_perms = not args.no_skip_permissions
134
+ experiments = args.experiments or DEFAULT_EXPERIMENTS
135
+ total = len(experiments)
136
+ passed = 0
137
+ failed = 0
138
+
139
+ results_dir, state_dir = create_output_dirs(args.agent or "default", arm)
140
+ work_dir, ephemeral_clone, owns_clone = resolve_work_dir(args, state_dir)
141
+
142
+ if arm == "baseline":
143
+ hg_dir = work_dir / ".homegraph"
144
+ if hg_dir.exists():
145
+ log("Baseline: 保留 .homegraph(A/B 共用仓库;baseline 通过 deveco.jsonc deny homegraph_* 隔离)")
146
+
147
+ if prebuilt_index_meta is not None:
148
+ index_meta = prebuilt_index_meta
149
+ else:
150
+ index_meta = ensure_homegraph_index_for_arm(
151
+ work_dir, arm, skip_index=getattr(args, "skip_index", False),
152
+ )
153
+
154
+ if arm == "homegraph" and not index_meta.get("homegraph_index_success"):
155
+ error("HomeGraph 索引失败,homegraph 组无法评测。")
156
+ err = index_meta.get("homegraph_index_error", "")
157
+ if err:
158
+ error(f" 原因: {err}")
159
+ error(" 请先在 homegraph 仓库执行 npm run build,再重试 run_all.py --arm homegraph")
160
+ append_run_log(state_dir, f"ABORT: homegraph index failed: {err}")
161
+ write_run_manifest(state_dir, results_dir, {
162
+ "arm": arm, "agent": agent["name"], "agent_key": args.agent,
163
+ "branch": args.branch, "repo_url": args.repo_url,
164
+ "repo_root": str(work_dir), "experiments": experiments,
165
+ "aborted": True, **index_meta,
166
+ })
167
+ sys.exit(1)
168
+
169
+ if agent.get("binary") == "deveco":
170
+ write_deveco_project_config(work_dir, arm)
171
+
172
+ write_run_manifest(state_dir, results_dir, {
173
+ "arm": arm,
174
+ "agent": agent["name"],
175
+ "agent_key": args.agent,
176
+ "branch": args.branch,
177
+ "repo_url": args.repo_url,
178
+ "repo_root": str(work_dir),
179
+ "experiments": experiments,
180
+ **index_meta,
181
+ })
182
+ append_run_log(state_dir, f"开始: arm={arm}, agent={agent['name']}, exps={experiments}")
183
+
184
+ os.environ["EVAL_ARM"] = arm
185
+
186
+ header(f"边界评测 — 档位切换 ({arm})")
187
+ print(f"组别 : {arm}")
188
+ print(f"Agent : {agent['name']} ({agent['binary']})")
189
+ print(f"仓库 : {work_dir}")
190
+ print(f"分支 : {args.branch}")
191
+ print(f"权限 : {'跳过确认' if skip_perms else '需确认'}")
192
+ print(f"实验数 : {total}")
193
+ print(f"输出 : {results_dir}")
194
+ print(f"日志 : {state_dir}\n")
195
+
196
+ overall_start = current_time_ms()
197
+
198
+ for exp_id in experiments:
199
+ header(f"实验 {exp_id}")
200
+ append_run_log(state_dir, f"开始实验 {exp_id}")
201
+
202
+ if ephemeral_clone:
203
+ log("重置 clone 到干净状态...")
204
+ reset_clone(ephemeral_clone, args.branch, arm)
205
+ else:
206
+ log("重置本地仓库...")
207
+ reset_local(work_dir, arm)
208
+
209
+ if exp_id == "5":
210
+ ok = run_session.run_session("5", skip_perms, args.agent,
211
+ results_dir=results_dir, state_dir=state_dir)
212
+ else:
213
+ ok = run_one.run_experiment(exp_id, skip_perms, args.agent,
214
+ results_dir=results_dir, state_dir=state_dir)
215
+
216
+ if ok:
217
+ passed += 1
218
+ else:
219
+ failed += 1
220
+ error(f"实验 {exp_id} 失败")
221
+ print()
222
+
223
+ overall_end = current_time_ms()
224
+ duration = (overall_end - overall_start) // 1000
225
+
226
+ append_run_log(state_dir, f"完成: passed={passed}, failed={failed}, duration_s={duration}")
227
+
228
+ header(f"组别完成 — {arm}")
229
+ print(f" 通过 : {passed} / {total}")
230
+ print(f" 失败 : {failed} / {total}")
231
+ print(f" 耗时 : {duration // 60}m {duration % 60}s")
232
+ print(f" 输出 : {results_dir}")
233
+ print(f" 日志 : {state_dir}")
234
+
235
+ if owns_clone and ephemeral_clone and not args.keep_clone and ephemeral_clone.exists():
236
+ warn(f"删除临时 clone: {ephemeral_clone}")
237
+ shutil.rmtree(ephemeral_clone)
238
+
239
+ return {
240
+ "arm": arm,
241
+ "results_dir": results_dir,
242
+ "state_dir": state_dir,
243
+ "passed": passed,
244
+ "failed": failed,
245
+ "duration_s": duration,
246
+ "homegraph_index_ms": index_meta.get("homegraph_index_ms", 0),
247
+ }
248
+
249
+
250
+ def _generate_reports(summaries: list, agent_key: str):
251
+ """Run analyze.py logic after experiments; print report paths."""
252
+ reports = []
253
+ for s in summaries:
254
+ try:
255
+ path = analyze.analyze_run(s["results_dir"], verbose=False)
256
+ reports.append((s["arm"], path))
257
+ except ValueError as e:
258
+ warn(f"分析 {s['arm']} 失败: {e}")
259
+
260
+ compare_path = None
261
+ if len(summaries) == 2 and len(reports) == 2:
262
+ try:
263
+ baseline_s = next(s for s in summaries if s["arm"] == "baseline")
264
+ homegraph_s = next(s for s in summaries if s["arm"] == "homegraph")
265
+ compare_path = analyze.compare_runs(
266
+ baseline_s["results_dir"],
267
+ homegraph_s["results_dir"],
268
+ agent=agent_key,
269
+ baseline_wall_s=baseline_s["duration_s"],
270
+ homegraph_wall_s=homegraph_s["duration_s"],
271
+ verbose=True,
272
+ )
273
+ except ValueError as e:
274
+ warn(f"A/B 对比报告失败: {e}")
275
+
276
+ baseline_report = next((p for arm, p in reports if arm == "baseline"), None)
277
+ homegraph_report = next((p for arm, p in reports if arm == "homegraph"), None)
278
+ single_report = reports[0][1] if len(reports) == 1 else None
279
+
280
+ analyze.print_report_locations(
281
+ baseline_report=baseline_report,
282
+ homegraph_report=homegraph_report,
283
+ compare_report=compare_path,
284
+ single_report=single_report,
285
+ )
286
+ return reports, compare_path
287
+
288
+
289
+ def _blocking_homegraph_index(work_dir: Path, *, skip_index: bool = False) -> dict:
290
+ """Run full ``homegraph index`` and block until complete (or validate existing index)."""
291
+ if skip_index:
292
+ header("HomeGraph 索引检查(--skip-index,不执行 index)")
293
+ else:
294
+ header("HomeGraph 全量 index(阻塞,Photos 约 15–30 分钟)")
295
+ log(f"仓库: {work_dir}")
296
+ if skip_index:
297
+ log("模式: 仅校验已有 .homegraph/(可从同 commit 的其他机器复制整个目录)")
298
+ else:
299
+ log("命令: node --stack-size=8192 … homegraph index(见 deveco_arm.HOMEGRAPH_NODE_STACK_SIZE_KB)")
300
+ meta = ensure_homegraph_index(work_dir, skip=skip_index)
301
+ if not meta.get("homegraph_index_success"):
302
+ error("HomeGraph index 失败,中止。")
303
+ err = meta.get("homegraph_index_error", "")
304
+ if err:
305
+ error(f" 原因: {err}")
306
+ sys.exit(1)
307
+ return meta
308
+
309
+
310
+ def main():
311
+ analyze._configure_stdout()
312
+ cfg = load_config()
313
+ meta = cfg.get("meta", {})
314
+
315
+ parser = argparse.ArgumentParser(description="HomeGraph 档位切换边界评测")
316
+ parser.add_argument("--agent", default=os.environ.get("EVAL_AGENT", "deveco"),
317
+ help="Agent:claude / cursor / codex / opencode / deveco")
318
+ parser.add_argument("--arm", default=os.environ.get("EVAL_ARM", "baseline"),
319
+ choices=["baseline", "homegraph"],
320
+ help="baseline=不带 HomeGraph;homegraph=带 HomeGraph")
321
+ parser.add_argument("--both-arms", action="store_true",
322
+ help="一条命令依次跑 baseline 和 homegraph 两组 A/B")
323
+ parser.add_argument("--repo-path", default=os.environ.get("REPO_PATH", ""),
324
+ help="使用已有本地 clone,跳过 git clone")
325
+ parser.add_argument("--keep-clone", action="store_true")
326
+ parser.add_argument(
327
+ "--skip-index",
328
+ action="store_true",
329
+ help="不跑 homegraph init/index;要求仓库根目录已有健康的 .homegraph/(可复制自同 commit 的其他 checkout)",
330
+ )
331
+ parser.add_argument("--no-skip-permissions", action="store_true")
332
+ parser.add_argument("--branch", default=os.environ.get("BRANCH", meta.get("default_branch", "weekly_20260601")))
333
+ parser.add_argument("--repo-url", default=os.environ.get("REPO_URL", meta.get("repo_url", "")))
334
+ parser.add_argument("experiments", nargs="*")
335
+ args = parser.parse_args()
336
+
337
+ if not args.experiments:
338
+ args.experiments = DEFAULT_EXPERIMENTS
339
+
340
+ agent = get_agent(args.agent)
341
+ ok, resolved, err_msg = verify_agent_binary(agent)
342
+ if not ok:
343
+ error(err_msg)
344
+ sys.exit(1)
345
+ log(f"Agent CLI: {resolved}")
346
+
347
+ if args.both_arms and args.arm != "baseline":
348
+ warn("--both-arms 已指定,忽略 --arm")
349
+
350
+ if args.both_arms:
351
+ _rd, _sd = create_output_dirs(args.agent or "default", "baseline")
352
+ work_dir, _, _ = resolve_work_dir(args, _sd)
353
+
354
+ # Index FIRST so the user sees it immediately (15–30 min); baseline does not use MCP.
355
+ index_meta = _blocking_homegraph_index(work_dir, skip_index=args.skip_index)
356
+
357
+ summaries = []
358
+ print(f"\n{'=' * 60}\n 开始 homegraph 组(先看 HomeGraph 是否生效)\n{'=' * 60}\n")
359
+ summaries.append(run_suite(args, "homegraph", prebuilt_index_meta=index_meta))
360
+
361
+ print(f"\n{'=' * 60}\n 开始 baseline 组(无 HomeGraph)\n{'=' * 60}\n")
362
+ summaries.append(run_suite(args, "baseline"))
363
+
364
+ header("A/B 全部完成")
365
+ for s in summaries:
366
+ print(f" [{s['arm']}] 通过 {s['passed']},失败 {s['failed']},"
367
+ f"耗时 {s['duration_s'] // 60}m{s['duration_s'] % 60}s")
368
+ print(f" 输出 → {s['results_dir']}")
369
+ _generate_reports(summaries, args.agent or "default")
370
+ sys.exit(0 if all(s["failed"] == 0 for s in summaries) else 1)
371
+
372
+ summary = run_suite(args, args.arm)
373
+ _generate_reports([summary], args.agent or "default")
374
+ sys.exit(0 if summary["failed"] == 0 else 1)
375
+
376
+
377
+ if __name__ == "__main__":
378
+ main()