@ashx-j/lunr 0.2.10 → 0.2.12

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 (344) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +211 -236
  3. package/dist/builtin-extensions/ashxj-tui.d.ts +3 -0
  4. package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
  5. package/dist/builtin-extensions/ashxj-tui.js +28 -11
  6. package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
  7. package/dist/builtin-extensions/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/index.js +0 -2
  9. package/dist/builtin-extensions/index.js.map +1 -1
  10. package/dist/builtin-extensions/lunr-cron.d.ts +1 -1
  11. package/dist/builtin-extensions/lunr-cron.d.ts.map +1 -1
  12. package/dist/builtin-extensions/lunr-cron.js +7 -2
  13. package/dist/builtin-extensions/lunr-cron.js.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js +3 -3
  16. package/dist/builtin-extensions/pi-subagents/src/extension/chain-validation.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts +0 -2
  18. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.d.ts.map +1 -1
  19. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js +1 -23
  20. package/dist/builtin-extensions/pi-subagents/src/extension/doctor.js.map +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js +7 -8
  23. package/dist/builtin-extensions/pi-subagents/src/extension/fanout-child.js.map +1 -1
  24. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts +1 -1
  25. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  26. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +10 -18
  27. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  28. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +12 -9
  29. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
  30. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +38 -34
  31. package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
  32. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +3 -3
  33. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
  34. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +32 -47
  35. package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
  36. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts +2 -2
  37. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.d.ts.map +1 -1
  38. package/dist/builtin-extensions/pi-subagents/src/intercom/intercom-bridge.js.map +1 -1
  39. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts +7 -10
  40. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
  41. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +90 -109
  42. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
  43. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts +3 -2
  44. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
  45. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +37 -50
  46. package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
  47. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
  48. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +1 -1
  49. package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
  50. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts +4 -0
  51. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.d.ts.map +1 -1
  52. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js +5 -5
  53. package/dist/builtin-extensions/pi-subagents/src/runs/background/scheduled-runs.js.map +1 -1
  54. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
  55. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +31 -13
  56. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js.map +1 -1
  57. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts +2 -2
  58. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts.map +1 -1
  59. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js.map +1 -1
  60. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts +4 -3
  61. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
  62. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +48 -20
  63. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
  64. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts +2 -2
  65. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
  66. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +90 -64
  67. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
  68. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +6 -8
  69. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  70. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +269 -167
  71. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  72. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts +2 -1
  73. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.d.ts.map +1 -1
  74. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js +24 -33
  75. package/dist/builtin-extensions/pi-subagents/src/runs/shared/acceptance.js.map +1 -1
  76. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts +25 -0
  77. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.d.ts.map +1 -0
  78. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js +51 -0
  79. package/dist/builtin-extensions/pi-subagents/src/runs/shared/child-tools.js.map +1 -0
  80. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.d.ts.map +1 -1
  81. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js +20 -3
  82. package/dist/builtin-extensions/pi-subagents/src/runs/shared/dynamic-fanout.js.map +1 -1
  83. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +4 -1
  84. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
  85. package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
  86. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts +5 -0
  87. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.d.ts.map +1 -1
  88. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js +9 -3
  89. package/dist/builtin-extensions/pi-subagents/src/runs/shared/pi-args.js.map +1 -1
  90. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  91. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js +2 -2
  92. package/dist/builtin-extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  93. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts +2 -2
  94. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.d.ts.map +1 -1
  95. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js +20 -17
  96. package/dist/builtin-extensions/pi-subagents/src/runs/shared/task-intent.js.map +1 -1
  97. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts +70 -0
  98. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -0
  99. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +153 -0
  100. package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -0
  101. package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts +13 -8
  102. package/dist/builtin-extensions/pi-subagents/src/shared/settings.d.ts.map +1 -1
  103. package/dist/builtin-extensions/pi-subagents/src/shared/settings.js +20 -51
  104. package/dist/builtin-extensions/pi-subagents/src/shared/settings.js.map +1 -1
  105. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +82 -21
  106. package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
  107. package/dist/builtin-extensions/pi-subagents/src/shared/types.js +10 -2
  108. package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
  109. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +2 -2
  110. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
  111. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +20 -32
  112. package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
  113. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +2 -1
  114. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
  115. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +23 -449
  116. package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
  117. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -1
  118. package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
  119. package/dist/builtin-extensions/pi-subagents/src/tui/render.js +13 -11
  120. package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
  121. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts +2 -1
  122. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.d.ts.map +1 -1
  123. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js +18 -17
  124. package/dist/builtin-extensions/pi-subagents/src/watchdog/runtime.js.map +1 -1
  125. package/dist/builtin-extensions/simple-pi-memory.d.ts +2 -2
  126. package/dist/builtin-extensions/simple-pi-memory.d.ts.map +1 -1
  127. package/dist/builtin-extensions/simple-pi-memory.js +41 -17
  128. package/dist/builtin-extensions/simple-pi-memory.js.map +1 -1
  129. package/dist/catalog/models.json +1 -1
  130. package/dist/catalog/providers/amazon-bedrock.json +1 -1
  131. package/dist/catalog/providers/azure-openai-responses.json +1 -1
  132. package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
  133. package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
  134. package/dist/catalog/providers/fireworks.json +1 -1
  135. package/dist/catalog/providers/github-copilot.json +1 -1
  136. package/dist/catalog/providers/huggingface.json +1 -1
  137. package/dist/catalog/providers/minimax-cn.json +1 -1
  138. package/dist/catalog/providers/minimax.json +1 -1
  139. package/dist/catalog/providers/mistral.json +1 -1
  140. package/dist/catalog/providers/nvidia.json +1 -1
  141. package/dist/catalog/providers/openai.json +1 -1
  142. package/dist/catalog/providers/opencode-go.json +1 -1
  143. package/dist/catalog/providers/opencode.json +1 -1
  144. package/dist/catalog/providers/openrouter.json +1 -1
  145. package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
  146. package/dist/catalog/providers/qwen-cloud.json +1 -1
  147. package/dist/catalog/providers/qwen-token-plan-cn.json +1 -1
  148. package/dist/catalog/providers/qwen-token-plan.json +1 -1
  149. package/dist/catalog/providers/together.json +1 -1
  150. package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
  151. package/dist/catalog/providers/xai.json +1 -1
  152. package/dist/catalog/providers/zai-coding-cn.json +1 -1
  153. package/dist/catalog/providers/zai.json +1 -1
  154. package/dist/catalog/publication.json +3 -3
  155. package/dist/core/agent-session.d.ts +7 -1
  156. package/dist/core/agent-session.d.ts.map +1 -1
  157. package/dist/core/agent-session.js +36 -6
  158. package/dist/core/agent-session.js.map +1 -1
  159. package/dist/core/customize.d.ts +2 -0
  160. package/dist/core/customize.d.ts.map +1 -1
  161. package/dist/core/customize.js +6 -0
  162. package/dist/core/customize.js.map +1 -1
  163. package/dist/core/memory-cap.d.ts +4 -8
  164. package/dist/core/memory-cap.d.ts.map +1 -1
  165. package/dist/core/memory-cap.js +8 -8
  166. package/dist/core/memory-cap.js.map +1 -1
  167. package/dist/core/models-store.d.ts.map +1 -1
  168. package/dist/core/models-store.js +13 -1
  169. package/dist/core/models-store.js.map +1 -1
  170. package/dist/core/permissions.d.ts +11 -0
  171. package/dist/core/permissions.d.ts.map +1 -1
  172. package/dist/core/permissions.js +90 -34
  173. package/dist/core/permissions.js.map +1 -1
  174. package/dist/core/plan-mode.d.ts.map +1 -1
  175. package/dist/core/plan-mode.js +50 -16
  176. package/dist/core/plan-mode.js.map +1 -1
  177. package/dist/core/rollback.d.ts.map +1 -1
  178. package/dist/core/rollback.js +1 -1
  179. package/dist/core/rollback.js.map +1 -1
  180. package/dist/core/settings-manager.d.ts +9 -5
  181. package/dist/core/settings-manager.d.ts.map +1 -1
  182. package/dist/core/settings-manager.js +24 -10
  183. package/dist/core/settings-manager.js.map +1 -1
  184. package/dist/core/slash-commands.d.ts.map +1 -1
  185. package/dist/core/slash-commands.js +1 -5
  186. package/dist/core/slash-commands.js.map +1 -1
  187. package/dist/core/subagent-permission-inherit.d.ts +34 -22
  188. package/dist/core/subagent-permission-inherit.d.ts.map +1 -1
  189. package/dist/core/subagent-permission-inherit.js +37 -80
  190. package/dist/core/subagent-permission-inherit.js.map +1 -1
  191. package/dist/core/swarm.d.ts +17 -4
  192. package/dist/core/swarm.d.ts.map +1 -1
  193. package/dist/core/swarm.js +48 -10
  194. package/dist/core/swarm.js.map +1 -1
  195. package/dist/core/system-prompt.d.ts +6 -4
  196. package/dist/core/system-prompt.d.ts.map +1 -1
  197. package/dist/core/system-prompt.js +38 -48
  198. package/dist/core/system-prompt.js.map +1 -1
  199. package/dist/core/usage-adapters/openai-codex.d.ts +1 -1
  200. package/dist/core/usage-adapters/openai-codex.d.ts.map +1 -1
  201. package/dist/core/usage-adapters/openai-codex.js +22 -17
  202. package/dist/core/usage-adapters/openai-codex.js.map +1 -1
  203. package/dist/core/usage-service.d.ts +10 -1
  204. package/dist/core/usage-service.d.ts.map +1 -1
  205. package/dist/core/usage-service.js +17 -6
  206. package/dist/core/usage-service.js.map +1 -1
  207. package/dist/gateway/agent-bridge.d.ts +1 -1
  208. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  209. package/dist/gateway/agent-bridge.js +12 -5
  210. package/dist/gateway/agent-bridge.js.map +1 -1
  211. package/dist/gateway/commands.d.ts.map +1 -1
  212. package/dist/gateway/commands.js +2 -1
  213. package/dist/gateway/commands.js.map +1 -1
  214. package/dist/gateway/cron.d.ts +4 -1
  215. package/dist/gateway/cron.d.ts.map +1 -1
  216. package/dist/gateway/cron.js +18 -12
  217. package/dist/gateway/cron.js.map +1 -1
  218. package/dist/gateway/router.d.ts +1 -1
  219. package/dist/gateway/router.d.ts.map +1 -1
  220. package/dist/gateway/router.js.map +1 -1
  221. package/dist/main.d.ts.map +1 -1
  222. package/dist/main.js +0 -5
  223. package/dist/main.js.map +1 -1
  224. package/dist/migrations.d.ts +2 -0
  225. package/dist/migrations.d.ts.map +1 -1
  226. package/dist/migrations.js +21 -0
  227. package/dist/migrations.js.map +1 -1
  228. package/dist/modes/interactive/components/settings-selector.d.ts +4 -3
  229. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/settings-selector.js +21 -77
  231. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  232. package/dist/modes/interactive/components/usage-view.d.ts +1 -1
  233. package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/usage-view.js +7 -4
  235. package/dist/modes/interactive/components/usage-view.js.map +1 -1
  236. package/dist/modes/interactive/interactive-mode.d.ts +1 -2
  237. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  238. package/dist/modes/interactive/interactive-mode.js +39 -93
  239. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  240. package/docs/compaction.md +23 -23
  241. package/docs/containerization.md +24 -24
  242. package/docs/custom-provider.md +18 -18
  243. package/docs/development.md +16 -15
  244. package/docs/docs.json +6 -2
  245. package/docs/extensions.md +82 -80
  246. package/docs/features.md +102 -0
  247. package/docs/index.md +25 -19
  248. package/docs/json.md +7 -7
  249. package/docs/keybindings.md +4 -4
  250. package/docs/models.md +2 -2
  251. package/docs/packages.md +38 -42
  252. package/docs/prompt-templates.md +4 -4
  253. package/docs/providers.md +22 -10
  254. package/docs/quickstart.md +81 -46
  255. package/docs/rpc.md +7 -13
  256. package/docs/sdk.md +43 -41
  257. package/docs/security.md +18 -18
  258. package/docs/session-format.md +9 -9
  259. package/docs/sessions.md +13 -12
  260. package/docs/settings.md +62 -24
  261. package/docs/shell-aliases.md +2 -2
  262. package/docs/skills.md +11 -11
  263. package/docs/terminal-setup.md +5 -5
  264. package/docs/termux.md +7 -7
  265. package/docs/themes.md +12 -14
  266. package/docs/tmux.md +4 -4
  267. package/docs/tui.md +23 -23
  268. package/docs/usage.md +112 -87
  269. package/docs/windows.md +10 -2
  270. package/examples/README.md +3 -1
  271. package/examples/extensions/README.md +6 -6
  272. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  273. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  274. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  275. package/examples/extensions/doom-overlay/README.md +2 -2
  276. package/examples/extensions/gondolin/package-lock.json +2 -2
  277. package/examples/extensions/gondolin/package.json +1 -1
  278. package/examples/extensions/plan-mode/README.md +3 -1
  279. package/examples/extensions/sandbox/package-lock.json +2 -2
  280. package/examples/extensions/sandbox/package.json +1 -1
  281. package/examples/extensions/subagent/README.md +13 -11
  282. package/examples/extensions/todo.ts +2 -1
  283. package/examples/extensions/with-deps/package-lock.json +2 -2
  284. package/examples/extensions/with-deps/package.json +1 -1
  285. package/examples/sdk/README.md +9 -5
  286. package/package.json +6 -7
  287. package/dist/builtin-extensions/lunr-behavior.d.ts +0 -44
  288. package/dist/builtin-extensions/lunr-behavior.d.ts.map +0 -1
  289. package/dist/builtin-extensions/lunr-behavior.js +0 -213
  290. package/dist/builtin-extensions/lunr-behavior.js.map +0 -1
  291. package/dist/builtin-extensions/pi-subagents/agents/context-builder.md +0 -46
  292. package/dist/builtin-extensions/pi-subagents/agents/deep-researcher.md +0 -36
  293. package/dist/builtin-extensions/pi-subagents/agents/delegate.md +0 -12
  294. package/dist/builtin-extensions/pi-subagents/agents/oracle.md +0 -73
  295. package/dist/builtin-extensions/pi-subagents/agents/planner.md +0 -55
  296. package/dist/builtin-extensions/pi-subagents/agents/research-writer.md +0 -37
  297. package/dist/builtin-extensions/pi-subagents/agents/researcher.md +0 -52
  298. package/dist/builtin-extensions/pi-subagents/agents/reviewer.md +0 -79
  299. package/dist/builtin-extensions/pi-subagents/agents/scout.md +0 -50
  300. package/dist/builtin-extensions/pi-subagents/agents/worker.md +0 -55
  301. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts +0 -20
  302. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts.map +0 -1
  303. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js +0 -1273
  304. package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js.map +0 -1
  305. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts +0 -49
  306. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.d.ts.map +0 -1
  307. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js +0 -252
  308. package/dist/builtin-extensions/pi-subagents/src/agents/agent-memory.js.map +0 -1
  309. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts +0 -3
  310. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.d.ts.map +0 -1
  311. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js +0 -6
  312. package/dist/builtin-extensions/pi-subagents/src/agents/agent-scope.js.map +0 -1
  313. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts +0 -3
  314. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.d.ts.map +0 -1
  315. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js +0 -23
  316. package/dist/builtin-extensions/pi-subagents/src/agents/agent-selection.js.map +0 -1
  317. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts +0 -8
  318. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.d.ts.map +0 -1
  319. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js +0 -143
  320. package/dist/builtin-extensions/pi-subagents/src/agents/agent-serializer.js.map +0 -1
  321. package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts +0 -176
  322. package/dist/builtin-extensions/pi-subagents/src/agents/agents.d.ts.map +0 -1
  323. package/dist/builtin-extensions/pi-subagents/src/agents/agents.js +0 -1326
  324. package/dist/builtin-extensions/pi-subagents/src/agents/agents.js.map +0 -1
  325. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts +0 -7
  326. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.d.ts.map +0 -1
  327. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js +0 -307
  328. package/dist/builtin-extensions/pi-subagents/src/agents/chain-serializer.js.map +0 -1
  329. package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts +0 -8
  330. package/dist/builtin-extensions/pi-subagents/src/agents/identity.d.ts.map +0 -1
  331. package/dist/builtin-extensions/pi-subagents/src/agents/identity.js +0 -30
  332. package/dist/builtin-extensions/pi-subagents/src/agents/identity.js.map +0 -1
  333. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts +0 -35
  334. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.d.ts.map +0 -1
  335. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js +0 -151
  336. package/dist/builtin-extensions/pi-subagents/src/agents/proactive-skills.js.map +0 -1
  337. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts +0 -131
  338. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.d.ts.map +0 -1
  339. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js +0 -491
  340. package/dist/builtin-extensions/pi-subagents/src/profiles/profiles.js.map +0 -1
  341. package/dist/core/behavior-preset.d.ts +0 -60
  342. package/dist/core/behavior-preset.d.ts.map +0 -1
  343. package/dist/core/behavior-preset.js +0 -257
  344. package/dist/core/behavior-preset.js.map +0 -1
@@ -11,10 +11,12 @@ export declare const CUSTOMIZE_BRIDGE_SYMBOL: unique symbol;
11
11
  export interface CustomizeBridge {
12
12
  getGutterRail(): boolean;
13
13
  getPromptSymbol(): boolean;
14
+ getOpenAIFastMode(): boolean;
14
15
  getFooterMcp(): boolean;
15
16
  getFooterLsp(): boolean;
16
17
  getFooterContext(): boolean;
17
18
  getFooterTokens(): boolean;
19
+ getFooterCacheHitRate(): boolean;
18
20
  getFooterTps(): boolean;
19
21
  getFooterStatuses(): boolean;
20
22
  getFooterGit(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"customize.d.ts","sourceRoot":"","sources":["../../src/core/customize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;GAOG;AAEH,eAAO,MAAM,uBAAuB,eAAgC,CAAC;AAErE,MAAM,WAAW,eAAe;IAC/B,aAAa,IAAI,OAAO,CAAC;IACzB,eAAe,IAAI,OAAO,CAAC;IAC3B,YAAY,IAAI,OAAO,CAAC;IACxB,YAAY,IAAI,OAAO,CAAC;IACxB,gBAAgB,IAAI,OAAO,CAAC;IAC5B,eAAe,IAAI,OAAO,CAAC;IAC3B,YAAY,IAAI,OAAO,CAAC;IACxB,iBAAiB,IAAI,OAAO,CAAC;IAC7B,YAAY,IAAI,OAAO,CAAC;IACxB,aAAa,IAAI,OAAO,CAAC;IACzB,gBAAgB,IAAI,OAAO,CAAC;IAC5B,oBAAoB,IAAI,OAAO,CAAC;IAChC,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1C;AA8CD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAG9E;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAEhE","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * lunR TUI customize bridge.\n *\n * Exposed on `globalThis` under `Symbol.for(\"@lunr/customize\")` so the baked-in\n * ashxj-tui extension can read the customize settings (gutter rail, prompt\n * symbol, footer element toggles) without importing core code — same pattern as\n * the model-tiers and memory-cap bridges.\n */\n\nexport const CUSTOMIZE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/customize\");\n\nexport interface CustomizeBridge {\n\tgetGutterRail(): boolean;\n\tgetPromptSymbol(): boolean;\n\tgetFooterMcp(): boolean;\n\tgetFooterLsp(): boolean;\n\tgetFooterContext(): boolean;\n\tgetFooterTokens(): boolean;\n\tgetFooterTps(): boolean;\n\tgetFooterStatuses(): boolean;\n\tgetFooterGit(): boolean;\n\tgetFooterPlan(): boolean;\n\tgetFooterPlanBar(): boolean;\n\tgetHideThinkingBlock(): boolean;\n\tsetHideThinkingBlock(hide: boolean): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: CustomizeBridge = {\n\tgetGutterRail(): boolean {\n\t\treturn activeSettingsManager?.getGutterRail() ?? true;\n\t},\n\tgetPromptSymbol(): boolean {\n\t\treturn activeSettingsManager?.getPromptSymbol() ?? true;\n\t},\n\tgetFooterMcp(): boolean {\n\t\treturn activeSettingsManager?.getFooterMcp() ?? true;\n\t},\n\tgetFooterLsp(): boolean {\n\t\treturn activeSettingsManager?.getFooterLsp() ?? false;\n\t},\n\tgetFooterContext(): boolean {\n\t\treturn activeSettingsManager?.getFooterContext() ?? true;\n\t},\n\tgetFooterTokens(): boolean {\n\t\treturn activeSettingsManager?.getFooterTokens() ?? true;\n\t},\n\tgetFooterTps(): boolean {\n\t\treturn activeSettingsManager?.getFooterTps() ?? true;\n\t},\n\tgetFooterStatuses(): boolean {\n\t\treturn activeSettingsManager?.getFooterStatuses() ?? true;\n\t},\n\tgetFooterGit(): boolean {\n\t\treturn activeSettingsManager?.getFooterGit() ?? true;\n\t},\n\tgetFooterPlan(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlan() ?? true;\n\t},\n\tgetFooterPlanBar(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlanBar() ?? true;\n\t},\n\tgetHideThinkingBlock(): boolean {\n\t\treturn activeSettingsManager?.getHideThinkingBlock() ?? false;\n\t},\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tactiveSettingsManager?.setHideThinkingBlock(hide);\n\t},\n};\n\n/**\n * Register (or re-point) the global customize bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerCustomizeBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] = bridge;\n}\n\n/** Read the bridge from `globalThis`, or undefined when not registered (extension-safe). */\nexport function getCustomizeBridge(): CustomizeBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] as CustomizeBridge | undefined;\n}\n"]}
1
+ {"version":3,"file":"customize.d.ts","sourceRoot":"","sources":["../../src/core/customize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;GAOG;AAEH,eAAO,MAAM,uBAAuB,eAAgC,CAAC;AAErE,MAAM,WAAW,eAAe;IAC/B,aAAa,IAAI,OAAO,CAAC;IACzB,eAAe,IAAI,OAAO,CAAC;IAC3B,iBAAiB,IAAI,OAAO,CAAC;IAC7B,YAAY,IAAI,OAAO,CAAC;IACxB,YAAY,IAAI,OAAO,CAAC;IACxB,gBAAgB,IAAI,OAAO,CAAC;IAC5B,eAAe,IAAI,OAAO,CAAC;IAC3B,qBAAqB,IAAI,OAAO,CAAC;IACjC,YAAY,IAAI,OAAO,CAAC;IACxB,iBAAiB,IAAI,OAAO,CAAC;IAC7B,YAAY,IAAI,OAAO,CAAC;IACxB,aAAa,IAAI,OAAO,CAAC;IACzB,gBAAgB,IAAI,OAAO,CAAC;IAC5B,oBAAoB,IAAI,OAAO,CAAC;IAChC,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1C;AAoDD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAG9E;AAED,4FAA4F;AAC5F,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAEhE","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * lunR TUI customize bridge.\n *\n * Exposed on `globalThis` under `Symbol.for(\"@lunr/customize\")` so the baked-in\n * ashxj-tui extension can read the customize settings (gutter rail, prompt\n * symbol, footer element toggles) without importing core code — same pattern as\n * the model-tiers and memory-cap bridges.\n */\n\nexport const CUSTOMIZE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/customize\");\n\nexport interface CustomizeBridge {\n\tgetGutterRail(): boolean;\n\tgetPromptSymbol(): boolean;\n\tgetOpenAIFastMode(): boolean;\n\tgetFooterMcp(): boolean;\n\tgetFooterLsp(): boolean;\n\tgetFooterContext(): boolean;\n\tgetFooterTokens(): boolean;\n\tgetFooterCacheHitRate(): boolean;\n\tgetFooterTps(): boolean;\n\tgetFooterStatuses(): boolean;\n\tgetFooterGit(): boolean;\n\tgetFooterPlan(): boolean;\n\tgetFooterPlanBar(): boolean;\n\tgetHideThinkingBlock(): boolean;\n\tsetHideThinkingBlock(hide: boolean): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: CustomizeBridge = {\n\tgetGutterRail(): boolean {\n\t\treturn activeSettingsManager?.getGutterRail() ?? true;\n\t},\n\tgetPromptSymbol(): boolean {\n\t\treturn activeSettingsManager?.getPromptSymbol() ?? true;\n\t},\n\tgetOpenAIFastMode(): boolean {\n\t\treturn activeSettingsManager?.getOpenAIFastMode() ?? false;\n\t},\n\tgetFooterMcp(): boolean {\n\t\treturn activeSettingsManager?.getFooterMcp() ?? true;\n\t},\n\tgetFooterLsp(): boolean {\n\t\treturn activeSettingsManager?.getFooterLsp() ?? false;\n\t},\n\tgetFooterContext(): boolean {\n\t\treturn activeSettingsManager?.getFooterContext() ?? true;\n\t},\n\tgetFooterTokens(): boolean {\n\t\treturn activeSettingsManager?.getFooterTokens() ?? true;\n\t},\n\tgetFooterCacheHitRate(): boolean {\n\t\treturn activeSettingsManager?.getFooterCacheHitRate() ?? true;\n\t},\n\tgetFooterTps(): boolean {\n\t\treturn activeSettingsManager?.getFooterTps() ?? true;\n\t},\n\tgetFooterStatuses(): boolean {\n\t\treturn activeSettingsManager?.getFooterStatuses() ?? true;\n\t},\n\tgetFooterGit(): boolean {\n\t\treturn activeSettingsManager?.getFooterGit() ?? true;\n\t},\n\tgetFooterPlan(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlan() ?? true;\n\t},\n\tgetFooterPlanBar(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlanBar() ?? true;\n\t},\n\tgetHideThinkingBlock(): boolean {\n\t\treturn activeSettingsManager?.getHideThinkingBlock() ?? false;\n\t},\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tactiveSettingsManager?.setHideThinkingBlock(hide);\n\t},\n};\n\n/**\n * Register (or re-point) the global customize bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerCustomizeBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] = bridge;\n}\n\n/** Read the bridge from `globalThis`, or undefined when not registered (extension-safe). */\nexport function getCustomizeBridge(): CustomizeBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] as CustomizeBridge | undefined;\n}\n"]}
@@ -15,6 +15,9 @@ const bridge = {
15
15
  getPromptSymbol() {
16
16
  return activeSettingsManager?.getPromptSymbol() ?? true;
17
17
  },
18
+ getOpenAIFastMode() {
19
+ return activeSettingsManager?.getOpenAIFastMode() ?? false;
20
+ },
18
21
  getFooterMcp() {
19
22
  return activeSettingsManager?.getFooterMcp() ?? true;
20
23
  },
@@ -27,6 +30,9 @@ const bridge = {
27
30
  getFooterTokens() {
28
31
  return activeSettingsManager?.getFooterTokens() ?? true;
29
32
  },
33
+ getFooterCacheHitRate() {
34
+ return activeSettingsManager?.getFooterCacheHitRate() ?? true;
35
+ },
30
36
  getFooterTps() {
31
37
  return activeSettingsManager?.getFooterTps() ?? true;
32
38
  },
@@ -1 +1 @@
1
- {"version":3,"file":"customize.js","sourceRoot":"","sources":["../../src/core/customize.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAkBrE,IAAI,qBAAkD,CAAC;AAEvD,MAAM,MAAM,GAAoB;IAC/B,aAAa,GAAY;QACxB,OAAO,qBAAqB,EAAE,aAAa,EAAE,IAAI,IAAI,CAAC;IAAA,CACtD;IACD,eAAe,GAAY;QAC1B,OAAO,qBAAqB,EAAE,eAAe,EAAE,IAAI,IAAI,CAAC;IAAA,CACxD;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC;IAAA,CACrD;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,KAAK,CAAC;IAAA,CACtD;IACD,gBAAgB,GAAY;QAC3B,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,IAAI,CAAC;IAAA,CACzD;IACD,eAAe,GAAY;QAC1B,OAAO,qBAAqB,EAAE,eAAe,EAAE,IAAI,IAAI,CAAC;IAAA,CACxD;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC;IAAA,CACrD;IACD,iBAAiB,GAAY;QAC5B,OAAO,qBAAqB,EAAE,iBAAiB,EAAE,IAAI,IAAI,CAAC;IAAA,CAC1D;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC;IAAA,CACrD;IACD,aAAa,GAAY;QACxB,OAAO,qBAAqB,EAAE,aAAa,EAAE,IAAI,IAAI,CAAC;IAAA,CACtD;IACD,gBAAgB,GAAY;QAC3B,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,IAAI,CAAC;IAAA,CACzD;IACD,oBAAoB,GAAY;QAC/B,OAAO,qBAAqB,EAAE,oBAAoB,EAAE,IAAI,KAAK,CAAC;IAAA,CAC9D;IACD,oBAAoB,CAAC,IAAa,EAAQ;QACzC,qBAAqB,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAAA,CAClD;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,eAAgC,EAAQ;IAC/E,qBAAqB,GAAG,eAAe,CAAC;IACvC,UAAsC,CAAC,uBAAuB,CAAC,GAAG,MAAM,CAAC;AAAA,CAC1E;AAED,4FAA4F;AAC5F,MAAM,UAAU,kBAAkB,GAAgC;IACjE,OAAQ,UAAsC,CAAC,uBAAuB,CAAgC,CAAC;AAAA,CACvG","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * lunR TUI customize bridge.\n *\n * Exposed on `globalThis` under `Symbol.for(\"@lunr/customize\")` so the baked-in\n * ashxj-tui extension can read the customize settings (gutter rail, prompt\n * symbol, footer element toggles) without importing core code — same pattern as\n * the model-tiers and memory-cap bridges.\n */\n\nexport const CUSTOMIZE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/customize\");\n\nexport interface CustomizeBridge {\n\tgetGutterRail(): boolean;\n\tgetPromptSymbol(): boolean;\n\tgetFooterMcp(): boolean;\n\tgetFooterLsp(): boolean;\n\tgetFooterContext(): boolean;\n\tgetFooterTokens(): boolean;\n\tgetFooterTps(): boolean;\n\tgetFooterStatuses(): boolean;\n\tgetFooterGit(): boolean;\n\tgetFooterPlan(): boolean;\n\tgetFooterPlanBar(): boolean;\n\tgetHideThinkingBlock(): boolean;\n\tsetHideThinkingBlock(hide: boolean): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: CustomizeBridge = {\n\tgetGutterRail(): boolean {\n\t\treturn activeSettingsManager?.getGutterRail() ?? true;\n\t},\n\tgetPromptSymbol(): boolean {\n\t\treturn activeSettingsManager?.getPromptSymbol() ?? true;\n\t},\n\tgetFooterMcp(): boolean {\n\t\treturn activeSettingsManager?.getFooterMcp() ?? true;\n\t},\n\tgetFooterLsp(): boolean {\n\t\treturn activeSettingsManager?.getFooterLsp() ?? false;\n\t},\n\tgetFooterContext(): boolean {\n\t\treturn activeSettingsManager?.getFooterContext() ?? true;\n\t},\n\tgetFooterTokens(): boolean {\n\t\treturn activeSettingsManager?.getFooterTokens() ?? true;\n\t},\n\tgetFooterTps(): boolean {\n\t\treturn activeSettingsManager?.getFooterTps() ?? true;\n\t},\n\tgetFooterStatuses(): boolean {\n\t\treturn activeSettingsManager?.getFooterStatuses() ?? true;\n\t},\n\tgetFooterGit(): boolean {\n\t\treturn activeSettingsManager?.getFooterGit() ?? true;\n\t},\n\tgetFooterPlan(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlan() ?? true;\n\t},\n\tgetFooterPlanBar(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlanBar() ?? true;\n\t},\n\tgetHideThinkingBlock(): boolean {\n\t\treturn activeSettingsManager?.getHideThinkingBlock() ?? false;\n\t},\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tactiveSettingsManager?.setHideThinkingBlock(hide);\n\t},\n};\n\n/**\n * Register (or re-point) the global customize bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerCustomizeBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] = bridge;\n}\n\n/** Read the bridge from `globalThis`, or undefined when not registered (extension-safe). */\nexport function getCustomizeBridge(): CustomizeBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] as CustomizeBridge | undefined;\n}\n"]}
1
+ {"version":3,"file":"customize.js","sourceRoot":"","sources":["../../src/core/customize.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAoBrE,IAAI,qBAAkD,CAAC;AAEvD,MAAM,MAAM,GAAoB;IAC/B,aAAa,GAAY;QACxB,OAAO,qBAAqB,EAAE,aAAa,EAAE,IAAI,IAAI,CAAC;IAAA,CACtD;IACD,eAAe,GAAY;QAC1B,OAAO,qBAAqB,EAAE,eAAe,EAAE,IAAI,IAAI,CAAC;IAAA,CACxD;IACD,iBAAiB,GAAY;QAC5B,OAAO,qBAAqB,EAAE,iBAAiB,EAAE,IAAI,KAAK,CAAC;IAAA,CAC3D;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC;IAAA,CACrD;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,KAAK,CAAC;IAAA,CACtD;IACD,gBAAgB,GAAY;QAC3B,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,IAAI,CAAC;IAAA,CACzD;IACD,eAAe,GAAY;QAC1B,OAAO,qBAAqB,EAAE,eAAe,EAAE,IAAI,IAAI,CAAC;IAAA,CACxD;IACD,qBAAqB,GAAY;QAChC,OAAO,qBAAqB,EAAE,qBAAqB,EAAE,IAAI,IAAI,CAAC;IAAA,CAC9D;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC;IAAA,CACrD;IACD,iBAAiB,GAAY;QAC5B,OAAO,qBAAqB,EAAE,iBAAiB,EAAE,IAAI,IAAI,CAAC;IAAA,CAC1D;IACD,YAAY,GAAY;QACvB,OAAO,qBAAqB,EAAE,YAAY,EAAE,IAAI,IAAI,CAAC;IAAA,CACrD;IACD,aAAa,GAAY;QACxB,OAAO,qBAAqB,EAAE,aAAa,EAAE,IAAI,IAAI,CAAC;IAAA,CACtD;IACD,gBAAgB,GAAY;QAC3B,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,IAAI,CAAC;IAAA,CACzD;IACD,oBAAoB,GAAY;QAC/B,OAAO,qBAAqB,EAAE,oBAAoB,EAAE,IAAI,KAAK,CAAC;IAAA,CAC9D;IACD,oBAAoB,CAAC,IAAa,EAAQ;QACzC,qBAAqB,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAAA,CAClD;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,eAAgC,EAAQ;IAC/E,qBAAqB,GAAG,eAAe,CAAC;IACvC,UAAsC,CAAC,uBAAuB,CAAC,GAAG,MAAM,CAAC;AAAA,CAC1E;AAED,4FAA4F;AAC5F,MAAM,UAAU,kBAAkB,GAAgC;IACjE,OAAQ,UAAsC,CAAC,uBAAuB,CAAgC,CAAC;AAAA,CACvG","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * lunR TUI customize bridge.\n *\n * Exposed on `globalThis` under `Symbol.for(\"@lunr/customize\")` so the baked-in\n * ashxj-tui extension can read the customize settings (gutter rail, prompt\n * symbol, footer element toggles) without importing core code — same pattern as\n * the model-tiers and memory-cap bridges.\n */\n\nexport const CUSTOMIZE_BRIDGE_SYMBOL = Symbol.for(\"@lunr/customize\");\n\nexport interface CustomizeBridge {\n\tgetGutterRail(): boolean;\n\tgetPromptSymbol(): boolean;\n\tgetOpenAIFastMode(): boolean;\n\tgetFooterMcp(): boolean;\n\tgetFooterLsp(): boolean;\n\tgetFooterContext(): boolean;\n\tgetFooterTokens(): boolean;\n\tgetFooterCacheHitRate(): boolean;\n\tgetFooterTps(): boolean;\n\tgetFooterStatuses(): boolean;\n\tgetFooterGit(): boolean;\n\tgetFooterPlan(): boolean;\n\tgetFooterPlanBar(): boolean;\n\tgetHideThinkingBlock(): boolean;\n\tsetHideThinkingBlock(hide: boolean): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: CustomizeBridge = {\n\tgetGutterRail(): boolean {\n\t\treturn activeSettingsManager?.getGutterRail() ?? true;\n\t},\n\tgetPromptSymbol(): boolean {\n\t\treturn activeSettingsManager?.getPromptSymbol() ?? true;\n\t},\n\tgetOpenAIFastMode(): boolean {\n\t\treturn activeSettingsManager?.getOpenAIFastMode() ?? false;\n\t},\n\tgetFooterMcp(): boolean {\n\t\treturn activeSettingsManager?.getFooterMcp() ?? true;\n\t},\n\tgetFooterLsp(): boolean {\n\t\treturn activeSettingsManager?.getFooterLsp() ?? false;\n\t},\n\tgetFooterContext(): boolean {\n\t\treturn activeSettingsManager?.getFooterContext() ?? true;\n\t},\n\tgetFooterTokens(): boolean {\n\t\treturn activeSettingsManager?.getFooterTokens() ?? true;\n\t},\n\tgetFooterCacheHitRate(): boolean {\n\t\treturn activeSettingsManager?.getFooterCacheHitRate() ?? true;\n\t},\n\tgetFooterTps(): boolean {\n\t\treturn activeSettingsManager?.getFooterTps() ?? true;\n\t},\n\tgetFooterStatuses(): boolean {\n\t\treturn activeSettingsManager?.getFooterStatuses() ?? true;\n\t},\n\tgetFooterGit(): boolean {\n\t\treturn activeSettingsManager?.getFooterGit() ?? true;\n\t},\n\tgetFooterPlan(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlan() ?? true;\n\t},\n\tgetFooterPlanBar(): boolean {\n\t\treturn activeSettingsManager?.getFooterPlanBar() ?? true;\n\t},\n\tgetHideThinkingBlock(): boolean {\n\t\treturn activeSettingsManager?.getHideThinkingBlock() ?? false;\n\t},\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tactiveSettingsManager?.setHideThinkingBlock(hide);\n\t},\n};\n\n/**\n * Register (or re-point) the global customize bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerCustomizeBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] = bridge;\n}\n\n/** Read the bridge from `globalThis`, or undefined when not registered (extension-safe). */\nexport function getCustomizeBridge(): CustomizeBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[CUSTOMIZE_BRIDGE_SYMBOL] as CustomizeBridge | undefined;\n}\n"]}
@@ -1,17 +1,12 @@
1
1
  import type { SettingsManager } from "./settings-manager.ts";
2
- /**
3
- * simple-pi-memory character-cap bridge.
4
- *
5
- * The bridge is exposed on `globalThis` under `Symbol.for("@lunr/memory-cap")` so
6
- * the baked-in simple-pi-memory extension can read/write the cap from lunR
7
- * settings instead of its legacy `~/.pi/simple-memory/config.json` — without
8
- * importing core code (same pattern as the model-tiers bridge).
9
- */
2
+ /** Memory settings shared with the baked-in simple-memory extension. */
10
3
  export declare const MEMORY_CAP_BRIDGE_SYMBOL: unique symbol;
11
4
  export declare const MEMORY_CHAR_CAP_DEFAULT = 5000;
12
5
  export declare const MEMORY_CHAR_CAP_MIN = 1;
13
6
  export declare const MEMORY_CHAR_CAP_MAX = 30000;
7
+ export declare const MEMORY_TOOL_NAMES: Set<string>;
14
8
  export interface MemoryCapBridge {
9
+ isEnabled(): boolean;
15
10
  /** Current character cap (clamped to 1..30000). */
16
11
  getCharCap(): number;
17
12
  /** Persist a new character cap into lunR settings. */
@@ -24,4 +19,5 @@ export interface MemoryCapBridge {
24
19
  * runtime settings manager.
25
20
  */
26
21
  export declare function registerMemoryCapBridge(settingsManager: SettingsManager): void;
22
+ export declare function getMemoryCapBridge(): MemoryCapBridge | undefined;
27
23
  //# sourceMappingURL=memory-cap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-cap.d.ts","sourceRoot":"","sources":["../../src/core/memory-cap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;GAOG;AAEH,eAAO,MAAM,wBAAwB,eAAiC,CAAC;AAEvE,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC/B,mDAAmD;IACnD,UAAU,IAAI,MAAM,CAAC;IACrB,sDAAsD;IACtD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAaD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAG9E","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * simple-pi-memory character-cap bridge.\n *\n * The bridge is exposed on `globalThis` under `Symbol.for(\"@lunr/memory-cap\")` so\n * the baked-in simple-pi-memory extension can read/write the cap from lunR\n * settings instead of its legacy `~/.pi/simple-memory/config.json` — without\n * importing core code (same pattern as the model-tiers bridge).\n */\n\nexport const MEMORY_CAP_BRIDGE_SYMBOL = Symbol.for(\"@lunr/memory-cap\");\n\nexport const MEMORY_CHAR_CAP_DEFAULT = 5000;\nexport const MEMORY_CHAR_CAP_MIN = 1;\nexport const MEMORY_CHAR_CAP_MAX = 30000;\n\nexport interface MemoryCapBridge {\n\t/** Current character cap (clamped to 1..30000). */\n\tgetCharCap(): number;\n\t/** Persist a new character cap into lunR settings. */\n\tsetCharCap(cap: number): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: MemoryCapBridge = {\n\tgetCharCap(): number {\n\t\treturn activeSettingsManager?.getMemoryCharCap() ?? MEMORY_CHAR_CAP_DEFAULT;\n\t},\n\tsetCharCap(cap: number): void {\n\t\tactiveSettingsManager?.setMemoryCharCap(cap);\n\t},\n};\n\n/**\n * Register (or re-point) the global memory-cap bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerMemoryCapBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[MEMORY_CAP_BRIDGE_SYMBOL] = bridge;\n}\n"]}
1
+ {"version":3,"file":"memory-cap.d.ts","sourceRoot":"","sources":["../../src/core/memory-cap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,wEAAwE;AAExE,eAAO,MAAM,wBAAwB,eAAiC,CAAC;AAEvE,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAC5C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AACzC,eAAO,MAAM,iBAAiB,aAA0D,CAAC;AAEzF,MAAM,WAAW,eAAe;IAC/B,SAAS,IAAI,OAAO,CAAC;IACrB,mDAAmD;IACnD,UAAU,IAAI,MAAM,CAAC;IACrB,sDAAsD;IACtD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAgBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI,CAG9E;AAED,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,SAAS,CAEhE","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/** Memory settings shared with the baked-in simple-memory extension. */\n\nexport const MEMORY_CAP_BRIDGE_SYMBOL = Symbol.for(\"@lunr/memory-cap\");\n\nexport const MEMORY_CHAR_CAP_DEFAULT = 5000;\nexport const MEMORY_CHAR_CAP_MIN = 1;\nexport const MEMORY_CHAR_CAP_MAX = 30000;\nexport const MEMORY_TOOL_NAMES = new Set([\"memory_add\", \"memory_remove\", \"memory_load\"]);\n\nexport interface MemoryCapBridge {\n\tisEnabled(): boolean;\n\t/** Current character cap (clamped to 1..30000). */\n\tgetCharCap(): number;\n\t/** Persist a new character cap into lunR settings. */\n\tsetCharCap(cap: number): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: MemoryCapBridge = {\n\tisEnabled(): boolean {\n\t\treturn activeSettingsManager?.getMemoryEnabled() ?? true;\n\t},\n\tgetCharCap(): number {\n\t\treturn activeSettingsManager?.getMemoryCharCap() ?? MEMORY_CHAR_CAP_DEFAULT;\n\t},\n\tsetCharCap(cap: number): void {\n\t\tactiveSettingsManager?.setMemoryCharCap(cap);\n\t},\n};\n\n/**\n * Register (or re-point) the global memory-cap bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerMemoryCapBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[MEMORY_CAP_BRIDGE_SYMBOL] = bridge;\n}\n\nexport function getMemoryCapBridge(): MemoryCapBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[MEMORY_CAP_BRIDGE_SYMBOL] as MemoryCapBridge | undefined;\n}\n"]}
@@ -1,17 +1,14 @@
1
- /**
2
- * simple-pi-memory character-cap bridge.
3
- *
4
- * The bridge is exposed on `globalThis` under `Symbol.for("@lunr/memory-cap")` so
5
- * the baked-in simple-pi-memory extension can read/write the cap from lunR
6
- * settings instead of its legacy `~/.pi/simple-memory/config.json` — without
7
- * importing core code (same pattern as the model-tiers bridge).
8
- */
1
+ /** Memory settings shared with the baked-in simple-memory extension. */
9
2
  export const MEMORY_CAP_BRIDGE_SYMBOL = Symbol.for("@lunr/memory-cap");
10
3
  export const MEMORY_CHAR_CAP_DEFAULT = 5000;
11
4
  export const MEMORY_CHAR_CAP_MIN = 1;
12
5
  export const MEMORY_CHAR_CAP_MAX = 30000;
6
+ export const MEMORY_TOOL_NAMES = new Set(["memory_add", "memory_remove", "memory_load"]);
13
7
  let activeSettingsManager;
14
8
  const bridge = {
9
+ isEnabled() {
10
+ return activeSettingsManager?.getMemoryEnabled() ?? true;
11
+ },
15
12
  getCharCap() {
16
13
  return activeSettingsManager?.getMemoryCharCap() ?? MEMORY_CHAR_CAP_DEFAULT;
17
14
  },
@@ -29,4 +26,7 @@ export function registerMemoryCapBridge(settingsManager) {
29
26
  activeSettingsManager = settingsManager;
30
27
  globalThis[MEMORY_CAP_BRIDGE_SYMBOL] = bridge;
31
28
  }
29
+ export function getMemoryCapBridge() {
30
+ return globalThis[MEMORY_CAP_BRIDGE_SYMBOL];
31
+ }
32
32
  //# sourceMappingURL=memory-cap.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-cap.js","sourceRoot":"","sources":["../../src/core/memory-cap.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AASzC,IAAI,qBAAkD,CAAC;AAEvD,MAAM,MAAM,GAAoB;IAC/B,UAAU,GAAW;QACpB,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,uBAAuB,CAAC;IAAA,CAC5E;IACD,UAAU,CAAC,GAAW,EAAQ;QAC7B,qBAAqB,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAAA,CAC7C;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,eAAgC,EAAQ;IAC/E,qBAAqB,GAAG,eAAe,CAAC;IACvC,UAAsC,CAAC,wBAAwB,CAAC,GAAG,MAAM,CAAC;AAAA,CAC3E","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/**\n * simple-pi-memory character-cap bridge.\n *\n * The bridge is exposed on `globalThis` under `Symbol.for(\"@lunr/memory-cap\")` so\n * the baked-in simple-pi-memory extension can read/write the cap from lunR\n * settings instead of its legacy `~/.pi/simple-memory/config.json` — without\n * importing core code (same pattern as the model-tiers bridge).\n */\n\nexport const MEMORY_CAP_BRIDGE_SYMBOL = Symbol.for(\"@lunr/memory-cap\");\n\nexport const MEMORY_CHAR_CAP_DEFAULT = 5000;\nexport const MEMORY_CHAR_CAP_MIN = 1;\nexport const MEMORY_CHAR_CAP_MAX = 30000;\n\nexport interface MemoryCapBridge {\n\t/** Current character cap (clamped to 1..30000). */\n\tgetCharCap(): number;\n\t/** Persist a new character cap into lunR settings. */\n\tsetCharCap(cap: number): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: MemoryCapBridge = {\n\tgetCharCap(): number {\n\t\treturn activeSettingsManager?.getMemoryCharCap() ?? MEMORY_CHAR_CAP_DEFAULT;\n\t},\n\tsetCharCap(cap: number): void {\n\t\tactiveSettingsManager?.setMemoryCharCap(cap);\n\t},\n};\n\n/**\n * Register (or re-point) the global memory-cap bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerMemoryCapBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[MEMORY_CAP_BRIDGE_SYMBOL] = bridge;\n}\n"]}
1
+ {"version":3,"file":"memory-cap.js","sourceRoot":"","sources":["../../src/core/memory-cap.ts"],"names":[],"mappings":"AAEA,wEAAwE;AAExE,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AACzC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC,CAAC;AAUzF,IAAI,qBAAkD,CAAC;AAEvD,MAAM,MAAM,GAAoB;IAC/B,SAAS,GAAY;QACpB,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,IAAI,CAAC;IAAA,CACzD;IACD,UAAU,GAAW;QACpB,OAAO,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,uBAAuB,CAAC;IAAA,CAC5E;IACD,UAAU,CAAC,GAAW,EAAQ;QAC7B,qBAAqB,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAAA,CAC7C;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,eAAgC,EAAQ;IAC/E,qBAAqB,GAAG,eAAe,CAAC;IACvC,UAAsC,CAAC,wBAAwB,CAAC,GAAG,MAAM,CAAC;AAAA,CAC3E;AAED,MAAM,UAAU,kBAAkB,GAAgC;IACjE,OAAQ,UAAsC,CAAC,wBAAwB,CAAgC,CAAC;AAAA,CACxG","sourcesContent":["import type { SettingsManager } from \"./settings-manager.ts\";\n\n/** Memory settings shared with the baked-in simple-memory extension. */\n\nexport const MEMORY_CAP_BRIDGE_SYMBOL = Symbol.for(\"@lunr/memory-cap\");\n\nexport const MEMORY_CHAR_CAP_DEFAULT = 5000;\nexport const MEMORY_CHAR_CAP_MIN = 1;\nexport const MEMORY_CHAR_CAP_MAX = 30000;\nexport const MEMORY_TOOL_NAMES = new Set([\"memory_add\", \"memory_remove\", \"memory_load\"]);\n\nexport interface MemoryCapBridge {\n\tisEnabled(): boolean;\n\t/** Current character cap (clamped to 1..30000). */\n\tgetCharCap(): number;\n\t/** Persist a new character cap into lunR settings. */\n\tsetCharCap(cap: number): void;\n}\n\nlet activeSettingsManager: SettingsManager | undefined;\n\nconst bridge: MemoryCapBridge = {\n\tisEnabled(): boolean {\n\t\treturn activeSettingsManager?.getMemoryEnabled() ?? true;\n\t},\n\tgetCharCap(): number {\n\t\treturn activeSettingsManager?.getMemoryCharCap() ?? MEMORY_CHAR_CAP_DEFAULT;\n\t},\n\tsetCharCap(cap: number): void {\n\t\tactiveSettingsManager?.setMemoryCharCap(cap);\n\t},\n};\n\n/**\n * Register (or re-point) the global memory-cap bridge.\n * Safe to call multiple times — later calls only swap the settings source, so an\n * early startup registration (before extensions load) can be replaced by the live\n * runtime settings manager.\n */\nexport function registerMemoryCapBridge(settingsManager: SettingsManager): void {\n\tactiveSettingsManager = settingsManager;\n\t(globalThis as Record<symbol, unknown>)[MEMORY_CAP_BRIDGE_SYMBOL] = bridge;\n}\n\nexport function getMemoryCapBridge(): MemoryCapBridge | undefined {\n\treturn (globalThis as Record<symbol, unknown>)[MEMORY_CAP_BRIDGE_SYMBOL] as MemoryCapBridge | undefined;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"models-store.d.ts","sourceRoot":"","sources":["../../src/core/models-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAM3E,qBAAa,8BAA+B,YAAW,WAAW;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAEzD,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAEpE;IAEK,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;IAEK,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9C;CACD;AAED,8EAA8E;AAC9E,qBAAa,eAAgB,YAAW,WAAW;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C,YAAY,IAAI,GAAE,MAAiD,EAElE;IAED,OAAO,CAAC,KAAK;IAIP,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAIpE;IAEK,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE;IAEK,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9C;CACD","sourcesContent":["import { join } from \"node:path\";\nimport type { ModelsStore, ModelsStoreEntry } from \"@ashx-j/lunr-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { type AuthStorageBackend, FileAuthStorageBackend } from \"./auth-storage.ts\";\n\ntype StoredModels = Record<string, ModelsStoreEntry>;\n\nexport class InMemoryCodingAgentModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.entries.get(providerId);\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tthis.entries.set(providerId, entry);\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tthis.entries.delete(providerId);\n\t}\n}\n\n/** Locked JSON-backed storage for dynamically refreshed provider catalogs. */\nexport class FileModelsStore implements ModelsStore {\n\tprivate readonly storage: AuthStorageBackend;\n\n\tconstructor(path: string = join(getAgentDir(), \"models-store.json\")) {\n\t\tthis.storage = new FileAuthStorageBackend(path);\n\t}\n\n\tprivate parse(content: string | undefined): StoredModels {\n\t\treturn content ? (JSON.parse(content) as StoredModels) : {};\n\t}\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.storage.withLock((content) => ({\n\t\t\tresult: structuredClone(this.parse(content)[providerId]),\n\t\t}));\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tcurrent[providerId] = structuredClone(entry);\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tdelete current[providerId];\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"models-store.d.ts","sourceRoot":"","sources":["../../src/core/models-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAM3E,qBAAa,8BAA+B,YAAW,WAAW;IACjE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAEzD,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAEpE;IAEK,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;IAEK,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9C;CACD;AAED,8EAA8E;AAC9E,qBAAa,eAAgB,YAAW,WAAW;IAClD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAE7C,YAAY,IAAI,GAAE,MAAiD,EAElE;IAED,OAAO,CAAC,KAAK;IAaP,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAIpE;IAEK,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE;IAEK,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9C;CACD","sourcesContent":["import { join } from \"node:path\";\nimport type { ModelsStore, ModelsStoreEntry } from \"@ashx-j/lunr-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { type AuthStorageBackend, FileAuthStorageBackend } from \"./auth-storage.ts\";\n\ntype StoredModels = Record<string, ModelsStoreEntry>;\n\nexport class InMemoryCodingAgentModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.entries.get(providerId);\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tthis.entries.set(providerId, entry);\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tthis.entries.delete(providerId);\n\t}\n}\n\n/** Locked JSON-backed storage for dynamically refreshed provider catalogs. */\nexport class FileModelsStore implements ModelsStore {\n\tprivate readonly storage: AuthStorageBackend;\n\n\tconstructor(path: string = join(getAgentDir(), \"models-store.json\")) {\n\t\tthis.storage = new FileAuthStorageBackend(path);\n\t}\n\n\tprivate parse(content: string | undefined): StoredModels {\n\t\tconst trimmed = content?.replace(/^\\uFEFF/, \"\").trim();\n\t\tif (!trimmed) return {};\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(trimmed) as unknown;\n\t\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n\t\t\treturn parsed as StoredModels;\n\t\t} catch {\n\t\t\t// Mid-write / power-loss can leave NULs or truncated JSON.\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.storage.withLock((content) => ({\n\t\t\tresult: structuredClone(this.parse(content)[providerId]),\n\t\t}));\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tcurrent[providerId] = structuredClone(entry);\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tdelete current[providerId];\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n}\n"]}
@@ -20,7 +20,19 @@ export class FileModelsStore {
20
20
  this.storage = new FileAuthStorageBackend(path);
21
21
  }
22
22
  parse(content) {
23
- return content ? JSON.parse(content) : {};
23
+ const trimmed = content?.replace(/^\uFEFF/, "").trim();
24
+ if (!trimmed)
25
+ return {};
26
+ try {
27
+ const parsed = JSON.parse(trimmed);
28
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
29
+ return {};
30
+ return parsed;
31
+ }
32
+ catch {
33
+ // Mid-write / power-loss can leave NULs or truncated JSON.
34
+ return {};
35
+ }
24
36
  }
25
37
  async read(providerId) {
26
38
  return this.storage.withLock((content) => ({
@@ -1 +1 @@
1
- {"version":3,"file":"models-store.js","sourceRoot":"","sources":["../../src/core/models-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAA2B,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAIpF,MAAM,OAAO,8BAA8B;IACzB,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IAE/D,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAyC;QACrE,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAAA,CACpC;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,KAAuB,EAAiB;QACvE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAAA,CACpC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAiB;QAC/C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAAA,CAChC;CACD;AAED,8EAA8E;AAC9E,MAAM,OAAO,eAAe;IACV,OAAO,CAAqB;IAE7C,YAAY,IAAI,GAAW,IAAI,CAAC,WAAW,EAAE,EAAE,mBAAmB,CAAC,EAAE;QACpE,IAAI,CAAC,OAAO,GAAG,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAAA,CAChD;IAEO,KAAK,CAAC,OAA2B,EAAgB;QACxD,OAAO,OAAO,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IAAA,CAC5D;IAED,KAAK,CAAC,IAAI,CAAC,UAAkB,EAAyC;QACrE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC1C,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;SACxD,CAAC,CAAC,CAAC;IAAA,CACJ;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,KAAuB,EAAiB;QACvE,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YACnD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpC,OAAO,CAAC,UAAU,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;YAC7C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAAA,CACrE,CAAC,CAAC;IAAA,CACH;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB,EAAiB;QAC/C,MAAM,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC;YACnD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpC,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;YAC3B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QAAA,CACrE,CAAC,CAAC;IAAA,CACH;CACD","sourcesContent":["import { join } from \"node:path\";\nimport type { ModelsStore, ModelsStoreEntry } from \"@ashx-j/lunr-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { type AuthStorageBackend, FileAuthStorageBackend } from \"./auth-storage.ts\";\n\ntype StoredModels = Record<string, ModelsStoreEntry>;\n\nexport class InMemoryCodingAgentModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.entries.get(providerId);\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tthis.entries.set(providerId, entry);\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tthis.entries.delete(providerId);\n\t}\n}\n\n/** Locked JSON-backed storage for dynamically refreshed provider catalogs. */\nexport class FileModelsStore implements ModelsStore {\n\tprivate readonly storage: AuthStorageBackend;\n\n\tconstructor(path: string = join(getAgentDir(), \"models-store.json\")) {\n\t\tthis.storage = new FileAuthStorageBackend(path);\n\t}\n\n\tprivate parse(content: string | undefined): StoredModels {\n\t\treturn content ? (JSON.parse(content) as StoredModels) : {};\n\t}\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.storage.withLock((content) => ({\n\t\t\tresult: structuredClone(this.parse(content)[providerId]),\n\t\t}));\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tcurrent[providerId] = structuredClone(entry);\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tdelete current[providerId];\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"models-store.js","sourceRoot":"","sources":["../../src/core/models-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport type { ModelsStore, ModelsStoreEntry } from \"@ashx-j/lunr-ai\";\nimport { getAgentDir } from \"../config.ts\";\nimport { type AuthStorageBackend, FileAuthStorageBackend } from \"./auth-storage.ts\";\n\ntype StoredModels = Record<string, ModelsStoreEntry>;\n\nexport class InMemoryCodingAgentModelsStore implements ModelsStore {\n\tprivate readonly entries = new Map<string, ModelsStoreEntry>();\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.entries.get(providerId);\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tthis.entries.set(providerId, entry);\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tthis.entries.delete(providerId);\n\t}\n}\n\n/** Locked JSON-backed storage for dynamically refreshed provider catalogs. */\nexport class FileModelsStore implements ModelsStore {\n\tprivate readonly storage: AuthStorageBackend;\n\n\tconstructor(path: string = join(getAgentDir(), \"models-store.json\")) {\n\t\tthis.storage = new FileAuthStorageBackend(path);\n\t}\n\n\tprivate parse(content: string | undefined): StoredModels {\n\t\tconst trimmed = content?.replace(/^\\uFEFF/, \"\").trim();\n\t\tif (!trimmed) return {};\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(trimmed) as unknown;\n\t\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return {};\n\t\t\treturn parsed as StoredModels;\n\t\t} catch {\n\t\t\t// Mid-write / power-loss can leave NULs or truncated JSON.\n\t\t\treturn {};\n\t\t}\n\t}\n\n\tasync read(providerId: string): Promise<ModelsStoreEntry | undefined> {\n\t\treturn this.storage.withLock((content) => ({\n\t\t\tresult: structuredClone(this.parse(content)[providerId]),\n\t\t}));\n\t}\n\n\tasync write(providerId: string, entry: ModelsStoreEntry): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tcurrent[providerId] = structuredClone(entry);\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n\n\tasync delete(providerId: string): Promise<void> {\n\t\tawait this.storage.withLockAsync(async (content) => {\n\t\t\tconst current = this.parse(content);\n\t\t\tdelete current[providerId];\n\t\t\treturn { result: undefined, next: JSON.stringify(current, null, 2) };\n\t\t});\n\t}\n}\n"]}
@@ -80,10 +80,21 @@ export declare function clearSessionApprovals(sessionId?: string): void;
80
80
  export declare function resetAllPermissionContexts(): void;
81
81
  /** Appended to the system prompt while auto mode is active. */
82
82
  export declare const AUTO_MODE_ADDENDUM = "You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.";
83
+ export declare const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON = "The global AGENTS.md file is user-managed. The agent cannot change ~/.lunr/agent/AGENTS.md.";
84
+ export declare const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON = "Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.";
83
85
  export interface GateOptions {
84
86
  /** True when the current turn started from an explicit /swarm prompt — the
85
87
  * user already asked for the swarm, so the swarm approval gate is skipped. */
86
88
  explicitSwarmTurn?: boolean;
89
+ /** Assistant message that issued this tool call. Same-turn sibling SINGLE
90
+ * `subagent` calls count toward the swarm threshold. */
91
+ assistantMessage?: {
92
+ content?: ReadonlyArray<{
93
+ type?: string;
94
+ name?: string;
95
+ arguments?: unknown;
96
+ }>;
97
+ };
87
98
  }
88
99
  /**
89
100
  * Returns a block result when the tool call should be blocked, else undefined.
@@ -1 +1 @@
1
- {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: permission modes (Manual / YOLO / Plan / Auto).\n *\n * Per-session only — never persisted per session, but the default mode new\n * sessions start with is configurable in /settings (`defaultPermissionMode`,\n * default \"manual\").\n *\n * - manual: every mutating tool call (bash, edit, write) requires approval.\n * - yolo: auto-approve tools; the agent may still ask questions.\n * - plan: read-only; mutating tools are hard-blocked (planModeBlockReason).\n * - auto: fully autonomous; a system-prompt addendum steers the model to\n * self-decide, and rollback is force-enabled for the session.\n *\n * The gate is wired into `agent-session.ts` `_installAgentToolHooks` before\n * the synchronous `_toolCallGates` loop. beforeToolCall is already async, so\n * awaiting the approval dialog is fine.\n *\n * State (mode + session-scoped approvals) is keyed by session id so\n * concurrent gateway chats do not share permission decisions.\n */\n\nimport { resolve } from \"node:path\";\nimport { planModeBlockReason } from \"./plan-mode.ts\";\nimport { effectiveSwarmCount, SWARM_APPROVAL_THRESHOLD } from \"./swarm.ts\";\n\n/** Shift+Tab cycle order. */\nexport const PERMISSION_MODES = [\"manual\", \"yolo\", \"plan\", \"auto\"] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\nexport function nextPermissionMode(current: PermissionMode): PermissionMode {\n\tconst i = PERMISSION_MODES.indexOf(current);\n\treturn PERMISSION_MODES[(i + 1) % PERMISSION_MODES.length];\n}\n\n/** True when the (default or session) permission mode is plan. */\nexport function isPlanModeActive(sessionId?: string): boolean {\n\treturn getPermissionMode(sessionId) === \"plan\";\n}\n\n/**\n * Destination mode when leaving plan via approve / `/plan off` / `/plan <text>`.\n * Explicit Shift+Tab or `/mode` picks do not use this — they already chose a mode.\n */\nexport function restorePermissionModeAfterPlan(\n\tprevious: PermissionMode | undefined,\n\tdefaultMode: PermissionMode,\n): PermissionMode {\n\tif (previous && previous !== \"plan\") return previous;\n\treturn defaultMode === \"plan\" ? \"yolo\" : defaultMode;\n}\n\nexport interface ApprovalRequest {\n\ttoolName: string;\n\t/** \"bash\" (detail = command), \"edit\"/\"write\" (detail = path),\n\t * \"edit-outside\"/\"write-outside\" when path escapes cwd,\n\t * \"swarm\" for auto-activated agent swarms (detail = summary lines). */\n\taction: string;\n\tdetail: string;\n\t/** \"swarm\" when this is the agent-swarm approval prompt, \"plan\" for the\n\t * present_plan plan-approval prompt — the UI renders a dedicated dialog\n\t * for each instead of the generic tool dialog. */\n\tkind?: \"swarm\" | \"plan\";\n}\n\nexport type ApprovalDecision = \"once\" | \"session\" | \"reject\";\n/** Handlers may return a bare decision string, a reject carrying user feedback\n * that becomes the block reason the model sees, or an approve carrying optional\n * feedback (plan approval with comments). */\nexport type ApprovalResponse =\n\t| ApprovalDecision\n\t| { decision: \"reject\"; feedback: string }\n\t| { decision: \"approve\"; feedback?: string };\n\n/** Read-only tools that never need approval. */\nconst READ_ONLY_TOOLS = new Set([\n\t\"read\",\n\t\"grep\",\n\t\"find\",\n\t\"ls\",\n\t\"web_search\",\n\t\"web_fetch\",\n\t\"fetch_content\",\n\t\"get_search_content\",\n\t\"sourcegraph\",\n\t\"repo_map\",\n\t\"symbol_outline\",\n\t\"read_block\",\n\t\"code_overview\",\n\t\"ast_search\",\n\t\"lsp_diagnostics\",\n\t\"lsp_hover\",\n\t\"lsp_definition\",\n\t\"lsp_references\",\n\t\"lsp_symbols\",\n\t\"lsp_code_actions\",\n\t\"lsp_completions\",\n\t\"behavior_load\",\n\t\"memory_load\",\n]);\n\n/** Tools that mutate state and must be gated in manual mode. */\nconst MUTATING_TOOLS = new Set([\n\t\"bash\",\n\t\"edit\",\n\t\"write\",\n\t\"behavior_add\",\n\t\"behavior_remove\",\n\t\"memory_add\",\n\t\"memory_remove\",\n\t\"cron\",\n]);\n\nconst REJECT_REASON = \"Rejected by user (permission mode: manual).\";\nexport const NO_HANDLER_REASON = \"Mutating tool blocked in manual mode: no approval channel available.\";\nexport const SWARM_REJECT_REASON = \"Agent swarm rejected by user.\";\nexport const NO_SWARM_HANDLER_REASON = \"Agent swarm blocked: no approval channel available.\";\n/** Session-approval key for auto-activated agent swarms. */\nconst SWARM_ACTION = \"swarm\";\n\ninterface PermissionContext {\n\tmode: PermissionMode;\n\tapprovals: Set<string>;\n}\n\nconst contexts = new Map<string, PermissionContext>();\nlet defaultContext: PermissionContext = { mode: \"manual\", approvals: new Set() };\nlet approvalHandler: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined;\n\nfunction getContext(sessionId?: string): PermissionContext {\n\tif (!sessionId) return defaultContext;\n\treturn contexts.get(sessionId) ?? defaultContext;\n}\n\nexport function createPermissionContext(sessionId: string, mode: PermissionMode = defaultContext.mode): void {\n\tcontexts.set(sessionId, { mode, approvals: new Set() });\n}\n\nexport function deletePermissionContext(sessionId: string): void {\n\tcontexts.delete(sessionId);\n}\n\nexport function getPermissionMode(sessionId?: string): PermissionMode {\n\treturn getContext(sessionId).mode;\n}\n\nexport function setPermissionMode(mode: PermissionMode, sessionId?: string): void {\n\tgetContext(sessionId).mode = mode;\n}\n\nexport function resetPermissions(defaultMode: PermissionMode = \"manual\", sessionId?: string): void {\n\tif (sessionId) {\n\t\tcontexts.set(sessionId, { mode: defaultMode, approvals: new Set() });\n\t} else {\n\t\tdefaultContext = { mode: defaultMode, approvals: new Set() };\n\t}\n}\n\nexport function registerApprovalHandler(fn: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined): void {\n\tapprovalHandler = fn;\n}\n\n/** Model-facing result texts for the present_plan tool. */\nexport const PLAN_APPROVED_TEXT = \"Plan approved — implement it now.\";\nexport const PLAN_DECLINED_TEXT = \"Plan declined — revise the plan and call present_plan again.\";\nexport const PLAN_PASS_THROUGH_TEXT = \"Plan presented. The user will review and reply.\";\n\n/** lunr: map an approval response to the model-facing present_plan result text. */\nexport function planApprovalResultText(resp: ApprovalResponse): string {\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (decision === \"reject\") {\n\t\treturn feedback\n\t\t\t? `Plan declined: ${feedback} — revise the plan and call present_plan again.`\n\t\t\t: PLAN_DECLINED_TEXT;\n\t}\n\treturn feedback ? `Plan approved with feedback: ${feedback} — implement it now.` : PLAN_APPROVED_TEXT;\n}\n\n/**\n * lunr: present_plan approval request. Unlike the mutating-tool and swarm gates\n * this fails OPEN when no approval handler is registered (or none is reachable,\n * e.g. a gateway turn without a chat context): headless sessions have no one to\n * show the dialog to, so the plan is presented and the user replies in chat\n * instead of deadlocking the turn. Everything else keeps fail-closed.\n */\nexport async function requestPlanApproval(summary: string): Promise<string> {\n\tif (!approvalHandler) return PLAN_PASS_THROUGH_TEXT;\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName: \"present_plan\", action: \"plan\", detail: summary, kind: \"plan\" });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"approval request failed\";\n\t\tif (message === NO_HANDLER_REASON) return PLAN_PASS_THROUGH_TEXT;\n\t\treturn `Plan declined: ${message} — revise the plan and call present_plan again.`;\n\t}\n\treturn planApprovalResultText(resp);\n}\n\nexport function clearSessionApprovals(sessionId?: string): void {\n\tgetContext(sessionId).approvals.clear();\n}\n\n/** Test seam: remove every per-session context and restore the default. */\nexport function resetAllPermissionContexts(): void {\n\tcontexts.clear();\n\tdefaultContext = { mode: \"manual\", approvals: new Set() };\n\tapprovalHandler = undefined;\n}\n\n/** Appended to the system prompt while auto mode is active. */\nexport const AUTO_MODE_ADDENDUM =\n\t\"You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.\";\n\nfunction isPathOutsideCwd(absPath: string, cwd: string): boolean {\n\tconst norm = (p: string) => p.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\tconst np = norm(absPath);\n\tconst nc = norm(cwd);\n\tif (np === nc) return false;\n\treturn !np.startsWith(`${nc}/`);\n}\n\nfunction resolvePath(cwd: string, p: unknown): string {\n\tif (typeof p !== \"string\") return \"\";\n\tif (!p) return \"\";\n\treturn resolve(cwd, p);\n}\n\nfunction isMutatingTool(toolName: string): boolean {\n\treturn MUTATING_TOOLS.has(toolName);\n}\n\nexport interface GateOptions {\n\t/** True when the current turn started from an explicit /swarm prompt — the\n\t * user already asked for the swarm, so the swarm approval gate is skipped. */\n\texplicitSwarmTurn?: boolean;\n}\n\n/** First task text of a parallel fan-out, used as the dialog summary line. */\nfunction swarmTaskSummary(input: Record<string, unknown>): string {\n\tif (!Array.isArray(input.tasks)) return \"\";\n\tfor (const task of input.tasks) {\n\t\tconst text = task && typeof task === \"object\" ? (task as { task?: unknown }).task : undefined;\n\t\tif (typeof text === \"string\" && text.trim()) return sanitizeDetail(text);\n\t}\n\treturn \"\";\n}\n\n/**\n * Agent-swarm gate. An auto-activated swarm (one `subagent` call launching more\n * than SWARM_APPROVAL_THRESHOLD parallel subagents) requires user approval in\n * manual AND yolo modes; auto mode runs it unconditionally and explicit /swarm\n * turns are pre-approved. Fail-closed without an approval handler, same as the\n * mutating-tool gate.\n */\nasync function gateSwarmCall(\n\tinput: Record<string, unknown>,\n\tctx: PermissionContext,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tif (ctx.mode === \"auto\") return undefined;\n\tif (options?.explicitSwarmTurn) return undefined;\n\tconst count = effectiveSwarmCount(input);\n\tif (count <= SWARM_APPROVAL_THRESHOLD) return undefined;\n\tif (ctx.approvals.has(SWARM_ACTION)) return undefined;\n\n\tif (!approvalHandler) {\n\t\treturn { block: true, reason: NO_SWARM_HANDLER_REASON };\n\t}\n\n\tconst summary = swarmTaskSummary(input);\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({\n\t\t\ttoolName: \"subagent\",\n\t\t\taction: SWARM_ACTION,\n\t\t\tdetail: summary ? `agent swarm (${count} subagents)\\n${summary}` : `agent swarm (${count} subagents)`,\n\t\t\tkind: \"swarm\",\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_SWARM_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(SWARM_ACTION);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\t\treturn { block: true, reason: feedback ? `${SWARM_REJECT_REASON} ${feedback}` : SWARM_REJECT_REASON };\n\t}\n\treturn undefined;\n}\n\nfunction sanitizeDetail(value: unknown): string {\n\tconst text = String(value ?? \"\").trim();\n\treturn text.length > 200 ? `${text.slice(0, 200)}…` : text;\n}\n\n/**\n * Returns a block result when the tool call should be blocked, else undefined.\n * Read-only tools always pass. YOLO and Auto always pass mutating tools. Plan\n * mode hard-blocks mutating tools (no prompt). Manual mode gates every mutating\n * tool; if an approval handler is registered it is asked, otherwise the call is\n * blocked (fail-closed — no silent allow).\n */\nexport async function gateToolCall(\n\ttoolName: string,\n\tinput: Record<string, unknown>,\n\tcwd: string,\n\tsessionId?: string,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tconst ctx = getContext(sessionId);\n\tif (READ_ONLY_TOOLS.has(toolName)) return undefined;\n\n\t// lunr: agent-swarm gate runs before the mode early-return — it applies in\n\t// yolo mode too (only auto mode bypasses it).\n\tif (toolName === \"subagent\") {\n\t\tconst swarmBlock = await gateSwarmCall(input, ctx, options);\n\t\tif (swarmBlock) return swarmBlock;\n\t}\n\n\tif (ctx.mode === \"plan\") {\n\t\tconst reason = planModeBlockReason(toolName, input);\n\t\treturn reason ? { block: true, reason } : undefined;\n\t}\n\n\tif (ctx.mode !== \"manual\") return undefined;\n\tif (!isMutatingTool(toolName)) return undefined;\n\n\tlet action: string;\n\tlet detail: string;\n\n\tif (toolName === \"bash\") {\n\t\taction = \"bash\";\n\t\tdetail = sanitizeDetail(input.command);\n\t} else if (toolName === \"edit\" || toolName === \"write\") {\n\t\tconst path = resolvePath(cwd, input.path);\n\t\tconst outside = path ? isPathOutsideCwd(path, cwd) : false;\n\t\taction = outside ? `${toolName}-outside` : toolName;\n\t\tdetail = path || String(input.path ?? \"\");\n\t} else if (toolName === \"behavior_add\" || toolName === \"memory_add\") {\n\t\taction = toolName;\n\t\tdetail = sanitizeDetail(input.content);\n\t} else if (toolName === \"behavior_remove\" || toolName === \"memory_remove\") {\n\t\taction = toolName;\n\t\tdetail = sanitizeDetail(input.line);\n\t} else if (toolName === \"cron\") {\n\t\taction = \"cron\";\n\t\tdetail = sanitizeDetail(input.action);\n\t} else {\n\t\t// All other mutating tools fall back to the tool name with no extra detail.\n\t\taction = toolName;\n\t\tdetail = \"\";\n\t}\n\n\tif (ctx.approvals.has(action)) return undefined;\n\n\tif (!approvalHandler) {\n\t\treturn { block: true, reason: NO_HANDLER_REASON };\n\t}\n\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName, action, detail });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(action);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\t\treturn { block: true, reason: feedback ? `${REJECT_REASON} ${feedback}` : REJECT_REASON };\n\t}\n\t// \"once\" — allow this call only\n\treturn undefined;\n}\n"]}
1
+ {"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/core/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,6BAA6B;AAC7B,eAAO,MAAM,gBAAgB,6CAA8C,CAAC;AAC5E,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAG1E;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC7C,QAAQ,EAAE,cAAc,GAAG,SAAS,EACpC,WAAW,EAAE,cAAc,GACzB,cAAc,CAGhB;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB;;4EAEwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;;uDAEmD;IACnD,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAC7D;;8CAE8C;AAC9C,MAAM,MAAM,gBAAgB,GACzB,gBAAgB,GAChB;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,QAAQ,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAgC9C,eAAO,MAAM,iBAAiB,yEAAyE,CAAC;AACxG,eAAO,MAAM,mBAAmB,kCAAkC,CAAC;AACnE,eAAO,MAAM,uBAAuB,wDAAwD,CAAC;AAoB7F,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,cAAoC,GAAG,IAAI,CAE3G;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,cAAc,CAEpE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAEhF;AAED,wBAAgB,gBAAgB,CAAC,WAAW,GAAE,cAAyB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAMjG;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI,CAEnH;AAED,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,2CAAsC,CAAC;AACtE,eAAO,MAAM,kBAAkB,sEAAiE,CAAC;AACjG,eAAO,MAAM,sBAAsB,oDAAoD,CAAC;AAExF,mFAAmF;AACnF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CASrE;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAW1E;AAED,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAE9D;AAED,2EAA2E;AAC3E,wBAAgB,0BAA0B,IAAI,IAAI,CAIjD;AAED,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,4JAC2H,CAAC;AAgB3J,eAAO,MAAM,qCAAqC,gGAC4C,CAAC;AAC/F,eAAO,MAAM,qCAAqC,8GAC0D,CAAC;AA6B7G,MAAM,WAAW,WAAW;IAC3B;mFAC+E;IAC/E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;6DACyD;IACzD,gBAAgB,CAAC,EAAE;QAClB,OAAO,CAAC,EAAE,aAAa,CAAC;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC/E,CAAC;CACF;AA6FD;;;;;;GAMG;AACH,wBAAsB,YAAY,CACjC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CA6EtD","sourcesContent":["/**\n * lunR: permission modes (Manual / YOLO / Plan / Auto).\n *\n * Per-session only — never persisted per session, but the default mode new\n * sessions start with is configurable in /settings (`defaultPermissionMode`,\n * default \"manual\").\n *\n * - manual: every mutating tool call (bash, edit, write) requires approval.\n * - yolo: auto-approve tools; the agent may still ask questions.\n * - plan: read-only; mutating tools are hard-blocked (planModeBlockReason).\n * - auto: fully autonomous; a system-prompt addendum steers the model to\n * self-decide, and rollback is force-enabled for the session.\n *\n * The gate is wired into `agent-session.ts` `_installAgentToolHooks` before\n * the synchronous `_toolCallGates` loop. beforeToolCall is already async, so\n * awaiting the approval dialog is fine.\n *\n * State (mode + session-scoped approvals) is keyed by session id so\n * concurrent gateway chats do not share permission decisions.\n */\n\nimport { dirname, join, resolve } from \"node:path\";\nimport { getAgentDir } from \"../config.ts\";\nimport { isCodeRewriteMutating, planModeBlockReason } from \"./plan-mode.ts\";\nimport { effectiveSwarmCountForTurn, SWARM_APPROVAL_THRESHOLD } from \"./swarm.ts\";\n\n/** Shift+Tab cycle order. */\nexport const PERMISSION_MODES = [\"manual\", \"yolo\", \"plan\", \"auto\"] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\nexport function nextPermissionMode(current: PermissionMode): PermissionMode {\n\tconst i = PERMISSION_MODES.indexOf(current);\n\treturn PERMISSION_MODES[(i + 1) % PERMISSION_MODES.length];\n}\n\n/** True when the (default or session) permission mode is plan. */\nexport function isPlanModeActive(sessionId?: string): boolean {\n\treturn getPermissionMode(sessionId) === \"plan\";\n}\n\n/**\n * Destination mode when leaving plan via approve / `/plan off` / `/plan <text>`.\n * Explicit Shift+Tab or `/mode` picks do not use this — they already chose a mode.\n */\nexport function restorePermissionModeAfterPlan(\n\tprevious: PermissionMode | undefined,\n\tdefaultMode: PermissionMode,\n): PermissionMode {\n\tif (previous && previous !== \"plan\") return previous;\n\treturn defaultMode === \"plan\" ? \"yolo\" : defaultMode;\n}\n\nexport interface ApprovalRequest {\n\ttoolName: string;\n\t/** \"bash\" (detail = command), \"edit\"/\"write\" (detail = path),\n\t * \"edit-outside\"/\"write-outside\" when path escapes cwd,\n\t * \"swarm\" for auto-activated agent swarms (detail = summary lines). */\n\taction: string;\n\tdetail: string;\n\t/** \"swarm\" when this is the agent-swarm approval prompt, \"plan\" for the\n\t * present_plan plan-approval prompt — the UI renders a dedicated dialog\n\t * for each instead of the generic tool dialog. */\n\tkind?: \"swarm\" | \"plan\";\n}\n\nexport type ApprovalDecision = \"once\" | \"session\" | \"reject\";\n/** Handlers may return a bare decision string, a reject carrying user feedback\n * that becomes the block reason the model sees, or an approve carrying optional\n * feedback (plan approval with comments). */\nexport type ApprovalResponse =\n\t| ApprovalDecision\n\t| { decision: \"reject\"; feedback: string }\n\t| { decision: \"approve\"; feedback?: string };\n\n/** Read-only tools that never need approval. */\nconst READ_ONLY_TOOLS = new Set([\n\t\"read\",\n\t\"grep\",\n\t\"find\",\n\t\"ls\",\n\t\"web_search\",\n\t\"web_fetch\",\n\t\"fetch_content\",\n\t\"get_search_content\",\n\t\"sourcegraph\",\n\t\"repo_map\",\n\t\"symbol_outline\",\n\t\"read_block\",\n\t\"code_overview\",\n\t\"ast_search\",\n\t\"lsp_diagnostics\",\n\t\"lsp_hover\",\n\t\"lsp_definition\",\n\t\"lsp_references\",\n\t\"lsp_symbols\",\n\t\"lsp_code_actions\",\n\t\"lsp_completions\",\n\t\"memory_load\",\n]);\n\n/** Tools that mutate state and must be gated in manual mode. */\nconst MUTATING_TOOLS = new Set([\"bash\", \"edit\", \"write\", \"memory_add\", \"memory_remove\", \"cron\"]);\n\nconst REJECT_REASON = \"Rejected by user (permission mode: manual).\";\nexport const NO_HANDLER_REASON = \"Mutating tool blocked in manual mode: no approval channel available.\";\nexport const SWARM_REJECT_REASON = \"Agent swarm rejected by user.\";\nexport const NO_SWARM_HANDLER_REASON = \"Agent swarm blocked: no approval channel available.\";\n/** Session-approval key for auto-activated agent swarms. */\nconst SWARM_ACTION = \"swarm\";\n\ninterface PermissionContext {\n\tmode: PermissionMode;\n\tapprovals: Set<string>;\n}\n\nconst contexts = new Map<string, PermissionContext>();\nlet defaultContext: PermissionContext = { mode: \"manual\", approvals: new Set() };\nlet approvalHandler: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined;\n/** One swarm prompt covers every sibling SINGLE `subagent` on the same assistant message. */\nconst turnSwarmDecisions = new WeakMap<object, { decision: ApprovalDecision; feedback?: string }>();\n\nfunction getContext(sessionId?: string): PermissionContext {\n\tif (!sessionId) return defaultContext;\n\treturn contexts.get(sessionId) ?? defaultContext;\n}\n\nexport function createPermissionContext(sessionId: string, mode: PermissionMode = defaultContext.mode): void {\n\tcontexts.set(sessionId, { mode, approvals: new Set() });\n}\n\nexport function deletePermissionContext(sessionId: string): void {\n\tcontexts.delete(sessionId);\n}\n\nexport function getPermissionMode(sessionId?: string): PermissionMode {\n\treturn getContext(sessionId).mode;\n}\n\nexport function setPermissionMode(mode: PermissionMode, sessionId?: string): void {\n\tgetContext(sessionId).mode = mode;\n}\n\nexport function resetPermissions(defaultMode: PermissionMode = \"manual\", sessionId?: string): void {\n\tif (sessionId) {\n\t\tcontexts.set(sessionId, { mode: defaultMode, approvals: new Set() });\n\t} else {\n\t\tdefaultContext = { mode: defaultMode, approvals: new Set() };\n\t}\n}\n\nexport function registerApprovalHandler(fn: ((req: ApprovalRequest) => Promise<ApprovalResponse>) | undefined): void {\n\tapprovalHandler = fn;\n}\n\n/** Model-facing result texts for the present_plan tool. */\nexport const PLAN_APPROVED_TEXT = \"Plan approved — implement it now.\";\nexport const PLAN_DECLINED_TEXT = \"Plan declined — revise the plan and call present_plan again.\";\nexport const PLAN_PASS_THROUGH_TEXT = \"Plan presented. The user will review and reply.\";\n\n/** lunr: map an approval response to the model-facing present_plan result text. */\nexport function planApprovalResultText(resp: ApprovalResponse): string {\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (decision === \"reject\") {\n\t\treturn feedback\n\t\t\t? `Plan declined: ${feedback} — revise the plan and call present_plan again.`\n\t\t\t: PLAN_DECLINED_TEXT;\n\t}\n\treturn feedback ? `Plan approved with feedback: ${feedback} — implement it now.` : PLAN_APPROVED_TEXT;\n}\n\n/**\n * lunr: present_plan approval request. Unlike the mutating-tool and swarm gates\n * this fails OPEN when no approval handler is registered (or none is reachable,\n * e.g. a gateway turn without a chat context): headless sessions have no one to\n * show the dialog to, so the plan is presented and the user replies in chat\n * instead of deadlocking the turn. Everything else keeps fail-closed.\n */\nexport async function requestPlanApproval(summary: string): Promise<string> {\n\tif (!approvalHandler) return PLAN_PASS_THROUGH_TEXT;\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName: \"present_plan\", action: \"plan\", detail: summary, kind: \"plan\" });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : \"approval request failed\";\n\t\tif (message === NO_HANDLER_REASON) return PLAN_PASS_THROUGH_TEXT;\n\t\treturn `Plan declined: ${message} — revise the plan and call present_plan again.`;\n\t}\n\treturn planApprovalResultText(resp);\n}\n\nexport function clearSessionApprovals(sessionId?: string): void {\n\tgetContext(sessionId).approvals.clear();\n}\n\n/** Test seam: remove every per-session context and restore the default. */\nexport function resetAllPermissionContexts(): void {\n\tcontexts.clear();\n\tdefaultContext = { mode: \"manual\", approvals: new Set() };\n\tapprovalHandler = undefined;\n}\n\n/** Appended to the system prompt while auto mode is active. */\nexport const AUTO_MODE_ADDENDUM =\n\t\"You are running fully autonomously. Do not ask the user questions or wait for confirmation; make reasonable decisions and complete the task end-to-end.\";\n\nfunction isPathOutsideCwd(absPath: string, cwd: string): boolean {\n\tconst norm = (p: string) => p.replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\tconst np = norm(absPath);\n\tconst nc = norm(cwd);\n\tif (np === nc) return false;\n\treturn !np.startsWith(`${nc}/`);\n}\n\nfunction resolvePath(cwd: string, p: unknown): string {\n\tif (typeof p !== \"string\") return \"\";\n\tif (!p) return \"\";\n\treturn resolve(cwd, p);\n}\n\nexport const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON =\n\t\"The global AGENTS.md file is user-managed. The agent cannot change ~/.lunr/agent/AGENTS.md.\";\nexport const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON =\n\t\"Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.\";\n\nfunction protectedFileWriteReason(toolName: string, input: Record<string, unknown>, cwd: string): string | undefined {\n\tif (toolName !== \"edit\" && toolName !== \"write\" && toolName !== \"code_rewrite\") return undefined;\n\tconst target = resolvePath(cwd, input.path);\n\tif (!target) return undefined;\n\tconst normalize = (path: string) => {\n\t\tconst normalized = resolve(path).replace(/\\\\/g, \"/\").replace(/\\/$/, \"\");\n\t\treturn process.platform === \"win32\" ? normalized.toLowerCase() : normalized;\n\t};\n\tconst agentsPaths = [join(getAgentDir(), \"AGENTS.md\"), join(getAgentDir(), \"AGENTS.MD\")];\n\tif (agentsPaths.some((candidate) => normalize(target) === normalize(candidate))) {\n\t\treturn GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON;\n\t}\n\tif (normalize(target) === normalize(join(dirname(getAgentDir()), \"simple-memory\", \"memory.md\"))) {\n\t\treturn MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON;\n\t}\n\treturn undefined;\n}\n\nfunction isMutatingTool(toolName: string): boolean {\n\treturn MUTATING_TOOLS.has(toolName);\n}\n\nfunction requiresManualApproval(toolName: string, input: Record<string, unknown>): boolean {\n\tif (isMutatingTool(toolName)) return true;\n\treturn toolName === \"code_rewrite\" && isCodeRewriteMutating(input);\n}\n\nexport interface GateOptions {\n\t/** True when the current turn started from an explicit /swarm prompt — the\n\t * user already asked for the swarm, so the swarm approval gate is skipped. */\n\texplicitSwarmTurn?: boolean;\n\t/** Assistant message that issued this tool call. Same-turn sibling SINGLE\n\t * `subagent` calls count toward the swarm threshold. */\n\tassistantMessage?: {\n\t\tcontent?: ReadonlyArray<{ type?: string; name?: string; arguments?: unknown }>;\n\t};\n}\n\nfunction firstTaskText(value: unknown): string {\n\tif (typeof value === \"string\" && value.trim()) return sanitizeDetail(value);\n\treturn \"\";\n}\n\n/** First task text of a parallel fan-out or sibling SINGLE, used as the dialog summary. */\nfunction swarmTaskSummary(input: Record<string, unknown>, assistantMessage?: GateOptions[\"assistantMessage\"]): string {\n\tif (Array.isArray(input.tasks)) {\n\t\tfor (const task of input.tasks) {\n\t\t\tconst text = task && typeof task === \"object\" ? firstTaskText((task as { task?: unknown }).task) : \"\";\n\t\t\tif (text) return text;\n\t\t}\n\t}\n\tconst own = firstTaskText(input.task);\n\tif (own) return own;\n\tfor (const block of assistantMessage?.content ?? []) {\n\t\tif (block.type !== \"toolCall\" || block.name !== \"subagent\") continue;\n\t\tconst args =\n\t\t\tblock.arguments && typeof block.arguments === \"object\" && !Array.isArray(block.arguments)\n\t\t\t\t? (block.arguments as Record<string, unknown>)\n\t\t\t\t: undefined;\n\t\tconst text = firstTaskText(args?.task);\n\t\tif (text) return text;\n\t}\n\treturn \"\";\n}\n\n/**\n * Agent-swarm gate. An auto-activated swarm (more than SWARM_APPROVAL_THRESHOLD\n * parallel subagents in one `tasks`/`chain.parallel` call, or that many same-turn\n * SINGLE `subagent` calls) requires user approval in manual AND yolo modes; auto\n * mode runs it unconditionally and explicit /swarm turns are pre-approved.\n * Fail-closed without an approval handler, same as the mutating-tool gate.\n */\nasync function gateSwarmCall(\n\tinput: Record<string, unknown>,\n\tctx: PermissionContext,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tif (ctx.mode === \"auto\") return undefined;\n\tif (options?.explicitSwarmTurn) return undefined;\n\tconst count = effectiveSwarmCountForTurn(input, options?.assistantMessage);\n\tif (count <= SWARM_APPROVAL_THRESHOLD) return undefined;\n\tif (ctx.approvals.has(SWARM_ACTION)) return undefined;\n\n\tconst turnKey = options?.assistantMessage;\n\tconst cached = turnKey ? turnSwarmDecisions.get(turnKey) : undefined;\n\tif (cached) {\n\t\tif (cached.decision === \"reject\") {\n\t\t\treturn { block: true, reason: cached.feedback ? `${SWARM_REJECT_REASON} ${cached.feedback}` : SWARM_REJECT_REASON };\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tif (!approvalHandler) {\n\t\treturn { block: true, reason: NO_SWARM_HANDLER_REASON };\n\t}\n\n\tconst summary = swarmTaskSummary(input, options?.assistantMessage);\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({\n\t\t\ttoolName: \"subagent\",\n\t\t\taction: SWARM_ACTION,\n\t\t\tdetail: summary ? `agent swarm (${count} subagents)\\n${summary}` : `agent swarm (${count} subagents)`,\n\t\t\tkind: \"swarm\",\n\t\t});\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_SWARM_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst rawDecision = typeof resp === \"string\" ? resp : resp.decision;\n\tconst decision: ApprovalDecision = rawDecision === \"approve\" ? \"once\" : rawDecision;\n\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\tif (turnKey) turnSwarmDecisions.set(turnKey, { decision, ...(feedback ? { feedback } : {}) });\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(SWARM_ACTION);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\treturn { block: true, reason: feedback ? `${SWARM_REJECT_REASON} ${feedback}` : SWARM_REJECT_REASON };\n\t}\n\treturn undefined;\n}\n\nfunction sanitizeDetail(value: unknown): string {\n\tconst text = String(value ?? \"\").trim();\n\treturn text.length > 200 ? `${text.slice(0, 200)}…` : text;\n}\n\n/**\n * Returns a block result when the tool call should be blocked, else undefined.\n * Read-only tools always pass. YOLO and Auto always pass mutating tools. Plan\n * mode hard-blocks mutating tools (no prompt). Manual mode gates every mutating\n * tool; if an approval handler is registered it is asked, otherwise the call is\n * blocked (fail-closed — no silent allow).\n */\nexport async function gateToolCall(\n\ttoolName: string,\n\tinput: Record<string, unknown>,\n\tcwd: string,\n\tsessionId?: string,\n\toptions?: GateOptions,\n): Promise<{ block: true; reason: string } | undefined> {\n\tconst ctx = getContext(sessionId);\n\tconst protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);\n\tif (protectedWriteReason) {\n\t\treturn { block: true, reason: protectedWriteReason };\n\t}\n\tif (READ_ONLY_TOOLS.has(toolName)) return undefined;\n\n\t// lunr: agent-swarm gate runs before the mode early-return — it applies in\n\t// yolo mode too (only auto mode bypasses it).\n\tif (toolName === \"subagent\") {\n\t\tconst swarmBlock = await gateSwarmCall(input, ctx, options);\n\t\tif (swarmBlock) return swarmBlock;\n\t}\n\n\tif (ctx.mode === \"plan\") {\n\t\tconst reason = planModeBlockReason(toolName, input);\n\t\treturn reason ? { block: true, reason } : undefined;\n\t}\n\n\tif (ctx.mode !== \"manual\") return undefined;\n\tif (!requiresManualApproval(toolName, input)) return undefined;\n\n\tlet action: string;\n\tlet detail: string;\n\n\tif (toolName === \"bash\") {\n\t\taction = \"bash\";\n\t\tdetail = sanitizeDetail(input.command);\n\t} else if (toolName === \"edit\" || toolName === \"write\") {\n\t\tconst path = resolvePath(cwd, input.path);\n\t\tconst outside = path ? isPathOutsideCwd(path, cwd) : false;\n\t\taction = outside ? `${toolName}-outside` : toolName;\n\t\tdetail = path || String(input.path ?? \"\");\n\t} else if (toolName === \"memory_add\") {\n\t\taction = toolName;\n\t\tdetail = sanitizeDetail(input.content);\n\t} else if (toolName === \"memory_remove\") {\n\t\taction = toolName;\n\t\tdetail = sanitizeDetail(input.line);\n\t} else if (toolName === \"cron\") {\n\t\taction = \"cron\";\n\t\tdetail = sanitizeDetail(input.action);\n\t} else if (toolName === \"code_rewrite\") {\n\t\taction = \"code_rewrite\";\n\t\tdetail = sanitizeDetail(input.path ?? input.pattern);\n\t} else {\n\t\t// All other mutating tools fall back to the tool name with no extra detail.\n\t\taction = toolName;\n\t\tdetail = \"\";\n\t}\n\n\tif (ctx.approvals.has(action)) return undefined;\n\n\tif (!approvalHandler) {\n\t\treturn { block: true, reason: NO_HANDLER_REASON };\n\t}\n\n\tlet resp: ApprovalResponse;\n\ttry {\n\t\tresp = await approvalHandler({ toolName, action, detail });\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : NO_HANDLER_REASON;\n\t\treturn { block: true, reason: message };\n\t}\n\n\tconst decision = typeof resp === \"string\" ? resp : resp.decision;\n\tif (decision === \"session\") {\n\t\tctx.approvals.add(action);\n\t\treturn undefined;\n\t}\n\tif (decision === \"reject\") {\n\t\tconst feedback = typeof resp === \"string\" ? undefined : resp.feedback?.trim();\n\t\treturn { block: true, reason: feedback ? `${REJECT_REASON} ${feedback}` : REJECT_REASON };\n\t}\n\t// \"once\" — allow this call only\n\treturn undefined;\n}\n"]}
@@ -18,9 +18,10 @@
18
18
  * State (mode + session-scoped approvals) is keyed by session id so
19
19
  * concurrent gateway chats do not share permission decisions.
20
20
  */
21
- import { resolve } from "node:path";
22
- import { planModeBlockReason } from "./plan-mode.js";
23
- import { effectiveSwarmCount, SWARM_APPROVAL_THRESHOLD } from "./swarm.js";
21
+ import { dirname, join, resolve } from "node:path";
22
+ import { getAgentDir } from "../config.js";
23
+ import { isCodeRewriteMutating, planModeBlockReason } from "./plan-mode.js";
24
+ import { effectiveSwarmCountForTurn, SWARM_APPROVAL_THRESHOLD } from "./swarm.js";
24
25
  /** Shift+Tab cycle order. */
25
26
  export const PERMISSION_MODES = ["manual", "yolo", "plan", "auto"];
26
27
  export function nextPermissionMode(current) {
@@ -63,20 +64,10 @@ const READ_ONLY_TOOLS = new Set([
63
64
  "lsp_symbols",
64
65
  "lsp_code_actions",
65
66
  "lsp_completions",
66
- "behavior_load",
67
67
  "memory_load",
68
68
  ]);
69
69
  /** Tools that mutate state and must be gated in manual mode. */
70
- const MUTATING_TOOLS = new Set([
71
- "bash",
72
- "edit",
73
- "write",
74
- "behavior_add",
75
- "behavior_remove",
76
- "memory_add",
77
- "memory_remove",
78
- "cron",
79
- ]);
70
+ const MUTATING_TOOLS = new Set(["bash", "edit", "write", "memory_add", "memory_remove", "cron"]);
80
71
  const REJECT_REASON = "Rejected by user (permission mode: manual).";
81
72
  export const NO_HANDLER_REASON = "Mutating tool blocked in manual mode: no approval channel available.";
82
73
  export const SWARM_REJECT_REASON = "Agent swarm rejected by user.";
@@ -86,6 +77,8 @@ const SWARM_ACTION = "swarm";
86
77
  const contexts = new Map();
87
78
  let defaultContext = { mode: "manual", approvals: new Set() };
88
79
  let approvalHandler;
80
+ /** One swarm prompt covers every sibling SINGLE `subagent` on the same assistant message. */
81
+ const turnSwarmDecisions = new WeakMap();
89
82
  function getContext(sessionId) {
90
83
  if (!sessionId)
91
84
  return defaultContext;
@@ -177,41 +170,93 @@ function resolvePath(cwd, p) {
177
170
  return "";
178
171
  return resolve(cwd, p);
179
172
  }
173
+ export const GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON = "The global AGENTS.md file is user-managed. The agent cannot change ~/.lunr/agent/AGENTS.md.";
174
+ export const MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON = "Memory is model-managed through the memory tools. Do not directly change ~/.lunr/simple-memory/memory.md.";
175
+ function protectedFileWriteReason(toolName, input, cwd) {
176
+ if (toolName !== "edit" && toolName !== "write" && toolName !== "code_rewrite")
177
+ return undefined;
178
+ const target = resolvePath(cwd, input.path);
179
+ if (!target)
180
+ return undefined;
181
+ const normalize = (path) => {
182
+ const normalized = resolve(path).replace(/\\/g, "/").replace(/\/$/, "");
183
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
184
+ };
185
+ const agentsPaths = [join(getAgentDir(), "AGENTS.md"), join(getAgentDir(), "AGENTS.MD")];
186
+ if (agentsPaths.some((candidate) => normalize(target) === normalize(candidate))) {
187
+ return GLOBAL_AGENTS_FILE_WRITE_BLOCK_REASON;
188
+ }
189
+ if (normalize(target) === normalize(join(dirname(getAgentDir()), "simple-memory", "memory.md"))) {
190
+ return MEMORY_FILE_DIRECT_WRITE_BLOCK_REASON;
191
+ }
192
+ return undefined;
193
+ }
180
194
  function isMutatingTool(toolName) {
181
195
  return MUTATING_TOOLS.has(toolName);
182
196
  }
183
- /** First task text of a parallel fan-out, used as the dialog summary line. */
184
- function swarmTaskSummary(input) {
185
- if (!Array.isArray(input.tasks))
186
- return "";
187
- for (const task of input.tasks) {
188
- const text = task && typeof task === "object" ? task.task : undefined;
189
- if (typeof text === "string" && text.trim())
190
- return sanitizeDetail(text);
197
+ function requiresManualApproval(toolName, input) {
198
+ if (isMutatingTool(toolName))
199
+ return true;
200
+ return toolName === "code_rewrite" && isCodeRewriteMutating(input);
201
+ }
202
+ function firstTaskText(value) {
203
+ if (typeof value === "string" && value.trim())
204
+ return sanitizeDetail(value);
205
+ return "";
206
+ }
207
+ /** First task text of a parallel fan-out or sibling SINGLE, used as the dialog summary. */
208
+ function swarmTaskSummary(input, assistantMessage) {
209
+ if (Array.isArray(input.tasks)) {
210
+ for (const task of input.tasks) {
211
+ const text = task && typeof task === "object" ? firstTaskText(task.task) : "";
212
+ if (text)
213
+ return text;
214
+ }
215
+ }
216
+ const own = firstTaskText(input.task);
217
+ if (own)
218
+ return own;
219
+ for (const block of assistantMessage?.content ?? []) {
220
+ if (block.type !== "toolCall" || block.name !== "subagent")
221
+ continue;
222
+ const args = block.arguments && typeof block.arguments === "object" && !Array.isArray(block.arguments)
223
+ ? block.arguments
224
+ : undefined;
225
+ const text = firstTaskText(args?.task);
226
+ if (text)
227
+ return text;
191
228
  }
192
229
  return "";
193
230
  }
194
231
  /**
195
- * Agent-swarm gate. An auto-activated swarm (one `subagent` call launching more
196
- * than SWARM_APPROVAL_THRESHOLD parallel subagents) requires user approval in
197
- * manual AND yolo modes; auto mode runs it unconditionally and explicit /swarm
198
- * turns are pre-approved. Fail-closed without an approval handler, same as the
199
- * mutating-tool gate.
232
+ * Agent-swarm gate. An auto-activated swarm (more than SWARM_APPROVAL_THRESHOLD
233
+ * parallel subagents in one `tasks`/`chain.parallel` call, or that many same-turn
234
+ * SINGLE `subagent` calls) requires user approval in manual AND yolo modes; auto
235
+ * mode runs it unconditionally and explicit /swarm turns are pre-approved.
236
+ * Fail-closed without an approval handler, same as the mutating-tool gate.
200
237
  */
201
238
  async function gateSwarmCall(input, ctx, options) {
202
239
  if (ctx.mode === "auto")
203
240
  return undefined;
204
241
  if (options?.explicitSwarmTurn)
205
242
  return undefined;
206
- const count = effectiveSwarmCount(input);
243
+ const count = effectiveSwarmCountForTurn(input, options?.assistantMessage);
207
244
  if (count <= SWARM_APPROVAL_THRESHOLD)
208
245
  return undefined;
209
246
  if (ctx.approvals.has(SWARM_ACTION))
210
247
  return undefined;
248
+ const turnKey = options?.assistantMessage;
249
+ const cached = turnKey ? turnSwarmDecisions.get(turnKey) : undefined;
250
+ if (cached) {
251
+ if (cached.decision === "reject") {
252
+ return { block: true, reason: cached.feedback ? `${SWARM_REJECT_REASON} ${cached.feedback}` : SWARM_REJECT_REASON };
253
+ }
254
+ return undefined;
255
+ }
211
256
  if (!approvalHandler) {
212
257
  return { block: true, reason: NO_SWARM_HANDLER_REASON };
213
258
  }
214
- const summary = swarmTaskSummary(input);
259
+ const summary = swarmTaskSummary(input, options?.assistantMessage);
215
260
  let resp;
216
261
  try {
217
262
  resp = await approvalHandler({
@@ -225,13 +270,16 @@ async function gateSwarmCall(input, ctx, options) {
225
270
  const message = err instanceof Error ? err.message : NO_SWARM_HANDLER_REASON;
226
271
  return { block: true, reason: message };
227
272
  }
228
- const decision = typeof resp === "string" ? resp : resp.decision;
273
+ const rawDecision = typeof resp === "string" ? resp : resp.decision;
274
+ const decision = rawDecision === "approve" ? "once" : rawDecision;
275
+ const feedback = typeof resp === "string" ? undefined : resp.feedback?.trim();
276
+ if (turnKey)
277
+ turnSwarmDecisions.set(turnKey, { decision, ...(feedback ? { feedback } : {}) });
229
278
  if (decision === "session") {
230
279
  ctx.approvals.add(SWARM_ACTION);
231
280
  return undefined;
232
281
  }
233
282
  if (decision === "reject") {
234
- const feedback = typeof resp === "string" ? undefined : resp.feedback?.trim();
235
283
  return { block: true, reason: feedback ? `${SWARM_REJECT_REASON} ${feedback}` : SWARM_REJECT_REASON };
236
284
  }
237
285
  return undefined;
@@ -249,6 +297,10 @@ function sanitizeDetail(value) {
249
297
  */
250
298
  export async function gateToolCall(toolName, input, cwd, sessionId, options) {
251
299
  const ctx = getContext(sessionId);
300
+ const protectedWriteReason = protectedFileWriteReason(toolName, input, cwd);
301
+ if (protectedWriteReason) {
302
+ return { block: true, reason: protectedWriteReason };
303
+ }
252
304
  if (READ_ONLY_TOOLS.has(toolName))
253
305
  return undefined;
254
306
  // lunr: agent-swarm gate runs before the mode early-return — it applies in
@@ -264,7 +316,7 @@ export async function gateToolCall(toolName, input, cwd, sessionId, options) {
264
316
  }
265
317
  if (ctx.mode !== "manual")
266
318
  return undefined;
267
- if (!isMutatingTool(toolName))
319
+ if (!requiresManualApproval(toolName, input))
268
320
  return undefined;
269
321
  let action;
270
322
  let detail;
@@ -278,11 +330,11 @@ export async function gateToolCall(toolName, input, cwd, sessionId, options) {
278
330
  action = outside ? `${toolName}-outside` : toolName;
279
331
  detail = path || String(input.path ?? "");
280
332
  }
281
- else if (toolName === "behavior_add" || toolName === "memory_add") {
333
+ else if (toolName === "memory_add") {
282
334
  action = toolName;
283
335
  detail = sanitizeDetail(input.content);
284
336
  }
285
- else if (toolName === "behavior_remove" || toolName === "memory_remove") {
337
+ else if (toolName === "memory_remove") {
286
338
  action = toolName;
287
339
  detail = sanitizeDetail(input.line);
288
340
  }
@@ -290,6 +342,10 @@ export async function gateToolCall(toolName, input, cwd, sessionId, options) {
290
342
  action = "cron";
291
343
  detail = sanitizeDetail(input.action);
292
344
  }
345
+ else if (toolName === "code_rewrite") {
346
+ action = "code_rewrite";
347
+ detail = sanitizeDetail(input.path ?? input.pattern);
348
+ }
293
349
  else {
294
350
  // All other mutating tools fall back to the tool name with no extra detail.
295
351
  action = toolName;