tianshu-harness 3.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/LICENSE +189 -0
  2. package/README.en.md +1066 -0
  3. package/README.ja.md +1214 -0
  4. package/README.ko.md +1216 -0
  5. package/README.md +309 -0
  6. package/completions/rivet.bash +118 -0
  7. package/completions/rivet.fish +110 -0
  8. package/completions/rivet.ps1 +230 -0
  9. package/completions/rivet.zsh +187 -0
  10. package/dist/account-OAEKORZE.js +47 -0
  11. package/dist/account-login-V6FOLHJR.js +65 -0
  12. package/dist/account-status-KHNPPAFL.js +23 -0
  13. package/dist/agent/worker-process/child.js +407 -0
  14. package/dist/browser-cli-FLNY5ZHI.js +19 -0
  15. package/dist/browser-readiness-LWVGSBD5.js +12 -0
  16. package/dist/build-backends-5KXKR2S4.js +13 -0
  17. package/dist/build-options-66Y4ZE7C.js +9 -0
  18. package/dist/bundled-skills/brainstorming/SKILL.md +139 -0
  19. package/dist/bundled-skills/visual-acceptance/SKILL.md +64 -0
  20. package/dist/chain-7MAMFXZ3.js +10 -0
  21. package/dist/checkpoint-MND4DUIX.js +33 -0
  22. package/dist/chunk-2E6CK2RC.js +392 -0
  23. package/dist/chunk-2EBWGAXD.js +51 -0
  24. package/dist/chunk-2HDP7RMR.js +119 -0
  25. package/dist/chunk-2HKD2UFM.js +1000 -0
  26. package/dist/chunk-2VYRLULP.js +51 -0
  27. package/dist/chunk-2XN7PM4N.js +125 -0
  28. package/dist/chunk-35H7GVNR.js +66 -0
  29. package/dist/chunk-3C3R7JXY.js +77 -0
  30. package/dist/chunk-3VGD2FXB.js +118 -0
  31. package/dist/chunk-424AP7FM.js +534 -0
  32. package/dist/chunk-4J5TZGOE.js +3707 -0
  33. package/dist/chunk-4QJ3Y5JM.js +898 -0
  34. package/dist/chunk-4U2ET7ZY.js +1326 -0
  35. package/dist/chunk-4XPFLICE.js +876 -0
  36. package/dist/chunk-5B2OCU5P.js +31707 -0
  37. package/dist/chunk-5GGOGLSN.js +73 -0
  38. package/dist/chunk-5JRZPLI6.js +251 -0
  39. package/dist/chunk-5TQ3JYBU.js +397 -0
  40. package/dist/chunk-66JPZSGX.js +55 -0
  41. package/dist/chunk-6HSVXHCZ.js +764 -0
  42. package/dist/chunk-6S5FPUS7.js +21 -0
  43. package/dist/chunk-722LQO64.js +131 -0
  44. package/dist/chunk-73NJ7IT7.js +354 -0
  45. package/dist/chunk-7FW3I7WC.js +95 -0
  46. package/dist/chunk-7KUCBNLB.js +173 -0
  47. package/dist/chunk-7RDOV3DF.js +201 -0
  48. package/dist/chunk-A5MNH4ER.js +79 -0
  49. package/dist/chunk-ADIVZ2D5.js +15 -0
  50. package/dist/chunk-AE3P3F6W.js +366 -0
  51. package/dist/chunk-AERM3VGP.js +280 -0
  52. package/dist/chunk-AEWHC4WM.js +246 -0
  53. package/dist/chunk-AOVQ7VIF.js +169 -0
  54. package/dist/chunk-AOYHP3WI.js +12411 -0
  55. package/dist/chunk-B3YEBABJ.js +7160 -0
  56. package/dist/chunk-BCQXEZPJ.js +154 -0
  57. package/dist/chunk-BKTQAYO2.js +418 -0
  58. package/dist/chunk-BSECIPAQ.js +80 -0
  59. package/dist/chunk-BUIMGNDD.js +52 -0
  60. package/dist/chunk-BXHV3GSB.js +10320 -0
  61. package/dist/chunk-C6ZVZCPP.js +139 -0
  62. package/dist/chunk-CEZNQVWM.js +82 -0
  63. package/dist/chunk-CGFZGR7G.js +1492 -0
  64. package/dist/chunk-CGOADM2X.js +337 -0
  65. package/dist/chunk-CI4R6P2B.js +24 -0
  66. package/dist/chunk-D2TCGRSX.js +73 -0
  67. package/dist/chunk-D4PTYFOG.js +154 -0
  68. package/dist/chunk-D54ZWG4T.js +717 -0
  69. package/dist/chunk-DEBI37QB.js +145 -0
  70. package/dist/chunk-DWROHPXP.js +1051 -0
  71. package/dist/chunk-DZ6UOJ5D.js +92 -0
  72. package/dist/chunk-EBJTVRQN.js +81 -0
  73. package/dist/chunk-EGEI2RQA.js +1167 -0
  74. package/dist/chunk-EHHUASO5.js +1305 -0
  75. package/dist/chunk-EPKTIOED.js +41 -0
  76. package/dist/chunk-ER5JW2QZ.js +5681 -0
  77. package/dist/chunk-ETHFACAB.js +315 -0
  78. package/dist/chunk-EXUE5W2F.js +112 -0
  79. package/dist/chunk-EXXICUIW.js +73 -0
  80. package/dist/chunk-FFQSZJOO.js +169 -0
  81. package/dist/chunk-FHFKPGDO.js +85 -0
  82. package/dist/chunk-FW3QKMFX.js +158 -0
  83. package/dist/chunk-GD4ZNZ7W.js +30 -0
  84. package/dist/chunk-GHVMWF2I.js +581 -0
  85. package/dist/chunk-GMKAXSYQ.js +297 -0
  86. package/dist/chunk-HBVF6BWO.js +325 -0
  87. package/dist/chunk-HV4YGVMS.js +379 -0
  88. package/dist/chunk-ILBCKAV6.js +89 -0
  89. package/dist/chunk-J4U4AW46.js +440 -0
  90. package/dist/chunk-J6ESSM47.js +1791 -0
  91. package/dist/chunk-JBZHIC6T.js +2309 -0
  92. package/dist/chunk-JCFWOULR.js +245 -0
  93. package/dist/chunk-JRF5L6OD.js +131 -0
  94. package/dist/chunk-JSS75KCG.js +2014 -0
  95. package/dist/chunk-JSXWIWWJ.js +225 -0
  96. package/dist/chunk-JYV7I2QH.js +98 -0
  97. package/dist/chunk-KIOXTQQL.js +1596 -0
  98. package/dist/chunk-KWVTXT5B.js +89 -0
  99. package/dist/chunk-KX22RD6R.js +33 -0
  100. package/dist/chunk-LA6IPTGH.js +709 -0
  101. package/dist/chunk-LH5VCGLB.js +1796 -0
  102. package/dist/chunk-LQQ6XJ2Y.js +269 -0
  103. package/dist/chunk-MJQ55WZZ.js +65 -0
  104. package/dist/chunk-ML3UKMH3.js +40 -0
  105. package/dist/chunk-MOZPLHSU.js +5526 -0
  106. package/dist/chunk-NGEWJ4DF.js +89 -0
  107. package/dist/chunk-NH6VIOAR.js +211 -0
  108. package/dist/chunk-O5VZQKCB.js +26106 -0
  109. package/dist/chunk-OHSV42QB.js +748 -0
  110. package/dist/chunk-OO3TAHO5.js +4070 -0
  111. package/dist/chunk-OTNHSAGN.js +38282 -0
  112. package/dist/chunk-OUWAC7AQ.js +442 -0
  113. package/dist/chunk-OXMIV4WE.js +270 -0
  114. package/dist/chunk-P5KJURUR.js +229 -0
  115. package/dist/chunk-P6GJOVO6.js +307 -0
  116. package/dist/chunk-QARAGUXX.js +23 -0
  117. package/dist/chunk-R43HJCDX.js +2711 -0
  118. package/dist/chunk-RAXBAWRN.js +210 -0
  119. package/dist/chunk-RK3JHWPT.js +39 -0
  120. package/dist/chunk-RWA23GMM.js +24 -0
  121. package/dist/chunk-S4K4L6IM.js +179 -0
  122. package/dist/chunk-SAXK6LVF.js +124 -0
  123. package/dist/chunk-SEPGEJNK.js +1607 -0
  124. package/dist/chunk-SUJERP5I.js +285 -0
  125. package/dist/chunk-T3ED6BY2.js +913 -0
  126. package/dist/chunk-THKDVSEC.js +90 -0
  127. package/dist/chunk-TI4GSEL5.js +52 -0
  128. package/dist/chunk-TPI73L57.js +164 -0
  129. package/dist/chunk-TVHW77C7.js +338 -0
  130. package/dist/chunk-TWNHOSDT.js +1073 -0
  131. package/dist/chunk-UFMN76QD.js +347 -0
  132. package/dist/chunk-UHGLFRZE.js +205 -0
  133. package/dist/chunk-UTZYPKBF.js +15231 -0
  134. package/dist/chunk-UXNLELW6.js +25 -0
  135. package/dist/chunk-UXXS53EA.js +166 -0
  136. package/dist/chunk-V5DHFGI7.js +171 -0
  137. package/dist/chunk-V5YIPMHV.js +2353 -0
  138. package/dist/chunk-WMUWEO2C.js +754 -0
  139. package/dist/chunk-WOE3D7JM.js +945 -0
  140. package/dist/chunk-X2IK5LVR.js +2592 -0
  141. package/dist/chunk-XU2YXCDL.js +459 -0
  142. package/dist/chunk-YJG5HIX5.js +203 -0
  143. package/dist/chunk-Z3QE7TZM.js +72 -0
  144. package/dist/chunk-Z5Z3JHJY.js +64 -0
  145. package/dist/chunk-ZDIFBJFT.js +168 -0
  146. package/dist/chunk-ZGGCEXDC.js +176 -0
  147. package/dist/chunk-ZMZCZNKU.js +263 -0
  148. package/dist/chunk-ZNC5T65N.js +17 -0
  149. package/dist/chunk-ZO3I3A7O.js +308 -0
  150. package/dist/chunk-ZQKXBUB7.js +217 -0
  151. package/dist/chunk-ZTRINFM2.js +78 -0
  152. package/dist/chunk-ZU7JZCVP.js +193 -0
  153. package/dist/chunk-ZZAWNALS.js +350 -0
  154. package/dist/cli/entry.js +54 -0
  155. package/dist/connector-L5QQTR6Y.js +26 -0
  156. package/dist/context-62DC6EC3.js +31 -0
  157. package/dist/council-convene-NJWPNBDU.js +46 -0
  158. package/dist/create-agent-config-ODSQWNVC.js +55 -0
  159. package/dist/default-registry-2PU3BTAU.js +68 -0
  160. package/dist/deliver-task-KONV4C4M.js +57 -0
  161. package/dist/delivery-gate-v2-F2YVMVGK.js +27 -0
  162. package/dist/domain-knowledge-store-DDZ3F4J7.js +11 -0
  163. package/dist/fetch-core-ZPPYDSZH.js +14 -0
  164. package/dist/galaxy-K72BBDQN.js +91 -0
  165. package/dist/goal-criteria-SCALAU2D.js +141 -0
  166. package/dist/goal-persist-XWY2GDQX.js +19 -0
  167. package/dist/goal-tracker-FXMJ2GVK.js +11 -0
  168. package/dist/headless-LSB6I7PT.js +162 -0
  169. package/dist/headless-coordinator-VDPDMVUT.js +90 -0
  170. package/dist/inject-U55SMB6A.js +39 -0
  171. package/dist/login-flow-CD4ZGXOC.js +59 -0
  172. package/dist/logs-cli-SQVYFMMN.js +283 -0
  173. package/dist/loop-ULZYBDA3.js +76 -0
  174. package/dist/main.js +4064 -0
  175. package/dist/manager-ROZBCWPA.js +171 -0
  176. package/dist/manager-Z7XFFUOM.js +10670 -0
  177. package/dist/meridian-indexer-ZIW363L7.js +21 -0
  178. package/dist/native-resolver-PN34UIVV.js +13 -0
  179. package/dist/node_modules/better-sqlite3/lib/database.js +90 -0
  180. package/dist/node_modules/better-sqlite3/lib/index.js +3 -0
  181. package/dist/node_modules/better-sqlite3/lib/methods/aggregate.js +43 -0
  182. package/dist/node_modules/better-sqlite3/lib/methods/backup.js +67 -0
  183. package/dist/node_modules/better-sqlite3/lib/methods/function.js +31 -0
  184. package/dist/node_modules/better-sqlite3/lib/methods/inspect.js +7 -0
  185. package/dist/node_modules/better-sqlite3/lib/methods/pragma.js +12 -0
  186. package/dist/node_modules/better-sqlite3/lib/methods/serialize.js +16 -0
  187. package/dist/node_modules/better-sqlite3/lib/methods/table.js +189 -0
  188. package/dist/node_modules/better-sqlite3/lib/methods/transaction.js +78 -0
  189. package/dist/node_modules/better-sqlite3/lib/methods/wrappers.js +54 -0
  190. package/dist/node_modules/better-sqlite3/lib/sqlite-error.js +20 -0
  191. package/dist/node_modules/better-sqlite3/lib/util.js +12 -0
  192. package/dist/node_modules/better-sqlite3/package.json +59 -0
  193. package/dist/ownership-ledger-E3WIEKPL.js +9 -0
  194. package/dist/package.json +3 -0
  195. package/dist/path-grants-XRRXHXG7.js +40 -0
  196. package/dist/paths-LVV5IMQN.js +49 -0
  197. package/dist/plan-fact-anchors-LMVQZCW5.js +13 -0
  198. package/dist/plan-store-ODLTTPFB.js +17 -0
  199. package/dist/plan-templates-5FPFBOL6.js +109 -0
  200. package/dist/plugin-loader-ZZKX7ZE6.js +22 -0
  201. package/dist/prefix-budget-62OV5HQC.js +13 -0
  202. package/dist/project-trust-5WS5MOMU.js +31 -0
  203. package/dist/provider-cli-ALDQXIT7.js +37 -0
  204. package/dist/providers-XQYTAVPK.js +11 -0
  205. package/dist/proxy-resolver-V2Y6534D.js +15 -0
  206. package/dist/recovery-cli-KPGY6FY3.js +106 -0
  207. package/dist/review-discipline-MNSYCST5.js +55 -0
  208. package/dist/review-router-BVQZW3MX.js +18 -0
  209. package/dist/seed-capsules/seed-capsule-attack-methodology.md +62 -0
  210. package/dist/seed-capsules/seed-capsule-changgeng.md +31 -0
  211. package/dist/seed-capsules/seed-capsule-design-aesthetics.md +38 -0
  212. package/dist/seed-capsules/seed-capsule-diagnostic-ladder.md +54 -0
  213. package/dist/seed-capsules/seed-capsule-fu.md +39 -0
  214. package/dist/seed-capsules/seed-capsule-huagai.md +73 -0
  215. package/dist/seed-capsules/seed-capsule-kaiyang.md +65 -0
  216. package/dist/seed-capsules/seed-capsule-knowledge-work.md +40 -0
  217. package/dist/seed-capsules/seed-capsule-tanlang.md +47 -0
  218. package/dist/seed-capsules/seed-capsule-tianfu.md +23 -0
  219. package/dist/seed-capsules/seed-capsule-tianliang.md +63 -0
  220. package/dist/seed-capsules/seed-capsule-tianquan.md +32 -0
  221. package/dist/seed-capsules/seed-capsule-tianxuan-ccr.md +22 -0
  222. package/dist/seed-capsules/seed-capsule-tianxuan.md +64 -0
  223. package/dist/seed-capsules/seed-capsule-yaoguang.md +87 -0
  224. package/dist/serve-X2R2UTLF.js +170 -0
  225. package/dist/serve-agent-KHSU6RVV.js +965 -0
  226. package/dist/session-persist-HUUC772H.js +37 -0
  227. package/dist/session-registry-6XUD5C4Y.js +15 -0
  228. package/dist/skill-loader-CK3RMO47.js +48 -0
  229. package/dist/skills/cli-harness-sop.md +207 -0
  230. package/dist/spawn-git-4HFU65AH.js +29 -0
  231. package/dist/sse-EYUTBWUK.js +512 -0
  232. package/dist/starflow-NOFBMPFU.js +30 -0
  233. package/dist/streamableHttp-V67CNJMO.js +447 -0
  234. package/dist/task-contract-6XHBNJQK.js +32 -0
  235. package/dist/task-ledger-3K4TJIER.js +9 -0
  236. package/dist/team-orchestrate-S6NHZP7X.js +64 -0
  237. package/dist/title-extract-QX4XGCYN.js +50 -0
  238. package/dist/todo-QDXGRZZP.js +31 -0
  239. package/dist/todo-store-V3TTO5AH.js +12 -0
  240. package/dist/tool-preset-LU5BYEDZ.js +23 -0
  241. package/dist/tool-tiers-GD742YBN.js +23 -0
  242. package/dist/turndown.es-OI55K6C3.js +17373 -0
  243. package/dist/verification-attribution-EKG4CNUV.js +13 -0
  244. package/dist/volatile-git-MBTST7RA.js +15 -0
  245. package/dist/wave-checkpoint-XLIIHXQA.js +30 -0
  246. package/dist/web-cli-DUG4I35O.js +233 -0
  247. package/dist/web-search-3IK542AA.js +34 -0
  248. package/dist/workers/cpu-worker.js +45 -0
  249. package/dist/workflow-runner-HX7UBAYG.js +297 -0
  250. package/dist/worktree-baseline-O5NCU6M2.js +9 -0
  251. package/package.json +122 -0
  252. package/scripts/check-mobile-env.mjs +76 -0
  253. package/scripts/fetch-native-sqlite.js +392 -0
  254. package/scripts/prune-installed-wasms.js +45 -0
  255. package/scripts/tree-sitter-wasm-keep.js +40 -0
@@ -0,0 +1,913 @@
1
+ #!/usr/bin/env -S node --expose-gc --max-old-space-size=4096
2
+ import { createRequire as __rivetCreateRequire } from 'node:module'; const require = __rivetCreateRequire(import.meta.url);
3
+ import {
4
+ WRITE_TOOL_NAMES,
5
+ extractWriteFilePaths
6
+ } from "./chunk-ZU7JZCVP.js";
7
+ import {
8
+ listPlansSync
9
+ } from "./chunk-ZMZCZNKU.js";
10
+ import {
11
+ spawnGitSync
12
+ } from "./chunk-THKDVSEC.js";
13
+ import {
14
+ writeFileAtomicSync
15
+ } from "./chunk-A5MNH4ER.js";
16
+ import {
17
+ init_paths,
18
+ memoryDir
19
+ } from "./chunk-BCQXEZPJ.js";
20
+ import {
21
+ init_esm_shims
22
+ } from "./chunk-5GGOGLSN.js";
23
+
24
+ // src/agent/regression-inventory.ts
25
+ init_esm_shims();
26
+ var INVENTORY_HEADING_RE = /^#{2,6}\s*(?:回归清单|回归契约|regression\s+inventory\b).*$/im;
27
+ function extractRegressionInventory(markdown) {
28
+ const headingMatch = markdown.match(INVENTORY_HEADING_RE);
29
+ if (!headingMatch || headingMatch.index === void 0) return [];
30
+ const headingLevel = (headingMatch[0].match(/^#+/) ?? ["##"])[0].length;
31
+ const rest = markdown.slice(headingMatch.index + headingMatch[0].length);
32
+ const items = [];
33
+ for (const line of rest.split(/\r?\n/)) {
34
+ const nextHeading = line.match(/^(#{1,6})\s/);
35
+ if (nextHeading && nextHeading[1].length <= headingLevel) break;
36
+ const m = line.match(/^\s*(?:[-*]\s*(?:\[[ xX]\]\s*)?|\d+\.\s+)(.+)$/);
37
+ if (m && m[1].trim()) items.push(m[1].trim());
38
+ }
39
+ return items;
40
+ }
41
+ function findApprovedPlanInventory(cwd) {
42
+ try {
43
+ const approved = listPlansSync(cwd).filter((p) => p.status === "approved");
44
+ if (approved.length === 0) return void 0;
45
+ const inventory = extractRegressionInventory(approved[0].content);
46
+ return inventory.length > 0 ? inventory : void 0;
47
+ } catch {
48
+ return void 0;
49
+ }
50
+ }
51
+ function needleForItem(item) {
52
+ const backtick = item.match(/`([^`]+)`/);
53
+ return (backtick?.[1] ?? item).trim();
54
+ }
55
+ function gitGrepSearcher(cwd, needle) {
56
+ try {
57
+ const res = spawnGitSync(["grep", "-l", "-F", "--", needle], { cwd, encoding: "utf-8", timeout: 1e4 });
58
+ if (res.status === 0) return "present";
59
+ if (res.status === 1) return "missing";
60
+ return "unknown";
61
+ } catch {
62
+ return "unknown";
63
+ }
64
+ }
65
+ function verifyRegressionInventory(cwd, items, searcher = gitGrepSearcher) {
66
+ return items.map((item) => {
67
+ const needle = needleForItem(item);
68
+ return { item, needle, status: needle ? searcher(cwd, needle) : "unknown" };
69
+ });
70
+ }
71
+ function formatInventoryReport(results) {
72
+ if (results.length === 0) return [];
73
+ const missing = results.filter((r) => r.status === "missing");
74
+ const unknown = results.filter((r) => r.status === "unknown");
75
+ const lines = ["", `--- \u56DE\u5F52\u6E05\u5355\u6838\u9A8C (${results.length - missing.length - unknown.length}/${results.length} \u4ECD\u5B58\u5728) ---`];
76
+ for (const r of results) {
77
+ const icon = r.status === "present" ? "\u2705" : r.status === "missing" ? "\u274C" : "\u2753";
78
+ lines.push(` ${icon} ${r.item}${r.status === "missing" ? `\uFF08\u951A\u70B9 \`${r.needle}\` \u5DF2\u6D88\u5931\uFF09` : ""}`);
79
+ }
80
+ if (missing.length > 0) {
81
+ lines.push("", ` \u26A0\uFE0F ${missing.length} \u4E2A\u529F\u80FD\u951A\u70B9\u5728\u6539\u52A8\u540E\u6D88\u5931\u2014\u2014\u8FD9\u6B63\u662F\u91CD\u6784\u4E22\u529F\u80FD\u7684\u5F62\u6001\u3002\u9010\u9879\u786E\u8BA4\u662F\u6709\u610F\u79FB\u9664\u8FD8\u662F\u56DE\u5F52\uFF0C\u56DE\u5F52\u7684\u5FC5\u987B\u4FEE\u590D\u540E\u518D\u4EA4\u4ED8\u3002`);
82
+ }
83
+ if (unknown.length > 0) {
84
+ lines.push(` \u2753 ${unknown.length} \u9879\u65E0\u6CD5\u81EA\u52A8\u6838\u9A8C\uFF08\u975E git \u4ED3\u5E93\u6216 grep \u5931\u8D25\uFF09\u2014\u2014\u8BF7\u4EBA\u5DE5\u786E\u8BA4\u3002`);
85
+ }
86
+ return lines;
87
+ }
88
+
89
+ // src/agent/hooks/render-verify-hook.ts
90
+ init_esm_shims();
91
+ var UI_EXTENSIONS = /* @__PURE__ */ new Set([".tsx", ".jsx", ".vue", ".svelte", ".css", ".html"]);
92
+ var VISUAL_TOOLS = /* @__PURE__ */ new Set(["browser", "computer_use", "browser_debug"]);
93
+ function createRenderVerifyHook(deps) {
94
+ const maxFires = deps.maxFires ?? 2;
95
+ let fireCount = 0;
96
+ return {
97
+ phase: "postTurn",
98
+ name: "render-verify",
99
+ run(ctx) {
100
+ const { snapshot } = ctx;
101
+ if (!snapshot.touchedUiFiles) return;
102
+ if (snapshot.sawVisualVerify) return;
103
+ if (fireCount >= maxFires) return;
104
+ fireCount++;
105
+ const visualAvailable = deps.getVisualToolsAvailable?.() ?? true;
106
+ const advice = visualAvailable ? "UI \u6587\u4EF6\u5DF2\u4FEE\u6539\u4F46\u5C1A\u672A\u68C0\u67E5\u6E32\u67D3\u7ED3\u679C\u3002\u4EA4\u4ED8\u524D\u7528 browser_debug \u81EA\u8BC1\uFF1Aopen \u2192 navigate \u5230 dev server \u2192 screenshot \u770B\u5E03\u5C40 + console \u67E5\u62A5\u9519\uFF1B\u539F\u751F\u684C\u9762\u5E94\u7528\u573A\u666F\u7528 computer_use snapshot\uFF08\u672A\u6302\u8F7D\u65F6\u7ECF /tools enable computer_use \u6216 delegate_task \u6D3E\u53D1\uFF09\u3002\u786E\u8BA4\u6E32\u67D3\u65E0\u8BEF\u540E\u518D\u4EA4\u4ED8\u3002" : "UI \u6587\u4EF6\u5DF2\u4FEE\u6539\uFF0C\u4F46\u5F53\u524D\u73AF\u5883\u7F3A\u5C11\u89C6\u89C9\u9A8C\u8BC1\u5DE5\u5177\uFF08\u65E0 Playwright \u6216\u975E Pro\u2014\u2014browser_debug \u9700\u8981 Playwright\uFF0Ccomputer_use \u9700\u8981 Pro + macOS/Windows\uFF09\u3002\u4EA4\u4ED8\u524D\u8BF7\u4EBA\u5DE5\u8FC7\u76EE\u6E32\u67D3\u7ED3\u679C\uFF0C\u786E\u8BA4\u89C6\u89C9\u65E0\u8BEF\u540E\u518D\u4EA4\u4ED8\u3002";
107
+ deps.advisoryBus.submit({
108
+ key: "render-verify",
109
+ priority: 0.55,
110
+ category: "discipline",
111
+ tier: "operational",
112
+ content: advice,
113
+ ttl: 1,
114
+ // 没有 expect 的条目 adopted 恒 0,会被 efficacy 负反馈环当成零采纳
115
+ // 逐步冷却直至本会话静默——这条提醒一直走在被系统自己掐掉的轨道上。
116
+ // 精度局限:tool_appears 只认工具名,`browser_debug open`/`navigate`
117
+ // 这种操作类调用也会记成采纳(谓词表达不了 isVerifyCall 的 action 过滤),
118
+ // 所以它的 lift 数据偏高,够用来免于静音,别当精确读数。
119
+ // 工具不可用的分支催的是人工过目,没有工具痕迹可核销,故不挂 expect
120
+ // (该分支有 fireCount 上限兜底)。
121
+ ...visualAvailable ? {
122
+ expect: {
123
+ kind: "tool_appears",
124
+ tools: ["browser_debug", "browser", "computer_use"],
125
+ withinTurns: 3
126
+ }
127
+ } : {}
128
+ });
129
+ }
130
+ };
131
+ }
132
+ function isUiFilePath(filePath) {
133
+ const lower = filePath.toLowerCase();
134
+ if (lower.includes("__tests__") || lower.includes(".test.") || lower.includes(".spec.")) return false;
135
+ if (lower.includes(".rivet/scratch/")) return false;
136
+ for (const ext of UI_EXTENSIONS) {
137
+ if (lower.endsWith(ext)) return true;
138
+ }
139
+ return false;
140
+ }
141
+ function isVisualVerifyTool(toolName) {
142
+ return VISUAL_TOOLS.has(toolName);
143
+ }
144
+
145
+ // src/memory/unified-memory.ts
146
+ init_esm_shims();
147
+ init_paths();
148
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
149
+ import { join as join2 } from "path";
150
+ import { createHash } from "crypto";
151
+
152
+ // src/context/project-memory-writer.ts
153
+ init_esm_shims();
154
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, openSync, closeSync } from "fs";
155
+ import { join } from "path";
156
+ import { randomBytes } from "crypto";
157
+ var MAX_ENTRIES = 200;
158
+ var MAX_FILE_SIZE = 16384;
159
+ var MAX_COMMIT_FACT_ENTRIES = 300;
160
+ var LOCK_RETRY_MAX_MS = 500;
161
+ var LOCK_RETRY_INTERVAL_MS = 20;
162
+ function acquireLock(lockPath) {
163
+ const start = Date.now();
164
+ while (true) {
165
+ try {
166
+ const fd = openSync(lockPath, "wx");
167
+ writeFileSync(fd, String(process.pid), "utf-8");
168
+ closeSync(fd);
169
+ return () => {
170
+ try {
171
+ unlinkSync(lockPath);
172
+ } catch {
173
+ }
174
+ };
175
+ } catch {
176
+ if (Date.now() - start > LOCK_RETRY_MAX_MS) {
177
+ return () => {
178
+ };
179
+ }
180
+ const waitUntil = Date.now() + LOCK_RETRY_INTERVAL_MS;
181
+ while (Date.now() < waitUntil) {
182
+ }
183
+ }
184
+ }
185
+ }
186
+ function atomicWrite(targetPath, content) {
187
+ const dir = join(targetPath, "..");
188
+ const tmpName = `.memory.${randomBytes(4).toString("hex")}.tmp`;
189
+ const tmpPath = join(dir, tmpName);
190
+ writeFileSync(tmpPath, content, "utf-8");
191
+ renameSync(tmpPath, targetPath);
192
+ }
193
+ function appendProjectMemory(cwd, claim) {
194
+ const entry = {
195
+ id: claim.id,
196
+ kind: claim.kind,
197
+ text: claim.text,
198
+ confidence: claim.confidence,
199
+ createdAt: claim.createdAt,
200
+ source: claim.evidence?.[0]?.summary ?? "unknown",
201
+ ...claim.tags && claim.tags.length > 0 ? { tags: claim.tags } : {}
202
+ };
203
+ if (entry.tags?.includes("commit_fact")) {
204
+ appendToJsonl(cwd, "commit-facts.jsonl", entry, MAX_COMMIT_FACT_ENTRIES);
205
+ return;
206
+ }
207
+ appendToJsonl(cwd, "memory.jsonl", entry);
208
+ }
209
+ function appendKnowledgeJsonl(cwd, filename, record, fifoCap) {
210
+ appendToJsonl(cwd, filename, record, fifoCap);
211
+ }
212
+ function appendToJsonl(cwd, filename, entry, fifoCap) {
213
+ const dir = join(cwd, ".rivet", "knowledge");
214
+ mkdirSync(dir, { recursive: true });
215
+ const path = join(dir, filename);
216
+ const lockPath = join(dir, `${filename}.lock`);
217
+ const release = acquireLock(lockPath);
218
+ try {
219
+ let existing = "";
220
+ if (existsSync(path)) {
221
+ try {
222
+ existing = readFileSync(path, "utf-8");
223
+ } catch {
224
+ }
225
+ }
226
+ let newContent = existing + JSON.stringify(entry) + "\n";
227
+ if (fifoCap !== void 0) {
228
+ const lines = newContent.split("\n").filter((l) => l.trim());
229
+ if (lines.length > fifoCap) {
230
+ newContent = lines.slice(lines.length - fifoCap).join("\n") + "\n";
231
+ }
232
+ }
233
+ atomicWrite(path, newContent);
234
+ } finally {
235
+ release();
236
+ }
237
+ }
238
+ function readCommitFacts(cwd) {
239
+ const path = join(cwd, ".rivet", "knowledge", "commit-facts.jsonl");
240
+ if (!existsSync(path)) return [];
241
+ const entries = [];
242
+ try {
243
+ for (const line of readFileSync(path, "utf-8").split("\n").filter((l) => l.trim())) {
244
+ try {
245
+ const parsed = JSON.parse(line);
246
+ if (parsed.id && parsed.text) entries.push(parsed);
247
+ } catch {
248
+ }
249
+ }
250
+ } catch {
251
+ return [];
252
+ }
253
+ return entries;
254
+ }
255
+ function compactProjectMemory(cwd) {
256
+ const dir = join(cwd, ".rivet", "knowledge");
257
+ const path = join(dir, "memory.jsonl");
258
+ const lockPath = join(dir, "memory.jsonl.lock");
259
+ if (!existsSync(path)) return 0;
260
+ const release = acquireLock(lockPath);
261
+ try {
262
+ const entries = [];
263
+ let fileSize = 0;
264
+ try {
265
+ const raw = readFileSync(path, "utf-8");
266
+ fileSize = raw.length;
267
+ const lines = raw.split("\n").filter((l) => l.trim());
268
+ for (const line of lines) {
269
+ try {
270
+ const parsed = JSON.parse(line);
271
+ if (parsed.id && parsed.text) entries.push(parsed);
272
+ } catch {
273
+ }
274
+ }
275
+ } catch {
276
+ return 0;
277
+ }
278
+ const seen = /* @__PURE__ */ new Map();
279
+ for (const entry of entries) {
280
+ seen.set(entry.id, entry);
281
+ }
282
+ const kept = [...seen.values()].sort((a, b) => b.confidence - a.confidence || (b.createdAt ?? b.ts ?? 0) - (a.createdAt ?? a.ts ?? 0)).slice(0, MAX_ENTRIES);
283
+ if (kept.length < entries.length || fileSize > MAX_FILE_SIZE) {
284
+ atomicWrite(path, kept.map((e) => JSON.stringify(e)).join("\n") + "\n");
285
+ return entries.length - kept.length;
286
+ }
287
+ return 0;
288
+ } finally {
289
+ release();
290
+ }
291
+ }
292
+
293
+ // src/memory/query-terms.ts
294
+ init_esm_shims();
295
+ var HAN_RE = new RegExp("\\p{Script=Han}", "u");
296
+ var WORD_RE = /[\p{L}\p{N}_]+/gu;
297
+ var LATIN_OR_NUMBER_RE = /[a-z0-9_]+/gi;
298
+ var MAX_TERMS = 32;
299
+ function tokenizeRecallQuery(query) {
300
+ const terms = /* @__PURE__ */ new Set();
301
+ const normalized = query.toLocaleLowerCase();
302
+ for (const segment of normalized.match(WORD_RE) ?? []) {
303
+ for (const token of segment.match(LATIN_OR_NUMBER_RE) ?? []) {
304
+ if (token.length >= 3) terms.add(token);
305
+ }
306
+ const han = Array.from(segment).filter((char) => HAN_RE.test(char));
307
+ if (han.length === 1) {
308
+ terms.add(han[0]);
309
+ } else {
310
+ for (let index = 0; index < han.length - 1; index++) {
311
+ terms.add(`${han[index]}${han[index + 1]}`);
312
+ }
313
+ }
314
+ }
315
+ return [...terms].slice(0, MAX_TERMS);
316
+ }
317
+
318
+ // src/memory/unified-memory.ts
319
+ function projectHash(cwd) {
320
+ return createHash("sha256").update(cwd).digest("hex").slice(0, 12);
321
+ }
322
+ function legacyMemoryPath(cwd) {
323
+ return join2(memoryDir(projectHash(cwd)), "memory.jsonl");
324
+ }
325
+ function memoryPath(cwd) {
326
+ return join2(cwd, ".rivet", "knowledge", "memory.jsonl");
327
+ }
328
+ function generateId() {
329
+ return `mem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
330
+ }
331
+ function normalizeEntry(raw) {
332
+ if (!raw.id || !raw.text) return null;
333
+ return {
334
+ id: String(raw.id),
335
+ text: String(raw.text),
336
+ kind: raw.kind ?? "fact",
337
+ confidence: typeof raw.confidence === "number" ? raw.confidence : 0.5,
338
+ source: raw.source ?? "manual",
339
+ status: raw.status ?? "observed",
340
+ evidence: typeof raw.evidence === "string" ? raw.evidence : void 0,
341
+ sessionId: typeof raw.sessionId === "string" ? raw.sessionId : void 0,
342
+ tags: Array.isArray(raw.tags) ? raw.tags.filter((t) => typeof t === "string") : [],
343
+ ts: typeof raw.ts === "number" ? raw.ts : typeof raw.createdAt === "number" ? raw.createdAt : 0,
344
+ repeatCount: typeof raw.repeatCount === "number" ? raw.repeatCount : 1,
345
+ promotedToRule: typeof raw.promotedToRule === "string" ? raw.promotedToRule : void 0,
346
+ claimId: typeof raw.claimId === "string" ? raw.claimId : void 0,
347
+ fileRefs: Array.isArray(raw.fileRefs) ? raw.fileRefs.filter((f) => typeof f === "string") : void 0,
348
+ validFrom: typeof raw.validFrom === "number" ? raw.validFrom : void 0,
349
+ validTo: typeof raw.validTo === "number" ? raw.validTo : void 0,
350
+ supersededBy: typeof raw.supersededBy === "string" ? raw.supersededBy : void 0,
351
+ transferableTo: Array.isArray(raw.transferableTo) ? raw.transferableTo.filter((t) => typeof t === "string") : void 0,
352
+ topic: typeof raw.topic === "string" ? raw.topic : void 0
353
+ };
354
+ }
355
+ function readJsonlEntries(path) {
356
+ if (!existsSync2(path)) return [];
357
+ const results = [];
358
+ try {
359
+ for (const line of readFileSync2(path, "utf-8").split("\n").filter(Boolean)) {
360
+ try {
361
+ const entry = normalizeEntry(JSON.parse(line));
362
+ if (entry) results.push(entry);
363
+ } catch {
364
+ }
365
+ }
366
+ } catch {
367
+ return [];
368
+ }
369
+ return results;
370
+ }
371
+ function isCurrentEntry(entry) {
372
+ if (entry.validTo !== void 0 && entry.validTo <= Date.now()) return false;
373
+ if (entry.supersededBy) return false;
374
+ if (entry.status === "expired" || entry.status === "rejected") return false;
375
+ return true;
376
+ }
377
+ function appendMemoryEntry(cwd, partial) {
378
+ const normalized = partial.text.trim().toLowerCase().slice(0, 200);
379
+ let repeatCount = 1;
380
+ const path = memoryPath(cwd);
381
+ if (existsSync2(path)) {
382
+ try {
383
+ for (const line of readFileSync2(path, "utf-8").split("\n")) {
384
+ if (!line.trim()) continue;
385
+ if (line.toLowerCase().includes(normalized.slice(0, 50))) {
386
+ repeatCount++;
387
+ }
388
+ }
389
+ } catch {
390
+ }
391
+ }
392
+ const entry = {
393
+ id: partial.id ?? generateId(),
394
+ text: partial.text.slice(0, 500),
395
+ kind: partial.kind,
396
+ confidence: partial.confidence,
397
+ source: partial.source,
398
+ status: partial.status,
399
+ evidence: partial.evidence,
400
+ sessionId: partial.sessionId,
401
+ tags: partial.tags,
402
+ ts: partial.ts ?? Date.now(),
403
+ repeatCount,
404
+ promotedToRule: partial.promotedToRule,
405
+ claimId: partial.claimId,
406
+ fileRefs: partial.fileRefs,
407
+ validFrom: partial.validFrom,
408
+ validTo: partial.validTo,
409
+ supersededBy: partial.supersededBy,
410
+ transferableTo: partial.transferableTo,
411
+ topic: partial.topic
412
+ };
413
+ appendKnowledgeJsonl(cwd, "memory.jsonl", compactUndefined(entry));
414
+ return entry;
415
+ }
416
+ function compactUndefined(obj) {
417
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== void 0));
418
+ }
419
+ function supersedeMemoryEntry(cwd, oldId, newId) {
420
+ const path = memoryPath(cwd);
421
+ if (!existsSync2(path)) return false;
422
+ const lockPath = join2(cwd, ".rivet", "knowledge", "memory.jsonl.lock");
423
+ const release = acquireLock(lockPath);
424
+ try {
425
+ let found = false;
426
+ const lines = [];
427
+ try {
428
+ for (const line of readFileSync2(path, "utf-8").split("\n").filter(Boolean)) {
429
+ try {
430
+ const raw = JSON.parse(line);
431
+ if (raw.id === oldId && !raw.supersededBy) {
432
+ raw.validTo = Date.now();
433
+ raw.supersededBy = newId;
434
+ raw.status = "expired";
435
+ found = true;
436
+ lines.push(JSON.stringify(raw));
437
+ continue;
438
+ }
439
+ } catch {
440
+ }
441
+ lines.push(line);
442
+ }
443
+ } catch {
444
+ return false;
445
+ }
446
+ if (!found) return false;
447
+ writeFileAtomicSync(path, lines.join("\n") + "\n");
448
+ return true;
449
+ } finally {
450
+ release();
451
+ }
452
+ }
453
+ function pruneMemoryStore(cwd, options = {}) {
454
+ const path = memoryPath(cwd);
455
+ if (!existsSync2(path)) return 0;
456
+ const retentionMs = (options.retentionDays ?? 90) * 864e5;
457
+ const lockPath = join2(cwd, ".rivet", "knowledge", "memory.jsonl.lock");
458
+ const release = acquireLock(lockPath);
459
+ try {
460
+ const raw = readFileSync2(path, "utf-8");
461
+ const lines = raw.split("\n").filter(Boolean);
462
+ const now = Date.now();
463
+ const kept = [];
464
+ let pruned = 0;
465
+ for (const line of lines) {
466
+ let parsed = null;
467
+ try {
468
+ parsed = JSON.parse(line);
469
+ } catch {
470
+ kept.push(line);
471
+ continue;
472
+ }
473
+ if (!parsed?.id || !parsed.text && parsed.kind !== "tombstone") {
474
+ kept.push(line);
475
+ continue;
476
+ }
477
+ const validTo = typeof parsed.validTo === "number" ? parsed.validTo : void 0;
478
+ if (validTo !== void 0 && validTo <= now - retentionMs) {
479
+ pruned++;
480
+ continue;
481
+ }
482
+ kept.push(line);
483
+ }
484
+ if (pruned === 0 && raw.length <= (options.maxFileBytes ?? 16384)) return 0;
485
+ writeFileAtomicSync(path, (pruned > 0 ? kept : lines).join("\n") + "\n");
486
+ return pruned;
487
+ } catch {
488
+ return 0;
489
+ } finally {
490
+ release();
491
+ }
492
+ }
493
+ function readMemoryEntries(cwd) {
494
+ const primary = readJsonlEntries(memoryPath(cwd));
495
+ const legacy = readJsonlEntries(legacyMemoryPath(cwd)).filter((e) => e.source !== "auto");
496
+ if (legacy.length === 0) return primary;
497
+ const seen = new Set(primary.map((e) => e.id));
498
+ const merged = [...primary];
499
+ for (const entry of legacy) {
500
+ if (!seen.has(entry.id)) merged.push(entry);
501
+ }
502
+ return merged;
503
+ }
504
+ function recallMemoryEntries(cwd, query, limit = 5, kindFilter, options) {
505
+ const terms = tokenizeRecallQuery(query);
506
+ if (terms.length === 0) return [];
507
+ const kinds = kindFilter ? Array.isArray(kindFilter) ? kindFilter : [kindFilter] : void 0;
508
+ const excludedSessionIds = /* @__PURE__ */ new Set();
509
+ if (options?.excludeSessionId) excludedSessionIds.add(options.excludeSessionId);
510
+ for (const id of options?.excludeSessionIds ?? []) excludedSessionIds.add(id);
511
+ const candidates = readMemoryEntries(cwd).filter((e) => !kinds || kinds.includes(e.kind)).filter((e) => options?.includeHistory || isCurrentEntry(e)).filter((e) => !options?.topic || (e.topic ?? "").toLowerCase().includes(options.topic.toLowerCase())).filter((e) => !excludedSessionIds.has(e.sessionId ?? ""));
512
+ const scored = candidates.map((entry) => {
513
+ const text = entry.text.toLowerCase();
514
+ const tagText = entry.tags.join(" ").toLowerCase();
515
+ let score = 0;
516
+ for (const term of terms) {
517
+ if (text.includes(term)) score += 2;
518
+ if (tagText.includes(term)) score += 1;
519
+ }
520
+ score *= entry.confidence;
521
+ return { entry, score };
522
+ }).filter((s) => s.score > 0).sort((a, b) => b.score - a.score || b.entry.ts - a.entry.ts);
523
+ return scored.slice(0, limit).map((s) => s.entry);
524
+ }
525
+ function renderMemoryBlock(cwd, query, maxChars = 2e3, sourceFilter, options) {
526
+ const excludedSessionIds = /* @__PURE__ */ new Set();
527
+ if (options?.excludeSessionId) excludedSessionIds.add(options.excludeSessionId);
528
+ for (const id of options?.excludeSessionIds ?? []) excludedSessionIds.add(id);
529
+ const excluded = (e) => !excludedSessionIds.has(e.sessionId ?? "");
530
+ const excludeOptions = { excludeSessionIds: [...excludedSessionIds] };
531
+ const recalled = sourceFilter ? options?.queryGatedSource ? recallMemoryEntries(cwd, query, 100, void 0, excludeOptions).filter((e) => e.source === sourceFilter).sort((a, b) => b.ts - a.ts || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, 8) : readMemoryEntries(cwd).filter((e) => e.source === sourceFilter).filter(excluded).filter(isCurrentEntry).sort((a, b) => b.ts - a.ts || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, 8) : recallMemoryEntries(cwd, query, 8, void 0, excludeOptions);
532
+ if (recalled.length === 0) return null;
533
+ const lines = ["<cross-session-memory>"];
534
+ let budget = maxChars;
535
+ for (const entry of recalled) {
536
+ const line = ` <m kind="${escapeXml(entry.kind)}" c="${entry.confidence.toFixed(2)}">${escapeXml(entry.text)}</m>`;
537
+ if (line.length > budget) break;
538
+ lines.push(line);
539
+ budget -= line.length;
540
+ }
541
+ lines.push("</cross-session-memory>");
542
+ return lines.join("\n");
543
+ }
544
+ function escapeXml(value) {
545
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
546
+ }
547
+ function countSimilarMemoryEntries(cwd, text) {
548
+ const normalized = text.trim().toLowerCase().slice(0, 200);
549
+ return readMemoryEntries(cwd).filter(
550
+ (e) => e.text.trim().toLowerCase().slice(0, 200) === normalized
551
+ ).length;
552
+ }
553
+ function validateKnowledgeChains(entries) {
554
+ const issues = [];
555
+ const byId = new Map(entries.map((e) => [e.id, e]));
556
+ const supersedeTargets = new Set(
557
+ entries.map((e) => e.supersededBy).filter((id) => !!id)
558
+ );
559
+ const reportedCycleMembers = /* @__PURE__ */ new Set();
560
+ for (const entry of entries) {
561
+ if (!entry.supersededBy) continue;
562
+ if (!byId.has(entry.supersededBy)) {
563
+ issues.push({
564
+ kind: "dangling_reference",
565
+ entryIds: [entry.id],
566
+ detail: `${entry.id} \u7684 supersededBy \u6307\u5411\u4E0D\u5B58\u5728\u7684 ${entry.supersededBy}`
567
+ });
568
+ continue;
569
+ }
570
+ if (reportedCycleMembers.has(entry.id)) continue;
571
+ const visited = /* @__PURE__ */ new Set();
572
+ let current = entry;
573
+ let cycleStart = null;
574
+ while (current) {
575
+ if (visited.has(current.id)) {
576
+ cycleStart = current.id;
577
+ break;
578
+ }
579
+ visited.add(current.id);
580
+ if (!current.supersededBy) break;
581
+ current = byId.get(current.supersededBy);
582
+ }
583
+ if (cycleStart) {
584
+ for (const id of visited) reportedCycleMembers.add(id);
585
+ issues.push({
586
+ kind: "cycle",
587
+ entryIds: [...visited],
588
+ detail: `supersede \u94FE\u5728 ${cycleStart} \u5F62\u6210\u73AF\uFF08${visited.size} \u4E2A\u6761\u76EE\uFF09`
589
+ });
590
+ continue;
591
+ }
592
+ if (supersedeTargets.has(entry.id)) continue;
593
+ let leaf = entry;
594
+ while (leaf.supersededBy && byId.has(leaf.supersededBy)) {
595
+ leaf = byId.get(leaf.supersededBy);
596
+ }
597
+ if (!isCurrentEntry(leaf)) {
598
+ let cursor = entry;
599
+ let allDead = true;
600
+ while (cursor) {
601
+ if (isCurrentEntry(cursor)) {
602
+ allDead = false;
603
+ break;
604
+ }
605
+ if (!cursor.supersededBy) break;
606
+ cursor = byId.get(cursor.supersededBy);
607
+ }
608
+ if (allDead) {
609
+ issues.push({
610
+ kind: "dead_chain",
611
+ entryIds: [entry.id, ...leaf.id !== entry.id ? [leaf.id] : []],
612
+ detail: `\u4ECE ${entry.id} \u8D77\u7684 supersede \u94FE\u65E0 current \u53F6\u5B50\uFF08\u672B\u7AEF ${leaf.id} \u5DF2\u5C01\u53E3\uFF09`
613
+ });
614
+ }
615
+ }
616
+ }
617
+ return issues;
618
+ }
619
+
620
+ // src/agent/post-commit-review-queue.ts
621
+ init_esm_shims();
622
+ var queue = [];
623
+ function enqueuePostCommitReviewOutcome(entry) {
624
+ queue.push({ ...entry, enqueuedAt: Date.now() });
625
+ }
626
+ function consumePostCommitReviewOutcomes() {
627
+ return queue.splice(0);
628
+ }
629
+
630
+ // src/agent/probe-detector.ts
631
+ init_esm_shims();
632
+ import { isAbsolute, join as join3 } from "path";
633
+ var CONSOLE_PROBE_RE = /(^|[^.])\bconsole\.(log|debug|dir|trace)\s*\(/gm;
634
+ var DEBUGGER_RE = /\bdebugger\b/g;
635
+ var ONLY_PROBE_RE = /\b(it|describe|test|xit|xdescribe|xit)\.only\s*\(/g;
636
+ var ASSERT_PROBE_RE = /(^|[^.\w])assert\s*\(/gm;
637
+ var PROBE_PATTERNS = [
638
+ { name: "console.log/debug/dir/trace", re: CONSOLE_PROBE_RE },
639
+ { name: "debugger", re: DEBUGGER_RE },
640
+ { name: ".only() test isolation", re: ONLY_PROBE_RE },
641
+ { name: "bare assert()", re: ASSERT_PROBE_RE }
642
+ ];
643
+ var WHITELIST_PREFIXES = [
644
+ "scripts/",
645
+ "desktop/scripts/",
646
+ // CLI 脚本的用户可见输出(台账 F2 实例②)
647
+ "bin/",
648
+ "src/server/serve.ts"
649
+ // API server startup logs
650
+ ];
651
+ var WHITELIST_SUFFIXES = [
652
+ ".test.ts",
653
+ ".test.tsx",
654
+ ".test.js",
655
+ ".spec.ts",
656
+ ".md"
657
+ ];
658
+ var STRUCTURED_LOG_RE = /\b(?!console\b)\w+(?:\.\w+)*\.(info|warn|error|debug|trace|verbose|silly|fatal)\s*\(/;
659
+ var CONDITIONAL_DEBUG_RE = /\bif\s*\([^)]*\)\s*\{?\s*console\.(debug|log|dir|trace)\s*\(/;
660
+ function isWhitelistedPath(filePath) {
661
+ const normalized = filePath.replace(/^\.\//, "");
662
+ for (const suffix of WHITELIST_SUFFIXES) {
663
+ if (normalized.endsWith(suffix)) return true;
664
+ }
665
+ for (const prefix of WHITELIST_PREFIXES) {
666
+ if (normalized.startsWith(prefix)) return true;
667
+ }
668
+ return false;
669
+ }
670
+ function detectProbes(content, filePath) {
671
+ if (isWhitelistedPath(filePath)) return [];
672
+ const lines = content.split("\n");
673
+ const hits = [];
674
+ for (let i = 0; i < lines.length; i++) {
675
+ const line = lines[i];
676
+ if (line.length > 120) continue;
677
+ const trimmed = line.trimStart();
678
+ if (trimmed.startsWith("//") || trimmed.startsWith("*")) continue;
679
+ for (const { name, re } of PROBE_PATTERNS) {
680
+ re.lastIndex = 0;
681
+ if (re.test(line)) {
682
+ if (name === "console.log/debug/dir/trace" && STRUCTURED_LOG_RE.test(line)) {
683
+ continue;
684
+ }
685
+ if (name === "console.log/debug/dir/trace" && CONDITIONAL_DEBUG_RE.test(line)) {
686
+ continue;
687
+ }
688
+ hits.push({
689
+ filePath,
690
+ pattern: name,
691
+ line: line.length > 120 ? line.slice(0, 120) + "..." : line,
692
+ lineNumber: i + 1
693
+ });
694
+ }
695
+ re.lastIndex = 0;
696
+ }
697
+ }
698
+ return hits;
699
+ }
700
+ function scanFilesForProbes(filePaths, cwd, readFile) {
701
+ const allHits = [];
702
+ for (const filePath of filePaths) {
703
+ if (isWhitelistedPath(filePath)) continue;
704
+ const content = readFile(isAbsolute(filePath) ? filePath : join3(cwd, filePath));
705
+ if (content === null) continue;
706
+ const hits = detectProbes(content, filePath);
707
+ allHits.push(...hits);
708
+ }
709
+ return allHits;
710
+ }
711
+ function formatProbeHits(hits) {
712
+ if (hits.length === 0) return [];
713
+ const lines = [
714
+ "",
715
+ "\u26A0\uFE0F \u63A2\u9488\u6B8B\u7559\u68C0\u6D4B \u2014 \u4EE5\u4E0B\u6587\u4EF6\u5305\u542B\u8C03\u8BD5\u63A2\u9488\uFF08console.log/debugger/.only \u7B49\uFF09\uFF0C\u4EA4\u4ED8\u524D\u5E94\u6E05\u7406\uFF1A"
716
+ ];
717
+ const byFile = /* @__PURE__ */ new Map();
718
+ for (const hit of hits) {
719
+ const existing = byFile.get(hit.filePath) ?? [];
720
+ existing.push(hit);
721
+ byFile.set(hit.filePath, existing);
722
+ }
723
+ for (const [filePath, fileHits] of byFile) {
724
+ lines.push(` ${filePath}:`);
725
+ for (const h of fileHits.slice(0, 3)) {
726
+ lines.push(` L${h.lineNumber} [${h.pattern}] ${h.line.trim()}`);
727
+ }
728
+ if (fileHits.length > 3) {
729
+ lines.push(` ... +${fileHits.length - 3} more`);
730
+ }
731
+ }
732
+ lines.push(" \u6E05\u7406\u63A2\u9488\u540E\u91CD\u65B0\u4EA4\u4ED8\u3002\u5982\u679C\u662F\u6709\u610F\u6DFB\u52A0\u7684\u65E5\u5FD7\uFF0C\u8BF7\u4F7F\u7528\u7ED3\u6784\u5316\u65E5\u5FD7\uFF08logger.info \u7B49\uFF09\u3002");
733
+ return lines;
734
+ }
735
+
736
+ // src/agent/hooks/external-claim-tracking-hook.ts
737
+ init_esm_shims();
738
+ var DELEGATE_TOOLS = /* @__PURE__ */ new Set(["delegate_task", "delegate_batch"]);
739
+ var VERIFY_TOOLS = /* @__PURE__ */ new Set([
740
+ "read_file",
741
+ "grep",
742
+ "glob",
743
+ "semantic_search",
744
+ "lsp_goto_definition",
745
+ "lsp_find_references"
746
+ ]);
747
+ var CLAIM_TTL_TURNS = 5;
748
+ var FILE_LINE_RE = /(\b(?:src|test|tests|scripts|docs|config)\/[^\s:)]+\.(?:ts|tsx|js|jsx|json|md)):(\d+)/g;
749
+ function canonicalizePath(pathRef) {
750
+ return pathRef.replace(/:\d+.*$/, "");
751
+ }
752
+ function extractClaimedPaths(content) {
753
+ const paths = /* @__PURE__ */ new Set();
754
+ FILE_LINE_RE.lastIndex = 0;
755
+ let match;
756
+ while ((match = FILE_LINE_RE.exec(content)) !== null) {
757
+ paths.add(canonicalizePath(match[1]));
758
+ }
759
+ return [...paths];
760
+ }
761
+ function verifyTargetOf(tool) {
762
+ const input = tool.input ?? {};
763
+ const parts = [];
764
+ for (const key of ["path", "file_path", "file", "pattern", "query", "command"]) {
765
+ const v = input[key];
766
+ if (typeof v === "string") parts.push(v);
767
+ }
768
+ if (tool.target) parts.push(tool.target);
769
+ return parts.join(" ");
770
+ }
771
+ function findUnverifiedClaimRefs(tracker, text) {
772
+ const scanText = text.split("\n").filter((l) => !l.includes("[\u5F85\u6838]")).join("\n");
773
+ const refs = extractClaimedPaths(scanText);
774
+ if (refs.length === 0) return [];
775
+ const unverified = new Set(
776
+ tracker.claims.filter((c) => c.verifiedAt === void 0).map((c) => c.filePath)
777
+ );
778
+ return refs.filter((r) => unverified.has(r));
779
+ }
780
+ function createExternalClaimTrackingHook(deps) {
781
+ const tracker = { claims: [] };
782
+ const hook = {
783
+ phase: "postTool",
784
+ name: "external-claim-tracking",
785
+ getClaimTracker() {
786
+ return tracker;
787
+ },
788
+ resetClaimTracker() {
789
+ tracker.claims = [];
790
+ },
791
+ run(ctx, tool) {
792
+ const { turn } = ctx.snapshot;
793
+ tracker.claims = tracker.claims.filter((c) => c.expiresAtTurn > turn);
794
+ if (DELEGATE_TOOLS.has(tool.name) && tool.success && tool.resultContent) {
795
+ const claimedPaths = extractClaimedPaths(tool.resultContent);
796
+ const inputPaths = /* @__PURE__ */ new Set();
797
+ const files = tool.input?.files;
798
+ if (Array.isArray(files)) {
799
+ for (const f of files) {
800
+ if (typeof f === "string") inputPaths.add(canonicalizePath(f));
801
+ }
802
+ }
803
+ const inputFiles = tool.input?.input_files;
804
+ if (Array.isArray(inputFiles)) {
805
+ for (const f of inputFiles) {
806
+ if (typeof f === "string") inputPaths.add(canonicalizePath(f));
807
+ }
808
+ }
809
+ for (const filePath of claimedPaths) {
810
+ if (inputPaths.has(filePath)) continue;
811
+ tracker.claims.push({
812
+ filePath,
813
+ turn,
814
+ expiresAtTurn: turn + CLAIM_TTL_TURNS
815
+ });
816
+ }
817
+ return;
818
+ }
819
+ const isVerifyShapedBash = tool.name === "bash" && /\b(grep|cat|rg|find|head|tail|sed)\b/.test(String(tool.input?.command ?? ""));
820
+ if ((VERIFY_TOOLS.has(tool.name) || isVerifyShapedBash) && tool.success) {
821
+ const hay = verifyTargetOf(tool);
822
+ if (hay) {
823
+ tracker.claims = tracker.claims.map(
824
+ (c) => c.verifiedAt === void 0 && hay.includes(c.filePath) ? { ...c, verifiedAt: turn } : c
825
+ );
826
+ }
827
+ return;
828
+ }
829
+ if (tool.name === "deliver_task" && tool.success) {
830
+ const input = tool.input ?? {};
831
+ const checklist = Array.isArray(input.checklist) ? input.checklist.map((e) => typeof e?.item === "string" ? e.item : "").join("\n") : "";
832
+ const text = `${typeof input.message === "string" ? input.message : ""}
833
+ ${checklist}`;
834
+ const refs = findUnverifiedClaimRefs(tracker, text);
835
+ if (refs.length > 0) {
836
+ deps.advisoryBus.submit({
837
+ key: "external-claim-in-delivery",
838
+ priority: 0.6,
839
+ category: "discipline",
840
+ content: `\u26A0 \u4EA4\u4ED8\u6587\u672C\u5F15\u7528\u4E86 delegate \u62A5\u544A\u7684 ${refs.join("\u3001")}\uFF0C\u4F46\u672C\u4F1A\u8BDD\u6CA1\u6709\u5BF9\u5176\u72EC\u7ACB\u6838\u9A8C\uFF08read_file/grep\uFF09\u3002worker \u7684 file:line \u662F\u5F85\u6838\u9A8C\u5047\u8BBE\u2014\u2014commit \u524D\u5148\u6838\u9A8C\uFF0C\u6216\u5C06\u8BE5\u6761\u6807\u6CE8 [\u5F85\u6838] \u964D\u7EA7\u4E3A\u7EBF\u7D22\u3002`,
841
+ ttl: 1,
842
+ expect: { kind: "tool_appears", tools: [...VERIFY_TOOLS, "bash"], targetIncludes: refs[0], withinTurns: 2 }
843
+ });
844
+ }
845
+ return;
846
+ }
847
+ if (!WRITE_TOOL_NAMES.has(tool.name)) return;
848
+ const writePaths = extractWriteFilePaths(tool.name, tool.input);
849
+ if (writePaths.length === 0) return;
850
+ const activeClaims = tracker.claims.filter((c) => c.expiresAtTurn > turn);
851
+ const matchedClaim = activeClaims.find(
852
+ (c) => writePaths.some((wp) => c.filePath === wp || wp.endsWith(c.filePath) || c.filePath.endsWith(wp))
853
+ );
854
+ if (!matchedClaim) return;
855
+ const history = ctx.snapshot.recentToolHistory;
856
+ const claimedPath = matchedClaim.filePath;
857
+ const hasIndependentVerify = history.some((h) => {
858
+ const target = h.target ?? "";
859
+ const pathMatches = target.includes(claimedPath) || claimedPath.includes(target);
860
+ if (!pathMatches) return false;
861
+ if (VERIFY_TOOLS.has(h.tool)) return true;
862
+ if (h.tool === "bash" && /\b(grep|cat|find|rg)\b/.test(target)) return true;
863
+ return false;
864
+ });
865
+ if (!hasIndependentVerify && matchedClaim.verifiedAt === void 0) {
866
+ deps.advisoryBus.submit({
867
+ key: "external-claim-unverified",
868
+ priority: 0.56,
869
+ category: "discipline",
870
+ content: `\u26A0 delegate \u62A5\u544A\u4E2D\u63D0\u5230\u4E86 ${claimedPath}\uFF0C\u4F60\u6B63\u5728\u7F16\u8F91\u5B83\uFF0C\u4F46\u4E2D\u95F4\u6CA1\u6709\u72EC\u7ACB\u6838\u9A8C\uFF08read_file/grep\uFF09\u3002worker \u62A5\u544A\u7684\u884C\u53F7\u53EF\u80FD\u504F\u79FB\u6216\u5F15\u7528\u4E86\u8FC7\u65F6\u6587\u4EF6\u72B6\u6001\u3002\u5148\u7528 read_file \u6216 grep \u72EC\u7ACB\u786E\u8BA4\u8BE5\u8DEF\u5F84\u7684\u5F53\u524D\u5185\u5BB9\uFF0C\u518D\u7F16\u8F91\u3002`,
871
+ ttl: 1,
872
+ // 谓词映射表(P1a):external-claim → tool_appears(核验类, 目标=声称路径, 2 轮)
873
+ expect: {
874
+ kind: "tool_appears",
875
+ tools: [...VERIFY_TOOLS, "bash"],
876
+ targetIncludes: claimedPath,
877
+ withinTurns: 2
878
+ }
879
+ });
880
+ }
881
+ }
882
+ };
883
+ return hook;
884
+ }
885
+
886
+ export {
887
+ extractRegressionInventory,
888
+ findApprovedPlanInventory,
889
+ verifyRegressionInventory,
890
+ formatInventoryReport,
891
+ createRenderVerifyHook,
892
+ isUiFilePath,
893
+ isVisualVerifyTool,
894
+ appendProjectMemory,
895
+ readCommitFacts,
896
+ compactProjectMemory,
897
+ tokenizeRecallQuery,
898
+ isCurrentEntry,
899
+ appendMemoryEntry,
900
+ supersedeMemoryEntry,
901
+ pruneMemoryStore,
902
+ readMemoryEntries,
903
+ renderMemoryBlock,
904
+ countSimilarMemoryEntries,
905
+ validateKnowledgeChains,
906
+ enqueuePostCommitReviewOutcome,
907
+ consumePostCommitReviewOutcomes,
908
+ detectProbes,
909
+ scanFilesForProbes,
910
+ formatProbeHits,
911
+ findUnverifiedClaimRefs,
912
+ createExternalClaimTrackingHook
913
+ };