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
package/dist/main.js ADDED
@@ -0,0 +1,4064 @@
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
+ buildCockpitSnapshot
5
+ } from "./chunk-FFQSZJOO.js";
6
+ import {
7
+ DOMAIN_SWITCH_CACHE_WARNING,
8
+ HANDOFF_NUDGE_RATIO,
9
+ TuiApp,
10
+ aggregateUsageRows,
11
+ approvePlanAndKickoff,
12
+ boxCharsFor,
13
+ buildDomainPickerEntries,
14
+ checkForUpdate,
15
+ collectUsageRows,
16
+ computeUsageCost,
17
+ configureSpinnerVerbs,
18
+ detectInstallRoot,
19
+ displayWidth,
20
+ filterCommands,
21
+ findModelPricing,
22
+ formatElapsed,
23
+ formatHandoffNudge,
24
+ formatMilestoneLine,
25
+ formatPlanReviewDate,
26
+ formatUpdateBanner,
27
+ generateGreetingLlm,
28
+ getCurrentVersion,
29
+ getDeepSeekUserSummary,
30
+ getOnboardingState,
31
+ getPaletteCommands,
32
+ loadHistory,
33
+ loadPlatformAuth,
34
+ markWelcomeGuideShown,
35
+ parseScrollbackTranscript,
36
+ pickGreetingTemplate,
37
+ queryDeepSeekBalance,
38
+ registerTuiSlashCommands,
39
+ resolveAppPromptInput,
40
+ resolveAutoApproveMs,
41
+ resolveOrchestrationHintEnabled,
42
+ searchHistory,
43
+ setReducedMotion,
44
+ shouldArm,
45
+ shouldShowWelcomeGuide,
46
+ truncateToDisplayWidth,
47
+ useAsciiBorders
48
+ } from "./chunk-5B2OCU5P.js";
49
+ import {
50
+ tapAgentCallbacks
51
+ } from "./chunk-V5DHFGI7.js";
52
+ import "./chunk-ML3UKMH3.js";
53
+ import {
54
+ commitWelcomeStellarIdentityLine
55
+ } from "./chunk-AOVQ7VIF.js";
56
+ import "./chunk-AEWHC4WM.js";
57
+ import "./chunk-OUWAC7AQ.js";
58
+ import {
59
+ HELP_TEXT,
60
+ applyEarlyCliEnv,
61
+ routeEarlyCli
62
+ } from "./chunk-C6ZVZCPP.js";
63
+ import {
64
+ formatVersionLine
65
+ } from "./chunk-66JPZSGX.js";
66
+ import {
67
+ applyProjectTemplates,
68
+ bootstrapInteractiveSession,
69
+ collectPostBoundaryEditIds,
70
+ createUpdateGoalTool,
71
+ ensureVerifyDeclaration,
72
+ formatAuthorityLabel,
73
+ formatWorkerIdentity,
74
+ parseSessionCliArgs,
75
+ recordTemplatesDecision,
76
+ renderRivetMdStack,
77
+ restorePlanModeFromMeta,
78
+ statusWord,
79
+ switchAgentRuntime,
80
+ upsertStackSection
81
+ } from "./chunk-AOYHP3WI.js";
82
+ import "./chunk-4U2ET7ZY.js";
83
+ import "./chunk-JBZHIC6T.js";
84
+ import "./chunk-KWVTXT5B.js";
85
+ import "./chunk-2XN7PM4N.js";
86
+ import "./chunk-SAXK6LVF.js";
87
+ import "./chunk-D2TCGRSX.js";
88
+ import "./chunk-73NJ7IT7.js";
89
+ import "./chunk-5TQ3JYBU.js";
90
+ import "./chunk-KX22RD6R.js";
91
+ import {
92
+ detectEnv,
93
+ formatGitMissingBanner
94
+ } from "./chunk-BXHV3GSB.js";
95
+ import "./chunk-FW3QKMFX.js";
96
+ import {
97
+ formatWorkerResultDigest
98
+ } from "./chunk-WOE3D7JM.js";
99
+ import {
100
+ listPersistedResultRounds,
101
+ loadPersistedResult,
102
+ loadPersistedResultRound
103
+ } from "./chunk-B3YEBABJ.js";
104
+ import "./chunk-UXXS53EA.js";
105
+ import "./chunk-DWROHPXP.js";
106
+ import "./chunk-ZDIFBJFT.js";
107
+ import "./chunk-D54ZWG4T.js";
108
+ import "./chunk-R43HJCDX.js";
109
+ import "./chunk-D4PTYFOG.js";
110
+ import {
111
+ shortOrderLabel
112
+ } from "./chunk-AERM3VGP.js";
113
+ import {
114
+ setPlanSession
115
+ } from "./chunk-RK3JHWPT.js";
116
+ import "./chunk-NH6VIOAR.js";
117
+ import "./chunk-S4K4L6IM.js";
118
+ import "./chunk-3VGD2FXB.js";
119
+ import "./chunk-UXNLELW6.js";
120
+ import "./chunk-TVHW77C7.js";
121
+ import "./chunk-424AP7FM.js";
122
+ import "./chunk-JCFWOULR.js";
123
+ import "./chunk-2HKD2UFM.js";
124
+ import "./chunk-5JRZPLI6.js";
125
+ import "./chunk-JRF5L6OD.js";
126
+ import "./chunk-EBJTVRQN.js";
127
+ import "./chunk-J4U4AW46.js";
128
+ import "./chunk-2HDP7RMR.js";
129
+ import {
130
+ loadConstellation
131
+ } from "./chunk-OTNHSAGN.js";
132
+ import "./chunk-DZ6UOJ5D.js";
133
+ import "./chunk-T3ED6BY2.js";
134
+ import "./chunk-RAXBAWRN.js";
135
+ import {
136
+ TIER_HINT,
137
+ TIER_TO_WIRE,
138
+ applySandboxPolicyForApprovalMode,
139
+ formatPermissionLabel,
140
+ formatTierLabel,
141
+ nextShiftTabPlanToggle,
142
+ shiftTabPlanToggleHint
143
+ } from "./chunk-4J5TZGOE.js";
144
+ import "./chunk-BUIMGNDD.js";
145
+ import "./chunk-ZU7JZCVP.js";
146
+ import "./chunk-JSS75KCG.js";
147
+ import "./chunk-EHHUASO5.js";
148
+ import "./chunk-LA6IPTGH.js";
149
+ import "./chunk-HBVF6BWO.js";
150
+ import "./chunk-UHGLFRZE.js";
151
+ import "./chunk-4QJ3Y5JM.js";
152
+ import {
153
+ starDomainRegistry
154
+ } from "./chunk-CGOADM2X.js";
155
+ import "./chunk-ZGGCEXDC.js";
156
+ import {
157
+ listPlansSync,
158
+ readPlanSync,
159
+ rejectPlan,
160
+ stripPlanChrome
161
+ } from "./chunk-ZMZCZNKU.js";
162
+ import "./chunk-Z3QE7TZM.js";
163
+ import "./chunk-GHVMWF2I.js";
164
+ import "./chunk-J6ESSM47.js";
165
+ import "./chunk-3C3R7JXY.js";
166
+ import "./chunk-TI4GSEL5.js";
167
+ import "./chunk-OXMIV4WE.js";
168
+ import "./chunk-4XPFLICE.js";
169
+ import {
170
+ buildSystemPrompt
171
+ } from "./chunk-V5YIPMHV.js";
172
+ import "./chunk-ILBCKAV6.js";
173
+ import {
174
+ resolveCapabilities,
175
+ tryResolveCredentialKey
176
+ } from "./chunk-X2IK5LVR.js";
177
+ import "./chunk-CEZNQVWM.js";
178
+ import "./chunk-O5VZQKCB.js";
179
+ import "./chunk-SEPGEJNK.js";
180
+ import "./chunk-7RDOV3DF.js";
181
+ import "./chunk-6HSVXHCZ.js";
182
+ import "./chunk-RWA23GMM.js";
183
+ import {
184
+ RECOMMENDED_MAX_SKILLS,
185
+ countInstalledSkills,
186
+ parseSkillMarkdown,
187
+ skillRegistry
188
+ } from "./chunk-OHSV42QB.js";
189
+ import "./chunk-ADIVZ2D5.js";
190
+ import "./chunk-7FW3I7WC.js";
191
+ import "./chunk-GD4ZNZ7W.js";
192
+ import "./chunk-ZQKXBUB7.js";
193
+ import "./chunk-Z5Z3JHJY.js";
194
+ import {
195
+ killAllSync
196
+ } from "./chunk-KIOXTQQL.js";
197
+ import "./chunk-35H7GVNR.js";
198
+ import {
199
+ loadTodos,
200
+ setTodoSession
201
+ } from "./chunk-AE3P3F6W.js";
202
+ import "./chunk-JSXWIWWJ.js";
203
+ import "./chunk-BSECIPAQ.js";
204
+ import "./chunk-2E6CK2RC.js";
205
+ import "./chunk-ZO3I3A7O.js";
206
+ import "./chunk-P6GJOVO6.js";
207
+ import "./chunk-TPI73L57.js";
208
+ import "./chunk-HV4YGVMS.js";
209
+ import "./chunk-722LQO64.js";
210
+ import "./chunk-GMKAXSYQ.js";
211
+ import "./chunk-EPKTIOED.js";
212
+ import "./chunk-2VYRLULP.js";
213
+ import "./chunk-SUJERP5I.js";
214
+ import {
215
+ debugLog
216
+ } from "./chunk-CI4R6P2B.js";
217
+ import "./chunk-XU2YXCDL.js";
218
+ import {
219
+ applyConfiguredGitBashPath,
220
+ setTargetConventions
221
+ } from "./chunk-ETHFACAB.js";
222
+ import "./chunk-THKDVSEC.js";
223
+ import "./chunk-UFMN76QD.js";
224
+ import "./chunk-EXUE5W2F.js";
225
+ import {
226
+ SessionPersist,
227
+ formatExitSummary
228
+ } from "./chunk-LH5VCGLB.js";
229
+ import "./chunk-6S5FPUS7.js";
230
+ import "./chunk-EXXICUIW.js";
231
+ import "./chunk-QARAGUXX.js";
232
+ import "./chunk-DEBI37QB.js";
233
+ import {
234
+ isProFeatureEnabled
235
+ } from "./chunk-YJG5HIX5.js";
236
+ import {
237
+ canonicalizeModelId,
238
+ contractModels,
239
+ disambiguateKeyPrefix,
240
+ findModelInKey,
241
+ findModelOwner,
242
+ getGreetingConfig,
243
+ loadConfig,
244
+ parseModelRef,
245
+ presetIncludes,
246
+ registerProvider,
247
+ removeProvider,
248
+ setApprovalMode,
249
+ setDefaultDomainConfig,
250
+ setDefaultModelConfig,
251
+ setDefaultProvider,
252
+ setUiConfig,
253
+ setupProvider,
254
+ upsertProviderModel
255
+ } from "./chunk-ER5JW2QZ.js";
256
+ import {
257
+ THEMES,
258
+ THEME_PALETTES,
259
+ color,
260
+ getActiveThemeName,
261
+ getTheme,
262
+ listCustomThemes,
263
+ registerCustomTheme,
264
+ resolveThemeEntry,
265
+ setTheme
266
+ } from "./chunk-CGFZGR7G.js";
267
+ import "./chunk-P5KJURUR.js";
268
+ import "./chunk-WMUWEO2C.js";
269
+ import "./chunk-BKTQAYO2.js";
270
+ import "./chunk-OO3TAHO5.js";
271
+ import {
272
+ isRestrictedPath
273
+ } from "./chunk-EGEI2RQA.js";
274
+ import "./chunk-ZTRINFM2.js";
275
+ import "./chunk-ZNC5T65N.js";
276
+ import {
277
+ detectProjectTrustStakes,
278
+ dismissProjectTrustPrompt,
279
+ isProjectTrusted,
280
+ isTrustPromptDismissed,
281
+ trustProject
282
+ } from "./chunk-7KUCBNLB.js";
283
+ import "./chunk-A5MNH4ER.js";
284
+ import {
285
+ init_paths,
286
+ rivetHome,
287
+ sessionsDir
288
+ } from "./chunk-BCQXEZPJ.js";
289
+ import {
290
+ init_esm_shims
291
+ } from "./chunk-5GGOGLSN.js";
292
+
293
+ // src/main.ts
294
+ init_esm_shims();
295
+
296
+ // src/platform/eperm-filter.ts
297
+ init_esm_shims();
298
+ function isWindowsScandirNoise(error) {
299
+ if (typeof error !== "object" || error === null) return false;
300
+ const err = error;
301
+ const code = err.code;
302
+ if (code !== "EPERM" && code !== "EACCES") return false;
303
+ const syscall = err.syscall;
304
+ if (syscall !== "scandir" && syscall !== "stat") return false;
305
+ const path = typeof err.path === "string" ? err.path : String(err.message ?? "");
306
+ return isRestrictedPath(path, code);
307
+ }
308
+ function handleRejection(reason) {
309
+ if (isWindowsScandirNoise(reason)) return;
310
+ const detail = reason instanceof Error ? reason.stack ?? reason.message : String(reason);
311
+ console.error(`[rivet] Unhandled promise rejection: ${detail}`);
312
+ }
313
+ function installEpermFilter() {
314
+ if (process.__epermFilterInstalled) return;
315
+ process.__epermFilterInstalled = true;
316
+ process.on("unhandledRejection", handleRejection);
317
+ }
318
+
319
+ // src/platform/staged-runtime-guard.ts
320
+ init_esm_shims();
321
+ import { existsSync, readdirSync, rmSync, statSync } from "fs";
322
+ import { dirname, join } from "path";
323
+ function hasAnyFile(dir) {
324
+ let entries;
325
+ try {
326
+ entries = readdirSync(dir);
327
+ } catch {
328
+ return false;
329
+ }
330
+ const subdirs = [];
331
+ for (const entry of entries) {
332
+ const full = join(dir, entry);
333
+ try {
334
+ if (statSync(full).isDirectory()) subdirs.push(full);
335
+ else return true;
336
+ } catch {
337
+ }
338
+ }
339
+ return subdirs.some(hasAnyFile);
340
+ }
341
+ function packageDirs(modulesDir) {
342
+ const out = [];
343
+ let entries;
344
+ try {
345
+ entries = readdirSync(modulesDir);
346
+ } catch {
347
+ return out;
348
+ }
349
+ for (const entry of entries) {
350
+ if (entry.startsWith(".")) continue;
351
+ const full = join(modulesDir, entry);
352
+ try {
353
+ if (!statSync(full).isDirectory()) continue;
354
+ } catch {
355
+ continue;
356
+ }
357
+ if (entry.startsWith("@")) {
358
+ let scoped;
359
+ try {
360
+ scoped = readdirSync(full);
361
+ } catch {
362
+ continue;
363
+ }
364
+ for (const sub of scoped) {
365
+ const subFull = join(full, sub);
366
+ try {
367
+ if (statSync(subFull).isDirectory()) out.push({ name: `${entry}/${sub}`, dir: subFull });
368
+ } catch {
369
+ }
370
+ }
371
+ continue;
372
+ }
373
+ out.push({ name: entry, dir: full });
374
+ }
375
+ return out;
376
+ }
377
+ function findParentModules(distDir) {
378
+ let cur = dirname(distDir);
379
+ for (let i = 0; i < 6; i++) {
380
+ const candidate = join(cur, "node_modules");
381
+ if (existsSync(candidate)) return candidate;
382
+ const next = dirname(cur);
383
+ if (next === cur) break;
384
+ cur = next;
385
+ }
386
+ return null;
387
+ }
388
+ function inspectStagedRuntime(distDir) {
389
+ const modulesDir = join(distDir, "node_modules");
390
+ if (!existsSync(modulesDir)) return { action: "ok", emptyPackages: [] };
391
+ const empty = packageDirs(modulesDir).filter((p) => !hasAnyFile(p.dir)).map((p) => p.name);
392
+ if (empty.length === 0) return { action: "ok", emptyPackages: [] };
393
+ const parent = findParentModules(distDir);
394
+ if (parent) {
395
+ const coveredByParent = empty.every((name) => {
396
+ const candidate = join(parent, name);
397
+ return existsSync(candidate) && hasAnyFile(candidate);
398
+ });
399
+ if (coveredByParent) return { action: "heal", emptyPackages: empty, healableFrom: parent };
400
+ }
401
+ return { action: "fatal", emptyPackages: empty };
402
+ }
403
+ var RECOVERY = "node scripts/pack-native.js && node scripts/stage-runtime-deps.js";
404
+ function assertStagedRuntimeIntact(distDir, exit = process.exit) {
405
+ if (process.env.RIVET_SKIP_STAGED_RUNTIME_CHECK === "1") return;
406
+ let result;
407
+ try {
408
+ result = inspectStagedRuntime(distDir);
409
+ } catch {
410
+ return;
411
+ }
412
+ if (result.action === "ok") return;
413
+ if (result.action === "heal") {
414
+ try {
415
+ for (const name of result.emptyPackages) {
416
+ rmSync(join(distDir, "node_modules", name), { recursive: true, force: true });
417
+ }
418
+ console.warn(
419
+ `[rivet] dist/node_modules \u6709 ${result.emptyPackages.length} \u4E2A\u7A7A\u5305\u76EE\u5F55\uFF08tsup clean \u6B8B\u7559\uFF09\uFF0C\u5DF2\u79FB\u9664\u4EE5\u6062\u590D\u4E0A\u5C42 node_modules \u89E3\u6790\u3002\u5B8C\u6574\u968F\u5305\u4F9D\u8D56\u8BF7\u8DD1\uFF1A${RECOVERY}`
420
+ );
421
+ return;
422
+ } catch {
423
+ }
424
+ }
425
+ console.error("[rivet] \u542F\u52A8\u4E2D\u6B62\uFF1Adist \u7684\u539F\u751F/wasm \u4F9D\u8D56\u672A\u968F\u5305\u5206\u53D1\uFF0C\u7EE7\u7EED\u8FD0\u884C\u4F1A\u9759\u9ED8\u964D\u7EA7\u3002");
426
+ console.error(` \u7A7A\u5305\u76EE\u5F55\uFF08${result.emptyPackages.length}\uFF09\uFF1A${result.emptyPackages.slice(0, 8).join(", ")}`);
427
+ console.error(` \u53D7\u5F71\u54CD\uFF1Ameridian(tree-sitter) / ast-grep / typescript LSP / better-sqlite3`);
428
+ console.error(` \u4FEE\u590D\uFF1A${RECOVERY}`);
429
+ console.error(" \u8DF3\u8FC7\u6B64\u68C0\u67E5\uFF08\u4E0D\u63A8\u8350\uFF09\uFF1ARIVET_SKIP_STAGED_RUNTIME_CHECK=1");
430
+ exit(1);
431
+ }
432
+
433
+ // src/main.ts
434
+ import { fileURLToPath } from "url";
435
+ import { dirname as dirname3 } from "path";
436
+
437
+ // src/cli/prompt-version-warning.ts
438
+ init_esm_shims();
439
+ import { createHash } from "crypto";
440
+ import { existsSync as existsSync2, mkdirSync, readFileSync, writeFileSync } from "fs";
441
+ import { join as join2 } from "path";
442
+ init_paths();
443
+ var MARKER_FILE = ".static-prompt-hash";
444
+ function getPromptHash() {
445
+ const prompt = buildSystemPrompt({ tools: [] });
446
+ return createHash("sha256").update(prompt, "utf8").digest("hex");
447
+ }
448
+ function getMarkerPath() {
449
+ return join2(rivetHome(), MARKER_FILE);
450
+ }
451
+ function readStoredHash() {
452
+ const path = getMarkerPath();
453
+ if (!existsSync2(path)) return null;
454
+ try {
455
+ return readFileSync(path, "utf8").trim();
456
+ } catch {
457
+ return null;
458
+ }
459
+ }
460
+ function writeStoredHash(hash) {
461
+ const path = getMarkerPath();
462
+ try {
463
+ mkdirSync(rivetHome(), { recursive: true });
464
+ writeFileSync(path, hash, "utf8");
465
+ } catch {
466
+ }
467
+ }
468
+ function maybePrintStaticPromptCacheWarning() {
469
+ const currentHash = getPromptHash();
470
+ const storedHash = readStoredHash();
471
+ if (storedHash === currentHash) return;
472
+ process.stderr.write(
473
+ "\n\u26A0\uFE0F \u7CFB\u7EDF\u63D0\u793A\u8BCD\u5DF2\u53D8\u66F4\uFF1A\u65E7\u4F1A\u8BDD\u7684\u524D\u7F00\u7F13\u5B58\u5C06\u5728\u4E0B\u4E00\u8F6E\u5931\u6548\u5E76\u89E6\u53D1\u5B8C\u6574\u91CD\u5EFA\u3002\n \u5EFA\u8BAE\uFF1A\u5347\u7EA7\u540E\u8BF7\u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u4E0D\u8981\u5728\u65E7\u4F1A\u8BDD\u91CC\u7EE7\u7EED\u957F\u5BF9\u8BDD\uFF0C\u4EE5\u907F\u514D\u9AD8\u989D cache creation \u8D39\u7528\u3002\n Static prompt changed; start a new session to avoid cache rebuild costs.\n\n"
474
+ );
475
+ writeStoredHash(currentHash);
476
+ }
477
+
478
+ // src/tui/engine/bridge.ts
479
+ init_esm_shims();
480
+ function wrapCallbacksWithTuiApp(app2, original = {}) {
481
+ const gen = app2.runGen;
482
+ const live = () => app2.runGen === gen;
483
+ return {
484
+ onTextDelta: (text) => {
485
+ if (!live()) return;
486
+ app2.callbacks.onTextDelta(text);
487
+ original.onTextDelta?.(text);
488
+ },
489
+ onThinkingDelta: (thinking) => {
490
+ if (!live()) return;
491
+ app2.callbacks.onThinkingDelta(thinking);
492
+ original.onThinkingDelta?.(thinking);
493
+ },
494
+ onToolUse: (id, name, input) => {
495
+ if (!live()) return;
496
+ app2.callbacks.onToolUse(id, name, input);
497
+ original.onToolUse?.(id, name, input);
498
+ },
499
+ onToolResult: (id, name, result, isError, rawPath, uiContent) => {
500
+ if (!live()) {
501
+ debugLog(`[tool-result-trace] DROP (stale run) id=${id} name=${name} isError=${isError}`);
502
+ return;
503
+ }
504
+ debugLog(`[tool-result-trace] bridge id=${id} name=${name} isError=${isError} len=${result?.length ?? 0}`);
505
+ app2.callbacks.onToolResult(id, name, result, isError, rawPath, uiContent);
506
+ original.onToolResult?.(id, name, result, isError, rawPath, uiContent);
507
+ },
508
+ onTurnComplete: (usage, turnNumber, isFinal) => {
509
+ if (!live()) return;
510
+ app2.callbacks.onTurnComplete(usage, turnNumber, isFinal);
511
+ original.onTurnComplete?.(usage, turnNumber, isFinal);
512
+ },
513
+ onError: (error) => {
514
+ if (!live()) return;
515
+ app2.callbacks.onError(error);
516
+ original.onError?.(error);
517
+ },
518
+ onAbort: (reason) => {
519
+ if (!live()) return;
520
+ app2.callbacks.onAbort(reason);
521
+ original.onAbort?.(reason);
522
+ },
523
+ onApprovalRequired: async (id, name, input) => {
524
+ if (!live()) return false;
525
+ if (original.onApprovalRequired) {
526
+ return original.onApprovalRequired(id, name, input);
527
+ }
528
+ return app2.callbacks.onApprovalRequired(id, name, input);
529
+ },
530
+ onCheckpoint: (hash) => {
531
+ if (!live()) return;
532
+ app2.callbacks.onCheckpoint?.(hash);
533
+ original.onCheckpoint?.(hash);
534
+ },
535
+ onPhaseChange: (phase, detail) => {
536
+ if (!live()) return;
537
+ app2.callbacks.onPhaseChange?.(phase, detail);
538
+ original.onPhaseChange?.(phase, detail);
539
+ },
540
+ onDomainDrift: (drift) => {
541
+ if (!live()) return;
542
+ original.onDomainDrift?.(drift);
543
+ },
544
+ onIntentNote: (intent) => {
545
+ if (!live()) return;
546
+ app2.callbacks.onIntentNote?.(intent);
547
+ original.onIntentNote?.(intent);
548
+ },
549
+ onSteerDrain: () => {
550
+ if (!live()) return null;
551
+ const drained = app2.callbacks.onSteerDrain?.() ?? null;
552
+ const originalDrained = original.onSteerDrain?.() ?? null;
553
+ return drained ?? originalDrained;
554
+ },
555
+ onDelegationActivity: (activity) => {
556
+ if (!live()) return;
557
+ app2.callbacks.onDelegationActivity?.(activity);
558
+ original.onDelegationActivity?.(activity);
559
+ }
560
+ };
561
+ }
562
+
563
+ // src/agent/event-stream-sink.ts
564
+ init_esm_shims();
565
+ import { createWriteStream, mkdirSync as mkdirSync2 } from "fs";
566
+ import { dirname as dirname2 } from "path";
567
+ function createNdjsonEventSink(path) {
568
+ let stream = null;
569
+ let broken = false;
570
+ let brokenLogged = false;
571
+ const open = () => {
572
+ if (stream || broken) return stream;
573
+ try {
574
+ mkdirSync2(dirname2(path), { recursive: true });
575
+ stream = createWriteStream(path, { flags: "a" });
576
+ stream.on("error", (err) => {
577
+ if (!brokenLogged) {
578
+ brokenLogged = true;
579
+ console.error(`[event-sink] stream error for ${path}:`, err.message);
580
+ }
581
+ broken = true;
582
+ });
583
+ } catch {
584
+ broken = true;
585
+ }
586
+ return stream;
587
+ };
588
+ return {
589
+ sink: (event) => {
590
+ const out = open();
591
+ if (!out) return;
592
+ try {
593
+ out.write(JSON.stringify(event) + "\n");
594
+ } catch {
595
+ broken = true;
596
+ }
597
+ },
598
+ close: () => {
599
+ const out = stream;
600
+ stream = null;
601
+ if (!out) return Promise.resolve();
602
+ return new Promise((resolve) => {
603
+ try {
604
+ out.end(() => resolve());
605
+ } catch {
606
+ resolve();
607
+ }
608
+ });
609
+ }
610
+ };
611
+ }
612
+
613
+ // src/tui/screen-reader.ts
614
+ init_esm_shims();
615
+ var PRIMARY_ARG_KEYS = ["path", "file_path", "command", "pattern", "query", "url", "prompt"];
616
+ var MAX_ARG_CHARS = 80;
617
+ function primaryArg(input) {
618
+ if (!input || typeof input !== "object") return null;
619
+ const record = input;
620
+ for (const key of PRIMARY_ARG_KEYS) {
621
+ const value = record[key];
622
+ if (typeof value === "string" && value.trim()) {
623
+ const flat = value.replace(/\s+/g, " ").trim();
624
+ return flat.length > MAX_ARG_CHARS ? `${flat.slice(0, MAX_ARG_CHARS)}\u2026` : flat;
625
+ }
626
+ }
627
+ return null;
628
+ }
629
+ function formatEventForScreenReader(event) {
630
+ switch (event.type) {
631
+ case "tool_use": {
632
+ const name = typeof event.data.name === "string" ? event.data.name : "\u672A\u77E5\u5DE5\u5177";
633
+ const arg = primaryArg(event.data.input);
634
+ return arg ? `\u5F00\u59CB ${name}\uFF1A${arg}` : `\u5F00\u59CB ${name}`;
635
+ }
636
+ case "approval_required": {
637
+ const name = typeof event.data.toolName === "string" ? event.data.toolName : "\u672A\u77E5\u5DE5\u5177";
638
+ const arg = primaryArg(event.data.input);
639
+ const what = arg ? `\u7B49\u5F85\u6279\u51C6 ${name}\uFF1A${arg}` : `\u7B49\u5F85\u6279\u51C6 ${name}`;
640
+ return `${what}\u3002\u6309 y \u6279\u51C6\uFF0Cn \u62D2\u7EDD\uFF0Ce \u7F16\u8F91\uFF0CCtrl+E \u89E3\u91CA\u98CE\u9669`;
641
+ }
642
+ case "turn_complete":
643
+ return event.data.isFinal === true ? "\u56DE\u5408\u5B8C\u6210" : null;
644
+ case "error": {
645
+ const message = typeof event.data.error === "string" ? event.data.error : "\u672A\u77E5\u9519\u8BEF";
646
+ return `\u51FA\u9519\uFF1A${message}`;
647
+ }
648
+ case "status":
649
+ return event.data.status === "aborted" ? "\u5DF2\u4E2D\u65AD" : null;
650
+ default:
651
+ return null;
652
+ }
653
+ }
654
+
655
+ // src/main.ts
656
+ import { readFileSync as readFileSync4, statSync as statSync2 } from "fs";
657
+ import { join as pathJoin } from "path";
658
+
659
+ // src/tui/format/welcome.ts
660
+ init_esm_shims();
661
+ import { homedir } from "os";
662
+ var FULL_FIXED_ROWS = 8;
663
+ var RESERVED_ROWS = 5;
664
+ var MIN_COLS = 44;
665
+ var CONTENT_MAX = 72;
666
+ var STAR_AT = 0.38;
667
+ var TAG_GAP = 6;
668
+ var WIDE = { ambiguousAsWide: true };
669
+ var MISSION_ZH = "\u628A\u661F\u8FB0\u5E26\u7ED9\u6BCF\u4E00\u4F4D\u5F00\u53D1\u8005";
670
+ var MISSION_EN = "Models as partners, not tools.";
671
+ var HINT_DOMAIN_CMD = "/domain";
672
+ var HINT_DOMAIN_DESC = "\u67E5\u770B\u661F\u57DF\u63CF\u8FF0\u4E0E\u5207\u6362 \xB7 \u4E0D\u540C\u661F\u57DF\u5DE5\u7A0B\u80FD\u529B\u4E0D\u540C";
673
+ var HINT_DOMAIN_SHORT = "\u661F\u57DF\u63CF\u8FF0\u4E0E\u5207\u6362";
674
+ var HINT_HANDOFF = "\u6EE160%\u4EA4\u63A5\u65B0\u4F1A\u8BDD";
675
+ var HINT_CACHE_A = "\u4E2D\u9014\u5207";
676
+ var HINT_CACHE_CMDS = "/model /domain";
677
+ var HINT_CACHE_B = "\u788E\u7F13\u5B58";
678
+ var HINT_COLLAB_CMDS = "/team /scout";
679
+ var HINT_COLLAB_DESC = "\u534F\u540C\u2014\u2014\u5E76\u884C\u65BD\u5DE5 \xB7 \u53EA\u8BFB\u4FA6\u5BDF";
680
+ var HINT_COLLAB_SHORT_CMDS = "/team /scout";
681
+ var HINT_COLLAB_SHORT_DESC = "\u534F\u540C\u591A\u4EE3\u7406";
682
+ var GUIDE_INTRO = "\u7EC8\u7AEF\u91CC\u7684 AI \u5DE5\u7A0B\u5E08 \u2014\u2014 \u76F4\u63A5\u8BF4\u4F60\u8981\u505A\u4EC0\u4E48\uFF0C\u6211\u6765\u5E72\u6D3B";
683
+ var GUIDE_INTRO_SHORT = "\u7EC8\u7AEF\u91CC\u7684 AI \u5DE5\u7A0B\u5E08 \u2014\u2014 \u76F4\u63A5\u8BF4\u4F60\u8981\u505A\u4EC0\u4E48";
684
+ var GUIDE_INTRO_TINY = "\u76F4\u63A5\u8BF4\u4F60\u8981\u505A\u4EC0\u4E48\uFF0C\u6211\u6765\u5E72\u6D3B";
685
+ var GUIDE_EXAMPLES = ["\u770B\u770B\u8FD9\u4E2A\u9879\u76EE\u7684\u7ED3\u6784", "\u5E2E\u6211\u8DD1\u4E00\u4E0B\u6D4B\u8BD5\uFF0C\u628A\u5931\u8D25\u7684\u4FEE\u6389", "@src/main.ts \u8FD9\u6BB5\u4EE3\u7801\u5728\u505A\u4EC0\u4E48"];
686
+ var GUIDE_HINT = "\u76F4\u63A5\u5F00\u59CB \xB7 Tab \u8865\u5168\u8DEF\u5F84 \xB7 / \u6D4F\u89C8\u5168\u90E8\u547D\u4EE4 \xB7 /theme \u6362\u80A4";
687
+ var GUIDE_HINT_SHORT = "\u76F4\u63A5\u5F00\u59CB \xB7 / \u547D\u4EE4 \xB7 /theme \u6362\u80A4";
688
+ var GUIDE_INTRO_VOICE = {
689
+ playful: "\u55E8\uFF01\u6211\u662F\u5C0F\u5929\uFF0C\u4F60\u7684\u7EC8\u7AEF\u661F\u7075\u2014\u2014\u60F3\u505A\u4EC0\u4E48\u76F4\u63A5\u8BF4",
690
+ tech: "Nova \u5728\u7EBF\u3002\u76EE\u6807\u5DF2\u5C31\u7EEA\u2014\u2014\u76F4\u63A5\u4E0B\u8FBE\u4EFB\u52A1"
691
+ };
692
+ var BLOCK_FONT = {
693
+ T: ["#####", "..#..", "..#..", "..#..", "..#.."],
694
+ I: ["#####", "..#..", "..#..", "..#..", "#####"],
695
+ A: [".###.", "#...#", "#####", "#...#", "#...#"],
696
+ N: ["#...#", "##..#", "#.#.#", "#..##", "#...#"],
697
+ S: [".####", "#....", ".###.", "....#", "####."],
698
+ H: ["#...#", "#...#", "#####", "#...#", "#...#"],
699
+ U: ["#...#", "#...#", "#...#", "#...#", ".###."],
700
+ R: ["####.", "#...#", "####.", "#..#.", "#...#"],
701
+ V: ["#...#", "#...#", "#...#", ".#.#.", "..#.."],
702
+ E: ["#####", "#....", "####.", "#....", "#####"]
703
+ };
704
+ var SHADOW_FONT = {
705
+ T: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u2588\u2588\u2551 ", " \u255A\u2550\u255D "],
706
+ I: ["\u2588\u2588\u2557 ", "\u2588\u2588\u2551 ", "\u2588\u2588\u2551 ", "\u2588\u2588\u2551 ", "\u2588\u2588\u2551 ", "\u255A\u2550\u255D "],
707
+ A: [" \u2588\u2588\u2588\u2588\u2588\u2557 ", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551", "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u255D"],
708
+ N: ["\u2588\u2588\u2588\u2557 \u2588\u2588\u2557", "\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551", "\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551", "\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551", "\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D"],
709
+ S: ["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557", "\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551", "\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],
710
+ H: ["\u2588\u2588\u2557 \u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2550\u255D \u255A\u2550\u255D"],
711
+ U: ["\u2588\u2588\u2557 \u2588\u2588\u2557", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u2588\u2588\u2551 \u2588\u2588\u2551", "\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D", " \u255A\u2550\u2550\u2550\u2550\u2550\u255D "]
712
+ };
713
+ var SHADOW_MIN_COLS = 58;
714
+ var DEFAULT_LOGO_STYLE = "shadow";
715
+ function logoSpec(style) {
716
+ const measured = (word, font, gap) => {
717
+ const glyphRows = [...word].map((ch) => font[ch] ?? []);
718
+ const rowCount = glyphRows[0]?.length ?? 0;
719
+ const joined = [];
720
+ for (let r = 0; r < rowCount; r++) joined.push(glyphRows.map((g) => g[r] ?? "").join(gap));
721
+ return { word, font, cols: Math.max(...joined.map((j) => displayWidth(j))), rows: rowCount, gap };
722
+ };
723
+ return style === "pixel" ? measured("TIANSHU", BLOCK_FONT, " ") : measured("TIANSHU", SHADOW_FONT, "");
724
+ }
725
+ function resolveLogoSpec(explicit, cols) {
726
+ let style = resolveLogoStyle(explicit);
727
+ if (style === "shadow" && cols < SHADOW_MIN_COLS) style = "pixel";
728
+ return { spec: logoSpec(style), style };
729
+ }
730
+ function resolveLogoStyle(explicit) {
731
+ const raw = explicit ?? process.env["RIVET_WELCOME_LOGO"];
732
+ return raw === "pixel" || raw === "tianshu" ? "pixel" : DEFAULT_LOGO_STYLE;
733
+ }
734
+ var bodyW = (cols) => Math.min(cols, CONTENT_MAX);
735
+ function truncateWide(text, maxWidth) {
736
+ const ellW = displayWidth("\u2026", WIDE);
737
+ return displayWidth(text, WIDE) > maxWidth ? `${truncateToDisplayWidth(text, Math.max(0, maxWidth - ellW), WIDE)}\u2026` : text;
738
+ }
739
+ function tildify(cwd) {
740
+ const home = homedir();
741
+ return home && cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd;
742
+ }
743
+ function hexToRgb(hex) {
744
+ const m = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i.exec(hex);
745
+ if (!m) return null;
746
+ return [Number.parseInt(m[1], 16), Number.parseInt(m[2], 16), Number.parseInt(m[3], 16)];
747
+ }
748
+ var toHex = (r, g, b) => `#${[r, g, b].map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")).join("")}`;
749
+ function brandWord(text, brandColor) {
750
+ const rgb = hexToRgb(brandColor);
751
+ if (!rgb) return color(text, brandColor, { bold: true });
752
+ const chars = [...text];
753
+ return chars.map((ch, i) => {
754
+ const t = chars.length > 1 ? i / (chars.length - 1) : 0;
755
+ const lift = (1 - t) * 0.45;
756
+ const mixed = toHex(rgb[0] + (255 - rgb[0]) * lift, rgb[1] + (255 - rgb[1]) * lift, rgb[2] + (255 - rgb[2]) * lift);
757
+ return color(ch, mixed, { bold: true });
758
+ }).join("");
759
+ }
760
+ function effortBadge(effort, theme) {
761
+ if (!effort) return "";
762
+ const short = effort === "medium" ? "med" : effort;
763
+ const c = effort === "max" || effort === "auto" ? theme.secondary : effort === "high" ? theme.primary : effort === "off" ? theme.dim : theme.muted;
764
+ return color(`\u25CE${short}`, c);
765
+ }
766
+ function logoRows(theme, cols, version, spec, degradeTinySymbols = false) {
767
+ spec = spec ?? logoSpec(resolveLogoStyle(void 0));
768
+ const glyphs = [...spec.word].map((ch) => spec.font[ch]);
769
+ const rows = [];
770
+ const star = degradeTinySymbols ? "*" : "\u2726";
771
+ const brandSeg = version ? `${color(star, theme.brandColor, { bold: true })} ${brandWord("\u5929\u67A2", theme.brandColor)}${color(" \xB7 ", theme.dim)}${color(`v${version}`, theme.dim)}` : `${color(star, theme.brandColor, { bold: true })} ${brandWord("\u5929\u67A2", theme.brandColor)}`;
772
+ for (let r = 0; r < spec.rows; r++) {
773
+ const line = glyphs.map((g) => g[r]).join(spec.gap);
774
+ if (r === 1 && spec.cols + TAG_GAP + displayWidth(brandSeg, WIDE) <= cols) {
775
+ rows.push(`${color(line, theme.brandColor, { bold: true })}${" ".repeat(TAG_GAP)}${brandSeg}`);
776
+ } else {
777
+ rows.push(color(line, theme.brandColor, { bold: true }));
778
+ }
779
+ }
780
+ return rows;
781
+ }
782
+ function missionLine(theme, cols) {
783
+ const plain = ` ${MISSION_ZH} \xB7 ${MISSION_EN}`;
784
+ if (displayWidth(plain) <= bodyW(cols) && displayWidth(plain, WIDE) <= cols) {
785
+ return `${" "}${color(MISSION_ZH, theme.muted)}${color(" \xB7 ", theme.dim)}${color(MISSION_EN, theme.dim)}`;
786
+ }
787
+ return null;
788
+ }
789
+ function isMissionLine(line) {
790
+ return line.replace(/\x1B\[[0-9;]*m/g, "").includes(MISSION_ZH);
791
+ }
792
+ var MISSION_SHIMMER_FRAME_MS = 16;
793
+ function missionShimmer(theme, cols) {
794
+ const finalLine = missionLine(theme, cols);
795
+ if (!finalLine) return null;
796
+ const cells = [];
797
+ for (const ch of ` ${MISSION_ZH} \xB7 `) cells.push({ ch, base: ch === " " || ch === "\xB7" ? theme.dim : theme.muted });
798
+ for (const ch of MISSION_EN) cells.push({ ch, base: theme.dim });
799
+ const WIN = 4;
800
+ const kira = theme.voice === "playful";
801
+ const neon = theme.voice === "tech";
802
+ const frameCount = Math.min(10, Math.max(6, Math.ceil(cells.length / 6)));
803
+ const step = (cells.length + WIN) / frameCount;
804
+ const frames = [];
805
+ for (let f = 0; f < frameCount; f++) {
806
+ const head = Math.round(f * step);
807
+ const rendered = cells.map((c, i) => {
808
+ const d = head - i;
809
+ if (d >= 0 && d < WIN && c.ch !== " ") {
810
+ if (kira && d === 0) return color(c.ch, "#ffffff", { bold: true });
811
+ if (neon && d > 0) return color(c.ch, theme.secondary, { bold: true });
812
+ return color(c.ch, theme.primary, { bold: true });
813
+ }
814
+ return color(c.ch, c.base);
815
+ }).join("");
816
+ frames.push(rendered);
817
+ }
818
+ frames.push(finalLine);
819
+ return { final: finalLine, frames };
820
+ }
821
+ function datumLine(theme, ascii, cols, separator) {
822
+ const h = ascii ? "-" : boxCharsFor(separator ?? "thin").h;
823
+ const star = ascii ? "*" : "\u2726";
824
+ const k = Math.max(1, Math.floor(cols * STAR_AT));
825
+ const rest = Math.max(0, cols - k - displayWidth(star, WIDE));
826
+ return color(h.repeat(k), theme.muted, { bold: true }) + color(star, theme.brandColor, { bold: true }) + color(h.repeat(rest), theme.muted, { bold: true });
827
+ }
828
+ function entryHintLines(theme, ascii, cols) {
829
+ const handoff = ascii ? "-" : "\u23DC";
830
+ const note = ascii ? "." : "\u2727";
831
+ const domainFull = `${color(note, theme.secondary)} ${color(HINT_DOMAIN_CMD, theme.brandColor)} ${color(HINT_DOMAIN_DESC, theme.muted)}`;
832
+ const domainShort = `${color(note, theme.secondary)} ${color(HINT_DOMAIN_CMD, theme.brandColor)} ${color(HINT_DOMAIN_SHORT, theme.muted)}`;
833
+ const domainPlainW = (t) => displayWidth(t.replace(/\x1B\[[0-9;]*m/g, ""), WIDE);
834
+ const collabFull = `${color(note, theme.secondary)} ${color(HINT_COLLAB_CMDS, theme.brandColor)} ${color(HINT_COLLAB_DESC, theme.muted)}`;
835
+ const collabShort = `${color(note, theme.secondary)} ${color(HINT_COLLAB_SHORT_CMDS, theme.brandColor)} ${color(HINT_COLLAB_SHORT_DESC, theme.muted)}`;
836
+ const mergedFull = `${color(handoff, theme.secondary)} ${color("/handoff", theme.brandColor)} ${color(HINT_HANDOFF, theme.muted)}${color(" \xB7 ", theme.dim)}${color(HINT_CACHE_A, theme.muted)} ${color(HINT_CACHE_CMDS, theme.secondary)} ${color(HINT_CACHE_B, theme.muted)}`;
837
+ const mergedShort = `${color(handoff, theme.secondary)} ${color("/handoff", theme.brandColor)} ${color("\u4EA4\u63A5", theme.muted)}${color(" \xB7 ", theme.dim)}${color(HINT_CACHE_CMDS, theme.secondary)} ${color(HINT_CACHE_B, theme.muted)}`;
838
+ const lines = [];
839
+ if (domainPlainW(domainFull) <= cols) lines.push(domainFull);
840
+ else if (domainPlainW(domainShort) <= cols) lines.push(domainShort);
841
+ if (domainPlainW(collabFull) <= cols) lines.push(collabFull);
842
+ else if (domainPlainW(collabShort) <= cols) lines.push(collabShort);
843
+ if (domainPlainW(mergedFull) <= cols) lines.push(mergedFull);
844
+ else if (domainPlainW(mergedShort) <= cols) lines.push(mergedShort);
845
+ return lines;
846
+ }
847
+ function guideLines(theme, ascii, cols) {
848
+ const star = ascii ? "*" : "\u2726";
849
+ const enter = ascii ? "-" : "\u23CE";
850
+ const lines = [];
851
+ const glyphW = (glyph, text) => displayWidth(` ${glyph} ${text}`, WIDE);
852
+ const voiceIntro = theme.voice !== "default" ? GUIDE_INTRO_VOICE[theme.voice] : void 0;
853
+ const intro = voiceIntro && glyphW(star, voiceIntro) <= cols ? voiceIntro : glyphW(star, GUIDE_INTRO) <= cols ? GUIDE_INTRO : glyphW(star, GUIDE_INTRO_SHORT) <= cols ? GUIDE_INTRO_SHORT : glyphW(star, GUIDE_INTRO_TINY) <= cols ? GUIDE_INTRO_TINY : null;
854
+ if (intro) lines.push(` ${color(star, theme.secondary)} ${color(intro, theme.muted)}`);
855
+ for (const ex of GUIDE_EXAMPLES) {
856
+ if (displayWidth(` \xB7 ${ex}`, WIDE) <= cols) lines.push(` ${color("\xB7", theme.dim)} ${color(ex, theme.muted)}`);
857
+ }
858
+ const hint = glyphW(enter, GUIDE_HINT) <= cols ? GUIDE_HINT : glyphW(enter, GUIDE_HINT_SHORT) <= cols ? GUIDE_HINT_SHORT : null;
859
+ if (hint) lines.push(` ${color(enter, theme.secondary)} ${color(hint, theme.dim)}`);
860
+ return lines;
861
+ }
862
+ function compactLine(input, theme, ascii) {
863
+ const star = ascii ? "*" : "\u2726";
864
+ const sep = color(" \xB7 ", theme.dim);
865
+ const out = [color(`${star} \u5929\u67A2`, theme.brandColor, { bold: true })];
866
+ const resume = input.priorMsgCount > 0;
867
+ const eff = effortBadge(input.reasoningEffort, theme);
868
+ const modelPart = eff ? `${color(input.modelName, theme.secondary)} ${eff}` : color(input.modelName, theme.secondary);
869
+ const items = [];
870
+ if (resume) {
871
+ items.push(color(`\u2191\u7EED${input.priorMsgCount}\u8F6E`, theme.secondary), modelPart);
872
+ } else {
873
+ items.push(modelPart, color(tildify(input.cwd), theme.muted));
874
+ items.push(input.numericId ? color(`#${input.numericId}`, theme.dim) : color(input.sessionId.slice(0, 8), theme.dim));
875
+ }
876
+ if (input.version) items.push(color(`v${input.version}`, theme.dim));
877
+ let acc = displayWidth("\u2726 \u5929\u67A2", WIDE);
878
+ for (const item of items) {
879
+ const need = displayWidth(" \xB7 ", WIDE) + displayWidth(item, WIDE);
880
+ if (acc + need > input.columns) break;
881
+ acc += need;
882
+ out.push(sep, item);
883
+ }
884
+ return truncateWide(out.join(""), input.columns);
885
+ }
886
+ function formatWelcome(input, theme) {
887
+ const cols = input.columns > 0 ? input.columns : 80;
888
+ const ascii = useAsciiBorders();
889
+ const { spec: logoSpecResolved } = resolveLogoSpec(input.logoStyle, cols);
890
+ const logoRowCount = logoSpecResolved.rows;
891
+ const compactLine0 = () => [compactLine(input, theme, ascii)];
892
+ if (input.compact) return compactLine0();
893
+ const rows = input.rows && input.rows > 0 ? input.rows : Number.POSITIVE_INFINITY;
894
+ const guideExtra = input.guide ? 1 : 0;
895
+ if (rows < logoRowCount + FULL_FIXED_ROWS + RESERVED_ROWS + guideExtra) return compactLine0();
896
+ if (cols < MIN_COLS) return compactLine0();
897
+ const mission = missionLine(theme, cols);
898
+ return [
899
+ "",
900
+ ...logoRows(theme, cols, input.version, logoSpecResolved, ascii),
901
+ ...mission ? [mission] : [],
902
+ datumLine(theme, ascii, cols, input.separator),
903
+ "",
904
+ ...input.guide ? guideLines(theme, ascii, cols) : entryHintLines(theme, ascii, cols),
905
+ ""
906
+ ];
907
+ }
908
+
909
+ // src/tui/welcome-greeting.ts
910
+ init_esm_shims();
911
+ var GREETING_SETTLE_MS = 1200;
912
+ function greetingEnvDisabled() {
913
+ const v = process.env.RIVET_WELCOME_GREETING;
914
+ return v === "off" || v === "0";
915
+ }
916
+ function settleWelcomeGreeting(deps) {
917
+ if (!deps.enabled || !deps.isTty || greetingEnvDisabled()) return;
918
+ const theme = getTheme();
919
+ const greetingCfg = deps.greetingConfig ?? getGreetingConfig();
920
+ const settleHour = deps.hour ?? (/* @__PURE__ */ new Date()).getHours();
921
+ const commitGreeting = (text) => {
922
+ if (deps.isAgentBusy() || deps.isInputPending()) return;
923
+ try {
924
+ deps.commitStatic(`${color("\u2726", theme.secondary)} ${color(text, theme.muted)}`);
925
+ } catch {
926
+ }
927
+ };
928
+ void (async () => {
929
+ try {
930
+ let text = null;
931
+ if (greetingCfg.enabled) {
932
+ let provider = deps.provider;
933
+ if (!provider) {
934
+ const cfg = loadConfig();
935
+ const deepseek = cfg.provider.providers["deepseek"];
936
+ const prov = deepseek ?? cfg.provider.providers[cfg.provider.default];
937
+ provider = {
938
+ apiKey: prov?.apiKey ?? (prov?.apiKeyEnv ? process.env[prov.apiKeyEnv] : void 0),
939
+ baseUrl: prov?.baseUrl
940
+ };
941
+ }
942
+ if (provider.apiKey && provider.baseUrl) {
943
+ text = await Promise.race([
944
+ generateGreetingLlm(provider.baseUrl, provider.apiKey, greetingCfg.model, settleHour, "zh-CN"),
945
+ new Promise((resolve) => setTimeout(() => resolve(null), GREETING_SETTLE_MS))
946
+ ]);
947
+ }
948
+ }
949
+ commitGreeting(text ?? pickGreetingTemplate(settleHour, deps.voice ?? theme.voice));
950
+ } catch {
951
+ }
952
+ })();
953
+ }
954
+
955
+ // src/tui/domain-drift-nudge.ts
956
+ init_esm_shims();
957
+ function formatDomainDriftNudge(drift) {
958
+ return `\u26A1 \u68C0\u6D4B\u5230\u4EFB\u52A1\u91CD\u5FC3\u53EF\u80FD\u5DF2\u4ECE\u300C${drift.currentName}\u300D\u8F6C\u4E3A\u300C${drift.recommendedName}\u300D\u65B9\u5411\u3002\u5F53\u524D\u4F1A\u8BDD\u4FDD\u6301\u4E0D\u53D8\uFF08\u4F1A\u8BDD\u5185\u5207\u6362\u661F\u57DF\u4F1A\u91CD\u5EFA\u524D\u7F00\u7F13\u5B58\uFF09\u3002\u56DB\u9009\u4E00\uFF1A\u2460 /capsule ${drift.recommendedName} \u2014\u2014 \u628A${drift.recommendedName}\u7684\u5B8C\u6574\u8BA4\u77E5\u65B9\u6CD5\u6CE8\u5165\u672C\u8F6E\u5BF9\u8BDD\uFF08\u6D88\u606F\u7EA7\u8FFD\u52A0\uFF0C\u96F6\u7F13\u5B58\u4EE3\u4EF7\uFF0C\u6700\u591A\u540C\u65F6\u4F69\u6234 2 \u679A\uFF09\uFF1B\u2461 \u65B0\u5F00\u4E00\u4E2A\u4F1A\u8BDD\u8FDB\u5165${drift.recommendedName}\uFF08/domain ${drift.recommendedId}\uFF09\u4E13\u505A\u5BA1\u67E5\u4E0E\u89C4\u5212\uFF0C\u5F53\u524D\u4F1A\u8BDD\u7EE7\u7EED\u6267\u884C\u2014\u2014\u591A\u4F1A\u8BDD\u591A\u661F\u57DF\u5E76\u884C\uFF0C\u5404\u4F1A\u8BDD\u524D\u7F00\u7F13\u5B58\u4E92\u4E0D\u5F71\u54CD\uFF0C\u5BA1\u67E5/\u89C4\u5212\u7ED3\u679C\u4EA4\u56DE\u5F53\u524D\u4F1A\u8BDD\u91C7\u7EB3\u6267\u884C\uFF1B\u2462 \u5148 /handoff \u5199\u4EA4\u63A5\u6458\u8981\uFF0C\u518D\u65B0\u5F00\u4F1A\u8BDD\u9009\u62E9 Auto\uFF1B\u2463 \u5FFD\u7565\u2014\u2014\u4EFB\u52A1\u65B9\u5411\u672A\u53D8\u65F6\u4E0D\u5EFA\u8BAE\u52A8\u3002`;
959
+ }
960
+
961
+ // src/tui/disconnect-flow.ts
962
+ init_esm_shims();
963
+ function hostOf(baseUrl) {
964
+ try {
965
+ return new URL(baseUrl).host;
966
+ } catch {
967
+ return baseUrl;
968
+ }
969
+ }
970
+ function buildDisconnectEntries(providers, opts) {
971
+ const saved = Object.entries(providers).filter(([, p]) => p.userSaved);
972
+ return saved.map(([name, p]) => {
973
+ const sharedKeyWith = p.keyRef ? saved.filter(([other, candidate]) => other !== name && candidate.keyRef === p.keyRef).map(([other]) => other) : [];
974
+ const credentialImpact = p.keyRef ? sharedKeyWith.length > 0 ? { kind: "managed-shared", keyRef: p.keyRef, sharedWith: sharedKeyWith } : { kind: "managed-exclusive", keyRef: p.keyRef } : p.apiKeyEnv ? { kind: "environment", variable: p.apiKeyEnv } : p.apiKey ? { kind: "inline-legacy" } : { kind: "none" };
975
+ return {
976
+ name,
977
+ modelCount: p.models.length,
978
+ baseUrl: p.baseUrl,
979
+ isDefault: name === opts.defaultProvider,
980
+ sharedKeyWith,
981
+ credentialImpact,
982
+ defaultModelDangling: !!opts.defaultModelRef && opts.defaultModelRef.startsWith(`${name}:`)
983
+ };
984
+ });
985
+ }
986
+ function toChoiceEntries(entries) {
987
+ return entries.map((e) => {
988
+ const notes = [];
989
+ if (e.isDefault) notes.push("\u5F53\u524D\u9ED8\u8BA4\u2014\u2014\u9009\u4E2D\u540E\u5148\u6539\u8BBE\u65B0\u9ED8\u8BA4\uFF0C\u518D\u56DE\u6765\u5220\u9664");
990
+ if (e.sharedKeyWith.length > 0) notes.push(`\u4E0E ${e.sharedKeyWith.join("\u3001")} \u5171\u7528\u540C\u4E00 key\uFF08\u72EC\u7ACB\u5220\u9664\uFF09`);
991
+ if (e.defaultModelDangling) notes.push("\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u5728\u6B64\u7EC4\u5185\uFF0C\u5220\u9664\u65F6\u4E00\u5E76\u6E05\u9664");
992
+ const description = [`${e.modelCount} \u4E2A\u6A21\u578B \xB7 ${hostOf(e.baseUrl)}`, ...notes].join("\uFF1B");
993
+ return { id: e.name, label: e.name, description, current: e.isDefault };
994
+ });
995
+ }
996
+ function buildDisconnectImpactText(entry) {
997
+ switch (entry.credentialImpact.kind) {
998
+ case "managed-exclusive":
999
+ return `\u5220\u9664 provider \u6761\u76EE\u548C ${entry.modelCount} \u4E2A\u6A21\u578B\uFF0C\u5E76\u5220\u9664 secrets.json \u4E2D\u6258\u7BA1\u7684 API key`;
1000
+ case "managed-shared":
1001
+ return `\u5220\u9664 provider \u6761\u76EE\u548C ${entry.modelCount} \u4E2A\u6A21\u578B\uFF1BAPI key \u4ECD\u88AB ${entry.credentialImpact.sharedWith.join("\u3001")} \u4F7F\u7528\uFF0C\u5C06\u4FDD\u7559`;
1002
+ case "environment":
1003
+ return `\u5220\u9664 provider \u6761\u76EE\u548C ${entry.modelCount} \u4E2A\u6A21\u578B\uFF1B\u73AF\u5883\u53D8\u91CF ${entry.credentialImpact.variable} \u4E0D\u4F1A\u4FEE\u6539`;
1004
+ case "inline-legacy":
1005
+ return `\u5220\u9664 provider \u6761\u76EE\u548C ${entry.modelCount} \u4E2A\u6A21\u578B\uFF1B\u914D\u7F6E\u4E2D\u7684\u65E7\u9274\u6743\u4FE1\u606F\u968F\u914D\u7F6E\u5220\u9664`;
1006
+ case "none":
1007
+ return `\u53EA\u5220\u9664 provider \u6761\u76EE\u548C ${entry.modelCount} \u4E2A\u6A21\u578B`;
1008
+ }
1009
+ }
1010
+ function buildConfirmTitle(entry) {
1011
+ const dangling = entry.defaultModelDangling ? "\n\u26A0 \u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u6307\u5411\u6B64\u7EC4\u2014\u2014\u5220\u9664\u65F6\u5C06\u4E00\u5E76\u6E05\u9664" : "";
1012
+ return `\u65AD\u5F00\u300C${entry.name}\u300D\uFF1F${buildDisconnectImpactText(entry)}\uFF0C\u4E0D\u53EF\u64A4\u9500\u3002${dangling}`;
1013
+ }
1014
+ function buildPostDeleteMessage(target, removal, runtime) {
1015
+ const base = `\u5DF2\u65AD\u5F00 ${target}\uFF08${removal.modelCount} \u4E2A\u6A21\u578B\uFF09${removal.secretNote}`;
1016
+ if (!runtime.needed) return { text: base, isError: false };
1017
+ if (runtime.switched) {
1018
+ return {
1019
+ text: `${base}\uFF1B\u5F53\u524D\u4F1A\u8BDD\u5DF2\u5207\u6362\u5230 ${runtime.targetModel ?? "\u9ED8\u8BA4\u6A21\u578B"}`,
1020
+ isError: false
1021
+ };
1022
+ }
1023
+ return {
1024
+ text: `${base}\uFF0C\u4F46\u5F53\u524D\u4F1A\u8BDD\u5207\u6362\u5931\u8D25\uFF1A${runtime.error ?? "\u672A\u77E5\u539F\u56E0"}\u3002\u8BF7\u8FD0\u884C /model \u9009\u62E9\u53EF\u7528\u6A21\u578B\u3002`,
1025
+ isError: true
1026
+ };
1027
+ }
1028
+ function buildRetargetEntries(providers, currentDefault) {
1029
+ return Object.entries(providers).filter(([name, p]) => name !== currentDefault && p.userSaved && p.models.length > 0).map(([name, p]) => ({ name, modelCount: p.models.length, baseUrl: p.baseUrl }));
1030
+ }
1031
+ function toRetargetChoiceEntries(entries) {
1032
+ return entries.map((e) => ({
1033
+ id: e.name,
1034
+ label: e.name,
1035
+ description: `${e.modelCount} \u4E2A\u6A21\u578B \xB7 ${hostOf(e.baseUrl)}`
1036
+ }));
1037
+ }
1038
+ function buildRetargetTitle(currentDefault) {
1039
+ return `\u300C${currentDefault}\u300D\u662F\u5F53\u524D\u9ED8\u8BA4 provider\uFF0C\u4E0D\u53EF\u76F4\u63A5\u5220\u9664\u3002
1040
+ \u8BF7\u5148\u9009\u62E9\u65B0\u7684\u9ED8\u8BA4 provider\u2014\u2014\u6539\u8BBE\u540E\u8FD4\u56DE\u5217\u8868\u5373\u53EF\u5220\u9664\u539F\u9ED8\u8BA4\u3002`;
1041
+ }
1042
+
1043
+ // src/agent/risk-explain.ts
1044
+ init_esm_shims();
1045
+
1046
+ // src/agent/side-path-ask.ts
1047
+ init_esm_shims();
1048
+ var DEFAULT_TIMEOUT_MS = 3e4;
1049
+ async function askSidePath(deps, params) {
1050
+ if (!deps.client) return null;
1051
+ const request = deps.promptEngine.buildOaiRequest(
1052
+ [...deps.getMessages(), { role: "user", content: params.instruction }],
1053
+ void 0,
1054
+ deps.contextWindow,
1055
+ { sidePath: true }
1056
+ );
1057
+ request.tools = void 0;
1058
+ request.tool_choice = "none";
1059
+ const chunks = [];
1060
+ let errored = false;
1061
+ const timeoutSignal = AbortSignal.timeout(params.timeoutMs ?? DEFAULT_TIMEOUT_MS);
1062
+ const signal = params.signal ? AbortSignal.any([params.signal, timeoutSignal]) : timeoutSignal;
1063
+ try {
1064
+ await deps.client.stream(request, {
1065
+ onTextDelta: (text2) => {
1066
+ chunks.push(text2);
1067
+ params.onDelta?.(text2);
1068
+ },
1069
+ onThinkingDelta: () => {
1070
+ },
1071
+ onContentBlock: () => {
1072
+ },
1073
+ onStopReason: (_reason, usage) => {
1074
+ if (usage && (usage.input_tokens ?? 0) > 0) {
1075
+ deps.recordUsage?.(usage, request.model);
1076
+ }
1077
+ },
1078
+ onError: () => {
1079
+ errored = true;
1080
+ }
1081
+ }, signal);
1082
+ } catch {
1083
+ return null;
1084
+ }
1085
+ if (errored) return null;
1086
+ const text = chunks.join("").trim();
1087
+ return text.length > 0 ? text : null;
1088
+ }
1089
+
1090
+ // src/agent/risk-explain.ts
1091
+ var DEFAULT_TIMEOUT_MS2 = 2e4;
1092
+ var MAX_LINES = 6;
1093
+ function buildInstruction(toolName, input) {
1094
+ let rendered;
1095
+ try {
1096
+ rendered = JSON.stringify(input, null, 2);
1097
+ } catch {
1098
+ rendered = String(input);
1099
+ }
1100
+ if (rendered.length > 4e3) rendered = rendered.slice(0, 4e3) + "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09";
1101
+ return [
1102
+ "\u3010\u4FA7\u8DEF\u63D0\u95EE\uFF0C\u4E0D\u5F71\u54CD\u4E3B\u4EFB\u52A1\u3011\u4E0A\u9762\u662F\u5F53\u524D\u5BF9\u8BDD\u3002agent \u6B63\u8BF7\u6C42\u6267\u884C\u4E0B\u9762\u8FD9\u4E2A\u5DE5\u5177\uFF0C\u7B49\u5F85\u7528\u6237\u6279\u51C6\uFF1A",
1103
+ "",
1104
+ `\u5DE5\u5177\uFF1A${toolName}`,
1105
+ "\u53C2\u6570\uFF1A",
1106
+ "```json",
1107
+ rendered,
1108
+ "```",
1109
+ "",
1110
+ "\u8BF7\u57FA\u4E8E\u4E0A\u8FF0\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u5E2E\u7528\u6237\u5224\u65AD\u662F\u5426\u8BE5\u6279\u51C6\u3002\u56DE\u7B54\u4E09\u70B9\uFF1A",
1111
+ "1. \u5B83\u5B9E\u9645\u4F1A\u505A\u4EC0\u4E48\uFF08\u4E0D\u8981\u590D\u8FF0\u53C2\u6570\uFF0C\u8BF4\u6548\u679C\uFF09",
1112
+ "2. \u7ED3\u5408\u5F53\u524D\u5BF9\u8BDD\uFF0C\u4E3A\u4EC0\u4E48\u8FD9\u4E00\u6B65\u662F\u9700\u8981\u7684",
1113
+ "3. \u6279\u51C6\u540E\u53EF\u80FD\u51FA\u4EC0\u4E48\u95EE\u9898\u2014\u2014\u662F\u5426\u4E0D\u53EF\u9006\u3001\u5F71\u54CD\u8303\u56F4\u591A\u5927",
1114
+ "",
1115
+ "\u7B2C\u4E00\u884C\u5FC5\u987B\u662F `RISK: low`\u3001`RISK: medium` \u6216 `RISK: high` \u4E09\u8005\u4E4B\u4E00\uFF0C",
1116
+ `\u5176\u540E\u7528\u4E2D\u6587\u7B80\u8FF0\uFF0C\u6700\u591A ${MAX_LINES} \u884C\uFF0C\u4E0D\u8981\u7528\u6807\u9898\u3001\u4E0D\u8981\u8C03\u7528\u5DE5\u5177\u3002`,
1117
+ "\u8BC4\u7EA7\u53E3\u5F84\uFF1A\u53EA\u8BFB\u6216\u6613\u64A4\u9500 = low\uFF1B\u4F1A\u6539\u52A8\u5DE5\u4F5C\u533A\u4F46\u53EF\u56DE\u6EDA = medium\uFF1B",
1118
+ "\u4E0D\u53EF\u9006\u3001\u89E6\u53CA\u5DE5\u4F5C\u533A\u5916\u3001\u6216\u4F1A\u5F71\u54CD\u8FDC\u7AEF/\u751F\u4EA7 = high\u3002"
1119
+ ].join("\n");
1120
+ }
1121
+ function parseRiskExplanation(raw) {
1122
+ const text = raw.trim();
1123
+ if (!text) return null;
1124
+ const lines = text.split("\n");
1125
+ let level = "medium";
1126
+ let bodyStart = 0;
1127
+ const head = lines[0]?.trim() ?? "";
1128
+ const m = /^`?RISK:\s*(low|medium|high)`?/i.exec(head);
1129
+ if (m) {
1130
+ level = m[1].toLowerCase();
1131
+ bodyStart = 1;
1132
+ }
1133
+ const body = lines.slice(bodyStart).map((l) => l.replace(/\s+$/, "")).filter((l, i, arr) => !(l === "" && (i === 0 || arr[i - 1] === "")));
1134
+ while (body.length > 0 && body[0] === "") body.shift();
1135
+ while (body.length > 0 && body[body.length - 1] === "") body.pop();
1136
+ if (body.length === 0) return null;
1137
+ return { level, lines: body.slice(0, MAX_LINES) };
1138
+ }
1139
+ async function explainToolRisk(deps, params) {
1140
+ const raw = await askSidePath(deps, {
1141
+ instruction: buildInstruction(params.toolName, params.input),
1142
+ timeoutMs: params.timeoutMs ?? DEFAULT_TIMEOUT_MS2,
1143
+ signal: params.signal
1144
+ });
1145
+ return raw === null ? null : parseRiskExplanation(raw);
1146
+ }
1147
+
1148
+ // src/agent/side-question.ts
1149
+ init_esm_shims();
1150
+ var DEFAULT_TIMEOUT_MS3 = 45e3;
1151
+ function buildSideQuestionInstruction(question) {
1152
+ return [
1153
+ "\u3010\u4FA7\u8DEF\u63D0\u95EE\u3011\u7528\u6237\u5728\u4E0D\u6253\u65AD\u5F53\u524D\u4EFB\u52A1\u7684\u524D\u63D0\u4E0B\u95EE\u4E86\u4E00\u4E2A\u95EE\u9898\u3002",
1154
+ "\u4F60\u7684\u56DE\u7B54**\u4E0D\u4F1A\u8FDB\u5165\u5BF9\u8BDD\u5386\u53F2**\uFF0C\u4E5F\u4E0D\u4F1A\u5F71\u54CD\u6B63\u5728\u8FDB\u884C\u7684\u5DE5\u4F5C\u3002",
1155
+ "",
1156
+ "\u89C4\u5219\uFF1A",
1157
+ "- \u4F60**\u6CA1\u6709\u4EFB\u4F55\u5DE5\u5177**\u3002\u53EA\u80FD\u57FA\u4E8E\u4E0A\u9762\u5DF2\u6709\u7684\u5BF9\u8BDD\u5185\u5BB9\u56DE\u7B54\u3002",
1158
+ "- \u9700\u8981\u8BFB\u6587\u4EF6\u3001\u8DD1\u547D\u4EE4\u3001\u67E5\u5916\u90E8\u8D44\u6599\u624D\u80FD\u7B54\u7684\uFF0C\u76F4\u63A5\u8BF4\u660E\u9700\u8981\u4EC0\u4E48\uFF0C\u4E0D\u8981\u731C\u3002",
1159
+ "- \u4E0D\u8981\u6267\u884C\u4EFB\u52A1\u3001\u4E0D\u8981\u6539\u4EE3\u7801\u3001\u4E0D\u8981\u7ED9\u51FA\u5F85\u529E\u6E05\u5355\u2014\u2014\u8FD9\u662F\u4E00\u6B21\u95EE\u7B54\uFF0C\u4E0D\u662F\u4E00\u6B21\u59D4\u6D3E\u3002",
1160
+ "- \u7B80\u6D01\u4F5C\u7B54\uFF0C\u80FD\u4E00\u6BB5\u8BF4\u6E05\u5C31\u4E0D\u8981\u5206\u70B9\u3002",
1161
+ "",
1162
+ "\u95EE\u9898\uFF1A",
1163
+ question
1164
+ ].join("\n");
1165
+ }
1166
+ async function askSideQuestion(deps, params) {
1167
+ const question = params.question.trim();
1168
+ if (!question) return null;
1169
+ return askSidePath(deps, {
1170
+ instruction: buildSideQuestionInstruction(question),
1171
+ timeoutMs: params.timeoutMs ?? DEFAULT_TIMEOUT_MS3,
1172
+ signal: params.signal,
1173
+ onDelta: params.onDelta
1174
+ });
1175
+ }
1176
+
1177
+ // src/tui/worker-detail.ts
1178
+ init_esm_shims();
1179
+ var MAX_CONTENT_CHARS = 500;
1180
+ function truncate(text, max = MAX_CONTENT_CHARS) {
1181
+ if (text.length <= max) return text;
1182
+ return text.slice(0, max - 1) + "\u2026";
1183
+ }
1184
+ function formatTokens(usage) {
1185
+ if (!usage) return "-";
1186
+ const parts = [];
1187
+ if (usage.input_tokens !== void 0) parts.push(`in ${usage.input_tokens}`);
1188
+ if (usage.output_tokens !== void 0) parts.push(`out ${usage.output_tokens}`);
1189
+ if (usage.cache_read_input_tokens) parts.push(`cache ${usage.cache_read_input_tokens}`);
1190
+ if (usage.reasoning_tokens) parts.push(`reason ${usage.reasoning_tokens}`);
1191
+ return parts.join(" \xB7 ") || "-";
1192
+ }
1193
+ function formatRoundTime(ms) {
1194
+ if (!ms) return "-- --:--";
1195
+ const d = new Date(ms);
1196
+ const p = (n) => String(n).padStart(2, "0");
1197
+ return `${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
1198
+ }
1199
+ function formatOaiMessages(messages) {
1200
+ const lines = [];
1201
+ for (const msg of messages) {
1202
+ switch (msg.role) {
1203
+ case "system": {
1204
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1205
+ lines.push(`\u250C\u2500 system`);
1206
+ lines.push(truncate(text));
1207
+ break;
1208
+ }
1209
+ case "user": {
1210
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1211
+ lines.push(`\u258C you`);
1212
+ lines.push(truncate(text));
1213
+ break;
1214
+ }
1215
+ case "assistant": {
1216
+ const text = typeof msg.content === "string" ? msg.content : "";
1217
+ if (text) {
1218
+ lines.push(truncate(text));
1219
+ }
1220
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
1221
+ for (const tc of msg.tool_calls) {
1222
+ const name = tc.function?.name ?? "?";
1223
+ const args2 = tc.function?.arguments ?? "{}";
1224
+ lines.push(`\u25CF ${name} ${truncate(args2, 160)}`);
1225
+ }
1226
+ }
1227
+ break;
1228
+ }
1229
+ case "tool": {
1230
+ lines.push(`\u25CF tool result ${msg.tool_call_id ?? ""}`);
1231
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1232
+ lines.push(truncate(text));
1233
+ break;
1234
+ }
1235
+ }
1236
+ }
1237
+ return lines.join("\n");
1238
+ }
1239
+ function buildWorkerDetailContent(workerId, cwd, liveView) {
1240
+ const shortLabel = liveView?.shortLabel ?? shortOrderLabel(workerId);
1241
+ const lines = [];
1242
+ lines.push(`\u2550\u2550 \u5B50\u4EE3\u7406 ${shortLabel} \u2550\u2550`);
1243
+ const identity = liveView ? formatWorkerIdentity({ profile: liveView.profile, authority: liveView.authority }) : shortLabel;
1244
+ const statusText = liveView ? statusWord(liveView.status) : "unknown";
1245
+ const elapsedText = liveView?.elapsedMs !== void 0 ? ` \xB7 ${formatElapsed(liveView.elapsedMs)}` : "";
1246
+ lines.push(`${identity} \xB7 ${statusText}${elapsedText}`);
1247
+ if (liveView?.contract?.objective) {
1248
+ lines.push(`\u76EE\u6807\uFF1A${truncate(liveView.contract.objective)}`);
1249
+ }
1250
+ const paramLines = [];
1251
+ if (liveView?.contract) {
1252
+ const c = liveView.contract;
1253
+ paramLines.push(`\u5DE5\u5177\uFF1A${c.allowedToolsDigest}`);
1254
+ paramLines.push(`\u9884\u7B97\uFF1A${c.budget.maxTurns} \u8F6E \xB7 ${Math.floor(c.budget.timeoutMs / 1e3)}s`);
1255
+ if (c.scope.files?.length) {
1256
+ paramLines.push(`\u8303\u56F4\uFF1A${c.scope.files.slice(0, 5).join(", ")}${c.scope.files.length > 5 ? ` +${c.scope.files.length - 5}` : ""}`);
1257
+ }
1258
+ }
1259
+ paramLines.push(`id: ${workerId}`);
1260
+ if (liveView?.authority) paramLines.push(`\u661F\u57DF\uFF1A${formatAuthorityLabel(liveView.authority, liveView.authorityReason)}`);
1261
+ if (liveView?.activityLog && liveView.activityLog.length > 0) {
1262
+ lines.push("");
1263
+ lines.push("\u2500\u2500 \u6D3B\u52A8 \u2500\u2500");
1264
+ for (const entry of liveView.activityLog) {
1265
+ lines.push(` ${entry}`);
1266
+ }
1267
+ }
1268
+ const result = loadPersistedResult(workerId);
1269
+ if (result) {
1270
+ lines.push("");
1271
+ lines.push("\u2500\u2500 \u7ED3\u679C \u2500\u2500");
1272
+ lines.push(formatWorkerResultDigest({
1273
+ status: result.status,
1274
+ summary: result.summary,
1275
+ findingsCount: result.findings?.length ?? 0,
1276
+ changedFilesCount: result.changedFiles?.length ?? 0,
1277
+ sourcesReviewedCount: result.sourcesReviewed,
1278
+ failureReason: result.failureReason,
1279
+ evidenceStatus: result.evidenceStatus,
1280
+ salvagedFindingsCount: result.findings?.filter((f) => f.salvaged === true).length ?? 0
1281
+ }));
1282
+ if (result.findings && result.findings.length > 0) {
1283
+ lines.push("\u53D1\u73B0\uFF1A");
1284
+ for (const f of result.findings.slice(0, 5)) {
1285
+ const conf = f.confidence ? ` [${f.confidence}]` : "";
1286
+ lines.push(` \xB7${conf} ${truncate(f.claim, 120)}`);
1287
+ }
1288
+ if (result.findings.length > 5) lines.push(` \u2026 \u8FD8\u6709 ${result.findings.length - 5} \u6761`);
1289
+ }
1290
+ if (result.verification) {
1291
+ const v = result.verification;
1292
+ const g = v.status === "passed" ? "\u2705" : v.status === "failed" ? "\u274C" : "\u26A0";
1293
+ lines.push(`\u9A8C\u8BC1\uFF1A${g} ${v.passed ?? 0}/${(v.passed ?? 0) + (v.failed ?? 0)} \u901A\u8FC7 \xB7 ${v.command}`);
1294
+ }
1295
+ if (result.changedFiles && result.changedFiles.length > 0) {
1296
+ lines.push("\u6539\u52A8\u6587\u4EF6\uFF1A");
1297
+ for (const f of result.changedFiles.slice(0, 20)) lines.push(` \xB7 ${f}`);
1298
+ if (result.changedFiles.length > 20) lines.push(` \u2026 \u8FD8\u6709 ${result.changedFiles.length - 20} \u4E2A`);
1299
+ }
1300
+ if (result.nextActions && result.nextActions.length > 0) {
1301
+ lines.push("\u540E\u7EED\u52A8\u4F5C\uFF1A");
1302
+ for (const a of result.nextActions.slice(0, 5)) lines.push(` \xB7 ${truncate(a, 120)}`);
1303
+ }
1304
+ if (result.risks && result.risks.length > 0) {
1305
+ lines.push("\u98CE\u9669\uFF1A");
1306
+ for (const r of result.risks.slice(0, 10)) lines.push(` \xB7 ${r}`);
1307
+ }
1308
+ if (result.artifacts && result.artifacts.length > 0) {
1309
+ lines.push("\u4EA7\u7269\uFF1A");
1310
+ for (const a of result.artifacts) {
1311
+ lines.push(` \xB7 [${a.kind}] ${a.title}`);
1312
+ lines.push(` ${truncate(a.content, 200)}`);
1313
+ }
1314
+ }
1315
+ lines.push("");
1316
+ lines.push("\u2500\u2500 \u53C2\u6570 \u2500\u2500");
1317
+ if (result.model) lines.push(`\u6A21\u578B\uFF1A${result.model}`);
1318
+ if (result.provider) lines.push(`\u63D0\u4F9B\u5546\uFF1A${result.provider}`);
1319
+ if (result.usage) lines.push(`\u7528\u91CF\uFF1A${formatTokens(result.usage)}`);
1320
+ lines.push(...paramLines);
1321
+ } else if (paramLines.length > 0) {
1322
+ lines.push("");
1323
+ lines.push("\u2500\u2500 \u53C2\u6570 \u2500\u2500");
1324
+ lines.push(...paramLines);
1325
+ }
1326
+ const rounds = listPersistedResultRounds(workerId);
1327
+ if (rounds.length > 1) {
1328
+ lines.push("");
1329
+ lines.push(`\u2500\u2500 Rounds \u2500\u2500 \u8BE5 id \u6D3E\u53D1\u4E86 ${rounds.length} \u6B21\uFF0CResult \u4E3A\u6700\u65B0\u4E00\u8F6E`);
1330
+ rounds.forEach((round, i) => {
1331
+ const r = loadPersistedResultRound(workerId, round.nonce);
1332
+ const status = r?.status ?? "?";
1333
+ const summary = r ? ` \xB7 ${truncate(r.summary, 60)}` : "";
1334
+ lines.push(` #${i + 1} ${formatRoundTime(round.savedAt)} \xB7 ${status}${summary}`);
1335
+ });
1336
+ }
1337
+ const sessionId = `worker-${workerId.replace(/:/g, "-")}`;
1338
+ const persist = new SessionPersist(sessionId, cwd);
1339
+ let transcriptText = "";
1340
+ try {
1341
+ const messages = persist.loadOai();
1342
+ transcriptText = formatOaiMessages(messages);
1343
+ } catch {
1344
+ transcriptText = "(worker transcript not available)";
1345
+ }
1346
+ if (transcriptText) {
1347
+ lines.push("");
1348
+ lines.push("\u2500\u2500 \u8F6C\u5F55 \u2500\u2500");
1349
+ lines.push(transcriptText);
1350
+ }
1351
+ const content = lines.join("\n");
1352
+ return {
1353
+ content,
1354
+ title: `\u5B50\u4EE3\u7406 ${shortLabel}`,
1355
+ messages: parseScrollbackTranscript(content)
1356
+ };
1357
+ }
1358
+
1359
+ // src/tui/engine/exit-cleanup.ts
1360
+ init_esm_shims();
1361
+ function registerExitCleanup(deps) {
1362
+ process.on("exit", () => {
1363
+ try {
1364
+ deps.restoreTerminalSync();
1365
+ } catch {
1366
+ }
1367
+ try {
1368
+ if (process.stdin.isTTY && process.stdin.setRawMode) process.stdin.setRawMode(false);
1369
+ } catch {
1370
+ }
1371
+ try {
1372
+ deps.killMcpChildrenSync();
1373
+ } catch {
1374
+ }
1375
+ try {
1376
+ killAllSync();
1377
+ } catch {
1378
+ }
1379
+ });
1380
+ }
1381
+
1382
+ // src/tui/theme-custom.ts
1383
+ init_esm_shims();
1384
+ init_paths();
1385
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
1386
+ import { join as join3, basename } from "path";
1387
+ function customThemesDir(base) {
1388
+ return join3(base ?? rivetHome(), "themes");
1389
+ }
1390
+ var HEX_RE = /^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/;
1391
+ var COLOR_KEYS = [
1392
+ "primary",
1393
+ "secondary",
1394
+ "success",
1395
+ "warning",
1396
+ "error",
1397
+ "dim",
1398
+ "pulseQuiet",
1399
+ "pulseActive",
1400
+ "pulseAlert",
1401
+ "toolShell",
1402
+ "toolEdit",
1403
+ "toolTest",
1404
+ "toolDelegate"
1405
+ ];
1406
+ var OVERRIDE_KEYS = [
1407
+ "userColor",
1408
+ "assistantColor",
1409
+ "muted",
1410
+ "systemColor",
1411
+ "inlineCode"
1412
+ ];
1413
+ function pickHexFields(raw, keys) {
1414
+ const out = {};
1415
+ if (typeof raw !== "object" || raw === null) return out;
1416
+ for (const key of keys) {
1417
+ const v = raw[key];
1418
+ if (typeof v === "string" && HEX_RE.test(v)) out[key] = v;
1419
+ }
1420
+ return out;
1421
+ }
1422
+ function parseCustomThemeJson(text) {
1423
+ let raw;
1424
+ try {
1425
+ raw = JSON.parse(text);
1426
+ } catch {
1427
+ return null;
1428
+ }
1429
+ if (typeof raw !== "object" || raw === null) return null;
1430
+ const obj = raw;
1431
+ const input = {};
1432
+ if (typeof obj.base === "string" && obj.base in THEME_PALETTES) {
1433
+ input.base = obj.base;
1434
+ }
1435
+ if (obj.background === "dark" || obj.background === "light") input.background = obj.background;
1436
+ if (typeof obj.description === "string") input.description = obj.description;
1437
+ input.colors = pickHexFields(obj.colors, COLOR_KEYS);
1438
+ input.overrides = pickHexFields(obj.overrides, OVERRIDE_KEYS);
1439
+ return input;
1440
+ }
1441
+ var NAME_RE = /^[A-Za-z0-9_-]+$/;
1442
+ function loadCustomThemes(baseDir) {
1443
+ const dir = customThemesDir(baseDir);
1444
+ let files;
1445
+ try {
1446
+ files = readdirSync2(dir).filter((f) => f.endsWith(".json"));
1447
+ } catch {
1448
+ return [];
1449
+ }
1450
+ const loaded = [];
1451
+ for (const file of files) {
1452
+ const name = basename(file, ".json");
1453
+ if (!NAME_RE.test(name)) continue;
1454
+ try {
1455
+ const input = parseCustomThemeJson(readFileSync2(join3(dir, file), "utf8"));
1456
+ if (!input) {
1457
+ process.stderr.write(`[theme] skip invalid custom theme: ${file}
1458
+ `);
1459
+ continue;
1460
+ }
1461
+ registerCustomTheme(name, input);
1462
+ loaded.push(name);
1463
+ } catch {
1464
+ process.stderr.write(`[theme] failed to read custom theme: ${file}
1465
+ `);
1466
+ }
1467
+ }
1468
+ return loaded;
1469
+ }
1470
+
1471
+ // src/tui/theme-detect.ts
1472
+ init_esm_shims();
1473
+ function parseOsc11Luminance(response) {
1474
+ const m = response.match(/rgb:([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})\/([0-9a-fA-F]{1,4})/);
1475
+ if (!m) return null;
1476
+ const norm = (s) => parseInt(s, 16) / (16 ** s.length - 1);
1477
+ const r = norm(m[1]), g = norm(m[2]), b = norm(m[3]);
1478
+ return 0.299 * r + 0.587 * g + 0.114 * b;
1479
+ }
1480
+ function parseColorFgBg(env) {
1481
+ if (!env) return null;
1482
+ const parts = env.split(";");
1483
+ const bgRaw = parts[parts.length - 1]?.trim();
1484
+ if (!bgRaw || !/^\d+$/.test(bgRaw)) return null;
1485
+ const bgIndex = Number(bgRaw);
1486
+ return bgIndex === 7 || bgIndex === 15 ? "light" : "dark";
1487
+ }
1488
+ async function detectTerminalBackground(opts = {}) {
1489
+ const stdin = opts.stdin ?? process.stdin;
1490
+ const stdout = opts.stdout ?? process.stdout;
1491
+ const env = opts.env ?? process.env;
1492
+ const timeoutMs = opts.timeoutMs ?? 500;
1493
+ const fallback = () => parseColorFgBg(env.COLORFGBG) ?? "dark";
1494
+ if (!stdin.isTTY || !stdout.isTTY) return fallback();
1495
+ const wasRaw = stdin.isRaw === true;
1496
+ try {
1497
+ const result = await new Promise((resolve) => {
1498
+ let buffer = "";
1499
+ let done = false;
1500
+ const finish = (value) => {
1501
+ if (done) return;
1502
+ done = true;
1503
+ clearTimeout(timer);
1504
+ stdin.off("data", onData);
1505
+ try {
1506
+ if (!wasRaw) stdin.setRawMode(false);
1507
+ } catch {
1508
+ }
1509
+ stdin.pause();
1510
+ resolve(value);
1511
+ };
1512
+ const onData = (chunk) => {
1513
+ buffer += chunk.toString("latin1");
1514
+ if (/\]11;.*(\x07|\x1B\\)/.test(buffer)) {
1515
+ const lum = parseOsc11Luminance(buffer);
1516
+ finish(lum === null ? null : lum > 0.5 ? "light" : "dark");
1517
+ }
1518
+ };
1519
+ const timer = setTimeout(() => finish(null), timeoutMs);
1520
+ try {
1521
+ if (!wasRaw) stdin.setRawMode(true);
1522
+ stdin.resume();
1523
+ stdin.on("data", onData);
1524
+ stdout.write("\x1B]11;?\x07");
1525
+ } catch {
1526
+ finish(null);
1527
+ }
1528
+ });
1529
+ return result ?? fallback();
1530
+ } catch {
1531
+ return fallback();
1532
+ }
1533
+ }
1534
+ function autoThemeFor(background) {
1535
+ return background === "light" ? "paper" : "graphite";
1536
+ }
1537
+
1538
+ // src/tui/statusline.ts
1539
+ init_esm_shims();
1540
+ import { spawn } from "child_process";
1541
+ var StatusLineRunner = class {
1542
+ constructor(config, onUpdate) {
1543
+ this.onUpdate = onUpdate;
1544
+ this.command = config.command;
1545
+ this.intervalMs = config.intervalMs ?? 3e3;
1546
+ this.timeoutMs = config.timeoutMs ?? 2e3;
1547
+ }
1548
+ onUpdate;
1549
+ command;
1550
+ intervalMs;
1551
+ timeoutMs;
1552
+ lastRunMs = 0;
1553
+ inFlight = false;
1554
+ lastOutput = null;
1555
+ /** 当前缓存的 statusline 文本(脚本 stdout 首行)。 */
1556
+ get current() {
1557
+ return this.lastOutput;
1558
+ }
1559
+ /**
1560
+ * 请求刷新。节流 + 单飞;实际执行时把 payload JSON 写入脚本 stdin。
1561
+ * 失败/超时静默保留上一次输出。
1562
+ */
1563
+ refresh(payload) {
1564
+ const now = Date.now();
1565
+ if (this.inFlight || now - this.lastRunMs < this.intervalMs) return;
1566
+ this.lastRunMs = now;
1567
+ this.inFlight = true;
1568
+ let child;
1569
+ try {
1570
+ child = spawn(this.command, { shell: true, stdio: ["pipe", "pipe", "ignore"], windowsHide: true });
1571
+ } catch {
1572
+ this.inFlight = false;
1573
+ return;
1574
+ }
1575
+ let stdout = "";
1576
+ let settled = false;
1577
+ const settle = () => {
1578
+ if (settled) return;
1579
+ settled = true;
1580
+ clearTimeout(timer);
1581
+ this.inFlight = false;
1582
+ const firstLine = stdout.split("\n")[0]?.trim() ?? "";
1583
+ if (firstLine) {
1584
+ this.lastOutput = firstLine.slice(0, 300);
1585
+ this.onUpdate(this.lastOutput);
1586
+ }
1587
+ };
1588
+ const timer = setTimeout(() => {
1589
+ try {
1590
+ child.kill("SIGKILL");
1591
+ } catch {
1592
+ }
1593
+ settle();
1594
+ }, this.timeoutMs);
1595
+ child.stdout?.on("data", (chunk) => {
1596
+ stdout += chunk.toString("utf8");
1597
+ });
1598
+ child.on("error", () => settle());
1599
+ child.on("close", () => settle());
1600
+ try {
1601
+ child.stdin?.write(JSON.stringify(payload));
1602
+ child.stdin?.end();
1603
+ } catch {
1604
+ }
1605
+ }
1606
+ };
1607
+
1608
+ // src/tui/transcript-verbose.ts
1609
+ init_esm_shims();
1610
+ var MAX_TOOL_RESULT_CHARS = 1e5;
1611
+ function guard(text) {
1612
+ if (text.length <= MAX_TOOL_RESULT_CHARS) return text;
1613
+ return `${text.slice(0, MAX_TOOL_RESULT_CHARS)}
1614
+ \u2026 (truncated at ${MAX_TOOL_RESULT_CHARS} chars; full output in session jsonl)`;
1615
+ }
1616
+ function contentToText(content) {
1617
+ if (typeof content === "string") return content;
1618
+ if (content == null) return "";
1619
+ return JSON.stringify(content);
1620
+ }
1621
+ function buildVerboseTranscript(messages) {
1622
+ const lines = [];
1623
+ for (const msg of messages) {
1624
+ switch (msg.role) {
1625
+ case "system":
1626
+ break;
1627
+ case "user": {
1628
+ lines.push("\u258C you");
1629
+ lines.push(contentToText(msg.content));
1630
+ lines.push("");
1631
+ break;
1632
+ }
1633
+ case "assistant": {
1634
+ const text = typeof msg.content === "string" ? msg.content : "";
1635
+ if (text) {
1636
+ lines.push(text);
1637
+ }
1638
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
1639
+ for (const tc of msg.tool_calls) {
1640
+ const name = tc.function?.name ?? "?";
1641
+ const args2 = tc.function?.arguments ?? "{}";
1642
+ lines.push(`\u25CF ${name} ${guard(args2)}`);
1643
+ }
1644
+ }
1645
+ if (text || msg.tool_calls && msg.tool_calls.length > 0) lines.push("");
1646
+ break;
1647
+ }
1648
+ case "tool": {
1649
+ lines.push(`\u25CF tool result ${msg.tool_call_id ?? ""}`);
1650
+ lines.push(guard(contentToText(msg.content)));
1651
+ lines.push("");
1652
+ break;
1653
+ }
1654
+ }
1655
+ }
1656
+ const content = lines.join("\n");
1657
+ return { content, messages: parseScrollbackTranscript(content) };
1658
+ }
1659
+
1660
+ // src/tui/model-picker-selection.ts
1661
+ init_esm_shims();
1662
+ function isCurrentModelSelection(provider, modelId, activeProvider, activeModelId) {
1663
+ return provider === activeProvider && modelId === activeModelId;
1664
+ }
1665
+
1666
+ // src/tui/initial-status.ts
1667
+ init_esm_shims();
1668
+ function resolveInitialModelName(input) {
1669
+ const configuredModelId = input.defaultModelRef && input.defaultModelRef.includes(":") ? input.defaultModelRef.slice(input.defaultModelRef.indexOf(":") + 1) : void 0;
1670
+ const displayRef = input.runtimeModelId ?? configuredModelId;
1671
+ const configuredModel = displayRef ? input.models.find((m) => m.id === displayRef || m.alias === displayRef) : void 0;
1672
+ const currentModel = configuredModel ?? input.models[0];
1673
+ const modelName = displayRef ? configuredModel?.alias ?? displayRef : currentModel?.alias ?? currentModel?.id ?? "unknown";
1674
+ return { modelName, currentModel };
1675
+ }
1676
+ function resolveInitialDomainName(input) {
1677
+ return input.agentDomainName ?? (input.defaultDomain && input.defaultDomain !== "auto" ? input.resolve(input.defaultDomain)?.name : void 0);
1678
+ }
1679
+
1680
+ // src/main.ts
1681
+ import { join as join5 } from "path";
1682
+ import { execSync } from "child_process";
1683
+
1684
+ // src/bootstrap/init-scaffold.ts
1685
+ init_esm_shims();
1686
+ import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1687
+ import { join as join4 } from "path";
1688
+ var ACTION_GLYPH = {
1689
+ created: "\u2713",
1690
+ updated: "\u2713",
1691
+ skipped: "\u2013",
1692
+ error: "\u2717"
1693
+ };
1694
+ var ACTION_VERB = {
1695
+ created: "\u5DF2\u521B\u5EFA",
1696
+ updated: "\u5DF2\u66F4\u65B0",
1697
+ skipped: "\u8DF3\u8FC7",
1698
+ error: "\u5931\u8D25"
1699
+ };
1700
+ function formatInitApplyReport(report) {
1701
+ const lines = report.items.map((i) => `${ACTION_GLYPH[i.action]} ${i.path} \u2014 ${ACTION_VERB[i.action]}\uFF1A${i.detail}`);
1702
+ const errors = report.items.filter((i) => i.action === "error").length;
1703
+ const changed = report.items.filter((i) => i.action === "created" || i.action === "updated").length;
1704
+ lines.push(`\u5B8C\u6210\uFF1A${changed} \u9879\u5199\u5165\uFF0C${report.items.length - changed - errors} \u9879\u8DF3\u8FC7${errors > 0 ? `\uFF0C${errors} \u9879\u5931\u8D25` : ""}\u3002`);
1705
+ return lines.join("\n");
1706
+ }
1707
+ function applyVerifyBranch(cwd, items) {
1708
+ const decl = ensureVerifyDeclaration(cwd);
1709
+ if (decl.fingerprint.language === "unknown") {
1710
+ items.push({ path: ".rivet-config.json", action: "skipped", detail: "\u672A\u8BC6\u522B\u7684\u9879\u76EE\u7C7B\u578B\uFF0Cverify \u58F0\u660E\u9700\u624B\u5DE5\u586B\u5199" });
1711
+ return;
1712
+ }
1713
+ items.push({
1714
+ path: ".rivet-config.json",
1715
+ action: decl.wrote ? "updated" : "skipped",
1716
+ detail: decl.wrote ? `verify \u58F0\u660E\u8865\u7F3A\uFF1A${decl.filledKeys.join("\u3001")}\uFF08\u5DF2\u6709 key \u4FDD\u7559\uFF09` : "verify \u58F0\u660E\u5DF2\u662F\u6700\u65B0\uFF0C\u672A\u6539\u52A8"
1717
+ });
1718
+ try {
1719
+ const rivetMdPath = join4(cwd, ".rivet.md");
1720
+ const stack = renderRivetMdStack(decl.fingerprint, decl.verify);
1721
+ const body = existsSync3(rivetMdPath) ? readFileSync3(rivetMdPath, "utf-8") : "# Project\n";
1722
+ const next = upsertStackSection(body, stack);
1723
+ if (next !== body) {
1724
+ writeFileSync2(rivetMdPath, next, "utf-8");
1725
+ items.push({ path: ".rivet.md", action: "updated", detail: "## Stack \u6BB5\u5DF2\u540C\u6B65\uFF08\u7531\u58F0\u660E\u5355\u5411\u751F\u6210\uFF09" });
1726
+ } else {
1727
+ items.push({ path: ".rivet.md", action: "skipped", detail: "## Stack \u6BB5\u5DF2\u662F\u6700\u65B0" });
1728
+ }
1729
+ } catch (e) {
1730
+ items.push({ path: ".rivet.md", action: "error", detail: `\u540C\u6B65\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}` });
1731
+ }
1732
+ }
1733
+ function renderInitSkillMarkdown(spec) {
1734
+ const triggersYaml = "[" + spec.triggers.map((t) => `'${t.replace(/'/g, "")}'`).join(", ") + "]";
1735
+ return [
1736
+ "---",
1737
+ `name: ${spec.slug}`,
1738
+ `description: ${spec.description}`,
1739
+ `triggers: ${triggersYaml}`,
1740
+ "---",
1741
+ "",
1742
+ spec.body.trim(),
1743
+ ""
1744
+ ].join("\n");
1745
+ }
1746
+ function applySkillsBranch(cwd, specs, items) {
1747
+ const dir = join4(cwd, ".rivet", "skills");
1748
+ let installed = countInstalledSkills(cwd);
1749
+ for (const spec of specs) {
1750
+ const rel = `.rivet/skills/${spec.slug}.md`;
1751
+ if (installed >= RECOMMENDED_MAX_SKILLS) {
1752
+ items.push({ path: rel, action: "skipped", detail: `\u5DF2\u8FBE\u6280\u80FD\u5EFA\u8BAE\u4E0A\u9650 ${RECOMMENDED_MAX_SKILLS} \u4E2A` });
1753
+ continue;
1754
+ }
1755
+ if (existsSync3(join4(cwd, rel)) || existsSync3(join4(dir, spec.slug, "SKILL.md"))) {
1756
+ items.push({ path: rel, action: "skipped", detail: "\u540C\u540D skill \u5DF2\u5B58\u5728\uFF0C\u672A\u8986\u76D6" });
1757
+ continue;
1758
+ }
1759
+ const content = renderInitSkillMarkdown(spec);
1760
+ try {
1761
+ parseSkillMarkdown(content, `${spec.slug}.md`);
1762
+ } catch (e) {
1763
+ items.push({ path: rel, action: "error", detail: `\u6E32\u67D3\u7ED3\u679C\u672A\u901A\u8FC7 skill \u6821\u9A8C\uFF1A${e instanceof Error ? e.message : String(e)}` });
1764
+ continue;
1765
+ }
1766
+ try {
1767
+ mkdirSync3(dir, { recursive: true });
1768
+ writeFileSync2(join4(cwd, rel), content, "utf-8");
1769
+ installed++;
1770
+ items.push({ path: rel, action: "created", detail: spec.description });
1771
+ } catch (e) {
1772
+ items.push({ path: rel, action: "error", detail: `\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}` });
1773
+ }
1774
+ }
1775
+ }
1776
+ function applyHooksBranch(cwd, specs, items) {
1777
+ const rivetDir = join4(cwd, ".rivet");
1778
+ const hooksJsonPath = join4(rivetDir, "hooks.json");
1779
+ let raw = {};
1780
+ if (existsSync3(hooksJsonPath)) {
1781
+ try {
1782
+ raw = JSON.parse(readFileSync3(hooksJsonPath, "utf-8"));
1783
+ } catch {
1784
+ items.push({ path: ".rivet/hooks.json", action: "error", detail: "\u5DF2\u6709 hooks.json \u4E0D\u662F\u5408\u6CD5 JSON\uFF0C\u672A\u6539\u52A8\uFF08\u8BF7\u624B\u5DE5\u4FEE\u590D\u540E\u91CD\u8BD5\uFF09" });
1785
+ return;
1786
+ }
1787
+ }
1788
+ const entries = Array.isArray(raw.hooks) ? raw.hooks : [];
1789
+ let jsonChanged = false;
1790
+ for (const spec of specs) {
1791
+ const scriptRel = `.rivet/hooks/${spec.name}`;
1792
+ const scriptAbs = join4(cwd, scriptRel);
1793
+ let scriptReady = existsSync3(scriptAbs);
1794
+ if (scriptReady) {
1795
+ items.push({ path: scriptRel, action: "skipped", detail: "\u811A\u672C\u5DF2\u5B58\u5728\uFF0C\u672A\u8986\u76D6" });
1796
+ } else {
1797
+ try {
1798
+ mkdirSync3(join4(rivetDir, "hooks"), { recursive: true });
1799
+ writeFileSync2(scriptAbs, spec.script, "utf-8");
1800
+ try {
1801
+ chmodSync(scriptAbs, 493);
1802
+ } catch {
1803
+ }
1804
+ items.push({ path: scriptRel, action: "created", detail: spec.purpose });
1805
+ scriptReady = true;
1806
+ } catch (e) {
1807
+ items.push({ path: scriptRel, action: "error", detail: `\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}` });
1808
+ }
1809
+ }
1810
+ if (!scriptReady) continue;
1811
+ if (!entries.some((h) => h.event === spec.event && h.script === scriptRel)) {
1812
+ entries.push({ event: spec.event, script: scriptRel, ...spec.timeoutMs ? { timeoutMs: spec.timeoutMs } : {} });
1813
+ jsonChanged = true;
1814
+ items.push({ path: ".rivet/hooks.json", action: "updated", detail: `\u5408\u5E76 ${spec.event} \u2192 ${scriptRel}` });
1815
+ } else {
1816
+ items.push({ path: ".rivet/hooks.json", action: "skipped", detail: `${spec.event} \u2192 ${scriptRel} \u6761\u76EE\u5DF2\u5B58\u5728` });
1817
+ }
1818
+ }
1819
+ if (jsonChanged) {
1820
+ try {
1821
+ mkdirSync3(rivetDir, { recursive: true });
1822
+ writeFileSync2(hooksJsonPath, JSON.stringify({ ...raw, hooks: entries }, null, 2) + "\n", "utf-8");
1823
+ } catch (e) {
1824
+ items.push({ path: ".rivet/hooks.json", action: "error", detail: `\u5199\u5165\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}` });
1825
+ }
1826
+ }
1827
+ }
1828
+ function applyInitCommit(cwd, commit) {
1829
+ const items = [];
1830
+ if (commit.verify) applyVerifyBranch(cwd, items);
1831
+ if (commit.skills.length > 0) applySkillsBranch(cwd, commit.skills, items);
1832
+ if (commit.hooks.length > 0) applyHooksBranch(cwd, commit.hooks, items);
1833
+ return { items };
1834
+ }
1835
+
1836
+ // src/utils/pricing-phase.ts
1837
+ init_esm_shims();
1838
+ var HOUR_MS = 36e5;
1839
+ var DAY_MS = 864e5;
1840
+ var BEIJING_OFFSET_MS = 8 * HOUR_MS;
1841
+ var PEAK_WINDOWS = [
1842
+ [9 * 60, 12 * 60],
1843
+ [14 * 60, 18 * 60]
1844
+ ];
1845
+ var TRANSITION_MINUTES = PEAK_WINDOWS.flatMap(([start, end]) => [start, end]);
1846
+ function beijingParts(nowMs) {
1847
+ const shifted = nowMs + BEIJING_OFFSET_MS;
1848
+ const d = new Date(shifted);
1849
+ return {
1850
+ weekday: d.getUTCDay(),
1851
+ minuteOfDay: d.getUTCHours() * 60 + d.getUTCMinutes(),
1852
+ dayStartMs: Math.floor(shifted / DAY_MS) * DAY_MS - BEIJING_OFFSET_MS
1853
+ };
1854
+ }
1855
+ function deepseekPricingPhase(nowMs) {
1856
+ const { weekday, minuteOfDay } = beijingParts(nowMs);
1857
+ if (weekday === 0 || weekday === 6) return "offpeak";
1858
+ return PEAK_WINDOWS.some(([start, end]) => minuteOfDay >= start && minuteOfDay < end) ? "peak" : "offpeak";
1859
+ }
1860
+
1861
+ // src/tui/cache-telemetry.ts
1862
+ init_esm_shims();
1863
+ function projectCacheTelemetry(session, turnNumber, previousStatus) {
1864
+ const history = session.getCacheHistory();
1865
+ const latestSnapshot = history[history.length - 1];
1866
+ const latestSnapshotTotal = latestSnapshot ? latestSnapshot.cacheRead + latestSnapshot.cacheCreation : 0;
1867
+ const hasHistoricalCounters = history.some((s) => s.cacheRead + s.cacheCreation > 0);
1868
+ const hasCurrentCounters = latestSnapshot?.turn === turnNumber && latestSnapshotTotal > 0;
1869
+ const hitRate = session.getRecentTurnHitRate(3) ?? session.getCacheHitRate();
1870
+ const latestHitRate = hasCurrentCounters ? session.getLatestTurnHitRate() : null;
1871
+ const wasCompacted = turnNumber > 1 && session.wasCompactedAt(turnNumber - 1);
1872
+ if (!hasCurrentCounters && hasHistoricalCounters) {
1873
+ return { hitRate, status: "stale", latestHitRate: null, wasCompacted };
1874
+ }
1875
+ if (latestHitRate !== null && latestHitRate < 0.4 && turnNumber > 1) {
1876
+ return { hitRate, status: "degraded", latestHitRate, wasCompacted };
1877
+ }
1878
+ if (latestHitRate !== null && latestHitRate >= 0.6) {
1879
+ return {
1880
+ hitRate,
1881
+ status: previousStatus === "degraded" ? "recovering" : "healthy",
1882
+ latestHitRate,
1883
+ wasCompacted
1884
+ };
1885
+ }
1886
+ return { hitRate, status: "healthy", latestHitRate, wasCompacted };
1887
+ }
1888
+
1889
+ // src/tui/cache-panel-source.ts
1890
+ init_esm_shims();
1891
+ var CACHE_PANEL_MAX_DAYS = 30;
1892
+ var AGGREGATE_TTL_MS = 3e4;
1893
+ var OFFICIAL_TTL_MS = 6e4;
1894
+ function periodDays(period, now) {
1895
+ if (period === "7d") return 7;
1896
+ if (period === "30d") return 30;
1897
+ const start = new Date(now);
1898
+ start.setHours(0, 0, 0, 0);
1899
+ return Math.max(0, (now - start.getTime()) / 864e5);
1900
+ }
1901
+ function toPanelOfficial(snapshot) {
1902
+ if (snapshot.source === "none") {
1903
+ return { status: "unavailable", hint: snapshot.hint };
1904
+ }
1905
+ return {
1906
+ status: "ready",
1907
+ source: snapshot.source,
1908
+ todayCost: snapshot.todayCost,
1909
+ monthCost: snapshot.monthCost,
1910
+ balance: snapshot.balance,
1911
+ currency: snapshot.currency,
1912
+ hint: snapshot.hint
1913
+ };
1914
+ }
1915
+ var CachePanelSource = class {
1916
+ constructor(deps) {
1917
+ this.deps = deps;
1918
+ }
1919
+ deps;
1920
+ rows = null;
1921
+ rowsAt = 0;
1922
+ rowsLoading = false;
1923
+ official = { status: "loading" };
1924
+ officialAt = 0;
1925
+ officialLoading = false;
1926
+ now() {
1927
+ return this.deps.now?.() ?? Date.now();
1928
+ }
1929
+ /** 丢弃缓存,下次读取重新拉取(面板打开时调用,保证看到的是新数据)。 */
1930
+ invalidate() {
1931
+ this.rowsAt = 0;
1932
+ this.officialAt = 0;
1933
+ }
1934
+ ensureRows(now) {
1935
+ if (this.rowsLoading || now - this.rowsAt < AGGREGATE_TTL_MS) return;
1936
+ this.rowsLoading = true;
1937
+ void collectUsageRows(this.deps.sessionsRoot(), { days: CACHE_PANEL_MAX_DAYS, now }).then((collected) => {
1938
+ this.rows = collected.rows;
1939
+ }).catch(() => {
1940
+ this.rows = this.rows ?? [];
1941
+ }).finally(() => {
1942
+ this.rowsLoading = false;
1943
+ this.rowsAt = this.now();
1944
+ this.deps.onUpdate();
1945
+ });
1946
+ }
1947
+ ensureOfficial(now) {
1948
+ if (this.officialLoading || now - this.officialAt < OFFICIAL_TTL_MS) return;
1949
+ this.officialLoading = true;
1950
+ void this.deps.loadOfficial().then((snapshot) => {
1951
+ this.official = toPanelOfficial(snapshot);
1952
+ }).catch((err) => {
1953
+ this.official = { status: "unavailable", hint: `\u5B98\u65B9\u8D26\u5355\u67E5\u8BE2\u5931\u8D25\uFF1A${err.message}` };
1954
+ }).finally(() => {
1955
+ this.officialLoading = false;
1956
+ this.officialAt = this.now();
1957
+ this.deps.onUpdate();
1958
+ });
1959
+ }
1960
+ data(period = "today") {
1961
+ const now = this.now();
1962
+ this.ensureRows(now);
1963
+ this.ensureOfficial(now);
1964
+ const rows = this.rows;
1965
+ const aggregates = rows === null ? null : {
1966
+ today: aggregateUsageRows(rows, { days: periodDays("today", now), now, resolvePricing: this.deps.resolvePricing }),
1967
+ "7d": aggregateUsageRows(rows, { days: 7, now, resolvePricing: this.deps.resolvePricing }),
1968
+ "30d": aggregateUsageRows(rows, { days: 30, now, resolvePricing: this.deps.resolvePricing })
1969
+ };
1970
+ return {
1971
+ period,
1972
+ session: this.deps.session(),
1973
+ aggregates,
1974
+ loading: this.rowsLoading && rows === null,
1975
+ official: this.official
1976
+ };
1977
+ }
1978
+ };
1979
+
1980
+ // src/main.ts
1981
+ init_paths();
1982
+
1983
+ // src/cli/project-trust-prompt.ts
1984
+ init_esm_shims();
1985
+ function interpretTrustKey(ch) {
1986
+ if (ch === "y" || ch === "Y") return "trust";
1987
+ if (ch === "n" || ch === "N" || ch === "\x1B") return "skip";
1988
+ if (ch === "d" || ch === "D") return "dismiss";
1989
+ return null;
1990
+ }
1991
+ function buildTrustPromptText(stakes) {
1992
+ const lines = [
1993
+ "",
1994
+ "\u250C \u9879\u76EE\u6388\u4FE1 \u2014 \u68C0\u6D4B\u5230\u672C\u9879\u76EE\u5E26\u6709\u9700\u8981\u4FE1\u4EFB\u624D\u80FD\u751F\u6548\u7684\u8BBE\u7F6E",
1995
+ "\u2502"
1996
+ ];
1997
+ if (stakes.sensitiveKeys.length > 0) {
1998
+ lines.push(`\u2502 .rivet-config.json \u542B\u5B89\u5168\u654F\u611F\u952E\uFF1A${stakes.sensitiveKeys.join("\u3001")}`);
1999
+ }
2000
+ if (stakes.hasHooks) {
2001
+ lines.push("\u2502 .rivet/hooks.json \u5B58\u5728\uFF08\u9879\u76EE\u7EA7 hooks\uFF09");
2002
+ }
2003
+ lines.push(
2004
+ "\u2502",
2005
+ "\u2502 \u8FD9\u4E9B\u952E\u53EF\u4EE5\u66F4\u6539\u5BA1\u6279\u6A21\u5F0F\u3001\u9884\u6388\u6743\u547D\u4EE4\u3001\u62C9\u8D77\u8FDB\u7A0B\u3001\u6539\u5199\u51FA\u65B9\u5411\u2014\u2014",
2006
+ "\u2502 \u6309\u4FE1\u4EFB\u8FB9\u754C\uFF08SECURITY.md\uFF09\uFF0C\u4ED3\u5E93\u5185\u5BB9\u4E0D\u80FD\u81EA\u6211\u6388\u6743\uFF0C\u9700\u4F60\u663E\u5F0F\u6388\u4FE1\u3002",
2007
+ "\u2502 \u6388\u4FE1\u8BB0\u5F55\u5B58\u672C\u673A ~/.rivet/project-trust.json\uFF0C\u7EDD\u4E0D\u5199\u56DE\u4ED3\u5E93\u3002",
2008
+ "\u2502",
2009
+ "\u2502 [y] \u6388\u4FE1\uFF08\u5F53\u6B21\u4F1A\u8BDD\u751F\u6548\uFF09 [n] \u6682\u4E0D\uFF08\u4E0B\u6B21\u542F\u52A8\u518D\u95EE\uFF09 [d] \u672C\u9879\u76EE\u4E0D\u518D\u63D0\u793A",
2010
+ "\u2514",
2011
+ ""
2012
+ );
2013
+ return lines.join("\n");
2014
+ }
2015
+ async function promptProjectTrust(stakes) {
2016
+ process.stderr.write(buildTrustPromptText(stakes));
2017
+ if (!process.stdin.isTTY) return "skip";
2018
+ process.stdin.setRawMode(true);
2019
+ process.stdin.resume();
2020
+ let onData;
2021
+ try {
2022
+ return await new Promise((resolve) => {
2023
+ onData = (chunk) => {
2024
+ const decision = interpretTrustKey(chunk.toString());
2025
+ if (decision) resolve(decision);
2026
+ };
2027
+ process.stdin.on("data", onData);
2028
+ });
2029
+ } finally {
2030
+ if (onData) process.stdin.removeListener("data", onData);
2031
+ process.stdin.setRawMode(false);
2032
+ process.stdin.pause();
2033
+ }
2034
+ }
2035
+
2036
+ // src/cache/deepseek-official-usage.ts
2037
+ init_esm_shims();
2038
+ function failureHint(failure) {
2039
+ switch (failure) {
2040
+ case "unauthorized":
2041
+ return "\u5E73\u53F0\u767B\u5F55\u5DF2\u8FC7\u671F\uFF0C\u53BB\u684C\u9762\u7AEF\u300C\u6210\u672C\u300D\u91CD\u65B0\u767B\u5F55";
2042
+ case "network":
2043
+ return "\u5E73\u53F0\u8D26\u5355\u8BF7\u6C42\u5931\u8D25\uFF08\u7F51\u7EDC\u9519\u8BEF\uFF09\uFF0C\u7A0D\u540E\u91CD\u8BD5";
2044
+ case "malformed":
2045
+ return "\u5E73\u53F0\u8FD4\u56DE\u7ED3\u6784\u5F02\u5E38\uFF0C\u6682\u65E0\u6CD5\u5C55\u793A\u8D26\u5355";
2046
+ default:
2047
+ return "\u672A\u767B\u5F55 DeepSeek \u5E73\u53F0\uFF0C\u53BB\u684C\u9762\u7AEF\u300C\u6210\u672C\u300D\u767B\u5F55\u540E\u53EF\u770B\u5B98\u65B9\u8D26\u5355";
2048
+ }
2049
+ }
2050
+ async function fetchOfficialUsage(deps) {
2051
+ const hasPlatformAuth = loadPlatformAuth() !== null;
2052
+ if (hasPlatformAuth) {
2053
+ const result = await getDeepSeekUserSummary(deps.apiKey, deps.baseUrl, deps.signal);
2054
+ if (result.data) {
2055
+ const s = result.data;
2056
+ return {
2057
+ source: "platform",
2058
+ todayCost: s.current_day_cost / 100,
2059
+ monthCost: s.current_month_cost / 100,
2060
+ balance: String(s.balance_info?.total_balance ?? ""),
2061
+ currency: s.balance_info?.currency ?? "CNY",
2062
+ requests: s.current_day_requests
2063
+ };
2064
+ }
2065
+ const balance2 = await queryDeepSeekBalance(deps.apiKey, deps.baseUrl, deps.signal);
2066
+ const first2 = balance2?.balances[0];
2067
+ if (first2) {
2068
+ return {
2069
+ source: "balance",
2070
+ balance: first2.totalBalance,
2071
+ currency: first2.currency,
2072
+ failure: result.failure,
2073
+ hint: failureHint(result.failure)
2074
+ };
2075
+ }
2076
+ return { source: "none", failure: result.failure, hint: failureHint(result.failure) };
2077
+ }
2078
+ const balance = await queryDeepSeekBalance(deps.apiKey, deps.baseUrl, deps.signal);
2079
+ const first = balance?.balances[0];
2080
+ if (first) {
2081
+ return { source: "balance", balance: first.totalBalance, currency: first.currency };
2082
+ }
2083
+ return { source: "none", failure: "no-credentials", hint: failureHint(void 0) };
2084
+ }
2085
+
2086
+ // src/tui/engine/perf-monitor.ts
2087
+ init_esm_shims();
2088
+ import { monitorEventLoopDelay } from "perf_hooks";
2089
+ var SAMPLE_NAMES = ["renderLive", "delta", "formatMarkdown", "flush"];
2090
+ var NS_PER_MS = 1e6;
2091
+ var MAX_RETAINED_SAMPLES = 4096;
2092
+ function roundMs(value) {
2093
+ return Number.isFinite(value) ? Math.round(value * 100) / 100 : 0;
2094
+ }
2095
+ function emptyStats() {
2096
+ return { count: 0, p50Ms: 0, p99Ms: 0, maxMs: 0 };
2097
+ }
2098
+ function isTuiPerfEnabled(args2 = process.argv.slice(2), env = process.env) {
2099
+ return args2.includes("--debug-perf") || env.RIVET_DEBUG_TELEMETRY === "1";
2100
+ }
2101
+ var TuiPerfMonitor = class {
2102
+ enabled;
2103
+ now;
2104
+ histogram;
2105
+ samples;
2106
+ counts;
2107
+ maxima;
2108
+ cacheHits = 0;
2109
+ cacheMisses = 0;
2110
+ lastLoopLag = { p99Ms: 0, maxMs: 0 };
2111
+ lastLoopLagAt = Number.NEGATIVE_INFINITY;
2112
+ stopped = false;
2113
+ constructor(options) {
2114
+ this.enabled = options.enabled;
2115
+ this.now = options.now ?? (() => performance.now());
2116
+ if (!this.enabled) return;
2117
+ this.samples = {
2118
+ renderLive: [],
2119
+ delta: [],
2120
+ formatMarkdown: [],
2121
+ flush: []
2122
+ };
2123
+ this.counts = { renderLive: 0, delta: 0, formatMarkdown: 0, flush: 0 };
2124
+ this.maxima = { renderLive: 0, delta: 0, formatMarkdown: 0, flush: 0 };
2125
+ this.histogram = (options.createHistogram ?? (() => monitorEventLoopDelay({ resolution: 20 })))();
2126
+ this.histogram.enable();
2127
+ }
2128
+ measure(name, operation) {
2129
+ if (!this.enabled) return operation();
2130
+ const start = this.now();
2131
+ try {
2132
+ return operation();
2133
+ } finally {
2134
+ this.record(name, this.now() - start);
2135
+ }
2136
+ }
2137
+ record(name, durationMs) {
2138
+ if (!this.enabled || !this.samples || !this.counts || !this.maxima) return;
2139
+ const value = Math.max(0, durationMs);
2140
+ const retained = this.samples[name];
2141
+ if (retained.length >= MAX_RETAINED_SAMPLES) retained.shift();
2142
+ retained.push(value);
2143
+ this.counts[name]++;
2144
+ this.maxima[name] = Math.max(this.maxima[name], value);
2145
+ }
2146
+ recordCache(hit) {
2147
+ if (!this.enabled) return;
2148
+ if (hit) this.cacheHits++;
2149
+ else this.cacheMisses++;
2150
+ }
2151
+ getLoopLagWindow(minIntervalMs = 1e3) {
2152
+ if (!this.enabled || !this.histogram) return this.lastLoopLag;
2153
+ const now = this.now();
2154
+ if (now - this.lastLoopLagAt < minIntervalMs) return this.lastLoopLag;
2155
+ this.lastLoopLag = this.sampleLoopLag();
2156
+ this.lastLoopLagAt = now;
2157
+ return this.lastLoopLag;
2158
+ }
2159
+ summary() {
2160
+ if (!this.enabled || !this.samples || !this.counts || !this.maxima) return void 0;
2161
+ const stats = {};
2162
+ for (const name of SAMPLE_NAMES) {
2163
+ const retained = [...this.samples[name]].sort((a, b) => a - b);
2164
+ if (retained.length === 0) {
2165
+ stats[name] = emptyStats();
2166
+ continue;
2167
+ }
2168
+ const percentile = (p) => retained[Math.max(0, Math.ceil(p * retained.length) - 1)];
2169
+ stats[name] = {
2170
+ count: this.counts[name],
2171
+ p50Ms: roundMs(percentile(0.5)),
2172
+ p99Ms: roundMs(percentile(0.99)),
2173
+ maxMs: roundMs(this.maxima[name])
2174
+ };
2175
+ }
2176
+ return {
2177
+ kind: "perf-summary",
2178
+ samples: stats,
2179
+ cache: { hits: this.cacheHits, misses: this.cacheMisses },
2180
+ loopLag: this.sampleLoopLag()
2181
+ };
2182
+ }
2183
+ stop() {
2184
+ if (!this.histogram || this.stopped) return;
2185
+ this.histogram.disable();
2186
+ this.stopped = true;
2187
+ }
2188
+ sampleLoopLag() {
2189
+ if (!this.histogram) return this.lastLoopLag;
2190
+ const snapshot = {
2191
+ p99Ms: roundMs(this.histogram.percentile(99) / NS_PER_MS),
2192
+ maxMs: roundMs(this.histogram.max / NS_PER_MS)
2193
+ };
2194
+ this.histogram.reset();
2195
+ return snapshot;
2196
+ }
2197
+ };
2198
+
2199
+ // src/tui/engine/shutdown-sequence.ts
2200
+ init_esm_shims();
2201
+ async function runTuiShutdownSequence(options, code) {
2202
+ const errors = [];
2203
+ const runStep = async (step) => {
2204
+ try {
2205
+ await step();
2206
+ } catch (error) {
2207
+ errors.push(error);
2208
+ }
2209
+ };
2210
+ await runStep(options.dispose);
2211
+ await runStep(options.flushTelemetry);
2212
+ for (const cleanup of options.cleanup) {
2213
+ await runStep(cleanup);
2214
+ }
2215
+ if (errors.length > 0) {
2216
+ try {
2217
+ options.reportErrors?.(new AggregateError(errors, "TUI shutdown completed with errors"));
2218
+ } catch {
2219
+ }
2220
+ }
2221
+ options.exit(code);
2222
+ }
2223
+
2224
+ // src/main.ts
2225
+ installEpermFilter();
2226
+ assertStagedRuntimeIntact(dirname3(fileURLToPath(import.meta.url)));
2227
+ function applyPickerEffort(ctx2, e) {
2228
+ if (!e) return;
2229
+ const valid = ["auto", "off", "low", "medium", "high", "max"];
2230
+ if (valid.includes(e)) ctx2.agent.setReasoningEffort(e);
2231
+ }
2232
+ var args = process.argv.slice(2);
2233
+ if (args.includes("--help") || args.includes("-h")) {
2234
+ process.stdout.write(HELP_TEXT);
2235
+ process.exit(0);
2236
+ }
2237
+ if (args.includes("--version") || args.includes("-v")) {
2238
+ process.stdout.write(formatVersionLine());
2239
+ process.exit(0);
2240
+ }
2241
+ var modelArgIdx = args.indexOf("--model");
2242
+ var requestedModel = modelArgIdx >= 0 ? args[modelArgIdx + 1] : void 0;
2243
+ var providerArgIdx = args.indexOf("--provider");
2244
+ var requestedProvider = providerArgIdx >= 0 ? args[providerArgIdx + 1] : void 0;
2245
+ await applyEarlyCliEnv(args);
2246
+ var sessionCliArgs = parseSessionCliArgs(args);
2247
+ var requestedResumeId = sessionCliArgs.resumeId;
2248
+ var wantContinue = sessionCliArgs.continueLatest;
2249
+ var wantSessionPicker = sessionCliArgs.openPicker;
2250
+ var wantNewSession = sessionCliArgs.forceNew;
2251
+ var skipWelcome = args.includes("--skip-welcome");
2252
+ var wantScreenReader = args.includes("--screen-reader");
2253
+ var screenReaderMode = false;
2254
+ var streamEventsIdx = args.indexOf("--stream-events");
2255
+ var streamEventsArg = streamEventsIdx >= 0 ? args[streamEventsIdx + 1] : void 0;
2256
+ var streamEventsPath = streamEventsArg && !streamEventsArg.startsWith("-") ? streamEventsArg : void 0;
2257
+ if (streamEventsIdx >= 0 && !streamEventsPath) {
2258
+ process.stderr.write("--stream-events requires a file path (stdout is the TUI render surface)\n");
2259
+ process.exit(2);
2260
+ }
2261
+ var app = null;
2262
+ var ctx = null;
2263
+ var eventStream = streamEventsPath ? createNdjsonEventSink(streamEventsPath) : null;
2264
+ var heartbeatInterval = null;
2265
+ var perfSummaryFlush = Promise.resolve();
2266
+ var ADVISORY_STATUS_BUFFER_MAX = 20;
2267
+ var advisoryStatusNotices = [];
2268
+ var isShuttingDown = false;
2269
+ async function shutdown(code = 0) {
2270
+ if (isShuttingDown) return;
2271
+ isShuttingDown = true;
2272
+ await runTuiShutdownSequence({
2273
+ dispose: () => {
2274
+ app?.dispose();
2275
+ },
2276
+ flushTelemetry: () => perfSummaryFlush,
2277
+ cleanup: [
2278
+ () => {
2279
+ return ctx?.shutdown();
2280
+ },
2281
+ () => eventStream?.close(),
2282
+ () => {
2283
+ if (ctx) {
2284
+ const summary = formatExitSummary(ctx.persist.loadMetadata(), ctx.sessionId);
2285
+ if (summary) process.stdout.write(`
2286
+ ${summary}
2287
+ `);
2288
+ }
2289
+ },
2290
+ () => {
2291
+ if (heartbeatInterval) {
2292
+ clearInterval(heartbeatInterval);
2293
+ heartbeatInterval = null;
2294
+ }
2295
+ },
2296
+ () => {
2297
+ if (process.stdin.isTTY && process.stdin.setRawMode) {
2298
+ process.stdin.setRawMode(false);
2299
+ }
2300
+ },
2301
+ () => {
2302
+ killAllSync();
2303
+ }
2304
+ ],
2305
+ exit: (exitCode) => process.exit(exitCode),
2306
+ reportErrors: (error) => {
2307
+ try {
2308
+ const details = error.errors.map((item) => item instanceof Error ? item.message : String(item)).join("; ");
2309
+ process.stderr.write(`[shutdown] ${error.errors.length} cleanup error(s): ${details}
2310
+ `);
2311
+ } catch {
2312
+ }
2313
+ }
2314
+ }, code);
2315
+ }
2316
+ process.on("SIGINT", () => {
2317
+ void shutdown(0);
2318
+ });
2319
+ process.on("SIGTERM", () => {
2320
+ void shutdown(0);
2321
+ });
2322
+ registerExitCleanup({
2323
+ restoreTerminalSync: () => app?.restoreTerminalSync(),
2324
+ killMcpChildrenSync: () => ctx?.refs.mcpManager?.killChildrenSync?.()
2325
+ });
2326
+ async function main() {
2327
+ const stdout = process.stdout;
2328
+ const stdin = process.stdin;
2329
+ if (await routeEarlyCli(args)) return;
2330
+ if (wantNewSession) {
2331
+ process.env.RIVET_NEW_SESSION = "1";
2332
+ } else if (requestedResumeId) {
2333
+ const resolved = SessionPersist.resolveSessionId(process.cwd(), requestedResumeId);
2334
+ if (!resolved) {
2335
+ process.stderr.write(`\u672A\u627E\u5230\u5339\u914D\u4F1A\u8BDD: "${requestedResumeId}"\u3002\u7528 rivet --list \u67E5\u770B\u4F1A\u8BDD\u5217\u8868\u3002
2336
+ `);
2337
+ process.exit(1);
2338
+ }
2339
+ if ("ambiguous" in resolved) {
2340
+ process.stderr.write(
2341
+ `\u4F1A\u8BDD\u524D\u7F00 "${requestedResumeId}" \u5339\u914D\u5230\u591A\u4E2A\u4F1A\u8BDD,\u8BF7\u7528\u66F4\u957F\u524D\u7F00:
2342
+ ` + resolved.ambiguous.map((id) => ` ${id.slice(0, 12)}`).join("\n") + "\n"
2343
+ );
2344
+ process.exit(1);
2345
+ }
2346
+ process.env.RIVET_RESUME_ID = resolved.id;
2347
+ } else if (wantContinue) {
2348
+ process.env.RIVET_RESUME = "1";
2349
+ }
2350
+ const isHeadless = args.includes("-p") || args.includes("--print") || args.includes("--goal");
2351
+ if (isHeadless) {
2352
+ const { parseCliArgs, runHeadless } = await import("./headless-LSB6I7PT.js");
2353
+ const { loadConfig: loadConfig2 } = await import("./manager-ROZBCWPA.js");
2354
+ const { AgentLoop } = await import("./loop-ULZYBDA3.js");
2355
+ const { GoalTracker, buildGoalModePrompt } = await import("./goal-tracker-FXMJ2GVK.js");
2356
+ const { SessionContext } = await import("./context-62DC6EC3.js");
2357
+ const { createAgentConfig, createMainAgentConfigInput } = await import("./create-agent-config-ODSQWNVC.js");
2358
+ const { MeridianIndexer } = await import("./meridian-indexer-ZIW363L7.js");
2359
+ const { createDefaultToolRegistry } = await import("./default-registry-2PU3BTAU.js");
2360
+ const { createDeliverTaskTool } = await import("./deliver-task-KONV4C4M.js");
2361
+ const { createTaskLedger } = await import("./task-ledger-3K4TJIER.js");
2362
+ const { createOwnershipLedger } = await import("./ownership-ledger-E3WIEKPL.js");
2363
+ const { createVerificationAttribution } = await import("./verification-attribution-EKG4CNUV.js");
2364
+ const { createDeliveryGateV2 } = await import("./delivery-gate-v2-F2YVMVGK.js");
2365
+ const { createWorktreeBaseline } = await import("./worktree-baseline-O5NCU6M2.js");
2366
+ const { createHeadlessCoordinator } = await import("./headless-coordinator-VDPDMVUT.js");
2367
+ const { initializePlugins } = await import("./plugin-loader-ZZKX7ZE6.js");
2368
+ const { createGalaxyTool } = await import("./galaxy-K72BBDQN.js");
2369
+ const { createStarflowTool } = await import("./starflow-NOFBMPFU.js");
2370
+ const { createCouncilConveneTool } = await import("./council-convene-NJWPNBDU.js");
2371
+ const { createTeamOrchestrateTool } = await import("./team-orchestrate-S6NHZP7X.js");
2372
+ const { DomainKnowledgeStore } = await import("./domain-knowledge-store-DDZ3F4J7.js");
2373
+ const parsed = parseCliArgs(args);
2374
+ const effectivePrompt = parsed.goal ? buildGoalModePrompt(parsed.goal) : parsed.prompt;
2375
+ if (!effectivePrompt) {
2376
+ process.stderr.write('Usage: rivet -p "<prompt>" [--json] [--stream-json]\n or: rivet --goal "<task>" [--budget N] [--json] [--stream-json]\n');
2377
+ process.exit(2);
2378
+ }
2379
+ const cfg = loadConfig2();
2380
+ setTargetConventions(cfg.editor.platform, cfg.editor.eol);
2381
+ applyConfiguredGitBashPath(cfg.env.gitBashPath);
2382
+ const { buildSearchBackends } = await import("./web-search-3IK542AA.js");
2383
+ const { buildFetchOptions } = await import("./build-options-66Y4ZE7C.js");
2384
+ const registryOptions = {
2385
+ preset: (await import("./tool-preset-LU5BYEDZ.js")).resolveToolPreset(process.cwd()),
2386
+ desktopTools: cfg.agent.desktopTools,
2387
+ computerUse: (process.platform === "darwin" || process.platform === "win32") && process.env.RIVET_COMPUTER_USE !== "0",
2388
+ proEnabled: isProFeatureEnabled(cfg, "computerUse"),
2389
+ // 透传 network.{proxy,noProxy}:headless 模式 web_search 也需走代理,
2390
+ // 与 web_fetch 对齐(详见 bootstrap.ts 同名调用注释)。
2391
+ searchBackends: buildSearchBackends(cfg, {
2392
+ proxy: {
2393
+ ...cfg.network.proxy ? { proxyUrl: cfg.network.proxy } : {},
2394
+ ...cfg.network.noProxy ? { noProxy: cfg.network.noProxy } : {}
2395
+ }
2396
+ }),
2397
+ fetchOptions: buildFetchOptions(cfg)
2398
+ };
2399
+ const defaultModelRef = cfg.agent.defaultModel;
2400
+ const modelParts = (r) => r ? disambiguateKeyPrefix(cfg.provider.providers, parseModelRef(r)) : null;
2401
+ const defaultModelParts = modelParts(defaultModelRef);
2402
+ const requestedParts = modelParts(requestedModel);
2403
+ const preferredProvider = defaultModelParts?.provider && cfg.provider.providers[defaultModelParts.provider] ? defaultModelParts.provider : void 0;
2404
+ const provName = requestedProvider ?? preferredProvider ?? cfg.provider.default;
2405
+ const prov = cfg.provider.providers[provName];
2406
+ if (!prov) {
2407
+ process.stderr.write(`Provider not configured: ${provName}. Run: rivet config setup <provider>
2408
+ `);
2409
+ process.exit(1);
2410
+ }
2411
+ const pinnedKeyId = requestedParts ? requestedParts.keyId : provName === defaultModelParts?.provider ? defaultModelParts.keyId : void 0;
2412
+ const defaultModelId = provName === defaultModelParts?.provider ? defaultModelParts.modelRef : void 0;
2413
+ const wantedModelId = requestedParts ? requestedParts.modelRef : defaultModelId;
2414
+ const resolvedModelId = wantedModelId ? canonicalizeModelId(wantedModelId) : void 0;
2415
+ const providerPool = contractModels(prov);
2416
+ const owner = wantedModelId ? pinnedKeyId ? findModelInKey(prov, pinnedKeyId, wantedModelId) : findModelOwner(prov, wantedModelId) : void 0;
2417
+ const exactInPool = wantedModelId ? providerPool.find((m) => m.id === wantedModelId) : void 0;
2418
+ const normalizedInPool = resolvedModelId !== void 0 && resolvedModelId !== wantedModelId ? providerPool.find((m) => m.id === resolvedModelId) : void 0;
2419
+ const model = owner?.model ?? exactInPool ?? normalizedInPool ?? providerPool[0];
2420
+ if (wantedModelId && !owner && !exactInPool && !normalizedInPool) {
2421
+ process.stderr.write(
2422
+ `[model] \u914D\u7F6E\u7684\u6A21\u578B "${wantedModelId}" \u4E0D\u5728 provider "${provName}" \u4E0B\uFF0C\u5DF2\u56DE\u9000\u5230 "${model.id}"\uFF08\u8BE5\u6863\u4E0D\u652F\u6301\u89C6\u89C9\u65F6\u56FE\u7247\u5C06\u65E0\u6CD5\u88AB\u8BC6\u522B\uFF09\u3002\u53EF\u9009\uFF1A${providerPool.map((m) => m.id).join(", ")}
2423
+ `
2424
+ );
2425
+ }
2426
+ const ownerKey = owner?.owner;
2427
+ const key = ownerKey && (ownerKey.keyRef || ownerKey.apiKey || ownerKey.apiKeyEnv) ? tryResolveCredentialKey({ name: prov.name, keyRef: ownerKey.keyRef, apiKey: ownerKey.apiKey, apiKeyEnv: ownerKey.apiKeyEnv }) ?? "" : prov.apiKey ?? process.env[prov.apiKeyEnv ?? ""];
2428
+ if (!key) {
2429
+ process.stderr.write(`API key not set. Export ${prov.apiKeyEnv ?? "API_KEY"} or run: rivet config setup ${prov.name}
2430
+ `);
2431
+ process.exit(1);
2432
+ }
2433
+ const sessionId = crypto.randomUUID();
2434
+ const goalBudget = parsed.budget ?? 100;
2435
+ const headlessMaxTurns = parsed.goal ? goalBudget : Math.max(1, Number(process.env.RIVET_HEADLESS_MAX_TURNS) || 15);
2436
+ const goalTrackerRef = { current: null };
2437
+ const pluginRegistry = createDefaultToolRegistry([], registryOptions);
2438
+ const pluginResult = await initializePlugins(cfg.plugins, pluginRegistry, process.cwd());
2439
+ if (pluginResult.warnings.length > 0) {
2440
+ process.stderr.write(`[plugins] ${pluginResult.loaded}/${pluginResult.scanned} loaded; warnings: ${pluginResult.warnings.join("; ")}
2441
+ `);
2442
+ }
2443
+ const builtinNames = new Set(createDefaultToolRegistry([], registryOptions).getAllNames());
2444
+ const pluginTools = pluginRegistry.getAll().filter((t) => !builtinNames.has(t.definition.name));
2445
+ const result = await runHeadless({
2446
+ prompt: effectivePrompt,
2447
+ json: parsed.json,
2448
+ streamJson: parsed.streamJson,
2449
+ sessionId,
2450
+ model: model.id,
2451
+ eventSink: eventStream?.sink,
2452
+ createAgent: () => {
2453
+ const toolRegistry = createDefaultToolRegistry([], registryOptions);
2454
+ for (const tool of pluginTools) {
2455
+ toolRegistry.register(tool);
2456
+ }
2457
+ for (const name of pluginResult.suppressTools) {
2458
+ toolRegistry.remove(name);
2459
+ }
2460
+ const b1TaskLedger = createTaskLedger({ taskId: sessionId });
2461
+ const b1Baseline = createWorktreeBaseline({
2462
+ branch: "",
2463
+ head: "",
2464
+ preExistingDirty: [],
2465
+ preExistingUntracked: [],
2466
+ capturedAt: Date.now()
2467
+ });
2468
+ const b1Ownership = createOwnershipLedger({
2469
+ baseline: b1Baseline,
2470
+ taskLedger: b1TaskLedger
2471
+ });
2472
+ const b1Attribution = createVerificationAttribution({ ownership: b1Ownership });
2473
+ const b1Gate = createDeliveryGateV2({
2474
+ taskLedger: b1TaskLedger,
2475
+ ownership: b1Ownership,
2476
+ attribution: b1Attribution
2477
+ });
2478
+ const headlessAgentRef = { current: null };
2479
+ toolRegistry.register(createDeliverTaskTool(() => ({
2480
+ taskLedger: b1TaskLedger,
2481
+ ownership: b1Ownership,
2482
+ gate: b1Gate,
2483
+ isGoalActive: () => goalTrackerRef.current?.isActive() ?? false,
2484
+ isGoalAchieved: () => goalTrackerRef.current?.isGoalAchieved() ?? false,
2485
+ getLastVerdict: () => goalTrackerRef.current?.getLastVerdict() ?? null,
2486
+ getImpactedTests: () => headlessAgentRef.current ? [...headlessAgentRef.current.getEvidenceState().impactedTests] : [],
2487
+ // 收编 #2:冗余义务门禁消费(headless 生产注入)
2488
+ getObligationStore: () => headlessAgentRef.current?.obligations.getStore() ?? { obligations: [] },
2489
+ // 证据防火墙 Phase 2:claim tracker(headless 生产注入;hook 未装配时 fail-open)
2490
+ getClaimTracker: () => headlessAgentRef.current?.externalClaimTracker?.(),
2491
+ scoutFirewallConfig: cfg.agent.scoutEvidenceFirewall
2492
+ })));
2493
+ if (presetIncludes(registryOptions.preset, "update_goal")) {
2494
+ toolRegistry.register(createUpdateGoalTool(
2495
+ () => goalTrackerRef.current,
2496
+ () => ({ sessionId, cwd: process.cwd() })
2497
+ ));
2498
+ }
2499
+ const headlessCoordinator = createHeadlessCoordinator({
2500
+ toolRegistry,
2501
+ provider: prov,
2502
+ providerName: provName,
2503
+ apiKey: key,
2504
+ auth: void 0,
2505
+ cwd: process.cwd(),
2506
+ sessionId
2507
+ });
2508
+ const headlessGalaxyTool = createGalaxyTool({
2509
+ delegateBatch: async (requests, policy, abortSignal, onProgress, onWorkerSettled) => headlessCoordinator.delegateBatch(requests, policy, abortSignal, onProgress, onWorkerSettled),
2510
+ getRuntimeSnapshot: () => headlessCoordinator.getRuntimeSnapshot(),
2511
+ // 路由学习(收编 #5):headless 无 SharedRuntime,per-session 建库即可。
2512
+ domainKnowledgeStore: new DomainKnowledgeStore(join5(process.cwd(), ".rivet", "knowledge")),
2513
+ // DP 证据冗余(收编 #2):agent 创建后由 headlessAgentRef 惰性提供。
2514
+ get obligationTracker() {
2515
+ return headlessAgentRef.current?.obligations;
2516
+ }
2517
+ });
2518
+ toolRegistry.register(headlessGalaxyTool);
2519
+ toolRegistry.register(createStarflowTool({
2520
+ councilTool: createCouncilConveneTool({
2521
+ delegateBatch: async (requests, policy, abortSignal, onProgress) => headlessCoordinator.delegateBatch(requests, policy, abortSignal, onProgress)
2522
+ }),
2523
+ teamTool: createTeamOrchestrateTool({
2524
+ delegateBatch: async (requests, policy, abortSignal, onProgress, onWorkerSettled) => headlessCoordinator.delegateBatch(requests, policy, abortSignal, onProgress, onWorkerSettled),
2525
+ delegate: async (request, abortSignal) => headlessCoordinator.delegate(request, abortSignal)
2526
+ }),
2527
+ galaxyTool: headlessGalaxyTool,
2528
+ cwd: process.cwd()
2529
+ }));
2530
+ const headlessIndexer = new MeridianIndexer(process.cwd());
2531
+ const agentCfg = createAgentConfig(createMainAgentConfigInput({
2532
+ apiKey: key,
2533
+ meridianIndexer: headlessIndexer,
2534
+ model: { id: model.id, maxTokens: model.maxTokens, contextWindow: model.contextWindow, reasoningEffort: model.reasoningEffort, capabilities: model.capabilities, supportsVision: model.supportsVision },
2535
+ cwd: process.cwd(),
2536
+ provider: prov,
2537
+ allProviders: cfg.provider.providers,
2538
+ config: cfg,
2539
+ sessionId,
2540
+ toolDefinitions: toolRegistry.getDefinitions(),
2541
+ sessionMemoryBlock: void 0,
2542
+ auth: void 0
2543
+ }));
2544
+ const session = new SessionContext();
2545
+ const agent = new AgentLoop({ ...agentCfg, toolRegistry, zen: void 0, maxTurns: headlessMaxTurns }, session, process.cwd());
2546
+ headlessAgentRef.current = agent;
2547
+ agent.config.coordinatorRef = () => headlessCoordinator;
2548
+ if (parsed.goal) {
2549
+ const tracker = new GoalTracker({
2550
+ goal: parsed.goal,
2551
+ maxIterations: goalBudget,
2552
+ contextWindow: model.contextWindow ?? 0,
2553
+ maxJudgeRuns: agent.config.goalJudge?.maxRuns
2554
+ });
2555
+ goalTrackerRef.current = tracker;
2556
+ agent.setGoalTracker(tracker);
2557
+ if (agent.config.goalJudge?.enabled !== false) {
2558
+ if (cfg.agent.goal?.judge?.browser === true) {
2559
+ process.stderr.write("[goal] \u26A0 goal-judge browser disabled in headless mode \u2014 web_fetch read-only only\n");
2560
+ }
2561
+ const goal = parsed.goal;
2562
+ void (async () => {
2563
+ try {
2564
+ const { extractGoalCriteria, completionFromClient, buildCheapClient } = await import("./goal-criteria-SCALAU2D.js");
2565
+ const cheapProfile = cfg.workers?.profiles?.cheap;
2566
+ const allProviders = agent.config.allProviders ?? {};
2567
+ let completion;
2568
+ if (cheapProfile && allProviders[cheapProfile.provider]) {
2569
+ const cheap = buildCheapClient(cheapProfile, allProviders, agent.config.sessionId);
2570
+ completion = cheap ? completionFromClient(cheap.client, cheap.model) : completionFromClient(agent.config.client, model.id);
2571
+ } else {
2572
+ completion = completionFromClient(agent.config.client, model.id);
2573
+ }
2574
+ const criteria = await extractGoalCriteria(goal, completion);
2575
+ tracker.setSuccessCriteria(criteria);
2576
+ process.stderr.write(`[goal] judge criteria:
2577
+ ${criteria.map((c, i) => ` ${i + 1}. ${c}`).join("\n")}
2578
+ `);
2579
+ } catch {
2580
+ process.stderr.write("[goal] criteria extraction failed \u2014 judge will use wide judgment\n");
2581
+ }
2582
+ })();
2583
+ }
2584
+ }
2585
+ return agent;
2586
+ }
2587
+ // 审计面收尾:sink 是缓冲写入,不 await close 就落到下面的 process.exit 会丢掉
2588
+ // 尾段(TUI 侧同一份清理挂在 shutdown() 的 cleanup 列表上,无头分支不走
2589
+ // shutdown)。finally 同时覆盖 runHeadless 抛错的情形——异常路径也要收尾。
2590
+ }).finally(() => eventStream?.close());
2591
+ if (result.stdout) process.stdout.write(result.stdout + "\n");
2592
+ else if (result.json) process.stdout.write(JSON.stringify(result.json) + "\n");
2593
+ if (result.stderr) process.stderr.write(result.stderr + "\n");
2594
+ const exitCode = parsed.goal ? goalTrackerRef.current?.isGoalAchieved() ? 0 : 1 : result.exitCode;
2595
+ process.exit(exitCode);
2596
+ }
2597
+ const forceRecoveryCli = process.env.RIVET_FORCE_RECOVERY_CLI === "1";
2598
+ if (!forceRecoveryCli && (!stdout.isTTY || !stdin.isTTY)) {
2599
+ process.stderr.write("[T9] stdout and stdin must be TTY (use -p for headless mode or RIVET_FORCE_RECOVERY_CLI=1).\n");
2600
+ process.exit(1);
2601
+ }
2602
+ process.stderr.write("[T9] Initializing agent runtime...\n");
2603
+ maybePrintStaticPromptCacheWarning();
2604
+ if (!forceRecoveryCli && !process.env.RIVET_TRUST_PROJECT && !isProjectTrusted(process.cwd()) && !isTrustPromptDismissed(process.cwd())) {
2605
+ const stakes = detectProjectTrustStakes(process.cwd());
2606
+ if (stakes.sensitiveKeys.length > 0 || stakes.hasHooks) {
2607
+ const decision = await promptProjectTrust(stakes);
2608
+ if (decision === "trust") {
2609
+ trustProject(process.cwd());
2610
+ process.stderr.write("[rivet] \u5DF2\u6388\u4FE1\u672C\u9879\u76EE\u2014\u2014\u5B89\u5168\u654F\u611F\u914D\u7F6E\u952E\u5F53\u6B21\u4F1A\u8BDD\u751F\u6548\uFF1B\u9879\u76EE hooks \u5373\u523B\u53EF\u7528\u3002\n");
2611
+ } else if (decision === "dismiss") {
2612
+ dismissProjectTrustPrompt(process.cwd());
2613
+ process.stderr.write("[rivet] \u5DF2\u5173\u95ED\u672C\u9879\u76EE\u7684\u6388\u4FE1\u63D0\u793A\uFF08\u5B89\u5168\u952E\u4ECD\u88AB\u5FFD\u7565\uFF09\uFF1B\u968F\u65F6\u53EF\u7528 /trust \u6388\u4FE1\u3002\n");
2614
+ }
2615
+ }
2616
+ }
2617
+ try {
2618
+ ctx = await bootstrapInteractiveSession({
2619
+ cwd: process.cwd(),
2620
+ args,
2621
+ modelId: requestedModel,
2622
+ providerName: requestedProvider,
2623
+ asyncExtras: true
2624
+ });
2625
+ } catch (bootErr) {
2626
+ const msg = bootErr.message ?? "";
2627
+ if (msg.includes("No API key") || msg.includes("not configured")) {
2628
+ process.stderr.write(`
2629
+ [T9] ${msg}
2630
+ Starting in degraded mode \u2014 /connect \u5411\u5BFC\u5C06\u81EA\u52A8\u6253\u5F00...
2631
+
2632
+ `);
2633
+ ctx = await bootstrapInteractiveSession({
2634
+ cwd: process.cwd(),
2635
+ args,
2636
+ modelId: requestedModel,
2637
+ providerName: requestedProvider,
2638
+ asyncExtras: true,
2639
+ allowMissingKey: true
2640
+ });
2641
+ } else {
2642
+ throw bootErr;
2643
+ }
2644
+ }
2645
+ loadCustomThemes();
2646
+ const configuredTheme = ctx.config.ui?.theme ?? "cobalt";
2647
+ let themeName = configuredTheme;
2648
+ if (configuredTheme === "auto") {
2649
+ const detected = await detectTerminalBackground();
2650
+ themeName = autoThemeFor(detected);
2651
+ if (process.env["RIVET_DEBUG"]) {
2652
+ process.stderr.write(`[T9] Theme auto-detect: ${detected} background \u2192 ${themeName}
2653
+ `);
2654
+ }
2655
+ }
2656
+ if (!setTheme(themeName)) setTheme("cobalt");
2657
+ const theme = getTheme();
2658
+ if (ctx.config.ui?.spinnerVerbs?.length) {
2659
+ configureSpinnerVerbs(ctx.config.ui.spinnerVerbs, ctx.config.ui.spinnerVerbsMode ?? "replace");
2660
+ }
2661
+ if (ctx.config.ui?.reducedMotion) setReducedMotion(true);
2662
+ screenReaderMode = wantScreenReader || ctx.config.ui?.screenReader === true;
2663
+ if (screenReaderMode) {
2664
+ setReducedMotion(true);
2665
+ app?.setScreenReader(true);
2666
+ }
2667
+ if (process.env["RIVET_DEBUG"]) {
2668
+ process.stderr.write(`[T9] Provider: ${ctx.provider.name}, Model: ${ctx.config.provider.default}
2669
+ `);
2670
+ process.stderr.write(`[T9] Session: ${ctx.sessionId.slice(0, 8)}...
2671
+ `);
2672
+ }
2673
+ heartbeatInterval = ctx.heartbeatInterval;
2674
+ ctx.agent.advisoryBus.setStatusSink((entries) => {
2675
+ for (const e of entries) {
2676
+ advisoryStatusNotices.push(e.content);
2677
+ }
2678
+ if (advisoryStatusNotices.length > ADVISORY_STATUS_BUFFER_MAX) {
2679
+ advisoryStatusNotices.splice(0, advisoryStatusNotices.length - ADVISORY_STATUS_BUFFER_MAX);
2680
+ }
2681
+ });
2682
+ if (forceRecoveryCli) {
2683
+ const { runRecoveryCli } = await import("./recovery-cli-KPGY6FY3.js");
2684
+ await runRecoveryCli(ctx);
2685
+ await shutdown(0);
2686
+ return;
2687
+ }
2688
+ const { modelName, currentModel } = resolveInitialModelName({
2689
+ models: contractModels(ctx.provider),
2690
+ runtimeModelId: ctx.agent.config.promptEngine.getModel(),
2691
+ defaultModelRef: ctx.config.agent.defaultModel
2692
+ });
2693
+ let gitBranch;
2694
+ try {
2695
+ gitBranch = execSync("git rev-parse --abbrev-ref HEAD", {
2696
+ cwd: process.cwd(),
2697
+ stdio: ["ignore", "pipe", "ignore"],
2698
+ windowsHide: true
2699
+ }).toString().trim() || void 0;
2700
+ } catch {
2701
+ }
2702
+ app = new TuiApp({
2703
+ stdout,
2704
+ stdin,
2705
+ cols: stdout.columns,
2706
+ rows: stdout.rows,
2707
+ modelName,
2708
+ history: loadHistory(),
2709
+ contextWindow: currentModel?.contextWindow,
2710
+ gitBranch,
2711
+ // 审批时判定工作区外路径,显示「批准并记住此目录」选项。
2712
+ cwd: ctx.cwd,
2713
+ // 协同建议行(输入时提示 /team /scout /council):env 优先,其次 ui.orchestrationHint。
2714
+ orchestrationHint: resolveOrchestrationHintEnabled(process.env.RIVET_ORCHESTRATION_HINT, ctx.config.ui?.orchestrationHint),
2715
+ perfMonitor: new TuiPerfMonitor({ enabled: isTuiPerfEnabled(args) }),
2716
+ onPerfSummary: (summary) => {
2717
+ perfSummaryFlush = ctx.flushTuiPerfSummary(summary);
2718
+ }
2719
+ });
2720
+ const tuiApp = app;
2721
+ tuiApp.setApprovalMode(ctx.config.agent.approval ?? "auto-safe");
2722
+ tuiApp.setRoutingConfiguredProvider(() => {
2723
+ const cfg = ctx.config;
2724
+ return Object.keys(cfg.workers?.profiles ?? {}).length > 0 || Object.keys(cfg.agent.review?.profiles ?? {}).length > 0;
2725
+ });
2726
+ ctx.setStatusLine = (text) => tuiApp.setStatusLine(text);
2727
+ tuiApp.setRiskExplainer(async (toolName, input) => explainToolRisk({
2728
+ client: ctx?.agent.config.client,
2729
+ promptEngine: ctx.agent.config.promptEngine,
2730
+ getMessages: () => ctx?.session.getMessages() ?? [],
2731
+ contextWindow: ctx.agent.config.contextWindow,
2732
+ recordUsage: (usage, model) => ctx?.agent.recordSidePathUsage("risk-explain", usage, model)
2733
+ }, { toolName, input }));
2734
+ tuiApp.setSideQuestionAsker(async (question, onDelta) => askSideQuestion({
2735
+ client: ctx?.agent.config.client,
2736
+ promptEngine: ctx.agent.config.promptEngine,
2737
+ getMessages: () => ctx?.session.getMessages() ?? [],
2738
+ contextWindow: ctx.agent.config.contextWindow,
2739
+ recordUsage: (usage, model) => ctx?.agent.recordSidePathUsage("side-question", usage, model)
2740
+ }, { question, onDelta }));
2741
+ ctx.agent.onPlanApprovalRequested = (info) => {
2742
+ setImmediate(() => tuiApp.openPlanApprovalPanel(info, planReviewViewFor(info.slug)));
2743
+ const delayMs = resolveAutoApproveMs();
2744
+ if (shouldArm(ctx.refs.goalTrackerRef.current?.isActive() === true, delayMs)) {
2745
+ tuiApp.armPlanAutoApprove(info.slug, delayMs);
2746
+ }
2747
+ };
2748
+ tuiApp.planAutoApproveGuardsProvider = () => ({
2749
+ idle: !tuiApp.isAgentBusy,
2750
+ goalActive: ctx.refs.goalTrackerRef.current?.isActive() === true,
2751
+ planStillSubmitted: listPlansSync(ctx.agent.cwd).find((p) => p.slug === tuiApp.planAutoApproveSlug)?.status === "submitted"
2752
+ });
2753
+ tuiApp.onPlanAutoApproveFire = (slug) => {
2754
+ const plan = listPlansSync(ctx.agent.cwd).find((p) => p.slug === slug);
2755
+ const option = plan?.options?.find((o) => o.label.includes("Recommended")) ?? plan?.options?.[0];
2756
+ tuiApp.commitStatic(`\u23F3 Goal \u6A21\u5F0F\uFF1A\u5012\u8BA1\u65F6\u7ED3\u675F\uFF0C\u81EA\u52A8\u6279\u51C6\u8BA1\u5212\u300C${plan?.title ?? slug}\u300D\u5E76\u6267\u884C`);
2757
+ void approvePlanAndKickoff(
2758
+ {
2759
+ cwd: ctx.agent.cwd,
2760
+ agent: ctx.agent,
2761
+ submitToAgent: (prompt) => {
2762
+ tuiApp.submitText(prompt);
2763
+ },
2764
+ notify: (content, isError) => tuiApp.commitStatic(content, { isError })
2765
+ },
2766
+ slug,
2767
+ option?.label
2768
+ );
2769
+ };
2770
+ ctx.agent.onAskUserQuestionRequested = (info) => {
2771
+ setImmediate(() => tuiApp.openAskUserQuestionPanel(info));
2772
+ };
2773
+ const initialDomain = resolveInitialDomainName({
2774
+ agentDomainName: ctx.agent.getSessionDomain()?.name,
2775
+ defaultDomain: ctx.config.agent.defaultDomain,
2776
+ resolve: (id) => starDomainRegistry.get(id)
2777
+ });
2778
+ if (initialDomain) {
2779
+ tuiApp.setSessionStarDomain(initialDomain);
2780
+ }
2781
+ tuiApp.setDomainSyncProvider(() => ctx.agent.getSessionDomain()?.name ?? void 0);
2782
+ tuiApp.setReasoningEffortProvider(() => ctx.agent.getReasoningEffort() ?? ctx.agent.config.reasoningEffort);
2783
+ if (ctx.config.ui?.glanceDensity) tuiApp.glanceDensity = ctx.config.ui.glanceDensity;
2784
+ let statusLineTimer = null;
2785
+ if (ctx.config.ui?.statusLine?.command) {
2786
+ const slConfig = ctx.config.ui.statusLine;
2787
+ const runner = new StatusLineRunner(slConfig, (text) => tuiApp.setStatusLine(text));
2788
+ const pushStatusLine = () => {
2789
+ const metrics = tuiApp.getMetrics();
2790
+ runner.refresh({
2791
+ session_id: ctx.sessionId,
2792
+ model: { display_name: tuiApp.getModelInfo().modelName },
2793
+ workspace: { current_dir: process.cwd() },
2794
+ git: { branch: gitBranch },
2795
+ context: metrics?.maxTokens ? { ratio: (metrics.estimatedTokens ?? 0) / metrics.maxTokens, estimated_tokens: metrics.estimatedTokens, max_tokens: metrics.maxTokens } : void 0,
2796
+ cost: { total_yuan: metrics?.cost }
2797
+ });
2798
+ };
2799
+ pushStatusLine();
2800
+ statusLineTimer = setInterval(pushStatusLine, Math.max(1e3, slConfig.intervalMs ?? 3e3));
2801
+ statusLineTimer.unref?.();
2802
+ }
2803
+ const initialMeta = ctx.persist.loadMetadata();
2804
+ if (initialMeta?.sidePanelOpen) {
2805
+ tuiApp.setSidePanelOpen(true);
2806
+ }
2807
+ loadTodos(ctx.sessionId, ctx.cwd);
2808
+ setTodoSession(ctx.sessionId, ctx.cwd);
2809
+ setPlanSession(ctx.sessionId);
2810
+ tuiApp.setSidePanelChangeCallback((open) => {
2811
+ ctx.persist.updateMetadata({ sidePanelOpen: open });
2812
+ });
2813
+ const cachePanelSource = new CachePanelSource({
2814
+ sessionsRoot: () => sessionsDir(ctx.cwd),
2815
+ resolvePricing: (model) => findModelPricing(
2816
+ ctx?.agent.config.allProviders ?? {},
2817
+ ctx?.agent.config.providerName,
2818
+ model
2819
+ ),
2820
+ session: () => {
2821
+ if (!ctx) return null;
2822
+ const total = ctx.session.getTotalUsage();
2823
+ if (!total.input_tokens && !total.output_tokens) return null;
2824
+ const pricing = findModelPricing(
2825
+ ctx.agent.config.allProviders ?? {},
2826
+ ctx.agent.config.providerName,
2827
+ ctx.agent.config.promptEngine.getModel()
2828
+ );
2829
+ const cacheRead = total.cache_read_input_tokens ?? 0;
2830
+ const savings = pricing ? cacheRead / 1e6 * Math.max(0, (pricing.input ?? 0) - (pricing.cacheRead ?? pricing.input ?? 0)) : null;
2831
+ return {
2832
+ hitRate: ctx.session.getRecentTurnHitRate(3) ?? ctx.session.getCacheHitRate(),
2833
+ input: total.input_tokens,
2834
+ output: total.output_tokens,
2835
+ cacheRead,
2836
+ cacheCreate: total.cache_creation_input_tokens ?? 0,
2837
+ cost: pricing ? computeUsageCost(total, pricing).total : null,
2838
+ savings
2839
+ };
2840
+ },
2841
+ loadOfficial: () => {
2842
+ const provider = ctx?.provider;
2843
+ const apiKey = provider?.apiKey ?? (provider?.apiKeyEnv ? process.env[provider.apiKeyEnv] : void 0);
2844
+ return fetchOfficialUsage({ apiKey, baseUrl: provider?.baseUrl });
2845
+ },
2846
+ onUpdate: () => {
2847
+ tuiApp.refreshOverlay("cache");
2848
+ }
2849
+ });
2850
+ const filteredPaletteCommands = () => {
2851
+ const base = getPaletteCommands().filter((c) => c.name.startsWith("/") || c.name.startsWith("__surface:"));
2852
+ return filterCommands(base, tuiApp.getOverlayQuery());
2853
+ };
2854
+ const pendingPlanPickerEntries = () => {
2855
+ try {
2856
+ return listPlansSync(ctx.agent.cwd).filter((p) => p.status === "submitted").map((p) => ({
2857
+ slug: p.slug,
2858
+ title: p.title,
2859
+ status: p.status,
2860
+ createdAt: p.createdAt.toLocaleString(),
2861
+ options: p.options?.map((o) => o.label)
2862
+ }));
2863
+ } catch {
2864
+ return [];
2865
+ }
2866
+ };
2867
+ const planPreviewContent = () => {
2868
+ const preview = tuiApp.getPlanPreview();
2869
+ if (!preview) return null;
2870
+ const back = preview.returnTo ? ["q/Esc", "\u8FD4\u56DE"] : ["q/Esc", "\u5173\u95ED"];
2871
+ const footerHints = [["\u2191\u2193/j/k", "\u6EDA\u52A8"], ["PgUp/PgDn", "\u7FFB\u9875"], ["/", "\u641C\u7D22"], back];
2872
+ try {
2873
+ if (preview.draftPath) {
2874
+ const text = readFileSync4(pathJoin(ctx.agent.cwd, preview.draftPath), "utf-8");
2875
+ if (!text.trim()) return { content: "\uFF08\u8349\u7A3F\u8FD8\u662F\u7A7A\u7684\u2014\u2014agent \u6B63\u5728\u89C4\u5212\uFF0C\u7A0D\u540E\u518D\u770B\uFF09", title: "\u8BA1\u5212\u8349\u7A3F\uFF08\u64B0\u5199\u4E2D\uFF09", footerHints };
2876
+ return { content: stripPlanChrome(text).join("\n"), title: "\u8BA1\u5212\u8349\u7A3F\uFF08\u64B0\u5199\u4E2D\uFF09", footerHints };
2877
+ }
2878
+ const doc = readPlanSync(ctx.agent.cwd, preview.slug);
2879
+ if (!doc) return { content: `\u8BA1\u5212 ${preview.slug} \u4E0D\u5B58\u5728\u6216\u5DF2\u5220\u9664\u3002`, title: "\u8BA1\u5212\u9884\u89C8", footerHints };
2880
+ return { content: stripPlanChrome(doc.content).join("\n"), title: `\u8BA1\u5212\u9884\u89C8: \u300C${doc.title}\u300D\xB7 ${doc.slug}`, footerHints };
2881
+ } catch {
2882
+ return { content: `\u65E0\u6CD5\u8BFB\u53D6\u8BA1\u5212\u6587\u4EF6\uFF08${preview.draftPath ?? preview.slug}\uFF09\u3002\u6587\u4EF6\u53EF\u80FD\u5DF2\u88AB\u79FB\u52A8\u6216\u5220\u9664\u3002`, title: "\u8BA1\u5212\u9884\u89C8", footerHints };
2883
+ }
2884
+ };
2885
+ const planReviewViewFor = (slug) => {
2886
+ try {
2887
+ const doc = listPlansSync(ctx.agent.cwd).find((p) => p.slug === slug);
2888
+ if (!doc) return {};
2889
+ const body = stripPlanChrome(doc.content).join("\n");
2890
+ return {
2891
+ ...body.trim() ? { body } : {},
2892
+ date: formatPlanReviewDate(doc.createdAt)
2893
+ };
2894
+ } catch {
2895
+ return {};
2896
+ }
2897
+ };
2898
+ let disconnectTarget;
2899
+ let disconnectEntries = [];
2900
+ tuiApp.registerOverlays(
2901
+ {
2902
+ // Pager — scrollback 内容 或 当前选中 worker 的 detail(用于 /tasks Enter)
2903
+ pagerContent: () => {
2904
+ const plan = planPreviewContent();
2905
+ if (plan) {
2906
+ return { content: plan.content, page: 0, title: plan.title, footerHints: plan.footerHints, messages: parseScrollbackTranscript(plan.content) };
2907
+ }
2908
+ const jobId = tuiApp.getJobDetailId();
2909
+ if (jobId) {
2910
+ const text = tuiApp.getJobDetailView(jobId);
2911
+ if (text) {
2912
+ return {
2913
+ content: text,
2914
+ page: 0,
2915
+ title: `\u540E\u53F0\u4EFB\u52A1\u65E5\u5FD7: ${jobId}`,
2916
+ messages: parseScrollbackTranscript(text)
2917
+ };
2918
+ }
2919
+ }
2920
+ const workerId = tuiApp.getWorkerDetailId();
2921
+ if (workerId) {
2922
+ const liveView = tuiApp.getWorkerDetailView(workerId);
2923
+ const { content: content2, title, messages } = buildWorkerDetailContent(workerId, process.cwd(), liveView);
2924
+ return {
2925
+ content: content2,
2926
+ page: 0,
2927
+ title,
2928
+ messages
2929
+ };
2930
+ }
2931
+ if (tuiApp.isPagerVerbose()) {
2932
+ const verbose = buildVerboseTranscript(ctx.session.getMessages());
2933
+ return {
2934
+ content: verbose.content || "(no messages yet)",
2935
+ page: 0,
2936
+ title: "Transcript",
2937
+ messages: verbose.messages
2938
+ };
2939
+ }
2940
+ const content = tuiApp.getScrollbackContent() || "(no messages yet)";
2941
+ return {
2942
+ content,
2943
+ page: 0,
2944
+ title: "Scrollback",
2945
+ messages: parseScrollbackTranscript(content)
2946
+ };
2947
+ },
2948
+ // Starmap
2949
+ starmapEntries: () => {
2950
+ const domains = starDomainRegistry.list();
2951
+ const constellation = ctx ? loadConstellation(ctx.cwd) : null;
2952
+ const milestones = constellation ? constellation.milestones.slice(-5).reverse().map((m) => formatMilestoneLine(m)) : [];
2953
+ const activeDomainName = tuiApp.getDomainName?.();
2954
+ return {
2955
+ entries: domains.map((d) => ({
2956
+ name: d.name,
2957
+ glyph: d.uiPersona.glyph,
2958
+ description: d.motto ?? "",
2959
+ active: activeDomainName != null && (d.name === activeDomainName || d.id === activeDomainName),
2960
+ accent: d.uiPersona.accent
2961
+ })),
2962
+ milestones
2963
+ };
2964
+ },
2965
+ // Command palette — 实时 query 过滤(与 paletteExec 共用 filteredPaletteCommands)
2966
+ paletteCommands: () => {
2967
+ const cmds = filteredPaletteCommands();
2968
+ return {
2969
+ commands: cmds.map((c) => ({ label: c.name, description: c.description, hotkey: c.hotkey })),
2970
+ selectedIndex: 0,
2971
+ searchText: tuiApp.getOverlayQuery() || void 0
2972
+ };
2973
+ },
2974
+ // Cockpit — 运行时仪表盘
2975
+ cockpitSnapshot: () => {
2976
+ if (!ctx) return void 0;
2977
+ const metrics = tuiApp.getMetrics();
2978
+ return buildCockpitSnapshot({
2979
+ agent: ctx.agent,
2980
+ session: ctx.session,
2981
+ model: contractModels(ctx.provider)[0]?.id ?? "unknown",
2982
+ cacheHitRate: ctx.session.getRecentTurnHitRate(3) ?? ctx.session.getCacheHitRate(),
2983
+ cost: metrics?.cost ?? 0,
2984
+ mcpManager: ctx.refs.mcpManager,
2985
+ advisoryStatusNotices
2986
+ });
2987
+ },
2988
+ // Rewind — 最近用户消息(携带真实 messageIndex 作为回溯边界)
2989
+ rewindEntries: () => {
2990
+ const messages = ctx?.session.getMessages() ?? [];
2991
+ const all = [];
2992
+ let ord = 0;
2993
+ messages.forEach((m, i) => {
2994
+ if (m.role === "user" && typeof m.content === "string") {
2995
+ ord++;
2996
+ all.push({ index: ord, messageIndex: i, content: m.content });
2997
+ }
2998
+ });
2999
+ return { entries: all.slice(-30), selectedIndex: 0 };
3000
+ },
3001
+ // Rewind phase 2 — 摘要动作的缓存代价是否值得标注(非前缀缓存 provider 不标)
3002
+ rewindCachePreserving: () => ctx?.agent.compaction.isCachePreservingProvider() ?? false,
3003
+ // Rewind phase 2 — 精确到选中消息的代码回滚会影响哪些文件
3004
+ rewindFilePreview: (messageIndex) => {
3005
+ const fh = ctx?.agent.getFileHistory();
3006
+ if (!fh) return [];
3007
+ const messages = ctx?.session.getMessages() ?? [];
3008
+ return fh.getBoundaryFiles(collectPostBoundaryEditIds(messages, messageIndex));
3009
+ },
3010
+ // Chronicle
3011
+ chronicleEntries: () => {
3012
+ try {
3013
+ const sessions = SessionPersist.listMainSessions(process.cwd()).slice(0, 20);
3014
+ const entries = sessions.map((s, i) => {
3015
+ const title = (s.title ?? "").replace(/\s+/g, " ").trim().slice(0, 60);
3016
+ const turns = s.turnCount ?? 0;
3017
+ const model = s.model ?? "?";
3018
+ return {
3019
+ index: i + 1,
3020
+ time: s.updatedAt ? new Date(s.updatedAt).toLocaleString() : "",
3021
+ summary: `${s.id.slice(0, 8)} ${turns}\u8F6E ${model}${title ? " " + title : ""}`,
3022
+ current: s.id === ctx.sessionId,
3023
+ id: s.id
3024
+ };
3025
+ });
3026
+ return { entries };
3027
+ } catch {
3028
+ return { entries: [] };
3029
+ }
3030
+ },
3031
+ // History search — Ctrl+R 反向搜索(searchHistory 评分排序:前缀 +10 / 词命中 +5)
3032
+ historySearchData: () => {
3033
+ const query = tuiApp.getOverlayQuery();
3034
+ const all = loadHistory();
3035
+ const filtered = query ? searchHistory(query, 50) : all.slice(0, 50);
3036
+ return {
3037
+ entries: filtered,
3038
+ selectedIndex: 0,
3039
+ query
3040
+ };
3041
+ },
3042
+ // Tasks — /tasks 显示子代理(per-worker,来自舰队读模型;filter 由 overlay nav 决定)
3043
+ tasksData: () => tuiApp.getTasksData(),
3044
+ // Jobs — /jobs 显示后台 shell 任务(来自 TUI job 读模型)
3045
+ jobsData: () => tuiApp.getJobsData(),
3046
+ // Cache — /cache DeepSeek 缓存面板(period 由 overlay nav 注入)
3047
+ cachePanelData: () => cachePanelSource.data(),
3048
+ // Domain Picker — 裸 /domain 打开的 CC 风星域选择器(entries 由共享 builder 构造)
3049
+ domainPickerData: () => ({
3050
+ entries: buildDomainPickerEntries(ctx.agent.getSessionDomain()),
3051
+ selectedIndex: 0
3052
+ }),
3053
+ modelPickerData: () => {
3054
+ const activeModelId = ctx?.agent.config.promptEngine.getModel();
3055
+ const activeProvider = ctx?.provider.name;
3056
+ const entries = [];
3057
+ for (const [provName, prov] of Object.entries(ctx?.config.provider.providers ?? {})) {
3058
+ if (!prov.userSaved) continue;
3059
+ for (const m of contractModels(prov)) {
3060
+ entries.push({
3061
+ id: m.id,
3062
+ provider: provName,
3063
+ current: isCurrentModelSelection(provName, m.id, activeProvider, activeModelId),
3064
+ contextWindow: m.contextWindow,
3065
+ // effort 行可用性(CC 对标):effortFormat 'none' = 模型不吃推理等级信号
3066
+ effortSupported: resolveCapabilities(provName, prov.capabilities, m.capabilities).effortFormat !== "none"
3067
+ });
3068
+ }
3069
+ }
3070
+ return {
3071
+ entries,
3072
+ selectedIndex: 0
3073
+ };
3074
+ },
3075
+ themePickerData: () => {
3076
+ const currentTheme = getActiveThemeName();
3077
+ const defaultTheme = ctx?.config.ui?.theme;
3078
+ const builtins = Object.keys(THEMES).map((t) => ({
3079
+ name: t,
3080
+ current: t === currentTheme,
3081
+ isDefault: t === defaultTheme,
3082
+ description: THEMES[t].description
3083
+ }));
3084
+ const customs = listCustomThemes().map((n) => {
3085
+ const key = `custom:${n}`;
3086
+ return {
3087
+ name: key,
3088
+ current: key === currentTheme,
3089
+ isDefault: key === defaultTheme,
3090
+ description: resolveThemeEntry(key)?.description ?? "Custom color theme"
3091
+ };
3092
+ });
3093
+ return {
3094
+ entries: [...builtins, ...customs],
3095
+ selectedIndex: 0
3096
+ };
3097
+ },
3098
+ // Effort / Permission 选择面板——/effort 或 /permission 无参数时弹出,上下选择 + 回车确认。
3099
+ choicePanelData: () => {
3100
+ if (tuiApp.choicePanelKind === "permission") {
3101
+ const current2 = ctx?.agent.config.approvalMode ?? "auto-safe";
3102
+ const entries2 = [
3103
+ { id: TIER_TO_WIRE.supervise, label: formatTierLabel("supervise"), description: TIER_HINT.zh.supervise, current: current2 === "manual" },
3104
+ { id: TIER_TO_WIRE.auto, label: formatTierLabel("auto"), description: TIER_HINT.zh.auto, current: current2 === "auto-safe", recommended: true },
3105
+ { id: TIER_TO_WIRE.unattended, label: formatTierLabel("unattended"), description: `${TIER_HINT.zh.unattended} \u9700\u4E8C\u6B21\u786E\u8BA4\u3002`, current: current2 === "dangerously-skip-permissions" }
3106
+ ];
3107
+ return { title: "\u6743\u9650\u6A21\u5F0F / Permission", choices: entries2, selectedIndex: Math.max(0, entries2.findIndex((e) => e.current)) };
3108
+ }
3109
+ if (tuiApp.choicePanelKind === "permission-yolo-confirm") {
3110
+ const entries2 = [
3111
+ { id: "cancel", label: "\u53D6\u6D88", description: "\u4FDD\u6301\u5F53\u524D\u6743\u9650\u6A21\u5F0F\u4E0D\u53D8\u3002", current: true },
3112
+ { id: "confirm-yolo", label: "\u26A0 \u786E\u8BA4\u8FDB\u5165\u5168\u81EA\u52A8", description: "\u65E0\u8F6E\u6B21\u5239\u8F66 \xB7 \u65E0\u8FDB\u5EA6\u64AD\u62A5 \xB7 \u6240\u6709\u5DE5\u5177\u76F4\u63A5\u6267\u884C\uFF08\u6C99\u7BB1\u4ECD\u62E6\u9879\u76EE\u5916\u5199\u5165\uFF09\u3002\u56DE\u6EDA\u515C\u5E95\uFF1A/rollback + git \u68C0\u67E5\u70B9\u3002\u4E5F\u53EF\u76F4\u63A5\u8F93\u5165 /yes\u3002\u8BBE\u4E3A\u9ED8\u8BA4\u540E\u91CD\u542F\u4ECD\u662F\u5168\u81EA\u52A8\u3002" }
3113
+ ];
3114
+ return { title: "\u786E\u8BA4\u5168\u81EA\u52A8 / Confirm Unattended", choices: entries2, selectedIndex: 0 };
3115
+ }
3116
+ if (tuiApp.choicePanelKind === "disconnect") {
3117
+ const cfg = loadConfig();
3118
+ disconnectEntries = buildDisconnectEntries(cfg.provider.providers, {
3119
+ defaultProvider: cfg.provider.default,
3120
+ defaultModelRef: cfg.agent.defaultModel
3121
+ });
3122
+ return {
3123
+ title: "\u65AD\u5F00\u670D\u52A1\u5546 / Disconnect\uFF08\u4E00\u4E2A key \u4E00\u7EC4\u6A21\u578B\uFF0C\u6574\u7EC4\u5220\u9664\u5E76\u6E05\u9664\u5BC6\u94A5\uFF09",
3124
+ choices: toChoiceEntries(disconnectEntries),
3125
+ selectedIndex: 0
3126
+ };
3127
+ }
3128
+ if (tuiApp.choicePanelKind === "disconnect-confirm") {
3129
+ const entry = disconnectEntries.find((e) => e.name === disconnectTarget);
3130
+ const title = entry ? buildConfirmTitle(entry) : `\u65AD\u5F00\u300C${disconnectTarget ?? ""}\u300D\uFF1F`;
3131
+ const impact = entry ? buildDisconnectImpactText(entry) : "\u5220\u9664 provider \u6761\u76EE\u548C\u6A21\u578B\u5217\u8868";
3132
+ const entries2 = [
3133
+ { id: "cancel", label: "\u53D6\u6D88", description: "\u4E0D\u505A\u4EFB\u4F55\u66F4\u6539\u3002", current: true },
3134
+ { id: "confirm-disconnect", label: `\u26A0 \u786E\u8BA4\u5220\u9664 ${disconnectTarget ?? ""}`, description: `${impact}\uFF0C\u4E0D\u53EF\u64A4\u9500\u3002` }
3135
+ ];
3136
+ return { title, choices: entries2, selectedIndex: 0 };
3137
+ }
3138
+ if (tuiApp.choicePanelKind === "disconnect-retarget") {
3139
+ const cfg = loadConfig();
3140
+ return {
3141
+ title: buildRetargetTitle(cfg.provider.default),
3142
+ choices: toRetargetChoiceEntries(buildRetargetEntries(cfg.provider.providers, cfg.provider.default)),
3143
+ selectedIndex: 0
3144
+ };
3145
+ }
3146
+ if (tuiApp.choicePanelKind === "plan-approval") {
3147
+ const info = tuiApp.pendingPlanApproval;
3148
+ const title = info?.title ?? "\u5F85\u5BA1\u6279\u8BA1\u5212";
3149
+ const excerpt = tuiApp.planApprovalExcerpt;
3150
+ const countdown = tuiApp.planAutoApproveRemainSec;
3151
+ const countdownLine = countdown !== void 0 ? `
3152
+ \u23F3 Goal \u6A21\u5F0F\uFF1A${countdown}s \u540E\u81EA\u52A8\u6279\u51C6\uFF08\u6279\u51C6/\u9A73\u56DE\u5373\u53D6\u6D88\uFF1BEsc \u6536\u8D77\u4E0D\u53D6\u6D88\uFF09` : "";
3153
+ const fullTitle = excerpt ? `\u8BA1\u5212\u5BA1\u6279 / Plan Approval
3154
+ \u300C${title}\u300D${countdownLine}
3155
+ \u2500\u2500
3156
+ ${excerpt}` : `\u8BA1\u5212\u5BA1\u6279 / Plan Approval
3157
+ \u300C${title}\u300D${countdownLine}`;
3158
+ const entries2 = [];
3159
+ const options = info?.options ?? [];
3160
+ if (options.length > 1) {
3161
+ for (const [i, o] of options.entries()) {
3162
+ const recommended = /recommended/i.test(o.label);
3163
+ const cleanLabel = o.label.replace(/\s*[((]?\s*recommended\s*[))]?/i, "").trim();
3164
+ entries2.push({
3165
+ id: `approve:${i}`,
3166
+ label: `\u6279\u51C6\u5E76\u6267\u884C \u2014 ${cleanLabel}`,
3167
+ description: o.description || `\u4EE5\u65B9\u6848\u300C${cleanLabel}\u300D\u6267\u884C\u8BA1\u5212`,
3168
+ recommended
3169
+ });
3170
+ }
3171
+ } else {
3172
+ entries2.push({ id: "approve", label: "\u6279\u51C6\u5E76\u6267\u884C", description: `\u6267\u884C\u8BA1\u5212\u300C${title}\u300D`, recommended: true });
3173
+ }
3174
+ entries2.push(
3175
+ { id: "reject", label: "\u9A73\u56DE\u4FEE\u8BA2", description: "\u6807\u8BB0\u4E3A REJECTED\uFF0Cagent \u53EF\u7EE7\u7EED\u4FEE\u6539" },
3176
+ { id: "reject-exit", label: "\u9A73\u56DE\u5E76\u9000\u51FA\u8BA1\u5212\u6A21\u5F0F", description: "\u9A73\u56DE\u8BA1\u5212\u5E76\u9000\u51FA plan mode" },
3177
+ { id: "__reject_comment__", label: "\u9A73\u56DE\u5E76\u586B\u5199\u53CD\u9988\u2026", description: "\u8F93\u5165\u53CD\u9988\u540E\u9A73\u56DE\uFF0Cagent \u53EF\u7EE7\u7EED\u4FEE\u8BA2" }
3178
+ );
3179
+ const recommendedIndex = Math.max(0, entries2.findIndex((e) => e.recommended));
3180
+ return {
3181
+ title: fullTitle,
3182
+ choices: entries2,
3183
+ selectedIndex: recommendedIndex,
3184
+ inputSubMode: tuiApp.getChoicePanelInputState(),
3185
+ footerHints: [["\u2191\u2193", "\u9009\u62E9"], ["Enter", "\u786E\u8BA4"], ["v", "\u9884\u89C8\u5168\u6587"], ["Esc", "\u53D6\u6D88"]]
3186
+ };
3187
+ }
3188
+ if (tuiApp.choicePanelKind === "ask-user-question") {
3189
+ return { title: "", choices: [], selectedIndex: 0 };
3190
+ }
3191
+ const current = ctx?.agent.getReasoningEffort() ?? ctx?.agent.config.reasoningEffort ?? "high";
3192
+ const isAuto = ctx?.agent.config.autoReasoning && !ctx?.agent.userReasoningOverride;
3193
+ const entries = [
3194
+ { id: "auto", label: "Auto", description: "\u6309\u4EFB\u52A1\u590D\u6742\u5EA6\u81EA\u52A8\u9009\u6863\uFF08\u67B6\u6784/\u5B89\u5168/\u6839\u56E0\u2192max\uFF0C\u91CD\u6784/\u8C03\u8BD5\u2192high\uFF0C\u67E5\u770B\u2192low\uFF09", recommended: isAuto, current: isAuto },
3195
+ { id: "max", label: "Max", description: "\u5B8C\u6574\u63A8\u7406\u94FE\u3002\u6700\u6DF1\u5EA6\u601D\u8003\uFF0C\u9002\u5408\u67B6\u6784\u8BBE\u8BA1\u3001\u5B89\u5168\u5BA1\u67E5\u3001\u6839\u56E0\u6392\u67E5", current: !isAuto && current === "max" },
3196
+ { id: "high", label: "High", description: "\u8BA4\u771F\u63A8\u7406\u3002\u590D\u6742\u91CD\u6784\u3001bug \u4FEE\u590D\u3001\u529F\u80FD\u5B9E\u73B0", current: !isAuto && current === "high" },
3197
+ { id: "medium", label: "Medium", description: "\u6807\u51C6\u7F16\u7801\u3002\u5E38\u89C4\u6539\u52A8\u3001\u6DFB\u52A0\u6D4B\u8BD5", current: !isAuto && current === "medium" },
3198
+ { id: "low", label: "Low", description: "\u8F7B\u91CF\u63A8\u7406\u3002\u7B80\u5355\u67E5\u8BE2\u3001\u8BFB\u53D6\u6587\u4EF6", current: !isAuto && current === "low" },
3199
+ { id: "off", label: "Off", description: "\u5173\u95ED\u601D\u8003\u3002\u6700\u5FEB\u54CD\u5E94\uFF0C\u7EAF\u6267\u884C", current: !isAuto && current === "off" }
3200
+ ];
3201
+ return { title: "\u63A8\u7406\u5F3A\u5EA6 / Reasoning Effort", choices: entries, selectedIndex: Math.max(0, entries.findIndex((e) => e.current)) };
3202
+ },
3203
+ // Plan Picker — /plan-approve 无参打开的待批计划选择器。
3204
+ // 同步读盘(渲染路径不能 await),只列出等待批准的 submitted 计划。
3205
+ planPickerData: () => ({ entries: pendingPlanPickerEntries(), selectedIndex: 0 })
3206
+ },
3207
+ /* paletteExec: */
3208
+ (index) => {
3209
+ const cmds = filteredPaletteCommands();
3210
+ const name = cmds[index]?.name;
3211
+ if (!name) return;
3212
+ if (name.startsWith("__surface:")) {
3213
+ const surfaceId = name.slice("__surface:".length);
3214
+ if (["pager", "cockpit", "starmap", "chronicle", "tasks"].includes(surfaceId)) {
3215
+ tuiApp.activateOverlay(surfaceId);
3216
+ }
3217
+ } else if (name.startsWith("/")) {
3218
+ if (name === "/starmap" || name === "/chronicle") {
3219
+ tuiApp.activateOverlay(name.slice(1));
3220
+ } else if (name === "/scroll" || name === "/pager") {
3221
+ tuiApp.activateOverlay("pager");
3222
+ } else if (name === "/cockpit") {
3223
+ tuiApp.activateOverlay("cockpit");
3224
+ } else if (name === "/rewind") {
3225
+ tuiApp.activateOverlay("rewind");
3226
+ } else if (name === "/cache") {
3227
+ tuiApp.activateOverlay("cache");
3228
+ } else {
3229
+ tuiApp.setInput(name + " ");
3230
+ }
3231
+ }
3232
+ },
3233
+ /* rewindExec: */
3234
+ (messageIndex, mode) => {
3235
+ const messages = ctx?.session.getMessages() ?? [];
3236
+ const target = messages[messageIndex];
3237
+ const content = target && typeof target.content === "string" ? target.content : "";
3238
+ if (mode === "summarize-from" || mode === "summarize-to") {
3239
+ const scope = mode === "summarize-from" ? "from" : "to";
3240
+ tuiApp.commitStatic(`\u23F3 \u6B63\u5728\u6458\u8981${scope === "from" ? "\u6B64\u6D88\u606F\u4E4B\u540E" : "\u6B64\u6D88\u606F\u4E4B\u524D"}\u7684\u5BF9\u8BDD\u2026`);
3241
+ void ctx?.agent.compaction.summarizeRange({ scope, messageIndex }).then(
3242
+ (result) => {
3243
+ if (!result.ok) {
3244
+ tuiApp.commitStatic(`\u6458\u8981\u5931\u8D25\uFF1A${result.reason}`, { isError: true });
3245
+ return;
3246
+ }
3247
+ const saved = result.beforeTokens - result.afterTokens;
3248
+ tuiApp.commitStatic(
3249
+ `\u23EA \u5DF2\u628A ${result.replaced} \u6761\u6D88\u606F\u538B\u6210\u6458\u8981 \u2014 ${result.beforeTokens} \u2192 ${result.afterTokens} tokens\uFF08\u7701 ${saved}\uFF09`
3250
+ );
3251
+ },
3252
+ (err) => tuiApp.commitStatic(`\u6458\u8981\u5931\u8D25\uFF1A${err.message}`, { isError: true })
3253
+ );
3254
+ return;
3255
+ }
3256
+ const doCode = mode === "code" || mode === "both";
3257
+ const doConvo = mode === "convo" || mode === "both";
3258
+ if (doCode) {
3259
+ const fh = ctx?.agent.getFileHistory();
3260
+ if (fh) {
3261
+ const ids = collectPostBoundaryEditIds(messages, messageIndex);
3262
+ fh.rewindToBoundary(ids).then(
3263
+ (changed) => tuiApp.commitStatic(`\u23EA \u5DF2\u628A ${changed.length} \u4E2A\u6587\u4EF6\u6062\u590D\u5230\u6B64\u6D88\u606F${changed.length ? "" : "\uFF08\u65E0\u53EF\u6062\u590D\u7684\u7F16\u8F91\uFF09"}`),
3264
+ (err) => tuiApp.commitStatic(`\u56DE\u6EDA\u4EE3\u7801\u5931\u8D25\uFF1A${err.message}`)
3265
+ );
3266
+ } else {
3267
+ tuiApp.commitStatic("\u65E0\u6587\u4EF6\u5386\u53F2\uFF0C\u65E0\u6CD5\u6062\u590D\u4EE3\u7801\u3002");
3268
+ }
3269
+ }
3270
+ if (doConvo && messageIndex >= 0) {
3271
+ ctx.session.rewindToMessages(messages.slice(0, messageIndex));
3272
+ ctx.agent.config.promptEngine.resetAppendixBaseline();
3273
+ tuiApp.commitStatic("\u23EA \u5DF2\u622A\u65AD\u5BF9\u8BDD\u5230\u6B64\u6D88\u606F \u2014 \u5DF2\u56DE\u586B\u8F93\u5165\u6846\u3002");
3274
+ tuiApp.setInput(content);
3275
+ }
3276
+ },
3277
+ /* chronicleExec: */
3278
+ (id) => {
3279
+ void tuiApp.tryDispatchSlash(`/resume ${id}`);
3280
+ },
3281
+ /* domainPickerExec: */
3282
+ (key) => {
3283
+ const midSession = ctx.agent.getSessionTurnCount() > 0;
3284
+ if (key === "auto") {
3285
+ ctx.agent.resetSessionDomain();
3286
+ tuiApp.setSessionStarDomain(void 0);
3287
+ tuiApp.commitStatic("Domain \u2192 Auto\uFF08\u6309\u4EFB\u52A1\u5339\u914D\uFF09");
3288
+ } else {
3289
+ const d = starDomainRegistry.get(key);
3290
+ if (d) {
3291
+ ctx.agent.setSessionDomain({ id: d.id, name: d.name, volatileBlock: d.volatileBlock, motto: d.motto, courageThreshold: d.courageThreshold });
3292
+ tuiApp.setSessionStarDomain(d.name);
3293
+ tuiApp.commitStatic(`Domain \u2192 ${d.name} (${d.decisionStyle})`);
3294
+ } else {
3295
+ return;
3296
+ }
3297
+ }
3298
+ if (midSession) tuiApp.commitStatic(DOMAIN_SWITCH_CACHE_WARNING);
3299
+ },
3300
+ /* modelPickerExec: */
3301
+ (provider, modelId, effort) => {
3302
+ applyPickerEffort(ctx, effort);
3303
+ try {
3304
+ ctx.agent.abort();
3305
+ } catch {
3306
+ }
3307
+ const res = switchAgentRuntime(ctx, modelId, provider);
3308
+ if (res.ok && res.modelName) {
3309
+ applyPickerEffort(ctx, effort);
3310
+ tuiApp.setModelInfo(res.modelName, res.contextWindow);
3311
+ attachJobSubscription();
3312
+ tuiApp.commitStatic(`Model switched to: ${res.modelName}${effort ? `\uFF08effort \u2192 ${effort}\uFF0C\u4EC5\u672C\u4F1A\u8BDD\uFF09` : ""}`);
3313
+ } else {
3314
+ tuiApp.commitStatic(`\u26A0\uFE0F Model switch failed: ${res.error ?? "unknown error"}`);
3315
+ }
3316
+ },
3317
+ /* domainPickerSaveDefaultExec: */
3318
+ (key) => {
3319
+ const midSession = ctx.agent.getSessionTurnCount() > 0;
3320
+ if (key === "auto") {
3321
+ ctx.agent.resetSessionDomain();
3322
+ tuiApp.setSessionStarDomain(void 0);
3323
+ tuiApp.commitStatic("Domain \u2192 Auto\uFF08\u6309\u4EFB\u52A1\u5339\u914D\uFF09");
3324
+ } else {
3325
+ const d = starDomainRegistry.get(key);
3326
+ if (d) {
3327
+ ctx.agent.setSessionDomain({ id: d.id, name: d.name, volatileBlock: d.volatileBlock, motto: d.motto, courageThreshold: d.courageThreshold });
3328
+ tuiApp.setSessionStarDomain(d.name);
3329
+ tuiApp.commitStatic(`Domain \u2192 ${d.name} (${d.decisionStyle})`);
3330
+ } else {
3331
+ tuiApp.commitStatic(`\u26A0\uFE0F \u672A\u77E5\u661F\u57DF: ${key}`);
3332
+ return;
3333
+ }
3334
+ }
3335
+ try {
3336
+ setDefaultDomainConfig({ defaultDomain: key });
3337
+ tuiApp.commitStatic(`\u5DF2\u8BBE\u4E3A\u9ED8\u8BA4\u661F\u57DF\uFF1A${key}\uFF08\u65B0\u4F1A\u8BDD\u8D77\u59CB\u751F\u6548\uFF09`);
3338
+ } catch (err) {
3339
+ tuiApp.commitStatic(`\u26A0\uFE0F \u8BBE\u7F6E\u9ED8\u8BA4\u5931\u8D25: ${err.message}`);
3340
+ }
3341
+ if (midSession) tuiApp.commitStatic(DOMAIN_SWITCH_CACHE_WARNING);
3342
+ },
3343
+ /* modelPickerSaveDefaultExec: */
3344
+ (provider, modelId, effort) => {
3345
+ try {
3346
+ ctx.agent.abort();
3347
+ } catch {
3348
+ }
3349
+ const res = switchAgentRuntime(ctx, modelId, provider);
3350
+ if (res.ok && res.modelName) {
3351
+ applyPickerEffort(ctx, effort);
3352
+ tuiApp.setModelInfo(res.modelName, res.contextWindow);
3353
+ attachJobSubscription();
3354
+ tuiApp.commitStatic(`Model switched to: ${res.modelName}`);
3355
+ } else {
3356
+ tuiApp.commitStatic(`\u26A0\uFE0F Model switch failed: ${res.error ?? "unknown error"}`);
3357
+ }
3358
+ try {
3359
+ setDefaultModelConfig({ defaultModel: `${provider}:${modelId}`, ...effort ? { defaultEffort: effort } : {} });
3360
+ tuiApp.commitStatic(`\u5DF2\u8BBE\u4E3A\u9ED8\u8BA4\u6A21\u578B\uFF1A${provider}:${modelId}\uFF08\u65B0\u4F1A\u8BDD\u8D77\u59CB\u751F\u6548\uFF09${effort ? ` \xB7 effort \u2192 ${effort}` : ""}`);
3361
+ } catch (err) {
3362
+ tuiApp.commitStatic(`\u26A0\uFE0F \u8BBE\u7F6E\u9ED8\u8BA4\u5931\u8D25: ${err.message}`);
3363
+ }
3364
+ },
3365
+ /* themePickerExec: */
3366
+ (themeName2) => {
3367
+ setTheme(themeName2);
3368
+ tuiApp.forceRedraw();
3369
+ tuiApp.commitStatic(`Theme switched to: ${themeName2}`);
3370
+ },
3371
+ /* themePickerSaveDefaultExec: */
3372
+ (themeName2) => {
3373
+ setTheme(themeName2);
3374
+ tuiApp.forceRedraw();
3375
+ tuiApp.commitStatic(`Theme switched to: ${themeName2}`);
3376
+ try {
3377
+ setUiConfig({ theme: themeName2 });
3378
+ tuiApp.commitStatic(`\u5DF2\u8BBE\u4E3A\u9ED8\u8BA4\u4E3B\u9898\uFF1A${themeName2}\uFF08\u91CD\u542F\u540E\u4ECD\u751F\u6548\uFF09`);
3379
+ } catch (err) {
3380
+ tuiApp.commitStatic(`\u26A0\uFE0F \u8BBE\u7F6E\u9ED8\u8BA4\u5931\u8D25: ${err.message}`);
3381
+ }
3382
+ },
3383
+ /* choicePanelExec: */
3384
+ (id) => {
3385
+ const applyPermission = (mode) => {
3386
+ ctx.agent.setApprovalMode(mode);
3387
+ tuiApp.setApprovalMode(mode);
3388
+ applySandboxPolicyForApprovalMode(mode);
3389
+ const yoloMaxTurns = mode === "dangerously-skip-permissions" ? 0 : 200;
3390
+ ctx.agent.config.maxTurns = yoloMaxTurns;
3391
+ try {
3392
+ setApprovalMode(mode);
3393
+ } catch (err) {
3394
+ tuiApp.commitStatic(`\u26A0 \u6743\u9650\u6A21\u5F0F\u5DF2\u5207\u6362\u4F46\u6301\u4E45\u5316\u5931\u8D25: ${err.message}`);
3395
+ }
3396
+ const label2 = formatPermissionLabel(mode);
3397
+ const turnNote = mode === "dangerously-skip-permissions" ? "\uFF08\u65E0\u9650\u8F6E\u6B21\uFF09" : "";
3398
+ tuiApp.commitStatic(`\u6743\u9650\u6A21\u5F0F \u2192 ${label2}${turnNote}\uFF08\u5DF2\u8BBE\u4E3A\u9ED8\u8BA4\uFF0C\u91CD\u542F\u540E\u4ECD\u751F\u6548\uFF09`);
3399
+ };
3400
+ if (tuiApp.choicePanelKind === "permission") {
3401
+ tuiApp.choicePanelKind = "effort";
3402
+ if (id === "dangerously-skip-permissions") {
3403
+ setImmediate(() => {
3404
+ tuiApp.choicePanelKind = "permission-yolo-confirm";
3405
+ tuiApp.activateOverlay("choice-panel");
3406
+ });
3407
+ return;
3408
+ }
3409
+ applyPermission(id);
3410
+ return;
3411
+ }
3412
+ if (tuiApp.choicePanelKind === "permission-yolo-confirm") {
3413
+ tuiApp.choicePanelKind = "effort";
3414
+ if (id === "confirm-yolo") {
3415
+ applyPermission("dangerously-skip-permissions");
3416
+ } else {
3417
+ tuiApp.commitStatic("\u5DF2\u53D6\u6D88 \u2014 \u6743\u9650\u6A21\u5F0F\u672A\u6539\u53D8\u3002");
3418
+ }
3419
+ return;
3420
+ }
3421
+ if (tuiApp.choicePanelKind === "disconnect") {
3422
+ tuiApp.choicePanelKind = "effort";
3423
+ disconnectTarget = id;
3424
+ const entry = disconnectEntries.find((e) => e.name === id);
3425
+ if (entry?.isDefault) {
3426
+ const cfg = loadConfig();
3427
+ if (buildRetargetEntries(cfg.provider.providers, cfg.provider.default).length === 0) {
3428
+ tuiApp.commitStatic("\u26A0\uFE0F \u6CA1\u6709\u5176\u4ED6\u5DF2\u63A5\u5165\u7684 provider \u53EF\u6539\u8BBE\u4E3A\u9ED8\u8BA4\u2014\u2014\u65E0\u6CD5\u5220\u9664\u5F53\u524D\u9ED8\u8BA4\u3002", { isError: true });
3429
+ return;
3430
+ }
3431
+ }
3432
+ setImmediate(() => {
3433
+ tuiApp.choicePanelKind = entry?.isDefault ? "disconnect-retarget" : "disconnect-confirm";
3434
+ tuiApp.activateOverlay("choice-panel");
3435
+ });
3436
+ return;
3437
+ }
3438
+ if (tuiApp.choicePanelKind === "disconnect-retarget") {
3439
+ tuiApp.choicePanelKind = "effort";
3440
+ try {
3441
+ setDefaultProvider(id);
3442
+ if (ctx) ctx.config.provider = loadConfig().provider;
3443
+ tuiApp.commitStatic(`\u9ED8\u8BA4 provider \u2192 ${id}\u3002\u539F\u9ED8\u8BA4\u73B0\u5DF2\u89E3\u9501\uFF0C\u53EF\u8FD4\u56DE\u5217\u8868\u5220\u9664\u3002`);
3444
+ } catch (err) {
3445
+ tuiApp.commitStatic(`\u26A0\uFE0F \u8BBE\u7F6E\u9ED8\u8BA4\u5931\u8D25\uFF1A${err.message}`, { isError: true });
3446
+ return;
3447
+ }
3448
+ setImmediate(() => {
3449
+ tuiApp.choicePanelKind = "disconnect";
3450
+ tuiApp.activateOverlay("choice-panel");
3451
+ });
3452
+ return;
3453
+ }
3454
+ if (tuiApp.choicePanelKind === "disconnect-confirm") {
3455
+ tuiApp.choicePanelKind = "effort";
3456
+ const target = disconnectTarget;
3457
+ disconnectTarget = void 0;
3458
+ if (id !== "confirm-disconnect" || !target) {
3459
+ tuiApp.commitStatic("\u5DF2\u53D6\u6D88 \u2014 \u672A\u505A\u4EFB\u4F55\u66F4\u6539\u3002");
3460
+ return;
3461
+ }
3462
+ const currentProviderName = ctx?.provider.name;
3463
+ try {
3464
+ const result = removeProvider(target);
3465
+ const fresh = loadConfig();
3466
+ let runtime = { needed: false, switched: false };
3467
+ if (ctx) {
3468
+ ctx.config.provider = fresh.provider;
3469
+ if (currentProviderName === target) {
3470
+ const prov = fresh.provider.providers[fresh.provider.default];
3471
+ const modelAlias = prov && contractModels(prov)[0]?.id;
3472
+ if (!modelAlias) {
3473
+ runtime = { needed: true, switched: false, error: "\u9ED8\u8BA4 provider \u6CA1\u6709\u53EF\u7528\u6A21\u578B" };
3474
+ } else {
3475
+ const res = switchAgentRuntime(ctx, modelAlias, fresh.provider.default);
3476
+ if (res.ok && res.modelName) {
3477
+ tuiApp.setModelInfo(res.modelName, res.contextWindow);
3478
+ attachJobSubscription();
3479
+ runtime = { needed: true, switched: true, targetModel: res.modelName };
3480
+ } else {
3481
+ runtime = { needed: true, switched: false, error: res.error ?? "\u8FD0\u884C\u65F6\u5207\u6362\u672A\u6210\u529F" };
3482
+ }
3483
+ }
3484
+ }
3485
+ }
3486
+ const secretNote = result.secretDeleted ? "\uFF0CAPI key \u5DF2\u6E05\u9664" : result.keyRefSharedWith.length > 0 ? `\uFF1BkeyRef \u4ECD\u88AB ${result.keyRefSharedWith.join("\u3001")} \u5F15\u7528\uFF0C\u5BC6\u94A5\u4FDD\u7559` : "";
3487
+ const message = buildPostDeleteMessage(target, { modelCount: result.modelCount, secretNote }, runtime);
3488
+ tuiApp.commitStatic(message.text, { isError: message.isError });
3489
+ } catch (err) {
3490
+ tuiApp.commitStatic(`\u26A0\uFE0F \u65AD\u5F00\u5931\u8D25\uFF1A${err.message}`, { isError: true });
3491
+ }
3492
+ return;
3493
+ }
3494
+ if (tuiApp.choicePanelKind === "plan-approval") {
3495
+ const info = tuiApp.pendingPlanApproval;
3496
+ const rejectComment = tuiApp.choicePanelInputBuffer.trim();
3497
+ tuiApp.cancelPlanAutoApprove();
3498
+ tuiApp.clearPlanReviewState();
3499
+ if (!info) return;
3500
+ const deps = {
3501
+ cwd: ctx.agent.cwd,
3502
+ agent: ctx.agent,
3503
+ submitToAgent: (prompt) => {
3504
+ tuiApp.submitText(prompt);
3505
+ },
3506
+ notify: (content, isError) => tuiApp.commitStatic(content, { isError })
3507
+ };
3508
+ if (id === "approve") {
3509
+ const option = info.options?.find((o) => o.label.includes("Recommended")) ?? info.options?.[0];
3510
+ void approvePlanAndKickoff(deps, info.slug, option?.label);
3511
+ } else if (id.startsWith("approve:")) {
3512
+ const idx = Number(id.slice("approve:".length));
3513
+ const option = Number.isInteger(idx) ? info.options?.[idx] : void 0;
3514
+ void approvePlanAndKickoff(deps, info.slug, option?.label);
3515
+ } else if (id === "reject") {
3516
+ void rejectPlan(ctx.agent.cwd, info.slug).then((doc) => {
3517
+ deps.notify(doc ? `\u8BA1\u5212\u300C${info.title}\u300D\u5DF2\u9A73\u56DE\uFF0C\u53EF\u7EE7\u7EED\u4FEE\u8BA2\u3002` : "\u8BA1\u5212\u4E0D\u5B58\u5728\u6216\u5DF2\u88AB\u5220\u9664\u3002");
3518
+ });
3519
+ } else if (id === "reject-exit") {
3520
+ void rejectPlan(ctx.agent.cwd, info.slug).then((doc) => {
3521
+ ctx.agent.exitPlanMode();
3522
+ deps.notify(doc ? `\u8BA1\u5212\u300C${info.title}\u300D\u5DF2\u9A73\u56DE\uFF0C\u5DF2\u9000\u51FA plan mode\u3002` : "\u5DF2\u9000\u51FA plan mode\u3002");
3523
+ });
3524
+ } else if (id === "__reject_comment__") {
3525
+ void rejectPlan(ctx.agent.cwd, info.slug).then((doc) => {
3526
+ if (!doc) {
3527
+ deps.notify("\u8BA1\u5212\u4E0D\u5B58\u5728\u6216\u5DF2\u88AB\u5220\u9664\u3002");
3528
+ return;
3529
+ }
3530
+ deps.notify(`\u8BA1\u5212\u300C${info.title}\u300D\u5DF2\u9A73\u56DE${rejectComment ? "\uFF08\u542B\u53CD\u9988\uFF09" : ""}\uFF0C\u53EF\u7EE7\u7EED\u4FEE\u8BA2\u3002`);
3531
+ if (rejectComment) {
3532
+ deps.submitToAgent(
3533
+ `User rejected the plan. Feedback:
3534
+
3535
+ ${rejectComment}
3536
+
3537
+ Revise the plan in \`.rivet/plans/${info.slug}.md\`, then call plan action=submit again.`
3538
+ );
3539
+ }
3540
+ });
3541
+ }
3542
+ return;
3543
+ }
3544
+ if (tuiApp.choicePanelKind === "ask-user-question") {
3545
+ const done = tuiApp.resolveAskChoice(id);
3546
+ if (!done) return;
3547
+ return;
3548
+ }
3549
+ ctx.agent.setReasoningEffort(id);
3550
+ const label = id === "auto" ? "Auto\uFF08\u6309\u4EFB\u52A1\u590D\u6742\u5EA6\u81EA\u52A8\u9009\u6863\uFF09" : id;
3551
+ tuiApp.commitStatic(`Reasoning effort \u2192 ${label}`);
3552
+ },
3553
+ /* connectExec: */
3554
+ (commit, summary) => {
3555
+ try {
3556
+ if (commit.mode === "preset") {
3557
+ setupProvider(commit.setup);
3558
+ } else if (commit.mode === "add-model") {
3559
+ upsertProviderModel(commit.providerName, commit.model);
3560
+ } else {
3561
+ registerProvider({
3562
+ providerName: commit.providerName,
3563
+ baseUrl: commit.baseUrl,
3564
+ ...commit.apiKey ? { apiKey: commit.apiKey } : {},
3565
+ protocol: commit.protocol,
3566
+ models: commit.models,
3567
+ makeDefault: commit.makeDefault,
3568
+ ...commit.advanced ? { advanced: commit.advanced } : {}
3569
+ });
3570
+ }
3571
+ } catch (e) {
3572
+ tuiApp.commitStatic(`\u26A0\uFE0F \u914D\u7F6E\u4FDD\u5B58\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
3573
+ return false;
3574
+ }
3575
+ if (commit.mode === "preset" && commit.needsLogin) {
3576
+ tuiApp.commitStatic(`\u2705 ${summary}
3577
+ \u4E0B\u4E00\u6B65\uFF1A/login \u5B8C\u6210\u6D4F\u89C8\u5668\u767B\u5F55\uFF08token \u81EA\u52A8\u843D\u76D8\u5E76\u7EED\u671F\uFF09\uFF0C\u7136\u540E\u518D\u5F00\u59CB\u5BF9\u8BDD\u3002`);
3578
+ return true;
3579
+ }
3580
+ let liveApplied = false;
3581
+ try {
3582
+ const fresh = loadConfig();
3583
+ if (ctx) {
3584
+ ctx.config.provider = fresh.provider;
3585
+ const prov = fresh.provider.providers[fresh.provider.default];
3586
+ const modelAlias = prov && contractModels(prov)[0]?.id;
3587
+ if (modelAlias) {
3588
+ try {
3589
+ ctx.agent.abort();
3590
+ } catch {
3591
+ }
3592
+ const res = switchAgentRuntime(ctx, modelAlias);
3593
+ if (res.ok && res.modelName) {
3594
+ tuiApp.setModelInfo(res.modelName, res.contextWindow);
3595
+ attachJobSubscription();
3596
+ liveApplied = true;
3597
+ }
3598
+ }
3599
+ }
3600
+ } catch {
3601
+ }
3602
+ tuiApp.commitStatic(
3603
+ liveApplied ? `\u2705 ${summary}
3604
+ \u4E0B\u4E00\u6B65\uFF1A\u76F4\u63A5\u5F00\u59CB\u5BF9\u8BDD\u2014\u2014/model \u53EF\u968F\u65F6\u5207\u6362\u6A21\u578B\uFF0C/connect \u53EF\u518D\u6DFB\u52A0\u670D\u52A1\u5546\u3002` : `\u2705 ${summary}
3605
+ \uFF08\u5DF2\u4FDD\u5B58\u5230\u914D\u7F6E\u3002\u82E5\u6A21\u578B\u672A\u5207\u6362\uFF0C\u91CD\u542F\u5929\u67A2\u540E\u751F\u6548\u3002\uFF09
3606
+ \u4E0B\u4E00\u6B65\uFF1A/model \u5207\u6362\u6A21\u578B\uFF0C/connect \u518D\u6DFB\u52A0\u670D\u52A1\u5546\u3002`
3607
+ );
3608
+ return true;
3609
+ },
3610
+ /* planPickerExec: */
3611
+ (slug) => {
3612
+ tuiApp.cancelPlanAutoApprove();
3613
+ void approvePlanAndKickoff(
3614
+ {
3615
+ cwd: ctx.agent.cwd,
3616
+ agent: ctx.agent,
3617
+ submitToAgent: (prompt) => {
3618
+ tuiApp.submitText(prompt);
3619
+ },
3620
+ notify: (content, isError) => tuiApp.commitStatic(content, { isError })
3621
+ },
3622
+ slug
3623
+ );
3624
+ },
3625
+ /* initExec: */
3626
+ (commit, summary) => {
3627
+ try {
3628
+ const report = applyInitCommit(ctx.agent.cwd, commit);
3629
+ tuiApp.commitStatic(`\u2705 ${summary}
3630
+ ${formatInitApplyReport(report)}`);
3631
+ } catch (e) {
3632
+ tuiApp.commitStatic(`\u26A0\uFE0F \u9879\u76EE\u521D\u59CB\u5316\u5931\u8D25: ${e instanceof Error ? e.message : String(e)}`);
3633
+ }
3634
+ }
3635
+ );
3636
+ tuiApp.setWorkerKill((workerId) => ctx?.refs.coordinator?.killWorker(workerId) ?? false);
3637
+ tuiApp.setWorkerSteer((workerId, text) => ctx?.refs.coordinator?.steerWorker(workerId, text) ?? false);
3638
+ tuiApp.setWorkerRunningQuery((workerId) => ctx?.refs.coordinator?.isWorkerRunning(workerId) ?? false);
3639
+ let subscribedJobs;
3640
+ let jobListener;
3641
+ const attachJobSubscription = () => {
3642
+ const jobs = ctx?.agent.jobs;
3643
+ if (!jobs || jobs === subscribedJobs) return;
3644
+ if (subscribedJobs && jobListener) subscribedJobs.removeListener("event", jobListener);
3645
+ subscribedJobs = jobs;
3646
+ jobListener = (ev) => {
3647
+ tuiApp.handleJobEvent(ev);
3648
+ };
3649
+ jobs.on("event", jobListener);
3650
+ for (const snap of jobs.list()) {
3651
+ tuiApp.handleJobEvent({ kind: snap.status === "running" ? "started" : "exit", job: snap });
3652
+ }
3653
+ };
3654
+ attachJobSubscription();
3655
+ tuiApp.setJobKill((jobId) => ctx?.agent.jobs?.kill(jobId) ?? false);
3656
+ tuiApp.setJobLogs((jobId) => ctx?.agent.jobs?.logs(jobId) ?? null);
3657
+ registerTuiSlashCommands(app, ctx);
3658
+ const paletteHints = getPaletteCommands().filter((c) => c.name.startsWith("/")).map((c) => ({ name: c.name, description: c.description, ...c.argsHint ? { argsHint: c.argsHint } : {}, ...c.tier === "core" ? { tier: "core" } : {} }));
3659
+ const skillHints = skillRegistry.list().map((s) => ({
3660
+ name: `/skill ${s.name}`,
3661
+ description: s.description ? s.description.split("\n")[0] : `Load skill: ${s.name}`
3662
+ }));
3663
+ app.setSlashCommands([...paletteHints, ...skillHints]);
3664
+ let prevCacheStatus = "healthy";
3665
+ app.setMetricsProvider(() => {
3666
+ if (!ctx) return null;
3667
+ const session = ctx.session;
3668
+ const total = session.getTotalUsage();
3669
+ const providers = ctx.agent.config.allProviders ?? {};
3670
+ const providerName = ctx.agent.config.providerName;
3671
+ const modelId = ctx ? contractModels(ctx.provider)[0]?.id : void 0;
3672
+ const pricing = findModelPricing(providers, providerName, modelId);
3673
+ const cost = pricing ? computeUsageCost(total, pricing).total : 0;
3674
+ const maxTokens = ctx.agent.config.contextWindow ?? currentModel?.contextWindow ?? 0;
3675
+ const turnNumber = session.getTurnCount();
3676
+ const cacheProjection = projectCacheTelemetry(session, turnNumber, prevCacheStatus);
3677
+ prevCacheStatus = cacheProjection.status;
3678
+ return {
3679
+ estimatedTokens: session.getRealOccupancy(),
3680
+ conversationTokens: session.getConversationTokens(),
3681
+ maxTokens,
3682
+ cacheHitRate: session.getRecentTurnHitRate(3) ?? session.getCacheHitRate(),
3683
+ cacheStatus: cacheProjection.status,
3684
+ cost,
3685
+ inputTokens: total.input_tokens,
3686
+ outputTokens: total.output_tokens,
3687
+ lastRealPromptTokens: session.getLastRealPromptTokens(),
3688
+ // DeepSeek 峰时/闲时计价提醒:仅官方 deepseek provider 给值,其余缺省不渲染。
3689
+ // 闭包动态读当前 providerName,/model 切走/切回自动显隐。
3690
+ pricingPhase: providerName === "deepseek" ? deepseekPricingPhase(Date.now()) : void 0
3691
+ };
3692
+ });
3693
+ if (ctx.agent.config.providerName === "deepseek") {
3694
+ const pricingPhaseTimer = setInterval(() => tuiApp.forceRedraw(), 6e4);
3695
+ pricingPhaseTimer.unref?.();
3696
+ }
3697
+ app.setTodosProvider(() => ctx.refs.todoStore.read());
3698
+ app.setActivePlanProvider(() => ctx.agent.config.promptEngine?.getActivePlanPointer());
3699
+ app.setPlanDraftProvider(() => {
3700
+ const agent = ctx.agent;
3701
+ if (agent.planModeState !== "planning") return null;
3702
+ const path = agent.getActivePlanFilePath();
3703
+ if (!path) return null;
3704
+ try {
3705
+ const abs = pathJoin(agent.cwd, path);
3706
+ const bytes = statSync2(abs).size;
3707
+ return { path, bytes };
3708
+ } catch {
3709
+ return { path };
3710
+ }
3711
+ });
3712
+ app.setGoalTrackerProvider(() => ctx.refs.goalTrackerRef.current);
3713
+ app.setPlanModeProvider(() => ctx.agent.planModeState === "planning");
3714
+ app.setAskModeProvider(() => ctx.agent.askModeState === "asking");
3715
+ app.setPlanModeToggleHandler(() => {
3716
+ const agent = ctx.agent;
3717
+ const setSessionApproval = (mode) => {
3718
+ agent.setApprovalMode(mode);
3719
+ app.setApprovalMode(mode);
3720
+ agent.config.maxTurns = mode === "dangerously-skip-permissions" ? 0 : 200;
3721
+ };
3722
+ const current = agent.config.approvalMode ?? "auto-safe";
3723
+ const decision = nextShiftTabPlanToggle({
3724
+ isPlanning: agent.planModeState === "planning",
3725
+ currentApprovalMode: current,
3726
+ approvalModeBeforePlan: app.approvalModeBeforePlan ?? null
3727
+ });
3728
+ if (decision.action === "enter") {
3729
+ app.approvalModeBeforePlan = decision.stashMode;
3730
+ agent.enterPlanMode();
3731
+ const path = agent.getActivePlanFilePath();
3732
+ const hint = shiftTabPlanToggleHint("enter", decision.stashMode);
3733
+ app.commitStatic(path ? `${hint}\uFF08\u8BA1\u5212\u6587\u4EF6: \`${path}\`\uFF09` : hint);
3734
+ return;
3735
+ }
3736
+ agent.exitPlanMode();
3737
+ setSessionApproval(decision.restoreMode);
3738
+ app.approvalModeBeforePlan = null;
3739
+ app.commitStatic(shiftTabPlanToggleHint("exit", decision.restoreMode));
3740
+ });
3741
+ app.setPlanTraceProvider(() => ctx.agent.planTrace);
3742
+ app.setVisionInfo(
3743
+ ctx.agent.config.supportsVision ?? false,
3744
+ !!ctx.agent.config.visionClient,
3745
+ ctx.agent.config.visionBridge?.source
3746
+ );
3747
+ app.onSubmit((text, images) => {
3748
+ const trimmed = text.trim();
3749
+ if (!trimmed) return;
3750
+ const resolved = resolveAppPromptInput(trimmed, process.cwd(), app.getCommandPredicate());
3751
+ if (resolved === null) {
3752
+ app.rejectSubmit();
3753
+ void (async () => {
3754
+ const handled = await app.tryDispatchSlash(trimmed);
3755
+ if (!handled) {
3756
+ const firstTok = trimmed.split(/\s/)[0];
3757
+ const planHint = firstTok?.startsWith("/plan") ? "\n\u63D0\u793A: /plan-approve \u65E0\u53C2\u6253\u5F00\u5F85\u6279\u8BA1\u5212\u9009\u62E9\u5668\uFF0C\u6216 /plan-list \u67E5\u770B\u5168\u90E8\u8BA1\u5212\u3002" : "";
3758
+ app.commitStatic(`\u26A0\uFE0F Unknown command: ${firstTok}
3759
+ Type /help for available commands.${planHint}`);
3760
+ }
3761
+ })();
3762
+ return;
3763
+ }
3764
+ for (const toolName of resolved.requiredTools ?? []) {
3765
+ const mount = ctx.agent.enableTool(toolName);
3766
+ if (mount.status === "mounted") {
3767
+ const costNote = mount.cacheImpact === "prefix-invalidated" ? "\uFF08\u4E0B\u4E00\u8BF7\u6C42\u524D\u7F00\u7F13\u5B58\u4E00\u6B21\u6027 MISS\uFF0C\u540E\u7EED\u8F6E\u6B21\u6309\u65B0\u5DE5\u5177\u96C6\u91CD\u65B0\u7F13\u5B58\uFF09" : "";
3768
+ app.commitStatic(`\u{1F527} \u5DF2\u4E3A\u672C\u6B21 workflow \u6302\u8F7D\u5DE5\u5177 ${toolName}${costNote}`);
3769
+ }
3770
+ }
3771
+ const base = wrapCallbacksWithTuiApp(app, {
3772
+ onDomainDrift: (drift) => app.commitStatic(formatDomainDriftNudge(drift))
3773
+ });
3774
+ const sinks = [];
3775
+ if (eventStream) sinks.push(eventStream.sink);
3776
+ if (screenReaderMode) {
3777
+ sinks.push((event) => {
3778
+ const line = formatEventForScreenReader(event);
3779
+ if (line) app.commitStatic(line);
3780
+ });
3781
+ }
3782
+ const tapped = sinks.length > 0 ? tapAgentCallbacks(base, (event) => {
3783
+ for (const s of sinks) s(event);
3784
+ }) : null;
3785
+ ctx.agent.run(resolved.prompt, tapped ?? base, images).then((outcome) => {
3786
+ if (outcome === "skipped-already-running") app.notifyRunRejected();
3787
+ }).catch((err) => {
3788
+ process.stderr.write(`[T9] Agent error: ${err?.message}
3789
+ `);
3790
+ }).finally(() => {
3791
+ tapped?.flush();
3792
+ app.notifyRunSettled();
3793
+ });
3794
+ });
3795
+ app.setAgentRunningProbe(() => ctx?.agent.isRunning() === true);
3796
+ app.setZenBadgeProvider(() => ctx?.agent.zenController.isZen ? "\u7985" : void 0);
3797
+ app.onAbort(() => {
3798
+ if (ctx) {
3799
+ ctx.agent.abort();
3800
+ }
3801
+ });
3802
+ app.onExit(() => {
3803
+ void shutdown(0);
3804
+ });
3805
+ if (ctx.templatesPendingAgents && !args.includes("--dangerously-skip-permissions")) {
3806
+ const gitAvailable = (() => {
3807
+ try {
3808
+ execSync("git --version", { cwd: process.cwd(), stdio: "pipe", windowsHide: true });
3809
+ return true;
3810
+ } catch {
3811
+ return false;
3812
+ }
3813
+ })();
3814
+ const options = ["Create both (AGENTS.md + .rivet.md)", "Skip"];
3815
+ let selectedIdx = 0;
3816
+ const renderPicker = (idx) => {
3817
+ stdout.write("\x1B[2K\r");
3818
+ stdout.write("\x1B[1A\x1B[2K\r");
3819
+ for (let i = 0; i < options.length; i++) {
3820
+ const prefix = i === idx ? "\x1B[7m \u276F" : " ";
3821
+ const suffix = i === idx ? " \x1B[0m" : "";
3822
+ stdout.write(`${prefix} ${options[i]}${suffix}
3823
+ `);
3824
+ }
3825
+ stdout.write(`
3826
+ \u2191\u2193 navigate \xB7 Enter confirm \xB7 Esc skip
3827
+ `);
3828
+ stdout.write(`\x1B[${options.length + 2}A`);
3829
+ };
3830
+ stdout.write("\n");
3831
+ stdout.write("\u256D\u2500 First-run setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n");
3832
+ stdout.write("\u2502 This project has no AGENTS.md or .rivet.md. \u2502\n");
3833
+ stdout.write("\u2502 Create them from templates? \u2502\n");
3834
+ stdout.write("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F\n");
3835
+ if (!gitAvailable) {
3836
+ stdout.write("\n");
3837
+ stdout.write(" \u26A0 \u672A\u68C0\u6D4B\u5230 git\u3002git \u662F\u53EF\u9009\u4F9D\u8D56\u2014\u2014\u4E0D\u88C5\u4E5F\u80FD\u6B63\u5E38\u7528\uFF0C\n");
3838
+ stdout.write(" \u4F46\u5B89\u88C5\u540E\u53EF\u89E3\u9501\uFF1A\u59D4\u6D3E\u9694\u79BB / \u68C0\u67E5\u70B9\u56DE\u6EDA / commit / diff \u5BA1\u67E5\u3002\n");
3839
+ stdout.write(" \u5B89\u88C5\uFF1Ahttps://git-scm.com/downloads\n");
3840
+ stdout.write("\n");
3841
+ }
3842
+ stdout.write("\n");
3843
+ renderPicker(selectedIdx);
3844
+ let created = false;
3845
+ let aborted = false;
3846
+ if (process.stdin.isTTY) {
3847
+ process.stdin.setRawMode(true);
3848
+ process.stdin.resume();
3849
+ let onData;
3850
+ try {
3851
+ await new Promise((resolve) => {
3852
+ let buf = "";
3853
+ onData = (chunk) => {
3854
+ const str = chunk.toString();
3855
+ buf += str;
3856
+ if (buf === "\x1B[A" || buf === "\x1B[1;2A") {
3857
+ selectedIdx = (selectedIdx - 1 + options.length) % options.length;
3858
+ renderPicker(selectedIdx);
3859
+ buf = "";
3860
+ return;
3861
+ }
3862
+ if (buf === "\x1B[B" || buf === "\x1B[1;2B") {
3863
+ selectedIdx = (selectedIdx + 1) % options.length;
3864
+ renderPicker(selectedIdx);
3865
+ buf = "";
3866
+ return;
3867
+ }
3868
+ if (buf === "k" && selectedIdx > 0) {
3869
+ selectedIdx--;
3870
+ renderPicker(selectedIdx);
3871
+ buf = "";
3872
+ return;
3873
+ }
3874
+ if (buf === "j" && selectedIdx < options.length - 1) {
3875
+ selectedIdx++;
3876
+ renderPicker(selectedIdx);
3877
+ buf = "";
3878
+ return;
3879
+ }
3880
+ if (str === "\r" || str === "\n") {
3881
+ created = selectedIdx === 0;
3882
+ buf = "";
3883
+ resolve();
3884
+ return;
3885
+ }
3886
+ if (str === "1") {
3887
+ selectedIdx = 0;
3888
+ created = true;
3889
+ resolve();
3890
+ return;
3891
+ }
3892
+ if (str === "2") {
3893
+ selectedIdx = 1;
3894
+ created = false;
3895
+ resolve();
3896
+ return;
3897
+ }
3898
+ if (str === "\x1B" && buf.length === 1) {
3899
+ aborted = true;
3900
+ resolve();
3901
+ return;
3902
+ }
3903
+ if (buf.length >= 6) buf = "";
3904
+ };
3905
+ process.stdin.on("data", onData);
3906
+ });
3907
+ } finally {
3908
+ if (onData) process.stdin.removeListener("data", onData);
3909
+ }
3910
+ }
3911
+ stdout.write(`\x1B[${options.length + 2}B`);
3912
+ if (aborted) {
3913
+ applyProjectTemplates(process.cwd(), { agentsMode: "skip" });
3914
+ recordTemplatesDecision(process.cwd(), "declined");
3915
+ stdout.write("Skipped template creation.\n");
3916
+ } else if (created) {
3917
+ const result = applyProjectTemplates(process.cwd(), { agentsMode: "overwrite" });
3918
+ recordTemplatesDecision(process.cwd(), "created", {
3919
+ created: result.created,
3920
+ appended: result.appended,
3921
+ skipped: result.skipped
3922
+ });
3923
+ stdout.write(`\u2713 Created: ${result.created.join(", ") || "none"}
3924
+ `);
3925
+ } else {
3926
+ applyProjectTemplates(process.cwd(), { agentsMode: "skip" });
3927
+ recordTemplatesDecision(process.cwd(), "declined");
3928
+ stdout.write("Skipped template creation.\n");
3929
+ }
3930
+ } else if (ctx.templatesPendingAgents) {
3931
+ applyProjectTemplates(process.cwd(), { agentsMode: "skip" });
3932
+ recordTemplatesDecision(process.cwd(), "declined");
3933
+ }
3934
+ stdout.write("\x1B[2J\x1B[H");
3935
+ const existingMsgCount = ctx.session.getMessages().length;
3936
+ if (!skipWelcome) {
3937
+ const installRoot = detectInstallRoot();
3938
+ const guideShow = existingMsgCount === 0 && stdout.isTTY === true && shouldShowWelcomeGuide();
3939
+ const sessionDomainId = ctx.agent.getSessionDomain()?.id;
3940
+ const welcomeLines = formatWelcome({
3941
+ modelName,
3942
+ cwd: process.cwd(),
3943
+ sessionId: ctx.sessionId,
3944
+ priorMsgCount: existingMsgCount,
3945
+ columns: stdout.columns || 80,
3946
+ rows: stdout.rows || 24,
3947
+ numericId: ctx.agent.sessionNumericId,
3948
+ compact: existingMsgCount > 0,
3949
+ guide: guideShow,
3950
+ version: installRoot ? getCurrentVersion(installRoot) : null,
3951
+ approvalMode: ctx.config.agent.approval ?? "auto-safe",
3952
+ reasoningEffort: ctx.agent.planModeState === "planning" ? "max" : ctx.agent.config.autoReasoning && !ctx.agent.userReasoningOverride ? "auto" : ctx.agent.getReasoningEffort() ?? ctx.agent.config.reasoningEffort,
3953
+ separator: starDomainRegistry.list().find((d) => d.id === sessionDomainId)?.uiPersona?.separator
3954
+ }, theme);
3955
+ const shimmer = missionShimmer(theme, stdout.columns || 80);
3956
+ const animateMission = stdout.isTTY === true && process.env.RIVET_WELCOME_ANIM !== "0" && shimmer !== null;
3957
+ const missionIdx = animateMission ? welcomeLines.findIndex((l) => isMissionLine(l)) : -1;
3958
+ const sleepSync = (ms) => {
3959
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
3960
+ };
3961
+ if (animateMission && shimmer && missionIdx >= 0) {
3962
+ const before = welcomeLines.slice(0, missionIdx);
3963
+ const after = welcomeLines.slice(missionIdx + 1);
3964
+ if (before.length > 0) stdout.write(before.join("\n") + "\n");
3965
+ for (const frame of shimmer.frames) {
3966
+ stdout.write(`\r\x1B[2K${frame}`);
3967
+ sleepSync(MISSION_SHIMMER_FRAME_MS);
3968
+ }
3969
+ stdout.write(`\r\x1B[2K${shimmer.final}
3970
+ `);
3971
+ if (after.length > 0) stdout.write(after.join("\n") + "\n");
3972
+ } else {
3973
+ stdout.write(welcomeLines.join("\n") + "\n");
3974
+ }
3975
+ if (guideShow) markWelcomeGuideShown();
3976
+ }
3977
+ app.start();
3978
+ if (!skipWelcome && stdout.isTTY === true) {
3979
+ const identityApp = app;
3980
+ commitWelcomeStellarIdentityLine((text) => identityApp.commitStatic(text));
3981
+ }
3982
+ if (!skipWelcome && stdout.isTTY === true) {
3983
+ const settleApp = app;
3984
+ settleWelcomeGreeting({
3985
+ enabled: true,
3986
+ isTty: true,
3987
+ isAgentBusy: () => settleApp.isAgentBusy,
3988
+ isInputPending: () => settleApp.getInputValue() !== "" || settleApp.getInputImagesCount() > 0,
3989
+ commitStatic: (text) => settleApp.commitStatic(text)
3990
+ });
3991
+ }
3992
+ if (existingMsgCount > 0) {
3993
+ try {
3994
+ const est = ctx.session.getEstimatedTokens();
3995
+ const max = ctx.agent.config.contextWindow;
3996
+ if (max > 0 && est / max >= HANDOFF_NUDGE_RATIO) {
3997
+ app.commitStatic(formatHandoffNudge(est / max));
3998
+ }
3999
+ } catch {
4000
+ }
4001
+ }
4002
+ {
4003
+ const recentSessions = SessionPersist.listMainSessions(process.cwd()).filter((s) => s.id !== ctx.sessionId && (s.turnCount ?? 0) > 0 && typeof s.updatedAt === "number" && Date.now() - s.updatedAt < 7 * 24 * 60 * 60 * 1e3);
4004
+ if (wantSessionPicker) {
4005
+ if (recentSessions.length > 0) {
4006
+ app.activateOverlay("chronicle");
4007
+ } else {
4008
+ app.commitStatic("\u6CA1\u6709\u53EF\u6062\u590D\u7684\u5386\u53F2\u4F1A\u8BDD \u2014 \u5DF2\u5F00\u542F\u65B0\u4F1A\u8BDD\u3002");
4009
+ }
4010
+ }
4011
+ }
4012
+ {
4013
+ const restoredPlan = restorePlanModeFromMeta(ctx.agent, ctx.cwd, initialMeta);
4014
+ if (restoredPlan) {
4015
+ app.commitStatic(`\u{1F50D} \u5DF2\u6062\u590D\u8BA1\u5212\u6A21\u5F0F\uFF08draft: ${restoredPlan}\uFF09\u2014 /plan-mode \u9000\u51FA\u6216\u6279\u51C6\u8BA1\u5212\u540E\u6267\u884C\u3002`);
4016
+ }
4017
+ }
4018
+ if (ctx && !ctx.auth && (!ctx.apiKey || ctx.apiKey.trim() === "") && existingMsgCount === 0) {
4019
+ if (getOnboardingState().shouldShow) {
4020
+ app.commitStatic("\u5C1A\u672A\u914D\u7F6E\u6A21\u578B\u670D\u52A1\u5546\u7684 API \u5BC6\u94A5 \u2014 \u6B63\u5728\u6253\u5F00\u914D\u7F6E\u5411\u5BFC\uFF08/connect \u53EF\u968F\u65F6\u518D\u6B21\u6253\u5F00\uFF09\u3002");
4021
+ app.startConnect(void 0, ctx?.config.provider.default);
4022
+ } else {
4023
+ app.commitStatic("\u5C1A\u672A\u914D\u7F6E\u6A21\u578B\u5BC6\u94A5\u2014\u2014/connect \u6253\u5F00\u914D\u7F6E\u5411\u5BFC\uFF08\u81EA\u52A8\u5F39\u7A97\u5DF2\u6309\u4F60\u7684\u9009\u62E9\u5173\u95ED\uFF09\u3002");
4024
+ }
4025
+ }
4026
+ void (async () => {
4027
+ try {
4028
+ const env = await detectEnv(process.cwd());
4029
+ const banner = formatGitMissingBanner(env.git.available, env.platform);
4030
+ if (banner) app?.commitStatic(banner);
4031
+ } catch {
4032
+ }
4033
+ })();
4034
+ void (async () => {
4035
+ try {
4036
+ const { resolveToolPreset } = await import("./tool-preset-LU5BYEDZ.js");
4037
+ if (!presetIncludes(resolveToolPreset(process.cwd()), "browser_debug")) return;
4038
+ const { probeChromium, formatBrowserMissingBanner } = await import("./browser-readiness-LWVGSBD5.js");
4039
+ const probe = await probeChromium();
4040
+ const banner = formatBrowserMissingBanner(probe);
4041
+ if (banner) app?.commitStatic(banner);
4042
+ } catch {
4043
+ }
4044
+ })();
4045
+ if (!process.env.RIVET_NO_UPDATE_CHECK) {
4046
+ void (async () => {
4047
+ try {
4048
+ const update = await checkForUpdate();
4049
+ if (update?.hasUpdate) {
4050
+ app.commitStatic(formatUpdateBanner(update.current, update.latest));
4051
+ }
4052
+ } catch {
4053
+ }
4054
+ })();
4055
+ }
4056
+ }
4057
+ main().catch((err) => {
4058
+ process.stderr.write(`[T9] Fatal: ${err?.message}
4059
+ `);
4060
+ if (err.stack) {
4061
+ process.stderr.write(err.stack + "\n");
4062
+ }
4063
+ void shutdown(1);
4064
+ });