muonroi-cli 1.7.2 → 1.8.1

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 (326) hide show
  1. package/dist/packages/agent-harness-core/src/event-filter.js +1 -0
  2. package/dist/packages/agent-harness-core/src/event-redact.js +8 -0
  3. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +16 -0
  4. package/dist/packages/agent-harness-core/src/mcp-server.js +88 -10
  5. package/dist/packages/agent-harness-core/src/protocol.d.ts +15 -0
  6. package/dist/packages/agent-harness-core/src/selector.js +2 -2
  7. package/dist/packages/agent-harness-core/src/transports/sidechannel.js +1 -1
  8. package/dist/packages/agent-harness-opentui/src/agent-mode.js +1 -1
  9. package/dist/packages/agent-harness-opentui/src/install.js +1 -1
  10. package/dist/src/__test-stubs__/vitest-setup.js +4 -0
  11. package/dist/src/agent-harness/__tests__/mock-model.spec.js +54 -0
  12. package/dist/src/agent-harness/mock-model.d.ts +1 -1
  13. package/dist/src/agent-harness/mock-model.js +143 -6
  14. package/dist/src/agent-harness/test-spawn.js +3 -1
  15. package/dist/src/chat/chat-keychain.js +9 -1
  16. package/dist/src/cli/cost-forensics.js +7 -4
  17. package/dist/src/cli/keys.d.ts +2 -2
  18. package/dist/src/cli/keys.js +107 -28
  19. package/dist/src/cli/usage-report.js +2 -2
  20. package/dist/src/council/__tests__/abort-threading.test.d.ts +1 -0
  21. package/dist/src/council/__tests__/abort-threading.test.js +193 -0
  22. package/dist/src/council/__tests__/clarification-prompt.test.js +21 -1
  23. package/dist/src/council/__tests__/council-turn-length-emit.test.d.ts +1 -0
  24. package/dist/src/council/__tests__/council-turn-length-emit.test.js +130 -0
  25. package/dist/src/council/__tests__/debate-round-budget.test.d.ts +1 -0
  26. package/dist/src/council/__tests__/debate-round-budget.test.js +45 -0
  27. package/dist/src/council/__tests__/evaluator-metrics.test.js +3 -0
  28. package/dist/src/council/__tests__/post-debate-recommendation.test.d.ts +1 -0
  29. package/dist/src/council/__tests__/post-debate-recommendation.test.js +58 -0
  30. package/dist/src/council/__tests__/research-tools.test.js +4 -0
  31. package/dist/src/council/__tests__/round-tools.test.js +6 -0
  32. package/dist/src/council/clarifier-question-cap.test.d.ts +12 -0
  33. package/dist/src/council/clarifier-question-cap.test.js +73 -0
  34. package/dist/src/council/clarifier.d.ts +29 -1
  35. package/dist/src/council/clarifier.js +64 -1
  36. package/dist/src/council/debate-planner.d.ts +2 -1
  37. package/dist/src/council/debate-planner.js +5 -3
  38. package/dist/src/council/debate.d.ts +9 -0
  39. package/dist/src/council/debate.js +88 -8
  40. package/dist/src/council/index.d.ts +46 -1
  41. package/dist/src/council/index.js +125 -19
  42. package/dist/src/council/llm.js +41 -13
  43. package/dist/src/council/prompts.js +36 -1
  44. package/dist/src/council/types.d.ts +14 -1
  45. package/dist/src/ee/__tests__/export-transcripts.test.js +1 -1
  46. package/dist/src/ee/bridge.d.ts +3 -1
  47. package/dist/src/ee/bridge.js +9 -3
  48. package/dist/src/ee/bridge.test.js +1 -2
  49. package/dist/src/ee/client.js +15 -2
  50. package/dist/src/ee/recall-ledger.d.ts +20 -0
  51. package/dist/src/ee/recall-ledger.js +40 -1
  52. package/dist/src/ee/search.d.ts +25 -0
  53. package/dist/src/ee/search.js +73 -0
  54. package/dist/src/ee/types.d.ts +15 -1
  55. package/dist/src/ee/who-am-i.d.ts +41 -0
  56. package/dist/src/ee/who-am-i.js +143 -0
  57. package/dist/src/ee/who-am-i.test.d.ts +1 -0
  58. package/dist/src/ee/who-am-i.test.js +101 -0
  59. package/dist/src/flow/compaction/index.d.ts +1 -0
  60. package/dist/src/flow/compaction/index.js +4 -0
  61. package/dist/src/generated/version.d.ts +1 -1
  62. package/dist/src/generated/version.js +1 -1
  63. package/dist/src/headless/council-answers.js +1 -0
  64. package/dist/src/headless/output.d.ts +30 -1
  65. package/dist/src/headless/output.js +180 -0
  66. package/dist/src/headless/output.test.js +61 -1
  67. package/dist/src/hooks/index.js +48 -2
  68. package/dist/src/index.d.ts +2 -0
  69. package/dist/src/index.js +59 -62
  70. package/dist/src/lsp/client-normalize.test.d.ts +12 -0
  71. package/dist/src/lsp/client-normalize.test.js +34 -0
  72. package/dist/src/lsp/client.d.ts +1 -0
  73. package/dist/src/lsp/client.js +10 -2
  74. package/dist/src/lsp/manager.d.ts +1 -1
  75. package/dist/src/lsp/manager.js +13 -5
  76. package/dist/src/lsp/manager.test.js +41 -2
  77. package/dist/src/lsp/runtime.d.ts +1 -1
  78. package/dist/src/lsp/runtime.js +2 -2
  79. package/dist/src/maintain/__tests__/gh-create-pr.test.js +7 -3
  80. package/dist/src/maintain/__tests__/pr-builder.test.js +7 -3
  81. package/dist/src/mcp/__tests__/client-pool.spec.js +3 -3
  82. package/dist/src/mcp/__tests__/ee-tools.test.js +42 -14
  83. package/dist/src/mcp/__tests__/forensics-tools.test.js +3 -3
  84. package/dist/src/mcp/__tests__/lsp-tools.test.js +4 -4
  85. package/dist/src/mcp/auto-setup.js +0 -8
  86. package/dist/src/mcp/client-pool.d.ts +1 -1
  87. package/dist/src/mcp/client-pool.js +25 -9
  88. package/dist/src/mcp/ee-tools.d.ts +10 -0
  89. package/dist/src/mcp/ee-tools.js +34 -0
  90. package/dist/src/mcp/self-verify-jobs.d.ts +1 -0
  91. package/dist/src/mcp/self-verify-jobs.js +1 -3
  92. package/dist/src/mcp/self-verify-runner.js +1 -1
  93. package/dist/src/models/catalog-gemini.test.js +12 -10
  94. package/dist/src/models/catalog.json +106 -38
  95. package/dist/src/orchestrator/__tests__/auto-commit.test.d.ts +1 -0
  96. package/dist/src/orchestrator/__tests__/auto-commit.test.js +142 -0
  97. package/dist/src/orchestrator/__tests__/batch-turn-runner.test.js +3 -0
  98. package/dist/src/orchestrator/__tests__/delegations.test.d.ts +1 -0
  99. package/dist/src/orchestrator/__tests__/delegations.test.js +96 -0
  100. package/dist/src/orchestrator/__tests__/message-processor.test.js +2 -0
  101. package/dist/src/orchestrator/__tests__/prompts.test.d.ts +1 -0
  102. package/dist/src/orchestrator/__tests__/prompts.test.js +88 -0
  103. package/dist/src/orchestrator/__tests__/stream-runner.test.js +29 -0
  104. package/dist/src/orchestrator/__tests__/sub-session-delegation.test.d.ts +1 -0
  105. package/dist/src/orchestrator/__tests__/sub-session-delegation.test.js +507 -0
  106. package/dist/src/orchestrator/agent.test.js +5 -2
  107. package/dist/src/orchestrator/auto-commit.d.ts +110 -0
  108. package/dist/src/orchestrator/auto-commit.js +366 -0
  109. package/dist/src/orchestrator/batch-turn-runner.d.ts +3 -2
  110. package/dist/src/orchestrator/batch-turn-runner.js +2 -1
  111. package/dist/src/orchestrator/compaction-proposer-prompt.d.ts +8 -0
  112. package/dist/src/orchestrator/compaction-proposer-prompt.js +43 -0
  113. package/dist/src/orchestrator/compaction.d.ts +22 -0
  114. package/dist/src/orchestrator/compaction.js +42 -0
  115. package/dist/src/orchestrator/delegations.d.ts +1 -0
  116. package/dist/src/orchestrator/delegations.js +41 -0
  117. package/dist/src/orchestrator/error-utils.js +27 -2
  118. package/dist/src/orchestrator/message-processor.d.ts +23 -5
  119. package/dist/src/orchestrator/message-processor.js +226 -2573
  120. package/dist/src/orchestrator/orchestrator.d.ts +11 -2
  121. package/dist/src/orchestrator/orchestrator.js +530 -43
  122. package/dist/src/orchestrator/pending-calls.js +2 -1
  123. package/dist/src/orchestrator/preprocessor.d.ts +13 -0
  124. package/dist/src/orchestrator/preprocessor.js +146 -0
  125. package/dist/src/orchestrator/prompts.d.ts +16 -0
  126. package/dist/src/orchestrator/prompts.js +130 -67
  127. package/dist/src/orchestrator/safety-askcard.d.ts +66 -0
  128. package/dist/src/orchestrator/safety-askcard.js +74 -0
  129. package/dist/src/orchestrator/sandbox.test.js +8 -5
  130. package/dist/src/orchestrator/scope-ceiling.js +1 -1
  131. package/dist/src/orchestrator/stall-watchdog.d.ts +47 -0
  132. package/dist/src/orchestrator/stall-watchdog.js +23 -0
  133. package/dist/src/orchestrator/stall-watchdog.test.js +36 -1
  134. package/dist/src/orchestrator/stream-runner.js +52 -30
  135. package/dist/src/orchestrator/sub-agent-cap.d.ts +2 -0
  136. package/dist/src/orchestrator/sub-agent-cap.js +12 -4
  137. package/dist/src/orchestrator/sub-agent-model-tier.js +1 -1
  138. package/dist/src/orchestrator/subagent-compactor.d.ts +21 -0
  139. package/dist/src/orchestrator/subagent-compactor.js +148 -24
  140. package/dist/src/orchestrator/subagent-compactor.spec.js +249 -1
  141. package/dist/src/orchestrator/text-tool-call-detector.d.ts +9 -5
  142. package/dist/src/orchestrator/text-tool-call-detector.js +16 -12
  143. package/dist/src/orchestrator/text-tool-call-detector.test.js +66 -8
  144. package/dist/src/orchestrator/tool-args-repair.js +1 -1
  145. package/dist/src/orchestrator/tool-engine.d.ts +153 -0
  146. package/dist/src/orchestrator/tool-engine.js +3138 -0
  147. package/dist/src/orchestrator/turn-runner-deps.d.ts +3 -0
  148. package/dist/src/pil/__tests__/discovery-types.test.js +15 -4
  149. package/dist/src/pil/__tests__/discovery.test.js +89 -145
  150. package/dist/src/pil/__tests__/dual-run.test.js +2 -0
  151. package/dist/src/pil/__tests__/layer1-intent-trace.test.js +3 -0
  152. package/dist/src/pil/__tests__/layer1-intent.test.js +3 -0
  153. package/dist/src/pil/__tests__/layer16-clarity.test.js +35 -32
  154. package/dist/src/pil/__tests__/layer18-acceptance.test.js +1 -78
  155. package/dist/src/pil/__tests__/layer2_5-ponytail.test.d.ts +1 -0
  156. package/dist/src/pil/__tests__/layer2_5-ponytail.test.js +53 -0
  157. package/dist/src/pil/__tests__/layer3-ee-injection.test.js +67 -4
  158. package/dist/src/pil/__tests__/layer3-injected-chunk.test.js +14 -2
  159. package/dist/src/pil/__tests__/layer4-gsd.test.js +30 -0
  160. package/dist/src/pil/__tests__/layer5-context.test.js +39 -1
  161. package/dist/src/pil/__tests__/layer6-output.test.js +30 -2
  162. package/dist/src/pil/__tests__/llm-classify.test.js +79 -1
  163. package/dist/src/pil/__tests__/orchestrator-integration.test.js +3 -1
  164. package/dist/src/pil/__tests__/pipeline.test.js +11 -8
  165. package/dist/src/pil/__tests__/response-tools.test.js +52 -0
  166. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  167. package/dist/src/pil/agent-operating-contract.js +5 -3
  168. package/dist/src/pil/agent-operating-contract.test.js +2 -2
  169. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  170. package/dist/src/pil/cheap-model-playbook.js +1 -1
  171. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  172. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  173. package/dist/src/pil/config.d.ts +20 -0
  174. package/dist/src/pil/config.js +35 -0
  175. package/dist/src/pil/discovery-types.d.ts +32 -9
  176. package/dist/src/pil/discovery.d.ts +3 -3
  177. package/dist/src/pil/discovery.js +138 -244
  178. package/dist/src/pil/index.d.ts +1 -1
  179. package/dist/src/pil/index.js +1 -1
  180. package/dist/src/pil/layer1-intent.d.ts +9 -1
  181. package/dist/src/pil/layer1-intent.js +62 -7
  182. package/dist/src/pil/layer1-intent.test.js +112 -2
  183. package/dist/src/pil/layer15-context-scan.js +1 -1
  184. package/dist/src/pil/layer16-clarity.d.ts +21 -25
  185. package/dist/src/pil/layer16-clarity.js +52 -88
  186. package/dist/src/pil/layer18-acceptance.d.ts +13 -3
  187. package/dist/src/pil/layer18-acceptance.js +1 -75
  188. package/dist/src/pil/layer2-personality.js +7 -8
  189. package/dist/src/pil/layer2_5-ponytail.d.ts +2 -0
  190. package/dist/src/pil/layer2_5-ponytail.js +41 -0
  191. package/dist/src/pil/layer3-ee-injection.js +180 -14
  192. package/dist/src/pil/layer4-gsd.js +22 -8
  193. package/dist/src/pil/layer5-context.d.ts +1 -0
  194. package/dist/src/pil/layer5-context.js +26 -11
  195. package/dist/src/pil/layer6-output.js +23 -5
  196. package/dist/src/pil/llm-classify.d.ts +11 -0
  197. package/dist/src/pil/llm-classify.js +196 -3
  198. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  199. package/dist/src/pil/native-capabilities-workbook.js +4 -3
  200. package/dist/src/pil/pipeline.js +15 -1
  201. package/dist/src/pil/response-tools.d.ts +16 -0
  202. package/dist/src/pil/response-tools.js +41 -0
  203. package/dist/src/pil/schema.d.ts +8 -0
  204. package/dist/src/pil/schema.js +24 -3
  205. package/dist/src/pil/task-tier-map.js +7 -7
  206. package/dist/src/pil/types.d.ts +9 -3
  207. package/dist/src/product-loop/__tests__/discovery-interview.test.js +103 -1
  208. package/dist/src/product-loop/__tests__/gather-selectable-alts.test.js +34 -0
  209. package/dist/src/product-loop/__tests__/sprint-self-verify.test.js +12 -12
  210. package/dist/src/product-loop/discovery-interview.d.ts +20 -0
  211. package/dist/src/product-loop/discovery-interview.js +121 -7
  212. package/dist/src/product-loop/gather.js +19 -5
  213. package/dist/src/product-loop/loop-driver.js +2 -2
  214. package/dist/src/product-loop/sprint-self-verify.js +2 -2
  215. package/dist/src/providers/__tests__/reasoning-roundtrip.test.js +12 -0
  216. package/dist/src/providers/auth/__tests__/gemini-oauth.test.d.ts +1 -5
  217. package/dist/src/providers/auth/__tests__/gemini-oauth.test.js +1 -5
  218. package/dist/src/providers/auth/gcloud.d.ts +28 -0
  219. package/dist/src/providers/auth/gcloud.js +102 -0
  220. package/dist/src/providers/auth/gemini-oauth.d.ts +46 -19
  221. package/dist/src/providers/auth/gemini-oauth.js +292 -105
  222. package/dist/src/providers/auth/grok-oauth.d.ts +1 -1
  223. package/dist/src/providers/auth/grok-oauth.js +1 -1
  224. package/dist/src/providers/auth/registry.js +28 -6
  225. package/dist/src/providers/gemini.d.ts +1 -1
  226. package/dist/src/providers/gemini.js +10 -3
  227. package/dist/src/providers/keychain.d.ts +2 -2
  228. package/dist/src/providers/keychain.js +20 -2
  229. package/dist/src/providers/openai.js +5 -1
  230. package/dist/src/providers/runtime.d.ts +1 -1
  231. package/dist/src/providers/runtime.js +11 -2
  232. package/dist/src/providers/siliconflow-sse-repair.js +1 -1
  233. package/dist/src/providers/strategies/google.strategy.d.ts +9 -2
  234. package/dist/src/providers/strategies/google.strategy.js +159 -9
  235. package/dist/src/providers/strategies/thinking-mode.js +19 -6
  236. package/dist/src/providers/types.d.ts +1 -1
  237. package/dist/src/router/decide.test.js +40 -8
  238. package/dist/src/router/step-router.d.ts +20 -0
  239. package/dist/src/router/step-router.js +73 -0
  240. package/dist/src/self-qa/agentic-loop.js +30 -21
  241. package/dist/src/self-qa/orchestrator.js +5 -5
  242. package/dist/src/self-qa/scenario-planner.js +1 -1
  243. package/dist/src/self-qa/spec-emitter.js +4 -4
  244. package/dist/src/storage/__tests__/hierarchical-session.test.d.ts +1 -0
  245. package/dist/src/storage/__tests__/hierarchical-session.test.js +161 -0
  246. package/dist/src/storage/__tests__/sweep-stale-pending.test.js +2 -2
  247. package/dist/src/storage/index.d.ts +1 -1
  248. package/dist/src/storage/index.js +1 -1
  249. package/dist/src/storage/migrations.js +13 -1
  250. package/dist/src/storage/transcript-response-entry.test.js +18 -5
  251. package/dist/src/storage/transcript-view.js +7 -1
  252. package/dist/src/storage/transcript.d.ts +3 -0
  253. package/dist/src/storage/transcript.js +254 -73
  254. package/dist/src/storage/ui-interaction-log.d.ts +17 -0
  255. package/dist/src/storage/usage.js +22 -5
  256. package/dist/src/tools/__tests__/native-tools.test.js +6 -0
  257. package/dist/src/tools/bash.d.ts +36 -23
  258. package/dist/src/tools/bash.js +59 -301
  259. package/dist/src/tools/bash.test.js +2 -257
  260. package/dist/src/tools/file-tracker.d.ts +5 -0
  261. package/dist/src/tools/file-tracker.js +14 -0
  262. package/dist/src/tools/file.js +2 -0
  263. package/dist/src/tools/git-safety.d.ts +38 -1
  264. package/dist/src/tools/git-safety.js +94 -4
  265. package/dist/src/tools/git-safety.test.js +45 -1
  266. package/dist/src/tools/native-tools.d.ts +1 -1
  267. package/dist/src/tools/native-tools.js +66 -1
  268. package/dist/src/tools/registry-bash-empty-command.test.js +4 -3
  269. package/dist/src/tools/registry-git-safety.test.js +17 -6
  270. package/dist/src/tools/registry.d.ts +6 -0
  271. package/dist/src/tools/registry.js +215 -13
  272. package/dist/src/types/index.d.ts +8 -2
  273. package/dist/src/ui/app.d.ts +1 -0
  274. package/dist/src/ui/app.js +0 -0
  275. package/dist/src/ui/components/council-question-card.js +1 -0
  276. package/dist/src/ui/components/message-view.js +37 -3
  277. package/dist/src/ui/components/structured-response-view.js +7 -0
  278. package/dist/src/ui/components/task-list-panel.js +3 -12
  279. package/dist/src/ui/containers/chat-feed.d.ts +40 -0
  280. package/dist/src/ui/containers/chat-feed.js +66 -0
  281. package/dist/src/ui/containers/modals-layer.d.ts +87 -0
  282. package/dist/src/ui/containers/modals-layer.js +18 -0
  283. package/dist/src/ui/slash/__tests__/menu-parity.test.d.ts +1 -0
  284. package/dist/src/ui/slash/__tests__/menu-parity.test.js +1 -0
  285. package/dist/src/ui/slash/__tests__/ponytail.test.d.ts +1 -0
  286. package/dist/src/ui/slash/__tests__/ponytail.test.js +37 -0
  287. package/dist/src/ui/slash/expand.js +14 -1
  288. package/dist/src/ui/slash/export.js +16 -1
  289. package/dist/src/ui/slash/menu-items.js +1 -0
  290. package/dist/src/ui/slash/ponytail.d.ts +2 -0
  291. package/dist/src/ui/slash/ponytail.js +19 -0
  292. package/dist/src/ui/status-bar/store.js +0 -1
  293. package/dist/src/ui/status-bar/store.test.js +2 -2
  294. package/dist/src/ui/use-app-logic.d.ts +26 -0
  295. package/dist/src/ui/use-app-logic.js +0 -0
  296. package/dist/src/ui/utils/relaunch.js +1 -1
  297. package/dist/src/ui/utils/text.d.ts +11 -0
  298. package/dist/src/ui/utils/text.js +21 -1
  299. package/dist/src/ui/utils/text.test.js +25 -1
  300. package/dist/src/ui/utils/tools.js +3 -1
  301. package/dist/src/usage/cost-log.js +2 -2
  302. package/dist/src/usage/estimator.d.ts +14 -0
  303. package/dist/src/usage/estimator.js +22 -0
  304. package/dist/src/utils/__tests__/compaction-caps.test.d.ts +21 -0
  305. package/dist/src/utils/__tests__/compaction-caps.test.js +187 -0
  306. package/dist/src/utils/__tests__/llm-deadline-abort.test.d.ts +1 -0
  307. package/dist/src/utils/__tests__/llm-deadline-abort.test.js +33 -0
  308. package/dist/src/utils/__tests__/llm-deadline.test.js +16 -4
  309. package/dist/src/utils/__tests__/logger.test.d.ts +1 -0
  310. package/dist/src/utils/__tests__/logger.test.js +115 -0
  311. package/dist/src/utils/__tests__/settings-agent-first.test.d.ts +1 -0
  312. package/dist/src/utils/__tests__/settings-agent-first.test.js +48 -0
  313. package/dist/src/utils/install-manager.d.ts +1 -0
  314. package/dist/src/utils/install-manager.js +76 -7
  315. package/dist/src/utils/install-manager.test.js +43 -1
  316. package/dist/src/utils/llm-deadline.d.ts +9 -1
  317. package/dist/src/utils/llm-deadline.js +31 -2
  318. package/dist/src/utils/logger.d.ts +28 -0
  319. package/dist/src/utils/logger.js +171 -0
  320. package/dist/src/utils/permission-mode.d.ts +33 -0
  321. package/dist/src/utils/permission-mode.js +164 -3
  322. package/dist/src/utils/permission-mode.test.js +92 -1
  323. package/dist/src/utils/settings.d.ts +36 -32
  324. package/dist/src/utils/settings.js +151 -123
  325. package/dist/src/utils/update-checker.test.js +5 -1
  326. package/package.json +1 -1
@@ -22,6 +22,8 @@ export interface RecallLedger {
22
22
  record(entries: EERecallEntry[] | undefined, query: string): void;
23
23
  /** Clear one id once it has been rated. Returns true if it was actually pending. */
24
24
  clear(id: string): boolean;
25
+ /** Check if an id was ever cleared (fed back) in this session. Used by PIL Layer 3 to suppress re-injection. */
26
+ wasCleared(id: string): boolean;
25
27
  /** Oldest-first list of still-unrated recalls. */
26
28
  pending(): PendingRecall[];
27
29
  pendingCount(): number;
@@ -30,3 +32,21 @@ export interface RecallLedger {
30
32
  export declare function createRecallLedger(): RecallLedger;
31
33
  /** Process-scoped singleton = the current MCP session's unrated-recall debt. */
32
34
  export declare const sessionRecallLedger: RecallLedger;
35
+ /**
36
+ * Whether the recall-feedback ledger is active. Mirrors the gate env the external
37
+ * MCP ee.query already honours (EXPERIENCE_RECALL_FEEDBACK_GATE) so an operator
38
+ * can disable in-CLI ledger accounting with the same switch. In-CLI we only need
39
+ * on/off — never a hard refusal — so a turn is never blocked. Default on (soft).
40
+ */
41
+ export declare function isRecallLedgerEnabled(): boolean;
42
+ /**
43
+ * Compact, token-bounded reminder of still-unrated surfaced/recalled handles, for
44
+ * injection next to the `[id]` handles the agent already saw. Names the actual
45
+ * `{id, collection}` pairs so an `ee_feedback(id, collection, verdict)` call is
46
+ * actionable — the legacy static nudge named no ids, so the model could not
47
+ * complete the rating even when willing. Capped so a long session can't bloat the
48
+ * prompt (token-thrift).
49
+ */
50
+ export declare function formatPendingReminder(pending: PendingRecall[], opts?: {
51
+ max?: number;
52
+ }): string;
@@ -12,6 +12,8 @@
12
12
  */
13
13
  export function createRecallLedger() {
14
14
  const map = new Map();
15
+ // Tracks ids that have been fed back, so PIL Layer 3 can suppress re-injection.
16
+ const cleared = new Set();
15
17
  return {
16
18
  record(entries, query) {
17
19
  if (!Array.isArray(entries))
@@ -34,7 +36,14 @@ export function createRecallLedger() {
34
36
  }
35
37
  },
36
38
  clear(id) {
37
- return map.delete(String(id ?? "").trim());
39
+ const nid = String(id ?? "").trim();
40
+ const deleted = map.delete(nid);
41
+ if (deleted)
42
+ cleared.add(nid);
43
+ return deleted;
44
+ },
45
+ wasCleared(id) {
46
+ return cleared.has(String(id ?? "").trim());
38
47
  },
39
48
  pending() {
40
49
  return [...map.values()].sort((a, b) => a.ts - b.ts);
@@ -44,9 +53,39 @@ export function createRecallLedger() {
44
53
  },
45
54
  reset() {
46
55
  map.clear();
56
+ cleared.clear();
47
57
  },
48
58
  };
49
59
  }
50
60
  /** Process-scoped singleton = the current MCP session's unrated-recall debt. */
51
61
  export const sessionRecallLedger = createRecallLedger();
62
+ /**
63
+ * Whether the recall-feedback ledger is active. Mirrors the gate env the external
64
+ * MCP ee.query already honours (EXPERIENCE_RECALL_FEEDBACK_GATE) so an operator
65
+ * can disable in-CLI ledger accounting with the same switch. In-CLI we only need
66
+ * on/off — never a hard refusal — so a turn is never blocked. Default on (soft).
67
+ */
68
+ export function isRecallLedgerEnabled() {
69
+ return (String(process.env.EXPERIENCE_RECALL_FEEDBACK_GATE ?? "soft")
70
+ .trim()
71
+ .toLowerCase() !== "off");
72
+ }
73
+ /**
74
+ * Compact, token-bounded reminder of still-unrated surfaced/recalled handles, for
75
+ * injection next to the `[id]` handles the agent already saw. Names the actual
76
+ * `{id, collection}` pairs so an `ee_feedback(id, collection, verdict)` call is
77
+ * actionable — the legacy static nudge named no ids, so the model could not
78
+ * complete the rating even when willing. Capped so a long session can't bloat the
79
+ * prompt (token-thrift).
80
+ */
81
+ export function formatPendingReminder(pending, opts = {}) {
82
+ if (pending.length === 0)
83
+ return "";
84
+ const max = Math.max(1, Math.min(opts.max ?? 5, 20));
85
+ const shown = pending.slice(0, max);
86
+ const lines = shown.map((p) => ` - [${p.id} ${p.collection ?? "?"}]`);
87
+ const more = pending.length > max ? `\n …and ${pending.length - max} more` : "";
88
+ return (`↳ ${pending.length} earlier EE hint(s) still unrated — rate the one(s) you acted on so the brain keeps what helped: ` +
89
+ `ee_feedback(id, collection, followed|ignored|noise).\n${lines.join("\n")}${more}`);
90
+ }
52
91
  //# sourceMappingURL=recall-ledger.js.map
@@ -92,6 +92,31 @@ export declare function feedbackEE(pointId: string, collection: string, verdict:
92
92
  * compute unrated-recall debt as recalled ids minus fed-back ids. Best-effort.
93
93
  */
94
94
  export declare function mirrorFeedbackLocally(pointId: string, collection: string, verdict: string, reason?: string | null, logPath?: string): Promise<void>;
95
+ export interface WriteExperienceResult {
96
+ ok: boolean;
97
+ id?: string;
98
+ error?: string;
99
+ }
100
+ /**
101
+ * Write a NEW experience/lesson into the brain mid-session so it is RECALLABLE.
102
+ * POSTs to /api/import-memory → storeImportedExperience → upsertEntry, which
103
+ * embeds the text AND writes the `text_bm25` sparse vector (+ a proper payload via
104
+ * buildStorePayload). That dense+sparse write is what makes the lesson reliably
105
+ * recallable via ee_query / passive injection (both the dense and lexical legs can
106
+ * match it). NB: /api/ingest-point writes DENSE-ONLY (no sparse) — its points are
107
+ * lexically invisible and only surface on a strong dense match, so they are NOT
108
+ * reliably recallable; do not use it for recall-critical writes.
109
+ *
110
+ * This is the missing "agent proactively records a mistake→fix lesson" arm of the
111
+ * recall loop: ee_query recalls, ee_feedback rates, ee_write creates. Mirrors
112
+ * feedbackEE's direct-fetch transport (cached baseUrl + bearer token); fails soft.
113
+ */
114
+ export declare function writeExperienceEE(lesson: string, opts?: {
115
+ collection?: string;
116
+ title?: string;
117
+ projectSlug?: string;
118
+ confidence?: number;
119
+ }): Promise<WriteExperienceResult>;
95
120
  /** Reachability probe for the EE server. */
96
121
  export declare function healthEE(): Promise<{
97
122
  ok: boolean;
@@ -211,6 +211,79 @@ export async function mirrorFeedbackLocally(pointId, collection, verdict, reason
211
211
  logEeFailure("search.mirrorFeedbackLocally", classifyEeError(err), err);
212
212
  }
213
213
  }
214
+ /**
215
+ * Write a NEW experience/lesson into the brain mid-session so it is RECALLABLE.
216
+ * POSTs to /api/import-memory → storeImportedExperience → upsertEntry, which
217
+ * embeds the text AND writes the `text_bm25` sparse vector (+ a proper payload via
218
+ * buildStorePayload). That dense+sparse write is what makes the lesson reliably
219
+ * recallable via ee_query / passive injection (both the dense and lexical legs can
220
+ * match it). NB: /api/ingest-point writes DENSE-ONLY (no sparse) — its points are
221
+ * lexically invisible and only surface on a strong dense match, so they are NOT
222
+ * reliably recallable; do not use it for recall-critical writes.
223
+ *
224
+ * This is the missing "agent proactively records a mistake→fix lesson" arm of the
225
+ * recall loop: ee_query recalls, ee_feedback rates, ee_write creates. Mirrors
226
+ * feedbackEE's direct-fetch transport (cached baseUrl + bearer token); fails soft.
227
+ */
228
+ export async function writeExperienceEE(lesson, opts = {}) {
229
+ const { loadEEAuthToken, getCachedServerBaseUrl } = await import("./auth.js");
230
+ const { randomUUID } = await import("node:crypto");
231
+ const authToken = (await loadEEAuthToken()) ?? undefined;
232
+ const baseUrl = (getCachedServerBaseUrl() ?? "http://localhost:8082").replace(/\/+$/, "");
233
+ const collection = opts.collection ?? "experience-behavioral";
234
+ const id = randomUUID();
235
+ // storeImportedExperience embeds `${qa.trigger} ${qa.question} ${qa.solution}`,
236
+ // so put the lesson in solution (and the title in question) to anchor the vector.
237
+ const qa = {
238
+ trigger: "",
239
+ question: opts.title ?? "",
240
+ solution: lesson,
241
+ scope: opts.projectSlug ? { project_slug: opts.projectSlug } : {},
242
+ };
243
+ const body = {
244
+ experiences: [
245
+ {
246
+ id,
247
+ collection,
248
+ qa,
249
+ tier: 2,
250
+ confidence: opts.confidence ?? 0.65,
251
+ runtime: "muonroi-cli-agent",
252
+ },
253
+ ],
254
+ };
255
+ const headers = { "Content-Type": "application/json" };
256
+ if (authToken)
257
+ headers.Authorization = `Bearer ${authToken}`;
258
+ try {
259
+ const res = await fetch(`${baseUrl}/api/import-memory`, {
260
+ method: "POST",
261
+ headers,
262
+ body: JSON.stringify(body),
263
+ });
264
+ const respText = await res.text();
265
+ let parsed = null;
266
+ try {
267
+ parsed = JSON.parse(respText);
268
+ }
269
+ catch {
270
+ /* non-JSON error body — fall through to status handling */
271
+ }
272
+ if (!res.ok) {
273
+ return { ok: false, error: parsed?.error || respText || `HTTP ${res.status}` };
274
+ }
275
+ const r0 = parsed?.results?.[0];
276
+ if (!parsed?.stored || r0?.ok !== true) {
277
+ return { ok: false, error: r0?.reason ?? "not_stored" };
278
+ }
279
+ return { ok: true, id };
280
+ }
281
+ catch (err) {
282
+ const { logEeFailure, classifyEeError } = await import("../utils/ee-logger.js");
283
+ logEeFailure("search.writeExperienceEE", classifyEeError(err), err);
284
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
285
+ }
286
+ }
214
287
  /** Reachability probe for the EE server. */
215
288
  export async function healthEE() {
216
289
  const { createEEClient } = await import("./client.js");
@@ -361,6 +361,20 @@ export interface EERecallOptions {
361
361
  export interface EEUserResponse {
362
362
  user: string;
363
363
  }
364
+ export interface BrainProxyOptions {
365
+ /** Override the default system prompt sent to the LLM. */
366
+ systemPrompt?: string;
367
+ /** Request JSON-mode response_format (e.g. { type: "json_object" }). */
368
+ responseFormat?: {
369
+ type: string;
370
+ };
371
+ /** Override the LLM model id used for classification. */
372
+ model?: string;
373
+ /** Override max_tokens for the LLM response. */
374
+ maxTokens?: number;
375
+ /** Override the brain provider (siliconflow | ollama | openai | ...). */
376
+ provider?: string;
377
+ }
364
378
  export interface EEClient {
365
379
  health(): Promise<{
366
380
  ok: boolean;
@@ -392,7 +406,7 @@ export interface EEClient {
392
406
  /** Active recall via /api/recall (recallMode). Returns [id col] index + records a surface. */
393
407
  recall(query: string, opts?: EERecallOptions): Promise<EERecallResponse | null>;
394
408
  user(): Promise<EEUserResponse | null>;
395
- brainProxy(prompt: string, timeoutMs?: number): Promise<string | null>;
409
+ brainProxy(prompt: string, timeoutMs?: number, options?: BrainProxyOptions): Promise<string | null>;
396
410
  pilContext(prompt: string, options?: {
397
411
  localeHint?: string;
398
412
  projectCtx?: Record<string, unknown>;
@@ -0,0 +1,41 @@
1
+ import type { OutputStyle } from "../pil/types.js";
2
+ export type PrivacyLevel = "minimal" | "standard" | "full";
3
+ export type WhoAmIDimName = "communication.question_style" | "communication.feedback_style" | "communication.brevity" | "personality.conflict_style" | "personality.risk_tolerance" | "personality.decision_speed" | "work_patterns.energy" | "work_patterns.multitasking" | "work_patterns.session_length" | "work_patterns.delegation_style";
4
+ export interface WhoAmIDim {
5
+ value: string;
6
+ confidence: number;
7
+ samples: number;
8
+ }
9
+ export interface WhoAmIProfile {
10
+ level: PrivacyLevel;
11
+ dims: Partial<Record<WhoAmIDimName, WhoAmIDim>>;
12
+ }
13
+ interface RawDim {
14
+ value: string | null;
15
+ confidence?: number;
16
+ sampleCount?: number;
17
+ samples?: number;
18
+ }
19
+ interface RawProfile {
20
+ dimensions?: Record<string, RawDim>;
21
+ }
22
+ /**
23
+ * PURE: project a raw EE profile to the privacy-gated dims for `level`, applying the
24
+ * positive name allowlist + value!=null commit gate + per-tier confidence floor.
25
+ */
26
+ export declare function selectWhoAmIDims(raw: RawProfile | null | undefined, level: PrivacyLevel): WhoAmIProfile["dims"];
27
+ /**
28
+ * PURE: derive an output-style baseline from the profile. brevity is the primary
29
+ * signal; decision_speed is a weaker fallback. Returns null when no usable signal
30
+ * exists so the caller keeps its own per-turn default.
31
+ */
32
+ export declare function outputStyleFromProfile(profile: WhoAmIProfile | null): OutputStyle | null;
33
+ /**
34
+ * Load + cache the privacy-gated profile for this process. The profile changes
35
+ * slowly (rebuilt by the EE Stop hook), so one read per process is enough.
36
+ * Returns null when EE is not installed, privacy is off, or nothing is committed.
37
+ */
38
+ export declare function getWhoAmIProfile(): WhoAmIProfile | null;
39
+ /** Clear the cache — test-only / after a known profile change. */
40
+ export declare function resetWhoAmICache(): void;
41
+ export {};
@@ -0,0 +1,143 @@
1
+ // src/ee/who-am-i.ts
2
+ //
3
+ // "Who Am I" v4.0 profile provider for the PIL. The personality/work-style profile
4
+ // is DEVICE-LOCAL (~/.experience/profile.yaml) and never leaves the machine, so it
5
+ // cannot come from the EE HTTP API — we read it on-device, reusing the EE install's
6
+ // parser (profile-model.js loadProfile) + privacy gate (config.js getPrivacyLevel)
7
+ // via createRequire (the same in-process pattern as src/ee/bridge.ts).
8
+ //
9
+ // Privacy is enforced HERE at read time via a positive per-dimension-NAME allowlist
10
+ // (defense in depth): the EE writer keeps committed values regardless of privacyLevel,
11
+ // so a standard→minimal downgrade leaves stale Tang-2 values physically in the file —
12
+ // trusting the file would leak opted-out data. Mirrors experience-engine
13
+ // src/profile-render.js. Fail-open: any error / missing EE install returns null and the
14
+ // PIL keeps its own per-turn defaults.
15
+ import { createRequire } from "node:module";
16
+ import * as os from "node:os";
17
+ import * as path from "node:path";
18
+ import { classifyEeError, logEeFailure } from "../utils/ee-logger.js";
19
+ // Tang 1 (work patterns + activity-derived decision_speed — namespaced personality.*
20
+ // but its SOURCE is activity, so it belongs to the minimal tier; allowlist by NAME).
21
+ const TIER_MINIMAL = [
22
+ "work_patterns.energy",
23
+ "work_patterns.multitasking",
24
+ "work_patterns.session_length",
25
+ "personality.decision_speed",
26
+ ];
27
+ // Tang 2 (decision + communication style) added at standard. `full` == standard today
28
+ // (no Tang-3 emotional dims exist); the allowlist guarantees emotional.* can never leak.
29
+ const TIER_STANDARD = [
30
+ ...TIER_MINIMAL,
31
+ "communication.question_style",
32
+ "communication.feedback_style",
33
+ "communication.brevity",
34
+ "personality.conflict_style",
35
+ "personality.risk_tolerance",
36
+ // delegation_style is `work_patterns.*` by name but transcript-derived, so it commits
37
+ // only at standard+ (the EE writer skips the transcript at `minimal`). Standard-only.
38
+ "work_patterns.delegation_style",
39
+ ];
40
+ const ALLOWLIST = {
41
+ minimal: TIER_MINIMAL,
42
+ standard: TIER_STANDARD,
43
+ full: TIER_STANDARD,
44
+ };
45
+ const WORK_DIMS = new Set(TIER_MINIMAL);
46
+ // Coarse work dims commit over 2-3-way splits (confidence ~0.45-0.6); the lower floor
47
+ // keeps the minimal tier usable. Mirrors experience-engine src/profile-render.js.
48
+ const WORK_MIN_CONFIDENCE = 0.45;
49
+ const MIN_CONFIDENCE = 0.6;
50
+ /**
51
+ * PURE: project a raw EE profile to the privacy-gated dims for `level`, applying the
52
+ * positive name allowlist + value!=null commit gate + per-tier confidence floor.
53
+ */
54
+ export function selectWhoAmIDims(raw, level) {
55
+ const out = {};
56
+ const allow = ALLOWLIST[level];
57
+ if (!allow || !raw?.dimensions)
58
+ return out;
59
+ for (const name of allow) {
60
+ const d = raw.dimensions[name];
61
+ if (!d || d.value == null)
62
+ continue;
63
+ const confidence = Number(d.confidence) || 0;
64
+ const floor = WORK_DIMS.has(name) ? WORK_MIN_CONFIDENCE : MIN_CONFIDENCE;
65
+ if (confidence < floor)
66
+ continue;
67
+ out[name] = {
68
+ value: String(d.value),
69
+ confidence,
70
+ samples: Math.round(Number(d.sampleCount ?? d.samples) || 0),
71
+ };
72
+ }
73
+ return out;
74
+ }
75
+ /**
76
+ * PURE: derive an output-style baseline from the profile. brevity is the primary
77
+ * signal; decision_speed is a weaker fallback. Returns null when no usable signal
78
+ * exists so the caller keeps its own per-turn default.
79
+ */
80
+ export function outputStyleFromProfile(profile) {
81
+ if (!profile)
82
+ return null;
83
+ const brevity = profile.dims["communication.brevity"]?.value;
84
+ if (brevity === "concise")
85
+ return "concise";
86
+ if (brevity === "verbose")
87
+ return "detailed";
88
+ if (brevity === "moderate")
89
+ return "balanced";
90
+ const speed = profile.dims["personality.decision_speed"]?.value;
91
+ if (speed === "fast-intuitive")
92
+ return "concise";
93
+ if (speed === "deliberate")
94
+ return "detailed";
95
+ return null;
96
+ }
97
+ let _cache;
98
+ /**
99
+ * Load + cache the privacy-gated profile for this process. The profile changes
100
+ * slowly (rebuilt by the EE Stop hook), so one read per process is enough.
101
+ * Returns null when EE is not installed, privacy is off, or nothing is committed.
102
+ */
103
+ export function getWhoAmIProfile() {
104
+ if (_cache !== undefined)
105
+ return _cache;
106
+ _cache = loadWhoAmIProfile();
107
+ return _cache;
108
+ }
109
+ /** Clear the cache — test-only / after a known profile change. */
110
+ export function resetWhoAmICache() {
111
+ _cache = undefined;
112
+ }
113
+ function loadWhoAmIProfile() {
114
+ try {
115
+ const req = createRequire(import.meta.url);
116
+ const srcDir = path.join(os.homedir(), ".experience", "src");
117
+ const config = req(path.join(srcDir, "config.js"));
118
+ const model = req(path.join(srcDir, "profile-model.js"));
119
+ if (typeof config.getPrivacyLevel !== "function" || typeof config.getProfilePath !== "function")
120
+ return null;
121
+ if (typeof model.loadProfile !== "function")
122
+ return null;
123
+ const level = String(config.getPrivacyLevel() ?? "off");
124
+ if (level !== "minimal" && level !== "standard" && level !== "full")
125
+ return null;
126
+ const raw = model.loadProfile(config.getProfilePath());
127
+ const dims = selectWhoAmIDims(raw, level);
128
+ if (Object.keys(dims).length === 0)
129
+ return null;
130
+ return { level, dims };
131
+ }
132
+ catch (err) {
133
+ // EE not installed (module absent) is an expected feature-off condition, not a
134
+ // failure — stay quiet. Any other error (corrupt profile, throwing module) is a
135
+ // real fault: log it (No-Silent-Catch) and degrade.
136
+ const code = err?.code;
137
+ if (code !== "MODULE_NOT_FOUND" && code !== "ERR_MODULE_NOT_FOUND") {
138
+ logEeFailure("who-am-i.load", classifyEeError(err), err);
139
+ }
140
+ return null;
141
+ }
142
+ }
143
+ //# sourceMappingURL=who-am-i.js.map
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,101 @@
1
+ import * as os from "node:os";
2
+ import { afterEach, beforeEach, describe, expect, test } from "vitest";
3
+ import { getWhoAmIProfile, outputStyleFromProfile, resetWhoAmICache, selectWhoAmIDims, } from "./who-am-i.js";
4
+ // Build a raw EE profile (the shape ~/.experience/src/profile-model.js loadProfile() returns).
5
+ function rawDim(value, confidence, sampleCount = 20) {
6
+ return { value, confidence, sampleCount, distribution: {}, evidence: null };
7
+ }
8
+ function rawProfile(dims) {
9
+ return { version: 1, updatedAt: null, dimensions: dims };
10
+ }
11
+ describe("selectWhoAmIDims — privacy allowlist + commit/confidence gates", () => {
12
+ const all = () => rawProfile({
13
+ "communication.question_style": rawDim("directive", 0.8),
14
+ "communication.feedback_style": rawDim("implicit", 0.75),
15
+ "communication.brevity": rawDim("concise", 0.83),
16
+ "personality.conflict_style": rawDim("direct-constructive", 0.7),
17
+ "personality.risk_tolerance": rawDim("experimental", 0.72),
18
+ "personality.decision_speed": rawDim("fast-intuitive", 0.7),
19
+ "work_patterns.energy": rawDim("night-owl", 0.6),
20
+ "work_patterns.multitasking": rawDim("sequential-deep", 0.65),
21
+ "work_patterns.session_length": rawDim("long", 0.55),
22
+ "work_patterns.delegation_style": rawDim("autonomous", 0.68),
23
+ });
24
+ test("minimal exposes only the 4 Tang-1 work dims", () => {
25
+ const dims = selectWhoAmIDims(all(), "minimal");
26
+ expect(Object.keys(dims).sort()).toEqual([
27
+ "personality.decision_speed",
28
+ "work_patterns.energy",
29
+ "work_patterns.multitasking",
30
+ "work_patterns.session_length",
31
+ ].sort());
32
+ });
33
+ test("standard exposes all 10 committed dims", () => {
34
+ const dims = selectWhoAmIDims(all(), "standard");
35
+ expect(Object.keys(dims).length).toBe(10);
36
+ });
37
+ test("delegation_style is standard-only — stripped at minimal (transcript-derived, not Tang-1)", () => {
38
+ expect(selectWhoAmIDims(all(), "minimal")["work_patterns.delegation_style"]).toBeUndefined();
39
+ expect(selectWhoAmIDims(all(), "standard")["work_patterns.delegation_style"]).toBeDefined();
40
+ });
41
+ test("standard-built profile rendered at minimal strips Tang-2 dims (no stale leak)", () => {
42
+ const dims = selectWhoAmIDims(all(), "minimal");
43
+ expect(dims["communication.brevity"]).toBeUndefined();
44
+ expect(dims["personality.conflict_style"]).toBeUndefined();
45
+ });
46
+ test("pending (value=null) dims are skipped", () => {
47
+ const dims = selectWhoAmIDims(rawProfile({ "communication.brevity": rawDim(null, 0.9, 5) }), "standard");
48
+ expect(Object.keys(dims).length).toBe(0);
49
+ });
50
+ test("per-tier confidence floors: 0.55 Tang-2 drops at 0.6, 0.50 work survives at 0.45", () => {
51
+ const dims = selectWhoAmIDims(rawProfile({
52
+ "communication.brevity": rawDim("concise", 0.55),
53
+ "work_patterns.energy": rawDim("night-owl", 0.5),
54
+ }), "standard");
55
+ expect(dims["communication.brevity"]).toBeUndefined();
56
+ expect(dims["work_patterns.energy"]).toBeDefined();
57
+ });
58
+ test("Tang-3 emotional.* is never exposed (not in any allowlist)", () => {
59
+ const dims = selectWhoAmIDims(rawProfile({ "emotional.mood": rawDim("calm", 0.99) }), "full");
60
+ expect(Object.keys(dims).length).toBe(0);
61
+ });
62
+ test("decision_speed (personality.* but Tang-1) is allowed at minimal — namespace trap", () => {
63
+ const dims = selectWhoAmIDims(rawProfile({ "personality.decision_speed": rawDim("measured", 0.7) }), "minimal");
64
+ expect(dims["personality.decision_speed"]).toBeDefined();
65
+ });
66
+ });
67
+ describe("outputStyleFromProfile — brevity/decision_speed → OutputStyle", () => {
68
+ const p = (dims) => ({ level: "standard", dims });
69
+ test("brevity concise → concise, verbose → detailed, moderate → balanced", () => {
70
+ expect(outputStyleFromProfile(p({ "communication.brevity": { value: "concise", confidence: 0.8, samples: 20 } }))).toBe("concise");
71
+ expect(outputStyleFromProfile(p({ "communication.brevity": { value: "verbose", confidence: 0.8, samples: 20 } }))).toBe("detailed");
72
+ expect(outputStyleFromProfile(p({ "communication.brevity": { value: "moderate", confidence: 0.8, samples: 20 } }))).toBe("balanced");
73
+ });
74
+ test("no brevity → decision_speed fast-intuitive → concise; deliberate → detailed", () => {
75
+ expect(outputStyleFromProfile(p({ "personality.decision_speed": { value: "fast-intuitive", confidence: 0.7, samples: 20 } }))).toBe("concise");
76
+ expect(outputStyleFromProfile(p({ "personality.decision_speed": { value: "deliberate", confidence: 0.7, samples: 20 } }))).toBe("detailed");
77
+ });
78
+ test("null profile or no usable dim → null (caller keeps its own default)", () => {
79
+ expect(outputStyleFromProfile(null)).toBeNull();
80
+ expect(outputStyleFromProfile(p({ "personality.decision_speed": { value: "measured", confidence: 0.7, samples: 20 } }))).toBeNull();
81
+ });
82
+ });
83
+ describe("getWhoAmIProfile — fail-open + cache", () => {
84
+ const origHome = process.env.HOME;
85
+ const origUser = process.env.USERPROFILE;
86
+ beforeEach(() => {
87
+ resetWhoAmICache();
88
+ });
89
+ afterEach(() => {
90
+ process.env.HOME = origHome;
91
+ process.env.USERPROFILE = origUser;
92
+ resetWhoAmICache();
93
+ });
94
+ test("returns null when no EE install is present (no ~/.experience modules)", () => {
95
+ const empty = os.tmpdir(); // no .experience/src here
96
+ process.env.HOME = empty;
97
+ process.env.USERPROFILE = empty;
98
+ expect(getWhoAmIProfile()).toBeNull();
99
+ });
100
+ });
101
+ //# sourceMappingURL=who-am-i.test.js.map
@@ -11,6 +11,7 @@ export interface CompactionResult {
11
11
  tokensBeforeCompress: number;
12
12
  tokensAfterCompress: number;
13
13
  historyPath: string;
14
+ summary: string;
14
15
  }
15
16
  /**
16
17
  * Orchestrate two-pass deliberate compaction.
@@ -49,6 +49,9 @@ export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBu
49
49
  const historyPath = path.join(historyDir, `${timestamp}.md`);
50
50
  const fullSerialized = serializeConversation(messages);
51
51
  await atomicWriteText(historyPath, fullSerialized);
52
+ // Save full JSON history next to the md file for exact expand/restore
53
+ const jsonPath = path.join(historyDir, `${timestamp}.json`);
54
+ await atomicWriteText(jsonPath, JSON.stringify(messages, null, 2));
52
55
  // Token estimation before
53
56
  const tokensBefore = estimateConversationTokens(systemPrompt, messages);
54
57
  // Pass 2: Compress
@@ -58,6 +61,7 @@ export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBu
58
61
  tokensBeforeCompress: tokensBefore,
59
62
  tokensAfterCompress: compressed.tokensAfter,
60
63
  historyPath,
64
+ summary: compressed.summary,
61
65
  };
62
66
  }
63
67
  //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "1.7.2";
1
+ export declare const PACKAGE_VERSION = "1.8.1";
2
2
  export declare const PACKAGE_DESCRIPTION = "BYOK AI coding agent with multi-model council debate, role-based routing, and auto-compact.";
@@ -1,5 +1,5 @@
1
1
  // AUTO-GENERATED by scripts/sync-version.cjs. DO NOT EDIT BY HAND.
2
2
  // Sourced from package.json at build time so it survives bun --compile bundling.
3
- export const PACKAGE_VERSION = "1.7.2";
3
+ export const PACKAGE_VERSION = "1.8.1";
4
4
  export const PACKAGE_DESCRIPTION = "BYOK AI coding agent with multi-model council debate, role-based routing, and auto-compact.";
5
5
  //# sourceMappingURL=version.js.map
@@ -9,6 +9,7 @@ export function createCouncilAutoAnswerer(opts) {
9
9
  "pil-interview": [],
10
10
  "pil-acceptance": [],
11
11
  "tool-loop-cap": [],
12
+ "safety-override": [],
12
13
  };
13
14
  const preflightApprove = opts.file?.preflightApprove ?? true;
14
15
  return {
@@ -1,5 +1,5 @@
1
1
  import type { ProcessMessageObserver } from "../orchestrator/agent-options.js";
2
- import type { StreamChunk, ToolCall, ToolResult } from "../types/index.js";
2
+ import type { StreamChunk, StructuredResponse, ToolCall, ToolResult } from "../types/index.js";
3
3
  export type HeadlessOutputFormat = "text" | "json";
4
4
  export interface HeadlessWrites {
5
5
  stdout?: string;
@@ -42,6 +42,13 @@ export type HeadlessJsonEvent = {
42
42
  totalTokens?: number;
43
43
  costUsdTicks?: number;
44
44
  };
45
+ } | {
46
+ type: "structured_response";
47
+ sessionID?: string;
48
+ stepNumber: number;
49
+ timestamp: number;
50
+ taskType: string;
51
+ data: Record<string, unknown>;
45
52
  } | {
46
53
  type: "error";
47
54
  sessionID?: string;
@@ -54,6 +61,28 @@ export declare function renderHeadlessPrelude(format: HeadlessOutputFormat, sess
54
61
  * Headless text output only. JSON streaming uses {@link createHeadlessJsonlEmitter} + `Agent.processMessage` observer.
55
62
  */
56
63
  export declare function renderHeadlessChunk(chunk: StreamChunk): HeadlessWrites;
64
+ /**
65
+ * Plain-text rendering of a respond_* terminal answer for headless `--format
66
+ * text`. Mirrors the per-taskType layout of {@link StructuredResponseView}
67
+ * (src/ui/components/structured-response-view.tsx) but emits flat text (no ANSI
68
+ * box-drawing) so the answer pipes cleanly. Falls back to the primary text
69
+ * field, then raw JSON, for taskTypes without a dedicated layout.
70
+ */
71
+ export declare function formatStructuredResponseText(sr: StructuredResponse): string;
72
+ /**
73
+ * Stateful headless TEXT consumer. Streams tool/error progress to stderr (via
74
+ * {@link renderHeadlessChunk}) but BUFFERS assistant `content` so that a
75
+ * terminal `respond_*` answer ({@link StructuredResponse}) supersedes any
76
+ * preamble the model leaked before calling the response tool — otherwise the
77
+ * answer would print twice (once as raw leaked content, once formatted). For a
78
+ * normal chat turn with no structured answer, the buffered content is flushed
79
+ * verbatim at the end. Mirrors the buffer-and-supersede design of
80
+ * {@link createHeadlessJsonlEmitter}.
81
+ */
82
+ export declare function createHeadlessTextEmitter(): {
83
+ consumeChunk(chunk: StreamChunk): HeadlessWrites;
84
+ flush(): HeadlessWrites;
85
+ };
57
86
  /**
58
87
  * Buffers assistant `content` per step and emits JSONL: step_start, text, tool_use, step_finish, error.
59
88
  * Pair with `agent.processMessage(prompt, emitter.observer)` in headless JSON mode only.