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,2711 @@
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
+ extractChangedFiles,
5
+ shapeWriteBudgetForProfile
6
+ } from "./chunk-D4PTYFOG.js";
7
+ import {
8
+ routeReviewWorkflow
9
+ } from "./chunk-NH6VIOAR.js";
10
+ import {
11
+ LARGE_FILE_WARN_THRESHOLD,
12
+ classifyChangeScale,
13
+ formatCaseSensitivityReviewStance,
14
+ formatMethodologyVerificationStance,
15
+ formatObjectiveReviewStance,
16
+ formatPathBoundaryReviewStance,
17
+ formatWeighingReviewStance,
18
+ formatWiringEffectivenessReviewStance,
19
+ isCrossModule,
20
+ isFixContext
21
+ } from "./chunk-S4K4L6IM.js";
22
+ import {
23
+ clearCheckpoint,
24
+ deriveTeamGroupId,
25
+ loadCheckpoint,
26
+ saveCheckpoint
27
+ } from "./chunk-3VGD2FXB.js";
28
+ import {
29
+ detectOverlapWithoutOrder,
30
+ validateTaskGraph
31
+ } from "./chunk-TVHW77C7.js";
32
+ import {
33
+ LinUCBBandit,
34
+ buildGatedInfluenceAuditEvent,
35
+ buildTeamEpisodeFromStore,
36
+ buildTeamWaveScopeHealth,
37
+ buildTeamWaveTelemetry,
38
+ evaluateSkillGate,
39
+ extractRequiredSkills,
40
+ formatSkillGateBlock,
41
+ formatTeamDelivery,
42
+ getInvokedSkills,
43
+ hashTeamObjective,
44
+ isSkillGateEnabled,
45
+ persistGatedInfluenceAudit,
46
+ persistTeamScopeHealth,
47
+ recordTeamEpisodeClosureFromStore
48
+ } from "./chunk-EHHUASO5.js";
49
+ import {
50
+ evaluateWaveGate,
51
+ formatWaveGate,
52
+ getWaveGate,
53
+ isWaveGateEnabled,
54
+ runChangedFilesTypecheckMemo,
55
+ setWaveGate,
56
+ typecheckGateEnabled
57
+ } from "./chunk-LA6IPTGH.js";
58
+ import {
59
+ dependencyId,
60
+ extractJsonCandidates
61
+ } from "./chunk-4QJ3Y5JM.js";
62
+ import {
63
+ deriveAuthority,
64
+ starDomainRegistry
65
+ } from "./chunk-CGOADM2X.js";
66
+ import {
67
+ skillRegistry
68
+ } from "./chunk-OHSV42QB.js";
69
+ import {
70
+ debugLog
71
+ } from "./chunk-CI4R6P2B.js";
72
+ import {
73
+ init_esm_shims
74
+ } from "./chunk-5GGOGLSN.js";
75
+
76
+ // src/agent/team-grouping.ts
77
+ init_esm_shims();
78
+ var MAX_WRITE_WORKERS = 3;
79
+ var MAX_READ_WORKERS = 3;
80
+ function touchFiles(task) {
81
+ return task.touchSet.length > 0 ? task.touchSet : task.files;
82
+ }
83
+ function isReadOnly(task) {
84
+ return task.profile === "code_scout" || task.profile === "doc_scout" || task.profile === "reviewer" && task.kind === "review";
85
+ }
86
+ function topologicalSort(tasks) {
87
+ const taskMap = new Map(tasks.map((t) => [t.id, t]));
88
+ const visited = /* @__PURE__ */ new Set();
89
+ const result = [];
90
+ function visit(id) {
91
+ if (visited.has(id)) return;
92
+ visited.add(id);
93
+ const task = taskMap.get(id);
94
+ if (task) {
95
+ for (const dep of task.dependsOn) {
96
+ const depId = dependencyId(dep);
97
+ if (taskMap.has(depId)) visit(depId);
98
+ }
99
+ }
100
+ result.push(id);
101
+ }
102
+ for (const t of tasks) visit(t.id);
103
+ return result;
104
+ }
105
+ function validateTaskDependencies(tasks) {
106
+ const taskMap = new Map(tasks.map((t) => [t.id, t]));
107
+ const dangling = [];
108
+ for (const t of tasks) {
109
+ for (const dep of t.dependsOn) {
110
+ const depId = dependencyId(dep);
111
+ if (!taskMap.has(depId)) dangling.push({ taskId: t.id, missingDep: depId });
112
+ }
113
+ }
114
+ const cycles = [];
115
+ const state = /* @__PURE__ */ new Map();
116
+ const stack = [];
117
+ function dfs(id) {
118
+ state.set(id, "gray");
119
+ stack.push(id);
120
+ const task = taskMap.get(id);
121
+ if (task) {
122
+ for (const dep of task.dependsOn) {
123
+ const depId = dependencyId(dep);
124
+ if (!taskMap.has(depId)) continue;
125
+ const depState = state.get(depId);
126
+ if (depState === "gray") {
127
+ const start = stack.indexOf(depId);
128
+ if (start >= 0) cycles.push(stack.slice(start));
129
+ } else if (depState !== "black") {
130
+ dfs(depId);
131
+ }
132
+ }
133
+ }
134
+ stack.pop();
135
+ state.set(id, "black");
136
+ }
137
+ for (const t of tasks) {
138
+ if (!state.has(t.id)) dfs(t.id);
139
+ }
140
+ return { dangling, cycles };
141
+ }
142
+ function isTestFor(testFile, sourceFile) {
143
+ const base = sourceFile.replace(/\.[^./\\]+$/, "");
144
+ const testBase = testFile.replace(/\.test\.[^./\\]+$/, "").replace(/\/__tests__/, "");
145
+ return base === testBase;
146
+ }
147
+ function bindSourceTestPairs(tasks) {
148
+ const result = [];
149
+ const consumed = /* @__PURE__ */ new Set();
150
+ for (const task of tasks) {
151
+ if (consumed.has(task.id)) continue;
152
+ consumed.add(task.id);
153
+ const files2 = touchFiles(task);
154
+ if (files2.length === 0) {
155
+ result.push(task);
156
+ continue;
157
+ }
158
+ let merged = false;
159
+ for (const other of tasks) {
160
+ if (consumed.has(other.id)) continue;
161
+ if (other.profile !== "patcher") continue;
162
+ const otherFiles = touchFiles(other);
163
+ if (otherFiles.length === 0) continue;
164
+ const allTestPairs = otherFiles.every(
165
+ (of) => files2.some((f) => isTestFor(of, f))
166
+ );
167
+ if (allTestPairs) {
168
+ consumed.add(other.id);
169
+ const mergedFiles = [.../* @__PURE__ */ new Set([...files2, ...otherFiles])];
170
+ result.push({
171
+ ...task,
172
+ files: mergedFiles,
173
+ touchSet: mergedFiles,
174
+ verification: [...task.verification, ...other.verification],
175
+ objective: [task.objective, other.objective].join("\n")
176
+ });
177
+ merged = true;
178
+ break;
179
+ }
180
+ }
181
+ if (!merged) {
182
+ result.push(task);
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ function groupTeamTasks(tasks, options) {
188
+ if (tasks.length === 0) return [];
189
+ const maxWrite = options?.maxWriteWorkers ?? MAX_WRITE_WORKERS;
190
+ const maxRead = options?.maxReadWorkers ?? MAX_READ_WORKERS;
191
+ const bound = bindSourceTestPairs(tasks);
192
+ const taskMap = new Map(bound.map((t) => [t.id, t]));
193
+ const diag = validateTaskDependencies(bound);
194
+ const danglingByTask = /* @__PURE__ */ new Map();
195
+ for (const d of diag.dangling) {
196
+ const arr = danglingByTask.get(d.taskId) ?? [];
197
+ arr.push(d.missingDep);
198
+ danglingByTask.set(d.taskId, arr);
199
+ }
200
+ const topoOrder = topologicalSort(bound);
201
+ const waves = [];
202
+ let waveCounter = 0;
203
+ const completed = /* @__PURE__ */ new Set();
204
+ const remaining = [...topoOrder];
205
+ while (remaining.length > 0) {
206
+ const ready = [];
207
+ const notReady = [];
208
+ for (const id of remaining) {
209
+ const task = taskMap.get(id);
210
+ if (!task) {
211
+ notReady.push(id);
212
+ continue;
213
+ }
214
+ const depsMet = task.dependsOn.every((dep) => {
215
+ const depId = dependencyId(dep);
216
+ return completed.has(depId) || !taskMap.has(depId);
217
+ });
218
+ if (depsMet) {
219
+ ready.push(id);
220
+ } else {
221
+ notReady.push(id);
222
+ }
223
+ }
224
+ if (ready.length === 0) {
225
+ const forced = remaining[0];
226
+ const cycle = diag.cycles.find((c) => c.includes(forced));
227
+ const reason = cycle ? `forced: dependency cycle ${cycle.join("\u2192")}\u2192${cycle[0]}` : "forced: unresolvable dependency order";
228
+ waves.push({
229
+ id: `W${++waveCounter}`,
230
+ taskIds: [forced],
231
+ reason,
232
+ parallelLimit: 1,
233
+ risk: "high"
234
+ });
235
+ completed.add(forced);
236
+ remaining.shift();
237
+ continue;
238
+ }
239
+ const writeReady = [];
240
+ const readReady = [];
241
+ for (const id of ready) {
242
+ const task = taskMap.get(id);
243
+ if (isReadOnly(task)) {
244
+ readReady.push(id);
245
+ } else {
246
+ writeReady.push(id);
247
+ }
248
+ }
249
+ const waveWriteTasks = [];
250
+ const writeFilesInWave = /* @__PURE__ */ new Set();
251
+ const deferredWrites = [];
252
+ for (const id of writeReady) {
253
+ const task = taskMap.get(id);
254
+ if (hasFileOverlapWithSet(task, writeFilesInWave)) {
255
+ deferredWrites.push(id);
256
+ continue;
257
+ }
258
+ if (waveWriteTasks.length >= maxWrite) {
259
+ deferredWrites.push(id);
260
+ continue;
261
+ }
262
+ waveWriteTasks.push(id);
263
+ for (const f of touchFiles(task)) writeFilesInWave.add(f);
264
+ }
265
+ const waveReadTasks = readReady.slice(0, maxRead);
266
+ const deferredReads = readReady.slice(maxRead);
267
+ const waveTaskIds = [...waveWriteTasks, ...waveReadTasks];
268
+ if (waveTaskIds.length > 0) {
269
+ const danglingNotes = waveTaskIds.filter((id) => danglingByTask.has(id)).map((id) => `${id} has unknown dep(s) ${danglingByTask.get(id).join(", ")}`);
270
+ const waveRisk = waveTaskIds.some((id) => taskMap.get(id)?.riskTier === "high") ? "high" : waveTaskIds.some((id) => taskMap.get(id)?.riskTier === "medium") || danglingNotes.length > 0 ? "medium" : "low";
271
+ const writeCount = waveWriteTasks.length;
272
+ const readCount = waveReadTasks.length;
273
+ const baseReason = writeCount > 0 && readCount > 0 ? `${writeCount} write + ${readCount} read tasks` : writeCount > 0 ? `${writeCount} write tasks` : `${readCount} read tasks`;
274
+ const reason = danglingNotes.length > 0 ? `${baseReason} (\u26A0 ${danglingNotes.join("; ")})` : baseReason;
275
+ waves.push({
276
+ id: `W${++waveCounter}`,
277
+ taskIds: waveTaskIds,
278
+ reason,
279
+ parallelLimit: waveTaskIds.length,
280
+ risk: waveRisk
281
+ });
282
+ for (const id of waveTaskIds) completed.add(id);
283
+ }
284
+ remaining.length = 0;
285
+ remaining.push(...deferredWrites, ...deferredReads, ...notReady);
286
+ }
287
+ return waves;
288
+ }
289
+ function hasFileOverlapWithSet(task, filesInWave) {
290
+ const taskFiles2 = touchFiles(task);
291
+ if (taskFiles2.length === 0 || filesInWave.size === 0) return false;
292
+ return taskFiles2.some((f) => filesInWave.has(f));
293
+ }
294
+
295
+ // src/agent/team-plan.ts
296
+ init_esm_shims();
297
+ var TASK_HEADING_RE = /^\s*(?:#{1,6}\s*)?(?:[-*]\s*)?(?:\[[ xX]\]\s*)?(?:\*\*)?(?:(Task\s+\d+[A-Za-z]?|T\d+[A-Za-z]?|Step\s+\d+[A-Za-z]?)(?:\s*[::.\-–—]\s*|\s+)(.*)|((?:Task|Step)\s+\d+[A-Za-z]?|T\d+[A-Za-z]?))\*?\*?\s*$/i;
298
+ var FILE_PATH_RE = /(?:`([^`]+)`|\b((?:src|docs|specs|test|tests|\.rivet)\/[\w./@+-]+(?:\.(?:ts|tsx|js|jsx|json|md|yml|yaml|toml|css|scss))?))/g;
299
+ function normalizeTaskId(raw) {
300
+ return raw.trim().replace(/\s+/g, " ");
301
+ }
302
+ function unique(values) {
303
+ return [...new Map(values.map((v) => [JSON.stringify(v), v])).values()];
304
+ }
305
+ function stripLineNoise(line) {
306
+ return line.replace(/^\s*(?:#{1,6}|[-*]|\d+\.)\s*/, "").replace(/\s+/g, " ").trim();
307
+ }
308
+ function extractFiles(text) {
309
+ const files2 = [];
310
+ for (const match of text.matchAll(FILE_PATH_RE)) {
311
+ const captured = (match[1] ?? match[2] ?? "").trim();
312
+ if (!captured) continue;
313
+ for (const raw of captured.split(/[,,、;;\s]+/)) {
314
+ const candidate = raw.replace(/[(),.;:]+$/g, "").trim();
315
+ if (!candidate) continue;
316
+ if (!/^(src|docs|specs|test|tests|\.rivet)\//.test(candidate)) continue;
317
+ files2.push(candidate);
318
+ }
319
+ }
320
+ return unique(files2);
321
+ }
322
+ function classifyTask(title) {
323
+ const lower = title.toLowerCase();
324
+ if (/审查|验收|review|squadron|inspector/.test(lower)) {
325
+ return { profile: "reviewer", kind: "review" };
326
+ }
327
+ if (/^验证$|^verify$|^verification$|验证任务|verify task/i.test(lower)) {
328
+ return { profile: "adversarial_verifier", kind: "verify" };
329
+ }
330
+ if (/调研|搜索|查找|scout|research|定位/.test(lower)) {
331
+ return { profile: "code_scout", kind: "code_search" };
332
+ }
333
+ return { profile: "patcher", kind: "patch_proposal" };
334
+ }
335
+ function classifyRiskTier(text) {
336
+ const lower = text.toLowerCase();
337
+ if (/auth|security|concurrency|persist|public.?api|config.*schema|schema.*config|migration/i.test(lower)) {
338
+ return "high";
339
+ }
340
+ if (/refactor|renam|mov|restructure/i.test(lower)) {
341
+ return "medium";
342
+ }
343
+ return "low";
344
+ }
345
+ function extractVerification(lines) {
346
+ const COMMAND_RE = /\b(?:npm|npx|node|tsx|tsc|run_tests|typecheck|pnpm|yarn|jest|vitest|make)\b/i;
347
+ return unique(lines.map(stripLineNoise).filter((line) => COMMAND_RE.test(line) || /`[^`]+`/.test(line)));
348
+ }
349
+ function parseDependencyRef(raw) {
350
+ const m = raw.match(/^([A-Za-z0-9_-]+)\(onFailure:(skip|alternate)(?::([A-Za-z0-9_-]+))?\)$/);
351
+ if (!m) return raw;
352
+ const id = m[1];
353
+ const onFailure = m[2];
354
+ const alternateId = m[3];
355
+ if (onFailure === "alternate" && !alternateId) return raw;
356
+ return {
357
+ dependsOn: id,
358
+ onFailure,
359
+ ...alternateId ? { alternateOrderId: alternateId } : {}
360
+ };
361
+ }
362
+ function extractDependencies(lines) {
363
+ const deps = [];
364
+ for (const line of lines) {
365
+ const m = line.match(/(?:depends?\s*(?:on)?|依赖|前置)\s*[::]?\s*(.+)/i);
366
+ if (m) {
367
+ const refs = m[1].split(/[,,、;;\s]+/).filter((r) => r && r.toLowerCase() !== "none");
368
+ deps.push(...refs.map(parseDependencyRef));
369
+ }
370
+ }
371
+ return unique(deps);
372
+ }
373
+ function sectionToDraft(section) {
374
+ const content = section.content.join("\n").trim();
375
+ const objective = [section.title, content].filter(Boolean).join("\n").trim() || section.id;
376
+ const classification = classifyTask(section.title || section.id);
377
+ return {
378
+ id: section.id,
379
+ title: section.title || section.id,
380
+ objective,
381
+ files: extractFiles(objective),
382
+ profile: classification.profile,
383
+ kind: classification.kind,
384
+ verification: extractVerification(section.content)
385
+ };
386
+ }
387
+ function draftToTeamTask(draft, sectionContent) {
388
+ const fullText = [draft.title, ...sectionContent].join("\n").toLowerCase();
389
+ return {
390
+ ...draft,
391
+ dependsOn: extractDependencies(sectionContent),
392
+ riskTier: classifyRiskTier(fullText),
393
+ touchSet: [...draft.files],
394
+ groupId: void 0,
395
+ routeHint: void 0
396
+ };
397
+ }
398
+ function parseTeamTaskDrafts(markdown) {
399
+ const sections = [];
400
+ let current = null;
401
+ for (const line of markdown.split(/\r?\n/)) {
402
+ const match = line.match(TASK_HEADING_RE);
403
+ if (match) {
404
+ if (current) sections.push(current);
405
+ const rawId = match[1] ?? match[3] ?? "Task";
406
+ const tail = (match[2] ?? "").trim();
407
+ const id = normalizeTaskId(rawId);
408
+ current = { id, title: tail || id, content: [] };
409
+ continue;
410
+ }
411
+ if (current) current.content.push(line);
412
+ }
413
+ if (current) sections.push(current);
414
+ return sections.map(sectionToDraft);
415
+ }
416
+ function parseTeamTasks(markdown) {
417
+ const sections = [];
418
+ let current = null;
419
+ for (const line of markdown.split(/\r?\n/)) {
420
+ const match = line.match(TASK_HEADING_RE);
421
+ if (match) {
422
+ if (current) sections.push(current);
423
+ const rawId = match[1] ?? match[3] ?? "Task";
424
+ const tail = (match[2] ?? "").trim();
425
+ const id = normalizeTaskId(rawId);
426
+ current = { id, title: tail || id, content: [] };
427
+ continue;
428
+ }
429
+ if (current) current.content.push(line);
430
+ }
431
+ if (current) sections.push(current);
432
+ return sections.map((section) => {
433
+ const draft = sectionToDraft(section);
434
+ return draftToTeamTask(draft, section.content);
435
+ });
436
+ }
437
+ function hasOverlappingFiles(a, b) {
438
+ if (a.files.length === 0 || b.files.length === 0) return false;
439
+ const bFiles = new Set(b.files);
440
+ return a.files.some((file) => bFiles.has(file));
441
+ }
442
+
443
+ // src/agent/council/council-seal.ts
444
+ init_esm_shims();
445
+ import { createHash } from "crypto";
446
+ function contractDigest(plan) {
447
+ const normalizeTask = (t) => ({
448
+ id: t.id,
449
+ objective: t.objective,
450
+ files: [...t.files].sort(),
451
+ dependsOn: [...t.dependsOn].sort(),
452
+ verification: [...t.verification ?? []].sort(),
453
+ riskTier: t.riskTier
454
+ });
455
+ const body = JSON.stringify({
456
+ objective: plan.objective,
457
+ tasks: [...plan.tasks].sort((a, b) => a.id.localeCompare(b.id)).map(normalizeTask)
458
+ });
459
+ return createHash("sha256").update(body).digest("hex").slice(0, 16);
460
+ }
461
+ function sealPlan(plan, now = Date.now()) {
462
+ const existing = plan.seal;
463
+ if (existing) throw new Error(`plan already sealed (v${existing.version}) \u2014 \u4FEE\u8BA2\u8D70 revisePlanSeal \u8C41\u514D\u534F\u8BAE\uFF0C\u4E0D\u53EF\u91CD\u5C01`);
464
+ return {
465
+ ...plan,
466
+ seal: { version: 1, digest: contractDigest(plan), sealedAt: now, exemptions: [] }
467
+ };
468
+ }
469
+ function verifyPlanSeal(plan) {
470
+ if (!plan.seal) return { status: "unsealed" };
471
+ const actual = contractDigest(plan);
472
+ if (actual === plan.seal.digest) return { status: "intact", version: plan.seal.version };
473
+ return { status: "broken", version: plan.seal.version, expected: plan.seal.digest, actual };
474
+ }
475
+ function formatSealStatus(plan) {
476
+ if (!plan.seal) return "\u5951\u7EA6\u672A\u5BC6\u5C01";
477
+ const check = verifyPlanSeal(plan);
478
+ const lineage = plan.seal.exemptions.length > 0 ? `\uFF08${plan.seal.exemptions.length} \u6B21\u8C41\u514D\u4FEE\u8BA2\uFF0C\u6700\u8FD1\uFF1A${plan.seal.exemptions.at(-1).reason}\uFF09` : "";
479
+ return check.status === "intact" ? `\u{1F50F} \u5951\u7EA6\u5DF2\u5BC6\u5C01 v${plan.seal.version} \xB7 ${plan.seal.digest}${lineage}` : `\u26D4 \u5951\u7EA6\u5BC6\u5C01\u7834\u635F v${plan.seal.version}\uFF1A\u5185\u5BB9\u4E0E\u5BC6\u5C01\u6458\u8981\u4E0D\u7B26\uFF08expected ${plan.seal.digest}, actual ${check.actual}\uFF09\u2014\u2014\u5DF2\u5BC6\u5C01\u5951\u7EA6\u4E0D\u53EF\u9759\u9ED8\u6539\u5199\uFF0C\u8D70 revisePlanSeal \u8C41\u514D\u534F\u8BAE`;
480
+ }
481
+
482
+ // src/agent/orchestration-outcome.ts
483
+ init_esm_shims();
484
+ var WORKER_ROW_CAP = 40;
485
+ function firstLineCap(text, cap) {
486
+ if (!text) return "";
487
+ const line = text.split("\n", 1)[0].trim();
488
+ return line.length > cap ? `${line.slice(0, cap - 1)}\u2026` : line;
489
+ }
490
+ function taskOf(workOrderId) {
491
+ const idx = workOrderId.lastIndexOf(":");
492
+ return idx >= 0 && idx < workOrderId.length - 1 ? workOrderId.slice(idx + 1) : workOrderId;
493
+ }
494
+ function buildWorkerRows(results) {
495
+ const rows = results.map((r) => ({
496
+ id: r.workOrderId ?? "",
497
+ task: taskOf(r.workOrderId ?? ""),
498
+ status: r.status,
499
+ ...r.failureReason ? { failureReason: r.failureReason } : {},
500
+ summary: firstLineCap(r.summary, 100),
501
+ ...r.objective ? { objective: firstLineCap(r.objective, 60) } : {},
502
+ changedCount: r.changedFiles?.length ?? 0,
503
+ ...r.changedFiles && r.changedFiles.length > 0 ? { changedFiles: r.changedFiles.slice(0, 3).map((f) => f.split("/").pop() ?? f) } : {},
504
+ ...r.diffArtifactId ? { diffArtifactId: r.diffArtifactId } : {},
505
+ ...r.evidenceStatus ? { evidenceStatus: r.evidenceStatus } : {},
506
+ ...r.usage && (typeof r.usage.input_tokens === "number" || typeof r.usage.output_tokens === "number") ? { usage: { input: r.usage.input_tokens ?? 0, output: r.usage.output_tokens ?? 0 } } : {},
507
+ ...typeof r.durationMs === "number" ? { durationMs: r.durationMs } : {}
508
+ }));
509
+ rows.sort((a, b) => (a.status === "passed" ? 1 : 0) - (b.status === "passed" ? 1 : 0));
510
+ return rows.length > WORKER_ROW_CAP ? rows.slice(0, WORKER_ROW_CAP) : rows;
511
+ }
512
+ function buildTeamOutcome(summary, fromWave, run) {
513
+ const results = summary.run?.results ?? [];
514
+ const total = results.length;
515
+ const passed = results.filter((r) => r.status === "passed").length;
516
+ const totalWaves = summary.waves.length;
517
+ const allFailed = total > 0 && passed === 0;
518
+ const isLastWave = fromWave + 1 >= totalWaves;
519
+ const hasRun = summary.run !== void 0;
520
+ let stoppedReason;
521
+ if (hasRun) {
522
+ if (allFailed) stoppedReason = "all-failed";
523
+ else if (run.gate && !run.gate.passed) stoppedReason = "wave-gate";
524
+ else if (run.reviewVerdict === "rejected") stoppedReason = "review-rejected";
525
+ else if (isLastWave) stoppedReason = "completed";
526
+ else if (passed < total) stoppedReason = "partial";
527
+ else stoppedReason = "more-waves";
528
+ }
529
+ return {
530
+ kind: "team",
531
+ dispatched: summary.dispatched,
532
+ wave: fromWave,
533
+ totalWaves,
534
+ workers: { total, passed },
535
+ // 已成功执行完的波次数:整波失败时本波未成功完成(= fromWave),
536
+ // 其余情况本波已完成(= fromWave + 1)。末波完成时 === totalWaves。
537
+ ...hasRun ? { completedWaves: allFailed ? fromWave : fromWave + 1, stoppedReason } : {},
538
+ ...run.gate ? { waveGate: { passed: run.gate.passed, failures: run.gate.failures } } : {},
539
+ ...run.reviewVerdict ? { reviewVerdict: run.reviewVerdict } : {},
540
+ ...total > 0 ? { workerRows: buildWorkerRows(results) } : {}
541
+ };
542
+ }
543
+
544
+ // src/agent/plan-executor.ts
545
+ init_esm_shims();
546
+ import { isAbsolute } from "path";
547
+
548
+ // src/agent/review-coordinator-deps.ts
549
+ init_esm_shims();
550
+ var REVIEW_PARENT_TURN_ID = "deliver_task:review-router";
551
+ function files(change) {
552
+ return [...change.files];
553
+ }
554
+ function objectiveReviewStanceBlock() {
555
+ return [
556
+ "\u5BA2\u89C2\u5BA1\u67E5\u59FF\u6001\uFF08\u6765\u81EA\u5916\u90E8 Claude Code Opus \u5BA1\u8BA1\u7ECF\u9A8C\u7684\u5185\u5316\uFF1B\u4E0D\u4F9D\u8D56\u5916\u90E8\u8F85\u52A9\u5728\u573A\uFF09\uFF1A",
557
+ formatObjectiveReviewStance()
558
+ ].join("\n");
559
+ }
560
+ function dataflowVerifierBlock() {
561
+ return [
562
+ "\u6570\u636E\u6D41\u9A8C\u8BC1\u59FF\u6001\uFF08\u590D\u6742 spec \u7684 P4-c \u6559\u8BAD\uFF09\uFF1A",
563
+ "1. \u4E0D\u8981\u628A spec \u6761\u6B3E\u5F53\u6210\u6241\u5E73\u6E05\u5355\u6838\u5BF9\uFF1B\u4ECE spec \u5B57\u6BB5/\u7EA6\u675F\u51FA\u53D1\uFF0C\u91CD\u6784\u4E8B\u5B9E\u6D41\u56FE\uFF1A\u751F\u4EA7\u8005 \u2192 \u4E2D\u95F4\u7ED3\u6784 \u2192 \u6D88\u8D39\u8005/\u5199\u5165\u76EE\u6807 \u2192 \u65AD\u8A00\u3002",
564
+ "2. \u68C0\u67E5\u7EC4\u5408\u95E8\u63A7\u7684\u6761\u4EF6\u77E9\u9635\uFF0C\u5982 source \xD7 severity \xD7 apply\uFF1B\u5D4C\u5957\u7EA6\u675F\u4E0D\u80FD\u62CD\u5E73\u6210\u72EC\u7ACB\u7684 if\u3002",
565
+ "3. \u8981\u6C42\u53CD\u4F8B\u8986\u76D6\uFF1A\u5982\u679C\u5B9E\u73B0\u53EA\u5904\u7406\u4E86 happy path\u3001\u5FD8\u4E86\u8C03\u7528\u5408\u7EA6\u3001\u58F0\u660E\u4E86\u7C7B\u578B\u5374\u4E0D\u6D88\u8D39\u3001\u6216\u7528 truthy/falsy \u54E8\u5175\uFF08\u5982 !waveId\uFF09\uFF0C\u54EA\u4E2A\u5DF2\u5B58\u5728\u6216\u65B0\u589E\u7684\u6D4B\u8BD5\u4F1A\u5931\u8D25\uFF1F",
566
+ "4. \u6D4B\u8BD5\u5168\u7EFF\u4E0D\u591F\u2014\u2014\u5B83\u5FC5\u987B\u80FD\u8BA9\u9519\u8BEF/\u521D\u7248\u5B9E\u73B0\u5728\u76F8\u5173 spec \u8DEF\u5F84\u4E0A\u53D8\u7EA2\u3002",
567
+ "5. \u865A\u5047\u7EFF\u706F/fixture \u5951\u7EA6\u5BA1\u8BA1\uFF1A\u5BF9\u6D4B\u8BD5 mock/fixture \u5728\u4F9D\u8D56\u8F93\u51FA\u4E0A\u8D4B\u503C\u7684\u6BCF\u4E2A\u5B57\u6BB5\uFF0C\u9A8C\u8BC1\u771F\u5B9E\u751F\u4EA7\u4EE3\u7801\u662F\u5426\u786E\u5B9E\u4EA7\u51FA\u8BE5\u5F62\u72B6\uFF08grep \u5199\u5165\u70B9\uFF0C\u4E0D\u662F\u53EA\u770B\u7C7B\u578B\u58F0\u660E\uFF09\u3002\u5BF9\u751F\u4EA7\u4EE3\u7801\u6E32\u67D3/\u6D88\u8D39\u7684\u6BCF\u4E2A\u5B57\u6BB5\uFF0C\u8FFD\u8E2A\u5176\u751F\u4EA7\u5199\u5165\u70B9\u53CA\u8BE5\u5199\u5165\u7684\u8FD0\u884C\u65F6\u6761\u4EF6\u662F\u5426\u771F\u7684\u80FD\u89E6\u53D1\uFF08`raw.x ?` \u5B88\u536B\u7684\u5199\u5165\u884C\uFF0C\u5982\u679C\u6570\u636E\u6E90\u4ECE\u4E0D\u643A\u5E26 x\uFF0C\u4ECD\u7136\u662F\u6B7B\u7684\uFF09\u3002fixture \u865A\u6784\u4E86\u4E00\u4E2A\u771F\u5B9E\u7CFB\u7EDF\u4ECE\u4E0D\u4EA7\u51FA\u7684\u5F62\u72B6\u2014\u2014\u6216\u53CC\u65B9\u5404\u81EA mock \u8FB9\u754C\u5374\u65E0\u4E00\u4EFD\u5408\u7EA6\u6D4B\u8BD5\u65AD\u8A00\u771F\u5B9E\u751F\u4EA7\u8005\u7684\u8F93\u51FA\u2014\u2014\u5C31\u662F\u865A\u5047\u7EFF\u706F\uFF0C\u4E0A\u62A5 HIGH\u3002"
568
+ ].join("\n");
569
+ }
570
+ function pathBoundaryReviewBlock() {
571
+ return [
572
+ "\u8DEF\u5F84\u8FB9\u754C/\u6CE8\u610F\u529B\u95E8\u63A7\u5BA1\u67E5\u59FF\u6001\uFF08T7/MeridianIndexer \u6559\u8BAD\uFF1B\u59CB\u7EC8\u9002\u7528\u4E8E path\u3001classifier\u3001discovery\u3001indexer\u3001watcher\u3001git-status\u3001ownership \u76F8\u5173\u6539\u52A8\uFF09\uFF1A",
573
+ formatPathBoundaryReviewStance()
574
+ ].join("\n");
575
+ }
576
+ function weighingReviewBlock() {
577
+ return [
578
+ "\u79F0\u91CF\u5BA1\u67E5\u59FF\u6001\uFF08\u5929\u6743\u79F0\u91CF\u8005\u6559\u8BAD\uFF1B\u9002\u7528\u4E8E\u91CD\u6784\u3001\u63D0\u53D6\u3001\u5C01\u88C5/\u4F5C\u7528\u57DF\u53D8\u66F4\u2014\u2014\u65E2\u9A8C\u771F\u4F2A\uFF0C\u4E5F\u79F0\u91CF\u4EE3\u4EF7\uFF09\uFF1A",
579
+ formatWeighingReviewStance()
580
+ ].join("\n");
581
+ }
582
+ function wiringEffectivenessBlock() {
583
+ return [
584
+ '\u63A5\u7EBF\u6709\u6548\u6027\u5BA1\u67E5\u59FF\u6001\uFF082026-06-12 \u566A\u97F3\u6CBB\u7406\u590D\u5BA1\u6559\u8BAD\uFF1B"built \u2260 wired \u2260 effective"\u2014\u2014\u9002\u7528\u4E8E\u6BCF\u6B21 feature/config/param/bus/gate \u65B0\u589E\uFF09\uFF1A',
585
+ formatWiringEffectivenessReviewStance()
586
+ ].join("\n");
587
+ }
588
+ function methodologyVerificationBlock() {
589
+ return [
590
+ '\u65B9\u6CD5\u8BBA\u9A8C\u8BC1\u59FF\u6001\uFF082026-06-14 PlanDesignIntentRouter \u5BF9\u6297\u5BA1\u67E5\u53CD\u63A8\uFF1B"\u65B9\u6CD5\u8BBA\u6587\u6863\u5373\u4EE3\u7801\u2014\u2014\u53EF\u6267\u884C\u6307\u4EE4\u9700\u5B9E\u8BC1\u9A8C\u8BC1"\u2014\u2014\u9002\u7528\u4E8E\u5BA1\u67E5\u77E5\u8BC6\u6587\u4EF6\u3001\u8BA1\u5212\u6A21\u677F\u3001\u89C4\u5219\u3001\u81EA\u68C0\u6E05\u5355\uFF09\uFF1A',
591
+ formatMethodologyVerificationStance()
592
+ ].join("\n");
593
+ }
594
+ function caseSensitivityReviewBlock() {
595
+ return [
596
+ "\u5927\u5C0F\u5199\u5BA1\u67E5\u59FF\u6001\uFF08macOS APFS \u5927\u5C0F\u5199\u4E0D\u654F\u611F\u2192\u5F00\u53D1\u673A\u4E0D\u62A5\u9519\uFF0CLinux/CI \u5D29\u6E83\u2014\u2014\u4E13\u6293 import \u8DEF\u5F84\u3001API \u6807\u8BC6\u7B26\u3001\u5168\u5C40\u53D8\u91CF\u5927\u5C0F\u5199\u4E0D\u4E00\u81F4\uFF09\uFF1A",
597
+ formatCaseSensitivityReviewStance()
598
+ ].join("\n");
599
+ }
600
+ function childReviewDepth(options) {
601
+ return (options.reviewDepth ?? 0) + 1;
602
+ }
603
+ function scope(change) {
604
+ return { files: files(change), overlapsPrimary: true };
605
+ }
606
+ function request(input) {
607
+ const reviewDepth = childReviewDepth(input.options);
608
+ return {
609
+ parentTurnId: input.options.parentTurnId ?? REVIEW_PARENT_TURN_ID,
610
+ objective: [
611
+ input.objective,
612
+ "",
613
+ `\u5BA1\u67E5\u6DF1\u5EA6: ${reviewDepth}\u3002\u5BA1\u67E5 worker \u4E0D\u5F97\u8C03\u7528 deliver_task\uFF1B\u4EC5\u62A5\u544A verdict/evidence \u5373\u53EF\u3002`
614
+ ].join("\n"),
615
+ kind: input.kind,
616
+ profile: input.profile,
617
+ scope: scope(input.change),
618
+ reviewDepth,
619
+ ...input.onActivity ? { onActivity: input.onActivity } : {}
620
+ };
621
+ }
622
+ function verificationEvidence(result) {
623
+ if (!result.verification) return void 0;
624
+ const v = result.verification;
625
+ return `ran: ${v.command} \u2192 ${v.status} (${v.passed ?? 0} passed, ${v.failed ?? 0} failed, ${v.skipped ?? 0} skipped)`;
626
+ }
627
+ function formatFinding(finding) {
628
+ const prefix = finding.evidenceKind === "firsthand" ? "[\u4E00\u624B] " : finding.evidenceKind === "inferred" ? "[\u8F6C\u8FF0] " : "";
629
+ const refs = finding.evidenceRefs && finding.evidenceRefs.length > 0 ? ` (${finding.evidenceRefs.join(", ")})` : "";
630
+ return `${prefix}${finding.claim} \u2014 ${finding.evidence}${refs}`;
631
+ }
632
+ function summarizeResult(result) {
633
+ const parts = [
634
+ verificationEvidence(result),
635
+ result.summary,
636
+ ...result.findings.slice(0, 3).map(formatFinding),
637
+ ...result.risks.slice(0, 3).map((risk) => `risk: ${risk}`)
638
+ ].filter((part) => Boolean(part && part.trim().length > 0));
639
+ return parts.join("\n");
640
+ }
641
+ function summarizeRun(run) {
642
+ if (run.status === "skipped") return "review worker skipped: objective did not pass delegation budget gate";
643
+ const summaries = run.results.map(summarizeResult).filter(Boolean);
644
+ return summaries.length > 0 ? summaries.join("\n---\n") : "review worker returned no evidence";
645
+ }
646
+ function extractSeverity(text) {
647
+ if (/\bCRITICAL\b|\bC\d+\b/i.test(text)) return "CRITICAL";
648
+ if (/\bHIGH\b|\bH\d+\b/i.test(text)) return "HIGH";
649
+ if (/\bMEDIUM\b|\bM\d+\b/i.test(text)) return "MEDIUM";
650
+ if (/\bLOW\b|\bL\d+\b/i.test(text)) return "LOW";
651
+ return void 0;
652
+ }
653
+ function mapWorkerFinding(result, finding) {
654
+ const text = `${finding.claim}
655
+ ${finding.evidence}
656
+ ${result.summary}`;
657
+ return {
658
+ severity: extractSeverity(text),
659
+ claim: finding.claim,
660
+ evidence: finding.evidence,
661
+ // 极性透传:worker 未上报时缺席,blocking 判定按 defect 处理(fail-closed)。
662
+ ...finding.polarity ? { polarity: finding.polarity } : {}
663
+ };
664
+ }
665
+ function mapSquadronFindings(run) {
666
+ const findings = [];
667
+ for (const result of run.results) {
668
+ if (result.status !== "passed") continue;
669
+ for (const finding of result.findings) {
670
+ findings.push(mapWorkerFinding(result, finding));
671
+ }
672
+ }
673
+ return findings;
674
+ }
675
+ function formatReportSource(source) {
676
+ switch (source) {
677
+ case "salvaged":
678
+ return "[\u6765\u6E90: \u5B57\u6BB5\u7EA7\u6253\u635E\uFF0Cunverified] ";
679
+ case "blocked":
680
+ return "[\u6765\u6E90: \u7ED3\u6784\u5316\u963B\u585E] ";
681
+ case "repaired":
682
+ return "[\u6765\u6E90: \u65E0\u5386\u53F2\u4FEE\u590D\u8F6E\uFF0C\u4EC5\u4F9B\u53C2\u8003] ";
683
+ default:
684
+ return "";
685
+ }
686
+ }
687
+ function classifyInfraFailure(result) {
688
+ switch (result.failureReason) {
689
+ case "json_parse":
690
+ case "schema_mismatch":
691
+ return "json";
692
+ case "max_turns":
693
+ return "budget";
694
+ case "timeout":
695
+ return "timeout";
696
+ default:
697
+ break;
698
+ }
699
+ const summary = result.summary;
700
+ if (/did not contain a JSON object|schema-valid JSON|parse/i.test(summary)) return "json";
701
+ if (/max.?turns|exhausted without a final turn/i.test(summary)) return "budget";
702
+ if (/timeout|timed out/i.test(summary)) return "timeout";
703
+ if (/skipped/i.test(summary)) return "skip";
704
+ return "worker";
705
+ }
706
+ function mapSquadronInfraFailures(run) {
707
+ if (run.status === "skipped") {
708
+ return [{ kind: "skip", claim: "Review Squadron skipped before producing findings" }];
709
+ }
710
+ const failures = [];
711
+ for (const result of run.results) {
712
+ if (result.status === "passed") continue;
713
+ const salvaged = result.findings.length > 0 ? result.findings.slice(0, 8).map((f) => ({ claim: f.claim, confidence: f.confidence })) : void 0;
714
+ failures.push({
715
+ kind: classifyInfraFailure(result),
716
+ claim: `${formatReportSource(result.reportSource)}${result.summary}`,
717
+ ...salvaged !== void 0 ? { salvagedFindings: salvaged } : {}
718
+ });
719
+ }
720
+ return failures;
721
+ }
722
+ function verifierResult(run) {
723
+ const verified = run.status === "completed" && run.results.some((result) => result.status === "passed" && result.evidenceStatus === "verified");
724
+ return {
725
+ verdict: verified ? "verified" : "rejected",
726
+ evidence: summarizeRun(run)
727
+ };
728
+ }
729
+ function patcherResult(run) {
730
+ const patchedRun = run.status === "completed" ? run.results.find((result) => result.status === "passed" && (result.changedFiles.length > 0 || Boolean(result.patchSummary))) : void 0;
731
+ if (!patchedRun) return { patched: false };
732
+ return {
733
+ patched: true,
734
+ ...patchedRun.changedFiles.length > 0 ? { changedFiles: [...patchedRun.changedFiles] } : {},
735
+ ...patchedRun.patchSummary ? { patchSummary: patchedRun.patchSummary } : {},
736
+ // 落盘句柄必须跟着回流:隔离 worktree 会被清理,句柄是主控取回补丁的唯一途径。
737
+ // 在这一层丢掉它,披露行就只能说「改了什么」而给不出补丁。
738
+ ...patchedRun.diffArtifactId ? { diffArtifactId: patchedRun.diffArtifactId } : {}
739
+ };
740
+ }
741
+ function verifierObjective(change) {
742
+ const largeWarn = formatLargeFileWarnings(change);
743
+ return [
744
+ "\u5728\u4EA4\u4ED8\u524D\u72EC\u7ACB\u5BF9\u6297\u6027\u9A8C\u8BC1\u6B64\u6539\u52A8\u3002",
745
+ objectiveReviewStanceBlock(),
746
+ dataflowVerifierBlock(),
747
+ pathBoundaryReviewBlock(),
748
+ weighingReviewBlock(),
749
+ wiringEffectivenessBlock(),
750
+ caseSensitivityReviewBlock(),
751
+ methodologyVerificationBlock(),
752
+ `\u8303\u56F4\u6587\u4EF6: ${files(change).join(", ") || "(\u65E0)"}`,
753
+ ...change.focusHint ? [`**\u5BA1\u67E5\u91CD\u70B9**: ${change.focusHint}`] : [],
754
+ ...largeWarn ? [largeWarn] : [],
755
+ "\u5C3D\u53EF\u80FD\u8FD0\u884C\u76F8\u5173\u7684\u65E2\u6709\u6D4B\u8BD5\uFF0C\u8FD4\u56DE\u547D\u4EE4 + \u89C2\u6D4B\u5230\u7684\u8F93\u51FA\u4F5C\u4E3A\u8BC1\u636E\u3002",
756
+ "\u4E0D\u8981\u6B62\u6B65\u4E8E\u6D4B\u8BD5\u7EFF\uFF1A\u5BF9\u53D8\u66F4\u6587\u4EF6\u81F3\u5C11\u5C1D\u8BD5\u4E00\u4E2A\u53CD\u4F8B\u6216\u8FB9\u754C/\u9519\u8BEF\u8DEF\u5F84\u63A2\u9488\u3002",
757
+ "\u5BF9 spec/\u96C6\u6210\u7C7B\u53D8\u66F4\uFF0C\u663E\u5F0F\u62A5\u544A\u4E8B\u5B9E\u6D41\u95ED\u73AF\u3001\u6761\u4EF6\u77E9\u9635\u8986\u76D6\u3001\u4EE5\u53CA\u4E00\u4E2A\u80FD\u8BA9\u7EAF\u6E05\u5355\u5F0F\u5B9E\u73B0\u5931\u8D25\u7684\u6D4B\u8BD5\u7528\u4F8B\u3002",
758
+ '\u4EC5\u5F53\u9A8C\u8BC1\u786E\u5B9E\u8FD0\u884C\u3001\u901A\u8FC7\u3001\u4E14\u672A\u53D1\u73B0\u53CD\u4F8B\u65F6\uFF0C\u8FD4\u56DE evidenceStatus="verified" \u7684 WorkerResult JSON\u3002'
759
+ ].join("\n");
760
+ }
761
+ function patcherObjective(change, verifier) {
762
+ return [
763
+ "\u5728\u9694\u79BB\u7684 worker worktree \u4E2D\u4FEE\u590D\u88AB\u5BF9\u6297\u9A8C\u8BC1\u62D2\u7EDD\u7684\u6539\u52A8\u3002",
764
+ "\u4FEE\u590D\u9A8C\u8BC1\u5668\u6307\u51FA\u7684\u6839\u56E0\uFF1B\u4E0D\u8981\u5F31\u5316\u6D4B\u8BD5\u6216\u4EC5\u538B\u5236\u75C7\u72B6\u3002",
765
+ `\u8303\u56F4\u6587\u4EF6: ${files(change).join(", ") || "(\u65E0)"}`,
766
+ `\u9A8C\u8BC1\u5668\u5224\u51B3: ${verifier.verdict}`,
767
+ `\u9A8C\u8BC1\u5668\u8BC1\u636E: ${verifier.evidence}`,
768
+ "\u8FD4\u56DE\u5E26 changedFiles \u548C patchSummary \u7684 WorkerResult JSON\u3002"
769
+ ].join("\n");
770
+ }
771
+ var WIRING_INSPECTOR_METHOD = [
772
+ "\u65B9\u6CD5\uFF08\u9010\u9879\uFF0C\u9644 file:line\uFF09\uFF1A",
773
+ "1. \u4ECE\u751F\u4EA7\u5165\u53E3\u6B63\u5411\u8FFD\u95ED\u73AF\uFF1A\u5165\u53E3\u2192\u7EC4\u5408\u6839\u2192\u6539\u52A8\u70B9\u3002\u6D4B\u8BD5/\u811A\u672C\u4E2D\u7684\u6302\u70B9\u4E0D\u7B97\u3002\u65AD\u7EBF=HIGH\u3002",
774
+ "2. \u65B0\u589E\u53C2\u6570/\u5B57\u6BB5/setter\u2192grep \u6240\u6709\u8C03\u7528\u65B9\u3002\u96F6\u8C03\u7528\u65B9\u4F20\u503C/\u8BFB\u53D6=\u6B7B\u63A5\u7EBF\u3002",
775
+ "3. \u95E8\u63A7\u6761\u4EF6\u2192\u679A\u4E3E\u771F\u5B9E\u8F93\u5165\u5F62\u72B6(\u7A7A\u96C6\u5408/\u53EF\u9009\u5B57\u6BB5\u7F3A\u5931/\u81EA\u7531\u6587\u672C)\u2192\u4F30\u7B97\u901A\u8FC7\u7387\u3002~0%\u6216~100%\u5747\u65E0\u6548\u3002",
776
+ "4. \u6539\u52A8\u58F0\u79F0\u76EE\u6807\u2192\u6784\u9020\u6539\u524D/\u6539\u540E\u573A\u666F\u9A8C\u8BC1\u6307\u6807\u786E\u5B9E\u671D\u58F0\u79F0\u65B9\u5411\u79FB\u52A8\u3002",
777
+ "5. \u88AB\u79FB\u9664\u8C03\u7528\u70B9\u2192\u68C0\u67E5\u9057\u7559\u751F\u4EA7\u8005/setter/\u5B57\u6BB5\u662F\u5426\u4E5F\u6709\u6D3B\u6D88\u8D39\u8005\u3002"
778
+ ].join("\n");
779
+ var SILENCE_INSPECTOR_METHOD = [
780
+ "\u65B9\u6CD5\uFF08\u9010\u9879\u6267\u884C\uFF0C\u6BCF\u9879\u9644 file:line \u8BC1\u636E\uFF09\uFF1A",
781
+ "1. \u7A7A catch/\u88AB\u541E\u9519\u8BEF\uFF1A\u7528 ast_grep \u67E5\u627E\u7A7A\u4F53\u6216\u65E0\u64CD\u4F5C\u4F53\u7684 catch \u5757\u2014\u2014\u6A21\u5F0F `try { $$A } catch ($E) { }`\uFF08\u7A7A\u4F53\uFF09\u548C `try { $$A } catch ($E) { $$B }`\uFF0C\u7136\u540E\u8BFB\u53D6\u6BCF\u4E2A $B \u68C0\u67E5\u662F\u5426\u53EA\u6253\u4E86\u65E5\u5FD7/\u541E\u6389\u9519\u8BEF\u800C\u6CA1\u6709\u91CD\u65B0\u629B\u51FA\u6216\u4E0A\u6D6E\u3002grep \u65E0\u6CD5\u533A\u5206 catch \u4F53\u548C\u5468\u56F4\u4EE3\u7801\uFF1Bast_grep \u80FD\u7CBE\u786E\u5B9A\u4F4D\u7ED3\u6784\u5F62\u72B6\u3002",
782
+ "2. \u65E0 rejection \u5904\u7406\u5668\u7684 Promise\uFF1Aast_grep \u6A21\u5F0F `$$P.then($F)` \u548C `async $F($$) { $$ }`\u2014\u2014\u4EA4\u53C9\u5F15\u8BC1\u786E\u8BA4\u6BCF\u6761\u5F02\u6B65\u8DEF\u5F84\u90FD\u6709 .catch \u6216 try-catch\u3002rejected promise \u4E0A\u88F8 `.then` \u65E0 `.catch` = \u88AB\u541E\u6389\u7684 rejection\u3002",
783
+ '3. \u5BF9"\u6D4B\u8BD5\u5DF2\u901A\u8FC7/\u5DF2\u4FEE\u590D"\u7C7B\u58F0\u660E\uFF1A\u8981\u6C42\u63D0\u4F9B\u786E\u5207\u547D\u4EE4 + \u89C2\u6D4B\u5230\u7684\u901A\u8FC7\u6570\u3002\u53EA\u8986\u76D6 happy path\uFF08\u65E0\u9519\u8BEF\u8DEF\u5F84\u65AD\u8A00\uFF09\u7684\u7EFF\u8272\u662F\u865A\u5047\u7EFF\u706F\u2014\u2014\u6807\u8BB0\u5B83\u3002'
784
+ ].join("\n");
785
+ var INSPECTORS = [
786
+ {
787
+ name: "\u5B89\u5168\u5BA1\u67E5",
788
+ objective: "\u5BA1\u67E5\u8BA4\u8BC1\u3001\u6388\u6743\u3001\u8DEF\u5F84\u6821\u9A8C\u3001\u5BC6\u94A5\u6CC4\u9732\u3001\u4EE5\u53CA fail-open/fail-closed \u884C\u4E3A\u3002",
789
+ stances: ["pathBoundary"]
790
+ },
791
+ {
792
+ name: "\u751F\u547D\u5468\u671F",
793
+ objective: "\u5BA1\u67E5\u72B6\u6001\u8F6C\u6362\u3001\u5F02\u6B65\u7ADE\u6001\u3001\u53D6\u6D88\u4F20\u64AD\u3001\u8D85\u65F6\u4F20\u9012\u3001\u4EE5\u53CA load-check-save \u539F\u5B50\u6027\u3002\u9A8C\u8BC1\u5916\u5C42\u8D85\u65F6\u4E25\u683C\u652F\u914D\u5185\u5C42\u9884\u7B97\uFF08\u5185\u5C42\u5FC5\u987B\u5148\u89E6\u53D1\u4EE5\u4FDD\u7559\u90E8\u5206\u7ED3\u679C\uFF09\u3002",
794
+ stances: ["dataflow"]
795
+ },
796
+ {
797
+ name: "\u6570\u636E\u6D41",
798
+ objective: "\u5BA1\u67E5\u53C2\u6570\u4F20\u64AD\u3001\u767D\u540D\u5355/\u5DE5\u5177\u4F5C\u7528\u57DF\u4F20\u64AD\u3001\u6301\u4E45\u5316\u8DEF\u5F84\u3001\u4EE5\u53CA\u6570\u636E\u4E22\u5931\u98CE\u9669\u3002",
799
+ stances: ["dataflow", "pathBoundary"]
800
+ },
801
+ {
802
+ name: "\u9759\u9ED8\u5BA1\u67E5",
803
+ objective: '\u5BA1\u67E5\u88AB\u541E\u6389\u7684\u9519\u8BEF\u3001\u7A7A catch \u5757\u3001\u7F3A\u5931\u7684\u8BCA\u65AD\u4FE1\u606F\u3001\u4EE5\u53CA\u865A\u5047\u7EFF\u706F\u9A8C\u8BC1\u58F0\u660E\u3002\u5C06"\u6D4B\u8BD5\u5DF2\u901A\u8FC7/\u5DF2\u4FEE\u590D"\u7C7B\u65AD\u8A00\u4F5C\u4E3A\u6700\u9AD8\u4F18\u5148\u7EA7\u5BA1\u67E5\u76EE\u6807\uFF1A\u8981\u6C42\u63D0\u4F9B\u786E\u5207\u547D\u4EE4 + \u89C2\u6D4B\u5230\u7684\u8F93\u51FA\u3002\u540C\u65F6\u6807\u8BB0 fixture \u865A\u6784\u7684\u865A\u5047\u7EFF\u706F\uFF1A\u6D4B\u8BD5\u65AD\u8A00\u4E86\u4E00\u4E2A\u751F\u4EA7\u4EE3\u7801\u4ECE\u672A\u5199\u5165\u8FC7\u771F\u5B9E\u503C\u7684\u5B57\u6BB5/\u5F62\u72B6\u2014\u2014\u53EA\u6709 fixture \u5728\u5199\u2014\u2014\u5BFC\u81F4\u8BE5\u529F\u80FD\u7EFF\u706F\u4F46\u5B9E\u9645\u5DF2\u6B7B\u3002',
804
+ stances: [],
805
+ method: SILENCE_INSPECTOR_METHOD
806
+ },
807
+ {
808
+ name: "\u63A5\u7EBF\u5BA1\u67E5",
809
+ objective: '\u5BA1\u67E5\u7AEF\u5230\u7AEF\u63A5\u7EBF\u4E0E\u6709\u6548\u6027\u2014\u2014"\u6784\u5EFA \u2260 \u63A5\u7EBF \u2260 \u6709\u6548"\u3002\u6392\u67E5\uFF1A\u8BA1\u5212\u9879\u534A\u6210\u54C1\uFF08\u5B57\u6BB5\u52A0\u4E86\u4F46\u4ECE\u672A\u5F3A\u5236\u751F\u6548\uFF09\u3001\u65B0\u589E\u53EF\u9009\u53C2\u6570\u5374\u65E0\u8C03\u7528\u65B9\u3001setter/\u603B\u7EBF/\u914D\u7F6E\u6807\u5FD7\u4ECE\u672A\u88AB\u8BFB\u53D6\u6216\u51B2\u5237\u3001\u95E8\u7981\u88AB\u771F\u5B9E\u6570\u636E\u5F62\u72B6\u8FC7\u6EE4\u6389\u51E0\u4E4E\u6240\u6709\u8F93\u5165\uFF08\u9759\u9ED8\u7279\u6027\u6740\u622E\uFF09\u3001\u4EE5\u53CA\u6539\u52A8\u4E0E\u5176\u58F0\u79F0\u76EE\u6807\u80CC\u9053\u800C\u9A70\uFF08\u4F8B\u5982\u65E7\u901A\u9053\u4E0E\u65B0\u901A\u9053\u5E76\u5B58\u2014\u2014\u964D\u566A\u6539\u52A8\u91CC\u51FA\u73B0\u91CD\u590D\u6E32\u67D3\uFF09\u3002',
810
+ stances: ["wiring"],
811
+ method: WIRING_INSPECTOR_METHOD
812
+ }
813
+ ];
814
+ function stanceBlocks(stances) {
815
+ const blocks = [];
816
+ if (stances.includes("dataflow")) blocks.push(dataflowVerifierBlock());
817
+ if (stances.includes("pathBoundary")) blocks.push(pathBoundaryReviewBlock());
818
+ if (stances.includes("wiring")) blocks.push(wiringEffectivenessBlock());
819
+ if (stances.includes("methodology")) blocks.push(methodologyVerificationBlock());
820
+ return blocks;
821
+ }
822
+ var FINDING_CONTRACT = [
823
+ '\u6BCF\u9879\u53D1\u73B0\u987B\u62A5\u544A\u4E25\u91CD\u7EA7\u522B CRITICAL/HIGH/MEDIUM/LOW\u3001\u7ED3\u8BBA\u3001\u8BC1\u636E\uFF08file:line\uFF09\u3001\u4EE5\u53CA\u6700\u5C0F\u4FEE\u590D\u5EFA\u8BAE\u3002\u82E5\u8BE5\u5BA1\u67E5\u7EF4\u5EA6\u65E0\u95EE\u9898\uFF0C\u987B\u660E\u786E\u62A5\u544A"\u672A\u53D1\u73B0\u5F02\u5E38"\u2014\u2014\u6C89\u9ED8\u4E0D\u7B49\u4E8E\u901A\u8FC7\u3002',
824
+ 'severity \u8BED\u4E49\uFF1ACRITICAL/HIGH \u53EA\u7528\u4E8E\u5FC5\u987B\u4FEE\u590D\u7684\u7F3A\u9677\u3002\u786E\u8BA4\u6027\u7ED3\u8BBA\uFF08\u5DF2\u6838\u5B9E\u65E0\u95EE\u9898\u3001\u94FE\u8DEF\u95ED\u5408\u3001\u53E3\u5F84\u5BF9\u9F50\uFF09\u4E0D\u662F\u7F3A\u9677\u2014\u2014\u5728\u8BE5 finding \u4E0A\u6807 "polarity": "confirmation"\uFF0C\u5B83\u4F1A\u8FDB\u5165\u300C\u5DF2\u6838\u5B9E\u6E05\u5355\u300D\u800C\u975E blocking findings\uFF1B\u7F3A\u9677\u53EF\u663E\u5F0F\u6807 "defect"\uFF08\u7F3A\u7701\u6309 defect \u5904\u7406\uFF09\u3002',
825
+ "status \u8BED\u4E49\uFF1Astatus \u8868\u793A\u4F60\u7684\u5BA1\u67E5\u4EFB\u52A1\u662F\u5426\u5B8C\u6210\uFF0C\u4E0D\u662F\u88AB\u5BA1\u4EE3\u7801\u7684\u5224\u5B9A\u3002\u53D1\u73B0 CRITICAL \u7F3A\u9677\u65F6 status \u4ECD\u4E3A passed\u2014\u2014\u7F3A\u9677\u7ECF findings \u8868\u8FBE\uFF1Bfailed/blocked \u53EA\u7528\u4E8E\u4F60\u81EA\u5DF1\u6CA1\u5B8C\u6210\u5BA1\u67E5\uFF08\u9884\u7B97\u8017\u5C3D\u3001\u8BFB\u4E0D\u5230\u4EE3\u7801\u7B49\uFF09\u3002"
826
+ ].join("\n");
827
+ function formatLargeFileWarnings(change) {
828
+ if (!change.largeFiles || change.largeFiles.length === 0) return null;
829
+ const lines = [
830
+ `\u26A0\uFE0F ${change.largeFiles.length} \u4E2A\u6587\u4EF6\u8D85\u51FA ${Math.round(LARGE_FILE_WARN_THRESHOLD / 1e3)}KB \u5BA1\u67E5\u9608\u503C\uFF1A`
831
+ ];
832
+ for (const lf of change.largeFiles) {
833
+ const kb = Math.round(lf.sizeBytes / 1e3);
834
+ lines.push(` - ${lf.path} (${kb}KB)`);
835
+ }
836
+ lines.push(
837
+ "",
838
+ '\u4E0D\u8981\u6574\u6587\u4EF6\u8BFB\u53D6\u4E0A\u8FF0\u6587\u4EF6\u2014\u2014\u5148\u7528 grep/repo_graph \u6216 read_file(focus="\u5BA1\u67E5\u91CD\u70B9") \u5B9A\u4F4D\u5173\u952E\u7247\u6BB5\u3002',
839
+ "\u82E5\u9700\u7CBE\u786E\u6838\u9A8C\uFF0C\u518D\u7528 read_file + offset/limit \u53EA\u8BFB\u6539\u52A8\u884C\u9644\u8FD1\u7684\u76F8\u5173\u6BB5\u843D\u3002"
840
+ );
841
+ return lines.join("\n");
842
+ }
843
+ function inspectorObjective(inspector, change) {
844
+ const largeWarn = formatLargeFileWarnings(change);
845
+ const fileList = files(change).join(", ") || "(\u65E0)";
846
+ const header = change.commitMessage ? `\u3010${inspector.name}\u3011${change.commitMessage}` : `\u3010${inspector.name}\u3011${inspector.objective}`;
847
+ const intro = change.commitMessage ? inspector.objective : "";
848
+ return [
849
+ header,
850
+ `\u8303\u56F4: ${fileList}`,
851
+ ...intro ? [intro] : [],
852
+ objectiveReviewStanceBlock(),
853
+ ...stanceBlocks(inspector.stances),
854
+ ...inspector.method ? [inspector.method] : [],
855
+ ...change.focusHint ? [`\u5BA1\u67E5\u91CD\u70B9: ${change.focusHint}`] : [],
856
+ ...largeWarn ? [largeWarn] : [],
857
+ ...inspector.stances.includes("dataflow") ? ["For spec/integration changes, review the fact-flow graph, condition matrix, and counterexample tests before accepting checklist-style coverage."] : [],
858
+ FINDING_CONTRACT,
859
+ "",
860
+ "\u56DE\u590D\u8BED\u8A00: \u4E2D\u6587\u3002\u6240\u6709\u53D1\u73B0\u3001\u6458\u8981\u3001risks \u5747\u7528\u4E2D\u6587\u64B0\u5199\u3002"
861
+ ].join("\n");
862
+ }
863
+ function squadronRequests(change, options, onActivity) {
864
+ return INSPECTORS.map((inspector) => request({
865
+ change,
866
+ options,
867
+ kind: "review",
868
+ profile: "reviewer",
869
+ objective: inspectorObjective(inspector, change),
870
+ onActivity
871
+ }));
872
+ }
873
+ function computeAutoReviewBudget(change) {
874
+ const n = change.files.length;
875
+ if (n <= 3) return { maxTurns: 20, timeoutMs: 3e5 };
876
+ if (n <= 10) return { maxTurns: 28, timeoutMs: 36e4 };
877
+ return { maxTurns: 36, timeoutMs: 48e4 };
878
+ }
879
+ function earlyConvergenceHint(maxTurns, timeoutMs) {
880
+ const timeoutS = Math.round(timeoutMs / 1e3);
881
+ const draftDeadline = Math.max(3, Math.floor(maxTurns * 0.5));
882
+ const finalDeadline = maxTurns - 1;
883
+ if (maxTurns <= 15) {
884
+ return [
885
+ `\u9884\u7B97\u7EA6\u675F(${maxTurns} \u8F6E/${timeoutS}s)\u2014\u2014\u8FD9\u662F\u5C0F\u6539\u52A8\u5BA1\u67E5,\u4E25\u7981\u6269\u6563\u63A2\u7D22:`,
886
+ `1) \u9996\u8F6E git diff / git show \u9501\u5B9A\u6539\u52A8,\u53EA\u8BFB\u53D8\u66F4\u6587\u4EF6;`,
887
+ `2) \u7B2C ${draftDeadline} \u8F6E\u524D\u5FC5\u987B\u4EA7\u51FA\u7ED3\u8BBA\u8349\u6848;`,
888
+ `3) \u7B2C ${finalDeadline} \u8F6E\u505C\u6B62\u4E00\u5207\u5DE5\u5177\u8C03\u7528,\u8F93\u51FA verdict JSON\u2014\u2014\u672A\u8986\u76D6\u9879\u663E\u5F0F\u6807\u6CE8,best-effort > \u65E0\u7ED3\u8BBA\u3002`
889
+ ].join("\n");
890
+ }
891
+ return [
892
+ `\u9884\u7B97\u7EA6\u675F(${maxTurns} \u8F6E/${timeoutS}s),\u6309\u6B64\u8282\u594F\u6536\u655B:`,
893
+ `1) \u9996\u8F6E\u5148 git diff/git show \u9501\u5B9A\u6539\u52A8\u533A\u95F4,\u518D\u51B3\u5B9A\u8BFB\u4EC0\u4E48;`,
894
+ `2) \u9996\u6B21\u9605\u8BFB\u5148\u7528 grep/repo_graph \u6216 read_file(focus="\u5BA1\u67E5\u91CD\u70B9")\uFF0C\u53EA\u628A\u9AD8\u76F8\u5173\u7247\u6BB5\u653E\u5165\u4E0A\u4E0B\u6587\uFF1B\u5DF2\u77E5\u884C\u53F7\u540E\u518D\u7528 offset+limit(limit\u2264200) \u7CBE\u8BFB\u3002\u7981\u6B62\u65E0\u7126\u70B9\u6574\u6587\u4EF6 read\uFF1B\u770B\u533A\u6BB5\u53EF\u7528 read_section;`,
895
+ `3) \u7B2C ${draftDeadline} \u8F6E\u524D\u4EA7\u51FA\u7ED3\u8BBA\u8349\u6848;`,
896
+ `4) \u7B2C ${finalDeadline} \u8F6E\u505C\u6B62\u4E00\u5207\u63A2\u7D22,\u8F93\u51FA verdict JSON\u2014\u2014\u672A\u8986\u76D6\u9879\u663E\u5F0F\u6807\u6CE8,best-effort \u7ED3\u8BBA\u4F18\u4E8E\u65E0\u7ED3\u8BBA\u3002`
897
+ ].join("\n");
898
+ }
899
+ function createCoordinatorReviewDeps(coordinator, options = {}) {
900
+ return {
901
+ spawnVerifier: async (change, _signal, onActivity) => {
902
+ const run = await coordinator.delegate(request({
903
+ change,
904
+ options,
905
+ kind: "verify",
906
+ profile: "adversarial_verifier",
907
+ objective: verifierObjective(change),
908
+ onActivity
909
+ }), options.abortSignal);
910
+ return verifierResult(run);
911
+ },
912
+ spawnPatcher: async (change, verifier, _signal, onActivity) => {
913
+ const run = await coordinator.delegate(request({
914
+ change,
915
+ options,
916
+ kind: "patch_proposal",
917
+ profile: "patcher",
918
+ objective: patcherObjective(change, verifier),
919
+ onActivity
920
+ }), options.abortSignal);
921
+ return patcherResult(run);
922
+ },
923
+ spawnSquadron: async (change, _signal, onActivity) => {
924
+ const requests = squadronRequests(change, options, onActivity);
925
+ const run = coordinator.delegateBatch ? await coordinator.delegateBatch(requests, "all_required", options.abortSignal) : await runSquadronSerially(coordinator, requests, options.abortSignal);
926
+ return { findings: mapSquadronFindings(run), infraFailures: mapSquadronInfraFailures(run) };
927
+ },
928
+ spawnWiringReviewer: async (change, _signal, onActivity) => {
929
+ const budget = computeAutoReviewBudget(change);
930
+ const wiring = INSPECTORS.find((i) => i.name === "\u63A5\u7EBF\u5BA1\u67E5");
931
+ const silence = INSPECTORS.find((i) => i.name === "\u9759\u9ED8\u5BA1\u67E5");
932
+ const requests = [wiring, silence].map((inspector) => ({
933
+ ...request({
934
+ change,
935
+ options,
936
+ kind: "review",
937
+ profile: "reviewer",
938
+ objective: [
939
+ inspectorObjective(inspector, change),
940
+ earlyConvergenceHint(budget.maxTurns, budget.timeoutMs)
941
+ ].join("\n"),
942
+ onActivity
943
+ }),
944
+ budget
945
+ }));
946
+ const run = coordinator.delegateBatch ? await coordinator.delegateBatch(requests, "all_required", options.abortSignal) : await runSquadronSerially(coordinator, requests, options.abortSignal);
947
+ return { findings: mapSquadronFindings(run), infraFailures: mapSquadronInfraFailures(run) };
948
+ }
949
+ };
950
+ }
951
+ async function runSquadronSerially(coordinator, requests, abortSignal) {
952
+ const results = [];
953
+ for (const req of requests) {
954
+ const run = await coordinator.delegate(req, abortSignal);
955
+ results.push(...run.results);
956
+ }
957
+ return {
958
+ status: "completed",
959
+ results,
960
+ packet: results.map((result) => result.summary).join("\n"),
961
+ aggregationPolicy: "all_required"
962
+ };
963
+ }
964
+
965
+ // src/agent/team-orchestrator.ts
966
+ init_esm_shims();
967
+
968
+ // src/agent/team-wave-feedback.ts
969
+ init_esm_shims();
970
+ var MAX_FEEDBACK_ENTRIES = 5;
971
+ var MAX_FEEDBACK_ENTRY_CHARS = 90;
972
+ var MAX_LEAKED_FILES = 3;
973
+ function taskIdOf(workOrderId) {
974
+ const i = workOrderId.lastIndexOf(":");
975
+ return i >= 0 ? workOrderId.slice(i + 1) : workOrderId;
976
+ }
977
+ function clip(text, max) {
978
+ const flat = text.replace(/\s+/g, " ").trim();
979
+ return flat.length <= max ? flat : `${flat.slice(0, max - 1)}\u2026`;
980
+ }
981
+ function reasonOf(result) {
982
+ if (result.failureReason) return result.failureReason;
983
+ const risk = result.risks?.[0];
984
+ if (typeof risk === "string" && risk.trim()) return risk;
985
+ if (result.summary?.trim()) return result.summary;
986
+ return "";
987
+ }
988
+ function buildPriorWaveFeedback(input) {
989
+ const out = [];
990
+ const failed = (input.priorResults ?? []).filter((r) => r.status !== "passed");
991
+ for (const r of failed) {
992
+ const reason = reasonOf(r);
993
+ const head = `\u4E0A\u4E00\u6CE2 ${taskIdOf(r.workOrderId)} ${r.status}`;
994
+ out.push(clip(reason ? `${head}\uFF1A${reason}` : head, MAX_FEEDBACK_ENTRY_CHARS));
995
+ }
996
+ const gateFailures = (input.waveGateFailures ?? []).filter((f) => f.trim());
997
+ if (gateFailures.length > 0) {
998
+ out.push(clip(`\u4E0A\u4E00\u6CE2\u95E8\u7981\u672A\u8FC7\uFF1A${gateFailures.join("\uFF1B")}`, MAX_FEEDBACK_ENTRY_CHARS));
999
+ }
1000
+ const leaks = (input.scopeLeaks ?? []).filter((f) => f.trim());
1001
+ if (leaks.length > 0) {
1002
+ const named = leaks.slice(0, MAX_LEAKED_FILES).join("\u3001");
1003
+ const more = leaks.length > MAX_LEAKED_FILES ? ` \u7B49 ${leaks.length} \u5904` : "";
1004
+ out.push(clip(`\u4E0A\u4E00\u6CE2\u6709\u8BA1\u5212\u5916\u6539\u52A8\uFF1A${named}${more}\u2014\u2014\u672C\u6CE2\u52FF\u6269\u5927\u8303\u56F4`, MAX_FEEDBACK_ENTRY_CHARS));
1005
+ }
1006
+ if (out.length <= MAX_FEEDBACK_ENTRIES) return out;
1007
+ const kept = out.slice(0, MAX_FEEDBACK_ENTRIES - 1);
1008
+ kept.push(`\uFF08\u53E6\u6709 ${out.length - kept.length} \u6761\u4E0A\u4E00\u6CE2\u56DE\u6267\u5DF2\u7701\u7565\uFF09`);
1009
+ return kept;
1010
+ }
1011
+
1012
+ // src/agent/team-scheduler-bandit.ts
1013
+ init_esm_shims();
1014
+ var CONTEXT_DIMENSION = 8;
1015
+ var SCHEDULER_ARMS = [
1016
+ "parallelism:1",
1017
+ "parallelism:2",
1018
+ "parallelism:3",
1019
+ "parallelism:4",
1020
+ "parallelism:5"
1021
+ ];
1022
+ function clampUnit(value) {
1023
+ if (!Number.isFinite(value)) return 0;
1024
+ return Math.min(1, Math.max(0, value));
1025
+ }
1026
+ function clampReward(value) {
1027
+ if (!Number.isFinite(value)) return 0;
1028
+ return Math.min(1, Math.max(-1, value));
1029
+ }
1030
+ function teamSchedulerArmForParallelism(parallelism) {
1031
+ const safe = Math.max(1, Math.min(5, Math.trunc(parallelism)));
1032
+ return `parallelism:${safe}`;
1033
+ }
1034
+ function parallelismForTeamSchedulerArm(arm) {
1035
+ return Number.parseInt(arm.split(":")[1] ?? "1", 10);
1036
+ }
1037
+ function normalizeTeamSchedulerContext(context) {
1038
+ return [
1039
+ clampUnit(context.taskCount),
1040
+ clampUnit(context.writeTaskCount),
1041
+ clampUnit(context.readTaskCount),
1042
+ clampUnit(context.dependencyDepth),
1043
+ clampUnit(context.crossModuleScore),
1044
+ clampUnit(context.highRiskRatio),
1045
+ clampReward(context.historicalReward),
1046
+ clampUnit(context.scopeLeakRate)
1047
+ ];
1048
+ }
1049
+ function computeTeamSchedulerReward(input) {
1050
+ return clampReward(
1051
+ clampReward(input.teamWaveReward) - 0.3 * clampUnit(input.conflictRate) - 0.3 * clampUnit(input.scopeLeakRate) - 0.6 * (input.falseGreen ? 1 : 0)
1052
+ );
1053
+ }
1054
+ function createTeamSchedulerBandit() {
1055
+ const bandit = new LinUCBBandit({ dimension: CONTEXT_DIMENSION, alpha: 1.2, minConfidence: 0.05 });
1056
+ for (const arm of SCHEDULER_ARMS) bandit.addArm(arm);
1057
+ return bandit;
1058
+ }
1059
+ function recommendTeamSchedulerArm(bandit, context) {
1060
+ const rec = bandit.recommend(normalizeTeamSchedulerContext(context));
1061
+ if (!rec) return { arm: "parallelism:1", score: 0, confidence: 0 };
1062
+ const arm = SCHEDULER_ARMS.includes(rec.armId) ? rec.armId : "parallelism:1";
1063
+ return { arm, score: rec.score, confidence: rec.confidence };
1064
+ }
1065
+ function emptyTeamSchedulerState() {
1066
+ return {
1067
+ totalSamples: 0,
1068
+ arms: Object.fromEntries(SCHEDULER_ARMS.map((arm) => [arm, { samples: 0, totalReward: 0, averageReward: 0 }]))
1069
+ };
1070
+ }
1071
+ function summarizeTeamSchedulerBandit(bandit) {
1072
+ const stats = bandit.getStats();
1073
+ const state = emptyTeamSchedulerState();
1074
+ for (const stat of stats) {
1075
+ if (!SCHEDULER_ARMS.includes(stat.id)) continue;
1076
+ const arm = stat.id;
1077
+ const totalReward = stat.avgReward * stat.pulls;
1078
+ state.arms[arm] = { samples: stat.pulls, totalReward, averageReward: stat.avgReward };
1079
+ state.totalSamples += stat.pulls;
1080
+ }
1081
+ return state;
1082
+ }
1083
+ function parsePersistedSchedulerReward(json) {
1084
+ try {
1085
+ const record = JSON.parse(json);
1086
+ if (!SCHEDULER_ARMS.includes(record.arm)) return null;
1087
+ if (typeof record.reward !== "number" || !Number.isFinite(record.reward)) return null;
1088
+ return { arm: record.arm, reward: clampReward(record.reward) };
1089
+ } catch {
1090
+ return null;
1091
+ }
1092
+ }
1093
+ function buildHistoricalTeamSchedulerState(store, limit = 200) {
1094
+ const state = emptyTeamSchedulerState();
1095
+ if (!store?.loadBanditStatesByPrefix) return state;
1096
+ const rows = store.loadBanditStatesByPrefix("team_scheduler_reward:", limit);
1097
+ for (const row of rows) {
1098
+ const parsed = parsePersistedSchedulerReward(row.json);
1099
+ if (!parsed) continue;
1100
+ const current = state.arms[parsed.arm];
1101
+ current.samples += 1;
1102
+ current.totalReward += parsed.reward;
1103
+ current.averageReward = current.totalReward / current.samples;
1104
+ state.totalSamples += 1;
1105
+ }
1106
+ return state;
1107
+ }
1108
+
1109
+ // src/agent/team-scheduler-gate.ts
1110
+ init_esm_shims();
1111
+ var MIN_TOTAL_SAMPLES = 30;
1112
+ var MIN_ARM_SAMPLES = 5;
1113
+ var REWARD_MARGIN = 0.05;
1114
+ var MAX_FALSE_GREEN_RATE = 0;
1115
+ var MIN_RULE_AGREEMENT = 0.8;
1116
+ function safeNumber(value) {
1117
+ return Number.isFinite(value) ? value : 0;
1118
+ }
1119
+ function makeDecision(input, gateOpen, applied, reason, evidenceWindow, vetoSignals = []) {
1120
+ return {
1121
+ gateOpen,
1122
+ applied,
1123
+ reason,
1124
+ evidenceWindow: {
1125
+ source: "team_scheduler_bandit",
1126
+ totalSamples: input.state.totalSamples,
1127
+ minTotalSamples: MIN_TOTAL_SAMPLES,
1128
+ candidateArm: input.candidateArm,
1129
+ candidateSamples: input.state.arms[input.candidateArm]?.samples ?? 0,
1130
+ minArmSamples: MIN_ARM_SAMPLES,
1131
+ ruleParallelism: Math.max(1, Math.min(5, Math.trunc(input.ruleParallelism))),
1132
+ featureFlagEnabled: input.featureFlagEnabled === true,
1133
+ ...evidenceWindow
1134
+ },
1135
+ vetoSignals
1136
+ };
1137
+ }
1138
+ function evaluateTeamSchedulerGate(input) {
1139
+ const candidate = input.state.arms[input.candidateArm];
1140
+ const candidateParallelism = parallelismForTeamSchedulerArm(input.candidateArm);
1141
+ const ruleParallelism = Math.max(1, Math.min(5, Math.trunc(input.ruleParallelism)));
1142
+ if (input.state.totalSamples < MIN_TOTAL_SAMPLES) {
1143
+ return makeDecision(input, false, false, `shadow: total samples ${input.state.totalSamples}/${MIN_TOTAL_SAMPLES}`, {}, ["insufficient_samples"]);
1144
+ }
1145
+ if (!candidate || candidate.samples < MIN_ARM_SAMPLES) {
1146
+ return makeDecision(input, false, false, `shadow: arm samples ${candidate?.samples ?? 0}/${MIN_ARM_SAMPLES}`, {}, ["insufficient_arm_samples"]);
1147
+ }
1148
+ const margin = safeNumber(candidate.averageReward) - safeNumber(input.ruleBaselineReward);
1149
+ if (margin < REWARD_MARGIN) {
1150
+ return makeDecision(input, false, false, `shadow: reward margin ${margin.toFixed(3)} < ${REWARD_MARGIN}`, { rewardMargin: margin, minRewardMargin: REWARD_MARGIN }, ["reward_margin"]);
1151
+ }
1152
+ if (safeNumber(input.recentFalseGreenRate) > MAX_FALSE_GREEN_RATE) {
1153
+ return makeDecision(input, false, false, "shadow: false-green observed", { recentFalseGreenRate: safeNumber(input.recentFalseGreenRate) }, ["false_green"]);
1154
+ }
1155
+ if (safeNumber(input.ruleAgreementRate) < MIN_RULE_AGREEMENT) {
1156
+ return makeDecision(input, false, false, `shadow: rule agreement ${input.ruleAgreementRate.toFixed(2)} < ${MIN_RULE_AGREEMENT}`, { ruleAgreementRate: safeNumber(input.ruleAgreementRate), minRuleAgreement: MIN_RULE_AGREEMENT }, ["rule_agreement"]);
1157
+ }
1158
+ if (!input.hardGateSafe || candidateParallelism > ruleParallelism) {
1159
+ return makeDecision(input, false, false, "shadow: hard gate blocks candidate", { candidateParallelism, hardGateSafe: input.hardGateSafe }, ["hard_safety_floor", ...candidateParallelism > ruleParallelism ? ["down_only"] : []]);
1160
+ }
1161
+ const gateOpen = true;
1162
+ if (!input.featureFlagEnabled) return makeDecision(input, gateOpen, false, "shadow: feature flag disabled", { rewardMargin: margin, candidateParallelism }, ["explicit_flag_closed"]);
1163
+ return makeDecision(input, gateOpen, true, `applied: ${input.candidateArm} within rule parallelism ${ruleParallelism}`, { rewardMargin: margin, candidateParallelism });
1164
+ }
1165
+ function applyTeamSchedulerInfluence(ruleParallelism, candidateArm, gate) {
1166
+ const safeRule = Math.max(1, Math.min(5, Math.trunc(ruleParallelism)));
1167
+ if (!gate.applied) return safeRule;
1168
+ return Math.max(1, Math.min(safeRule, parallelismForTeamSchedulerArm(candidateArm), 5));
1169
+ }
1170
+
1171
+ // src/agent/team-scheduler-shadow.ts
1172
+ init_esm_shims();
1173
+ function teamSchedulerShadowKind(event) {
1174
+ return `team_scheduler_shadow:${event.sessionId}:${event.waveId}:${event.timestamp}`;
1175
+ }
1176
+ function teamSchedulerRewardKind(event) {
1177
+ return `team_scheduler_reward:${event.sessionId}:${event.waveId}:${event.timestamp}`;
1178
+ }
1179
+ function buildTeamSchedulerShadowEvent(input) {
1180
+ const timestamp = input.timestamp ?? Date.now();
1181
+ const objectiveHash = hashTeamObjective(input.objective);
1182
+ return {
1183
+ schemaVersion: 1,
1184
+ sessionId: input.sessionId,
1185
+ objectiveHash,
1186
+ waveId: input.waveId,
1187
+ ruleParallelism: Math.max(1, Math.min(5, Math.trunc(input.ruleParallelism))),
1188
+ recommendedArm: input.recommendedArm,
1189
+ applied: input.applied,
1190
+ gateOpen: input.gateOpen,
1191
+ reason: input.reason,
1192
+ pendingRewardId: `team_scheduler_reward:${objectiveHash}:${input.sessionId}:${input.waveId}:${timestamp}`,
1193
+ timestamp
1194
+ };
1195
+ }
1196
+ function buildTeamSchedulerRewardEvent(input) {
1197
+ const reward = computeTeamSchedulerReward(input.rewardInput);
1198
+ return {
1199
+ schemaVersion: 1,
1200
+ sessionId: input.sessionId,
1201
+ objectiveHash: hashTeamObjective(input.objective),
1202
+ waveId: input.waveId,
1203
+ arm: input.arm,
1204
+ reward,
1205
+ components: {
1206
+ teamWaveReward: input.rewardInput.teamWaveReward,
1207
+ conflictRate: input.rewardInput.conflictRate,
1208
+ scopeLeakRate: input.rewardInput.scopeLeakRate,
1209
+ falseGreen: input.rewardInput.falseGreen,
1210
+ parallelism: parallelismForTeamSchedulerArm(input.arm)
1211
+ },
1212
+ timestamp: input.timestamp ?? Date.now()
1213
+ };
1214
+ }
1215
+ function persistTeamSchedulerShadow(store, event) {
1216
+ if (!store) return;
1217
+ try {
1218
+ store.saveBanditState(teamSchedulerShadowKind(event), JSON.stringify(event));
1219
+ } catch {
1220
+ }
1221
+ }
1222
+ function persistTeamSchedulerReward(store, event) {
1223
+ if (!store) return;
1224
+ try {
1225
+ store.saveBanditState(teamSchedulerRewardKind(event), JSON.stringify(event));
1226
+ } catch {
1227
+ }
1228
+ }
1229
+
1230
+ // src/agent/team-perspectives.ts
1231
+ init_esm_shims();
1232
+
1233
+ // src/agent/expert-router.ts
1234
+ init_esm_shims();
1235
+ var DOMAIN_MERGE_ROLE = {
1236
+ tianquan: "base",
1237
+ tianshu: "base",
1238
+ tianfu: "constraint",
1239
+ tianliang: "constraint",
1240
+ tianji: "challenger",
1241
+ tianxuan: "challenger",
1242
+ pojun: "challenger",
1243
+ wenqu: "specialist",
1244
+ fu: "specialist"
1245
+ };
1246
+ var DEFAULT_BASE = "tianquan";
1247
+ var DEFAULT_CONSTRAINT = "tianfu";
1248
+ var DEFAULT_CHALLENGER = "tianxuan";
1249
+ var MAX_COUNCIL_EXPERTS = 5;
1250
+ var DEFAULT_COUNCIL_EXPERTS = 3;
1251
+ function mergeRoleFor(domainId) {
1252
+ return DOMAIN_MERGE_ROLE[domainId] ?? "specialist";
1253
+ }
1254
+ function rankDomains(taskDescription) {
1255
+ const lower = taskDescription.toLowerCase();
1256
+ const scored = [];
1257
+ for (const domain of starDomainRegistry.list()) {
1258
+ let score = 0;
1259
+ for (const keyword of domain.keywords) {
1260
+ if (lower.includes(keyword.toLowerCase())) score++;
1261
+ }
1262
+ if (score > 0) scored.push({ id: domain.id, score, role: mergeRoleFor(domain.id) });
1263
+ }
1264
+ scored.sort((a, b) => b.score - a.score || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
1265
+ return scored;
1266
+ }
1267
+ function selectExpertSet(taskDescription, opts) {
1268
+ const budget = clampBudget(opts?.maxExperts);
1269
+ const ranked = rankDomains(taskDescription);
1270
+ const known = new Set(starDomainRegistry.getDomainIds());
1271
+ const pickTop = (role) => ranked.find((d) => d.role === role)?.id;
1272
+ const selected = [];
1273
+ const add = (id) => {
1274
+ if (!id || selected.length >= budget) return;
1275
+ if (!known.has(id)) return;
1276
+ if (!selected.includes(id)) selected.push(id);
1277
+ };
1278
+ add(pickTop("base") ?? DEFAULT_BASE);
1279
+ add(pickTop("constraint") ?? DEFAULT_CONSTRAINT);
1280
+ add(pickTop("challenger") ?? DEFAULT_CHALLENGER);
1281
+ for (const d of ranked) {
1282
+ if (d.role === "specialist") add(d.id);
1283
+ }
1284
+ for (const d of ranked) add(d.id);
1285
+ if (selected.length === 0) selected.push(DEFAULT_BASE);
1286
+ return selected.slice(0, budget);
1287
+ }
1288
+ function clampBudget(maxExperts) {
1289
+ const n = maxExperts ?? DEFAULT_COUNCIL_EXPERTS;
1290
+ if (!Number.isFinite(n)) return DEFAULT_COUNCIL_EXPERTS;
1291
+ return Math.max(1, Math.min(MAX_COUNCIL_EXPERTS, Math.floor(n)));
1292
+ }
1293
+
1294
+ // src/agent/team-perspectives.ts
1295
+ function dependencyKey(dep) {
1296
+ return typeof dep === "string" ? `plain:${dep}` : `edge:${dep.dependsOn}:${dep.onFailure ?? ""}:${dep.alternateOrderId ?? ""}`;
1297
+ }
1298
+ function dedupeDependencyRefs(refs) {
1299
+ const seen = /* @__PURE__ */ new Set();
1300
+ const out = [];
1301
+ for (const r of refs) {
1302
+ const key2 = dependencyKey(r);
1303
+ if (seen.has(key2)) continue;
1304
+ seen.add(key2);
1305
+ out.push(typeof r === "string" ? r : { ...r });
1306
+ }
1307
+ return out;
1308
+ }
1309
+ function normalizePerspective(perspective, raw) {
1310
+ return {
1311
+ perspective,
1312
+ summary: raw.summary ?? `${perspective} perspective plan`,
1313
+ tasks: raw.tasks ?? [],
1314
+ dependencyNotes: raw.dependencyNotes ?? [],
1315
+ risks: raw.risks ?? [],
1316
+ verification: raw.verification ?? [],
1317
+ blockers: raw.blockers ?? [],
1318
+ alternatives: raw.alternatives ?? []
1319
+ };
1320
+ }
1321
+ function domainName(perspective) {
1322
+ return starDomainRegistry.get(perspective)?.name ?? perspective;
1323
+ }
1324
+ function mergePerspectivesByRole(perspectives) {
1325
+ const base = perspectives.find((p) => mergeRoleFor(p.perspective) === "base") ?? perspectives[0];
1326
+ if (!base) {
1327
+ return { tasks: [], dependencyNotes: [], risks: [], verification: [], accepted: [], rejected: [], deferred: [], augmented: [], conflicts: [] };
1328
+ }
1329
+ const others = perspectives.filter((p) => p !== base);
1330
+ const roleOf = (p) => mergeRoleFor(p.perspective);
1331
+ const constraints = others.filter((p) => roleOf(p) === "constraint");
1332
+ const challengers = others.filter((p) => roleOf(p) === "challenger");
1333
+ const specialists = others.filter((p) => roleOf(p) === "specialist" || roleOf(p) === "base");
1334
+ const tasks = base.tasks.map((t) => ({
1335
+ ...t,
1336
+ files: [...t.files],
1337
+ touchSet: [...t.touchSet],
1338
+ dependsOn: dedupeDependencyRefs(t.dependsOn),
1339
+ verification: [...t.verification]
1340
+ }));
1341
+ const taskIndex = new Map(tasks.map((t) => [t.id, t]));
1342
+ const accepted = [];
1343
+ const rejected = [];
1344
+ const deferred = [];
1345
+ const augmented = [];
1346
+ const conflicts = [];
1347
+ const verification = base.verification.map((v) => ({ taskId: v.taskId, command: v.command, expected: v.expected }));
1348
+ for (const c of constraints) {
1349
+ for (const risk of c.risks) {
1350
+ if (risk.taskId && taskIndex.has(risk.taskId)) {
1351
+ const task = taskIndex.get(risk.taskId);
1352
+ if (riskSeverityRank(risk.severity) > riskSeverityRank(task.riskTier)) {
1353
+ task.riskTier = risk.severity;
1354
+ accepted.push({ source: c.perspective, title: `Risk upgrade: ${risk.taskId} \u2192 ${risk.severity}`, reason: risk.claim });
1355
+ }
1356
+ }
1357
+ }
1358
+ for (const v of c.verification) {
1359
+ if (!verification.some((ev) => ev.command === v.command)) {
1360
+ verification.push({ taskId: v.taskId, command: v.command, expected: v.expected });
1361
+ accepted.push({ source: c.perspective, title: `Verification: ${v.command}`, reason: `${domainName(c.perspective)} added verification gate` });
1362
+ }
1363
+ }
1364
+ }
1365
+ const baseTaskIds = new Set(base.tasks.map((t) => t.id));
1366
+ for (const ch of challengers) {
1367
+ for (const c of constraints) {
1368
+ for (const cRisk of c.risks) {
1369
+ const riskTaskId = cRisk.taskId?.toLowerCase();
1370
+ const alt = riskTaskId ? ch.alternatives.find((a) => a.title.toLowerCase().includes(riskTaskId)) : void 0;
1371
+ if (alt && alt.recommendation === "accept") {
1372
+ conflicts.push({
1373
+ description: `Risk vs alternative conflict on ${cRisk.taskId ?? "unknown"}`,
1374
+ tianquan: "no position",
1375
+ tianfu: cRisk.claim,
1376
+ tianxuan: alt.tradeoff
1377
+ });
1378
+ }
1379
+ }
1380
+ }
1381
+ for (const chTask of ch.tasks) {
1382
+ const baseTask = base.tasks.find((t) => t.id === chTask.id);
1383
+ if (baseTask && !sameDependencySet(chTask.dependsOn.map(dependencyId), baseTask.dependsOn.map(dependencyId))) {
1384
+ if (chTask.dependsOn.length > 0 || baseTask.dependsOn.length > 0) {
1385
+ conflicts.push({
1386
+ description: `Dependency conflict on ${chTask.id}`,
1387
+ tianquan: `depends: [${baseTask.dependsOn.map(dependencyId).join(", ")}]`,
1388
+ tianfu: "(no position)",
1389
+ tianxuan: `depends: [${chTask.dependsOn.map(dependencyId).join(", ")}]`
1390
+ });
1391
+ }
1392
+ }
1393
+ }
1394
+ for (const alt of ch.alternatives) {
1395
+ const entry = { source: ch.perspective, title: alt.title, reason: alt.tradeoff };
1396
+ if (alt.recommendation === "accept") accepted.push(entry);
1397
+ else if (alt.recommendation === "defer") deferred.push(entry);
1398
+ else rejected.push(entry);
1399
+ }
1400
+ for (const blocker of ch.blockers) {
1401
+ accepted.push({ source: ch.perspective, title: `Blind spot: ${blocker.slice(0, 80)}`, reason: `${domainName(ch.perspective)} identified potential blocker` });
1402
+ }
1403
+ }
1404
+ for (const sp of specialists) {
1405
+ for (const alt of sp.alternatives) {
1406
+ deferred.push({ source: sp.perspective, title: alt.title, reason: alt.tradeoff });
1407
+ }
1408
+ for (const blocker of sp.blockers) {
1409
+ deferred.push({ source: sp.perspective, title: `Advisory: ${blocker.slice(0, 80)}`, reason: `${domainName(sp.perspective)} domain note` });
1410
+ }
1411
+ }
1412
+ const existingIds = new Set(tasks.map((t) => t.id));
1413
+ for (const src of [...challengers, ...specialists]) {
1414
+ const extras = src.tasks.filter((t) => t.id && !existingIds.has(t.id) && !baseTaskIds.has(t.id));
1415
+ if (extras.length === 0) continue;
1416
+ const consumed = /* @__PURE__ */ new Set();
1417
+ for (const b of [...tasks]) {
1418
+ if (!existingIds.has(b.id)) continue;
1419
+ const bFiles = filesOfTask(b);
1420
+ if (bFiles.length < 2) continue;
1421
+ const bSet = new Set(bFiles);
1422
+ const parts = extras.filter((e) => {
1423
+ if (consumed.has(e)) return false;
1424
+ const ef = filesOfTask(e);
1425
+ return ef.length > 0 && ef.every((f) => bSet.has(f));
1426
+ });
1427
+ if (parts.length < 2 || !pairwiseDisjoint(parts.map(filesOfTask))) continue;
1428
+ const shards = parts.map((p) => adoptShard(p, existingIds));
1429
+ for (const s of shards) {
1430
+ s.dependsOn = dedupeDependencyRefs([...s.dependsOn, ...b.dependsOn]).filter((d) => dependencyId(d) !== b.id && dependencyId(d) !== s.id);
1431
+ existingIds.add(s.id);
1432
+ }
1433
+ const bi = tasks.findIndex((t) => t.id === b.id);
1434
+ tasks.splice(bi, 1, ...shards);
1435
+ taskIndex.delete(b.id);
1436
+ existingIds.delete(b.id);
1437
+ for (const s of shards) taskIndex.set(s.id, s);
1438
+ const replacementIds = shards.map((s) => s.id);
1439
+ for (const t of tasks) {
1440
+ if (!t.dependsOn.some((d) => dependencyId(d) === b.id)) continue;
1441
+ const kept = t.dependsOn.filter((d) => dependencyId(d) !== b.id);
1442
+ const reconnected = [];
1443
+ for (const d of t.dependsOn) {
1444
+ if (dependencyId(d) !== b.id) continue;
1445
+ for (const id of replacementIds) {
1446
+ if (typeof d === "string") reconnected.push(id);
1447
+ else reconnected.push({
1448
+ dependsOn: id,
1449
+ ...d.onFailure ? { onFailure: d.onFailure } : {},
1450
+ ...d.alternateOrderId !== void 0 ? { alternateOrderId: d.alternateOrderId } : {}
1451
+ });
1452
+ }
1453
+ }
1454
+ t.dependsOn = dedupeDependencyRefs([...kept, ...reconnected]);
1455
+ }
1456
+ for (const p of parts) consumed.add(p);
1457
+ augmented.push({ source: src.perspective, title: `Monolith-split: ${b.id} \u2192 [${replacementIds.join(", ")}]`, reason: `${domainName(src.perspective)} cleanly partitioned a coarse base shard into parallel orthogonal shards` });
1458
+ }
1459
+ for (const e of extras) {
1460
+ if (consumed.has(e)) continue;
1461
+ const ef = filesOfTask(e);
1462
+ if (ef.length === 0) {
1463
+ deferred.push({ source: src.perspective, title: `Extra task: ${e.id}`, reason: "No files declared; cannot verify orthogonality \u2014 deferred for manual review" });
1464
+ continue;
1465
+ }
1466
+ if (tasks.every((t) => fileSetsDisjoint(ef, filesOfTask(t)))) {
1467
+ const adopted = adoptShard(e, existingIds);
1468
+ tasks.push(adopted);
1469
+ taskIndex.set(adopted.id, adopted);
1470
+ existingIds.add(adopted.id);
1471
+ augmented.push({ source: src.perspective, title: `Gap-fill shard: ${adopted.id}`, reason: `${domainName(src.perspective)} orthogonal shard touches only disjoint files; folded into the execution graph for parallelism` });
1472
+ } else {
1473
+ deferred.push({ source: src.perspective, title: `Extra task: ${e.id}`, reason: "Overlaps base files without a clean split; deferred to avoid double-write" });
1474
+ }
1475
+ }
1476
+ }
1477
+ const augmentedGraph = {
1478
+ mission: base.summary,
1479
+ nodes: tasks.map((t) => ({ id: t.id, title: t.title, objective: t.objective, profile: t.profile, kind: t.kind, files: t.files, dependsOn: t.dependsOn.map(dependencyId), riskTier: t.riskTier })),
1480
+ createdAt: 0
1481
+ };
1482
+ if (!validateTaskGraph(augmentedGraph).valid) {
1483
+ const liveIds = new Set(tasks.map((t) => t.id));
1484
+ for (const t of tasks) t.dependsOn = t.dependsOn.filter((d) => liveIds.has(dependencyId(d)));
1485
+ }
1486
+ const risks = base.risks.map((r) => ({ taskId: r.taskId, severity: r.severity, claim: r.claim, mitigation: r.mitigation }));
1487
+ for (const p of [...constraints, ...specialists]) {
1488
+ for (const r of p.risks) {
1489
+ if (!risks.some((er) => er.taskId === r.taskId && (er.claim === r.claim || er.claim === `[${domainName(p.perspective)}] ${r.claim}`))) {
1490
+ risks.push({ taskId: r.taskId, severity: r.severity, claim: `[${domainName(p.perspective)}] ${r.claim}`, mitigation: r.mitigation });
1491
+ }
1492
+ }
1493
+ }
1494
+ const dependencyNotes = [...base.dependencyNotes];
1495
+ for (const p of others) {
1496
+ for (const d of p.dependencyNotes) {
1497
+ if (!dependencyNotes.some((td) => td.from === d.from && td.to === d.to)) dependencyNotes.push(d);
1498
+ }
1499
+ }
1500
+ return { tasks, dependencyNotes, risks, verification, accepted, rejected, deferred, augmented, conflicts };
1501
+ }
1502
+ function filesOfTask(t) {
1503
+ return t.touchSet && t.touchSet.length > 0 ? t.touchSet : t.files ?? [];
1504
+ }
1505
+ function fileSetsDisjoint(a, b) {
1506
+ if (a.length === 0 || b.length === 0) return false;
1507
+ const setB = new Set(b);
1508
+ return !a.some((f) => setB.has(f));
1509
+ }
1510
+ function pairwiseDisjoint(groups) {
1511
+ for (let i = 0; i < groups.length; i++) {
1512
+ for (let j = i + 1; j < groups.length; j++) {
1513
+ if (!fileSetsDisjoint(groups[i], groups[j])) return false;
1514
+ }
1515
+ }
1516
+ return true;
1517
+ }
1518
+ function adoptShard(raw, existingIds) {
1519
+ const files2 = [...raw.files ?? []];
1520
+ const touchSet = raw.touchSet && raw.touchSet.length > 0 ? [...raw.touchSet] : [...files2];
1521
+ const baseId = raw.id || "shard";
1522
+ let id = baseId;
1523
+ let suffix = 2;
1524
+ while (existingIds.has(id)) id = `${baseId}__aug${suffix++}`;
1525
+ return {
1526
+ id,
1527
+ title: raw.title ?? id,
1528
+ objective: raw.objective ?? "",
1529
+ files: files2,
1530
+ profile: raw.profile ?? "patcher",
1531
+ kind: raw.kind ?? "patch_proposal",
1532
+ verification: [...raw.verification ?? []],
1533
+ dependsOn: [...raw.dependsOn ?? []],
1534
+ riskTier: raw.riskTier ?? "medium",
1535
+ touchSet
1536
+ };
1537
+ }
1538
+ function foldVerificationIntoTasks(tasks, verification) {
1539
+ if (verification.length === 0) return tasks;
1540
+ const gatesByTask = /* @__PURE__ */ new Map();
1541
+ for (const gate of verification) {
1542
+ if (!gate.taskId) continue;
1543
+ const command = gate.command.trim();
1544
+ if (!command) continue;
1545
+ const arr = gatesByTask.get(gate.taskId) ?? [];
1546
+ arr.push(command);
1547
+ gatesByTask.set(gate.taskId, arr);
1548
+ }
1549
+ if (gatesByTask.size === 0) return tasks;
1550
+ return tasks.map((task) => {
1551
+ const extra = gatesByTask.get(task.id);
1552
+ if (!extra || extra.length === 0) return task;
1553
+ const merged = [.../* @__PURE__ */ new Set([...task.verification, ...extra])];
1554
+ return { ...task, verification: merged };
1555
+ });
1556
+ }
1557
+ function riskSeverityRank(severity) {
1558
+ switch (severity) {
1559
+ case "low":
1560
+ return 0;
1561
+ case "medium":
1562
+ return 1;
1563
+ case "high":
1564
+ return 2;
1565
+ }
1566
+ }
1567
+ function sameDependencySet(a, b) {
1568
+ if (a.length !== b.length) return false;
1569
+ const setB = new Set(b);
1570
+ return a.every((dep) => setB.has(dep));
1571
+ }
1572
+ var ROLE_BRIEFS = {
1573
+ base: "\u804C\u8D23\uFF1A\u628A\u4EFB\u52A1\u6A2A\u5411\u5207\u6210\u6B63\u4EA4\u81EA\u5305\u542B\u5206\u7247\uFF0C\u4EA7\u51FA\u4EFB\u52A1\u4E3B\u56FE\u3002\u6BCF\u7247\u662F\u4E00\u4E2A\u5B8C\u6574\u3001\u72EC\u7ACB\u7684\u4EA4\u4ED8\u5355\u5143\uFF0C\u7531\u4E00\u4E2A\u80FD\u529B\u5F3A\u7684 flash \u7AEF\u5230\u7AEF\u72EC\u5360\uFF08\u5B9E\u73B0 + \u81EA\u8DD1 tsc/lint/\u76F8\u5173\u6D4B\u8BD5\u81F3\u5168\u7EFF\uFF09\u3002\u6309\u6A21\u5757/\u5173\u6CE8\u70B9\u8FB9\u754C\u5207\uFF0C\u5206\u7247\u95F4\u6587\u4EF6\u5C3D\u91CF\u4E24\u4E24\u4E0D\u76F8\u4EA4\u4EE5\u4FBF\u5E76\u884C\uFF1B\u53EA\u6709\u771F\u6709\u5148\u540E\u4F9D\u8D56\u65F6\u624D\u6807 dependsOn\u3002\u7981\u6B62\u6309\u5DE5\u5E8F\u7AD6\u5207\uFF08\u4E0D\u8981\u628A explore/patch/import/test/lint/type/verify \u62C6\u6210\u72EC\u7ACB\u89D2\u8272\u4EFB\u52A1\uFF09\u3002\u5B81\u53EF\u51E0\u4E2A\u5206\u91CF\u8DB3\u7684\u5206\u7247\uFF0C\u4E0D\u8981\u4E00\u5806\u5DE5\u5E8F\u788E\u7247\u3002",
1574
+ constraint: "\u804C\u8D23\uFF1A\u805A\u7126\u8DE8\u5206\u7247\u7684\u96C6\u6210\u9A8C\u8BC1\u95E8\u7981\u4E0E\u4E32\u884C\u7EA6\u675F\uFF08\u6BCF\u7247\u5DF2\u81EA\u9A8C\uFF0C\u4F60\u8865\u7684\u662F\u5206\u7247\u4E4B\u95F4\u7684\uFF09\u3002\u6307\u51FA\u54EA\u4E9B\u5206\u7247\u56E0\u5171\u4EAB\u6587\u4EF6/\u63A5\u53E3\u5FC5\u987B\u4E32\u884C\u5E76\u6807 dependsOn\uFF1B\u8BC4\u4F30\u98CE\u9669\u3001\u56DE\u5F52\u6D4B\u8BD5\uFF1B\u9047\u6B67\u4E49 fail-closed\u3002\u4E0D\u8981\u91CD\u65B0\u7AD6\u5207\u522B\u4EBA\u7684\u5206\u7247\u3002",
1575
+ challenger: "\u804C\u8D23\uFF1A\u5B9A\u5411\u53CD\u8BC1\u3001\u76F2\u533A\u53D1\u73B0\u3001\u8D28\u7591\u524D\u63D0\uFF1B\u5E76\u4E14\u2014\u2014\u5F53 base \u628A\u67D0\u4E2A\u5206\u7247\u62C6\u5F97\u8FC7\u7C97\uFF08\u4E00\u4E2A\u5206\u7247\u585E\u4E86\u591A\u4E2A\u672C\u53EF\u5E76\u884C\u7684\u6B63\u4EA4\u6A21\u5757\uFF09\u65F6\uFF0C\u63D0\u51FA\u66F4\u7EC6\u7684\u6B63\u4EA4\u5206\u7247\u66FF\u4EE3\uFF0C\u6BCF\u7247\u6807\u660E files\uFF08\u53D6\u81EA\u771F\u5B9E\u4EE3\u7801\u800C\u975E\u731C\u6D4B\uFF09\uFF0C\u8FD9\u4E9B\u5206\u7247\u53EF\u88AB\u91C7\u7EB3\u8FDB\u6267\u884C\u56FE\u3002",
1576
+ specialist: "\u804C\u8D23\uFF1A\u4ECE\u4F60\u7684\u4E13\u4E1A\u9886\u57DF\u89C6\u89D2\u7ED9\u51FA\u5EFA\u8BAE\u4E0E\u7EA6\u675F\uFF08\u9ED8\u8BA4\u8FDB\u5165 advisory\uFF09\u3002"
1577
+ };
1578
+ function perspectiveBrief(perspective) {
1579
+ const role = mergeRoleFor(perspective);
1580
+ const domain = starDomainRegistry.get(perspective);
1581
+ const name = domain?.name ?? perspective;
1582
+ const personaLine = domain?.volatileBlock.split("\n").map((l) => l.trim()).find((l) => l.length > 0);
1583
+ const head = `\u4F60\u662F${name} planner\u3002${ROLE_BRIEFS[role]}`;
1584
+ return personaLine ? `${head}
1585
+ \u8BA4\u77E5\u573A\uFF1A${personaLine}` : head;
1586
+ }
1587
+ function buildPlannerObjective(perspective, mission) {
1588
+ return [
1589
+ perspectiveBrief(perspective),
1590
+ "",
1591
+ `Mission: ${mission}`,
1592
+ "",
1593
+ "Read the relevant code, then return a JSON WorkerResult whose `artifacts` contains ONE entry:",
1594
+ '{ "kind": "note", "title": "perspective-plan", "content": "<a JSON string of your TeamPerspectivePlan>" }',
1595
+ "",
1596
+ "TeamPerspectivePlan = { perspective, summary, tasks, dependencyNotes, risks, verification, blockers, alternatives }.",
1597
+ "Each task = { id, title, objective, files, profile, kind, verification, dependsOn, riskTier, touchSet }.",
1598
+ '\u5206\u7247\u5951\u7EA6\uFF1A\u6BCF\u4E2A task \u662F\u4E00\u4E2A\u6A2A\u5411\u6B63\u4EA4\u3001\u81EA\u5305\u542B\u7684\u4EA4\u4ED8\u5206\u7247 \u2014\u2014 \u4E00\u4E2A flash \u7AEF\u5230\u7AEF\u505A\u5B8C\uFF08\u5B9E\u73B0 + \u81EA\u8DD1 tsc/lint/\u76F8\u5173\u6D4B\u8BD5\u81F3\u5168\u7EFF\uFF09\uFF0Cprofile \u7528 "patcher"\u3001kind \u7528 "patch_proposal"\u3002\u5206\u7247\u95F4 files \u5C3D\u91CF\u4E24\u4E24\u4E0D\u76F8\u4EA4\u4EE5\u4FBF\u5E76\u884C\uFF1B\u4E24\u7247\u5FC5\u987B\u6539\u540C\u4E00\u6587\u4EF6\u65F6\u7528 dependsOn \u6392\u5E8F\uFF0C\u4E0D\u8981\u5E76\u53D1\u62A2\u5199\u3002\u7981\u6B62\u6309\u5DE5\u5E8F\u7AD6\u5207\u6210 explore/lint/type/import/test \u7B49\u72EC\u7ACB\u89D2\u8272\u4EFB\u52A1\u3002files \u586B\u8BE5\u5206\u7247\u771F\u6B63\u4F1A\u6539\u7684\u771F\u5B9E\u8DEF\u5F84\uFF08\u6765\u81EA\u4EE3\u7801\u67E5\u8BC1\uFF0C\u4E0D\u8981\u731C\uFF09\u3002',
1599
+ `Set perspective to "${perspective}".`
1600
+ ].join("\n");
1601
+ }
1602
+ function parsePerspectiveResult(perspective, result) {
1603
+ const artifact = result.artifacts.find((a) => a.title === "perspective-plan");
1604
+ if (artifact) {
1605
+ try {
1606
+ for (const candidate of extractJsonCandidates(artifact.content)) {
1607
+ try {
1608
+ const raw = JSON.parse(candidate);
1609
+ return normalizePerspective(perspective, raw);
1610
+ } catch {
1611
+ }
1612
+ }
1613
+ } catch {
1614
+ }
1615
+ }
1616
+ return normalizePerspective(perspective, { summary: result.summary, blockers: result.risks });
1617
+ }
1618
+
1619
+ // src/agent/team-plan-cache.ts
1620
+ init_esm_shims();
1621
+ import { createHash as createHash2 } from "crypto";
1622
+ var TEAM_PLAN_CACHE_PREFIX = "team_plan_cache:";
1623
+ var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
1624
+ var SIMILARITY_THRESHOLD = 0.6;
1625
+ var SCAN_LIMIT = 100;
1626
+ function hashPlanObjective(objective) {
1627
+ return createHash2("sha256").update(objective.trim().toLowerCase()).digest("hex").slice(0, 16);
1628
+ }
1629
+ function teamPlanCacheKind(objectiveHash) {
1630
+ return `${TEAM_PLAN_CACHE_PREFIX}${objectiveHash}`;
1631
+ }
1632
+ function extractPlanKeywords(text) {
1633
+ return text.toLowerCase().replace(/[^a-z0-9_\-./\u4e00-\u9fff]/gu, " ").split(/\s+/).filter((w) => w.length > 1 && w.length < 40).filter((w, i, arr) => arr.indexOf(w) === i).slice(0, 16);
1634
+ }
1635
+ function isValidTask(task) {
1636
+ if (!task || typeof task !== "object") return false;
1637
+ const t = task;
1638
+ return typeof t.id === "string" && t.id.length > 0 && typeof t.objective === "string" && t.objective.length > 0 && typeof t.profile === "string" && typeof t.kind === "string" && Array.isArray(t.files) && Array.isArray(t.dependsOn) && (t.riskTier === "low" || t.riskTier === "medium" || t.riskTier === "high");
1639
+ }
1640
+ function parseSkeleton(json) {
1641
+ try {
1642
+ const parsed = JSON.parse(json);
1643
+ if (parsed?.schemaVersion !== 1) return null;
1644
+ if (typeof parsed.objectiveHash !== "string" || !Array.isArray(parsed.keywords)) return null;
1645
+ if (parsed.mode !== "standard" && parsed.mode !== "max") return null;
1646
+ if (!Array.isArray(parsed.tasks) || parsed.tasks.length === 0) return null;
1647
+ if (!parsed.tasks.every(isValidTask)) return null;
1648
+ if (typeof parsed.createdAt !== "number") return null;
1649
+ return parsed;
1650
+ } catch {
1651
+ return null;
1652
+ }
1653
+ }
1654
+ function saveTeamPlanSkeleton(store, input) {
1655
+ if (!store?.saveBanditState || input.tasks.length === 0) return;
1656
+ const skeleton = {
1657
+ schemaVersion: 1,
1658
+ objectiveHash: hashPlanObjective(input.objective),
1659
+ keywords: extractPlanKeywords(input.objective),
1660
+ mode: input.mode,
1661
+ tasks: input.tasks,
1662
+ createdAt: input.timestamp ?? Date.now()
1663
+ };
1664
+ try {
1665
+ store.saveBanditState(teamPlanCacheKind(skeleton.objectiveHash), JSON.stringify(skeleton));
1666
+ } catch {
1667
+ }
1668
+ }
1669
+ function loadTeamPlanSkeleton(store, objective, mode, options = {}) {
1670
+ if (!store?.loadBanditStatesByPrefix) return null;
1671
+ const maxAgeMs = options.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
1672
+ const now = options.now ?? Date.now();
1673
+ const fresh = (s) => now - s.createdAt <= maxAgeMs && s.mode === mode;
1674
+ try {
1675
+ const hash = hashPlanObjective(objective);
1676
+ for (const row of store.loadBanditStatesByPrefix(teamPlanCacheKind(hash), 1)) {
1677
+ const skeleton = parseSkeleton(row.json);
1678
+ if (skeleton && fresh(skeleton)) return skeleton;
1679
+ }
1680
+ const keywords = extractPlanKeywords(objective);
1681
+ if (keywords.length === 0) return null;
1682
+ let best = null;
1683
+ let bestScore = 0;
1684
+ for (const row of store.loadBanditStatesByPrefix(TEAM_PLAN_CACHE_PREFIX, SCAN_LIMIT)) {
1685
+ const skeleton = parseSkeleton(row.json);
1686
+ if (!skeleton || !fresh(skeleton)) continue;
1687
+ const overlap = keywords.filter((k) => skeleton.keywords.includes(k)).length;
1688
+ const score = overlap / Math.max(keywords.length, skeleton.keywords.length);
1689
+ if (score >= SIMILARITY_THRESHOLD && score > bestScore) {
1690
+ bestScore = score;
1691
+ best = skeleton;
1692
+ }
1693
+ }
1694
+ return best;
1695
+ } catch {
1696
+ return null;
1697
+ }
1698
+ }
1699
+
1700
+ // src/agent/team-orchestrator.ts
1701
+ function isFileScopedPatcher(task) {
1702
+ return task.profile === "patcher" && task.files.length > 0;
1703
+ }
1704
+ function buildExecutionObjective(task) {
1705
+ if (task.profile !== "patcher") return task.objective;
1706
+ return `\u4F60\u662F\u5929\u6881\u6267\u884C\u8005\u3002\u53EA\u6267\u884C\u672C task\uFF0C\u4E0D\u6269\u5C55\u8303\u56F4\uFF0C\u4E0D\u91CD\u5199\u8BA1\u5212\u3002
1707
+
1708
+ ${task.objective}`;
1709
+ }
1710
+ function taskAuthority(task) {
1711
+ if (task.profile === "patcher") return "tianliang";
1712
+ if (task.profile === "reviewer" || task.profile === "adversarial_verifier") return "tianquan";
1713
+ const derived = deriveAuthority(task.objective);
1714
+ debugLog(`[team-authority] ${derived.authority} \u2014 ${derived.reasons[0] ?? "n/a"}`);
1715
+ return derived.authority;
1716
+ }
1717
+ function selectDispatchableTeamTasks(tasks, maxParallel = 3) {
1718
+ const selected = [];
1719
+ const blocked = [];
1720
+ const selectedPatchers = [];
1721
+ for (const task of tasks) {
1722
+ if (selected.length >= maxParallel) {
1723
+ blocked.push(`${task.id}: deferred after maxParallel=${maxParallel}`);
1724
+ continue;
1725
+ }
1726
+ if (task.profile === "patcher" && task.files.length === 0) {
1727
+ blocked.push(`${task.id}: patcher task has no file scope`);
1728
+ continue;
1729
+ }
1730
+ if (isFileScopedPatcher(task)) {
1731
+ const conflict = selectedPatchers.find((prev) => hasOverlappingFiles(prev, task));
1732
+ if (conflict) {
1733
+ blocked.push(`${task.id}: overlapping patcher file scope with ${conflict.id}; serialize later`);
1734
+ continue;
1735
+ }
1736
+ selectedPatchers.push(task);
1737
+ }
1738
+ selected.push(task);
1739
+ }
1740
+ return { selected, blocked };
1741
+ }
1742
+ function teamTasksToDelegationRequests(tasks, parentTurnId = "team") {
1743
+ return tasks.map((task, index) => {
1744
+ const stableId = `team:${task.id || index}`;
1745
+ let deps;
1746
+ if (task.dependsOn && task.dependsOn.length > 0) {
1747
+ deps = task.dependsOn.map((d) => mapTeamDependency(d));
1748
+ }
1749
+ return {
1750
+ parentTurnId: `${parentTurnId}:${stableId}`,
1751
+ objective: buildExecutionObjective(task),
1752
+ kind: task.kind,
1753
+ profile: task.profile,
1754
+ scope: { files: task.files },
1755
+ // 预算发准(2026-08-18):写工按目标文件数定价,替代 flat 48 轮/600s——
1756
+ // 读工 profile 返回 undefined,行为零变化。
1757
+ budget: shapeWriteBudgetForProfile(task.files, task.profile),
1758
+ dependencies: deps,
1759
+ authority: taskAuthority(task),
1760
+ riskTier: "riskTier" in task ? task.riskTier : void 0
1761
+ };
1762
+ });
1763
+ }
1764
+ function mapTeamDependency(dep) {
1765
+ if (typeof dep === "string") return `team:${dep}`;
1766
+ return {
1767
+ dependsOn: `team:${dep.dependsOn}`,
1768
+ ...dep.onFailure ? { onFailure: dep.onFailure } : {},
1769
+ ...dep.alternateOrderId ? { alternateOrderId: `team:${dep.alternateOrderId}` } : {}
1770
+ };
1771
+ }
1772
+ function waveToRequests(wave, taskMap, parentTurnId) {
1773
+ return wave.taskIds.map((id) => taskMap.get(id)).filter((t) => Boolean(t)).map((task) => {
1774
+ const stableId = `team:${task.id}`;
1775
+ const deps = task.dependsOn.length > 0 ? task.dependsOn.map((d) => mapTeamDependency(d)) : void 0;
1776
+ return {
1777
+ parentTurnId: `${parentTurnId}:${stableId}`,
1778
+ objective: buildExecutionObjective(task),
1779
+ kind: task.kind,
1780
+ profile: task.profile,
1781
+ scope: { files: task.files },
1782
+ budget: shapeWriteBudgetForProfile(task.files, task.profile),
1783
+ dependencies: deps,
1784
+ authority: taskAuthority(task),
1785
+ riskTier: task.riskTier
1786
+ };
1787
+ });
1788
+ }
1789
+ function taskFiles(task) {
1790
+ return task.touchSet.length > 0 ? task.touchSet : task.files;
1791
+ }
1792
+ function extractTaskIdFromWorkOrderId(woId) {
1793
+ return woId.includes(":") ? woId.slice(woId.lastIndexOf(":") + 1) : woId;
1794
+ }
1795
+ function buildSchedulerContext(wave, waves, taskMap) {
1796
+ const waveTasks = wave.taskIds.map((id) => taskMap.get(id)).filter((task) => Boolean(task));
1797
+ const writeTasks = waveTasks.filter((task) => !(task.profile === "code_scout" || task.profile === "doc_scout" || task.profile === "reviewer" && task.kind === "review"));
1798
+ const readTasks = waveTasks.length - writeTasks.length;
1799
+ const moduleRoots = new Set(waveTasks.flatMap((task) => taskFiles(task).map((file) => file.split("/").slice(0, 2).join("/"))).filter(Boolean));
1800
+ const highRiskCount = waveTasks.filter((task) => task.riskTier === "high").length;
1801
+ const maxDeps = Math.max(0, ...waveTasks.map((task) => task.dependsOn.length));
1802
+ return {
1803
+ taskCount: Math.min(1, waveTasks.length / 5),
1804
+ writeTaskCount: Math.min(1, writeTasks.length / 5),
1805
+ readTaskCount: Math.min(1, readTasks / 5),
1806
+ dependencyDepth: Math.min(1, maxDeps / Math.max(1, waves.length)),
1807
+ crossModuleScore: Math.min(1, Math.max(0, moduleRoots.size - 1) / 4),
1808
+ highRiskRatio: waveTasks.length > 0 ? highRiskCount / waveTasks.length : 0,
1809
+ historicalReward: 0,
1810
+ scopeLeakRate: 0
1811
+ };
1812
+ }
1813
+ function resolveSchedulerState(deps) {
1814
+ if (deps.teamSchedulerState) return deps.teamSchedulerState;
1815
+ return summarizeTeamSchedulerBandit(createTeamSchedulerBandit());
1816
+ }
1817
+ function applySchedulerToWave(wave, waves, ctx) {
1818
+ const ruleParallelism = Math.max(1, Math.min(wave.parallelLimit, wave.taskIds.length, 5));
1819
+ const bandit = createTeamSchedulerBandit();
1820
+ const schedulerContext = buildSchedulerContext(wave, waves, ctx.taskMap);
1821
+ const state = resolveSchedulerState(ctx.deps);
1822
+ const shadowRecommendation = recommendTeamSchedulerArm(bandit, schedulerContext);
1823
+ const bestObservedArm = Object.entries(state.arms).filter(([, stat]) => stat.samples > 0).sort((a, b) => b[1].averageReward - a[1].averageReward)[0]?.[0];
1824
+ const recommended = { ...shadowRecommendation, arm: bestObservedArm ?? shadowRecommendation.arm };
1825
+ const candidateAvg = state.arms[recommended.arm]?.averageReward ?? 0;
1826
+ const baselineAvg = state.arms[teamSchedulerArmForParallelism(ruleParallelism)]?.averageReward ?? 0;
1827
+ const decision = evaluateTeamSchedulerGate({
1828
+ state,
1829
+ candidateArm: recommended.arm,
1830
+ ruleParallelism,
1831
+ ruleBaselineReward: baselineAvg,
1832
+ recentFalseGreenRate: 0,
1833
+ ruleAgreementRate: parallelismForTeamSchedulerArm(recommended.arm) <= ruleParallelism ? 1 : 0,
1834
+ hardGateSafe: wave.risk !== "high" || parallelismForTeamSchedulerArm(recommended.arm) <= 1,
1835
+ featureFlagEnabled: ctx.input.teamSchedulerBanditEnabled === true
1836
+ });
1837
+ const parallelLimit = applyTeamSchedulerInfluence(ruleParallelism, recommended.arm, decision);
1838
+ try {
1839
+ ctx.deps.recordTeamSchedulerShadow?.(buildTeamSchedulerShadowEvent({
1840
+ sessionId: ctx.deps.sessionId ?? "unknown",
1841
+ objective: ctx.input.objective,
1842
+ waveId: wave.id,
1843
+ ruleParallelism,
1844
+ recommendedArm: recommended.arm,
1845
+ applied: decision.applied,
1846
+ gateOpen: decision.gateOpen,
1847
+ reason: `${decision.reason}; candidateAvg=${candidateAvg.toFixed(3)} baselineAvg=${baselineAvg.toFixed(3)}`
1848
+ }));
1849
+ } catch {
1850
+ }
1851
+ try {
1852
+ ctx.deps.recordGatedInfluenceAudit?.(buildGatedInfluenceAuditEvent({
1853
+ source: "team_scheduler_bandit",
1854
+ sessionId: ctx.deps.sessionId ?? "unknown",
1855
+ targetId: wave.id,
1856
+ gateOpen: decision.gateOpen,
1857
+ applied: decision.applied,
1858
+ reason: decision.reason,
1859
+ evidenceWindow: {
1860
+ ...decision.evidenceWindow,
1861
+ candidateAverageReward: candidateAvg,
1862
+ baselineAverageReward: baselineAvg
1863
+ },
1864
+ vetoSignals: decision.vetoSignals
1865
+ }));
1866
+ } catch {
1867
+ }
1868
+ if (parallelLimit >= wave.taskIds.length) return { wave: { ...wave, parallelLimit: ruleParallelism }, blocked: [] };
1869
+ const keptTaskIds = wave.taskIds.slice(0, parallelLimit);
1870
+ const deferredTaskIds = wave.taskIds.slice(parallelLimit);
1871
+ return {
1872
+ wave: { ...wave, taskIds: keptTaskIds, parallelLimit, reason: `${wave.reason}; scheduler ${decision.applied ? "applied" : "shadow"} ${recommended.arm}` },
1873
+ blocked: deferredTaskIds.map((id) => `${id}: deferred by scheduler parallelLimit=${parallelLimit} within ${wave.id}`)
1874
+ };
1875
+ }
1876
+ async function dispatchWaveAt(waves, waveIndex, ctx) {
1877
+ const fromWave = Math.max(0, waveIndex);
1878
+ const { input, planned, tasks, taskMap, deps } = ctx;
1879
+ if (waves.length === 0) {
1880
+ return { mode: input.mode, planned, tasks, waves: [], dispatched: 0, blocked: [], packet: "team: no dispatchable waves." };
1881
+ }
1882
+ if (fromWave >= waves.length) {
1883
+ return { mode: input.mode, planned, tasks, waves, dispatched: 0, blocked: [], packet: `team: all ${waves.length} waves dispatched.` };
1884
+ }
1885
+ const targetWave = waves[fromWave];
1886
+ const scheduled = applySchedulerToWave(targetWave, waves, ctx);
1887
+ let dispatchWave = scheduled.wave;
1888
+ const remainingBlocked = [
1889
+ ...scheduled.blocked,
1890
+ ...waves.slice(fromWave + 1).map((w) => `${w.taskIds.join(", ")}: waiting for wave ${w.id} to complete`)
1891
+ ];
1892
+ const priorResults = input.priorResults;
1893
+ const crossWaveBlocked = [];
1894
+ const crossWaveSkipped = [];
1895
+ const blockedTaskIds = [];
1896
+ const skippedTaskIds = [];
1897
+ const failedIds = new Set(
1898
+ (priorResults ?? []).filter((r) => r.status !== "passed").map((r) => extractTaskIdFromWorkOrderId(r.workOrderId))
1899
+ );
1900
+ const priorPassedIds = new Set(
1901
+ (priorResults ?? []).filter((r) => r.status === "passed").map((r) => extractTaskIdFromWorkOrderId(r.workOrderId)).filter(Boolean)
1902
+ );
1903
+ if (priorResults && priorResults.length > 0) {
1904
+ if (failedIds.size > 0) {
1905
+ const filteredTaskIds = [];
1906
+ for (const taskId of dispatchWave.taskIds) {
1907
+ const task = taskMap.get(taskId);
1908
+ if (!task) {
1909
+ filteredTaskIds.push(taskId);
1910
+ continue;
1911
+ }
1912
+ const failedDepIds = [];
1913
+ const skippedDepIds = [];
1914
+ const waitingAlternates = [];
1915
+ for (const dep of task.dependsOn ?? []) {
1916
+ const depId = dependencyId(dep);
1917
+ if (!failedIds.has(depId)) continue;
1918
+ if (typeof dep === "string") {
1919
+ failedDepIds.push(depId);
1920
+ continue;
1921
+ }
1922
+ if (dep.onFailure === "skip") {
1923
+ skippedDepIds.push(depId);
1924
+ continue;
1925
+ }
1926
+ if (dep.onFailure === "alternate" && dep.alternateOrderId) {
1927
+ const altId = extractTaskIdFromWorkOrderId(dep.alternateOrderId);
1928
+ if (priorPassedIds.has(altId)) continue;
1929
+ if (failedIds.has(altId)) {
1930
+ skippedDepIds.push(depId);
1931
+ continue;
1932
+ }
1933
+ waitingAlternates.push(`${depId}\u2192${dep.alternateOrderId}`);
1934
+ continue;
1935
+ }
1936
+ failedDepIds.push(depId);
1937
+ }
1938
+ if (skippedDepIds.length > 0) {
1939
+ crossWaveSkipped.push(`${taskId}: skipped \u2014 conditional dependency failed (onFailure=skip): ${skippedDepIds.join(", ")}`);
1940
+ skippedTaskIds.push(taskId);
1941
+ } else if (failedDepIds.length > 0) {
1942
+ crossWaveBlocked.push(`${taskId}: blocked by prior wave failure (${failedDepIds.join(", ")})`);
1943
+ blockedTaskIds.push(taskId);
1944
+ } else if (waitingAlternates.length > 0) {
1945
+ crossWaveBlocked.push(`${taskId}: waiting for alternate (${waitingAlternates.join(", ")})`);
1946
+ blockedTaskIds.push(taskId);
1947
+ } else {
1948
+ filteredTaskIds.push(taskId);
1949
+ }
1950
+ }
1951
+ dispatchWave = { ...dispatchWave, taskIds: filteredTaskIds };
1952
+ }
1953
+ }
1954
+ const requests = waveToRequests(dispatchWave, taskMap, input.parentTurnId ?? "team");
1955
+ if (priorResults && priorResults.length > 0) {
1956
+ for (const req of requests) {
1957
+ if (req.dependencies && req.dependencies.length > 0) {
1958
+ const filtered = req.dependencies.filter((d) => {
1959
+ const rawId = dependencyId(d);
1960
+ const depId = rawId.includes(":") ? rawId.slice(rawId.lastIndexOf(":") + 1) : rawId;
1961
+ if (priorPassedIds.has(depId)) return false;
1962
+ if (typeof d === "object" && d.onFailure === "alternate" && d.alternateOrderId) {
1963
+ const altId = extractTaskIdFromWorkOrderId(d.alternateOrderId);
1964
+ if (failedIds.has(depId) && priorPassedIds.has(altId)) return false;
1965
+ }
1966
+ return true;
1967
+ });
1968
+ req.dependencies = filtered.length > 0 ? filtered : void 0;
1969
+ }
1970
+ }
1971
+ }
1972
+ if (input.onActivity) for (const r of requests) r.onActivity = input.onActivity;
1973
+ if (input.planConstraints && input.planConstraints.length > 0) {
1974
+ for (const r of requests) {
1975
+ r.constraints = [...r.constraints ?? [], ...input.planConstraints];
1976
+ }
1977
+ }
1978
+ const priorFeedback = buildPriorWaveFeedback({
1979
+ priorResults,
1980
+ waveGateFailures: input.priorWaveGateFailures,
1981
+ scopeLeaks: input.priorScopeLeaks
1982
+ });
1983
+ if (priorFeedback.length > 0) {
1984
+ for (const r of requests) {
1985
+ r.constraints = [...r.constraints ?? [], ...priorFeedback];
1986
+ }
1987
+ }
1988
+ const buildSyntheticResults = () => {
1989
+ const parentPrefix = input.parentTurnId ?? "team";
1990
+ const synthetic2 = [];
1991
+ for (let i = 0; i < blockedTaskIds.length; i++) {
1992
+ const detail = crossWaveBlocked[i];
1993
+ synthetic2.push({
1994
+ workOrderId: `${parentPrefix}:team:${blockedTaskIds[i]}`,
1995
+ status: "blocked",
1996
+ summary: detail,
1997
+ findings: [],
1998
+ artifacts: [{ kind: "risk", title: "Dependency blocked", content: detail }],
1999
+ changedFiles: [],
2000
+ risks: [],
2001
+ nextActions: [],
2002
+ evidenceStatus: "blocked"
2003
+ });
2004
+ }
2005
+ for (let i = 0; i < skippedTaskIds.length; i++) {
2006
+ const detail = crossWaveSkipped[i];
2007
+ synthetic2.push({
2008
+ workOrderId: `${parentPrefix}:team:${skippedTaskIds[i]}`,
2009
+ status: "blocked",
2010
+ summary: detail,
2011
+ findings: [],
2012
+ artifacts: [{ kind: "risk", title: "Dependency skipped", content: detail }],
2013
+ changedFiles: [],
2014
+ risks: [],
2015
+ nextActions: [],
2016
+ evidenceStatus: "skipped"
2017
+ });
2018
+ }
2019
+ return synthetic2;
2020
+ };
2021
+ if (requests.length === 0) {
2022
+ const synthetic2 = buildSyntheticResults();
2023
+ return {
2024
+ mode: input.mode,
2025
+ planned,
2026
+ tasks,
2027
+ waves,
2028
+ dispatched: 0,
2029
+ blocked: [...remainingBlocked, ...crossWaveBlocked],
2030
+ skipped: crossWaveSkipped.length > 0 ? crossWaveSkipped : void 0,
2031
+ run: synthetic2.length > 0 ? { status: "completed", results: synthetic2, packet: `team: wave ${targetWave.id} produced no dispatchable requests.` } : void 0,
2032
+ packet: `team: wave ${targetWave.id} produced no dispatchable requests.`
2033
+ };
2034
+ }
2035
+ if (input.onPlanReady) {
2036
+ input.onPlanReady({
2037
+ mode: input.mode,
2038
+ planned,
2039
+ tasks,
2040
+ waves,
2041
+ dispatched: requests.length,
2042
+ // 预览与实际派发结果一致(审查 fcb8106b):跨波 blocked/skipped 同步进预览。
2043
+ blocked: [...remainingBlocked, ...crossWaveBlocked],
2044
+ skipped: crossWaveSkipped.length > 0 ? crossWaveSkipped : void 0,
2045
+ packet: `[wave ${fromWave + 1}/${waves.length}] dispatching ${requests.length} workers\u2026`
2046
+ }, fromWave);
2047
+ }
2048
+ const run = await deps.delegateBatch(requests, "all_required", input.abortSignal);
2049
+ const synthetic = buildSyntheticResults();
2050
+ if (synthetic.length > 0) {
2051
+ run.results = [...run.results ?? [], ...synthetic];
2052
+ }
2053
+ try {
2054
+ deps.recordTeamWaveTelemetry?.(buildTeamWaveTelemetry({
2055
+ sessionId: deps.sessionId ?? "unknown",
2056
+ objective: input.objective,
2057
+ mode: input.mode,
2058
+ fromWave,
2059
+ wave: dispatchWave,
2060
+ waves,
2061
+ taskMap,
2062
+ run,
2063
+ dispatched: requests.length
2064
+ }));
2065
+ } catch {
2066
+ }
2067
+ return {
2068
+ mode: input.mode,
2069
+ planned,
2070
+ tasks,
2071
+ waves,
2072
+ dispatched: requests.length,
2073
+ blocked: [...remainingBlocked, ...crossWaveBlocked],
2074
+ skipped: crossWaveSkipped.length > 0 ? crossWaveSkipped : void 0,
2075
+ packet: `[wave ${fromWave + 1}/${waves.length}] ${run.packet}`,
2076
+ run
2077
+ };
2078
+ }
2079
+ async function runTeamSkeleton(input, deps) {
2080
+ const maxParallel = Math.max(1, Math.min(input.maxParallel ?? 3, 5));
2081
+ if (input.tasks && input.tasks.length > 0) {
2082
+ const enrichedTasks2 = input.tasks;
2083
+ const waves2 = groupTeamTasks(enrichedTasks2);
2084
+ const taskMap2 = new Map(enrichedTasks2.map((t) => [t.id, t]));
2085
+ if (waves2.length === 0) {
2086
+ return {
2087
+ mode: "standard",
2088
+ planned: [],
2089
+ tasks: enrichedTasks2,
2090
+ waves: [],
2091
+ dispatched: 0,
2092
+ blocked: ["pre-parsed tasks produced no dispatchable waves"],
2093
+ packet: "team: pre-parsed tasks \u2014 no waves to dispatch."
2094
+ };
2095
+ }
2096
+ return dispatchWaveAt(waves2, input.fromWave ?? 0, {
2097
+ taskMap: taskMap2,
2098
+ tasks: enrichedTasks2,
2099
+ planned: [],
2100
+ input,
2101
+ deps
2102
+ });
2103
+ }
2104
+ const drafts = input.mode === "standard" && input.planMarkdown ? parseTeamTaskDrafts(input.planMarkdown) : [];
2105
+ const enrichedTasks = input.planMarkdown ? parseTeamTasks(input.planMarkdown) : [];
2106
+ if (input.mode === "max") {
2107
+ const cached = loadTeamPlanSkeleton(deps.planCacheStore, input.objective, "max");
2108
+ let mergedTasks;
2109
+ let plannerRun;
2110
+ let planMerge;
2111
+ if (cached) {
2112
+ mergedTasks = cached.tasks;
2113
+ } else {
2114
+ const perspectives = selectExpertSet(input.objective);
2115
+ const plannerRequests = perspectives.map((perspective) => ({
2116
+ parentTurnId: `team:planner-${perspective}`,
2117
+ objective: buildPlannerObjective(perspective, input.objective),
2118
+ kind: "plan",
2119
+ profile: "perspective_planner",
2120
+ scope: {},
2121
+ authority: perspective,
2122
+ onActivity: input.onActivity
2123
+ }));
2124
+ plannerRun = await deps.delegateBatch(
2125
+ plannerRequests,
2126
+ "all_required",
2127
+ input.abortSignal,
2128
+ void 0,
2129
+ input.onWorkerSettled
2130
+ );
2131
+ const planFor = (perspective) => {
2132
+ const result = plannerRun.results.find((r) => r.workOrderId.includes(`planner-${perspective}`));
2133
+ return result ? parsePerspectiveResult(perspective, result) : normalizePerspective(perspective, {});
2134
+ };
2135
+ const merged = mergePerspectivesByRole(perspectives.map(planFor));
2136
+ mergedTasks = foldVerificationIntoTasks(merged.tasks, merged.verification);
2137
+ planMerge = { conflicts: merged.conflicts, risks: merged.risks, deferred: merged.deferred, rejected: merged.rejected, augmented: merged.augmented };
2138
+ if (mergedTasks.length > 0) {
2139
+ saveTeamPlanSkeleton(deps.planCacheStore, { objective: input.objective, mode: "max", tasks: mergedTasks });
2140
+ }
2141
+ }
2142
+ const advisories = detectOverlapWithoutOrder(mergedTasks.map((t) => ({ ...t, dependsOn: t.dependsOn.map(dependencyId) })));
2143
+ const waves2 = groupTeamTasks(mergedTasks);
2144
+ const taskMap2 = new Map(mergedTasks.map((t) => [t.id, t]));
2145
+ if (waves2.length === 0) {
2146
+ return {
2147
+ mode: input.mode,
2148
+ planned: [],
2149
+ tasks: mergedTasks,
2150
+ waves: [],
2151
+ dispatched: 0,
2152
+ blocked: ["max planning produced no dispatchable tasks"],
2153
+ packet: "team max: planners returned no tasks to dispatch.",
2154
+ ...plannerRun ? { run: plannerRun } : {},
2155
+ ...cached ? { planCacheHit: true } : {},
2156
+ ...planMerge ? { planMerge } : {},
2157
+ ...advisories.length > 0 ? { advisories } : {}
2158
+ };
2159
+ }
2160
+ const summary = await dispatchWaveAt(waves2, input.fromWave ?? 0, {
2161
+ taskMap: taskMap2,
2162
+ tasks: mergedTasks,
2163
+ planned: [],
2164
+ input,
2165
+ deps
2166
+ });
2167
+ return {
2168
+ ...summary,
2169
+ ...cached ? { planCacheHit: true } : {},
2170
+ ...planMerge ? { planMerge } : {},
2171
+ ...advisories.length > 0 ? { advisories } : {}
2172
+ };
2173
+ }
2174
+ const waves = groupTeamTasks(enrichedTasks);
2175
+ const taskMap = new Map(enrichedTasks.map((t) => [t.id, t]));
2176
+ if (waves.length === 0) {
2177
+ const { selected, blocked } = selectDispatchableTeamTasks(drafts, maxParallel);
2178
+ if (selected.length === 0) {
2179
+ return {
2180
+ mode: input.mode,
2181
+ planned: drafts,
2182
+ tasks: enrichedTasks,
2183
+ waves: [],
2184
+ dispatched: 0,
2185
+ blocked,
2186
+ packet: blocked.length > 0 ? `team skeleton blocked:
2187
+ ${blocked.join("\n")}` : "team skeleton: no task drafts found to dispatch."
2188
+ };
2189
+ }
2190
+ const requests = teamTasksToDelegationRequests(selected, input.parentTurnId ?? "team");
2191
+ if (input.onActivity) for (const r of requests) r.onActivity = input.onActivity;
2192
+ if (input.planConstraints && input.planConstraints.length > 0) {
2193
+ for (const r of requests) {
2194
+ r.constraints = [...r.constraints ?? [], ...input.planConstraints];
2195
+ }
2196
+ }
2197
+ const run = await deps.delegateBatch(requests, "all_required", input.abortSignal);
2198
+ try {
2199
+ deps.recordTeamWaveTelemetry?.(buildTeamWaveTelemetry({
2200
+ sessionId: deps.sessionId ?? "unknown",
2201
+ objective: input.objective,
2202
+ mode: input.mode,
2203
+ fromWave: input.fromWave ?? 0,
2204
+ wave: { id: `legacy-W${(input.fromWave ?? 0) + 1}`, taskIds: selected.map((task) => task.id), reason: "legacy unstructured plan dispatch", parallelLimit: maxParallel, risk: "medium" },
2205
+ waves: [{ id: `legacy-W${(input.fromWave ?? 0) + 1}`, taskIds: selected.map((task) => task.id), reason: "legacy unstructured plan dispatch", parallelLimit: maxParallel, risk: "medium" }],
2206
+ taskMap: new Map(selected.map((task) => [task.id, {
2207
+ ...task,
2208
+ dependsOn: [],
2209
+ riskTier: "medium",
2210
+ touchSet: [...task.files],
2211
+ groupId: void 0,
2212
+ routeHint: void 0
2213
+ }])),
2214
+ run,
2215
+ dispatched: requests.length
2216
+ }));
2217
+ } catch {
2218
+ }
2219
+ return {
2220
+ mode: input.mode,
2221
+ planned: drafts,
2222
+ tasks: enrichedTasks,
2223
+ waves: [],
2224
+ dispatched: requests.length,
2225
+ blocked,
2226
+ packet: run.packet,
2227
+ run
2228
+ };
2229
+ }
2230
+ return dispatchWaveAt(waves, input.fromWave ?? 0, {
2231
+ taskMap,
2232
+ tasks: enrichedTasks,
2233
+ planned: drafts,
2234
+ input,
2235
+ deps
2236
+ });
2237
+ }
2238
+
2239
+ // src/agent/wave-results-store.ts
2240
+ init_esm_shims();
2241
+ var waveResults = /* @__PURE__ */ new Map();
2242
+ function key(sessionId) {
2243
+ return sessionId ?? "__default__";
2244
+ }
2245
+ function setWaveResults(results, sessionId) {
2246
+ waveResults.set(key(sessionId), results);
2247
+ }
2248
+ function getWaveResults(sessionId) {
2249
+ return waveResults.get(key(sessionId));
2250
+ }
2251
+ function clearWaveResults(sessionId) {
2252
+ waveResults.delete(key(sessionId));
2253
+ }
2254
+
2255
+ // src/agent/plan-executor.ts
2256
+ function capList(items, n = 8) {
2257
+ return items.length <= n ? items.join(", ") : `${items.slice(0, n).join(", ")} (+${items.length - n} more)`;
2258
+ }
2259
+ function requireDelegate(deps) {
2260
+ if (!deps.delegate) throw new Error("plan execution review gate requires deps.delegate");
2261
+ return deps.delegate;
2262
+ }
2263
+ function teamReviewChangedFiles(run) {
2264
+ if (!run) return [];
2265
+ const files2 = /* @__PURE__ */ new Set();
2266
+ for (const result of run.results) {
2267
+ for (const file of result.changedFiles) files2.add(file);
2268
+ for (const artifact of result.artifacts) {
2269
+ if (artifact.kind === "diff") {
2270
+ for (const file of extractChangedFiles(artifact.content)) files2.add(file);
2271
+ }
2272
+ }
2273
+ }
2274
+ return [...files2];
2275
+ }
2276
+ function teamReviewForceLevel(mode, change, waveTasks) {
2277
+ if (mode === "max") return "L3";
2278
+ const base = classifyChangeScale(change);
2279
+ const hasHighRisk = waveTasks.some((task) => task.riskTier === "high");
2280
+ if (base === "L3" || change.crossModule || waveTasks.length >= 3 || hasHighRisk) return "L3";
2281
+ return base === "L1" ? "L2" : base;
2282
+ }
2283
+ function teamReviewFocusHint(waveTasks) {
2284
+ const gates = [...new Set(waveTasks.flatMap((task) => task.verification).map((v) => v.trim()).filter(Boolean))];
2285
+ if (gates.length === 0) return void 0;
2286
+ return `Planned acceptance gates (verify these, do not just trust green): ${gates.join("; ")}`;
2287
+ }
2288
+ function buildWaveCheckpoint(opts, summary, prior) {
2289
+ const taskById = new Map(summary.tasks.map((task) => [task.id, task]));
2290
+ const remainingOrders = summary.waves.slice(opts.fromWave + 1).flatMap((wave) => wave.taskIds).map((id) => taskById.get(id)).filter((task) => Boolean(task)).map((task) => ({
2291
+ id: task.id,
2292
+ objective: task.objective,
2293
+ profile: task.profile,
2294
+ kind: task.kind,
2295
+ scope: { files: task.files },
2296
+ authority: taskAuthority(task),
2297
+ // 依赖随任务存盘——resume 重建计划要靠它恢复剩余任务间的顺序与条件边。
2298
+ ...task.dependsOn.length > 0 ? { dependsOn: task.dependsOn } : {}
2299
+ }));
2300
+ return {
2301
+ groupId: deriveTeamGroupId(opts.objective),
2302
+ timestamp: Date.now(),
2303
+ lastCompletedWave: opts.fromWave,
2304
+ completedResults: [...prior?.completedResults ?? [], ...summary.run?.results ?? []],
2305
+ remainingOrders,
2306
+ objective: opts.objective,
2307
+ totalWaves: summary.waves.length
2308
+ };
2309
+ }
2310
+ async function executePlan(opts, deps) {
2311
+ let telemetryEvent;
2312
+ if (isSkillGateEnabled() && opts.fromWave === 0) {
2313
+ const required = opts.requiredSkills ?? (opts.planMarkdown ? extractRequiredSkills(opts.planMarkdown) : []);
2314
+ if (required.length > 0) {
2315
+ const verdict = evaluateSkillGate(required, {
2316
+ availableNames: new Set(skillRegistry.list().map((s) => s.name)),
2317
+ invokedNames: getInvokedSkills(opts.sessionId)
2318
+ });
2319
+ if (verdict.missing.length > 0) {
2320
+ throw new Error(formatSkillGateBlock(verdict.missing));
2321
+ }
2322
+ }
2323
+ }
2324
+ if (isWaveGateEnabled() && opts.fromWave > 0) {
2325
+ const prior = getWaveGate(opts.sessionId);
2326
+ if (prior && prior.wave === opts.fromWave - 1 && !prior.passed) {
2327
+ const recheck = await evaluateWaveGate({
2328
+ cwd: opts.cwd,
2329
+ wave: prior.wave,
2330
+ changedFiles: prior.changedFiles,
2331
+ commands: prior.commands,
2332
+ typecheckRunner: deps.getTypecheckRunner?.()
2333
+ });
2334
+ setWaveGate(recheck, opts.sessionId);
2335
+ if (!recheck.passed) {
2336
+ throw new Error(
2337
+ `\u6CE2\u95F4\u786C\u95E8\u7981\uFF1Awave ${prior.wave + 1} \u9A8C\u8BC1\u672A\u901A\u8FC7\uFF0C\u7981\u6B62\u6D3E\u53D1 wave ${opts.fromWave + 1}\u3002
2338
+ ` + formatWaveGate(recheck).join("\n") + `
2339
+ \u5148\u4FEE\u590D\u5931\u8D25\u9879\uFF08\u6216\u91CD\u8DD1\u8BE5\u6CE2\uFF09\uFF0C\u95E8\u7981\u590D\u8BC4\u901A\u8FC7\u540E\u65B9\u53EF\u7EE7\u7EED\u3002\u9003\u751F\u9600\uFF1ARIVET_WAVE_GATE=0\u3002`
2340
+ );
2341
+ }
2342
+ }
2343
+ }
2344
+ const priorResults = opts.fromWave > 0 ? getWaveResults(opts.sessionId) : void 0;
2345
+ const priorWaveGateFailures = opts.fromWave > 0 ? (getWaveGate(opts.sessionId)?.checks ?? []).filter((c) => c.status === "failed" || c.blocking === true && c.status !== "passed").map((c) => c.command) : [];
2346
+ const summary = await runTeamSkeleton(
2347
+ {
2348
+ mode: opts.mode,
2349
+ objective: opts.objective,
2350
+ planMarkdown: opts.planMarkdown,
2351
+ tasks: opts.tasks,
2352
+ maxParallel: opts.maxParallel,
2353
+ fromWave: opts.fromWave,
2354
+ parentTurnId: opts.parentTurnId,
2355
+ abortSignal: opts.abortSignal,
2356
+ priorResults,
2357
+ teamSchedulerBanditEnabled: deps.isTeamSchedulerBanditEnabled?.() === true,
2358
+ onActivity: opts.onActivity,
2359
+ onWorkerSettled: opts.onWorkerSettled,
2360
+ onPlanReady: opts.onPlanReady,
2361
+ // D8 L2:计划约束透传(team-orchestrator 分片在 TeamRunInput 消费并并入
2362
+ // waveToRequests 的 request.constraints)。条件注入——空则不带,fail-open。
2363
+ ...opts.planConstraints && opts.planConstraints.length > 0 ? { planConstraints: opts.planConstraints } : {},
2364
+ // 跨波回执:条件注入,空则不带字段——wave 0 与一切正常的波次行为不变。
2365
+ ...priorWaveGateFailures.length > 0 ? { priorWaveGateFailures } : {},
2366
+ ...opts.priorScopeLeaks && opts.priorScopeLeaks.length > 0 ? { priorScopeLeaks: opts.priorScopeLeaks } : {}
2367
+ },
2368
+ {
2369
+ delegateBatch: (requests, policy, abortSignal, onProgress, onWorkerSettled) => deps.delegateBatch(requests, policy, abortSignal, (completed, total) => {
2370
+ onProgress?.(completed, total);
2371
+ opts.onProgress?.(completed, total);
2372
+ }, onWorkerSettled ?? opts.onWorkerSettled),
2373
+ recordTeamWaveTelemetry: (event) => {
2374
+ telemetryEvent = event;
2375
+ deps.recordTeamWaveTelemetry?.(event);
2376
+ },
2377
+ recordTeamSchedulerShadow: (event) => deps.recordTeamSchedulerShadow?.(event),
2378
+ recordGatedInfluenceAudit: (event) => {
2379
+ if (deps.recordGatedInfluenceAudit) {
2380
+ deps.recordGatedInfluenceAudit(event);
2381
+ return;
2382
+ }
2383
+ const store = deps.getTeamSchedulerRewardStore?.();
2384
+ if (store?.saveBanditState) persistGatedInfluenceAudit({ saveBanditState: store.saveBanditState.bind(store) }, event);
2385
+ },
2386
+ teamSchedulerState: deps.getTeamSchedulerState?.() ?? buildHistoricalTeamSchedulerState(deps.getTeamSchedulerRewardStore?.()),
2387
+ sessionId: deps.getSessionId?.(),
2388
+ // Track 2: 计划骨架缓存与 reward 共用同一 append-only 存储。
2389
+ planCacheStore: deps.getTeamSchedulerRewardStore?.()
2390
+ }
2391
+ );
2392
+ if (summary.run?.results) {
2393
+ setWaveResults(summary.run.results, opts.sessionId);
2394
+ }
2395
+ if (summary.run?.results) {
2396
+ try {
2397
+ const prior = loadCheckpoint(opts.cwd, deriveTeamGroupId(opts.objective));
2398
+ saveCheckpoint(opts.cwd, buildWaveCheckpoint(opts, summary, prior));
2399
+ } catch {
2400
+ }
2401
+ }
2402
+ let reviewNote = "";
2403
+ let deliverySynthesis = "";
2404
+ let impactNote = "";
2405
+ let reviewVerdict;
2406
+ const effectiveFromWave = opts.fromWave;
2407
+ const isLastWave = summary.waves.length > 0 && effectiveFromWave >= summary.waves.length - 1;
2408
+ let scopeHealthNote = "";
2409
+ let scopeLeakedFiles = [];
2410
+ if (telemetryEvent) {
2411
+ try {
2412
+ const health = buildTeamWaveScopeHealth(telemetryEvent);
2413
+ const rewardStore = deps.getTeamSchedulerRewardStore?.();
2414
+ persistTeamScopeHealth(
2415
+ rewardStore?.saveBanditState ? { saveBanditState: rewardStore.saveBanditState.bind(rewardStore) } : void 0,
2416
+ health
2417
+ );
2418
+ if (health.severity === "medium" || health.severity === "high") {
2419
+ scopeLeakedFiles = health.leakedFiles;
2420
+ const parts = [];
2421
+ if (health.leakedFiles.length > 0) parts.push(`leaked (changed, not planned): ${health.leakedFiles.join(", ")}`);
2422
+ if (health.missingFiles.length > 0) parts.push(`missing (planned, untouched): ${health.missingFiles.join(", ")}`);
2423
+ scopeHealthNote = `
2424
+
2425
+ Scope health [${health.severity}]: ${parts.join("; ")}`;
2426
+ }
2427
+ } catch {
2428
+ }
2429
+ }
2430
+ const changedFiles = teamReviewChangedFiles(summary.run);
2431
+ if (opts.reviewGate && isLastWave && changedFiles.length > 0 && opts.reviewDepth === 0) {
2432
+ try {
2433
+ const delegate = requireDelegate(deps);
2434
+ const taskById = new Map(summary.tasks.map((task) => [task.id, task]));
2435
+ const waveTasks = (summary.waves[effectiveFromWave]?.taskIds ?? []).map((id) => taskById.get(id)).filter((task) => Boolean(task));
2436
+ const change = {
2437
+ files: changedFiles,
2438
+ crossModule: isCrossModule(changedFiles),
2439
+ isFix: isFixContext(opts.objective)
2440
+ };
2441
+ change.forceLevel = teamReviewForceLevel(opts.mode, change, waveTasks);
2442
+ const baseFocus = teamReviewFocusHint(waveTasks);
2443
+ let impactFocus;
2444
+ try {
2445
+ const analyzer = deps.getMeridianIndexer?.();
2446
+ const observed = (telemetryEvent?.changedFiles.observedChangedFiles ?? []).filter((f) => !isAbsolute(f));
2447
+ if (analyzer && observed.length > 0) {
2448
+ const impact = analyzer.impact(observed);
2449
+ const consumers = [...impact.direct, ...impact.transitive];
2450
+ const seg = [];
2451
+ if (consumers.length > 0) seg.push(`downstream consumers (verify not broken): ${capList(consumers)}`);
2452
+ if (impact.tests.length > 0) seg.push(`related tests to run: ${capList(impact.tests)}`);
2453
+ if (seg.length > 0) {
2454
+ impactFocus = `Blast radius \u2014 ${seg.join("; ")}`;
2455
+ impactNote = `
2456
+
2457
+ Blast radius [meridian]: ${seg.join("; ")}`;
2458
+ }
2459
+ }
2460
+ } catch {
2461
+ }
2462
+ let typecheckFocus;
2463
+ const typecheckRunner = deps.getTypecheckRunner?.();
2464
+ if (typecheckGateEnabled() && typecheckRunner) {
2465
+ try {
2466
+ const observed = (telemetryEvent?.changedFiles.observedChangedFiles ?? []).filter((f) => !isAbsolute(f));
2467
+ const tc = await runChangedFilesTypecheckMemo(opts.cwd, observed, typecheckRunner);
2468
+ if (tc) {
2469
+ change.forceLevel = "L3";
2470
+ typecheckFocus = `Typecheck \u2014 ${tc.summary}`;
2471
+ impactNote = `
2472
+
2473
+ Typecheck broken [tsc]: ${tc.summary}` + impactNote;
2474
+ }
2475
+ } catch {
2476
+ }
2477
+ }
2478
+ const focusParts = [
2479
+ typecheckFocus,
2480
+ baseFocus,
2481
+ scopeLeakedFiles.length > 0 ? `Scope leak \u2014 files changed outside the plan, scrutinize these: ${scopeLeakedFiles.join(", ")}` : void 0,
2482
+ impactFocus
2483
+ ].filter((s) => Boolean(s));
2484
+ const focusHint = focusParts.length > 0 ? focusParts.join(" | ") : void 0;
2485
+ const reviewDeps = createCoordinatorReviewDeps(
2486
+ {
2487
+ delegate: (request2, abortSignal) => delegate(request2, abortSignal),
2488
+ delegateBatch: (requests, policy, abortSignal, onProgress) => deps.delegateBatch(requests, policy, abortSignal, onProgress)
2489
+ },
2490
+ { reviewDepth: opts.reviewDepth, abortSignal: opts.abortSignal, parentTurnId: `${opts.parentTurnId}:review` }
2491
+ );
2492
+ const outcome = await routeReviewWorkflow(change, reviewDeps, { maxRounds: 3, ...focusHint ? { focusHint } : {} });
2493
+ reviewVerdict = outcome.verdict;
2494
+ reviewNote = `
2495
+
2496
+ Review gate [${outcome.tier}]: ${outcome.verdict}${outcome.evidence ? ` \u2014 ${outcome.evidence}` : ""}`;
2497
+ } catch (err) {
2498
+ const msg = err instanceof Error ? err.message : String(err);
2499
+ throw new Error(`review gate failed: ${msg}`);
2500
+ }
2501
+ }
2502
+ let waveGateNote = "";
2503
+ let gate;
2504
+ if (isWaveGateEnabled() && !isLastWave && summary.run) {
2505
+ try {
2506
+ const taskById = new Map(summary.tasks.map((task) => [task.id, task]));
2507
+ const waveTasks = (summary.waves[effectiveFromWave]?.taskIds ?? []).map((id) => taskById.get(id)).filter((task) => Boolean(task));
2508
+ const commands = [...new Set(waveTasks.flatMap((task) => task.verification).map((v) => v.trim()).filter(Boolean))];
2509
+ if (changedFiles.length > 0 || commands.length > 0) {
2510
+ const record = await evaluateWaveGate({
2511
+ cwd: opts.cwd,
2512
+ wave: effectiveFromWave,
2513
+ changedFiles: changedFiles.filter((f) => !isAbsolute(f)),
2514
+ commands,
2515
+ typecheckRunner: deps.getTypecheckRunner?.()
2516
+ });
2517
+ setWaveGate(record, opts.sessionId);
2518
+ waveGateNote = `
2519
+
2520
+ ${formatWaveGate(record).join("\n")}`;
2521
+ if (!record.passed) {
2522
+ waveGateNote += `
2523
+ \u26D4 \u4E0B\u4E00\u6CE2\u6D3E\u53D1\u5C06\u88AB\u786C\u62E6\uFF0C\u5148\u4FEE\u590D\u5931\u8D25\u9879\u3002\u9003\u751F\u9600\uFF1ARIVET_WAVE_GATE=0\u3002`;
2524
+ }
2525
+ gate = {
2526
+ wave: record.wave,
2527
+ passed: record.passed,
2528
+ failures: record.checks.filter((c) => c.status === "failed" || c.blocking && c.status !== "passed").map((c) => `${c.command}${c.detail ? ` \u2014 ${c.detail}` : ""}`)
2529
+ };
2530
+ }
2531
+ } catch {
2532
+ }
2533
+ }
2534
+ if (telemetryEvent) {
2535
+ const closedTelemetry = {
2536
+ ...telemetryEvent,
2537
+ outcome: {
2538
+ ...telemetryEvent.outcome,
2539
+ ...reviewVerdict ? { reviewVerdict } : {}
2540
+ }
2541
+ };
2542
+ try {
2543
+ deps.recordTeamWaveRewardClosure?.(closedTelemetry);
2544
+ } catch {
2545
+ }
2546
+ try {
2547
+ deps.recordTeamSchedulerReward?.(closedTelemetry);
2548
+ } catch {
2549
+ }
2550
+ if (isLastWave) {
2551
+ try {
2552
+ recordTeamEpisodeClosureFromStore(deps.getTeamSchedulerRewardStore?.(), closedTelemetry);
2553
+ } catch {
2554
+ }
2555
+ try {
2556
+ const episode = buildTeamEpisodeFromStore(deps.getTeamSchedulerRewardStore?.(), closedTelemetry);
2557
+ deliverySynthesis = `
2558
+
2559
+ ${formatTeamDelivery(episode)}`;
2560
+ } catch {
2561
+ }
2562
+ }
2563
+ }
2564
+ if (isLastWave && summary.run?.results && summary.run.results.every((result) => result.status === "passed")) {
2565
+ try {
2566
+ clearCheckpoint(opts.cwd, deriveTeamGroupId(opts.objective));
2567
+ } catch {
2568
+ }
2569
+ }
2570
+ return {
2571
+ summary,
2572
+ reviewVerdict,
2573
+ notes: { reviewNote, scopeHealthNote, impactNote, deliverySynthesis, waveGateNote },
2574
+ ...scopeLeakedFiles.length > 0 ? { scopeLeakedFiles } : {},
2575
+ gate,
2576
+ // P4 fix: reviewVerdict is just a single enum word (e.g. "verified") — the
2577
+ // real content with evidence is reviewNote. Strip leading newlines for the
2578
+ // inline panel display.
2579
+ ...reviewNote ? { reviewDetail: reviewNote.replace(/^\n+/, "").slice(0, 1e3) } : {}
2580
+ };
2581
+ }
2582
+ var EXECUTE_PLAN_WAVES_GUARDRAIL = 10;
2583
+ function classifyWaveStop(outcome, ctx = {}) {
2584
+ if (ctx.abortSignal?.aborted) return true;
2585
+ if (outcome.workers.total > 0 && outcome.workers.passed === 0) return true;
2586
+ if (outcome.waveGate && !outcome.waveGate.passed) return true;
2587
+ if (outcome.reviewVerdict === "rejected" || outcome.reviewVerdict === "inconclusive") return true;
2588
+ return false;
2589
+ }
2590
+ function aggregatePlanExecutorRuns(runs) {
2591
+ if (runs.length === 0) throw new Error("aggregatePlanExecutorRuns: no runs to aggregate");
2592
+ const summaries = runs.map((run) => run.summary);
2593
+ const lastRun = runs[runs.length - 1];
2594
+ const last = lastRun.summary;
2595
+ const results = summaries.flatMap((summary2) => summary2.run?.results ?? []);
2596
+ const summary = {
2597
+ ...last,
2598
+ dispatched: summaries.reduce((n, s) => n + s.dispatched, 0),
2599
+ run: last.run ? { ...last.run, results } : void 0
2600
+ };
2601
+ const notes = {
2602
+ reviewNote: runs.map((run) => run.notes.reviewNote).filter(Boolean).join("\n"),
2603
+ scopeHealthNote: runs.map((run) => run.notes.scopeHealthNote).filter(Boolean).join("\n"),
2604
+ impactNote: runs.map((run) => run.notes.impactNote).filter(Boolean).join("\n"),
2605
+ deliverySynthesis: runs.map((run) => run.notes.deliverySynthesis).filter(Boolean).join("\n"),
2606
+ waveGateNote: runs.map((run) => run.notes.waveGateNote).filter(Boolean).join("\n")
2607
+ };
2608
+ const gate = [...runs].reverse().find((run) => run.gate)?.gate;
2609
+ const reviewDetail = [...runs].reverse().find((run) => run.reviewDetail)?.reviewDetail;
2610
+ return {
2611
+ summary,
2612
+ reviewVerdict: lastRun.reviewVerdict,
2613
+ notes,
2614
+ ...gate ? { gate } : {},
2615
+ ...reviewDetail ? { reviewDetail } : {}
2616
+ };
2617
+ }
2618
+ async function executePlanWaves(opts, deps) {
2619
+ const startWave = opts.startWave ?? 0;
2620
+ const autoAdvance = opts.autoAdvance ?? true;
2621
+ const maxWaves = opts.maxWaves ?? startWave + EXECUTE_PLAN_WAVES_GUARDRAIL;
2622
+ if (maxWaves <= startWave) {
2623
+ throw new Error(`executePlanWaves: maxWaves (${maxWaves}) must be > startWave (${startWave})`);
2624
+ }
2625
+ const { startWave: _startWave, autoAdvance: _autoAdvance, maxWaves: _maxWaves, onWave, ...planOpts } = opts;
2626
+ const runs = [];
2627
+ let priorScopeLeaks = [];
2628
+ for (let wave = startWave; wave < maxWaves; wave++) {
2629
+ const run = await executePlan(
2630
+ { ...planOpts, fromWave: wave, ...priorScopeLeaks.length > 0 ? { priorScopeLeaks } : {} },
2631
+ deps
2632
+ );
2633
+ priorScopeLeaks = run.scopeLeakedFiles ?? [];
2634
+ runs.push(run);
2635
+ onWave?.(run, wave);
2636
+ const outcome = buildTeamOutcome(run.summary, wave, run);
2637
+ const stop = classifyWaveStop(outcome, { abortSignal: opts.abortSignal });
2638
+ if (stop || !autoAdvance || wave + 1 >= outcome.totalWaves) break;
2639
+ }
2640
+ return { runs, run: aggregatePlanExecutorRuns(runs) };
2641
+ }
2642
+
2643
+ // src/tui/frame-codec.ts
2644
+ init_esm_shims();
2645
+ var registeredPrefixes = [];
2646
+ function registerFramePrefix(prefix) {
2647
+ if (!registeredPrefixes.includes(prefix)) {
2648
+ registeredPrefixes.push(prefix);
2649
+ }
2650
+ }
2651
+ function containsRegisteredFrame(uiContent) {
2652
+ for (const prefix of registeredPrefixes) {
2653
+ if (uiContent.includes(prefix)) return true;
2654
+ }
2655
+ return false;
2656
+ }
2657
+ function encodeFrame(model, prefix) {
2658
+ return `${prefix}${JSON.stringify(model)}`;
2659
+ }
2660
+ function decodeFrame(value, prefix, validate) {
2661
+ const at = value.indexOf(prefix);
2662
+ if (at === -1) return null;
2663
+ try {
2664
+ const parsed = JSON.parse(value.slice(at + prefix.length));
2665
+ if (validate(parsed)) return parsed;
2666
+ return null;
2667
+ } catch {
2668
+ return null;
2669
+ }
2670
+ }
2671
+ function decodeFrameLastWins(value, prefix, validate) {
2672
+ let at = value.lastIndexOf(prefix);
2673
+ while (at !== -1) {
2674
+ const start = at + prefix.length;
2675
+ const nl = value.indexOf("\n", start);
2676
+ const body = nl === -1 ? value.slice(start) : value.slice(start, nl);
2677
+ try {
2678
+ const parsed = JSON.parse(body);
2679
+ if (validate(parsed)) return parsed;
2680
+ } catch {
2681
+ }
2682
+ at = at > 0 ? value.lastIndexOf(prefix, at - 1) : -1;
2683
+ }
2684
+ return null;
2685
+ }
2686
+
2687
+ export {
2688
+ groupTeamTasks,
2689
+ parseTeamTasks,
2690
+ sealPlan,
2691
+ verifyPlanSeal,
2692
+ formatSealStatus,
2693
+ registerFramePrefix,
2694
+ containsRegisteredFrame,
2695
+ encodeFrame,
2696
+ decodeFrame,
2697
+ decodeFrameLastWins,
2698
+ buildTeamOutcome,
2699
+ createCoordinatorReviewDeps,
2700
+ teamSchedulerArmForParallelism,
2701
+ buildTeamSchedulerRewardEvent,
2702
+ persistTeamSchedulerShadow,
2703
+ persistTeamSchedulerReward,
2704
+ clearWaveResults,
2705
+ teamReviewChangedFiles,
2706
+ teamReviewForceLevel,
2707
+ teamReviewFocusHint,
2708
+ executePlan,
2709
+ EXECUTE_PLAN_WAVES_GUARDRAIL,
2710
+ executePlanWaves
2711
+ };