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
@@ -1,6 +1,29 @@
1
+ import * as os from "node:os";
1
2
  import { classifyEeError, logEeFailure } from "../utils/ee-logger.js";
3
+ import { redactor } from "../utils/redactor.js";
2
4
  import { drainQueue, enqueue } from "./offline-queue.js";
3
5
  const DEFAULT_BASE = "http://localhost:8082";
6
+ function relativizePath(p) {
7
+ if (!p)
8
+ return p;
9
+ let normalized = p.replace(/\\/g, "/");
10
+ const home = os.homedir().replace(/\\/g, "/");
11
+ const normalizedHome = home.endsWith("/") ? home.slice(0, -1) : home;
12
+ if (normalized.startsWith(normalizedHome)) {
13
+ normalized = "~" + normalized.slice(normalizedHome.length);
14
+ }
15
+ return normalized;
16
+ }
17
+ function redactPayload(payload) {
18
+ if (!payload)
19
+ return payload;
20
+ try {
21
+ return JSON.parse(redactor.redact(JSON.stringify(payload)));
22
+ }
23
+ catch {
24
+ return payload;
25
+ }
26
+ }
4
27
  /**
5
28
  * Intercept timeout budget.
6
29
  * Local: 100ms (localhost p99 is <10ms, 100ms catches wedged server).
@@ -195,8 +218,12 @@ export function createEEClient(opts = {}) {
195
218
  }
196
219
  },
197
220
  async intercept(req) {
221
+ const redactedReq = {
222
+ ...req,
223
+ cwd: relativizePath(req.cwd),
224
+ };
198
225
  // 1. Cache hit — skip network entirely
199
- const cached = getCached(req);
226
+ const cached = getCached(redactedReq);
200
227
  if (cached)
201
228
  return cached;
202
229
  // 2. Circuit breaker — skip if open
@@ -207,7 +234,7 @@ export function createEEClient(opts = {}) {
207
234
  const resp = await f(`${baseUrl}/api/intercept`, {
208
235
  method: "POST",
209
236
  headers: headers(),
210
- body: JSON.stringify({ ...req, skipRoute: true }),
237
+ body: JSON.stringify(redactPayload({ ...redactedReq, skipRoute: true })),
211
238
  signal: AbortSignal.timeout(interceptTimeoutMs),
212
239
  });
213
240
  if (!resp.ok) {
@@ -221,7 +248,7 @@ export function createEEClient(opts = {}) {
221
248
  const raw = (await resp.json());
222
249
  const result = normalizeInterceptResponse(raw);
223
250
  recordCircuitSuccess({ fetchImpl: f, headers: headers(), baseUrl });
224
- setCached(req, result);
251
+ setCached(redactedReq, result);
225
252
  return result;
226
253
  }
227
254
  catch (err) {
@@ -231,10 +258,14 @@ export function createEEClient(opts = {}) {
231
258
  }
232
259
  },
233
260
  async posttool(payload) {
261
+ const redactedPayload = {
262
+ ...payload,
263
+ cwd: relativizePath(payload.cwd),
264
+ };
234
265
  await f(`${baseUrl}/api/posttool`, {
235
266
  method: "POST",
236
267
  headers: headers(),
237
- body: JSON.stringify(payload),
268
+ body: JSON.stringify(redactPayload(redactedPayload)),
238
269
  signal: AbortSignal.timeout(postToolTimeoutMs),
239
270
  }).catch((err) => {
240
271
  logEeFailure("client.posttool", classifyEeError(err), err);
@@ -243,6 +274,10 @@ export function createEEClient(opts = {}) {
243
274
  },
244
275
  async routeModel(req, signal) {
245
276
  try {
277
+ const redactedReq = {
278
+ ...req,
279
+ cwd: relativizePath(req.cwd),
280
+ };
246
281
  const ctrl = new AbortController();
247
282
  const t = setTimeout(() => ctrl.abort(), 250);
248
283
  if (signal)
@@ -250,7 +285,7 @@ export function createEEClient(opts = {}) {
250
285
  const resp = await f(`${baseUrl}/api/route-model`, {
251
286
  method: "POST",
252
287
  headers: headers(),
253
- body: JSON.stringify(req),
288
+ body: JSON.stringify(redactPayload(redactedReq)),
254
289
  signal: ctrl.signal,
255
290
  });
256
291
  clearTimeout(t);
@@ -264,6 +299,10 @@ export function createEEClient(opts = {}) {
264
299
  },
265
300
  async coldRoute(req, signal) {
266
301
  try {
302
+ const redactedReq = {
303
+ ...req,
304
+ cwd: relativizePath(req.cwd),
305
+ };
267
306
  const ctrl = new AbortController();
268
307
  const t = setTimeout(() => ctrl.abort(), 1000);
269
308
  if (signal)
@@ -271,7 +310,7 @@ export function createEEClient(opts = {}) {
271
310
  const resp = await f(`${baseUrl}/api/cold-route`, {
272
311
  method: "POST",
273
312
  headers: headers(),
274
- body: JSON.stringify(req),
313
+ body: JSON.stringify(redactPayload(redactedReq)),
275
314
  signal: ctrl.signal,
276
315
  });
277
316
  clearTimeout(t);
@@ -284,13 +323,14 @@ export function createEEClient(opts = {}) {
284
323
  }
285
324
  },
286
325
  feedback(payload) {
326
+ const redactedPayload = redactPayload(payload);
287
327
  f(`${baseUrl}/api/feedback`, {
288
328
  method: "POST",
289
329
  headers: headers(),
290
- body: JSON.stringify(payload),
330
+ body: JSON.stringify(redactedPayload),
291
331
  }).catch((err) => {
292
332
  logEeFailure("client.feedback", classifyEeError(err), err);
293
- void enqueue({ endpoint: "/api/feedback", body: payload, enqueuedAt: Date.now() });
333
+ void enqueue({ endpoint: "/api/feedback", body: redactedPayload, enqueuedAt: Date.now() });
294
334
  });
295
335
  },
296
336
  /**
@@ -300,7 +340,7 @@ export function createEEClient(opts = {}) {
300
340
  * stale_rule). Fire-and-forget; queued offline like standard feedback.
301
341
  */
302
342
  noiseFeedback(payload) {
303
- const body = { ...payload, verdict: "IRRELEVANT" };
343
+ const body = redactPayload({ ...payload, verdict: "IRRELEVANT" });
304
344
  f(`${baseUrl}/api/feedback`, {
305
345
  method: "POST",
306
346
  headers: headers(),
@@ -322,10 +362,11 @@ export function createEEClient(opts = {}) {
322
362
  },
323
363
  // ─── P0: Route feedback (fire-and-forget) ─────────────────────────────────
324
364
  routeFeedback(payload) {
365
+ const redactedPayload = redactPayload(payload);
325
366
  f(`${baseUrl}/api/route-feedback`, {
326
367
  method: "POST",
327
368
  headers: headers(),
328
- body: JSON.stringify(payload),
369
+ body: JSON.stringify(redactedPayload),
329
370
  }).catch((err) => {
330
371
  logEeFailure("client.routeFeedback", classifyEeError(err), err);
331
372
  /* fire-and-forget */
@@ -333,41 +374,54 @@ export function createEEClient(opts = {}) {
333
374
  },
334
375
  // ─── P1: Prompt-stale reconciliation ──────────────────────────────────────
335
376
  async promptStale(req) {
377
+ const redactedReq = redactPayload({
378
+ ...req,
379
+ nextPromptMeta: req.nextPromptMeta
380
+ ? {
381
+ ...req.nextPromptMeta,
382
+ cwd: req.nextPromptMeta.cwd ? relativizePath(req.nextPromptMeta.cwd) : undefined,
383
+ }
384
+ : undefined,
385
+ });
336
386
  try {
337
387
  const resp = await f(`${baseUrl}/api/prompt-stale`, {
338
388
  method: "POST",
339
389
  headers: headers(),
340
- body: JSON.stringify(req),
390
+ body: JSON.stringify(redactedReq),
341
391
  signal: AbortSignal.timeout(2000),
342
392
  });
343
393
  if (!resp.ok) {
344
- void enqueue({ endpoint: "/api/prompt-stale", body: req, enqueuedAt: Date.now() });
394
+ void enqueue({ endpoint: "/api/prompt-stale", body: redactedReq, enqueuedAt: Date.now() });
345
395
  return null;
346
396
  }
347
397
  return (await resp.json());
348
398
  }
349
399
  catch {
350
- void enqueue({ endpoint: "/api/prompt-stale", body: req, enqueuedAt: Date.now() });
400
+ void enqueue({ endpoint: "/api/prompt-stale", body: redactedReq, enqueuedAt: Date.now() });
351
401
  return null;
352
402
  }
353
403
  },
354
404
  // ─── P1: Session extract ──────────────────────────────────────────────────
355
405
  async extract(req, signal) {
406
+ const redactedReq = redactPayload({
407
+ ...req,
408
+ projectPath: relativizePath(req.projectPath),
409
+ });
356
410
  try {
357
411
  const resp = await f(`${baseUrl}/api/extract`, {
358
412
  method: "POST",
359
413
  headers: headers(),
360
- body: JSON.stringify(req),
414
+ body: JSON.stringify(redactedReq),
361
415
  signal: signal ?? AbortSignal.timeout(10_000),
362
416
  });
363
417
  if (!resp.ok) {
364
- void enqueue({ endpoint: "/api/extract", body: req, enqueuedAt: Date.now() });
418
+ void enqueue({ endpoint: "/api/extract", body: redactedReq, enqueuedAt: Date.now() });
365
419
  return null;
366
420
  }
367
421
  return (await resp.json());
368
422
  }
369
423
  catch {
370
- void enqueue({ endpoint: "/api/extract", body: req, enqueuedAt: Date.now() });
424
+ void enqueue({ endpoint: "/api/extract", body: redactedReq, enqueuedAt: Date.now() });
371
425
  return null;
372
426
  }
373
427
  },
@@ -527,11 +581,18 @@ export function createEEClient(opts = {}) {
527
581
  async recall(query, opts = {}) {
528
582
  const body = { query };
529
583
  if (opts.cwd)
530
- body.cwd = opts.cwd;
584
+ body.cwd = relativizePath(opts.cwd);
531
585
  if (opts.project)
532
586
  body.project_slug = opts.project;
533
587
  if (opts.sourceSession)
534
588
  body.sourceSession = opts.sourceSession;
589
+ // Per-stance recall weighting (item 3): forward the council stance/role so
590
+ // the server weights recall collections toward what this stance cares about.
591
+ if (opts.stance)
592
+ body.stance = opts.stance;
593
+ if (opts.role)
594
+ body.role = opts.role;
595
+ const redactedBody = redactPayload(body);
535
596
  // Server bounds the recall pipeline at ~8s internally (handleRecall's
536
597
  // AbortSignal.timeout(8000)); embedding + 3-leg search + network push real
537
598
  // wall-time past that (measured ~9.3s on a warm VPS). An 8s client ceiling
@@ -542,7 +603,7 @@ export function createEEClient(opts = {}) {
542
603
  const resp = await f(`${baseUrl}/api/recall`, {
543
604
  method: "POST",
544
605
  headers: headers(),
545
- body: JSON.stringify(body),
606
+ body: JSON.stringify(redactedBody),
546
607
  signal: opts.signal ?? AbortSignal.timeout(timeoutMs),
547
608
  });
548
609
  if (!resp.ok)
@@ -588,6 +649,8 @@ export function createEEClient(opts = {}) {
588
649
  body.maxTokens = options.maxTokens;
589
650
  if (options.provider)
590
651
  body.provider = options.provider;
652
+ if (options.useExtractModel)
653
+ body.useExtractModel = true;
591
654
  }
592
655
  const resp = await f(`${baseUrl}/api/brain`, {
593
656
  method: "POST",
@@ -15,6 +15,7 @@ export interface ExportOptions {
15
15
  dryRun?: boolean;
16
16
  /** Minimum messages per session to bother emitting (default 4 — skip noise). */
17
17
  minMessages?: number;
18
+ dbOverride?: any;
18
19
  }
19
20
  export interface ExportResult {
20
21
  totalSessions: number;
@@ -10,9 +10,7 @@
10
10
  * recover lessons from sessions that pre-date the transcript-emit feature.
11
11
  * Idempotent: re-running overwrites the same per-session JSONL.
12
12
  */
13
- import fs from "node:fs";
14
- import os from "node:os";
15
- import path from "node:path";
13
+ import { getDatabase } from "../storage/db.js";
16
14
  import { emitTranscriptToDisk, getEmitRoot } from "./transcript-emit.js";
17
15
  async function openDb(dbPath) {
18
16
  // Prefer better-sqlite3 (sync), fall back to bun:sqlite when running under Bun.
@@ -52,17 +50,15 @@ export async function exportTranscripts(opts = {}) {
52
50
  const maxAgeDays = opts.maxAgeDays ?? 30;
53
51
  const minMessages = opts.minMessages ?? 4;
54
52
  const dryRun = opts.dryRun ?? false;
55
- const dbPath = path.join(os.homedir(), ".muonroi-cli", "muonroi.db");
56
- if (!fs.existsSync(dbPath)) {
57
- throw new Error(`muonroi.db not found at ${dbPath}`);
58
- }
59
- const db = await openDb(dbPath);
53
+ const db = opts.dbOverride ?? getDatabase();
60
54
  try {
61
55
  const cutoff = Date.now() - maxAgeDays * 86400_000;
62
56
  const cutoffIso = new Date(cutoff).toISOString();
63
57
  // Pull sessions touched in window. cwd_last is the cwd at session-end —
64
58
  // critical for EE scope detection so framework/lang resolve correctly.
65
- const sessions = db.all(`SELECT id, updated_at, cwd_last FROM sessions WHERE updated_at >= '${cutoffIso}' ORDER BY updated_at DESC`);
59
+ const sessions = db
60
+ .prepare(`SELECT id, updated_at, cwd_last FROM sessions WHERE updated_at >= '${cutoffIso}' ORDER BY updated_at DESC`)
61
+ .all();
66
62
  const out = {
67
63
  totalSessions: sessions.length,
68
64
  written: 0,
@@ -71,7 +67,9 @@ export async function exportTranscripts(opts = {}) {
71
67
  outputRoot: getEmitRoot(),
72
68
  };
73
69
  for (const s of sessions) {
74
- const rows = db.all(`SELECT session_id, seq, role, message_json FROM messages WHERE session_id = '${s.id.replace(/'/g, "''")}' ORDER BY seq ASC`);
70
+ const rows = db
71
+ .prepare(`SELECT session_id, seq, role, message_json FROM messages WHERE session_id = '${s.id.replace(/'/g, "''")}' ORDER BY seq ASC`)
72
+ .all();
75
73
  if (rows.length === 0) {
76
74
  out.skippedEmpty++;
77
75
  continue;
@@ -47,9 +47,38 @@ export async function extractSession(messages, projectPath, source, sessionId) {
47
47
  getDefaultEEClient()
48
48
  .evolve("post-extract")
49
49
  .catch(() => { });
50
+ // WRITE arm of the who-am-i loop — fire-and-forget. Mine the user's working style from
51
+ // this transcript and persist it to experience-behavioral, which who-am-i-brain reads
52
+ // back next session (READ arm). Deliberately NOT awaited: the classify is a ~9s brain
53
+ // call and must not block cli-exit (same rationale as the async extract). It completes on
54
+ // cli-clear (process stays alive) and is best-effort on cli-exit — style converges over
55
+ // sessions, so a missed teardown is harmless. Fail-open, gated behind its own flag.
56
+ void writeStyleSignalsFireAndForget(transcript);
50
57
  }
51
58
  catch {
52
59
  // D-05: swallow all errors silently
53
60
  }
54
61
  }
62
+ /**
63
+ * Fire-and-forget bridge from extractSession into the style WRITE arm. Kept separate so the
64
+ * bridge/search imports stay lazy (only paid when a real session ends) and so every failure
65
+ * mode — flag off, EE unreachable, classifier null, write error — degrades to a no-op.
66
+ */
67
+ async function writeStyleSignalsFireAndForget(transcript) {
68
+ try {
69
+ const { isStyleExtractEnabled, writeStyleSignals } = await import("./extract-style.js");
70
+ if (!isStyleExtractEnabled())
71
+ return;
72
+ const { classifyViaBrain } = await import("./bridge.js");
73
+ const { writeExperienceEE } = await import("./search.js");
74
+ // No projectSlug: working style is a cross-repo property of the user, so style rules are
75
+ // written GLOBAL (unscoped) — who-am-i-brain searches experience-behavioral broadly and a
76
+ // repo-scoped style rule would be needlessly narrow. (Contrast the technical-lesson extract,
77
+ // which IS repo-scoped because a bug fix is repo-specific.)
78
+ await writeStyleSignals({ classifyViaBrain, writeExperience: writeExperienceEE }, transcript);
79
+ }
80
+ catch {
81
+ // swallow — style extraction is strictly best-effort
82
+ }
83
+ }
55
84
  //# sourceMappingURL=extract-session.js.map
@@ -0,0 +1,58 @@
1
+ import type { WriteExperienceResult } from "./search.js";
2
+ /** Feature flag — default ON, opt out with MUONROI_STYLE_EXTRACT=0. */
3
+ export declare function isStyleExtractEnabled(): boolean;
4
+ /**
5
+ * PURE: build the style-mining prompt. Asks the brain to emit 0..N natural-language style
6
+ * rules about the USER (never the task), each standalone and reusable as future guidance,
7
+ * with a self-reported confidence. Emitting NOTHING when the transcript shows no clear style
8
+ * is explicitly the right answer — we would rather miss a session than pollute the brain.
9
+ */
10
+ export declare function buildStyleExtractPrompt(transcript: string): string;
11
+ export interface StyleRule {
12
+ rule: string;
13
+ confidence: number;
14
+ }
15
+ /**
16
+ * PURE: coerce a brain reply (JSON string, fenced block, or already-parsed object) into a
17
+ * gated list of style rules. Applies the confidence floor, length bounds, dedup by normalized
18
+ * text, and the per-session cap. Returns [] when nothing usable survives (fail-open).
19
+ */
20
+ export declare function parseStyleRules(raw: unknown): StyleRule[];
21
+ /**
22
+ * PURE: a stable title for a style rule so repeated sessions MERGE server-side instead of
23
+ * accreting near-duplicates. Derived deterministically from the rule text (lowercased, first
24
+ * few significant words) — same recurring preference → same title → storeImportedExperience
25
+ * can collapse them. Marked with a "user-style:" prefix so the entries are identifiable and
26
+ * prunable as a class.
27
+ */
28
+ export declare function styleRuleTitle(rule: string): string;
29
+ export interface StyleExtractDeps {
30
+ classifyViaBrain: (prompt: string, timeoutMs?: number, options?: {
31
+ systemPrompt?: string;
32
+ responseFormat?: {
33
+ type: string;
34
+ };
35
+ maxTokens?: number;
36
+ useExtractModel?: boolean;
37
+ }) => Promise<string | null>;
38
+ writeExperience: (lesson: string, opts: {
39
+ collection?: string;
40
+ title?: string;
41
+ projectSlug?: string;
42
+ confidence?: number;
43
+ }) => Promise<WriteExperienceResult>;
44
+ }
45
+ /**
46
+ * Classify the transcript into gated style rules. Fail-open []: a degraded brain must never
47
+ * break session teardown.
48
+ */
49
+ export declare function extractStyleSignals(deps: StyleExtractDeps, transcript: string): Promise<StyleRule[]>;
50
+ /**
51
+ * End-to-end WRITE arm: mine style rules from the transcript and persist each to
52
+ * experience-behavioral. Returns the number written. Fire-and-forget from extractSession —
53
+ * fail-open, never throws. `projectSlug` scopes the rule; confidence carries through so the
54
+ * brain can weight it.
55
+ */
56
+ export declare function writeStyleSignals(deps: StyleExtractDeps, transcript: string, opts?: {
57
+ projectSlug?: string;
58
+ }): Promise<number>;
@@ -0,0 +1,270 @@
1
+ // src/ee/extract-style.ts
2
+ //
3
+ // Personality / working-style extraction — the WRITE arm that CLOSES the who-am-i loop.
4
+ //
5
+ // The READ arm (who-am-i-brain.ts) derives a WhoAmIProfile from the `experience-behavioral`
6
+ // brain: it searches the user's accumulated style rules and classifies them into dims that
7
+ // the PIL layers read. But on a thin-client NOTHING was feeding that collection with style
8
+ // signals mined from the user's OWN muonroi-cli sessions — the general server extract
9
+ // (`extractFromSession`) only mines TECHNICAL mistakes/lessons (detectExperience → extractQA),
10
+ // never "the user prefers concise answers / rejects hand-holding / decides fast". So the loop
11
+ // was open: who-am-i could only read rules the user hand-authored or the Claude Code Stop hook
12
+ // happened to capture.
13
+ //
14
+ // This module runs at session-end (alongside extractSession) and mines the transcript for the
15
+ // USER's working-style, writing each high-confidence signal as a natural-language behavioral
16
+ // rule into `experience-behavioral` via writeExperienceEE. Next session, who-am-i-brain reads
17
+ // those rules back and classifies them into dims → the loop is closed.
18
+ //
19
+ // Design guarantees:
20
+ // • Agent-first (no keyword regex): the transcript→style mapping is decided by the brain LLM
21
+ // (classifyViaBrain), honouring the repo rule that classification is never regex. The only
22
+ // regex here is tolerant JSON extraction from the LLM reply.
23
+ // • Natural-language interface (NOT a shared enum): the WRITE side emits plain style
24
+ // sentences; the READ side (who-am-i-brain) re-classifies them with its own DIM_VOCAB.
25
+ // Neither side imports the other's vocabulary — so there is no cross-module enum coupling
26
+ // to drift (contrast the EE-side DIM_VOCAB lockstep this deliberately avoids).
27
+ // • Anti-pollution: experience-behavioral also drives passive hint injection, so a wrong or
28
+ // low-confidence guess is actively harmful (it feeds who-am-i AND every passive hint). We
29
+ // gate HARD — high confidence floor, length bounds, a small per-session cap, and a stable
30
+ // per-signal title so repeated sessions MERGE instead of accreting near-duplicates.
31
+ // • Fail-open: any gap (classifier null, unparseable output, dep throws, EE down) writes
32
+ // nothing and never throws. Style converges over many sessions; missing one is harmless.
33
+ /** The collection who-am-i-brain reads back — keep in lockstep with BEHAVIORAL_COLLECTION there. */
34
+ const BEHAVIORAL_COLLECTION = "experience-behavioral";
35
+ /**
36
+ * Only signals at/above this confidence are written. High on purpose: a style rule that lands
37
+ * in experience-behavioral influences who-am-i AND passive hints, so a confident-but-wrong
38
+ * guess is worse than silence. The brain self-reports confidence per the prompt contract.
39
+ */
40
+ const STYLE_WRITE_MIN_CONFIDENCE = 0.7;
41
+ /** At most this many style rules per session — style is slow-moving; a burst is almost always noise. */
42
+ const MAX_STYLE_RULES_PER_SESSION = 3;
43
+ /** A style rule shorter than this is too vague to guide anything; longer than this is task prose leaking in. */
44
+ const MIN_RULE_CHARS = 15;
45
+ const MAX_RULE_CHARS = 240;
46
+ /**
47
+ * Off the hot path (fire-and-forget at session-end), so a wide budget. The server's strong
48
+ * brainExtractModel is a reasoning model (deepseek-v4-flash) whose think+emit cycle runs
49
+ * ~4-10s on this transcript-sized prompt (verified live). 20s clears the tail; it never blocks
50
+ * anything (background). Mirrors who-am-i-brain's budget.
51
+ */
52
+ const STYLE_CLASSIFY_TIMEOUT_MS = 20000;
53
+ /**
54
+ * The rules JSON itself is tiny (~150 tokens), but the server's extract model
55
+ * (deepseek-v4-flash) is a REASONING model — its thinking tokens count against this same
56
+ * budget and land in a separate reasoning_content field, NOT the JSON. A tight cap (500) let
57
+ * the reasoning consume the whole budget and truncate the actual JSON to empty → intermittent
58
+ * zero-rule results (verified live: identical input gave 3 rules then 0). Give thinking ample
59
+ * headroom so the JSON always survives; the extra tokens are only spent when the model
60
+ * actually reasons, and this is an off-hot-path background call.
61
+ */
62
+ const STYLE_CLASSIFY_MAX_TOKENS = 3000;
63
+ /**
64
+ * System-prompt override — REQUIRED, same reason as who-am-i-brain: the EE brain proxy's
65
+ * default system prompt is a tier-classifier ("output ONE word … ignore content") that
66
+ * hijacks structured output into garbage. Verified on the live VPS (2026-07-05).
67
+ */
68
+ const STYLE_SYSTEM_PROMPT = "You mine a developer's WORKING STYLE from a session transcript — how they prefer to " +
69
+ "communicate, decide, delegate, receive feedback, and handle risk. Follow the user " +
70
+ "message instructions EXACTLY and output ONLY the requested JSON object. Do not classify " +
71
+ "task complexity, do not output single words, do not add prose before or after the JSON.";
72
+ /** Feature flag — default ON, opt out with MUONROI_STYLE_EXTRACT=0. */
73
+ export function isStyleExtractEnabled() {
74
+ return process.env.MUONROI_STYLE_EXTRACT !== "0";
75
+ }
76
+ /**
77
+ * PURE: build the style-mining prompt. Asks the brain to emit 0..N natural-language style
78
+ * rules about the USER (never the task), each standalone and reusable as future guidance,
79
+ * with a self-reported confidence. Emitting NOTHING when the transcript shows no clear style
80
+ * is explicitly the right answer — we would rather miss a session than pollute the brain.
81
+ */
82
+ export function buildStyleExtractPrompt(transcript) {
83
+ return [
84
+ "From the session transcript below, extract DURABLE signals about the DEVELOPER's working",
85
+ "style — not the task, not the code. Look for how they prefer to communicate (concise vs",
86
+ "detailed), decide (fast/intuitive vs deliberate), delegate (autonomous vs collaborative),",
87
+ "receive feedback (blunt correction vs gentle), and tolerate risk.",
88
+ "",
89
+ "Output ONLY a JSON object of the form:",
90
+ '{"rules": [{"rule": "<one imperative sentence of durable style guidance>", "confidence": 0.0-1.0}]}',
91
+ "",
92
+ "Rules:",
93
+ '- Each `rule` must be a standalone, reusable instruction (e.g. "The user prefers concise',
94
+ ' answers — skip preamble and lead with the recommendation."). NOT a fact about this task.',
95
+ "- Emit a signal ONLY when the transcript gives clear, repeated evidence. When in doubt, omit it.",
96
+ "- An EMPTY array is the correct answer for a task-only session with no style signal.",
97
+ "- Never invent a preference the transcript does not actually demonstrate.",
98
+ "- confidence reflects how strongly the transcript supports the rule.",
99
+ "",
100
+ "Transcript:",
101
+ transcript,
102
+ ].join("\n");
103
+ }
104
+ /**
105
+ * PURE: coerce a brain reply (JSON string, fenced block, or already-parsed object) into a
106
+ * gated list of style rules. Applies the confidence floor, length bounds, dedup by normalized
107
+ * text, and the per-session cap. Returns [] when nothing usable survives (fail-open).
108
+ */
109
+ export function parseStyleRules(raw) {
110
+ let obj = raw;
111
+ if (typeof raw === "string") {
112
+ const json = extractJsonObject(raw);
113
+ if (!json)
114
+ return [];
115
+ try {
116
+ obj = JSON.parse(json);
117
+ }
118
+ catch {
119
+ return [];
120
+ }
121
+ }
122
+ if (!obj || typeof obj !== "object")
123
+ return [];
124
+ const arr = obj.rules;
125
+ if (!Array.isArray(arr))
126
+ return [];
127
+ const seen = new Set();
128
+ const out = [];
129
+ for (const item of arr) {
130
+ if (!item || typeof item !== "object")
131
+ continue;
132
+ const rule = typeof item.rule === "string" ? item.rule.trim() : "";
133
+ const confidence = Number(item.confidence);
134
+ if (!rule || !Number.isFinite(confidence))
135
+ continue;
136
+ if (confidence < STYLE_WRITE_MIN_CONFIDENCE)
137
+ continue;
138
+ if (rule.length < MIN_RULE_CHARS || rule.length > MAX_RULE_CHARS)
139
+ continue;
140
+ const norm = rule.toLowerCase().replace(/\s+/g, " ");
141
+ if (seen.has(norm))
142
+ continue;
143
+ seen.add(norm);
144
+ out.push({ rule, confidence });
145
+ if (out.length >= MAX_STYLE_RULES_PER_SESSION)
146
+ break;
147
+ }
148
+ return out;
149
+ }
150
+ /** Tolerantly extract the first balanced JSON object from an LLM reply. */
151
+ function extractJsonObject(text) {
152
+ const start = text.indexOf("{");
153
+ if (start === -1)
154
+ return null;
155
+ let depth = 0;
156
+ let inStr = false;
157
+ let esc = false;
158
+ for (let i = start; i < text.length; i++) {
159
+ const ch = text[i];
160
+ if (inStr) {
161
+ if (esc)
162
+ esc = false;
163
+ else if (ch === "\\")
164
+ esc = true;
165
+ else if (ch === '"')
166
+ inStr = false;
167
+ continue;
168
+ }
169
+ if (ch === '"')
170
+ inStr = true;
171
+ else if (ch === "{")
172
+ depth++;
173
+ else if (ch === "}") {
174
+ depth--;
175
+ if (depth === 0)
176
+ return text.slice(start, i + 1);
177
+ }
178
+ }
179
+ return null;
180
+ }
181
+ /**
182
+ * PURE: a stable title for a style rule so repeated sessions MERGE server-side instead of
183
+ * accreting near-duplicates. Derived deterministically from the rule text (lowercased, first
184
+ * few significant words) — same recurring preference → same title → storeImportedExperience
185
+ * can collapse them. Marked with a "user-style:" prefix so the entries are identifiable and
186
+ * prunable as a class.
187
+ */
188
+ export function styleRuleTitle(rule) {
189
+ const words = rule
190
+ .toLowerCase()
191
+ .replace(/[^a-z0-9\s]/g, " ")
192
+ .split(/\s+/)
193
+ .filter((w) => w.length > 3 && !STOPWORDS.has(w))
194
+ .slice(0, 5)
195
+ .join("-");
196
+ return `user-style:${words || "general"}`;
197
+ }
198
+ const STOPWORDS = new Set([
199
+ "the",
200
+ "user",
201
+ "prefers",
202
+ "wants",
203
+ "with",
204
+ "that",
205
+ "this",
206
+ "they",
207
+ "them",
208
+ "their",
209
+ "when",
210
+ "into",
211
+ "over",
212
+ "from",
213
+ "answers",
214
+ "answer",
215
+ "reply",
216
+ "replies",
217
+ ]);
218
+ /**
219
+ * Classify the transcript into gated style rules. Fail-open []: a degraded brain must never
220
+ * break session teardown.
221
+ */
222
+ export async function extractStyleSignals(deps, transcript) {
223
+ try {
224
+ if (!transcript || transcript.trim().length < 100)
225
+ return [];
226
+ const reply = await deps.classifyViaBrain(buildStyleExtractPrompt(transcript), STYLE_CLASSIFY_TIMEOUT_MS, {
227
+ systemPrompt: STYLE_SYSTEM_PROMPT,
228
+ responseFormat: { type: "json_object" },
229
+ maxTokens: STYLE_CLASSIFY_MAX_TOKENS,
230
+ // Structured multi-signal extraction needs the server's stronger brainExtractModel;
231
+ // the hot-path model is too weak (verified on the live VPS for the READ side too).
232
+ useExtractModel: true,
233
+ });
234
+ if (!reply)
235
+ return [];
236
+ return parseStyleRules(reply);
237
+ }
238
+ catch {
239
+ return [];
240
+ }
241
+ }
242
+ /**
243
+ * End-to-end WRITE arm: mine style rules from the transcript and persist each to
244
+ * experience-behavioral. Returns the number written. Fire-and-forget from extractSession —
245
+ * fail-open, never throws. `projectSlug` scopes the rule; confidence carries through so the
246
+ * brain can weight it.
247
+ */
248
+ export async function writeStyleSignals(deps, transcript, opts = {}) {
249
+ if (!isStyleExtractEnabled())
250
+ return 0;
251
+ const rules = await extractStyleSignals(deps, transcript);
252
+ let written = 0;
253
+ for (const r of rules) {
254
+ try {
255
+ const res = await deps.writeExperience(r.rule, {
256
+ collection: BEHAVIORAL_COLLECTION,
257
+ title: styleRuleTitle(r.rule),
258
+ projectSlug: opts.projectSlug,
259
+ confidence: r.confidence,
260
+ });
261
+ if (res.ok)
262
+ written++;
263
+ }
264
+ catch {
265
+ // fail-open per rule — one bad write must not abort the rest
266
+ }
267
+ }
268
+ return written;
269
+ }
270
+ //# sourceMappingURL=extract-style.js.map