muonroi-cli 1.8.3 → 1.8.5

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 (477) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +133 -122
  3. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  4. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  9. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  10. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  12. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  14. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  16. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  17. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  18. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  19. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  21. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  22. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  23. package/dist/src/agent-harness/mock-model.js +63 -1
  24. package/dist/src/agent-harness/test-spawn.js +31 -0
  25. package/dist/src/cli/config/screen-providers.js +1 -1
  26. package/dist/src/cli/cost-forensics.d.ts +10 -0
  27. package/dist/src/cli/cost-forensics.js +30 -15
  28. package/dist/src/cli/keys-bundle.d.ts +1 -1
  29. package/dist/src/cli/keys-bundle.js +1 -1
  30. package/dist/src/cli/keys.d.ts +2 -2
  31. package/dist/src/cli/keys.js +19 -81
  32. package/dist/src/council/clarifier.d.ts +28 -2
  33. package/dist/src/council/clarifier.js +81 -15
  34. package/dist/src/council/context.js +49 -15
  35. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  36. package/dist/src/council/debate-checkpoint.js +176 -0
  37. package/dist/src/council/debate-planner.js +51 -3
  38. package/dist/src/council/debate-summary.d.ts +25 -0
  39. package/dist/src/council/debate-summary.js +85 -0
  40. package/dist/src/council/debate.d.ts +169 -2
  41. package/dist/src/council/debate.js +1210 -134
  42. package/dist/src/council/index.d.ts +85 -1
  43. package/dist/src/council/index.js +634 -196
  44. package/dist/src/council/leader.d.ts +26 -0
  45. package/dist/src/council/leader.js +150 -9
  46. package/dist/src/council/llm.d.ts +32 -0
  47. package/dist/src/council/llm.js +231 -38
  48. package/dist/src/council/panel-select.d.ts +30 -0
  49. package/dist/src/council/panel-select.js +72 -0
  50. package/dist/src/council/planner.js +23 -0
  51. package/dist/src/council/preflight.d.ts +7 -0
  52. package/dist/src/council/preflight.js +14 -2
  53. package/dist/src/council/prompts.d.ts +30 -3
  54. package/dist/src/council/prompts.js +254 -84
  55. package/dist/src/council/stance-recall.d.ts +42 -0
  56. package/dist/src/council/stance-recall.js +57 -0
  57. package/dist/src/council/strip-think.d.ts +17 -0
  58. package/dist/src/council/strip-think.js +33 -0
  59. package/dist/src/council/types.d.ts +128 -0
  60. package/dist/src/ee/artifact-cache.d.ts +16 -0
  61. package/dist/src/ee/artifact-cache.js +32 -0
  62. package/dist/src/ee/auth.d.ts +1 -0
  63. package/dist/src/ee/auth.js +15 -2
  64. package/dist/src/ee/bridge.d.ts +10 -0
  65. package/dist/src/ee/bridge.js +58 -0
  66. package/dist/src/ee/client.js +81 -18
  67. package/dist/src/ee/export-transcripts.d.ts +1 -0
  68. package/dist/src/ee/export-transcripts.js +8 -10
  69. package/dist/src/ee/extract-session.js +29 -0
  70. package/dist/src/ee/extract-style.d.ts +58 -0
  71. package/dist/src/ee/extract-style.js +270 -0
  72. package/dist/src/ee/recall-ledger.d.ts +9 -0
  73. package/dist/src/ee/recall-ledger.js +3 -0
  74. package/dist/src/ee/scope.d.ts +1 -0
  75. package/dist/src/ee/scope.js +26 -1
  76. package/dist/src/ee/search.d.ts +7 -0
  77. package/dist/src/ee/search.js +24 -0
  78. package/dist/src/ee/transcript-emit.js +2 -0
  79. package/dist/src/ee/types.d.ts +22 -0
  80. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  81. package/dist/src/ee/who-am-i-brain.js +220 -0
  82. package/dist/src/ee/who-am-i.d.ts +10 -3
  83. package/dist/src/ee/who-am-i.js +12 -0
  84. package/dist/src/ee/workflow-event.d.ts +48 -0
  85. package/dist/src/ee/workflow-event.js +81 -0
  86. package/dist/src/flow/compaction/compress.d.ts +3 -3
  87. package/dist/src/flow/compaction/compress.js +45 -8
  88. package/dist/src/flow/compaction/extract.d.ts +4 -7
  89. package/dist/src/flow/compaction/extract.js +50 -10
  90. package/dist/src/flow/compaction/index.d.ts +13 -1
  91. package/dist/src/flow/compaction/index.js +70 -3
  92. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  93. package/dist/src/flow/compaction/input-guard.js +43 -0
  94. package/dist/src/flow/fold-planning.d.ts +36 -0
  95. package/dist/src/flow/fold-planning.js +83 -0
  96. package/dist/src/flow/hierarchy.d.ts +146 -0
  97. package/dist/src/flow/hierarchy.js +427 -0
  98. package/dist/src/flow/index.d.ts +1 -0
  99. package/dist/src/flow/index.js +2 -0
  100. package/dist/src/flow/run-artifacts.d.ts +102 -0
  101. package/dist/src/flow/run-artifacts.js +208 -0
  102. package/dist/src/generated/version.d.ts +1 -1
  103. package/dist/src/generated/version.js +1 -1
  104. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  105. package/dist/src/gsd/assessment-schema.js +134 -0
  106. package/dist/src/gsd/capability-registry.d.ts +45 -0
  107. package/dist/src/gsd/capability-registry.js +337 -0
  108. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  109. package/dist/src/gsd/complexity-assessor.js +152 -0
  110. package/dist/src/gsd/config-bridge.d.ts +7 -0
  111. package/dist/src/gsd/config-bridge.js +114 -0
  112. package/dist/src/gsd/config-loader.d.ts +27 -0
  113. package/dist/src/gsd/config-loader.js +50 -0
  114. package/dist/src/gsd/council-context.d.ts +44 -0
  115. package/dist/src/gsd/council-context.js +114 -0
  116. package/dist/src/gsd/ee-closure.d.ts +28 -0
  117. package/dist/src/gsd/ee-closure.js +49 -0
  118. package/dist/src/gsd/flags.d.ts +55 -0
  119. package/dist/src/gsd/flags.js +83 -0
  120. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  121. package/dist/src/gsd/gsd-dispatch.js +131 -0
  122. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  123. package/dist/src/gsd/gsd-runtime.js +37 -0
  124. package/dist/src/gsd/host-adapter.d.ts +11 -0
  125. package/dist/src/gsd/host-adapter.js +29 -0
  126. package/dist/src/gsd/index.d.ts +24 -1
  127. package/dist/src/gsd/index.js +27 -0
  128. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  129. package/dist/src/gsd/loop-host-contract.js +39 -0
  130. package/dist/src/gsd/loop-host.d.ts +69 -0
  131. package/dist/src/gsd/loop-host.js +245 -0
  132. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  133. package/dist/src/gsd/loop-resolver.js +79 -0
  134. package/dist/src/gsd/model-tier.d.ts +13 -0
  135. package/dist/src/gsd/model-tier.js +45 -0
  136. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  137. package/dist/src/gsd/mutation-gate.js +41 -0
  138. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  139. package/dist/src/gsd/native-roadmap.js +343 -0
  140. package/dist/src/gsd/native-state.d.ts +47 -0
  141. package/dist/src/gsd/native-state.js +220 -0
  142. package/dist/src/gsd/paths.d.ts +23 -0
  143. package/dist/src/gsd/paths.js +66 -0
  144. package/dist/src/gsd/phase-dag.d.ts +12 -0
  145. package/dist/src/gsd/phase-dag.js +94 -0
  146. package/dist/src/gsd/phase-sync.d.ts +42 -0
  147. package/dist/src/gsd/phase-sync.js +321 -0
  148. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  149. package/dist/src/gsd/pil-gate-context.js +64 -0
  150. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  151. package/dist/src/gsd/pil-gate-critic.js +74 -0
  152. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  153. package/dist/src/gsd/plan-council-prompts.js +79 -0
  154. package/dist/src/gsd/plan-council.d.ts +44 -0
  155. package/dist/src/gsd/plan-council.js +251 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  157. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  158. package/dist/src/gsd/product-workspace.d.ts +13 -0
  159. package/dist/src/gsd/product-workspace.js +124 -0
  160. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  161. package/dist/src/gsd/ship-bridge.js +65 -0
  162. package/dist/src/gsd/state-document.d.ts +40 -0
  163. package/dist/src/gsd/state-document.js +163 -0
  164. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  165. package/dist/src/gsd/verdict-schema.js +144 -0
  166. package/dist/src/gsd/verify-context.d.ts +22 -0
  167. package/dist/src/gsd/verify-context.js +27 -0
  168. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  169. package/dist/src/gsd/verify-council-prompts.js +85 -0
  170. package/dist/src/gsd/verify-council.d.ts +25 -0
  171. package/dist/src/gsd/verify-council.js +119 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  173. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  174. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  175. package/dist/src/gsd/workflow-engine.js +207 -0
  176. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  177. package/dist/src/gsd/workflow-tools.js +277 -0
  178. package/dist/src/hooks/index.js +1 -1
  179. package/dist/src/index.js +44 -11
  180. package/dist/src/maintain/pr-builder.js +23 -13
  181. package/dist/src/mcp/auto-setup.js +57 -32
  182. package/dist/src/mcp/client-pool.js +1 -1
  183. package/dist/src/mcp/ee-tools.js +1 -0
  184. package/dist/src/mcp/oauth-callback.js +2 -2
  185. package/dist/src/mcp/research-onboarding.js +8 -7
  186. package/dist/src/mcp/runtime.js +34 -2
  187. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  188. package/dist/src/mcp/setup-guide-text.js +77 -76
  189. package/dist/src/models/catalog-client.d.ts +87 -0
  190. package/dist/src/models/catalog-client.js +105 -38
  191. package/dist/src/models/catalog.json +528 -265
  192. package/dist/src/models/registry.d.ts +22 -7
  193. package/dist/src/models/registry.js +73 -10
  194. package/dist/src/ops/doctor.js +8 -8
  195. package/dist/src/orchestrator/auto-commit.js +1 -1
  196. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  197. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  198. package/dist/src/orchestrator/cache-prefix.js +83 -0
  199. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  200. package/dist/src/orchestrator/compact-request.js +41 -0
  201. package/dist/src/orchestrator/compaction.d.ts +10 -0
  202. package/dist/src/orchestrator/compaction.js +27 -7
  203. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  204. package/dist/src/orchestrator/council-manager.js +65 -24
  205. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  206. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  207. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  208. package/dist/src/orchestrator/error-utils.js +132 -24
  209. package/dist/src/orchestrator/grounding-check.js +39 -1
  210. package/dist/src/orchestrator/message-processor.js +242 -33
  211. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  212. package/dist/src/orchestrator/orchestrator.js +651 -102
  213. package/dist/src/orchestrator/preprocessor.js +1 -1
  214. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  215. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  216. package/dist/src/orchestrator/prompts.js +159 -159
  217. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  218. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  219. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  220. package/dist/src/orchestrator/retry-classifier.js +46 -2
  221. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  222. package/dist/src/orchestrator/safety-intercept.js +55 -0
  223. package/dist/src/orchestrator/scope-reminder.js +1 -1
  224. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  225. package/dist/src/orchestrator/session-experience.js +2 -1
  226. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  227. package/dist/src/orchestrator/should-run-gate.js +18 -0
  228. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  229. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  230. package/dist/src/orchestrator/stream-runner.js +62 -29
  231. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  232. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  233. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  234. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  235. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  236. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  237. package/dist/src/orchestrator/tool-engine.d.ts +26 -0
  238. package/dist/src/orchestrator/tool-engine.js +669 -56
  239. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  240. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  241. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  242. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  243. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  244. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  245. package/dist/src/pil/agent-operating-contract.js +1 -1
  246. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  247. package/dist/src/pil/cheap-model-playbook.js +5 -1
  248. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  249. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  250. package/dist/src/pil/discovery-types.d.ts +1 -0
  251. package/dist/src/pil/discovery.js +16 -11
  252. package/dist/src/pil/layer1-intent.d.ts +18 -6
  253. package/dist/src/pil/layer1-intent.js +66 -757
  254. package/dist/src/pil/layer15-context-scan.js +15 -1
  255. package/dist/src/pil/layer2_5-ponytail.js +8 -8
  256. package/dist/src/pil/layer3-ee-injection.js +23 -8
  257. package/dist/src/pil/layer4-gsd.js +69 -16
  258. package/dist/src/pil/layer5-context.js +7 -3
  259. package/dist/src/pil/layer6-output.d.ts +23 -0
  260. package/dist/src/pil/layer6-output.js +5 -1
  261. package/dist/src/pil/llm-classify.d.ts +33 -2
  262. package/dist/src/pil/llm-classify.js +123 -131
  263. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  264. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  265. package/dist/src/pil/pipeline.js +34 -2
  266. package/dist/src/pil/response-tools.js +5 -3
  267. package/dist/src/pil/schema.d.ts +1 -0
  268. package/dist/src/pil/schema.js +2 -0
  269. package/dist/src/pil/types.d.ts +18 -0
  270. package/dist/src/playbook/directives.d.ts +4 -0
  271. package/dist/src/playbook/directives.js +17 -5
  272. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  273. package/dist/src/product-loop/backlog-builder.js +30 -6
  274. package/dist/src/product-loop/discovery-context-format.js +3 -1
  275. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  276. package/dist/src/product-loop/discovery-interview.js +32 -3
  277. package/dist/src/product-loop/discovery-schema.js +5 -1
  278. package/dist/src/product-loop/done-gate.js +3 -3
  279. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  280. package/dist/src/product-loop/ideal-trace.js +64 -0
  281. package/dist/src/product-loop/index.d.ts +13 -1
  282. package/dist/src/product-loop/index.js +333 -52
  283. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  284. package/dist/src/product-loop/loop-driver.js +327 -116
  285. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  286. package/dist/src/product-loop/phase-plan.js +39 -2
  287. package/dist/src/product-loop/phase-runner.js +9 -1
  288. package/dist/src/product-loop/progress-snapshot.js +4 -4
  289. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  290. package/dist/src/product-loop/sprint-runner.js +559 -16
  291. package/dist/src/product-loop/types.d.ts +36 -5
  292. package/dist/src/providers/adapter.d.ts +1 -1
  293. package/dist/src/providers/adapter.js +3 -4
  294. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  295. package/dist/src/providers/auth/browser-flow.js +1 -1
  296. package/dist/src/providers/auth/openai-oauth.js +1 -1
  297. package/dist/src/providers/auth/registry.js +0 -34
  298. package/dist/src/providers/auth/token-store.js +4 -1
  299. package/dist/src/providers/auth/types.d.ts +1 -1
  300. package/dist/src/providers/auth/types.js +1 -1
  301. package/dist/src/providers/capabilities.d.ts +24 -5
  302. package/dist/src/providers/capabilities.js +42 -24
  303. package/dist/src/providers/endpoints.d.ts +2 -2
  304. package/dist/src/providers/endpoints.js +11 -10
  305. package/dist/src/providers/keychain.d.ts +1 -1
  306. package/dist/src/providers/keychain.js +7 -9
  307. package/dist/src/providers/mcp-vision-bridge.js +82 -172
  308. package/dist/src/providers/openai-compatible.js +8 -1
  309. package/dist/src/providers/pricing.d.ts +2 -2
  310. package/dist/src/providers/pricing.js +3 -13
  311. package/dist/src/providers/runtime.d.ts +27 -2
  312. package/dist/src/providers/runtime.js +78 -15
  313. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  314. package/dist/src/providers/strategies/base.strategy.js +24 -1
  315. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  316. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  317. package/dist/src/providers/strategies/registry.js +4 -4
  318. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  319. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  320. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  321. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  322. package/dist/src/providers/types.d.ts +5 -6
  323. package/dist/src/providers/types.js +2 -2
  324. package/dist/src/providers/vision-backend.d.ts +47 -0
  325. package/dist/src/providers/vision-backend.js +258 -0
  326. package/dist/src/providers/vision-proxy.d.ts +22 -9
  327. package/dist/src/providers/vision-proxy.js +63 -132
  328. package/dist/src/providers/wire-debug.js +95 -0
  329. package/dist/src/reporter/index.js +1 -1
  330. package/dist/src/router/decide.d.ts +13 -0
  331. package/dist/src/router/decide.js +138 -36
  332. package/dist/src/router/peak-hour.d.ts +38 -0
  333. package/dist/src/router/peak-hour.js +107 -0
  334. package/dist/src/router/step-router.js +3 -2
  335. package/dist/src/router/warm.js +4 -5
  336. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  337. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  338. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  339. package/dist/src/scaffold/continuation-prompt.js +86 -60
  340. package/dist/src/scaffold/init-new.js +453 -453
  341. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  342. package/dist/src/scaffold/point-to-existing.js +25 -0
  343. package/dist/src/self-qa/agentic-loop.js +22 -22
  344. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  345. package/dist/src/{ui/state → state}/active-run.js +21 -0
  346. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  347. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  348. package/dist/src/state/turn-trace.d.ts +43 -0
  349. package/dist/src/state/turn-trace.js +32 -0
  350. package/dist/src/storage/db.js +2 -1
  351. package/dist/src/storage/index.d.ts +1 -1
  352. package/dist/src/storage/index.js +1 -1
  353. package/dist/src/storage/interaction-log.d.ts +1 -1
  354. package/dist/src/storage/interaction-log.js +5 -5
  355. package/dist/src/storage/migrations.js +196 -126
  356. package/dist/src/storage/session-experience-store.js +4 -4
  357. package/dist/src/storage/sessions.d.ts +28 -10
  358. package/dist/src/storage/sessions.js +112 -55
  359. package/dist/src/storage/transcript-view.js +1 -1
  360. package/dist/src/storage/transcript.d.ts +51 -0
  361. package/dist/src/storage/transcript.js +383 -112
  362. package/dist/src/storage/usage.js +14 -14
  363. package/dist/src/storage/workspaces.js +12 -12
  364. package/dist/src/tools/file.d.ts +15 -0
  365. package/dist/src/tools/file.js +32 -0
  366. package/dist/src/tools/native-tools.js +5 -0
  367. package/dist/src/tools/registry.d.ts +3 -0
  368. package/dist/src/tools/registry.js +460 -22
  369. package/dist/src/tools/research.d.ts +29 -0
  370. package/dist/src/tools/research.js +233 -0
  371. package/dist/src/types/index.d.ts +118 -3
  372. package/dist/src/ui/app.js +0 -0
  373. package/dist/src/ui/cards/product-status-card.js +1 -1
  374. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  375. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  376. package/dist/src/ui/components/context-rail.d.ts +26 -0
  377. package/dist/src/ui/components/context-rail.js +33 -0
  378. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  379. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  380. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  381. package/dist/src/ui/components/council-debate-pill.js +34 -0
  382. package/dist/src/ui/components/council-info-card.js +2 -2
  383. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  384. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  385. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  386. package/dist/src/ui/components/council-message-bubble.js +16 -15
  387. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  388. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  389. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  390. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  391. package/dist/src/ui/components/council-question-card.js +12 -12
  392. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  393. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  394. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  395. package/dist/src/ui/components/council-round-group.js +88 -0
  396. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  397. package/dist/src/ui/components/council-status-list.js +36 -24
  398. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  399. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  400. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  401. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  402. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  403. package/dist/src/ui/components/prompt-box.js +18 -16
  404. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  405. package/dist/src/ui/components/session-tree-card.js +46 -0
  406. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  407. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  408. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  409. package/dist/src/ui/components/task-list-panel.js +22 -2
  410. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  411. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  412. package/dist/src/ui/mcp-modal.js +2 -4
  413. package/dist/src/ui/modals/api-key-modal.js +1 -1
  414. package/dist/src/ui/modals/connect-modal.js +4 -3
  415. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  416. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  417. package/dist/src/ui/picker-providers.d.ts +1 -1
  418. package/dist/src/ui/picker-providers.js +1 -1
  419. package/dist/src/ui/primitives/index.d.ts +1 -0
  420. package/dist/src/ui/primitives/index.js +2 -0
  421. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  422. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  423. package/dist/src/ui/slash/compact.js +5 -7
  424. package/dist/src/ui/slash/cost.js +1 -1
  425. package/dist/src/ui/slash/council-inspect.js +4 -4
  426. package/dist/src/ui/slash/council.js +19 -1
  427. package/dist/src/ui/slash/debug.d.ts +3 -31
  428. package/dist/src/ui/slash/debug.js +9 -20
  429. package/dist/src/ui/slash/ideal.d.ts +6 -2
  430. package/dist/src/ui/slash/ideal.js +97 -7
  431. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  432. package/dist/src/ui/slash/menu-items.js +12 -18
  433. package/dist/src/ui/slash/registry.d.ts +2 -0
  434. package/dist/src/ui/slash/registry.js +4 -0
  435. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  436. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  437. package/dist/src/ui/status-bar/index.d.ts +1 -1
  438. package/dist/src/ui/status-bar/index.js +7 -3
  439. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  440. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  441. package/dist/src/ui/theme.d.ts +1 -0
  442. package/dist/src/ui/theme.js +2 -0
  443. package/dist/src/ui/types.d.ts +7 -0
  444. package/dist/src/ui/use-app-logic.js +0 -0
  445. package/dist/src/ui/utils/format.d.ts +14 -0
  446. package/dist/src/ui/utils/format.js +23 -3
  447. package/dist/src/usage/downgrade.js +2 -2
  448. package/dist/src/usage/product-ledger.js +2 -2
  449. package/dist/src/utils/clipboard-image.js +23 -23
  450. package/dist/src/utils/install-manager.js +14 -11
  451. package/dist/src/utils/logger.js +2 -2
  452. package/dist/src/utils/permission-mode.js +5 -3
  453. package/dist/src/utils/redactor.js +1 -1
  454. package/dist/src/utils/settings.d.ts +153 -5
  455. package/dist/src/utils/settings.js +233 -29
  456. package/dist/src/utils/side-question.js +2 -2
  457. package/dist/src/utils/skills.js +3 -3
  458. package/dist/src/utils/visible-retry.d.ts +11 -0
  459. package/dist/src/utils/visible-retry.js +10 -1
  460. package/dist/src/verify/entrypoint.d.ts +1 -1
  461. package/dist/src/verify/entrypoint.js +1 -1
  462. package/dist/src/verify/recipes.d.ts +13 -0
  463. package/dist/src/verify/recipes.js +15 -0
  464. package/package.json +135 -132
  465. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  466. package/dist/src/providers/auth/gcloud.js +0 -102
  467. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  468. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  469. package/dist/src/providers/gemini.d.ts +0 -11
  470. package/dist/src/providers/gemini.js +0 -45
  471. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  472. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  473. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  474. package/dist/src/providers/strategies/google.strategy.js +0 -174
  475. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  476. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  477. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -43,11 +43,11 @@ function isInternalCouncilMarker(content) {
43
43
  }
44
44
  function loadMessageRows(sessionId) {
45
45
  const rows = getDatabase()
46
- .prepare(`
47
- SELECT session_id, seq, role, message_json, created_at
48
- FROM messages
49
- WHERE session_id = ?
50
- ORDER BY seq ASC
46
+ .prepare(`
47
+ SELECT session_id, seq, role, message_json, created_at
48
+ FROM messages
49
+ WHERE session_id = ?
50
+ ORDER BY seq ASC
51
51
  `)
52
52
  .all(sessionId);
53
53
  for (const row of rows) {
@@ -67,12 +67,12 @@ function toPersistedCompaction(row) {
67
67
  }
68
68
  export function loadLatestCompaction(sessionId) {
69
69
  const row = getDatabase()
70
- .prepare(`
71
- SELECT session_id, first_kept_seq, summary, tokens_before, created_at
72
- FROM compactions
73
- WHERE session_id = ?
74
- ORDER BY id DESC
75
- LIMIT 1
70
+ .prepare(`
71
+ SELECT session_id, first_kept_seq, summary, tokens_before, created_at
72
+ FROM compactions
73
+ WHERE session_id = ?
74
+ ORDER BY id DESC
75
+ LIMIT 1
76
76
  `)
77
77
  .get(sessionId);
78
78
  return toPersistedCompaction(row);
@@ -99,6 +99,119 @@ export function loadTranscriptState(sessionId) {
99
99
  export function loadTranscript(sessionId) {
100
100
  return loadTranscriptState(sessionId).messages;
101
101
  }
102
+ /**
103
+ * Resume a session together with every session in its conversation tree.
104
+ *
105
+ * When a session has spawned child sessions (silent rotations, sub-agents,
106
+ * sub-sessions), resuming only the parent loses the work that happened in the
107
+ * children. This loader walks up to the root and then down through all
108
+ * descendants, applies each session's own compaction, merges the messages
109
+ * chronologically, and returns them as one flat transcript for the model.
110
+ *
111
+ * Sequence numbers from sessions other than the one being resumed are replaced
112
+ * with `null` so that usage attribution and compaction still belong to the
113
+ * resumed session.
114
+ */
115
+ export function loadSessionChainTranscriptState(sessionId) {
116
+ const chain = getSessionChain(sessionId);
117
+ if (chain.length <= 1) {
118
+ return loadTranscriptState(sessionId);
119
+ }
120
+ const records = [];
121
+ for (const sid of chain) {
122
+ const rows = loadMessageRows(sid);
123
+ const messages = rows.map((row) => JSON.parse(row.message_json));
124
+ const seqs = rows.map((row) => row.seq);
125
+ const timestamps = rows.map((row) => new Date(row.created_at));
126
+ const effective = buildEffectiveTranscript(messages, seqs, timestamps, loadLatestCompaction(sid));
127
+ for (let i = 0; i < effective.messages.length; i++) {
128
+ records.push({
129
+ sessionId: sid,
130
+ message: effective.messages[i],
131
+ seq: effective.seqs[i],
132
+ timestamp: effective.timestamps[i],
133
+ });
134
+ }
135
+ }
136
+ // getSessionChain already orders sessions by creation time. Preserve each
137
+ // session's internal effective-transcript order (especially compaction
138
+ // summaries, which must precede their kept tail) instead of re-sorting by
139
+ // individual message timestamps.
140
+ return {
141
+ messages: records.map((r) => r.message),
142
+ seqs: records.map((r) => (r.sessionId === sessionId ? r.seq : null)),
143
+ timestamps: records.map((r) => r.timestamp),
144
+ compaction: loadLatestCompaction(sessionId),
145
+ };
146
+ }
147
+ /**
148
+ * Enumerate the full session chain (root + all descendants) with per-session
149
+ * metadata, ordered root-first then by creation time. Read-only; safe to call
150
+ * on every render. Returns a single-node array for a session with no children.
151
+ */
152
+ export function getSessionChainInfos(sessionId) {
153
+ const chain = getSessionChain(sessionId);
154
+ if (chain.length === 0)
155
+ return [];
156
+ const db = getDatabase();
157
+ const placeholders = chain.map(() => "?").join(",");
158
+ let rows = [];
159
+ try {
160
+ rows = db
161
+ .prepare(`
162
+ SELECT s.id, s.parent_session_id, s.kind, s.model, s.status, s.created_at,
163
+ (SELECT COUNT(*) FROM messages m WHERE m.session_id = s.id) AS msgs
164
+ FROM sessions s
165
+ WHERE s.id IN (${placeholders})
166
+ `)
167
+ .all(...chain);
168
+ }
169
+ catch (err) {
170
+ logger.error("storage", "getSessionChainInfos query failed", {
171
+ sessionId,
172
+ message: err?.message,
173
+ });
174
+ return [];
175
+ }
176
+ const byId = new Map(rows.map((r) => [r.id, r]));
177
+ const depthOf = (id) => {
178
+ let depth = 0;
179
+ let cur = id;
180
+ const seen = new Set();
181
+ while (cur && !seen.has(cur)) {
182
+ seen.add(cur);
183
+ const parent = byId.get(cur)?.parent_session_id ?? null;
184
+ // Only count parents that are inside this chain (the walk-up root has none).
185
+ if (parent && byId.has(parent)) {
186
+ depth++;
187
+ cur = parent;
188
+ }
189
+ else {
190
+ break;
191
+ }
192
+ }
193
+ return depth;
194
+ };
195
+ const nodes = chain
196
+ .map((id) => byId.get(id))
197
+ .filter((r) => r !== undefined)
198
+ .map((r) => ({
199
+ id: r.id,
200
+ kind: r.kind ?? null,
201
+ model: r.model,
202
+ status: r.status,
203
+ messageCount: r.msgs,
204
+ parentId: r.parent_session_id,
205
+ depth: depthOf(r.id),
206
+ isCurrent: r.id === sessionId,
207
+ }));
208
+ // Render order: shallowest first (root → children → grandchildren) so the rail
209
+ // always shows the parent on top with descendants indented under it. Ties keep
210
+ // getSessionChain's created_at order. A stable index-carrying sort — chain
211
+ // created_at can tie at second granularity, so depth is the deterministic key.
212
+ const chainIndex = new Map(nodes.map((n, i) => [n.id, i]));
213
+ return nodes.sort((a, b) => a.depth - b.depth || chainIndex.get(a.id) - chainIndex.get(b.id));
214
+ }
102
215
  export function getNextMessageSequence(sessionId) {
103
216
  return getNextSequence(getDatabase(), sessionId);
104
217
  }
@@ -113,43 +226,44 @@ export function appendMessages(sessionId, messages) {
113
226
  // with `status='completed'` and the full message_json. Pre-A5 callers
114
227
  // hit this path identically: there is no pending row so the IGNORE
115
228
  // branch is unused and the INSERT wins.
116
- const insertMessage = db.prepare(`
117
- INSERT INTO messages (session_id, seq, role, message_json, created_at, status)
118
- VALUES (?, ?, ?, ?, ?, 'completed')
119
- ON CONFLICT(session_id, seq) DO UPDATE SET
120
- role = excluded.role,
121
- message_json = excluded.message_json,
122
- status = 'completed'
229
+ const insertMessage = db.prepare(`
230
+ INSERT INTO messages (session_id, seq, role, message_json, created_at, status)
231
+ VALUES (?, ?, ?, ?, ?, 'completed')
232
+ ON CONFLICT(session_id, seq) DO UPDATE SET
233
+ role = excluded.role,
234
+ message_json = excluded.message_json,
235
+ status = 'completed'
123
236
  `);
124
- const insertToolCall = db.prepare(`
125
- INSERT OR IGNORE INTO tool_calls (
126
- session_id, message_seq, tool_call_id, tool_name, args_json, status, started_at, completed_at
127
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
237
+ const insertToolCall = db.prepare(`
238
+ INSERT OR IGNORE INTO tool_calls (
239
+ session_id, message_seq, tool_call_id, tool_name, args_json, status, started_at, completed_at
240
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
128
241
  `);
129
- const updateToolCall = db.prepare(`
130
- UPDATE tool_calls
131
- SET tool_name = ?, args_json = ?, status = ?, completed_at = ?
132
- WHERE session_id = ? AND tool_call_id = ?
242
+ const updateToolCall = db.prepare(`
243
+ UPDATE tool_calls
244
+ SET tool_name = ?, args_json = ?, status = ?, completed_at = ?
245
+ WHERE session_id = ? AND tool_call_id = ?
133
246
  `);
134
- const selectToolCall = db.prepare(`
135
- SELECT id, tool_call_id, tool_name, args_json
136
- FROM tool_calls
137
- WHERE session_id = ? AND tool_call_id = ?
247
+ const selectToolCall = db.prepare(`
248
+ SELECT id, tool_call_id, tool_name, args_json
249
+ FROM tool_calls
250
+ WHERE session_id = ? AND tool_call_id = ?
138
251
  `);
139
- const insertToolResult = db.prepare(`
140
- INSERT INTO tool_results (tool_call_row_id, output_kind, output_json, success, created_at)
141
- VALUES (?, ?, ?, ?, ?)
252
+ const insertToolResult = db.prepare(`
253
+ INSERT INTO tool_results (tool_call_row_id, output_kind, output_json, success, created_at)
254
+ VALUES (?, ?, ?, ?, ?)
142
255
  `);
143
- const updateSession = db.prepare(`
144
- UPDATE sessions
145
- SET updated_at = ?
146
- WHERE id = ?
256
+ const updateSession = db.prepare(`
257
+ UPDATE sessions
258
+ SET updated_at = ?
259
+ WHERE id = ?
147
260
  `);
148
261
  messages.forEach((message, index) => {
149
262
  const seq = nextSeq + index;
150
263
  const createdAt = new Date().toISOString();
151
264
  insertedSeqs.push(seq);
152
265
  insertMessage.run(sessionId, seq, message.role, JSON.stringify(message), createdAt);
266
+ indexMessageInFts(db, sessionId, seq, message.role, JSON.stringify(message));
153
267
  if (message.role === "assistant" && Array.isArray(message.content)) {
154
268
  for (const part of message.content) {
155
269
  if (part.type !== "tool-call")
@@ -205,16 +319,20 @@ export function persistToolCallWriteAhead(sessionId, messageSeq, toolCallId, too
205
319
  const now = new Date().toISOString();
206
320
  try {
207
321
  getDatabase()
208
- .prepare(`
209
- INSERT OR IGNORE INTO tool_calls (
210
- session_id, message_seq, tool_call_id, tool_name, args_json, status, started_at, completed_at
211
- ) VALUES (?, ?, ?, ?, ?, 'pending', ?, NULL)
322
+ .prepare(`
323
+ INSERT OR IGNORE INTO tool_calls (
324
+ session_id, message_seq, tool_call_id, tool_name, args_json, status, started_at, completed_at
325
+ ) VALUES (?, ?, ?, ?, ?, 'pending', ?, NULL)
212
326
  `)
213
327
  .run(sessionId, messageSeq, toolCallId, toolName, argsJson, now);
214
328
  }
215
- catch {
216
- // Fail-open: write-ahead is best-effort. The post-stream UPDATE path
217
- // will still finalize the row from `appendMessages(...)`.
329
+ catch (err) {
330
+ logger.error("storage", `[transcript] persistToolCallWriteAhead failed: ${err.message}`, {
331
+ sessionId,
332
+ messageSeq,
333
+ toolCallId,
334
+ toolName,
335
+ });
218
336
  }
219
337
  }
220
338
  /**
@@ -253,16 +371,20 @@ export function persistToolCallWriteAhead(sessionId, messageSeq, toolCallId, too
253
371
  export function persistMessageWriteAhead(sessionId, seq, role, messageJson) {
254
372
  const now = new Date().toISOString();
255
373
  try {
256
- getDatabase()
257
- .prepare(`
258
- INSERT OR IGNORE INTO messages (
259
- session_id, seq, role, message_json, created_at, status
260
- ) VALUES (?, ?, ?, ?, ?, 'pending')
261
- `)
262
- .run(sessionId, seq, role, messageJson, now);
374
+ const db = getDatabase();
375
+ db.prepare(`
376
+ INSERT OR IGNORE INTO messages (
377
+ session_id, seq, role, message_json, created_at, status
378
+ ) VALUES (?, ?, ?, ?, ?, 'pending')
379
+ `).run(sessionId, seq, role, messageJson, now);
380
+ indexMessageInFts(db, sessionId, seq, role, messageJson);
263
381
  }
264
- catch {
265
- /* fail-open */
382
+ catch (err) {
383
+ logger.error("storage", `[transcript] persistMessageWriteAhead failed: ${err.message}`, {
384
+ sessionId,
385
+ seq,
386
+ role,
387
+ });
266
388
  }
267
389
  }
268
390
  /**
@@ -275,15 +397,15 @@ export function persistMessageWriteAhead(sessionId, seq, role, messageJson) {
275
397
  export function markMessageCompleted(sessionId, seq) {
276
398
  try {
277
399
  getDatabase()
278
- .prepare(`
279
- UPDATE messages
280
- SET status = 'completed'
281
- WHERE session_id = ? AND seq = ? AND status = 'pending'
400
+ .prepare(`
401
+ UPDATE messages
402
+ SET status = 'completed'
403
+ WHERE session_id = ? AND seq = ? AND status = 'pending'
282
404
  `)
283
405
  .run(sessionId, seq);
284
406
  }
285
- catch {
286
- /* fail-open */
407
+ catch (err) {
408
+ logger.error("storage", `[transcript] markMessageCompleted failed: ${err.message}`, { sessionId, seq });
287
409
  }
288
410
  }
289
411
  /**
@@ -297,15 +419,15 @@ export function markMessageCompleted(sessionId, seq) {
297
419
  export function markMessageErrored(sessionId, seq) {
298
420
  try {
299
421
  getDatabase()
300
- .prepare(`
301
- UPDATE messages
302
- SET status = 'errored'
303
- WHERE session_id = ? AND seq = ? AND status = 'pending'
422
+ .prepare(`
423
+ UPDATE messages
424
+ SET status = 'errored'
425
+ WHERE session_id = ? AND seq = ? AND status = 'pending'
304
426
  `)
305
427
  .run(sessionId, seq);
306
428
  }
307
- catch {
308
- /* fail-open */
429
+ catch (err) {
430
+ logger.error("storage", `[transcript] markMessageErrored failed: ${err.message}`, { sessionId, seq });
309
431
  }
310
432
  }
311
433
  /**
@@ -331,17 +453,17 @@ export function sweepStalePendingRows(staleAfterMs = 5 * 60 * 1000) {
331
453
  try {
332
454
  const db = getDatabase();
333
455
  const toolCalls = db
334
- .prepare(`
335
- UPDATE tool_calls
336
- SET status = 'aborted', completed_at = started_at
337
- WHERE status = 'pending' AND started_at < ?
456
+ .prepare(`
457
+ UPDATE tool_calls
458
+ SET status = 'aborted', completed_at = started_at
459
+ WHERE status = 'pending' AND started_at < ?
338
460
  `)
339
461
  .run(cutoff);
340
462
  const messages = db
341
- .prepare(`
342
- UPDATE messages
343
- SET status = 'aborted'
344
- WHERE status = 'pending' AND created_at < ?
463
+ .prepare(`
464
+ UPDATE messages
465
+ SET status = 'aborted'
466
+ WHERE status = 'pending' AND created_at < ?
345
467
  `)
346
468
  .run(cutoff);
347
469
  return { toolCalls: toolCalls.changes, messages: messages.changes };
@@ -355,10 +477,10 @@ export function markToolCallErrored(sessionId, toolCallId, errorMessage) {
355
477
  const now = new Date().toISOString();
356
478
  try {
357
479
  getDatabase()
358
- .prepare(`
359
- UPDATE tool_calls
360
- SET status = 'errored', completed_at = ?, args_json = COALESCE(args_json, ?)
361
- WHERE session_id = ? AND tool_call_id = ?
480
+ .prepare(`
481
+ UPDATE tool_calls
482
+ SET status = 'errored', completed_at = ?, args_json = COALESCE(args_json, ?)
483
+ WHERE session_id = ? AND tool_call_id = ?
362
484
  `)
363
485
  .run(now, JSON.stringify({ error: errorMessage.slice(0, 500) }), sessionId, toolCallId);
364
486
  }
@@ -368,28 +490,28 @@ export function markToolCallErrored(sessionId, toolCallId, errorMessage) {
368
490
  }
369
491
  export function appendCompaction(sessionId, firstKeptSeq, summary, tokensBefore) {
370
492
  withTransaction((db) => {
371
- db.prepare(`
372
- INSERT INTO compactions (session_id, first_kept_seq, summary, tokens_before, created_at)
373
- VALUES (?, ?, ?, ?, ?)
493
+ db.prepare(`
494
+ INSERT INTO compactions (session_id, first_kept_seq, summary, tokens_before, created_at)
495
+ VALUES (?, ?, ?, ?, ?)
374
496
  `).run(sessionId, firstKeptSeq, summary, tokensBefore, new Date().toISOString());
375
- db.prepare(`
376
- UPDATE sessions
377
- SET updated_at = ?
378
- WHERE id = ?
497
+ db.prepare(`
498
+ UPDATE sessions
499
+ SET updated_at = ?
500
+ WHERE id = ?
379
501
  `).run(new Date().toISOString(), sessionId);
380
502
  });
381
503
  }
382
504
  export function revertLatestCompaction(sessionId) {
383
505
  withTransaction((db) => {
384
- db.prepare(`
385
- DELETE FROM compactions
386
- WHERE session_id = ?
387
- AND id = (SELECT MAX(id) FROM compactions WHERE session_id = ?)
506
+ db.prepare(`
507
+ DELETE FROM compactions
508
+ WHERE session_id = ?
509
+ AND id = (SELECT MAX(id) FROM compactions WHERE session_id = ?)
388
510
  `).run(sessionId, sessionId);
389
- db.prepare(`
390
- UPDATE sessions
391
- SET updated_at = ?
392
- WHERE id = ?
511
+ db.prepare(`
512
+ UPDATE sessions
513
+ SET updated_at = ?
514
+ WHERE id = ?
393
515
  `).run(new Date().toISOString(), sessionId);
394
516
  });
395
517
  }
@@ -439,10 +561,10 @@ export function getSessionChain(sessionId) {
439
561
  .map(() => "?")
440
562
  .join(",");
441
563
  const sortedRows = db
442
- .prepare(`
443
- SELECT id FROM sessions
444
- WHERE id IN (${placeholders})
445
- ORDER BY created_at ASC
564
+ .prepare(`
565
+ SELECT id FROM sessions
566
+ WHERE id IN (${placeholders})
567
+ ORDER BY created_at ASC
446
568
  `)
447
569
  .all(...Array.from(allIds));
448
570
  chain = sortedRows.map((r) => r.id);
@@ -624,10 +746,10 @@ export function buildChatEntries(sessionId) {
624
746
  }
625
747
  function getNextSequence(db, sessionId) {
626
748
  const row = db
627
- .prepare(`
628
- SELECT COALESCE(MAX(seq), 0) AS max_seq
629
- FROM messages
630
- WHERE session_id = ?
749
+ .prepare(`
750
+ SELECT COALESCE(MAX(seq), 0) AS max_seq
751
+ FROM messages
752
+ WHERE session_id = ?
631
753
  `)
632
754
  .get(sessionId);
633
755
  return (row?.max_seq ?? 0) + 1;
@@ -677,12 +799,12 @@ function renderAssistantContent(content, callMap) {
677
799
  }
678
800
  function loadStoredToolResults(sessionId) {
679
801
  const rows = getDatabase()
680
- .prepare(`
681
- SELECT tc.tool_call_id, tr.output_json
682
- FROM tool_results tr
683
- JOIN tool_calls tc ON tc.id = tr.tool_call_row_id
684
- WHERE tc.session_id = ?
685
- ORDER BY tr.id ASC
802
+ .prepare(`
803
+ SELECT tc.tool_call_id, tr.output_json
804
+ FROM tool_results tr
805
+ JOIN tool_calls tc ON tc.id = tr.tool_call_row_id
806
+ WHERE tc.session_id = ?
807
+ ORDER BY tr.id ASC
686
808
  `)
687
809
  .all(sessionId);
688
810
  return new Map(rows.map((row) => [row.tool_call_id, JSON.parse(row.output_json)]));
@@ -703,12 +825,12 @@ export function getLastTodoWriteArgs(sessionId) {
703
825
  for (let i = chain.length - 1; i >= 0; i--) {
704
826
  try {
705
827
  const row = db
706
- .prepare(`
707
- SELECT args_json
708
- FROM tool_calls
709
- WHERE session_id = ? AND tool_name = 'todo_write'
710
- ORDER BY id DESC
711
- LIMIT 1
828
+ .prepare(`
829
+ SELECT args_json
830
+ FROM tool_calls
831
+ WHERE session_id = ? AND tool_name = 'todo_write'
832
+ ORDER BY id DESC
833
+ LIMIT 1
712
834
  `)
713
835
  .get(chain[i]);
714
836
  if (row?.args_json) {
@@ -721,4 +843,153 @@ export function getLastTodoWriteArgs(sessionId) {
721
843
  }
722
844
  return null;
723
845
  }
846
+ /**
847
+ * Persist the approved plan text for a session so that "tiếp tục"/"continue"
848
+ * turns (which are classified as chitchat/general by PIL Pass 0) can re-inject
849
+ * the APPROVED PLAN section into the system prompt instead of forgetting context.
850
+ *
851
+ * Stored as a synthetic tool_call row (tool_name='__approved_plan') so we reuse
852
+ * the existing schema and getLast* query pattern without a new table/migration.
853
+ * The planText is stored verbatim in args_json.
854
+ */
855
+ export function persistApprovedPlan(sessionId, planText) {
856
+ if (!sessionId || !planText)
857
+ return;
858
+ const db = getDatabase();
859
+ const toolCallId = `approved-plan-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
860
+ const now = new Date().toISOString();
861
+ try {
862
+ db.prepare(`
863
+ INSERT OR REPLACE INTO tool_calls (session_id, message_seq, tool_call_id, tool_name, args_json, status, started_at, completed_at)
864
+ VALUES (?, 0, ?, '__approved_plan', ?, 'completed', ?, ?)
865
+ `).run(sessionId, toolCallId, planText, now, now);
866
+ }
867
+ catch {
868
+ /* best-effort persistence; never block the turn */
869
+ }
870
+ }
871
+ /** Load the most recent persisted approved plan for this session (or parent chain). */
872
+ export function getLastApprovedPlan(sessionId) {
873
+ const chain = getSessionChain(sessionId);
874
+ const db = getDatabase();
875
+ for (let i = chain.length - 1; i >= 0; i--) {
876
+ try {
877
+ // 1) Prefer our synthetic persisted row (written by setPlanContext + persistApprovedPlan).
878
+ const synthetic = db
879
+ .prepare(`
880
+ SELECT args_json
881
+ FROM tool_calls
882
+ WHERE session_id = ? AND tool_name = '__approved_plan'
883
+ ORDER BY id DESC
884
+ LIMIT 1
885
+ `)
886
+ .get(chain[i]);
887
+ if (synthetic?.args_json) {
888
+ return synthetic.args_json;
889
+ }
890
+ // 2) Fallback: scan real plan tool_calls (respond_plan / generate_plan) written by
891
+ // council, PIL response-tools, or generate_plan UI. Extract a human-readable slice.
892
+ const planRow = db
893
+ .prepare(`
894
+ SELECT args_json, tool_name
895
+ FROM tool_calls
896
+ WHERE session_id = ? AND tool_name IN ('respond_plan', 'generate_plan')
897
+ ORDER BY id DESC
898
+ LIMIT 1
899
+ `)
900
+ .get(chain[i]);
901
+ if (planRow?.args_json) {
902
+ try {
903
+ const parsed = JSON.parse(planRow.args_json);
904
+ // respond_plan shape typically has { steps, assumptions?, risks? } or { plan: {...} }
905
+ const candidate = parsed?.plan ?? parsed;
906
+ if (candidate && (Array.isArray(candidate.steps) || typeof candidate === "object")) {
907
+ return JSON.stringify(candidate, null, 2);
908
+ }
909
+ // generate_plan may carry raw text or { content, steps }
910
+ if (typeof parsed === "string")
911
+ return parsed;
912
+ if (parsed && typeof parsed === "object")
913
+ return JSON.stringify(parsed, null, 2);
914
+ }
915
+ catch {
916
+ // not JSON — return as-is (may be a raw string payload)
917
+ if (typeof planRow.args_json === "string" && planRow.args_json.trim().length > 0) {
918
+ return planRow.args_json;
919
+ }
920
+ }
921
+ }
922
+ }
923
+ catch {
924
+ // ignore and check parent
925
+ }
926
+ }
927
+ return null;
928
+ }
929
+ function indexMessageInFts(db, sessionId, seq, role, messageJsonStr) {
930
+ db.prepare(`DELETE FROM session_history_fts WHERE session_id = ? AND seq = ?`).run(sessionId, seq);
931
+ let message;
932
+ try {
933
+ message = JSON.parse(messageJsonStr);
934
+ }
935
+ catch (err) {
936
+ logger.error("storage", `[transcript] Failed to parse message JSON for FTS indexing: ${err.message}`, {
937
+ sessionId,
938
+ seq,
939
+ role,
940
+ });
941
+ return;
942
+ }
943
+ let content = "";
944
+ let toolName = "";
945
+ let toolArgs = "";
946
+ let toolOutput = "";
947
+ const msgContent = message.content;
948
+ if (typeof msgContent === "string") {
949
+ content = msgContent;
950
+ }
951
+ else if (Array.isArray(msgContent)) {
952
+ const textParts = [];
953
+ const toolNames = [];
954
+ const argParts = [];
955
+ const outputParts = [];
956
+ for (const part of msgContent) {
957
+ if (part && typeof part === "object") {
958
+ if (part.type === "text" && typeof part.text === "string") {
959
+ textParts.push(part.text);
960
+ }
961
+ else if (part.type === "tool-call" && typeof part.toolName === "string") {
962
+ toolNames.push(part.toolName);
963
+ if (part.input !== undefined) {
964
+ argParts.push(typeof part.input === "string" ? part.input : JSON.stringify(part.input));
965
+ }
966
+ }
967
+ else if (part.type === "tool-result" && typeof part.toolName === "string") {
968
+ toolNames.push(part.toolName);
969
+ if (part.output !== undefined) {
970
+ outputParts.push(typeof part.output === "string" ? part.output : JSON.stringify(part.output));
971
+ }
972
+ }
973
+ }
974
+ }
975
+ content = textParts.join("\n").trim();
976
+ toolName = toolNames.join(", ").trim();
977
+ toolArgs = argParts.join("\n").trim();
978
+ toolOutput = outputParts.join("\n").trim();
979
+ }
980
+ try {
981
+ db.prepare(`
982
+ INSERT INTO session_history_fts (session_id, seq, role, tool_name, content, tool_args, tool_output)
983
+ VALUES (?, ?, ?, ?, ?, ?, ?)
984
+ `).run(sessionId, seq, role, toolName || null, content || null, toolArgs || null, toolOutput || null);
985
+ }
986
+ catch (err) {
987
+ logger.error("storage", `[transcript] Failed to execute FTS indexing query: ${err.message}`, {
988
+ sessionId,
989
+ seq,
990
+ role,
991
+ });
992
+ throw err;
993
+ }
994
+ }
724
995
  //# sourceMappingURL=transcript.js.map
@@ -14,11 +14,11 @@ export function recordUsageEvent(sessionId, source, model, usage, messageSeq, pi
14
14
  const cacheCreationTokens = usage.cacheCreationTokens ?? 0;
15
15
  const costMicros = estimateCostMicros(model, inputTokens, outputTokens, cacheReadTokens);
16
16
  getDatabase()
17
- .prepare(`
18
- INSERT INTO usage_events (
19
- session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at,
20
- pil_active, enrichment_delta, cache_read_tokens, cache_creation_tokens, provider_options_shape
21
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
17
+ .prepare(`
18
+ INSERT INTO usage_events (
19
+ session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at,
20
+ pil_active, enrichment_delta, cache_read_tokens, cache_creation_tokens, provider_options_shape
21
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
22
22
  `)
23
23
  .run(sessionId, messageSeq ?? null, source, model, inputTokens, outputTokens, totalTokens, costMicros, new Date().toISOString(), pilActive ? 1 : 0, enrichmentDelta, cacheReadTokens, cacheCreationTokens, providerOptionsShape);
24
24
  }
@@ -26,10 +26,10 @@ export function getSessionTotalTokens(sessionId) {
26
26
  const chain = getSessionChain(sessionId);
27
27
  const placeholders = chain.map(() => "?").join(",");
28
28
  const row = getDatabase()
29
- .prepare(`
30
- SELECT COALESCE(SUM(total_tokens), 0) AS total_tokens
31
- FROM usage_events
32
- WHERE session_id IN (${placeholders})
29
+ .prepare(`
30
+ SELECT COALESCE(SUM(total_tokens), 0) AS total_tokens
31
+ FROM usage_events
32
+ WHERE session_id IN (${placeholders})
33
33
  `)
34
34
  .get(...chain);
35
35
  const total = row?.total_tokens ?? 0;
@@ -44,11 +44,11 @@ export function listSessionUsage(sessionId) {
44
44
  const chain = getSessionChain(sessionId);
45
45
  const placeholders = chain.map(() => "?").join(",");
46
46
  const rows = getDatabase()
47
- .prepare(`
48
- SELECT id, session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at, cache_read_tokens, cache_creation_tokens
49
- FROM usage_events
50
- WHERE session_id IN (${placeholders})
51
- ORDER BY id ASC
47
+ .prepare(`
48
+ SELECT id, session_id, message_seq, source, model, input_tokens, output_tokens, total_tokens, cost_micros, created_at, cache_read_tokens, cache_creation_tokens
49
+ FROM usage_events
50
+ WHERE session_id IN (${placeholders})
51
+ ORDER BY id ASC
52
52
  `)
53
53
  .all(...chain);
54
54
  logger.debug("storage", "Retrieved session usage events from chain", {