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,1051 @@
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
+ buildGalaxyBudgetInputs,
5
+ isReviewGalaxyDimension,
6
+ validateGalaxyDimensionContract
7
+ } from "./chunk-ZDIFBJFT.js";
8
+ import {
9
+ deserializeUnifiedPlan
10
+ } from "./chunk-TVHW77C7.js";
11
+ import {
12
+ buildPrewarmValue
13
+ } from "./chunk-JSS75KCG.js";
14
+ import {
15
+ constraintsFromUnifiedPlan
16
+ } from "./chunk-UHGLFRZE.js";
17
+ import {
18
+ delegationToolTimeoutMs
19
+ } from "./chunk-6HSVXHCZ.js";
20
+ import {
21
+ external_exports
22
+ } from "./chunk-OO3TAHO5.js";
23
+ import {
24
+ writeFileAtomicSync
25
+ } from "./chunk-A5MNH4ER.js";
26
+ import {
27
+ init_esm_shims
28
+ } from "./chunk-5GGOGLSN.js";
29
+
30
+ // src/tools/starflow.ts
31
+ init_esm_shims();
32
+
33
+ // src/agent/starflow-orchestrator.ts
34
+ init_esm_shims();
35
+ import { createHash } from "crypto";
36
+ import { execFileSync } from "child_process";
37
+ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, statSync, unlinkSync, utimesSync, writeFileSync } from "fs";
38
+ import { join } from "path";
39
+
40
+ // src/agent/env-precheck.ts
41
+ init_esm_shims();
42
+ import { statfsSync } from "fs";
43
+ var DISK_TIGHT_GIB = 5;
44
+ var DISK_CAUTION_GIB = 20;
45
+ var GIB = 2 ** 30;
46
+ function fmtGib(bytes) {
47
+ const gib = bytes / GIB;
48
+ return gib >= 10 ? gib.toFixed(0) : gib.toFixed(1);
49
+ }
50
+ function probeEnvFacts(cwd) {
51
+ try {
52
+ const s = statfsSync(cwd);
53
+ const bsize = typeof s.bsize === "number" && s.bsize > 0 ? s.bsize : 0;
54
+ if (!bsize) return {};
55
+ return {
56
+ diskFreeBytes: (typeof s.bavail === "number" ? s.bavail : 0) * bsize,
57
+ diskTotalBytes: (typeof s.blocks === "number" ? s.blocks : 0) * bsize
58
+ };
59
+ } catch {
60
+ return {};
61
+ }
62
+ }
63
+ function diskTierLine(facts) {
64
+ const freeGib = (facts.diskFreeBytes ?? 0) / GIB;
65
+ if (freeGib < DISK_TIGHT_GIB) {
66
+ return `\u26A0 \u7D27\u5F20\uFF1AGB \u7EA7\u6784\u5EFA/\u514B\u9686\u4E0D\u53EF\u884C\uFF0C\u6D89\u53CA\u4EFB\u52A1\u987B\u964D\u7EA7\u6216\u6362\u8DEF\u5F84`;
67
+ }
68
+ if (freeGib < DISK_CAUTION_GIB) {
69
+ return `\u6CE8\u610F\uFF1A\u4EC5\u591F\u5355\u4E2A\u4E2D\u578B\u6784\u5EFA\uFF1B\u591A\u4EFB\u52A1\u5E76\u884C\u7684\u5927\u6784\u5EFA\u9700\u5148\u817E\u7A7A\u95F4`;
70
+ }
71
+ return `\u5145\u88D5`;
72
+ }
73
+ function formatEnvPrecheckBlock(facts) {
74
+ if (facts.diskFreeBytes === void 0) return "";
75
+ const total = facts.diskTotalBytes !== void 0 ? ` / \u5171 ${fmtGib(facts.diskTotalBytes)} GiB` : "";
76
+ return [
77
+ "\u2500\u2500 \u73AF\u5883\u9884\u68C0\uFF08\u786C\u7EA6\u675F\uFF0C\u8BC4\u5BA1/\u6392\u671F\u524D\u5FC5\u6838\uFF09\u2500\u2500",
78
+ `\u78C1\u76D8\uFF08\u9879\u76EE\u5377\uFF09\uFF1A\u53EF\u7528 ${fmtGib(facts.diskFreeBytes)} GiB${total} \u2014\u2014 ${diskTierLine(facts)}`,
79
+ "\u6D89\u53CA\u6784\u5EFA/\u4E0B\u8F7D/\u5927\u4EA7\u7269\u7684\u5DE5\u4F5C\u5757\u5FC5\u987B\u5728\u8BA1\u5212\u91CC\u663E\u5F0F\u6838\u5BF9\u4E0A\u8FF0\u4F59\u91CF\uFF1B\u88AB\u73AF\u5883\u7EA6\u675F\u964D\u7EA7\u8FC7\u7684\u5757\uFF0C\u91CD\u63D0/\u7EED\u8DD1\u524D\u5FC5\u987B\u590D\u68C0\u3002"
80
+ ].join("\n");
81
+ }
82
+ function formatEnvFooter(facts) {
83
+ if (facts.diskFreeBytes === void 0) return "";
84
+ return `\u73AF\u5883\u73B0\u72B6\uFF1A\u78C1\u76D8\u53EF\u7528 ${fmtGib(facts.diskFreeBytes)} GiB\uFF08\u9879\u76EE\u5377\uFF09\u2014\u2014${diskTierLine(facts)}`;
85
+ }
86
+
87
+ // src/agent/starflow-orchestrator.ts
88
+ var GLYPH = "\u{1F320}";
89
+ var MAX_TEAM_WAVES = 10;
90
+ var SUMMARY_CAP = 160;
91
+ var STARFLOW_HEARTBEAT_MS = 1e4;
92
+ var COUNCIL_VETO_RE = /^## ⛔ 议事会否决/m;
93
+ var COUNCIL_PLAN_JSON_RE = /```council-plan-json\n([\s\S]*?)\n```/;
94
+ var TEAM_NEXT_WAVE_RE = /再次调用 team_orchestrate 并传 fromWave: (\d+)/;
95
+ var TEAM_ALL_FAILED_RE = /全部 \d+ 个 worker 失败/;
96
+ var TEAM_WAVE_GATE_RE = /下一波派发将被硬拦/;
97
+ var TEAM_REVIEW_REJECTED_RE = /Review gate \[[^\]]*\]: rejected/;
98
+ var TEAM_DISPATCHED_RE = /^team \w+:派发 (\d+)/m;
99
+ var GALAXY_FAILED_RE = /聚合结论: (\d+)\/(\d+) 个维度未通过/;
100
+ var GALAXY_DIM_LINE_RE = /^ {2}([^\n:]+): ([✗⊗↑])/gm;
101
+ function firstLine(text, cap = SUMMARY_CAP) {
102
+ const line = text.split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "";
103
+ return line.length > cap ? `${line.slice(0, cap)}\u2026` : line;
104
+ }
105
+ function starflowDir(cwd) {
106
+ return join(cwd, ".rivet", "starflow");
107
+ }
108
+ function starflowStatePath(cwd, objective, sessionId) {
109
+ const hash = createHash("sha1").update(objective).update("\0").update(sessionId ?? "").digest("hex").slice(0, 12);
110
+ return join(starflowDir(cwd), `${hash}.json`);
111
+ }
112
+ var STARFLOW_LEASE_TTL_MS = 6e4;
113
+ function starflowRunId(objective, sessionId, toolUseId) {
114
+ return createHash("sha1").update("starflow-run\0").update(objective).update("\0").update(sessionId ?? "").update("\0").update(toolUseId ?? "").digest("hex").slice(0, 16);
115
+ }
116
+ function starflowLeasePath(cwd, objective) {
117
+ const hash = createHash("sha1").update("starflow-lease\0").update(objective).digest("hex").slice(0, 16);
118
+ return join(starflowDir(cwd), `${hash}.lease`);
119
+ }
120
+ function leaseOwnerIsAlive(path, now) {
121
+ try {
122
+ const ageMs = now - statSync(path).mtimeMs;
123
+ if (ageMs > STARFLOW_LEASE_TTL_MS) return false;
124
+ const raw = JSON.parse(readFileSync(path, "utf8"));
125
+ if (!Number.isInteger(raw.pid) || raw.pid <= 0) return false;
126
+ if (!isProcessAlive(raw.pid)) return false;
127
+ return true;
128
+ } catch {
129
+ try {
130
+ return now - statSync(path).mtimeMs <= STARFLOW_LEASE_TTL_MS;
131
+ } catch {
132
+ return false;
133
+ }
134
+ }
135
+ }
136
+ function isProcessAlive(pid) {
137
+ try {
138
+ process.kill(pid, 0);
139
+ return true;
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+ function acquireStarflowLease(cwd, objective, runId) {
145
+ const path = starflowLeasePath(cwd, objective);
146
+ mkdirSync(starflowDir(cwd), { recursive: true });
147
+ const owner = JSON.stringify({ pid: process.pid, runId, acquiredAt: Date.now() });
148
+ for (let attempt = 0; attempt < 2; attempt++) {
149
+ try {
150
+ const fd = openSync(path, "wx");
151
+ try {
152
+ writeFileSync(fd, owner, "utf8");
153
+ } finally {
154
+ closeSync(fd);
155
+ }
156
+ const refresh = setInterval(() => {
157
+ try {
158
+ utimesSync(path, /* @__PURE__ */ new Date(), /* @__PURE__ */ new Date());
159
+ } catch {
160
+ }
161
+ }, Math.floor(STARFLOW_LEASE_TTL_MS / 3));
162
+ refresh.unref?.();
163
+ return {
164
+ release: () => {
165
+ clearInterval(refresh);
166
+ try {
167
+ const current = JSON.parse(readFileSync(path, "utf8"));
168
+ if (current.runId === runId) unlinkSync(path);
169
+ } catch {
170
+ }
171
+ }
172
+ };
173
+ } catch {
174
+ if (leaseOwnerIsAlive(path, Date.now())) return void 0;
175
+ try {
176
+ unlinkSync(path);
177
+ } catch {
178
+ }
179
+ }
180
+ }
181
+ return void 0;
182
+ }
183
+ function freshState(objective, now, sessionId, toolUseId) {
184
+ return {
185
+ objective,
186
+ runId: starflowRunId(objective, sessionId, toolUseId),
187
+ revision: 0,
188
+ ...sessionId ? { sessionId } : {},
189
+ phase: "council",
190
+ phases: {},
191
+ teamRetries: 0,
192
+ updatedAt: now
193
+ };
194
+ }
195
+ function readStateFile(path, objective) {
196
+ try {
197
+ if (!existsSync(path)) return void 0;
198
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
199
+ if (parsed.objective !== objective || typeof parsed.phase !== "string") return void 0;
200
+ return {
201
+ ...parsed,
202
+ runId: typeof parsed.runId === "string" && parsed.runId.length > 0 ? parsed.runId : starflowRunId(objective, parsed.sessionId),
203
+ revision: Number.isSafeInteger(parsed.revision) && parsed.revision >= 0 ? parsed.revision : 0
204
+ };
205
+ } catch {
206
+ return void 0;
207
+ }
208
+ }
209
+ function loadState(cwd, objective, sessionId) {
210
+ const preferred = readStateFile(starflowStatePath(cwd, objective, sessionId), objective);
211
+ if (preferred) return preferred;
212
+ const candidates = [];
213
+ try {
214
+ for (const entry of readdirSync(starflowDir(cwd))) {
215
+ if (!entry.endsWith(".json")) continue;
216
+ const state = readStateFile(join(starflowDir(cwd), entry), objective);
217
+ if (state) candidates.push(state);
218
+ }
219
+ } catch {
220
+ return void 0;
221
+ }
222
+ const newest = candidates.sort((a, b) => b.updatedAt - a.updatedAt)[0];
223
+ return newest;
224
+ }
225
+ function saveState(cwd, state) {
226
+ try {
227
+ mkdirSync(starflowDir(cwd), { recursive: true });
228
+ const nextState = {
229
+ ...state,
230
+ revision: state.revision + 1,
231
+ updatedAt: Math.max(state.updatedAt, Date.now())
232
+ };
233
+ writeFileAtomicSync(starflowStatePath(cwd, state.objective, state.sessionId), JSON.stringify(nextState, null, 2));
234
+ state.revision = nextState.revision;
235
+ state.updatedAt = nextState.updatedAt;
236
+ return true;
237
+ } catch {
238
+ return false;
239
+ }
240
+ }
241
+ async function persistPhaseOutput(deps, state, phase, content) {
242
+ if (!content.trim()) return {};
243
+ try {
244
+ const artifactId = deps.params.artifactStore ? await deps.params.artifactStore.save({
245
+ tool: "starflow",
246
+ target: `${state.objective}:${phase}`,
247
+ rawContent: content,
248
+ summary: firstLine(content),
249
+ sections: []
250
+ }) : void 0;
251
+ if (artifactId) return { rawArtifactId: artifactId };
252
+ } catch {
253
+ }
254
+ try {
255
+ const rawPath = `${starflowStatePath(deps.cwd, state.objective, state.sessionId)}.${phase}.raw`;
256
+ writeFileAtomicSync(rawPath, content);
257
+ return { rawPath };
258
+ } catch {
259
+ return {};
260
+ }
261
+ }
262
+ function authorityForDraftItem(item) {
263
+ const probe = `${item.id} ${item.title}`.toLowerCase();
264
+ if (/(review|verify)/.test(probe)) return "yaoguang";
265
+ if (/(docs|research)/.test(probe)) return "tianxuan";
266
+ return "tianliang";
267
+ }
268
+ function deriveGalaxyDims(items) {
269
+ const seen = /* @__PURE__ */ new Set();
270
+ const dims = [];
271
+ for (const item of items ?? []) {
272
+ const name = item.id.trim();
273
+ if (!name || seen.has(name)) continue;
274
+ seen.add(name);
275
+ dims.push({
276
+ name,
277
+ objective: item.detail,
278
+ authority: authorityForDraftItem(item),
279
+ ...item.files && item.files.length > 0 ? { files: item.files } : {}
280
+ });
281
+ }
282
+ return dims.slice(0, 5);
283
+ }
284
+ var PREWARM_FACT_CAP = 1500;
285
+ var PREWARM_LINE_CAP = 200;
286
+ function buildPrewarmFactBlock(values) {
287
+ const lines = ["\u2500\u2500 \u76EE\u6807\u6587\u4EF6\u9884\u53D6\u6458\u8981\uFF08\u8BC4\u5BA1\u671F\u95F4\u5DF2\u8BFB\u53D6\uFF0C\u4F9B\u76F4\u63A5\u5F15\u7528\uFF09\u2500\u2500"];
288
+ let budget = PREWARM_FACT_CAP;
289
+ for (const v of values) {
290
+ if (budget <= 0) {
291
+ lines.push("\u2026\uFF08\u6458\u8981\u622A\u65AD\uFF09");
292
+ break;
293
+ }
294
+ const head = (v.uiContent ?? v.content ?? "").split("\n").map((l) => l.trim()).find((l) => l.length > 0) ?? "";
295
+ const snippet = head.length > PREWARM_LINE_CAP ? `${head.slice(0, PREWARM_LINE_CAP)}\u2026` : head;
296
+ if (!snippet) continue;
297
+ const line = ` ${v.canonicalPath}\uFF1A${snippet}`;
298
+ if (line.length > budget) {
299
+ lines.push("\u2026\uFF08\u6458\u8981\u622A\u65AD\uFF09");
300
+ break;
301
+ }
302
+ lines.push(line);
303
+ budget -= line.length;
304
+ }
305
+ if (lines.length <= 1) return void 0;
306
+ return lines.join("\n");
307
+ }
308
+ function baselinePrecheckBlock(cwd, files) {
309
+ if (files.length === 0) return "";
310
+ const run = (args) => {
311
+ try {
312
+ return execFileSync("git", args, { cwd, encoding: "utf8", timeout: 3e3, stdio: ["ignore", "pipe", "ignore"], windowsHide: true }).toString();
313
+ } catch {
314
+ return null;
315
+ }
316
+ };
317
+ const status = run(["-c", "core.quotePath=false", "status", "--short"]);
318
+ if (status === null) return "";
319
+ const statusLines = status.length > 0 ? status.split("\n").filter((l) => l.trim().length > 0) : [];
320
+ const hits = statusLines.filter((l) => {
321
+ const p = l.slice(3).trim().replace(/^"|"$/g, "");
322
+ return files.some((f) => p === f || p.startsWith(`${f}/`));
323
+ });
324
+ const log = run(["log", "--oneline", "-5", "--", ...files]);
325
+ const logLines = (log ?? "").split("\n").filter((l) => l.trim().length > 0).slice(0, 5);
326
+ const lines = ["", "\u2500\u2500 \u57FA\u7EBF\u9884\u68C0\uFF08\u5DE5\u4F5C\u6811/\u63D0\u4EA4\u73B0\u72B6\uFF0C\u8BC4\u5BA1\u524D\u5FC5\u6838\uFF09\u2500\u2500"];
327
+ if (hits.length > 0) {
328
+ lines.push("\u5DE5\u4F5C\u6811\u547D\u4E2D\u8349\u7A3F\u76EE\u6807\u6587\u4EF6\uFF1A");
329
+ for (const h of hits.slice(0, 20)) lines.push(` ${h}`);
330
+ } else {
331
+ lines.push("\u5DE5\u4F5C\u6811\u65E0\u8349\u7A3F\u76EE\u6807\u6587\u4EF6\u7684\u6539\u52A8\u3002");
332
+ }
333
+ if (logLines.length > 0) {
334
+ lines.push("\u76EE\u6807\u6587\u4EF6\u6700\u8FD1\u63D0\u4EA4\uFF1A");
335
+ for (const l of logLines) lines.push(` ${l}`);
336
+ }
337
+ lines.push("\u7B2C\u4E00\u8F6E\u8BC4\u5BA1\u5FC5\u987B\u5148\u6838\u5BF9\u8349\u7A3F\u65AD\u8A00\u4E0E\u4E0A\u8FF0\u5DE5\u4F5C\u6811/\u63D0\u4EA4\u73B0\u72B6\u7684\u5DEE\u5F02\u3002");
338
+ const block = lines.join("\n");
339
+ return block.length > 2048 ? `${block.slice(0, 2048)}
340
+ \u2026\uFF08\u9884\u68C0\u5757\u622A\u65AD\uFF09` : block;
341
+ }
342
+ function incrementalReviewNote(items) {
343
+ const carried = items.filter((i) => i.previousVerdict === "passed" && i.revision === void 0);
344
+ if (carried.length === 0) return "";
345
+ return [
346
+ "",
347
+ "\u2500\u2500 \u589E\u91CF\u8BC4\u5BA1\u8BF4\u660E \u2500\u2500",
348
+ `\u4EE5\u4E0B\u6761\u76EE\u5DF2\u5728\u524D\u8F6E\u8BC4\u5BA1\u901A\u8FC7\u4E14\u672C\u8F6E\u672A\u53D8\uFF08previousVerdict=passed\uFF09\uFF1A${carried.map((i) => i.id).join("\u3001")}\u3002`,
349
+ "\u6CBF\u7528\u524D\u8F6E\u901A\u8FC7\u7ED3\u8BBA\uFF0C\u9664\u975E\u4E0E\u5176\u4ED6\u6761\u76EE\u51B2\u7A81\u5426\u5219\u4E0D\u91CD\u5BA1\uFF1B\u5176\u4F59\u6761\u76EE\u4E3A\u91CD\u70B9\u8BC4\u5BA1\u5BF9\u8C61\u3002"
350
+ ].join("\n");
351
+ }
352
+ function augmentCouncilObjective(objective, items, cwd, opts) {
353
+ const parts = [objective];
354
+ if (opts?.precheck !== false) {
355
+ const precheck = baselinePrecheckBlock(cwd, items.flatMap((i) => i.files ?? []));
356
+ if (precheck) parts.push(precheck);
357
+ const env = formatEnvPrecheckBlock(probeEnvFacts(cwd));
358
+ if (env) parts.push(env);
359
+ }
360
+ const note = incrementalReviewNote(items);
361
+ if (note) parts.push(note);
362
+ return parts.join("\n\n");
363
+ }
364
+ function councilGate(result) {
365
+ if (result.isError) return { ok: false, reason: `\u8BC4\u5BA1\u6267\u884C\u5931\u8D25\uFF1A${firstLine(result.content)}` };
366
+ const outcome = result.orchestration?.kind === "council" ? result.orchestration : void 0;
367
+ if (outcome?.disabled) {
368
+ return { ok: false, reason: "\u8BC4\u5BA1\u672A\u6267\u884C\uFF08council \u5DF2\u7981\u7528\u6216\u672A\u6D3E\u53D1\u4EFB\u4F55\u5E2D\u4F4D\uFF0CCOUNCIL=0\uFF1F\uFF09" };
369
+ }
370
+ if (!outcome && (result.content.includes("\u5DF2\u7981\u7528") || result.content.includes("\u672A\u6D3E\u53D1\u4EFB\u4F55\u5E2D\u4F4D"))) {
371
+ return { ok: false, reason: "\u8BC4\u5BA1\u672A\u6267\u884C\uFF08council \u5DF2\u7981\u7528\u6216\u672A\u6D3E\u53D1\u4EFB\u4F55\u5E2D\u4F4D\uFF0CCOUNCIL=0\uFF1F\uFF09" };
372
+ }
373
+ if (outcome?.seats && outcome.seats.total > 0 && outcome.seats.passed === 0) {
374
+ return { ok: false, reason: `\u8BAE\u4E8B\u4F1A\u5E2D\u4F4D\u5168\u90E8\u5931\u8D25\uFF08${outcome.seats.total} \u5E2D\u5747\u672A\u4EA7\u51FA\u8D21\u732E\uFF09` };
375
+ }
376
+ const veto = COUNCIL_VETO_RE.exec(result.content);
377
+ if (veto) {
378
+ const reasons = result.content.slice(veto.index).split("\n").filter((l) => l.startsWith("- ")).slice(0, 5).map((l) => l.slice(2));
379
+ return { ok: false, reason: `\u8BAE\u4E8B\u4F1A\u5426\u51B3\uFF08blocking challenge \u672A\u5316\u89E3\uFF09${reasons.length > 0 ? `\uFF1A${reasons.join("\uFF1B")}` : ""}` };
380
+ }
381
+ return { ok: true };
382
+ }
383
+ function teamGate(result) {
384
+ if (result.isError) return { ok: false, reason: `\u6267\u884C\u5931\u8D25\uFF1A${firstLine(result.content)}` };
385
+ const outcome = result.orchestration?.kind === "team" ? result.orchestration : void 0;
386
+ if (outcome) {
387
+ if (outcome.workers.total > 0 && outcome.workers.passed === 0) {
388
+ return { ok: false, reason: "\u6CE2\u6B21 worker \u5168\u90E8\u5931\u8D25" };
389
+ }
390
+ if (outcome.waveGate && !outcome.waveGate.passed) {
391
+ const detail = outcome.waveGate.failures.slice(0, 2).join("\uFF1B");
392
+ return { ok: false, reason: `\u6CE2\u95F4\u786C\u95E8\u7981\u672A\u901A\u8FC7\uFF08${detail || "typecheck/\u9A8C\u8BC1\u547D\u4EE4\u5931\u8D25"}\uFF09` };
393
+ }
394
+ if (outcome.reviewVerdict === "rejected") return { ok: false, reason: "review gate \u9A73\u56DE\u4E86\u672C\u6CE2\u6539\u52A8" };
395
+ if (outcome.dispatched === 0) return { ok: false, reason: "\u672A\u6D3E\u53D1\u4EFB\u4F55 worker\uFF08\u8BA1\u5212\u65E0\u53EF\u6267\u884C\u6CE2\u6B21\uFF09" };
396
+ return { ok: true };
397
+ }
398
+ if (TEAM_ALL_FAILED_RE.test(result.content)) return { ok: false, reason: "\u6CE2\u6B21 worker \u5168\u90E8\u5931\u8D25" };
399
+ if (TEAM_WAVE_GATE_RE.test(result.content)) return { ok: false, reason: "\u6CE2\u95F4\u786C\u95E8\u7981\u672A\u901A\u8FC7\uFF08typecheck/\u9A8C\u8BC1\u547D\u4EE4\u5931\u8D25\uFF09" };
400
+ if (TEAM_REVIEW_REJECTED_RE.test(result.content)) return { ok: false, reason: "review gate \u9A73\u56DE\u4E86\u672C\u6CE2\u6539\u52A8" };
401
+ const dispatched = TEAM_DISPATCHED_RE.exec(result.content);
402
+ if (dispatched && Number(dispatched[1]) === 0) return { ok: false, reason: "\u672A\u6D3E\u53D1\u4EFB\u4F55 worker\uFF08\u8BA1\u5212\u65E0\u53EF\u6267\u884C\u6CE2\u6B21\uFF09" };
403
+ return { ok: true };
404
+ }
405
+ function nextWaveOf(result) {
406
+ const outcome = result.orchestration?.kind === "team" ? result.orchestration : void 0;
407
+ if (outcome) {
408
+ if (outcome.workers.total > 0 && outcome.workers.passed === 0) return void 0;
409
+ return outcome.wave + 1 < outcome.totalWaves ? outcome.wave + 1 : void 0;
410
+ }
411
+ const m = TEAM_NEXT_WAVE_RE.exec(result.content);
412
+ return m ? Number(m[1]) : void 0;
413
+ }
414
+ function galaxyGate(result) {
415
+ if (result.isError) return { ok: false, reason: `\u653B\u575A\u6267\u884C\u5931\u8D25\uFF1A${firstLine(result.content)}` };
416
+ const outcome = result.orchestration?.kind === "galaxy" ? result.orchestration : void 0;
417
+ if (outcome) {
418
+ const { total, passed, failed: failed2 } = outcome.dimensions;
419
+ const failedCount = Math.max(total - passed, failed2.length);
420
+ if (failedCount > 0) {
421
+ return {
422
+ ok: false,
423
+ reason: `${failedCount}/${total} \u4E2A\u7EF4\u5EA6\u672A\u901A\u8FC7${failed2.length > 0 ? `\uFF08${failed2.slice(0, 5).join("\u3001")}\uFF09` : ""}`
424
+ };
425
+ }
426
+ return { ok: true };
427
+ }
428
+ const failed = GALAXY_FAILED_RE.exec(result.content);
429
+ if (failed) {
430
+ const failedDims = [];
431
+ for (const m of result.content.matchAll(GALAXY_DIM_LINE_RE)) failedDims.push(m[1].trim());
432
+ return {
433
+ ok: false,
434
+ reason: `${failed[1]}/${failed[2]} \u4E2A\u7EF4\u5EA6\u672A\u901A\u8FC7${failedDims.length > 0 ? `\uFF08${failedDims.slice(0, 5).join("\u3001")}\uFF09` : ""}`
435
+ };
436
+ }
437
+ return { ok: true };
438
+ }
439
+ function extractPlanJson(content) {
440
+ return COUNCIL_PLAN_JSON_RE.exec(content)?.[1]?.trim() || void 0;
441
+ }
442
+ function absorbTeamBlocks(state, result, wave) {
443
+ const outcome = result.orchestration;
444
+ if (!outcome || typeof outcome !== "object" || outcome.kind !== "team") return;
445
+ const rows = outcome.workerRows;
446
+ if (!rows || rows.length === 0) return;
447
+ const merged = new Map((state.teamBlocks ?? []).map((b) => [b.task, b]));
448
+ for (const row of rows) merged.set(row.task, { ...row, wave });
449
+ state.teamBlocks = [...merged.values()];
450
+ }
451
+ var PHASE_LABELS = {
452
+ council: "\u9636\u6BB5 1 council \u8BC4\u5BA1",
453
+ team: "\u9636\u6BB5 2 team \u6CE2\u6B21",
454
+ galaxy: "\u9636\u6BB5 3 galaxy \u653B\u575A",
455
+ deliver: "\u9636\u6BB5 4 \u4EA4\u4ED8\u95E8\u7981"
456
+ };
457
+ function phaseStatusLine(key, record, note) {
458
+ const label = PHASE_LABELS[key];
459
+ if (!record) return `${label}\uFF1A\u2026 \u672A\u6267\u884C`;
460
+ const icon = record.status === "passed" ? "\u2705" : record.status === "skipped" ? "\u23ED \u8DF3\u8FC7" : "\u26D4 \u53D7\u963B";
461
+ return `${label}\uFF1A${icon}${note ?? ""} \u2014 ${record.summary}`;
462
+ }
463
+ var TEAM_REPORT_ROW_CAP = 24;
464
+ var WORKER_STATUS_ICON = {
465
+ passed: "\u2705",
466
+ failed: "\u26D4",
467
+ blocked: "\u23F8",
468
+ escalated: "\u26A0"
469
+ };
470
+ function fmtTok(n) {
471
+ return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
472
+ }
473
+ function fmtDur(ms) {
474
+ if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
475
+ return `${Math.round(ms / 1e3)}s`;
476
+ }
477
+ function renderTeamBlocks(blocks) {
478
+ const sorted = [...blocks].sort((a, b) => {
479
+ const na = a.status === "passed" ? 1 : 0;
480
+ const nb = b.status === "passed" ? 1 : 0;
481
+ return na - nb || a.wave - b.wave || a.task.localeCompare(b.task);
482
+ });
483
+ const over = sorted.length > TEAM_REPORT_ROW_CAP;
484
+ const shown = over ? sorted.filter((b) => b.status !== "passed").slice(0, TEAM_REPORT_ROW_CAP) : sorted;
485
+ const lines = ["", `\u6CE2\u6B21\u6218\u62A5\uFF08${blocks.length} \u5757 \xB7 \u5931\u8D25\u5728\u524D\uFF1B\u9010\u6CE2\u5168\u91CF\u5728 team phase artifact\uFF09\uFF1A`];
486
+ for (const b of shown) {
487
+ const icon = WORKER_STATUS_ICON[b.status] ?? "\xB7";
488
+ const bits = [];
489
+ bits.push(`${b.changedCount} \u6539\u52A8${b.changedFiles && b.changedFiles.length > 0 ? `(${b.changedFiles.join(",")})` : ""}`);
490
+ if (b.diffArtifactId) bits.push(`diff:${b.diffArtifactId}`);
491
+ if (b.usage) bits.push(`${fmtTok(b.usage.input)}/${fmtTok(b.usage.output)} tok`);
492
+ if (typeof b.durationMs === "number") bits.push(fmtDur(b.durationMs));
493
+ const reason = b.failureReason ? ` ${b.failureReason} \u2014` : b.summary ? "" : "";
494
+ const summary = b.summary ? ` ${b.summary}` : "";
495
+ lines.push(` w${b.wave} ${b.task} ${icon}${reason}${summary}\uFF08${bits.join(" \xB7 ")}\uFF09`);
496
+ }
497
+ if (over) {
498
+ const hidden = sorted.length - shown.length;
499
+ lines.push(` \u2026\u53E6\u6709 ${hidden} \u5757\u672A\u5185\u8054\uFF08\u5DF2\u8FC7\u6216\u8D85\u51FA\u4E0A\u9650\uFF09\uFF0C\u89C1 team phase artifact`);
500
+ }
501
+ const tally = (s) => blocks.filter((b) => b.status === s).length;
502
+ lines.push(` \u5C0F\u8BA1\uFF1A${blocks.length} \u5757 \xB7 \u2705${tally("passed")} \u26D4${tally("failed")} \u23F8${tally("blocked")} \u26A0${tally("escalated")}`);
503
+ return lines;
504
+ }
505
+ function nextStepHint(state) {
506
+ const reason = state.blockedReason ?? "";
507
+ switch (state.phase) {
508
+ case "council":
509
+ if (reason.includes("\u5DF2\u7981\u7528") || reason.includes("\u672A\u6D3E\u53D1\u4EFB\u4F55\u5E2D\u4F4D")) {
510
+ return "\u8BAE\u4E8B\u4F1A\u88AB\u7981\u7528\uFF08COUNCIL=0\uFF09\u3002\u5F00\u542F COUNCIL \u540E\u91CD\u8BD5\uFF0C\u6216\u653E\u5F03\u661F\u6D41\u6539\u7528 team_orchestrate \u76F4\u63A5\u6267\u884C\u3002";
511
+ }
512
+ if (reason.includes("\u5426\u51B3")) {
513
+ return "\u6309\u5426\u51B3\u7406\u7531\u4FEE\u8BA2\u8BA1\u5212\u8349\u7A3F\uFF08draftItems\uFF09\u540E\u91CD\u65B0\u8C03\u7528 starflow\uFF1B\u6216\u4F20 rounds:2 \u8BA9\u5E2D\u4F4D\u590D\u8BAE\u6536\u655B\u3002";
514
+ }
515
+ return "\u67E5\u770B\u4E0A\u65B9\u5931\u8D25\u539F\u56E0\u4FEE\u590D\u540E\u91CD\u8BD5\u3002";
516
+ case "team":
517
+ return "\u4FEE\u590D\u5931\u8D25\u9879\u540E\u7528 starflow({ objective, resume: true }) \u7EED\u8DD1\u2014\u2014council \u5DF2\u8FC7\u95E8\u7981\u4E0D\u4F1A\u91CD\u8DD1\u3002";
518
+ case "galaxy":
519
+ return "\u68C0\u67E5\u5931\u8D25\u7EF4\u5EA6\u4FEE\u590D\u540E\u7528 starflow({ objective, resume: true }) \u7EED\u8DD1\uFF1B\u6216\u5728 galaxyDims \u91CC\u8C03\u6574\u7EF4\u5EA6\u5212\u5206\u3002";
520
+ default:
521
+ return "\u67E5\u770B\u4E0A\u65B9\u539F\u56E0\u4FEE\u590D\u540E\u91CD\u8BD5\u3002";
522
+ }
523
+ }
524
+ function buildReport(state, teamRetried, cwd) {
525
+ const lines = [
526
+ `${GLYPH} \u661F\u6D41\u6267\u884C\u62A5\u544A \xB7 ${firstLine(state.objective, 80)}`,
527
+ "",
528
+ phaseStatusLine("council", state.phases.council),
529
+ phaseStatusLine("team", state.phases.team, teamRetried && state.phases.team?.status === "passed" ? "\uFF08\u590D\u8BAE 1 \u6B21\u540E\u901A\u8FC7\uFF09" : void 0),
530
+ phaseStatusLine("galaxy", state.phases.galaxy),
531
+ phaseStatusLine("deliver", state.phases.deliver)
532
+ ];
533
+ if (state.teamBlocks && state.teamBlocks.length > 0) {
534
+ lines.push(...renderTeamBlocks(state.teamBlocks));
535
+ }
536
+ if (state.phase === "done") {
537
+ lines.push(
538
+ "",
539
+ "\u4EA4\u4ED8\u68C0\u67E5\u6E05\u5355\uFF08deliver_task \u786C\u95E8\u7981\u524D\u7F6E\u81EA\u67E5\uFF09\uFF1A",
540
+ " - typecheck / \u6D4B\u8BD5\u5DF2\u8FD0\u884C\u5E76\u901A\u8FC7\uFF08\u672A\u8FD0\u884C = \u672A\u9A8C\u8BC1\uFF09",
541
+ " - \u6D88\u8D39\u65B9\u8DEF\u5F84\u6838\u5BF9\uFF08\u6539\u52A8\u8BED\u4E49\u901A\u8FBE\uFF09",
542
+ " - RED-GREEN \u8BC1\u636E\u9F50\u5907\uFF08\u5148\u5199\u5931\u8D25\u6D4B\u8BD5\u518D\u5B9E\u73B0\uFF09",
543
+ "",
544
+ "\u4E0B\u4E00\u6B65\uFF1A\u8C03\u7528 deliver_task \u5B8C\u6210\u4EA4\u4ED8\u95E8\u7981\u3002"
545
+ );
546
+ } else {
547
+ lines.push(
548
+ "",
549
+ `\u26D4 \u661F\u6D41\u505C\u6B62\u4E8E ${state.phase} \u9636\u6BB5\uFF1A${state.blockedReason ?? "\u672A\u77E5\u539F\u56E0"}`,
550
+ "",
551
+ `\u4E0B\u4E00\u6B65\u5EFA\u8BAE\uFF1A${nextStepHint(state)}`
552
+ );
553
+ }
554
+ if (cwd) {
555
+ const footer = formatEnvFooter(probeEnvFacts(cwd));
556
+ if (footer) lines.push("", footer);
557
+ }
558
+ return lines.join("\n");
559
+ }
560
+ function subParams(deps, tag) {
561
+ return { ...deps.params, input: {}, toolUseId: `${deps.params.toolUseId}-starflow-${tag}`, cwd: deps.cwd };
562
+ }
563
+ async function runWithPhaseHeartbeat(deps, phase, task) {
564
+ const startedAt = Date.now();
565
+ const heartbeat = setInterval(() => {
566
+ const elapsedS = Math.max(1, Math.round((Date.now() - startedAt) / 1e3));
567
+ deps.params.onOutput?.(`${GLYPH} \u661F\u6D41 \xB7 ${phase} \u9636\u6BB5\u6267\u884C\u4E2D\uFF08\u5DF2 ${elapsedS}s\uFF1B\u5B50\u4EE3\u7406\u6D3B\u52A8\u89C1\u4EFB\u52A1\u9762\u677F\uFF09
568
+ `);
569
+ }, STARFLOW_HEARTBEAT_MS);
570
+ heartbeat.unref?.();
571
+ try {
572
+ return await task();
573
+ } finally {
574
+ clearInterval(heartbeat);
575
+ }
576
+ }
577
+ async function runStarflow(deps, input) {
578
+ const now = () => Date.now();
579
+ const loadedState = input.resume ? loadState(deps.cwd, input.objective, deps.params.sessionId) : void 0;
580
+ const state = loadedState ? { ...loadedState, ...deps.params.sessionId ? { sessionId: deps.params.sessionId } : {} } : freshState(input.objective, now(), deps.params.sessionId, deps.params.toolUseId);
581
+ const lease = acquireStarflowLease(deps.cwd, input.objective, state.runId);
582
+ if (!lease) {
583
+ state.blockedReason = "another Starflow run for this objective is still active; wait for its checkpoint or resume it later";
584
+ return { state, report: buildReport(state, false, deps.cwd), resumed: Boolean(loadedState) };
585
+ }
586
+ try {
587
+ if (loadedState && deps.params.sessionId && loadedState.sessionId !== deps.params.sessionId) {
588
+ saveState(deps.cwd, state);
589
+ }
590
+ const result = await runStarflowUnlocked(deps, input, state);
591
+ return { ...result, resumed: Boolean(loadedState) };
592
+ } finally {
593
+ lease.release();
594
+ }
595
+ }
596
+ async function runStarflowUnlocked(deps, input, state) {
597
+ const now = () => Date.now();
598
+ let teamRetried = false;
599
+ let prewarmFactBlock;
600
+ const phaseStartedAt = /* @__PURE__ */ new Map();
601
+ const phaseOutputs = /* @__PURE__ */ new Map();
602
+ const beginPhase = (phase) => {
603
+ if (!phaseStartedAt.has(phase)) phaseStartedAt.set(phase, now());
604
+ };
605
+ const rememberPhaseOutput = (phase, content) => {
606
+ if (!content.trim()) return;
607
+ const outputs = phaseOutputs.get(phase) ?? [];
608
+ outputs.push(content);
609
+ phaseOutputs.set(phase, outputs);
610
+ };
611
+ const phaseRawContent = (phase, fallback) => {
612
+ const outputs = phaseOutputs.get(phase);
613
+ return outputs && outputs.length > 0 ? outputs.join("\n\n--- phase output ---\n\n") : fallback;
614
+ };
615
+ const phaseElapsed = (phase) => {
616
+ const started = phaseStartedAt.get(phase);
617
+ return started === void 0 ? void 0 : Math.max(0, now() - started);
618
+ };
619
+ const checkpoint = async (phase, record, rawContent) => {
620
+ const persisted = await persistPhaseOutput(deps, state, phase, rawContent);
621
+ state.phases[phase] = { ...record, ...persisted };
622
+ state.updatedAt = now();
623
+ saveState(deps.cwd, state);
624
+ };
625
+ const block = async (phase, reason, summary, rawContent = summary) => {
626
+ state.phase = phase;
627
+ state.blockedReason = reason;
628
+ const elapsedMs = phaseElapsed(phase);
629
+ await checkpoint(phase, { status: "blocked", summary, at: now(), ...elapsedMs === void 0 ? {} : { elapsedMs } }, phaseRawContent(phase, rawContent));
630
+ deps.params.onOutput?.(`${GLYPH} \u661F\u6D41 \xB7 ${phase} \u9636\u6BB5\u5DF2\u4FDD\u5B58\u4E2D\u65AD\u68C0\u67E5\u70B9\uFF0C\u53EF\u7528 resume: true \u7EED\u8DD1
631
+ `);
632
+ return { state, report: buildReport(state, teamRetried, deps.cwd) };
633
+ };
634
+ const pass = async (phase, next, summary, status = "passed", rawContent = summary) => {
635
+ const elapsedMs = phaseElapsed(phase);
636
+ state.phase = next;
637
+ state.blockedReason = void 0;
638
+ await checkpoint(phase, { status, summary, at: now(), ...elapsedMs === void 0 ? {} : { elapsedMs } }, phaseRawContent(phase, rawContent));
639
+ };
640
+ if (state.phase === "council") {
641
+ beginPhase("council");
642
+ deps.params.onOutput?.(`${GLYPH} \u661F\u6D41 \xB7 \u9636\u6BB5 1/4 council \u8BC4\u5BA1
643
+ `);
644
+ const councilInput = { objective: input.objective, confirm: true };
645
+ if (input.draftItems && input.draftItems.length > 0) {
646
+ councilInput.draftItems = input.draftItems;
647
+ councilInput.objective = augmentCouncilObjective(input.objective, input.draftItems, deps.cwd);
648
+ }
649
+ if (input.rounds) councilInput.rounds = input.rounds;
650
+ if (input.seats && input.seats.length > 0) councilInput.seats = input.seats;
651
+ const prewarmFiles = input.draftItems?.flatMap((i) => i.files ?? []) ?? [];
652
+ const prewarmPromise = prewarmFiles.length > 0 ? Promise.all(prewarmFiles.slice(0, 20).map((f) => buildPrewarmValue(deps.cwd, f))).then((vals) => vals.filter((v) => v !== void 0)) : Promise.resolve([]);
653
+ let result;
654
+ try {
655
+ result = await runWithPhaseHeartbeat(deps, "council", () => deps.councilTool.execute({ ...subParams(deps, "council"), input: councilInput }));
656
+ } catch (error) {
657
+ const message = error instanceof Error ? error.message : String(error);
658
+ rememberPhaseOutput("council", message);
659
+ return block("council", `council \u6267\u884C\u4E2D\u65AD\uFF1A${message}`, message);
660
+ }
661
+ const prewarmed = await prewarmPromise;
662
+ prewarmFactBlock = prewarmed.length > 0 ? buildPrewarmFactBlock(prewarmed) : void 0;
663
+ rememberPhaseOutput("council", result.content);
664
+ const gate = councilGate(result);
665
+ if (!gate.ok) return block("council", gate.reason, firstLine(result.content), result.content);
666
+ const planJson = extractPlanJson(result.content);
667
+ if (planJson) state.planJson = planJson;
668
+ await pass("council", "team", firstLine(result.content), "passed", result.content);
669
+ }
670
+ if (state.phase === "team") {
671
+ beginPhase("team");
672
+ deps.params.onOutput?.(`${GLYPH} \u661F\u6D41 \xB7 \u9636\u6BB5 2/4 team \u6CE2\u6B21
673
+ `);
674
+ for (; ; ) {
675
+ let fromWave = (state.completedTeamWaves ?? -1) + 1;
676
+ let lastResult;
677
+ const waveTag = state.teamRetries > 0 ? `team-r${state.teamRetries}` : "team";
678
+ for (let wave = 0; wave < MAX_TEAM_WAVES; wave++) {
679
+ const teamInput = { objective: input.objective, confirm: true, fromWave, autoAdvance: false };
680
+ if (state.planJson) teamInput.planJson = state.planJson;
681
+ try {
682
+ lastResult = await runWithPhaseHeartbeat(deps, "team", () => deps.teamTool.execute({ ...subParams(deps, `${waveTag}-w${fromWave}`), input: teamInput }));
683
+ } catch (error) {
684
+ const message = error instanceof Error ? error.message : String(error);
685
+ rememberPhaseOutput("team", message);
686
+ return block("team", `team \u6267\u884C\u4E2D\u65AD\uFF1A${message}`, message);
687
+ }
688
+ rememberPhaseOutput("team", lastResult.content);
689
+ absorbTeamBlocks(state, lastResult, fromWave);
690
+ const gate = teamGate(lastResult);
691
+ if (!gate.ok) {
692
+ if (state.teamRetries >= 1) return block("team", gate.reason, firstLine(lastResult.content), lastResult.content);
693
+ state.teamRetries++;
694
+ teamRetried = true;
695
+ state.updatedAt = now();
696
+ saveState(deps.cwd, state);
697
+ deps.params.onOutput?.(`${GLYPH} \u661F\u6D41 \xB7 team \u95E8\u7981\u672A\u8FC7\uFF08${gate.reason}\uFF09\u2192 \u56DE council \u590D\u8BAE\uFF08\u4E0A\u9650 1 \u6B21\uFF09
698
+ `);
699
+ const reInput = { objective: input.objective, confirm: true, rounds: 2 };
700
+ if (input.draftItems && input.draftItems.length > 0) {
701
+ reInput.draftItems = input.draftItems;
702
+ reInput.objective = augmentCouncilObjective(input.objective, input.draftItems, deps.cwd, { precheck: false });
703
+ }
704
+ if (input.seats && input.seats.length > 0) reInput.seats = input.seats;
705
+ phaseStartedAt.set("council", now());
706
+ let reResult;
707
+ try {
708
+ reResult = await runWithPhaseHeartbeat(deps, "council", () => deps.councilTool.execute({ ...subParams(deps, "council-retry"), input: reInput }));
709
+ } catch (error) {
710
+ const message = error instanceof Error ? error.message : String(error);
711
+ rememberPhaseOutput("council", message);
712
+ return block("team", `\u590D\u8BAE\u6267\u884C\u4E2D\u65AD\uFF1A${message}`, message);
713
+ }
714
+ rememberPhaseOutput("council", reResult.content);
715
+ const reGate = councilGate(reResult);
716
+ if (!reGate.ok) return block("team", `\u590D\u8BAE\u672A\u8FC7\uFF1A${reGate.reason}`, firstLine(reResult.content), reResult.content);
717
+ state.planJson = extractPlanJson(reResult.content) ?? state.planJson;
718
+ const reElapsedMs = phaseElapsed("council");
719
+ await checkpoint("council", {
720
+ status: reGate.ok ? "passed" : "blocked",
721
+ summary: firstLine(reResult.content),
722
+ at: now(),
723
+ ...reElapsedMs === void 0 ? {} : { elapsedMs: reElapsedMs }
724
+ }, phaseRawContent("council", reResult.content));
725
+ break;
726
+ }
727
+ if (state.completedTeamWaves === void 0 || fromWave > state.completedTeamWaves) {
728
+ state.completedTeamWaves = fromWave;
729
+ state.updatedAt = now();
730
+ saveState(deps.cwd, state);
731
+ }
732
+ const next = nextWaveOf(lastResult);
733
+ if (next === void 0) break;
734
+ fromWave = next;
735
+ if (wave === MAX_TEAM_WAVES - 1) {
736
+ return block("team", `\u6CE2\u6B21\u63A8\u8FDB\u8D85\u8FC7\u4E0A\u9650\uFF08${MAX_TEAM_WAVES}\uFF09\u2014\u2014\u5F02\u5E38\u7EED\u6CE2\u5FAA\u73AF`, firstLine(lastResult.content), lastResult.content);
737
+ }
738
+ }
739
+ if (lastResult && !teamGate(lastResult).ok) continue;
740
+ await pass("team", "galaxy", firstLine(lastResult?.content ?? ""), "passed", lastResult?.content ?? "");
741
+ break;
742
+ }
743
+ }
744
+ if (state.phase === "galaxy") {
745
+ beginPhase("galaxy");
746
+ const derived = input.galaxyDims ?? deriveGalaxyDims(input.draftItems);
747
+ const rawPlanJson = state.planJson;
748
+ const planJsonConstraints = rawPlanJson ? (() => {
749
+ const plan = deserializeUnifiedPlan(rawPlanJson);
750
+ if (!plan) return void 0;
751
+ const rendered = constraintsFromUnifiedPlan({
752
+ nonGoals: plan.nonGoals,
753
+ obligations: plan.obligations?.map((o) => ({ kind: o.kind, text: o.text }))
754
+ });
755
+ return rendered.length > 0 ? rendered : void 0;
756
+ })() : void 0;
757
+ const withPlanConstraints = (d) => planJsonConstraints ? { ...d, constraints: [...d.constraints ?? [], ...planJsonConstraints] } : d;
758
+ const dimsWithFacts = !input.galaxyDims && prewarmFactBlock ? derived.map((d) => ({ ...d, objective: `${prewarmFactBlock}
759
+
760
+ ${d.objective}` })) : derived;
761
+ if (dimsWithFacts.length < 2) {
762
+ const why = input.galaxyDims ? `\u663E\u5F0F galaxyDims \u4EC5 ${dimsWithFacts.length} \u4E2A\uFF08min 2\uFF09\uFF0C\u8DF3\u8FC7\u653B\u575A` : "\u65E0 draftItems \u53EF\u6D3E\u751F\u7EF4\u5EA6\uFF0C\u8DF3\u8FC7\u653B\u575A";
763
+ await pass("galaxy", "deliver", why, "skipped");
764
+ } else {
765
+ deps.params.onOutput?.(`${GLYPH} \u661F\u6D41 \xB7 \u9636\u6BB5 3/4 galaxy \u653B\u575A\uFF08${dimsWithFacts.length} \u7EF4\u5EA6\uFF09
766
+ `);
767
+ const dims = dimsWithFacts.slice(0, 5).map(withPlanConstraints);
768
+ let result;
769
+ try {
770
+ result = await runWithPhaseHeartbeat(deps, "galaxy", () => deps.galaxyTool.execute({
771
+ ...subParams(deps, "galaxy"),
772
+ input: { objective: input.objective, dimensions: dims, autoReview: input.autoReview ?? true, confirm: true }
773
+ }));
774
+ } catch (error) {
775
+ const message = error instanceof Error ? error.message : String(error);
776
+ rememberPhaseOutput("galaxy", message);
777
+ return block("galaxy", `galaxy \u6267\u884C\u4E2D\u65AD\uFF1A${message}`, message);
778
+ }
779
+ rememberPhaseOutput("galaxy", result.content);
780
+ const gate = galaxyGate(result);
781
+ if (!gate.ok) return block("galaxy", gate.reason, firstLine(result.content), result.content);
782
+ const truncated = derived.length > 5 ? `\uFF08\u8349\u7A3F ${derived.length} \u9879\u622A\u65AD\u4E3A 5 \u7EF4\uFF09` : "";
783
+ await pass("galaxy", "deliver", `${firstLine(result.content)}${truncated}`, "passed", result.content);
784
+ }
785
+ }
786
+ if (state.phase === "deliver") {
787
+ beginPhase("deliver");
788
+ await pass("deliver", "done", "\u4EA4\u4ED8\u6E05\u5355\u5DF2\u8F93\u51FA\uFF0C\u5F85\u8C03\u7528 deliver_task");
789
+ }
790
+ return { state, report: buildReport(state, teamRetried, deps.cwd) };
791
+ }
792
+
793
+ // src/tools/starflow.ts
794
+ var GLYPH2 = "\u{1F320}";
795
+ var draftItemSchema = external_exports.object({
796
+ id: external_exports.string().min(1),
797
+ title: external_exports.string(),
798
+ detail: external_exports.string(),
799
+ files: external_exports.array(external_exports.string()).optional(),
800
+ revision: external_exports.number().int().optional(),
801
+ previousVerdict: external_exports.literal("passed").optional()
802
+ });
803
+ var seatSchema = external_exports.object({
804
+ authority: external_exports.string().min(1),
805
+ charter: external_exports.string().optional(),
806
+ tierHint: external_exports.enum(["cheap", "balanced", "strong"]).optional(),
807
+ noDowngrade: external_exports.boolean().optional(),
808
+ provider: external_exports.string().optional(),
809
+ model: external_exports.string().optional()
810
+ });
811
+ var dimensionSchema = external_exports.object({
812
+ name: external_exports.string().min(1),
813
+ objective: external_exports.string().min(1),
814
+ authority: external_exports.string().optional(),
815
+ authorities: external_exports.array(external_exports.string()).min(2).max(5).optional(),
816
+ parallelism: external_exports.enum(["expert", "data"]).optional(),
817
+ replicas: external_exports.number().int().min(2).max(5).optional(),
818
+ profile: external_exports.string().optional(),
819
+ tierFloor: external_exports.enum(["cheap", "balanced", "strong"]).optional(),
820
+ files: external_exports.array(external_exports.string()).optional(),
821
+ symbols: external_exports.array(external_exports.string()).optional(),
822
+ maxTurns: external_exports.number().int().optional(),
823
+ timeoutMs: external_exports.number().int().optional(),
824
+ modelOverride: external_exports.object({ provider: external_exports.string(), model: external_exports.string() }).optional()
825
+ });
826
+ var inputSchema = external_exports.object({
827
+ objective: external_exports.string().min(1),
828
+ draftItems: external_exports.array(draftItemSchema).optional(),
829
+ galaxyDims: external_exports.array(dimensionSchema).min(2).max(5).optional(),
830
+ rounds: external_exports.union([external_exports.literal(1), external_exports.literal(2)]).optional(),
831
+ autoReview: external_exports.boolean().optional(),
832
+ seats: external_exports.array(seatSchema).optional(),
833
+ confirm: external_exports.boolean().optional(),
834
+ resume: external_exports.boolean().optional()
835
+ });
836
+ function timeoutDraftItems(value) {
837
+ if (!Array.isArray(value)) return void 0;
838
+ return value.filter((item) => {
839
+ if (!item || typeof item !== "object") return false;
840
+ const candidate = item;
841
+ return typeof candidate.id === "string" && typeof candidate.title === "string" && typeof candidate.detail === "string";
842
+ });
843
+ }
844
+ function timeoutGalaxyDims(value) {
845
+ if (!Array.isArray(value)) return void 0;
846
+ return value.filter((dimension) => {
847
+ if (!dimension || typeof dimension !== "object") return false;
848
+ const candidate = dimension;
849
+ return typeof candidate.name === "string" && typeof candidate.objective === "string";
850
+ });
851
+ }
852
+ function formatProposal(objective, rounds, dims, derivedFromDrafts, statePath, envBlock = "") {
853
+ const lines = [
854
+ `${GLYPH2} \u661F\u6D41\u6267\u884C\u65B9\u6848`,
855
+ "",
856
+ `\u76EE\u6807\uFF1A${objective}`,
857
+ "",
858
+ "\u5C06\u6267\u884C\u7684\u9636\u6BB5\uFF08\u72B6\u6001\u673A\u786C\u95E8\u7981\u4E32\u8054\uFF0C\u4EFB\u4E00\u4E0D\u8FC7\u5373 blocked \u5E76\u505C\u6B62\uFF09\uFF1A",
859
+ ` 1. council \u8BC4\u5BA1 \u2014 \u591A\u5E2D\u5BA1\u67E5\u8BA1\u5212\u8349\u7A3F\uFF0C\u4EA7\u51FA\u5BC6\u5C01\u6267\u884C\u5951\u7EA6\uFF08rounds: ${rounds}\uFF09`,
860
+ " 2. team \u6CE2\u6B21 \u2014 \u6309\u5951\u7EA6\u5206\u6CE2\u6D3E\u53D1 worker\uFF1B\u5931\u8D25\u81EA\u52A8\u56DE council \u590D\u8BAE\u4E00\u6B21\uFF0C\u518D\u8D25\u5373 blocked"
861
+ ];
862
+ if (dims.length >= 2) {
863
+ lines.push(` 3. galaxy \u653B\u575A \u2014 ${dims.length} \u4E2A\u7EF4\u5EA6\u5E76\u884C${derivedFromDrafts ? "\uFF08\u4ECE draftItems \u6D3E\u751F\uFF09" : ""}\uFF1A${dims.map((d) => d.name).join("\u3001")}`);
864
+ } else {
865
+ lines.push(" 3. galaxy \u653B\u575A \u2014 \u8DF3\u8FC7\uFF08\u65E0\u663E\u5F0F galaxyDims\uFF0C\u4E5F\u65E0\u6CD5\u4ECE draftItems \u6D3E\u751F\u51FA \u22652 \u4E2A\u7EF4\u5EA6\uFF09");
866
+ }
867
+ lines.push(
868
+ " 4. \u4EA4\u4ED8\u95E8\u7981 \u2014 \u8F93\u51FA\u4EA4\u4ED8\u68C0\u67E5\u6E05\u5355\uFF0C\u63D0\u793A\u8C03\u7528 deliver_task\uFF08\u786C\u95E8\u7981\u5F52 deliver_task\uFF09",
869
+ ""
870
+ );
871
+ if (envBlock) lines.push(envBlock, "");
872
+ lines.push(
873
+ `\u72B6\u6001\u6301\u4E45\u5316\uFF1A${statePath}\uFF08blocked/\u4E2D\u65AD\u540E\u53EF\u7528 resume: true \u7EED\u8DD1\uFF0C\u5DF2\u8FC7\u9636\u6BB5\u4E0D\u91CD\u8DD1\uFF09`,
874
+ "",
875
+ "\u8C03\u7528 starflow({..., confirm: true}) \u70B9\u706B\u6267\u884C\u3002"
876
+ );
877
+ return lines.join("\n");
878
+ }
879
+ function createStarflowTool(deps) {
880
+ return {
881
+ definition: {
882
+ name: "starflow",
883
+ description: `\u661F\u6D41\u7F16\u6392\u2014\u2014\u628A\u590D\u6742\u4EFB\u52A1\u4EA4\u7ED9\u72B6\u6001\u673A\u4E32\u8D77 council \u8BC4\u5BA1 \u2192 team \u6CE2\u6B21 \u2192 galaxy \u653B\u575A\u4E09\u6BB5\uFF0C\u9636\u6BB5\u95F4\u786C\u95E8\u7981\u515C\u5E95\uFF08\u8BC4\u5BA1\u672A\u6267\u884C/\u88AB\u5426\u51B3\u3001\u6CE2\u6B21\u5931\u8D25\u3001\u653B\u575A\u672A\u901A\u8FC7\u90FD\u4F1A blocked \u505C\u6B62\u5E76\u7ED9\u51FA\u4EBA\u8BDD\u89E3\u91CA\uFF09\uFF0C\u72B6\u6001\u843D\u76D8\u652F\u6301 resume \u7EED\u8DD1\u3002
884
+
885
+ ## \u4F55\u65F6\u4F7F\u7528
886
+ - \u7528\u6237\u8D70 /starflow \u6216\u660E\u786E\u8981\u6C42\u300C\u661F\u6D41\u300D\u5168\u6D41\u7A0B\uFF08\u8BC4\u5BA1+\u6267\u884C+\u653B\u575A\u4E00\u4F53\uFF09
887
+ - \u590D\u6742\u5DE5\u7A0B\u4EFB\u52A1\u9700\u8981\u8BC4\u5BA1-\u6267\u884C-\u653B\u575A\u7684\u786E\u5B9A\u6027\u4E32\u8054\uFF0C\u800C\u4E0D\u662F\u6A21\u578B\u81EA\u89C9\u8D70\u6D41\u7A0B
888
+
889
+ ## \u8C03\u7528\u534F\u8BAE\uFF08\u4E24\u9636\u6BB5\uFF09
890
+ 1. \u9996\u6B21\u8C03\u7528 starflow({objective, draftItems?, galaxyDims?, confirm: false}) \u5C55\u793A\u6267\u884C\u65B9\u6848\uFF0C\u7B49\u5F85\u7528\u6237\u786E\u8BA4
891
+ 2. \u7528\u6237\u786E\u8BA4\u540E\u8C03\u7528 starflow({..., confirm: true}) \u70B9\u706B\u6267\u884C
892
+
893
+ ## \u53C2\u6570\u8981\u70B9
894
+ - draftItems\uFF1A\u9700\u6C42\u6F84\u6E05\u540E\u7684\u8BA1\u5212\u8349\u7A3F\uFF08id/title/detail/files\uFF09\uFF0C\u5582\u7ED9 council \u8BC4\u5BA1\uFF1BgalaxyDims \u7F3A\u7701\u65F6\u4E5F\u4ECE\u5B83\u6D3E\u751F\u7EF4\u5EA6\u3002\u4FEE\u8BA2\u91CD\u63D0\u65F6\uFF1A\u672A\u53D8\u6761\u76EE\u4FDD\u6301 revision \u4E0D\u53D8\u5E76\u6807 previousVerdict:'passed'\uFF08starflow \u4F1A\u5728\u8BC4\u5BA1\u6E32\u67D3\u4E2D\u6807\u6CE8\u300C\u6CBF\u7528\u524D\u8F6E\u901A\u8FC7\u7ED3\u8BBA\u300D\uFF0C\u4E0D\u91CD\u5BA1\uFF09\uFF1B\u4FEE\u8BA2\u6761\u76EE bump revision \u65F6**\u5FC5\u987B\u540C\u65F6\u79FB\u9664 previousVerdict**\u2014\u2014\u4E24\u5B57\u6BB5\u540C\u73B0\u7684\u6761\u76EE\u88AB\u89C6\u4E3A\u5DF2\u4FEE\u8BA2\uFF0C\u91CD\u65B0\u8BC4\u5BA1\u4E0D\u6CBF\u7528
895
+ - seats\uFF1Acouncil \u5E2D\u4F4D\u8986\u76D6\uFF08\u540C council_convene \u7684 seats\uFF0Cauthority/charter/tierHint/provider/model\uFF09\u3002**\u4FEE\u8BA2\u8F6E\u63A8\u8350\u53EA\u53EC\u56DE\u300C\u4E0A\u8F6E\u5426\u51B3\u7684\u5E2D\u4F4D + \u4E0E\u4FEE\u8BA2\u70B9\u76F8\u5173\u7684\u57DF\u5E2D\u300D\uFF0C\u800C\u975E\u9ED8\u8BA4\u5168\u91CF**\u2014\u2014\u6210\u672C\u7ACB\u964D\u4E14\u5426\u51B3\u62E6\u622A\u529B\u4E0D\u51CF
896
+ - galaxyDims\uFF1A\u663E\u5F0F\u653B\u575A\u7EF4\u5EA6\uFF082-5 \u4E2A\uFF0C\u7ED3\u6784\u540C galaxy \u5DE5\u5177\u7684 dimensions\uFF09\uFF1B\u7F3A\u7701\u6309 draftItems \u6D3E\u751F\uFF0C\u6D3E\u751F\u4E0D\u51FA \u22652 \u4E2A\u5219\u8DF3\u8FC7\u653B\u575A\u9636\u6BB5
897
+ - rounds\uFF1Acouncil \u8FA9\u8BBA\u8F6E\u6570\uFF081-2\uFF0C\u9ED8\u8BA4 1\uFF1B\u9AD8\u98CE\u9669\u4EFB\u52A1\u4F20 2\uFF09\u3002\u26A0 rounds\u22652 \u53D7 councilMultiRound Pro \u95E8\u94B3\u5236\u2014\u2014Basic \u672A\u542F\u7528\u65F6\u964D\u7EA7\u5355\u8F6E\u7EE7\u7EED\uFF08\u4E0D\u62D2\u7EDD\uFF09\uFF0C\u8F93\u51FA\u6807\u6CE8\u300C\u5DF2\u6309\u5355\u8F6E\u6267\u884C\u2014\u2014Pro \u95E8\u300D
898
+ - resume\uFF1Ablocked/\u4E2D\u65AD\u540E\u4F20 true \u4ECE\u72B6\u6001\u6587\u4EF6\u7EED\u8DD1\uFF0C\u5DF2\u8FC7\u95E8\u7981\u7684\u9636\u6BB5\u4E0D\u91CD\u590D\u6267\u884C
899
+
900
+ ## \u51FA\u53E3
901
+ \u5168\u8FC7\u540E\u8F93\u51FA\u4EA4\u4ED8\u68C0\u67E5\u6E05\u5355\u2014\u2014\u8C03\u7528 deliver_task \u5B8C\u6210\u4EA4\u4ED8\u95E8\u7981\uFF08\u672A\u8FD0\u884C = \u672A\u9A8C\u8BC1\uFF09\u3002`,
902
+ input_schema: {
903
+ type: "object",
904
+ properties: {
905
+ objective: { type: "string", description: "\u661F\u6D41\u603B\u76EE\u6807\u2014\u2014\u9700\u6C42\u6F84\u6E05\u540E\u7684\u5B8C\u6574\u4EFB\u52A1\u63CF\u8FF0\u3002" },
906
+ draftItems: {
907
+ type: "array",
908
+ description: '\u8BA1\u5212\u8349\u7A3F\u6761\u76EE\uFF08\u4F9B council \u8BC4\u5BA1\uFF1BgalaxyDims \u7F3A\u7701\u65F6\u6309\u5B83\u6D3E\u751F\u653B\u575A\u7EF4\u5EA6\uFF09\u3002\u4FEE\u8BA2\u91CD\u63D0\u65F6\u672A\u53D8\u6761\u76EE\u6807 previousVerdict:"passed"\uFF08\u6E32\u67D3\u4E3A\u6CBF\u7528\u524D\u8F6E\u901A\u8FC7\u7ED3\u8BBA\uFF0C\u4E0D\u91CD\u5BA1\uFF09\u3002',
909
+ items: {
910
+ type: "object",
911
+ properties: {
912
+ id: { type: "string" },
913
+ title: { type: "string" },
914
+ detail: { type: "string" },
915
+ files: { type: "array", items: { type: "string" }, description: "\u8BE5\u6761\u76EE\u6D89\u53CA\u7684\u6587\u4EF6\uFF08team \u6CE2\u6B21\u5206\u7EC4 / galaxy \u7EF4\u5EA6 scope\uFF09\u3002" },
916
+ revision: { type: "integer", description: "\u4FEE\u8BA2\u8BB0\u8D26\uFF1A\u4FEE\u8BA2\u91CD\u63D0\u65F6 bump\uFF1B\u672A\u53D8\u6761\u76EE\u4FDD\u6301\u539F\u503C\u3002" },
917
+ previousVerdict: { type: "string", enum: ["passed"], description: "\u4E0A\u4E00\u8F6E\u8BC4\u5BA1\u5DF2\u901A\u8FC7\u4E14\u672C\u8F6E\u672A\u53D8\u2014\u2014\u8BC4\u5BA1\u6E32\u67D3\u4E2D\u6807\u6CE8\u300C\u6CBF\u7528\u524D\u8F6E\u901A\u8FC7\u7ED3\u8BBA\u300D\uFF0C\u9664\u975E\u4E0E\u5176\u4ED6\u6761\u76EE\u51B2\u7A81\u5426\u5219\u4E0D\u91CD\u5BA1\u3002" }
918
+ },
919
+ required: ["id", "title", "detail"]
920
+ }
921
+ },
922
+ galaxyDims: {
923
+ type: "array",
924
+ description: "\u663E\u5F0F galaxy \u653B\u575A\u7EF4\u5EA6\uFF082-5 \u4E2A\uFF0C\u7ED3\u6784\u540C galaxy \u5DE5\u5177\u7684 dimensions\uFF09\u3002\u7F3A\u7701\u65F6\u4ECE draftItems \u6D3E\u751F\u3002",
925
+ items: {
926
+ type: "object",
927
+ properties: {
928
+ name: { type: "string", description: "\u7EF4\u5EA6\u6807\u8BC6\uFF08\u5982 frontend / review / docs\uFF09" },
929
+ objective: { type: "string", description: "\u8BE5\u7EF4\u5EA6\u7684\u5177\u4F53\u6267\u884C\u76EE\u6807" },
930
+ authority: { type: "string", description: "\u8BE5\u7EF4\u5EA6\u4F7F\u7528\u7684\u661F\u57DF id\uFF08\u5355\u661F\u57DF\uFF0C\u4E0E authorities \u4E8C\u9009\u4E00\uFF09\u3002" },
931
+ authorities: { type: "array", items: { type: "string" }, description: "\u591A\u661F\u57DF\u72EC\u7ACB\u53EA\u8BFB\u89C6\u89D2\uFF08\u4E0E authority \u4E8C\u9009\u4E00\uFF09\u3002" },
932
+ parallelism: { type: "string", enum: ["expert", "data"], description: "expert \u5355\u5206\u7247\u6D3E\u53D1\uFF1Bdata \u72EC\u7ACB\u53EA\u8BFB\u526F\u672C\u3002" },
933
+ replicas: { type: "integer", minimum: 2, maximum: 5, description: "\u4EC5 data \u6A21\u5F0F\uFF1A\u72EC\u7ACB\u526F\u672C\u6570\u3002" },
934
+ profile: { type: "string", description: "worker profile\u3002\u7701\u7565\u65F6\u6309\u7EF4\u5EA6\u540D\u63A8\u5BFC\u3002" },
935
+ tierFloor: { type: "string", enum: ["cheap", "balanced", "strong"], description: "\u6A21\u578B\u6863\u4F4D\u786C\u5730\u677F\u3002" },
936
+ files: { type: "array", items: { type: "string" }, description: "\u53EF\u9009\uFF0C\u805A\u7126\u7684\u6587\u4EF6\u8DEF\u5F84\u3002" },
937
+ symbols: { type: "array", items: { type: "string" }, description: "\u53EF\u9009\uFF0C\u805A\u7126\u7684\u7B26\u53F7\u3002" },
938
+ maxTurns: { type: "integer", description: "\u8BE5\u7EF4\u5EA6 worker \u7684\u6700\u5927\u8F6E\u6B21\u3002" },
939
+ timeoutMs: { type: "integer", description: "\u8BE5\u7EF4\u5EA6 worker \u7684\u8D85\u65F6\u9884\u7B97\u3002" },
940
+ modelOverride: { type: "object", properties: { provider: { type: "string" }, model: { type: "string" } }, description: "\u53EF\u9009\uFF0C\u4E3A\u8BE5\u7EF4\u5EA6\u6307\u5B9A\u4E13\u7528 provider/model\u3002" }
941
+ },
942
+ required: ["name", "objective"]
943
+ },
944
+ minItems: 2,
945
+ maxItems: 5
946
+ },
947
+ rounds: { type: "number", enum: [1, 2], description: "council \u8FA9\u8BBA\u8F6E\u6570\uFF08\u9ED8\u8BA4 1\uFF1B\u9AD8\u98CE\u9669\u4EFB\u52A1\u4F20 2 \u542F\u7528\u53CD\u9A73\u8F6E\uFF09\u3002\u26A0 rounds\u22652 \u53D7 councilMultiRound Pro \u95E8\u94B3\u5236\u2014\u2014Basic \u672A\u542F\u7528\u65F6\u964D\u7EA7\u5355\u8F6E\u7EE7\u7EED\uFF08\u4E0D\u62D2\u7EDD\uFF09\uFF0C\u8F93\u51FA\u6807\u6CE8\u300C\u5DF2\u6309\u5355\u8F6E\u6267\u884C\u2014\u2014Pro \u95E8\u300D\u3002" },
948
+ autoReview: { type: "boolean", default: true, description: "Whether Galaxy adds the automatic review wave; defaults to true." },
949
+ seats: {
950
+ type: "array",
951
+ description: "council \u5E2D\u4F4D\u8986\u76D6\uFF08\u540C council_convene \u7684 seats\uFF0C\u900F\u4F20\u5230\u9996\u8F6E\u4E0E\u590D\u8BAE\u8F6E\uFF09\u3002\u4FEE\u8BA2\u8F6E\u63A8\u8350\u53EA\u53EC\u56DE\u300C\u4E0A\u8F6E\u5426\u51B3\u7684\u5E2D\u4F4D + \u4E0E\u4FEE\u8BA2\u70B9\u76F8\u5173\u7684\u57DF\u5E2D\u300D\uFF0C\u800C\u975E\u9ED8\u8BA4\u5168\u91CF\u3002",
952
+ items: {
953
+ type: "object",
954
+ properties: {
955
+ authority: { type: "string", description: "\u661F\u57DF id\uFF08\u6BCF\u5E2D\u5FC5\u987B\u4E0D\u540C\uFF09\u3002" },
956
+ charter: { type: "string", description: "\u5E2D\u4F4D\u7AE0\u7A0B\u2014\u2014\u8BE5\u5E2D\u672C\u6B21\u8BC4\u5BA1\u7684\u4E13\u5C5E\u804C\u8D23\u3002" },
957
+ tierHint: { type: "string", enum: ["cheap", "balanced", "strong"], description: "\u6A21\u578B\u6863\u4F4D\u63D0\u793A\u3002" },
958
+ noDowngrade: { type: "boolean", description: "\u7981\u6B62\u964D\u6863\u3002" },
959
+ provider: { type: "string", description: "\u5355\u5E2D\u4F4D provider\uFF08\u4E0E model \u914D\u5BF9\u4F7F\u7528\uFF09\u3002" },
960
+ model: { type: "string", description: "\u5355\u5E2D\u4F4D\u6A21\u578B\uFF08\u5FC5\u987B\u5B58\u5728\u4E8E\u8BE5 provider\uFF09\u3002" }
961
+ },
962
+ required: ["authority"]
963
+ }
964
+ },
965
+ confirm: { type: "boolean", description: "\u7528\u6237\u5DF2\u786E\u8BA4\u661F\u6D41\u65B9\u6848\u3002\u9996\u6B21\u8C03\u7528\u4E0D\u5E26\u6B64\u53C2\u6570\u4EE5\u5C55\u793A\u65B9\u6848\u5E76\u8BF7\u6C42\u786E\u8BA4\u3002" },
966
+ resume: { type: "boolean", description: "\u4ECE .rivet/starflow/ \u72B6\u6001\u6587\u4EF6\u7EED\u8DD1\u2014\u2014\u5DF2\u8FC7\u95E8\u7981\u7684\u9636\u6BB5\u4E0D\u91CD\u590D\u6267\u884C\u3002" }
967
+ },
968
+ required: ["objective"]
969
+ }
970
+ },
971
+ async execute(params) {
972
+ const parsed = inputSchema.safeParse(params.input);
973
+ if (!parsed.success) {
974
+ return { content: `\u661F\u6D41\u53C2\u6570\u9519\u8BEF\uFF1A${parsed.error.message}`, isError: true, errorKind: "format_error" };
975
+ }
976
+ const { objective, draftItems, galaxyDims, rounds, seats, autoReview, confirm, resume } = parsed.data;
977
+ const dims = galaxyDims ?? deriveGalaxyDims(draftItems);
978
+ const contractIssues = validateGalaxyDimensionContract(dims);
979
+ if (contractIssues.length > 0) {
980
+ return {
981
+ content: [
982
+ "Starflow Galaxy contract validation failed:",
983
+ ...contractIssues.map((issue) => "- dimension #" + (issue.dimensionIndex + 1) + ": " + issue.message)
984
+ ].join("\n"),
985
+ isError: true,
986
+ errorKind: "format_error"
987
+ };
988
+ }
989
+ if (!confirm) {
990
+ return {
991
+ content: formatProposal(objective, rounds ?? 1, dims, !galaxyDims, starflowStatePath(deps.cwd, objective, params.sessionId), formatEnvPrecheckBlock(probeEnvFacts(deps.cwd))),
992
+ uiContent: `${GLYPH2} \u661F\u6D41\u65B9\u6848 \xB7 ${dims.length >= 2 ? `${dims.length} \u7EF4\u5EA6` : "\u65E0\u653B\u575A\u7EF4\u5EA6"}`
993
+ };
994
+ }
995
+ const run = await runStarflow(
996
+ { councilTool: deps.councilTool, teamTool: deps.teamTool, galaxyTool: deps.galaxyTool, cwd: deps.cwd, params },
997
+ { objective, ...draftItems ? { draftItems } : {}, ...galaxyDims ? { galaxyDims } : {}, ...rounds ? { rounds } : {}, ...seats && seats.length > 0 ? { seats } : {}, ...autoReview === void 0 ? {} : { autoReview }, ...resume ? { resume } : {} }
998
+ );
999
+ const blocked = run.state.phase !== "done";
1000
+ return {
1001
+ content: run.report,
1002
+ orchestration: {
1003
+ kind: "starflow",
1004
+ runId: run.state.runId,
1005
+ phase: run.state.phase,
1006
+ done: !blocked,
1007
+ resumed: run.resumed ?? Boolean(resume),
1008
+ revision: run.state.revision,
1009
+ phases: Object.fromEntries(
1010
+ Object.entries(run.state.phases).map(([phase, record]) => [phase, {
1011
+ status: record?.status,
1012
+ at: record?.at,
1013
+ ...record?.elapsedMs === void 0 ? {} : { elapsedMs: record.elapsedMs }
1014
+ }])
1015
+ )
1016
+ },
1017
+ // blocked 是工具管线的失败信号(同 galaxy DP quorum 未达成的 isError 先例)。
1018
+ isError: blocked || void 0,
1019
+ uiContent: `${GLYPH2} \u661F\u6D41 \xB7 ${blocked ? `\u53D7\u963B\u4E8E ${run.state.phase} \u9636\u6BB5` : "\u5168\u9636\u6BB5\u901A\u8FC7\uFF0C\u5F85\u4EA4\u4ED8"}`
1020
+ };
1021
+ },
1022
+ requiresApproval: () => false,
1023
+ isConcurrencySafe: () => false,
1024
+ isEnabled: () => true,
1025
+ // 外层超时必须覆盖三阶段串行预算(同 galaxy.ts 思路:delegationToolTimeoutMs
1026
+ // 按 profile/波次/续跑倍率算单段,三段相加)。galaxy 维度未知时按 2 维估。
1027
+ timeoutMs: (params) => {
1028
+ const turnCount = params?.sessionTurnCount;
1029
+ const councilMs = delegationToolTimeoutMs(turnCount, [void 0, void 0, void 0], { taskCount: 3 });
1030
+ const teamMs = delegationToolTimeoutMs(turnCount, ["patcher", "patcher", "patcher"], { taskCount: 3 });
1031
+ const rawDims = timeoutGalaxyDims(params?.input?.galaxyDims);
1032
+ const draftItems = timeoutDraftItems(params?.input?.draftItems);
1033
+ const dims = rawDims ?? deriveGalaxyDims(draftItems);
1034
+ const executableDims = dims.length >= 2 ? dims : [];
1035
+ const budgetInputs = buildGalaxyBudgetInputs(executableDims);
1036
+ const galaxyMs = budgetInputs.profiles.length > 0 ? delegationToolTimeoutMs(turnCount, budgetInputs.profiles, {
1037
+ taskCount: budgetInputs.profiles.length,
1038
+ requestedTimeoutMs: budgetInputs.requestedTimeoutMs,
1039
+ tierFloors: budgetInputs.tierFloors
1040
+ }) : 0;
1041
+ const autoReview = params?.input?.autoReview ?? true;
1042
+ const hasExplicitReview = executableDims.some((d) => isReviewGalaxyDimension(d.name));
1043
+ const reviewMs = autoReview && executableDims.length > 0 && !hasExplicitReview ? delegationToolTimeoutMs(turnCount, ["reviewer"], { taskCount: 1 }) : 0;
1044
+ return councilMs + teamMs + galaxyMs + reviewMs;
1045
+ }
1046
+ };
1047
+ }
1048
+
1049
+ export {
1050
+ createStarflowTool
1051
+ };