mixdog 0.9.147 → 0.9.148

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/package.json +23 -3
  2. package/scripts/build-voice-runtime-unix.sh +101 -0
  3. package/scripts/embedding-quality-probe.mjs +96 -0
  4. package/scripts/generate-voice-runtime-manifest.mjs +300 -0
  5. package/scripts/generate-voice-runtime-manifest.test.mjs +135 -0
  6. package/scripts/native-binary-arch.mjs +30 -13
  7. package/scripts/native-binary-arch.test.mjs +40 -4
  8. package/scripts/plan-voice-runtime-release.mjs +73 -0
  9. package/scripts/prepare-native-assets.mjs +50 -9
  10. package/scripts/prune-embedding-runtime.mjs +3 -3
  11. package/scripts/sync-voice-runtime-manifest.mjs +46 -0
  12. package/scripts/verify-release-assets.mjs +106 -6
  13. package/scripts/verify-voice-runtime-release.mjs +89 -0
  14. package/scripts/voice-runtime-config.json +52 -0
  15. package/src/app.mjs +42 -5
  16. package/src/headless-exec.mjs +58 -32
  17. package/src/headless-exec.test.mjs +74 -13
  18. package/src/rules/lead/01-general.md +2 -0
  19. package/src/rules/shared/10-tool-workflow.md +7 -4
  20. package/src/rules/shared/30-exploration.md +2 -1
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +28 -9
  22. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +6 -1
  23. package/src/runtime/agent/orchestrator/config.mjs +53 -18
  24. package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +139 -0
  25. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +34 -5
  26. package/src/runtime/agent/orchestrator/mcp/client.mjs +94 -10
  27. package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +5 -0
  28. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +98 -0
  29. package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +90 -0
  30. package/src/runtime/agent/orchestrator/providers/anthropic-leaked-toolcall.mjs +67 -16
  31. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +4 -82
  32. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +0 -5
  33. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +62 -121
  34. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +48 -0
  35. package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +215 -0
  36. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +44 -48
  37. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +54 -31
  38. package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +56 -2
  39. package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +34 -2
  40. package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +61 -1
  41. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +6 -1
  42. package/src/runtime/agent/orchestrator/providers/gemini.mjs +61 -15
  43. package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +120 -1
  44. package/src/runtime/agent/orchestrator/providers/lib/env-utils.mjs +9 -0
  45. package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +0 -3
  46. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +187 -84
  47. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +36 -36
  48. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +16 -6
  49. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +50 -213
  50. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +135 -126
  51. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +17 -11
  52. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +20 -7
  53. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +11 -0
  54. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +132 -42
  55. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -2
  56. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +28 -10
  57. package/src/runtime/agent/orchestrator/providers/registry.mjs +122 -95
  58. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +58 -3
  59. package/src/runtime/agent/orchestrator/providers/tool-stream-state.mjs +4 -22
  60. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +7 -14
  61. package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +128 -0
  62. package/src/runtime/agent/orchestrator/session/context-compaction-policy.mjs +5 -0
  63. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +27 -48
  64. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +19 -14
  65. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +9 -43
  66. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +5 -1
  67. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +15 -2
  68. package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +325 -0
  69. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +599 -195
  70. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +22 -0
  71. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +9 -2
  72. package/src/runtime/agent/orchestrator/session/manager.mjs +3 -0
  73. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +26 -16
  74. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +23 -11
  75. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +118 -3
  76. package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +332 -0
  77. package/src/runtime/agent/orchestrator/session/store.mjs +38 -1
  78. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +27 -6
  79. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -20
  80. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +291 -128
  81. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +45 -8
  82. package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +224 -0
  83. package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +53 -3
  84. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +255 -25
  85. package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +87 -0
  86. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +1 -1
  87. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +132 -9
  88. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-pattern-fanout.mjs +29 -3
  90. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +1 -1
  91. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +178 -29
  92. package/src/runtime/agent/orchestrator/tools/builtin/local-search-telemetry.mjs +4 -1
  93. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +32 -5
  94. package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +5 -2
  95. package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +10 -1
  96. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +38 -10
  97. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +12 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +31 -1
  99. package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +11 -1
  100. package/src/runtime/agent/orchestrator/tools/builtin/read-windows.mjs +22 -4
  101. package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +6 -8
  102. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +25 -24
  103. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +152 -133
  104. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +114 -42
  105. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +129 -15
  106. package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +72 -0
  107. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +7 -8
  108. package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +4 -4
  109. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +201 -19
  110. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +26 -3
  111. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +10 -1
  112. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +55 -0
  113. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +115 -25
  114. package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +268 -0
  115. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +3 -3
  116. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +296 -46
  117. package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +104 -0
  118. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +136 -0
  119. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +127 -38
  120. package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +661 -0
  121. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +350 -9
  122. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +418 -44
  123. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +27 -3
  124. package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +552 -0
  125. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +65 -15
  126. package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
  127. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +284 -109
  128. package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +51 -21
  129. package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +44 -27
  130. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +6 -1
  131. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
  132. package/src/runtime/attachments/store.mjs +11 -3
  133. package/src/runtime/channels/data/voice-runtime-manifest.json +46 -70
  134. package/src/runtime/channels/lib/event-queue.mjs +51 -41
  135. package/src/runtime/channels/lib/scheduler.mjs +23 -28
  136. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -17
  137. package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +17 -0
  138. package/src/runtime/channels/lib/webhook.mjs +39 -20
  139. package/src/runtime/channels/lib/whisper-server.mjs +46 -1
  140. package/src/runtime/channels/lib/worker-main.mjs +3 -1
  141. package/src/runtime/media/adapters/gemini-video.mjs +20 -4
  142. package/src/runtime/media/jobs.mjs +13 -0
  143. package/src/runtime/media/renditions.mjs +7 -1
  144. package/src/runtime/media/store.mjs +42 -22
  145. package/src/runtime/memory/index.mjs +4 -9
  146. package/src/runtime/memory/lib/agent-ipc.mjs +1 -6
  147. package/src/runtime/memory/lib/archive-security.test.mjs +21 -1
  148. package/src/runtime/memory/lib/core-memory-store.mjs +28 -50
  149. package/src/runtime/memory/lib/embedding-model-config.mjs +37 -1
  150. package/src/runtime/memory/lib/embedding-model-config.test.mjs +33 -0
  151. package/src/runtime/memory/lib/embedding-provider.mjs +34 -12
  152. package/src/runtime/memory/lib/embedding-worker.mjs +37 -5
  153. package/src/runtime/memory/lib/ko-morph.mjs +46 -15
  154. package/src/runtime/memory/lib/memory-action-handlers.mjs +18 -1
  155. package/src/runtime/memory/lib/memory-cycle1.mjs +1 -18
  156. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +1 -18
  157. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +98 -45
  158. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +71 -0
  159. package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +78 -0
  160. package/src/runtime/memory/lib/memory-cycle2.mjs +37 -3
  161. package/src/runtime/memory/lib/memory-cycle3.mjs +1 -1
  162. package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +50 -0
  163. package/src/runtime/memory/lib/memory-recall-store.mjs +9 -24
  164. package/src/runtime/memory/lib/memory.mjs +50 -12
  165. package/src/runtime/memory/lib/pg/process.mjs +1 -10
  166. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -9
  167. package/src/runtime/memory/lib/query-handlers.mjs +2 -4
  168. package/src/runtime/memory/lib/session-ingest-runtime.mjs +2 -2
  169. package/src/runtime/shared/background-tasks.mjs +15 -0
  170. package/src/runtime/shared/background-tasks.test.mjs +78 -0
  171. package/src/runtime/shared/child-guardian.mjs +2 -10
  172. package/src/runtime/shared/pid-liveness.mjs +27 -0
  173. package/src/runtime/shared/runtime-root.mjs +1 -11
  174. package/src/runtime/shared/service-discovery.mjs +1 -17
  175. package/src/runtime/shared/singleton-owner.mjs +1 -11
  176. package/src/runtime/shared/staged-update.mjs +2 -12
  177. package/src/runtime/shared/tool-status.mjs +5 -1
  178. package/src/runtime/shared/tool-surface.mjs +15 -7
  179. package/src/runtime/shared/turn-snapshot-store.mjs +168 -0
  180. package/src/runtime/shared/turn-snapshot.mjs +137 -13
  181. package/src/runtime/shared/turn-worktree-snapshot.mjs +110 -18
  182. package/src/runtime/shared/webhook-session-run.mjs +16 -2
  183. package/src/runtime/web-search/lib/http-fetch.mjs +34 -4
  184. package/src/runtime/web-search/lib/state.mjs +15 -15
  185. package/src/runtime/web-search/lib/web-tools.mjs +46 -5
  186. package/src/session-runtime/context-status.mjs +4 -12
  187. package/src/session-runtime/runtime-core.mjs +20 -1
  188. package/src/standalone/agent-dispatch-broker.mjs +33 -2
  189. package/src/standalone/agent-tool/job-task-reconcile.mjs +78 -0
  190. package/src/standalone/agent-tool/notify.mjs +3 -1
  191. package/src/standalone/agent-tool/spawn-flow.mjs +48 -66
  192. package/src/standalone/agent-tool/tag-registry.mjs +116 -33
  193. package/src/standalone/agent-tool/tool-def.mjs +2 -2
  194. package/src/standalone/agent-tool/worker-index.mjs +8 -11
  195. package/src/standalone/agent-tool/worker-rows.mjs +4 -1
  196. package/src/standalone/agent-tool.mjs +20 -55
  197. package/src/standalone/agent-watchdog-registry.mjs +28 -4
  198. package/src/standalone/channel-client.mjs +47 -15
  199. package/src/standalone/channel-transport.mjs +44 -25
  200. package/src/standalone/daemon.mjs +31 -2
  201. package/src/standalone/hook-bus/config.mjs +25 -9
  202. package/src/standalone/hook-bus/handlers.mjs +16 -52
  203. package/src/standalone/hook-bus.mjs +29 -23
  204. package/src/standalone/memory-runtime-proxy.mjs +1 -16
  205. package/src/standalone/session-client.mjs +86 -23
  206. package/src/standalone/session-protocol.mjs +0 -2
  207. package/src/standalone/session-runtime-host-health.test.mjs +5 -4
  208. package/src/standalone/session-runtime-host.mjs +101 -6
  209. package/src/standalone/session-runtime-record.mjs +1 -5
  210. package/src/standalone/session-runtime-worker.mjs +52 -57
  211. package/src/standalone/session-service.mjs +4 -1
  212. package/src/standalone/session-transport.mjs +56 -25
  213. package/src/tui/App.jsx +40 -49
  214. package/src/tui/app/app-view.jsx +14 -21
  215. package/src/tui/app/core-memory-picker.mjs +29 -16
  216. package/src/tui/app/create-app-pickers.mjs +15 -36
  217. package/src/tui/app/extension-pickers.mjs +60 -49
  218. package/src/tui/app/maintenance-pickers.mjs +100 -57
  219. package/src/tui/app/message-selector.mjs +6 -5
  220. package/src/tui/app/model-picker.mjs +30 -13
  221. package/src/tui/app/onboarding-steps.mjs +21 -12
  222. package/src/tui/app/panel-epoch.mjs +56 -0
  223. package/src/tui/app/panel-epoch.test.mjs +1009 -0
  224. package/src/tui/app/panel-surface.mjs +98 -0
  225. package/src/tui/app/project-picker.mjs +30 -29
  226. package/src/tui/app/prompt-submit.mjs +192 -97
  227. package/src/tui/app/prompt-submit.test.mjs +206 -0
  228. package/src/tui/app/provider-setup-picker.mjs +74 -43
  229. package/src/tui/app/resume-picker.mjs +11 -8
  230. package/src/tui/app/route-pickers.mjs +45 -28
  231. package/src/tui/app/settings-picker.mjs +69 -18
  232. package/src/tui/app/shell-layout.mjs +1 -3
  233. package/src/tui/app/slash-commands.mjs +0 -2
  234. package/src/tui/app/slash-dispatch.mjs +4 -2
  235. package/src/tui/app/text-entry-policy.mjs +25 -0
  236. package/src/tui/app/theme-effort-pickers.mjs +11 -16
  237. package/src/tui/app/usage-context-panels.mjs +21 -25
  238. package/src/tui/app/use-global-key-input.mjs +3 -2
  239. package/src/tui/app/use-prompt-draft-flow.mjs +6 -18
  240. package/src/tui/app/use-prompt-handlers.mjs +3 -2
  241. package/src/tui/app/use-welcome-prompt-hint.mjs +17 -3
  242. package/src/tui/components/Picker.jsx +1 -1
  243. package/src/tui/components/TextEntryPanel.jsx +7 -2
  244. package/src/tui/dist/index.mjs +652 -561
  245. package/src/tui/lib/voice-setup.mjs +1 -2
  246. package/src/tui/session/agent-job-feed.mjs +73 -11
  247. package/src/tui/session/session-api-ext.mjs +5 -6
  248. package/src/tui/session/session-api.mjs +1 -0
  249. package/src/tui/session/tool-approval.mjs +15 -5
  250. package/src/tui/session/tui-steering-persist.mjs +33 -19
  251. package/src/tui/session/tui-steering-persist.test.mjs +104 -0
  252. package/src/tui/session-local.mjs +0 -22
  253. package/scripts/.tmp-coverage-report.mjs +0 -96
  254. package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.mjs +0 -57
  255. package/src/runtime/agent/orchestrator/tools/builtin/shell-monitor.test.mjs +0 -57
@@ -4086,8 +4086,6 @@ var CATEGORY_ORDER = [
4086
4086
  "Shell",
4087
4087
  "Agent",
4088
4088
  "Task",
4089
- "Schedule",
4090
- "Channel",
4091
4089
  "Setup",
4092
4090
  "Other"
4093
4091
  ];
@@ -4163,8 +4161,6 @@ var CATEGORY_COPY = /* @__PURE__ */ new Map([
4163
4161
  ["Shell", { active: "Running", done: "Ran", noun: "command" }],
4164
4162
  ["Agent", { active: "Calling", done: "Called", noun: "agent" }],
4165
4163
  ["Task", { active: "Checking", done: "Checked", noun: "task" }],
4166
- ["Schedule", { active: "Running", done: "Ran", noun: "schedule" }],
4167
- ["Channel", { active: "Sending", done: "Sent", noun: "message" }],
4168
4164
  ["Setup", { active: "Setting up", done: "Set up", noun: "item" }],
4169
4165
  ["Other", { active: "Calling", done: "Called", noun: "tool" }]
4170
4166
  ]);
@@ -4283,8 +4279,11 @@ function toolWorkUnit(name, args = {}, category = "") {
4283
4279
  case "job_wait":
4284
4280
  return unitDescriptor("Shell", { count: queryCount(a, "command", "commands", "cmd") || 1, noun: "command" });
4285
4281
  case "git":
4286
- case "git_stage":
4287
4282
  return unitDescriptor("Git", { count: queryCount(a, "command", "commands") || 1, noun: "Git command" });
4283
+ // Staging is not "running a Git command": it selects change_ids out of an
4284
+ // existing diff. Its own work unit keeps the two apart on the activity row.
4285
+ case "git_stage":
4286
+ return unitDescriptor("Git", { count: queryCount(a, "change_ids", "change_id") || 1, active: "Staging", done: "Staged", noun: "change" });
4288
4287
  case "agent":
4289
4288
  case "bridge": {
4290
4289
  const type = String(a.type || a.action || "").toLowerCase();
@@ -4303,8 +4302,11 @@ function toolWorkUnit(name, args = {}, category = "") {
4303
4302
  }
4304
4303
  case "task": {
4305
4304
  const action = String(a.action || "").toLowerCase();
4306
- if (action === "cancel") return unitDescriptor("Task", { count: queryCount(a, "task_id", "task_ids", "id", "ids") || 1, active: "Cancelling", done: "Cancelled", noun: "task" });
4307
- return unitDescriptor("Task", { count: queryCount(a, "task_id", "task_ids", "id", "ids") || 1, noun: "task" });
4305
+ const taskCount = queryCount(a, "task_id", "task_ids", "id", "ids") || 1;
4306
+ if (action === "cancel") return unitDescriptor("Task", { count: taskCount, active: "Cancelling", done: "Cancelled", noun: "task" });
4307
+ if (action === "wait") return unitDescriptor("Task", { count: taskCount, active: "Waiting for", done: "Waited for", noun: "task" });
4308
+ if (action === "list") return unitDescriptor("Task", { count: taskCount, active: "Listing", done: "Listed", noun: "task" });
4309
+ return unitDescriptor("Task", { count: taskCount, noun: "task" });
4308
4310
  }
4309
4311
  case "skill":
4310
4312
  case "skill_execute":
@@ -4319,7 +4321,9 @@ function toolWorkUnit(name, args = {}, category = "") {
4319
4321
  count: queryCount(a, "symbols", "symbol", "query", "file", "path") || 1,
4320
4322
  active: searching ? "Mapping" : "Reading",
4321
4323
  done: searching ? "Mapped" : "Read",
4322
- noun: searching ? "symbol" : "file"
4324
+ // "code map", not "file": an overview/imports/impact pass reads
4325
+ // structure, and sharing the plain read unit hid it behind file reads.
4326
+ noun: searching ? "symbol" : "code map"
4323
4327
  });
4324
4328
  }
4325
4329
  case "request_user_input":
@@ -5268,6 +5272,13 @@ init_config();
5268
5272
  // src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs
5269
5273
  init_plugin_paths();
5270
5274
  import { join as join6 } from "node:path";
5275
+
5276
+ // src/runtime/agent/orchestrator/providers/cursor-auth.mjs
5277
+ init_plugin_paths();
5278
+ init_atomic_file();
5279
+ var REFRESH_SKEW_MS = 5 * 6e4;
5280
+
5281
+ // src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs
5271
5282
  var ANTHROPIC_DEFAULT_CREDENTIALS_PATH = join6(resolvePluginData(), "anthropic-oauth-credentials.json");
5272
5283
 
5273
5284
  // src/runtime/agent/orchestrator/config.mjs
@@ -8512,6 +8523,21 @@ function textEntryReservedRows(value, width, maxRows) {
8512
8523
  return Math.min(wrappedTextRows(`${String(value ?? "")} `, w), cap);
8513
8524
  }
8514
8525
 
8526
+ // src/tui/app/text-entry-policy.mjs
8527
+ var CLEAR_BY_EMPTY_TEXT_ENTRY_KINDS = Object.freeze([
8528
+ "system-shell",
8529
+ "autoclear-provider",
8530
+ "profile-title"
8531
+ ]);
8532
+ var CLEAR_BY_EMPTY_KIND_SET = new Set(CLEAR_BY_EMPTY_TEXT_ENTRY_KINDS);
8533
+ function textEntryClearsByEmpty(kind) {
8534
+ return CLEAR_BY_EMPTY_KIND_SET.has(String(kind || ""));
8535
+ }
8536
+ function canSubmitTextEntry(value, allowEmpty = false) {
8537
+ if (allowEmpty === true) return true;
8538
+ return String(value ?? "").trim().length > 0;
8539
+ }
8540
+
8515
8541
  // src/tui/components/TextEntryPanel.jsx
8516
8542
  import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
8517
8543
  function insertText2(draft, input) {
@@ -8625,6 +8651,10 @@ function TextEntryPanel({
8625
8651
  hint = "",
8626
8652
  detail = "",
8627
8653
  initialValue = "",
8654
+ // Blank submit = the documented reset/clear action for some prompt kinds
8655
+ // (system shell → auto, provider auto-clear → built-in, profile title →
8656
+ // cleared). Off by default: every other prompt still requires a value.
8657
+ allowEmpty = false,
8628
8658
  mask = false,
8629
8659
  multiline = false,
8630
8660
  maxContentRows = 8,
@@ -8694,7 +8724,7 @@ function TextEntryPanel({
8694
8724
  }, [multiline, draft.value, mask, contentCells, maxContentRows, onContentRowsChange]);
8695
8725
  const submit = () => {
8696
8726
  if (submitGateRef.current) return;
8697
- if (!String(draftRef.current.value || "").trim()) return;
8727
+ if (!canSubmitTextEntry(draftRef.current.value, allowEmpty)) return;
8698
8728
  submitGateRef.current = true;
8699
8729
  const accepted = onSubmit?.(draftRef.current.value) !== false;
8700
8730
  if (accepted) {
@@ -8710,7 +8740,7 @@ function TextEntryPanel({
8710
8740
  if (submitGateRef.current) return;
8711
8741
  const current = draftRef.current;
8712
8742
  const next = prefix ? insertText2(current, prefix) : current;
8713
- if (!String(next.value || "").trim()) return;
8743
+ if (!canSubmitTextEntry(next.value, allowEmpty)) return;
8714
8744
  submitGateRef.current = true;
8715
8745
  const accepted = onSubmit?.(next.value) !== false;
8716
8746
  if (accepted) {
@@ -9376,7 +9406,7 @@ function compareSlashCommands(a, b) {
9376
9406
  return String(a?.name || "").localeCompare(String(b?.name || ""), "en", { sensitivity: "base" });
9377
9407
  }
9378
9408
  function overlayBlocksGlobalTranscriptScroll(owner = {}) {
9379
- return !!(owner.slashPaletteOpen || owner.picker || owner.toolApproval || owner.contextPanel || owner.usagePanel || owner.providerPrompt || owner.channelPrompt || owner.hookPrompt || owner.settingsPrompt);
9409
+ return !!(owner.slashPaletteOpen || owner.picker || owner.toolApproval || owner.contextPanel || owner.usagePanel || owner.providerPrompt || owner.settingsPrompt);
9380
9410
  }
9381
9411
  function normalizeSlashCommandName(cmd) {
9382
9412
  const name = String(cmd || "").toLowerCase();
@@ -9427,31 +9457,6 @@ function isLiveSpinnerMetaVisible({
9427
9457
  }
9428
9458
 
9429
9459
  // src/tui/app/input-parsers.mjs
9430
- function parseHookRuleInput(text) {
9431
- const parts = String(text || "").split("|").map((part) => part.trim());
9432
- const [tool, actionRaw, match, reason, patchText] = parts;
9433
- const action = String(actionRaw || "").toLowerCase();
9434
- if (!tool || !action) return { error: "usage: tool | allow|deny|modify | match(optional) | reason(optional) | json patch(optional)" };
9435
- if (!["allow", "deny", "block", "modify", "rewrite"].includes(action)) {
9436
- return { error: "hook action must be allow, deny, block, modify, or rewrite" };
9437
- }
9438
- const rule = { tool, action };
9439
- if (match) rule.match = match;
9440
- if (reason) rule.reason = reason;
9441
- if (patchText) {
9442
- try {
9443
- const patch = JSON.parse(patchText);
9444
- if (!patch || typeof patch !== "object" || Array.isArray(patch)) return { error: "json patch must be an object" };
9445
- rule.patch = patch;
9446
- } catch (e) {
9447
- return { error: `invalid json patch: ${e?.message || e}` };
9448
- }
9449
- }
9450
- if ((action === "modify" || action === "rewrite") && !rule.patch) {
9451
- return { error: "modify/rewrite needs a json patch object in the last field" };
9452
- }
9453
- return { rule };
9454
- }
9455
9460
  function parseMcpServerInput(text) {
9456
9461
  const parts = String(text || "").split("|").map((part) => part.trim());
9457
9462
  const [name, commandOrUrl, argsText = "", cwd = ""] = parts;
@@ -9608,6 +9613,90 @@ function copyToClipboard(text) {
9608
9613
  });
9609
9614
  }
9610
9615
 
9616
+ // src/tui/app/panel-epoch.mjs
9617
+ var panelEpoch = 0;
9618
+ function currentPanelEpoch() {
9619
+ return panelEpoch;
9620
+ }
9621
+ function supersedePanelEpoch() {
9622
+ panelEpoch += 1;
9623
+ return panelEpoch;
9624
+ }
9625
+ function isPanelEpochCurrent(token) {
9626
+ return token === panelEpoch;
9627
+ }
9628
+ function panelIdentity(panel) {
9629
+ if (!panel || typeof panel !== "object") return null;
9630
+ return panel._kind || panel.title || null;
9631
+ }
9632
+ function shouldSupersedePanelEpoch(previous, next) {
9633
+ if (!previous || typeof previous !== "object") return false;
9634
+ if (!next || typeof next !== "object") return true;
9635
+ if (previous === next) return false;
9636
+ return panelIdentity(previous) !== panelIdentity(next);
9637
+ }
9638
+
9639
+ // src/tui/app/panel-surface.mjs
9640
+ function createPanelSurface({ setPicker, setContextPanel, setUsagePanel } = {}) {
9641
+ let usageGeneration = 0;
9642
+ const claim = () => {
9643
+ let token = currentPanelEpoch();
9644
+ let released = false;
9645
+ const owns = () => !released && isPanelEpochCurrent(token);
9646
+ const write = (sink, value) => {
9647
+ if (!owns()) return false;
9648
+ sink?.(value);
9649
+ token = currentPanelEpoch();
9650
+ return true;
9651
+ };
9652
+ return {
9653
+ owns,
9654
+ paint: (panel) => write(setPicker, panel),
9655
+ // Clearing the context panel hands the surface back exactly as closing a
9656
+ // picker does. setPicker's caller supersedes the epoch on a close (see
9657
+ // shouldSupersedePanelEpoch); this sink has no such step, so a context
9658
+ // open still in flight stayed valid and repainted "Context Usage" after
9659
+ // the user had already pressed Esc. Superseding here is what makes the
9660
+ // dismissal final, and re-reading the token keeps THIS flow (Esc inside a
9661
+ // settings picker, which clears context and carries on) working.
9662
+ context: (panel) => {
9663
+ if (!owns()) return false;
9664
+ setContextPanel?.(panel);
9665
+ if (panel == null) supersedePanelEpoch();
9666
+ token = currentPanelEpoch();
9667
+ return true;
9668
+ },
9669
+ close: () => {
9670
+ if (!owns()) return false;
9671
+ setPicker?.(null);
9672
+ released = true;
9673
+ return true;
9674
+ },
9675
+ defer: (run) => {
9676
+ const deferredToken = token;
9677
+ return (...args) => !released && isPanelEpochCurrent(deferredToken) ? run(...args) : void 0;
9678
+ }
9679
+ };
9680
+ };
9681
+ const claimUsage = () => {
9682
+ const generation = usageGeneration += 1;
9683
+ const owns = () => generation === usageGeneration;
9684
+ return {
9685
+ owns,
9686
+ paint: (dashboard) => {
9687
+ if (!owns()) return false;
9688
+ setUsagePanel?.(dashboard);
9689
+ return true;
9690
+ }
9691
+ };
9692
+ };
9693
+ const closeUsage = () => {
9694
+ usageGeneration += 1;
9695
+ setUsagePanel?.(null);
9696
+ };
9697
+ return { claim, claimUsage, closeUsage };
9698
+ }
9699
+
9611
9700
  // src/tui/App.jsx
9612
9701
  import stringWidth11 from "string-width";
9613
9702
 
@@ -11959,7 +12048,7 @@ function normalizeToolTerminalStatus(value) {
11959
12048
  if (/^(running|pending|queued|in_progress|in-progress)$/.test(raw)) return "running";
11960
12049
  if (/^(completed|complete|done|success|succeeded|ok)$/.test(raw)) return "completed";
11961
12050
  if (/^(failed|fail|error|errored|timeout|timed_out|killed)$/.test(raw)) return "failed";
11962
- if (/^(cancelled|canceled|cancel)$/.test(raw)) return "cancelled";
12051
+ if (/^(cancelled|canceled|cancel|cancel[-_ ]unconfirmed|cancel[-_ ]pending|cancelling|canceling)$/.test(raw)) return "cancelled";
11963
12052
  if (/^(denied|deny|refused|rejected)$/.test(raw)) return "denied";
11964
12053
  return "";
11965
12054
  }
@@ -14844,12 +14933,20 @@ function useWelcomePromptHint({ store, state, toastErrorSignature }) {
14844
14933
  }
14845
14934
  }
14846
14935
  }
14847
- const activeWorkflow = await activeWorkflowSummaryForStore(store, state.workflow || {});
14936
+ let activeWorkflow = null;
14937
+ try {
14938
+ activeWorkflow = await activeWorkflowSummaryForStore(store, state.workflow || {});
14939
+ } catch {
14940
+ }
14848
14941
  if (!next && String(activeWorkflow?.id || state.workflow?.id || "").toLowerCase() === "solo") {
14849
14942
  next = CONDITIONAL_WELCOME_PROMPT_HINTS.soloWorkflow;
14850
14943
  }
14851
14944
  if (!next) {
14852
- const webSearchRoute = await store.getWebSearchRoute?.() || null;
14945
+ let webSearchRoute = null;
14946
+ try {
14947
+ webSearchRoute = await store.getWebSearchRoute?.() || null;
14948
+ } catch {
14949
+ }
14853
14950
  const webSearchProvider = String(webSearchRoute?.provider || "").trim();
14854
14951
  const webSearchModel = String(webSearchRoute?.model || "").trim();
14855
14952
  const defaultWebSearchRoute = webSearchProvider.toLowerCase() === "default" && webSearchModel.toLowerCase() === "default";
@@ -14869,7 +14966,8 @@ function useWelcomePromptHint({ store, state, toastErrorSignature }) {
14869
14966
  }
14870
14967
  if (alive) setConditionalWelcomePromptHint((prev) => prev === next ? prev : next);
14871
14968
  };
14872
- void refreshConditionalWelcomeHint();
14969
+ void refreshConditionalWelcomeHint().catch(() => {
14970
+ });
14873
14971
  return () => {
14874
14972
  alive = false;
14875
14973
  };
@@ -14919,27 +15017,20 @@ function useCopySelection({
14919
15017
  function createUsageContextPanels({
14920
15018
  store,
14921
15019
  state,
14922
- usageRequestRef,
14923
- setPicker,
15020
+ surface,
14924
15021
  setProviderPrompt,
14925
- setChannelPrompt,
14926
- setHookPrompt,
14927
15022
  setSettingsPrompt,
14928
- setContextPanel,
14929
- setUsagePanel,
14930
15023
  closeUsagePanel
14931
15024
  }) {
14932
15025
  const openUsagePanel = (arg = "") => {
14933
15026
  const refresh = /(?:^|\s)(?:refresh|--refresh|-r|true)(?:\s|$)/i.test(String(arg || ""));
14934
- const requestId = usageRequestRef.current + 1;
14935
- usageRequestRef.current = requestId;
15027
+ const own = surface.claim();
15028
+ const dashboardOwn = surface.claimUsage();
14936
15029
  setProviderPrompt(null);
14937
- setChannelPrompt(null);
14938
- setHookPrompt(null);
14939
15030
  setSettingsPrompt(null);
14940
- setPicker(null);
14941
- setContextPanel(null);
14942
- setUsagePanel({
15031
+ own.paint(null);
15032
+ own.context(null);
15033
+ dashboardOwn.paint({
14943
15034
  title: "Provider Quotas",
14944
15035
  subtitle: "Statusline-style provider quota windows.",
14945
15036
  checking: true,
@@ -14948,30 +15039,29 @@ function createUsageContextPanels({
14948
15039
  total: null
14949
15040
  });
14950
15041
  setTimeout(() => {
14951
- if (usageRequestRef.current !== requestId) return;
15042
+ if (!dashboardOwn.owns()) return;
14952
15043
  void store.getUsageDashboard?.({
14953
15044
  refresh,
14954
15045
  onUpdate: (dashboard) => {
14955
- if (usageRequestRef.current !== requestId) return;
14956
- if (!dashboard) return;
14957
- setUsagePanel(dashboard);
15046
+ if (dashboard) dashboardOwn.paint(dashboard);
14958
15047
  }
14959
15048
  }).then((dashboard) => {
14960
- if (usageRequestRef.current !== requestId) return;
15049
+ if (!dashboardOwn.owns()) return;
14961
15050
  if (!dashboard) {
14962
15051
  closeUsagePanel();
14963
15052
  store.pushNotice("usage dashboard unavailable", "warn");
14964
15053
  return;
14965
15054
  }
14966
- setUsagePanel(dashboard);
15055
+ dashboardOwn.paint(dashboard);
14967
15056
  }).catch((e) => {
14968
- if (usageRequestRef.current !== requestId) return;
15057
+ if (!dashboardOwn.owns()) return;
14969
15058
  closeUsagePanel();
14970
15059
  store.pushNotice(`usage failed: ${e?.message || e}`, "error");
14971
15060
  });
14972
15061
  }, 0);
14973
15062
  };
14974
15063
  const openContextPicker = async () => {
15064
+ const own = surface.claim();
14975
15065
  const [toolsStatus, mcpStatus, skillsStatus, pluginsStatus, contextStatusValue] = await Promise.all([
14976
15066
  Promise.resolve(store.toolsStatus?.()).catch(() => null),
14977
15067
  Promise.resolve(store.mcpStatus?.()).catch(() => null),
@@ -15109,12 +15199,11 @@ function createUsageContextPanels({
15109
15199
  _action: "extensions"
15110
15200
  }
15111
15201
  ];
15202
+ if (!own.owns()) return;
15112
15203
  setProviderPrompt(null);
15113
- setChannelPrompt(null);
15114
- setHookPrompt(null);
15115
15204
  setSettingsPrompt(null);
15116
- setPicker(null);
15117
- setContextPanel({
15205
+ own.paint(null);
15206
+ own.context({
15118
15207
  kind: "context",
15119
15208
  title: "Context Usage",
15120
15209
  detail: {
@@ -15194,21 +15283,20 @@ function createUsageContextPanels({
15194
15283
 
15195
15284
  // src/tui/app/prompt-submit.mjs
15196
15285
  init_paste_attachments();
15286
+ var providerWriteToken = 0;
15287
+ var settingsWriteToken = 0;
15288
+ var providerWriteInFlight = () => providerWriteToken > 0 && isPanelEpochCurrent(providerWriteToken);
15289
+ var settingsWriteInFlight = () => settingsWriteToken > 0 && isPanelEpochCurrent(settingsWriteToken);
15197
15290
  function createPromptSubmit({
15198
15291
  store,
15199
15292
  state,
15200
15293
  providerPrompt,
15201
- channelPrompt,
15202
- hookPrompt,
15203
15294
  settingsPrompt,
15204
15295
  setProviderPrompt,
15205
- setChannelPrompt,
15206
- setHookPrompt,
15207
15296
  setSettingsPrompt,
15208
15297
  oauthSubmitRef,
15209
15298
  clearModelCaches,
15210
15299
  openProviderSetupPicker,
15211
- openHooksPicker,
15212
15300
  openSettingsPicker,
15213
15301
  openProjectPicker,
15214
15302
  openAutoClearPicker,
@@ -15232,6 +15320,12 @@ function createPromptSubmit({
15232
15320
  }
15233
15321
  return Promise.resolve(target.apply(store, args));
15234
15322
  };
15323
+ const openPanel = (open, ...args) => {
15324
+ if (typeof open !== "function") return;
15325
+ void Promise.resolve(open(...args)).catch((error) => {
15326
+ store.pushNotice(`panel failed to open: ${error?.message || error}`, "error");
15327
+ });
15328
+ };
15235
15329
  const submitPrompt = (prompt, options) => {
15236
15330
  if (typeof store.submitAsync !== "function") return store.submit(prompt, options);
15237
15331
  void Promise.resolve(store.submitAsync(prompt, options)).then((accepted) => {
@@ -15241,6 +15335,14 @@ function createPromptSubmit({
15241
15335
  });
15242
15336
  return true;
15243
15337
  };
15338
+ const restoreSettingsPrompt = (target, value) => {
15339
+ setSettingsPrompt({
15340
+ ...target,
15341
+ submitting: false,
15342
+ initialValue: value,
15343
+ restoreEpoch: (Number(target.restoreEpoch) || 0) + 1
15344
+ });
15345
+ };
15244
15346
  const onSubmit = (raw) => {
15245
15347
  const text = String(raw ?? "");
15246
15348
  const commandText = text.trim();
@@ -15249,57 +15351,80 @@ function createPromptSubmit({
15249
15351
  store.pushNotice("wait for the current command to finish", "warn");
15250
15352
  return false;
15251
15353
  }
15354
+ const beginProviderSave = (target) => {
15355
+ const token = supersedePanelEpoch();
15356
+ providerWriteToken = token;
15357
+ setProviderPrompt((prompt) => prompt === target ? { ...prompt, submitting: true } : prompt);
15358
+ return token;
15359
+ };
15360
+ const endProviderSave = (token) => {
15361
+ if (providerWriteToken === token) providerWriteToken = 0;
15362
+ };
15363
+ const finishProviderSave = (target, token) => {
15364
+ endProviderSave(token);
15365
+ if (!isPanelEpochCurrent(token)) return;
15366
+ setProviderPrompt(null);
15367
+ if (target.afterSave) target.afterSave();
15368
+ else openPanel(openProviderSetupPicker);
15369
+ };
15370
+ const failProviderSave = (target, value, message, token) => {
15371
+ endProviderSave(token);
15372
+ store.pushNotice(message, "error");
15373
+ if (!isPanelEpochCurrent(token)) return;
15374
+ supersedePanelEpoch();
15375
+ setProviderPrompt({
15376
+ ...target,
15377
+ submitting: false,
15378
+ initialValue: value,
15379
+ restoreEpoch: (Number(target.restoreEpoch) || 0) + 1
15380
+ });
15381
+ };
15252
15382
  if (providerPrompt.kind === "api-key") {
15253
15383
  if (!commandText) {
15254
15384
  store.pushNotice(`API key is required for ${providerPrompt.providerId}`, "warn");
15255
15385
  return false;
15256
15386
  }
15257
- try {
15258
- store.saveProviderApiKey(providerPrompt.providerId, commandText);
15259
- clearModelCaches("all");
15260
- const afterSave = providerPrompt.afterSave;
15261
- setProviderPrompt(null);
15262
- if (afterSave) afterSave();
15263
- else void openProviderSetupPicker();
15264
- return true;
15265
- } catch (e) {
15266
- store.pushNotice(`api key save failed: ${e?.message || e}`, "error");
15387
+ if (providerWriteInFlight()) {
15388
+ store.pushNotice("API key is already being saved", "warn");
15267
15389
  return false;
15268
15390
  }
15391
+ const target = providerPrompt;
15392
+ const token = beginProviderSave(target);
15393
+ void serviceCall("saveProviderApiKey", target.providerId, commandText).then(() => {
15394
+ clearModelCaches("all");
15395
+ finishProviderSave(target, token);
15396
+ }).catch((error) => failProviderSave(target, commandText, `api key save failed: ${error?.message || error}`, token));
15397
+ return true;
15269
15398
  }
15270
15399
  if (providerPrompt.kind === "openai-usage-session") {
15271
15400
  if (!commandText) {
15272
15401
  store.pushNotice("OpenAI usage session key is required for credit lookup", "warn");
15273
15402
  return false;
15274
15403
  }
15275
- try {
15276
- store.saveOpenAIUsageSessionKey(commandText);
15277
- const afterSave = providerPrompt.afterSave;
15278
- setProviderPrompt(null);
15279
- if (afterSave) afterSave();
15280
- else void openProviderSetupPicker();
15281
- return true;
15282
- } catch (e) {
15283
- store.pushNotice(`OpenAI usage auth save failed: ${e?.message || e}`, "error");
15404
+ if (providerWriteInFlight()) {
15405
+ store.pushNotice("OpenAI usage session key is already being saved", "warn");
15284
15406
  return false;
15285
15407
  }
15408
+ const target = providerPrompt;
15409
+ const token = beginProviderSave(target);
15410
+ void serviceCall("saveOpenAIUsageSessionKey", commandText).then(() => finishProviderSave(target, token)).catch((error) => failProviderSave(target, commandText, `OpenAI usage auth save failed: ${error?.message || error}`, token));
15411
+ return true;
15286
15412
  }
15287
15413
  if (providerPrompt.kind === "local-url") {
15288
- try {
15289
- store.setLocalProvider(providerPrompt.providerId, {
15290
- enabled: true,
15291
- baseURL: commandText || providerPrompt.defaultURL
15292
- });
15293
- clearModelCaches("all");
15294
- const afterSave = providerPrompt.afterSave;
15295
- setProviderPrompt(null);
15296
- if (afterSave) afterSave();
15297
- else void openProviderSetupPicker();
15298
- return true;
15299
- } catch (e) {
15300
- store.pushNotice(`local provider update failed: ${e?.message || e}`, "error");
15414
+ if (providerWriteInFlight()) {
15415
+ store.pushNotice("local provider update is already running", "warn");
15301
15416
  return false;
15302
15417
  }
15418
+ const target = providerPrompt;
15419
+ const token = beginProviderSave(target);
15420
+ void serviceCall("setLocalProvider", target.providerId, {
15421
+ enabled: true,
15422
+ baseURL: commandText || target.defaultURL
15423
+ }).then(() => {
15424
+ clearModelCaches("all");
15425
+ finishProviderSave(target, token);
15426
+ }).catch((error) => failProviderSave(target, commandText, `local provider update failed: ${error?.message || error}`, token));
15427
+ return true;
15303
15428
  }
15304
15429
  if (providerPrompt.kind === "oauth-code") {
15305
15430
  if (!commandText) {
@@ -15321,7 +15446,7 @@ function createPromptSubmit({
15321
15446
  store.pushNotice(`${providerPrompt.providerName || "OAuth"} login complete`, "info");
15322
15447
  if (successReturn) successReturn();
15323
15448
  else if (afterSave) afterSave();
15324
- else void openProviderSetupPicker();
15449
+ else openPanel(openProviderSetupPicker);
15325
15450
  }).catch((e) => {
15326
15451
  oauthSubmitRef.current = false;
15327
15452
  store.pushNotice(`oauth code failed: ${e?.message || e}`, "error");
@@ -15331,46 +15456,51 @@ function createPromptSubmit({
15331
15456
  return true;
15332
15457
  }
15333
15458
  }
15334
- if (hookPrompt) {
15459
+ if (settingsPrompt) {
15335
15460
  if (state.commandBusy) {
15336
15461
  store.pushNotice("wait for the current command to finish", "warn");
15337
15462
  return false;
15338
15463
  }
15339
- try {
15340
- if (hookPrompt.kind === "rule-add") {
15341
- const parsed = parseHookRuleInput(commandText);
15342
- if (parsed.error) {
15343
- store.pushNotice(parsed.error, "warn");
15344
- return false;
15345
- }
15346
- store.addHookRule?.(parsed.rule);
15347
- setHookPrompt(null);
15348
- void openHooksPicker();
15349
- return true;
15350
- }
15351
- } catch (e) {
15352
- store.pushNotice(`hook update failed: ${e?.message || e}`, "error");
15353
- return false;
15354
- }
15355
- }
15356
- if (settingsPrompt) {
15357
- if (state.commandBusy) {
15358
- store.pushNotice("wait for the current command to finish", "warn");
15464
+ if (settingsWriteInFlight()) {
15465
+ store.pushNotice("wait for the current settings change to finish", "warn");
15359
15466
  return false;
15360
15467
  }
15468
+ const beginSettingsSave = (target) => {
15469
+ const token = supersedePanelEpoch();
15470
+ settingsWriteToken = token;
15471
+ setSettingsPrompt((prompt) => prompt === target ? { ...prompt, submitting: true } : prompt);
15472
+ return token;
15473
+ };
15474
+ const endSettingsSave = (token) => {
15475
+ if (settingsWriteToken === token) settingsWriteToken = 0;
15476
+ };
15477
+ const finishSettingsSave = (token, after) => {
15478
+ endSettingsSave(token);
15479
+ if (!isPanelEpochCurrent(token)) return;
15480
+ setSettingsPrompt(null);
15481
+ after?.();
15482
+ };
15483
+ const failSettingsSave = (target, value, message, token, tone = "error") => {
15484
+ endSettingsSave(token);
15485
+ store.pushNotice(message, tone);
15486
+ if (!isPanelEpochCurrent(token)) return;
15487
+ supersedePanelEpoch();
15488
+ restoreSettingsPrompt(target, value);
15489
+ };
15361
15490
  try {
15362
15491
  if (settingsPrompt.kind === "cwd") {
15363
15492
  if (!commandText) {
15364
15493
  store.pushNotice("working directory path is required", "warn");
15365
15494
  return false;
15366
15495
  }
15496
+ const target = settingsPrompt;
15497
+ const token = beginSettingsSave(target);
15367
15498
  void serviceCall("setCwd", commandText, {
15368
15499
  message: `Project set: ${projectNameFromPath(commandText)}`
15369
15500
  }).then(() => {
15370
- setSettingsPrompt(null);
15371
- void openSettingsPicker();
15501
+ finishSettingsSave(token, () => openPanel(openSettingsPicker));
15372
15502
  }).catch((error) => {
15373
- store.pushNotice(`project switch failed: ${error?.message || error}`, "error");
15503
+ failSettingsSave(target, commandText, `project switch failed: ${error?.message || error}`, token);
15374
15504
  });
15375
15505
  return true;
15376
15506
  }
@@ -15379,17 +15509,21 @@ function createPromptSubmit({
15379
15509
  store.pushNotice("project path is required", "warn");
15380
15510
  return false;
15381
15511
  }
15512
+ const target = settingsPrompt;
15513
+ const token = beginSettingsSave(target);
15382
15514
  void serviceCall("inspectProjectPath", commandText).then((result) => {
15383
15515
  const path2 = String(result?.path || commandText);
15384
15516
  if (result?.directory === true) {
15385
- setSettingsPrompt(null);
15386
- void registerProject(path2);
15517
+ finishSettingsSave(token, () => openPanel(registerProject, path2));
15387
15518
  return;
15388
15519
  }
15389
15520
  if (result?.exists === true) {
15390
- store.pushNotice(`${path2} is not a directory`, "warn");
15521
+ failSettingsSave(target, commandText, `${path2} is not a directory`, token, "warn");
15391
15522
  return;
15392
15523
  }
15524
+ endSettingsSave(token);
15525
+ if (!isPanelEpochCurrent(token)) return;
15526
+ supersedePanelEpoch();
15393
15527
  setSettingsPrompt({
15394
15528
  kind: "project-create-confirm",
15395
15529
  label: "New project \xB7 Create folder?",
@@ -15397,7 +15531,7 @@ function createPromptSubmit({
15397
15531
  pendingPath: path2
15398
15532
  });
15399
15533
  }).catch((error) => {
15400
- store.pushNotice(`project path check failed: ${error?.message || error}`, "error");
15534
+ failSettingsSave(target, commandText, `project path check failed: ${error?.message || error}`, token);
15401
15535
  });
15402
15536
  return true;
15403
15537
  }
@@ -15405,12 +15539,14 @@ function createPromptSubmit({
15405
15539
  const pendingPath = String(settingsPrompt.pendingPath || "");
15406
15540
  const answer = String(commandText || "").trim().toLowerCase();
15407
15541
  if (answer === "y" || answer === "yes") {
15542
+ const target = settingsPrompt;
15543
+ const token = beginSettingsSave(target);
15408
15544
  void serviceCall("ensureProjectDirectory", pendingPath).then((created) => {
15409
- setSettingsPrompt(null);
15410
- void registerProject(created || pendingPath);
15545
+ finishSettingsSave(token, () => openPanel(registerProject, created || pendingPath));
15411
15546
  }).catch((error) => {
15547
+ endSettingsSave(token);
15412
15548
  store.pushNotice(`could not create folder: ${error?.message || error}`, "error");
15413
- setSettingsPrompt(null);
15549
+ if (isPanelEpochCurrent(token)) setSettingsPrompt(null);
15414
15550
  });
15415
15551
  return true;
15416
15552
  }
@@ -15420,21 +15556,26 @@ function createPromptSubmit({
15420
15556
  }
15421
15557
  if (settingsPrompt.kind === "project-rename") {
15422
15558
  const targetPath = String(settingsPrompt.projectPath || "");
15559
+ const target = settingsPrompt;
15560
+ const token = beginSettingsSave(target);
15423
15561
  void serviceCall("renameProject", targetPath, commandText).then((updated) => {
15424
15562
  if (updated) {
15425
15563
  store.pushNotice(`project renamed to "${updated.name}"`, "info");
15426
15564
  }
15427
- setSettingsPrompt(null);
15428
- void openProjectPicker();
15565
+ finishSettingsSave(token, () => openPanel(openProjectPicker));
15429
15566
  }).catch((error) => {
15430
- store.pushNotice(`rename failed: ${error?.message || error}`, "error");
15567
+ failSettingsSave(target, commandText, `rename failed: ${error?.message || error}`, token);
15431
15568
  });
15432
15569
  return true;
15433
15570
  }
15434
15571
  if (settingsPrompt.kind === "system-shell") {
15435
- store.setSystemShell?.(commandText);
15436
- setSettingsPrompt(null);
15437
- void openSettingsPicker();
15572
+ const target = settingsPrompt;
15573
+ const token = beginSettingsSave(target);
15574
+ void serviceCall("setSystemShell", commandText).then(() => {
15575
+ finishSettingsSave(token, () => openPanel(openSettingsPicker));
15576
+ }).catch((error) => {
15577
+ failSettingsSave(target, commandText, `system shell update failed: ${error?.message || error}`, token);
15578
+ });
15438
15579
  return true;
15439
15580
  }
15440
15581
  if (settingsPrompt.kind === "autoclear-provider") {
@@ -15443,28 +15584,26 @@ function createPromptSubmit({
15443
15584
  store.pushNotice("auto-clear provider is missing", "warn");
15444
15585
  return false;
15445
15586
  }
15446
- const text2 = String(commandText || "").trim();
15447
- try {
15448
- if (text2) store.setAutoClear?.({ provider, duration: text2 });
15449
- else store.setAutoClear?.({ provider, resetProvider: true });
15450
- store.pushNotice(text2 ? `Auto-clear ${provider} default set to ${text2}` : `Auto-clear ${provider} default reset`, "info");
15451
- } catch (e) {
15452
- store.pushNotice(`autoclear failed: ${e?.message || e}`, "error");
15453
- return false;
15454
- }
15455
- setSettingsPrompt(null);
15456
- openAutoClearPicker({ advanced: true, returnTo: settingsPrompt.returnTo });
15587
+ const duration = String(commandText || "").trim();
15588
+ const target = settingsPrompt;
15589
+ const token = beginSettingsSave(target);
15590
+ void serviceCall("setAutoClear", duration ? { provider, duration } : { provider, resetProvider: true }).then(() => {
15591
+ store.pushNotice(duration ? `Auto-clear ${provider} default set to ${duration}` : `Auto-clear ${provider} default reset`, "info");
15592
+ finishSettingsSave(token, () => openPanel(openAutoClearPicker, { advanced: true, returnTo: target.returnTo }));
15593
+ }).catch((error) => {
15594
+ failSettingsSave(target, duration, `autoclear failed: ${error?.message || error}`, token);
15595
+ });
15457
15596
  return true;
15458
15597
  }
15459
15598
  if (settingsPrompt.kind === "profile-title") {
15460
- try {
15461
- store.setProfile?.({ title: commandText });
15599
+ const target = settingsPrompt;
15600
+ const token = beginSettingsSave(target);
15601
+ void serviceCall("setProfile", { title: commandText }).then(() => {
15462
15602
  store.pushNotice(commandText ? `Title set to "${commandText.trim()}"` : "Title cleared", "info");
15463
- } catch (e) {
15464
- store.pushNotice(`profile update failed: ${e?.message || e}`, "error");
15465
- }
15466
- setSettingsPrompt(null);
15467
- openProfilePicker();
15603
+ finishSettingsSave(token, () => openPanel(openProfilePicker));
15604
+ }).catch((error) => {
15605
+ failSettingsSave(target, commandText, `profile update failed: ${error?.message || error}`, token);
15606
+ });
15468
15607
  return true;
15469
15608
  }
15470
15609
  if (settingsPrompt.kind === "plugin-add") {
@@ -15616,8 +15755,6 @@ function createPromptSubmit({
15616
15755
  // src/tui/app/shell-layout.mjs
15617
15756
  function computeShellLayout({
15618
15757
  providerPrompt,
15619
- channelPrompt,
15620
- hookPrompt,
15621
15758
  settingsPrompt,
15622
15759
  panelTransitionEpoch,
15623
15760
  panelInkMaskEpoch,
@@ -15653,7 +15790,7 @@ function computeShellLayout({
15653
15790
  isInstantPanelCloseTransition: isInstantPanelCloseTransition2,
15654
15791
  PANEL_LAYOUT_SIG: PANEL_LAYOUT_SIG2
15655
15792
  }) {
15656
- const textEntryPrompt = providerPrompt || channelPrompt || hookPrompt || settingsPrompt;
15793
+ const textEntryPrompt = providerPrompt || settingsPrompt;
15657
15794
  const hasTextEntryPrompt = !!textEntryPrompt;
15658
15795
  const hasFloatingPanel = !!(toolApproval || picker || contextPanel || usagePanel || slashPaletteOpen || hasTextEntryPrompt);
15659
15796
  const expandedOptionPanel = !!(toolApproval || picker || contextPanel || usagePanel || hasTextEntryPrompt);
@@ -15909,7 +16046,7 @@ function useGlobalKeyInput({
15909
16046
  picker,
15910
16047
  usagePanel,
15911
16048
  contextPanel,
15912
- setContextPanel,
16049
+ surface,
15913
16050
  closeUsagePanel,
15914
16051
  isRawModeSupported,
15915
16052
  resizeState,
@@ -15987,7 +16124,7 @@ function useGlobalKeyInput({
15987
16124
  return;
15988
16125
  }
15989
16126
  if (key.escape && contextPanel && !picker) {
15990
- setContextPanel(null);
16127
+ surface.claim().context(null);
15991
16128
  return;
15992
16129
  }
15993
16130
  if (key.pageUp) {
@@ -16781,7 +16918,7 @@ var Item = React19.memo(function Item2({ item, prevKind, columns, toolOutputExpa
16781
16918
  // src/tui/app/app-view.jsx
16782
16919
  import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
16783
16920
  function renderAppView(ctx) {
16784
- const { PANEL_MAX_VISIBLE, acceptSlashPalette, activeSlashQuery, activeTools, agentRevision, cancelChannelPrompt, cancelHookPrompt, cancelProviderPrompt, cancelSettingsPrompt, cancelSlashPalette, channelPrompt, clearPromptHint, completeSlashPalette, contextPanel, cycleWorkflowFromPrompt, exiting, expandedOptionPanel, floatingPanelRows, frameColumns, gridSelectionActiveRef, guardHintWidth, handlePromptEscape, handlePromptHistoryNavigate, handlePromptInterrupt, handlePromptPaste, hasUserMessages, hookPrompt, initialStatusLine, inputBoxHidden, inputHint, inputHintTone, liveSpinner, onPromptDraftChange, onSubmit, overlayHintAttachItemIndex, overlayHintBandRows, overlayHintFallbackRow, overlayHintOnLastItem, panelCloseMaskRows, panelInkMaskEpoch, panelTransitionClearRows, panelTransitionEpoch, picker, pickerOpenedFromEnterRef, pickerOpenedFromEnterTimerRef, pickerVisibleRows, promptBoxRectRef, promptBoxRows, promptDraft, promptDraftOverride, promptMetaVisible, promptMouseSelectionRef, promptSelectionRef, promptSpinnerColumns, promptValueRef, providerPrompt, queuedCompact, queuedVisible, renderedTranscriptItems, resizeEpoch, resizeState, restoreQueuedToPrompt, setPicker, setSlashIndex, setTextEntryLayoutRows, settingsPrompt, showWelcomeBanner, slashCommands, slashIndex, slashPaletteOpen, state, statuslineStats, store, toolApproval, toolOutputExpanded, transcriptContentHeight, transcriptGuardRows, transcriptMeasureRef, transcriptTailPinned, transcriptWindow, transientStatusWidth, tuiReady, usagePanel, viewportHeight, welcomePromptHintRows, welcomePromptHintText } = ctx;
16921
+ const { PANEL_MAX_VISIBLE, acceptSlashPalette, activeSlashQuery, activeTools, agentRevision, cancelProviderPrompt, cancelSettingsPrompt, cancelSlashPalette, clearPromptHint, completeSlashPalette, contextPanel, cycleWorkflowFromPrompt, exiting, expandedOptionPanel, floatingPanelRows, frameColumns, gridSelectionActiveRef, guardHintWidth, handlePromptEscape, handlePromptHistoryNavigate, handlePromptInterrupt, handlePromptPaste, hasUserMessages, initialStatusLine, inputBoxHidden, inputHint, inputHintTone, liveSpinner, onPromptDraftChange, onSubmit, overlayHintAttachItemIndex, overlayHintBandRows, overlayHintFallbackRow, overlayHintOnLastItem, panelCloseMaskRows, panelInkMaskEpoch, panelTransitionClearRows, panelTransitionEpoch, picker, pickerOpenedFromEnterRef, pickerOpenedFromEnterTimerRef, pickerVisibleRows, promptBoxRectRef, promptBoxRows, promptDraft, promptDraftOverride, promptMetaVisible, promptMouseSelectionRef, promptSelectionRef, promptSpinnerColumns, promptValueRef, providerPrompt, queuedCompact, queuedVisible, renderedTranscriptItems, resizeEpoch, resizeState, restoreQueuedToPrompt, setSlashIndex, setTextEntryLayoutRows, settingsPrompt, showWelcomeBanner, slashCommands, slashIndex, slashPaletteOpen, state, statuslineStats, store, surface, toolApproval, toolOutputExpanded, transcriptContentHeight, transcriptGuardRows, transcriptMeasureRef, transcriptTailPinned, transcriptWindow, transientStatusWidth, tuiReady, usagePanel, viewportHeight, welcomePromptHintRows, welcomePromptHintText } = ctx;
16785
16922
  const promptInputControl = /* @__PURE__ */ jsx20(
16786
16923
  PromptInput,
16787
16924
  {
@@ -16967,7 +17104,7 @@ function renderAppView(ctx) {
16967
17104
  onCancel: () => {
16968
17105
  if (picker.onCancel) picker.onCancel();
16969
17106
  else {
16970
- setPicker(null);
17107
+ surface.claim().close();
16971
17108
  clearPromptHint();
16972
17109
  }
16973
17110
  },
@@ -17030,32 +17167,13 @@ function renderAppView(ctx) {
17030
17167
  detail: providerPrompt.detail || "",
17031
17168
  mask: providerPrompt.kind === "api-key" || providerPrompt.kind === "openai-usage-session",
17032
17169
  columns: frameColumns,
17170
+ initialValue: providerPrompt.initialValue || "",
17033
17171
  actionLabel: providerPrompt.kind === "oauth-code" ? "continue" : "save",
17034
17172
  promptLabel: providerPrompt.kind === "api-key" ? "API key > " : providerPrompt.kind === "oauth-code" ? "Paste code here if prompted > " : providerPrompt.kind === "openai-usage-session" ? "Session key > " : "Base URL > ",
17035
17173
  onSubmit,
17036
17174
  onCancel: cancelProviderPrompt
17037
- }
17038
- ) : channelPrompt ? /* @__PURE__ */ jsx20(
17039
- TextEntryPanel,
17040
- {
17041
- title: channelPrompt.label,
17042
- hint: channelPrompt.hint || "Save channel setting.",
17043
- mask: channelPrompt.kind === "webhook-token",
17044
- columns: frameColumns,
17045
- promptLabel: "Value > ",
17046
- onSubmit,
17047
- onCancel: cancelChannelPrompt
17048
- }
17049
- ) : hookPrompt ? /* @__PURE__ */ jsx20(
17050
- TextEntryPanel,
17051
- {
17052
- title: hookPrompt.label,
17053
- hint: hookPrompt.hint || "Save hook setting.",
17054
- columns: frameColumns,
17055
- promptLabel: "Value > ",
17056
- onSubmit,
17057
- onCancel: cancelHookPrompt
17058
- }
17175
+ },
17176
+ `provider-prompt:${providerPrompt.restoreEpoch || 0}`
17059
17177
  ) : settingsPrompt ? /* @__PURE__ */ jsx20(
17060
17178
  TextEntryPanel,
17061
17179
  {
@@ -17063,6 +17181,7 @@ function renderAppView(ctx) {
17063
17181
  hint: settingsPrompt.hint || "Save setting.",
17064
17182
  columns: frameColumns,
17065
17183
  initialValue: settingsPrompt.initialValue || "",
17184
+ allowEmpty: textEntryClearsByEmpty(settingsPrompt.kind),
17066
17185
  multiline: settingsPrompt.kind === "core-add" || settingsPrompt.kind === "core-edit",
17067
17186
  maxContentRows: PANEL_MAX_VISIBLE,
17068
17187
  onContentRowsChange: setTextEntryLayoutRows,
@@ -17070,7 +17189,8 @@ function renderAppView(ctx) {
17070
17189
  promptLabel: settingsPrompt.kind === "skill-use" ? "Command > " : settingsPrompt.kind === "autoclear-provider" ? "Duration > " : settingsPrompt.kind === "project-new" ? "Path > " : settingsPrompt.kind === "project-create-confirm" ? "Create? (y/n) > " : settingsPrompt.kind === "project-rename" ? "Name > " : settingsPrompt.kind === "core-add" ? "Sentence > " : settingsPrompt.kind === "core-edit" ? "Sentence > " : settingsPrompt.kind === "core-delete-confirm" ? "Delete? (y/n) > " : "Value > ",
17071
17190
  onSubmit,
17072
17191
  onCancel: cancelSettingsPrompt
17073
- }
17192
+ },
17193
+ `settings-prompt:${settingsPrompt.kind}:${settingsPrompt.restoreEpoch || 0}`
17074
17194
  ) : null }) : null,
17075
17195
  !inputBoxHidden ? /* @__PURE__ */ jsxs16(Fragment6, { children: [
17076
17196
  promptMetaVisible ? /* @__PURE__ */ jsxs16(Fragment6, { children: [
@@ -17172,12 +17292,8 @@ function usePromptDraftFlow({
17172
17292
  slashDismissedFor,
17173
17293
  setSlashDismissedFor,
17174
17294
  providerPrompt,
17175
- channelPrompt,
17176
- hookPrompt,
17177
17295
  settingsPrompt,
17178
17296
  setProviderPrompt,
17179
- setChannelPrompt,
17180
- setHookPrompt,
17181
17297
  setSettingsPrompt,
17182
17298
  oauthSubmitRef,
17183
17299
  openProjectPicker,
@@ -17216,6 +17332,7 @@ function usePromptDraftFlow({
17216
17332
  }
17217
17333
  }, [clearPromptHint, dismissWelcomePromptHint, resetPromptHistoryNav, showPromptHint, slashDismissedFor, syncPromptLayoutRows]);
17218
17334
  const cancelProviderPrompt = useCallback8(() => {
17335
+ supersedePanelEpoch();
17219
17336
  try {
17220
17337
  providerPrompt?.login?.cancel?.();
17221
17338
  } catch {
@@ -17227,17 +17344,8 @@ function usePromptDraftFlow({
17227
17344
  if (onCancel) onCancel();
17228
17345
  else if (afterSave) afterSave();
17229
17346
  }, [providerPrompt, showPromptHint]);
17230
- const cancelChannelPrompt = useCallback8(() => {
17231
- const onCancel = channelPrompt?.onCancel;
17232
- const afterSave = channelPrompt?.afterSave;
17233
- setChannelPrompt(null);
17234
- if (typeof onCancel === "function") onCancel();
17235
- else if (typeof afterSave === "function") afterSave();
17236
- }, [channelPrompt, showPromptHint]);
17237
- const cancelHookPrompt = useCallback8(() => {
17238
- setHookPrompt(null);
17239
- }, [showPromptHint]);
17240
17347
  const cancelSettingsPrompt = useCallback8(() => {
17348
+ supersedePanelEpoch();
17241
17349
  const kind = settingsPrompt?.kind;
17242
17350
  setSettingsPrompt(null);
17243
17351
  if (kind === "project-new" || kind === "project-create-confirm" || kind === "project-rename") {
@@ -17277,8 +17385,6 @@ function usePromptDraftFlow({
17277
17385
  return {
17278
17386
  onPromptDraftChange,
17279
17387
  cancelProviderPrompt,
17280
- cancelChannelPrompt,
17281
- cancelHookPrompt,
17282
17388
  cancelSettingsPrompt,
17283
17389
  acceptSlashPalette,
17284
17390
  completeSlashPalette,
@@ -17387,18 +17493,16 @@ var themeNotice = (applied) => `Theme set to ${applied?.label || applied?.id ||
17387
17493
  function createThemeEffortPickers({
17388
17494
  state,
17389
17495
  store,
17390
- setPicker,
17496
+ surface,
17391
17497
  setProviderPrompt,
17392
- setChannelPrompt,
17393
- setHookPrompt,
17394
17498
  setSettingsPrompt,
17395
- setContextPanel,
17396
17499
  closeUsagePanel,
17397
17500
  clean: clean2
17398
17501
  }) {
17399
17502
  const openThemePicker = (options = {}) => {
17400
17503
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
17401
17504
  const onboarding = options.onboarding || null;
17505
+ const own = surface.claim();
17402
17506
  let themes = [];
17403
17507
  try {
17404
17508
  themes = store.listThemes?.() || [];
@@ -17420,10 +17524,8 @@ function createThemeEffortPickers({
17420
17524
  _theme: entry
17421
17525
  }));
17422
17526
  setProviderPrompt(null);
17423
- setChannelPrompt(null);
17424
- setHookPrompt(null);
17425
17527
  setSettingsPrompt(null);
17426
- setContextPanel(null);
17528
+ own.context(null);
17427
17529
  closeUsagePanel();
17428
17530
  const applyTheme = (id, { persist = true } = {}) => {
17429
17531
  try {
@@ -17434,13 +17536,13 @@ function createThemeEffortPickers({
17434
17536
  }
17435
17537
  };
17436
17538
  const saveTheme = (id, { advance = false } = {}) => {
17437
- setPicker(null);
17539
+ own.close();
17438
17540
  const applied = applyTheme(id, { persist: true });
17439
17541
  store.pushNotice(themeNotice(applied || { id }), "info");
17440
17542
  if (advance && onboarding) onboarding.onAdvance?.();
17441
17543
  else if (returnTo) returnTo();
17442
17544
  };
17443
- setPicker({
17545
+ own.paint({
17444
17546
  title: "Theme",
17445
17547
  description: "Choose the color theme that looks best with your terminal.",
17446
17548
  help: onboarding ? void 0 : returnTo ? "\u2191/\u2193 Preview \xB7 Enter Choose \xB7 Esc Settings" : "\u2191/\u2193 Preview \xB7 Enter Choose \xB7 Esc Back",
@@ -17475,7 +17577,7 @@ function createThemeEffortPickers({
17475
17577
  saveTheme(entry.id, { advance: Boolean(onboarding) });
17476
17578
  },
17477
17579
  onCancel: () => {
17478
- setPicker(null);
17580
+ own.close();
17479
17581
  if (currentId) applyTheme(currentId, { persist: false });
17480
17582
  if (onboarding) onboarding.onCancel?.();
17481
17583
  else if (returnTo) returnTo();
@@ -17483,9 +17585,8 @@ function createThemeEffortPickers({
17483
17585
  });
17484
17586
  };
17485
17587
  const openEffortPicker = () => {
17588
+ const own = surface.claim();
17486
17589
  setProviderPrompt(null);
17487
- setChannelPrompt(null);
17488
- setHookPrompt(null);
17489
17590
  setSettingsPrompt(null);
17490
17591
  const items = Array.isArray(state.effortOptions) && state.effortOptions.length > 0 ? state.effortOptions : [];
17491
17592
  if (!items.length) {
@@ -17499,17 +17600,17 @@ function createThemeEffortPickers({
17499
17600
  markerColor: theme.success,
17500
17601
  description: clean2(item?.description).toLowerCase() === "current" ? "" : item?.description
17501
17602
  }));
17502
- setPicker({
17603
+ own.paint({
17503
17604
  title: "Effort",
17504
17605
  description: "Reasoning effort for the current model.",
17505
17606
  items: pickerItems,
17506
17607
  onSelect: (value) => {
17507
- setPicker(null);
17608
+ own.close();
17508
17609
  const pendingTurn = state.busy ? " (applies from the next turn)" : "";
17509
17610
  void store.setEffort(value).then((result) => store.pushNotice(result ? `Effort set to ${result}${pendingTurn}` : "Effort switch is already running.", result ? "info" : "warn")).catch((e) => store.pushNotice(`Couldn\u2019t switch effort: ${e?.message || e}`, "error"));
17510
17611
  },
17511
17612
  onCancel: () => {
17512
- setPicker(null);
17613
+ own.close();
17513
17614
  }
17514
17615
  });
17515
17616
  };
@@ -17519,11 +17620,12 @@ function createThemeEffortPickers({
17519
17620
  // src/tui/app/resume-picker.mjs
17520
17621
  function createResumePicker({
17521
17622
  store,
17522
- setPicker,
17623
+ surface,
17523
17624
  formatSessionUpdatedAt: formatSessionUpdatedAt2,
17524
17625
  formatSessionMessageCount: formatSessionMessageCount2
17525
17626
  }) {
17526
17627
  const openResumePicker = async () => {
17628
+ const own = surface.claim();
17527
17629
  let sessions;
17528
17630
  try {
17529
17631
  sessions = await store.listSessions({ refreshFromStorage: true });
@@ -17545,19 +17647,19 @@ function createResumePicker({
17545
17647
  description: title || preview || "(no message)"
17546
17648
  };
17547
17649
  });
17548
- setPicker({
17650
+ own.paint({
17549
17651
  title: "Resume",
17550
17652
  description: "Restore a saved chat session.",
17551
17653
  items,
17552
17654
  labelWidth: 21,
17553
17655
  onSelect: (value) => {
17554
- setPicker(null);
17656
+ own.close();
17555
17657
  const selected = sessions.find((session) => session.id === value);
17556
17658
  const resumedName = String(selected?.title || selected?.preview || value).replace(/\s+/g, " ").trim();
17557
17659
  void store.resume(value).then((ok) => store.pushNotice(ok ? `Resumed ${resumedName || value}` : "Couldn\u2019t resume chat.", ok ? "info" : "warn")).catch((e) => store.pushNotice(`Couldn\u2019t resume chat: ${e?.message || e}`, "error"));
17558
17660
  },
17559
17661
  onCancel: () => {
17560
- setPicker(null);
17662
+ own.close();
17561
17663
  }
17562
17664
  });
17563
17665
  };
@@ -17567,20 +17669,22 @@ function createResumePicker({
17567
17669
  // src/tui/app/core-memory-picker.mjs
17568
17670
  function createCoreMemoryPicker({
17569
17671
  store,
17570
- setPicker,
17672
+ surface,
17571
17673
  setSettingsPrompt,
17572
17674
  parseMemoryCoreRows: parseMemoryCoreRows2
17573
17675
  }) {
17574
17676
  let escReturnTo = null;
17575
17677
  const closeMemoryCorePicker = () => {
17576
17678
  if (escReturnTo) escReturnTo();
17577
- else setPicker(null);
17679
+ else surface.claim().close();
17578
17680
  };
17579
17681
  const openMemoryCorePicker = (options = {}) => {
17580
17682
  if (options && Object.prototype.hasOwnProperty.call(options, "returnTo")) {
17581
17683
  escReturnTo = typeof options.returnTo === "function" ? options.returnTo : null;
17582
17684
  }
17583
- setPicker({
17685
+ const own = surface.claim();
17686
+ const paintPanel = (panel) => own.paint(panel);
17687
+ paintPanel({
17584
17688
  title: "Memory",
17585
17689
  // Loading state lives in the header description row, not as a fake
17586
17690
  // selectable menu item.
@@ -17603,7 +17707,7 @@ function createCoreMemoryPicker({
17603
17707
  _rows: coreRows
17604
17708
  }
17605
17709
  ];
17606
- setPicker({
17710
+ paintPanel({
17607
17711
  title: "Memory",
17608
17712
  description: "User-curated core memories across projects.",
17609
17713
  items: rows.length ? rows : [{ value: "empty", label: "Memory", description: "empty" }],
@@ -17620,13 +17724,15 @@ function createCoreMemoryPicker({
17620
17724
  onCancel: closeMemoryCorePicker
17621
17725
  });
17622
17726
  }).catch((e) => {
17623
- setPicker(null);
17727
+ own.close();
17624
17728
  store.pushNotice(`core memory failed: ${e?.message || e}`, "error");
17625
17729
  });
17626
17730
  };
17627
17731
  const openCoreMemoryListPicker = (rows = null) => {
17732
+ const own = surface.claim();
17733
+ const paintPanel = (panel) => own.paint(panel);
17628
17734
  const renderList = (coreRows) => {
17629
- setPicker({
17735
+ paintPanel({
17630
17736
  title: "Memory \xB7 List",
17631
17737
  description: coreRows.length ? "Select a memory to edit or delete." : "No stored memories yet.",
17632
17738
  items: coreRows.length ? coreRows : [{ value: "empty", label: "Memory", description: "empty" }],
@@ -17643,7 +17749,7 @@ function createCoreMemoryPicker({
17643
17749
  renderList(rows);
17644
17750
  return;
17645
17751
  }
17646
- setPicker({
17752
+ paintPanel({
17647
17753
  title: "Memory \xB7 List",
17648
17754
  description: "Loading memories\u2026",
17649
17755
  items: [],
@@ -17651,13 +17757,16 @@ function createCoreMemoryPicker({
17651
17757
  },
17652
17758
  onCancel: () => openMemoryCorePicker()
17653
17759
  });
17654
- void store.memoryControl?.({ action: "core", op: "list", project_id: "*" }, { silent: true }).then((result) => renderList(parseMemoryCoreRows2(result))).catch((e) => {
17655
- setPicker(null);
17760
+ void store.memoryControl?.({ action: "core", op: "list", project_id: "*" }, { silent: true }).then((result) => {
17761
+ renderList(parseMemoryCoreRows2(result));
17762
+ }).catch((e) => {
17763
+ own.close();
17656
17764
  store.pushNotice(`core memory failed: ${e?.message || e}`, "error");
17657
17765
  });
17658
17766
  };
17659
17767
  const openCoreEntryActionsPicker = (entryItem) => {
17660
- setPicker({
17768
+ const own = surface.claim();
17769
+ own.paint({
17661
17770
  title: `Memory \xB7 #${entryItem._id}`,
17662
17771
  description: entryItem._summary || entryItem._element || "",
17663
17772
  items: [
@@ -17672,7 +17781,7 @@ function createCoreMemoryPicker({
17672
17781
  });
17673
17782
  };
17674
17783
  const beginAddCoreMemory = () => {
17675
- setPicker(null);
17784
+ surface.claim().close();
17676
17785
  setSettingsPrompt({
17677
17786
  kind: "core-add",
17678
17787
  label: "Add memory",
@@ -17680,7 +17789,7 @@ function createCoreMemoryPicker({
17680
17789
  });
17681
17790
  };
17682
17791
  const beginEditCoreMemory = (entryItem) => {
17683
- setPicker(null);
17792
+ surface.claim().close();
17684
17793
  setSettingsPrompt({
17685
17794
  kind: "core-edit",
17686
17795
  label: `Memory \xB7 Edit #${entryItem._id}`,
@@ -17695,7 +17804,7 @@ function createCoreMemoryPicker({
17695
17804
  });
17696
17805
  };
17697
17806
  const beginDeleteCoreMemory = (entryItem) => {
17698
- setPicker(null);
17807
+ surface.claim().close();
17699
17808
  setSettingsPrompt({
17700
17809
  kind: "core-delete-confirm",
17701
17810
  label: `Memory \xB7 Delete #${entryItem._id}?`,
@@ -17719,11 +17828,9 @@ function createExtensionPickers({
17719
17828
  theme: theme2,
17720
17829
  clean: clean2,
17721
17830
  copyToClipboard: copyToClipboard2,
17722
- setPicker,
17831
+ surface,
17723
17832
  getPicker,
17724
17833
  setProviderPrompt,
17725
- setChannelPrompt,
17726
- setHookPrompt,
17727
17834
  setSettingsPrompt,
17728
17835
  getDisabledSkills,
17729
17836
  setDisabledSkills
@@ -17741,6 +17848,7 @@ function createExtensionPickers({
17741
17848
  return { ...status, servers: status.servers || [] };
17742
17849
  };
17743
17850
  const openMcpServersPicker = async (options = {}) => {
17851
+ const own = surface.claim();
17744
17852
  const status = await mcpStatus();
17745
17853
  if (!status) return;
17746
17854
  const servers = status.servers || [];
@@ -17768,9 +17876,8 @@ function createExtensionPickers({
17768
17876
  _enabled: enabled
17769
17877
  });
17770
17878
  }
17879
+ if (!own.owns()) return;
17771
17880
  setProviderPrompt(null);
17772
- setChannelPrompt(null);
17773
- setHookPrompt(null);
17774
17881
  setSettingsPrompt(null);
17775
17882
  const toggleServer = (item) => {
17776
17883
  if (item._action !== "server" || !item._server?.name) return;
@@ -17790,7 +17897,7 @@ function createExtensionPickers({
17790
17897
  settle(() => openMcpServersPicker({ highlightValue }));
17791
17898
  });
17792
17899
  };
17793
- setPicker({
17900
+ own.paint({
17794
17901
  _kind: "mcp-servers",
17795
17902
  title: "MCP servers",
17796
17903
  description: "Enable or disable configured MCP servers.",
@@ -17802,7 +17909,7 @@ function createExtensionPickers({
17802
17909
  onCancel: () => {
17803
17910
  mcpActive = false;
17804
17911
  mcpEpoch++;
17805
- setPicker(null);
17912
+ own.close();
17806
17913
  }
17807
17914
  });
17808
17915
  mcpActive = true;
@@ -17821,6 +17928,7 @@ function createExtensionPickers({
17821
17928
  return { ...status, skills: status.skills || [] };
17822
17929
  };
17823
17930
  const openProjectSkillsPicker = async () => {
17931
+ const own = surface.claim();
17824
17932
  const status = await skillsStatus();
17825
17933
  if (!status) return;
17826
17934
  const skills = status.skills || [];
@@ -17842,26 +17950,26 @@ function createExtensionPickers({
17842
17950
  _skill: skill
17843
17951
  });
17844
17952
  }
17953
+ if (!own.owns()) return;
17845
17954
  setProviderPrompt(null);
17846
- setChannelPrompt(null);
17847
- setHookPrompt(null);
17848
17955
  setSettingsPrompt(null);
17849
- setPicker({
17956
+ own.paint({
17850
17957
  title: "Project skills",
17851
17958
  description: "Skills bundled with this project.",
17852
17959
  items,
17853
17960
  onSelect: (_value, item) => {
17854
- setPicker(null);
17961
+ own.close();
17855
17962
  if (item._action !== "view") return;
17856
17963
  openSkillDetailPicker(item._skill);
17857
17964
  },
17858
17965
  onCancel: () => {
17859
- setPicker(null);
17966
+ own.close();
17860
17967
  void openSkillsPicker();
17861
17968
  }
17862
17969
  });
17863
17970
  };
17864
17971
  const openSkillsPicker = async (options = {}) => {
17972
+ const own = surface.claim();
17865
17973
  let skills;
17866
17974
  if (Array.isArray(options.skills)) {
17867
17975
  skills = options.skills;
@@ -17893,9 +18001,8 @@ function createExtensionPickers({
17893
18001
  _enabled: enabled
17894
18002
  });
17895
18003
  }
18004
+ if (!own.owns()) return;
17896
18005
  setProviderPrompt(null);
17897
- setChannelPrompt(null);
17898
- setHookPrompt(null);
17899
18006
  setSettingsPrompt(null);
17900
18007
  const toggleSkill = (item) => {
17901
18008
  if (item._action !== "skill" || !item._skill?.name) return;
@@ -17910,7 +18017,7 @@ function createExtensionPickers({
17910
18017
  );
17911
18018
  openSkillsPicker({ highlightValue: name, disabledOverride: next, skills });
17912
18019
  };
17913
- setPicker({
18020
+ own.paint({
17914
18021
  _kind: "skills",
17915
18022
  title: "Skills",
17916
18023
  description: "Enable or disable project skills.",
@@ -17920,13 +18027,14 @@ function createExtensionPickers({
17920
18027
  onLeft: (item) => toggleSkill(item),
17921
18028
  onRight: (item) => toggleSkill(item),
17922
18029
  onCancel: () => {
17923
- setPicker(null);
18030
+ own.close();
17924
18031
  }
17925
18032
  });
17926
18033
  };
17927
18034
  const openSkillDetailPicker = (skill) => {
18035
+ const own = surface.claim();
17928
18036
  const disabled = getDisabledSkills().has(skill.name);
17929
- setPicker({
18037
+ own.paint({
17930
18038
  title: `Skill \xB7 ${skill.name}`,
17931
18039
  description: clean2(skill.description) || "Enable, disable, or run this skill.",
17932
18040
  items: [
@@ -17944,7 +18052,7 @@ function createExtensionPickers({
17944
18052
  }
17945
18053
  ],
17946
18054
  onSelect: (_value, item) => {
17947
- setPicker(null);
18055
+ own.close();
17948
18056
  if (item._action === "enable") {
17949
18057
  setDisabledSkills((current) => {
17950
18058
  const next = new Set(current);
@@ -17976,7 +18084,7 @@ function createExtensionPickers({
17976
18084
  }
17977
18085
  },
17978
18086
  onCancel: () => {
17979
- setPicker(null);
18087
+ own.close();
17980
18088
  void openSkillsPicker();
17981
18089
  }
17982
18090
  });
@@ -17992,11 +18100,12 @@ function createExtensionPickers({
17992
18100
  return { ...status, plugins: status.plugins || [] };
17993
18101
  };
17994
18102
  const beginAddPlugin = () => {
17995
- setPicker(null);
18103
+ surface.claim().close();
17996
18104
  setSettingsPrompt({ kind: "plugin-add", label: "Plugin URL", hint: "Git URL, owner/repo, or local path" });
17997
18105
  };
17998
18106
  const openPluginDetailPicker = (p) => {
17999
- setPicker({
18107
+ const own = surface.claim();
18108
+ own.paint({
18000
18109
  title: p.title || p.name,
18001
18110
  description: clean2(p.description) || "Update, MCP, or uninstall this plugin.",
18002
18111
  items: [
@@ -18038,7 +18147,7 @@ function createExtensionPickers({
18038
18147
  }
18039
18148
  ],
18040
18149
  onSelect: (_detailValue, detail) => {
18041
- setPicker(null);
18150
+ own.paint(null);
18042
18151
  if (detail._action === "info") {
18043
18152
  store.pushNotice([
18044
18153
  `${p.title || p.name}${p.version ? ` ${p.version}` : ""}`,
@@ -18052,11 +18161,11 @@ ${p.description}` : ""
18052
18161
  return;
18053
18162
  }
18054
18163
  if (detail._action === "update") {
18055
- void store.updatePlugin?.(p).then(() => openInstalledPluginsPicker()).catch((e) => store.pushNotice(`plugin update failed: ${e?.message || e}`, "error"));
18164
+ void store.updatePlugin?.(p).then(own.defer(() => openInstalledPluginsPicker())).catch((e) => store.pushNotice(`plugin update failed: ${e?.message || e}`, "error"));
18056
18165
  return;
18057
18166
  }
18058
18167
  if (detail._action === "enable-mcp") {
18059
- void store.enablePluginMcp?.(p).then(() => openMcpPicker()).catch((e) => store.pushNotice(`plugin MCP enable failed: ${e?.message || e}`, "error"));
18168
+ void store.enablePluginMcp?.(p).then(own.defer(() => openMcpPicker())).catch((e) => store.pushNotice(`plugin MCP enable failed: ${e?.message || e}`, "error"));
18060
18169
  return;
18061
18170
  }
18062
18171
  if (detail._action === "copy-root") {
@@ -18068,16 +18177,17 @@ ${p.description}` : ""
18068
18177
  return;
18069
18178
  }
18070
18179
  if (detail._action === "uninstall") {
18071
- void store.removePlugin?.(p).then(() => openInstalledPluginsPicker()).catch((e) => store.pushNotice(`plugin uninstall failed: ${e?.message || e}`, "error"));
18180
+ void store.removePlugin?.(p).then(own.defer(() => openInstalledPluginsPicker())).catch((e) => store.pushNotice(`plugin uninstall failed: ${e?.message || e}`, "error"));
18072
18181
  }
18073
18182
  },
18074
18183
  onCancel: () => {
18075
- setPicker(null);
18184
+ own.close();
18076
18185
  void openInstalledPluginsPicker();
18077
18186
  }
18078
18187
  });
18079
18188
  };
18080
18189
  const openInstalledPluginsPicker = async () => {
18190
+ const own = surface.claim();
18081
18191
  const status = await pluginStatus();
18082
18192
  if (!status) return;
18083
18193
  const plugins = status.plugins || [];
@@ -18099,33 +18209,32 @@ ${p.description}` : ""
18099
18209
  _plugin: plugin
18100
18210
  });
18101
18211
  }
18212
+ if (!own.owns()) return;
18102
18213
  setProviderPrompt(null);
18103
- setChannelPrompt(null);
18104
- setHookPrompt(null);
18105
18214
  setSettingsPrompt(null);
18106
- setPicker({
18215
+ own.paint({
18107
18216
  title: "Installed plugins",
18108
18217
  description: "Open an installed plugin to manage it.",
18109
18218
  items,
18110
18219
  onSelect: (_value, item) => {
18111
- setPicker(null);
18220
+ own.close();
18112
18221
  if (item._action !== "plugin") return;
18113
18222
  openPluginDetailPicker(item._plugin);
18114
18223
  },
18115
18224
  onCancel: () => {
18116
- setPicker(null);
18225
+ own.close();
18117
18226
  void openPluginsPicker();
18118
18227
  }
18119
18228
  });
18120
18229
  };
18121
18230
  const openPluginsPicker = async () => {
18231
+ const own = surface.claim();
18122
18232
  const status = await pluginStatus();
18123
18233
  if (!status) return;
18234
+ if (!own.owns()) return;
18124
18235
  setProviderPrompt(null);
18125
- setChannelPrompt(null);
18126
- setHookPrompt(null);
18127
18236
  setSettingsPrompt(null);
18128
- setPicker({
18237
+ own.paint({
18129
18238
  title: "Plugins",
18130
18239
  description: "Add or manage local plugin integrations.",
18131
18240
  items: [
@@ -18143,7 +18252,7 @@ ${p.description}` : ""
18143
18252
  }
18144
18253
  ],
18145
18254
  onSelect: (_value, item) => {
18146
- setPicker(null);
18255
+ own.close();
18147
18256
  if (item._action === "installed") {
18148
18257
  openInstalledPluginsPicker();
18149
18258
  return;
@@ -18151,11 +18260,12 @@ ${p.description}` : ""
18151
18260
  if (item._action === "add") beginAddPlugin();
18152
18261
  },
18153
18262
  onCancel: () => {
18154
- setPicker(null);
18263
+ own.close();
18155
18264
  }
18156
18265
  });
18157
18266
  };
18158
18267
  const openHooksPicker = async () => {
18268
+ const own = surface.claim();
18159
18269
  let status;
18160
18270
  try {
18161
18271
  status = await store.hooksStatus?.() || { events: [], recent: [] };
@@ -18180,20 +18290,14 @@ ${p.description}` : ""
18180
18290
  _action: "noop"
18181
18291
  }]
18182
18292
  ];
18293
+ if (!own.owns()) return;
18183
18294
  setProviderPrompt(null);
18184
- setChannelPrompt(null);
18185
- setHookPrompt(null);
18186
18295
  setSettingsPrompt(null);
18187
18296
  const toggleRule = (item) => {
18188
18297
  if (item._action !== "rule") return;
18189
- try {
18190
- store.setHookRuleEnabled?.(item._rule.index, !item._rule.enabled);
18191
- void openHooksPicker();
18192
- } catch (e) {
18193
- store.pushNotice(`hook toggle failed: ${e?.message || e}`, "error");
18194
- }
18298
+ void Promise.resolve(store.setHookRuleEnabled?.(item._rule.index, !item._rule.enabled)).then(own.defer(() => openHooksPicker())).catch((e) => store.pushNotice(`hook toggle failed: ${e?.message || e}`, "error"));
18195
18299
  };
18196
- setPicker({
18300
+ own.paint({
18197
18301
  _kind: "hooks",
18198
18302
  title: "Hooks",
18199
18303
  description: "Before-tool hook rules; Enter toggles a rule.",
@@ -18202,7 +18306,7 @@ ${p.description}` : ""
18202
18306
  onLeft: (item) => toggleRule(item),
18203
18307
  onRight: (item) => toggleRule(item),
18204
18308
  onCancel: () => {
18205
- setPicker(null);
18309
+ own.close();
18206
18310
  }
18207
18311
  });
18208
18312
  };
@@ -18225,16 +18329,20 @@ function createMaintenancePickers({
18225
18329
  store,
18226
18330
  theme: theme2,
18227
18331
  formatDuration: formatDuration2,
18228
- setPicker,
18332
+ surface,
18229
18333
  setProviderPrompt,
18230
- setChannelPrompt,
18231
- setHookPrompt,
18232
18334
  setSettingsPrompt,
18233
- setContextPanel,
18234
18335
  closeUsagePanel
18235
18336
  }) {
18236
18337
  const openUpdatePicker = (options = {}) => {
18237
18338
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
18339
+ const own = surface.claim();
18340
+ const paintPanel = (panel) => {
18341
+ if (!own.owns()) return false;
18342
+ setProviderPrompt(null);
18343
+ setSettingsPrompt(null);
18344
+ return own.paint(panel);
18345
+ };
18238
18346
  const readSettings = async () => {
18239
18347
  try {
18240
18348
  return await store.getUpdateSettings?.() || {};
@@ -18277,11 +18385,7 @@ function createMaintenancePickers({
18277
18385
  _action: "auto-update"
18278
18386
  }
18279
18387
  ];
18280
- setProviderPrompt(null);
18281
- setChannelPrompt(null);
18282
- setHookPrompt(null);
18283
- setSettingsPrompt(null);
18284
- setPicker({
18388
+ return paintPanel({
18285
18389
  title: "Update",
18286
18390
  description: "Check version and update mixdog.",
18287
18391
  help: "\u2191/\u2193 Select \xB7 Enter Open/Toggle \xB7 Esc Close",
@@ -18308,46 +18412,54 @@ function createMaintenancePickers({
18308
18412
  }
18309
18413
  },
18310
18414
  onCancel: () => {
18311
- setPicker(null);
18415
+ own.close();
18312
18416
  if (returnTo) returnTo();
18313
18417
  }
18314
18418
  });
18315
18419
  };
18420
+ const rerender = (opts = {}) => {
18421
+ void Promise.resolve(render2(opts)).catch((e) => store.pushNotice(`update panel failed: ${e?.message || e}`, "error"));
18422
+ };
18423
+ const deferredRerender = (opts = {}) => own.defer(() => rerender(opts));
18316
18424
  const toggleAutoUpdate = (enabled) => {
18317
- try {
18318
- void Promise.resolve(store.setAutoUpdate?.(enabled)).finally(() => render2());
18319
- store.pushNotice(`Auto-update ${enabled ? "on" : "off"}`, "info");
18320
- } catch (e) {
18321
- store.pushNotice(`auto-update failed: ${e?.message || e}`, "error");
18322
- }
18323
- render2();
18425
+ void Promise.resolve(store.setAutoUpdate?.(enabled)).then(() => store.pushNotice(`Auto-update ${enabled ? "on" : "off"}`, "info")).catch((e) => store.pushNotice(`auto-update failed: ${e?.message || e}`, "error")).finally(deferredRerender());
18324
18426
  };
18325
18427
  const recheck = () => {
18326
- render2({ checking: true });
18327
- void Promise.resolve(store.checkForUpdate?.({ force: true })).then(() => render2()).catch((e) => {
18428
+ rerender({ checking: true });
18429
+ const settled = deferredRerender();
18430
+ void Promise.resolve(store.checkForUpdate?.({ force: true })).then(() => settled()).catch((e) => {
18328
18431
  store.pushNotice(`update check failed: ${e?.message || e}`, "error");
18329
- render2();
18432
+ settled();
18330
18433
  });
18331
18434
  };
18332
18435
  const runUpdate = () => {
18333
18436
  store.pushNotice("Updating\u2026", "info");
18437
+ const settled = deferredRerender();
18334
18438
  void Promise.resolve(store.runUpdateNow?.()).then((result) => {
18335
18439
  if (result?.ok) {
18336
18440
  store.pushNotice(`v${result.version} installed \u2014 restart to apply`, "warn");
18337
18441
  } else {
18338
18442
  store.pushNotice(`Update failed: ${result?.error || "unknown error"}`, "error");
18339
18443
  }
18340
- render2();
18444
+ settled();
18341
18445
  }).catch((e) => {
18342
18446
  store.pushNotice(`Update failed: ${e?.message || e}`, "error");
18343
- render2();
18447
+ settled();
18344
18448
  });
18345
18449
  };
18346
- render2({ checking: true });
18347
- void Promise.resolve(store.checkForUpdate?.({})).then(() => render2()).catch(() => render2());
18450
+ void Promise.resolve(render2({ checking: true })).catch((e) => {
18451
+ store.pushNotice(`update panel failed: ${e?.message || e}`, "error");
18452
+ return false;
18453
+ }).then((painted) => {
18454
+ if (!painted) return;
18455
+ const initialChecked = deferredRerender();
18456
+ void Promise.resolve(store.checkForUpdate?.({})).then(() => initialChecked()).catch(() => initialChecked());
18457
+ });
18348
18458
  };
18349
18459
  const openAutoClearPicker = (options = {}) => {
18350
18460
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
18461
+ const own = surface.claim();
18462
+ const paintPanel = (panel) => own.paint(panel);
18351
18463
  const HOUR_MS = 60 * 60 * 1e3;
18352
18464
  const formatDurationInput = (ms) => {
18353
18465
  const value = Math.max(0, Math.round(Number(ms) || 0));
@@ -18364,19 +18476,20 @@ function createMaintenancePickers({
18364
18476
  }
18365
18477
  };
18366
18478
  const applyAutoClear = (patch = {}) => {
18479
+ const settled = own.defer(() => {
18480
+ void Promise.resolve(render2()).catch((e) => store.pushNotice(`auto-clear panel failed: ${e?.message || e}`, "error"));
18481
+ });
18367
18482
  void Promise.resolve(store.setAutoClear?.(patch)).then((next) => {
18368
18483
  if (!next) {
18369
18484
  store.pushNotice("autoclear unavailable", "warn");
18370
18485
  return;
18371
18486
  }
18372
18487
  store.pushNotice(next.enabled ? `autoclear on \xB7 idle ${formatDuration2(next.idleMs)}` : "autoclear off", "info");
18373
- }).catch((e) => store.pushNotice(`autoclear failed: ${e?.message || e}`, "error")).finally(() => {
18374
- void render2();
18375
- });
18488
+ }).catch((e) => store.pushNotice(`autoclear failed: ${e?.message || e}`, "error")).finally(settled);
18376
18489
  };
18377
18490
  const openProviderDurationEditor = (entry) => {
18378
18491
  if (!entry?.provider) return;
18379
- setPicker(null);
18492
+ own.close();
18380
18493
  setSettingsPrompt({
18381
18494
  kind: "autoclear-provider",
18382
18495
  label: `Auto-clear \xB7 ${entry.provider}`,
@@ -18401,7 +18514,7 @@ function createMaintenancePickers({
18401
18514
  _action: "provider-default",
18402
18515
  _entry: entry
18403
18516
  }));
18404
- setPicker({
18517
+ paintPanel({
18405
18518
  title: "Auto-clear \xB7 Advanced",
18406
18519
  description: "Provider default idle windows. Enter edits the duration text.",
18407
18520
  help: "\u2191/\u2193 Select \xB7 Enter Edit \xB7 Esc Back",
@@ -18437,7 +18550,7 @@ function createMaintenancePickers({
18437
18550
  _action: "advanced"
18438
18551
  }
18439
18552
  ];
18440
- setPicker({
18553
+ paintPanel({
18441
18554
  title: "Auto-clear",
18442
18555
  description: `Clear idle context after ${enabled ? formatDuration2(idleMs) : "never"} \xB7 lead cache TTL ${cacheTtlLabel}.`,
18443
18556
  help: "\u2191/\u2193 Select \xB7 \u2190/\u2192 Toggle On/Off \xB7 Enter Open/Toggle \xB7 Esc Close",
@@ -18458,22 +18571,21 @@ function createMaintenancePickers({
18458
18571
  }
18459
18572
  },
18460
18573
  onCancel: () => {
18461
- setPicker(null);
18574
+ own.close();
18462
18575
  if (returnTo) returnTo();
18463
18576
  }
18464
18577
  });
18465
18578
  };
18466
18579
  setProviderPrompt(null);
18467
- setChannelPrompt(null);
18468
- setHookPrompt(null);
18469
18580
  setSettingsPrompt(null);
18470
- setContextPanel(null);
18581
+ own.context(null);
18471
18582
  closeUsagePanel();
18472
18583
  if (options.advanced === true) renderAdvanced();
18473
18584
  else render2();
18474
18585
  };
18475
18586
  const openProfilePicker = async (options = {}) => {
18476
18587
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
18588
+ const own = surface.claim();
18477
18589
  let profile = null;
18478
18590
  try {
18479
18591
  profile = await store.getProfile?.() || null;
@@ -18492,36 +18604,26 @@ function createMaintenancePickers({
18492
18604
  const currentExperienceLevelId = profile?.experienceLevel || "";
18493
18605
  const currentExperienceLevel = experienceLevels.find((level) => level.id === currentExperienceLevelId) || null;
18494
18606
  const titleValue = String(profile?.title || "").trim();
18607
+ const reopenProfile = () => own.defer(() => {
18608
+ void Promise.resolve(openProfilePicker({ returnTo })).catch((e) => store.pushNotice(`profile panel failed: ${e?.message || e}`, "error"));
18609
+ });
18495
18610
  const cycleLanguage = (direction = 1) => {
18496
18611
  const idx = Math.max(0, languages.findIndex((lang) => lang.id === currentLangId));
18497
18612
  const next = languages[(idx + direction + languages.length) % languages.length];
18498
- try {
18499
- store.setProfile?.({ language: next.id });
18500
- store.pushNotice(`Language set to ${next.label}`, "info");
18501
- } catch (e) {
18502
- store.pushNotice(`profile update failed: ${e?.message || e}`, "error");
18503
- }
18504
- openProfilePicker({ returnTo });
18613
+ void Promise.resolve(store.setProfile?.({ language: next.id })).then(() => store.pushNotice(`Language set to ${next.label}`, "info")).catch((e) => store.pushNotice(`profile update failed: ${e?.message || e}`, "error")).finally(reopenProfile());
18505
18614
  };
18506
18615
  const cycleExperienceLevel = (direction = 1) => {
18507
18616
  const idx = experienceLevels.findIndex((level) => level.id === currentExperienceLevelId);
18508
18617
  const nextIdx = idx < 0 ? direction < 0 ? experienceLevels.length - 1 : 0 : (idx + direction + experienceLevels.length) % experienceLevels.length;
18509
18618
  const next = experienceLevels[nextIdx];
18510
- try {
18511
- store.setProfile?.({ experienceLevel: next.id });
18512
- store.pushNotice(`Experience level set to ${next.label}`, "info");
18513
- } catch (e) {
18514
- store.pushNotice(`profile update failed: ${e?.message || e}`, "error");
18515
- }
18516
- openProfilePicker({ returnTo });
18619
+ void Promise.resolve(store.setProfile?.({ experienceLevel: next.id })).then(() => store.pushNotice(`Experience level set to ${next.label}`, "info")).catch((e) => store.pushNotice(`profile update failed: ${e?.message || e}`, "error")).finally(reopenProfile());
18517
18620
  };
18621
+ if (!own.owns()) return;
18518
18622
  setProviderPrompt(null);
18519
- setChannelPrompt(null);
18520
- setHookPrompt(null);
18521
18623
  setSettingsPrompt(null);
18522
- setContextPanel(null);
18624
+ own.context(null);
18523
18625
  closeUsagePanel();
18524
- setPicker({
18626
+ own.paint({
18525
18627
  title: "Profile",
18526
18628
  description: "How the assistant addresses you, adapts terminology, and chooses its response language.",
18527
18629
  help: "\u2191/\u2193 Select \xB7 \u2190/\u2192 Change \xB7 Enter Edit \xB7 Esc Close",
@@ -18561,7 +18663,7 @@ function createMaintenancePickers({
18561
18663
  },
18562
18664
  onSelect: (_value, item) => {
18563
18665
  if (item?._action === "title") {
18564
- setPicker(null);
18666
+ own.close();
18565
18667
  setSettingsPrompt({
18566
18668
  kind: "profile-title",
18567
18669
  label: "Profile \xB7 Title",
@@ -18574,7 +18676,7 @@ function createMaintenancePickers({
18574
18676
  }
18575
18677
  },
18576
18678
  onCancel: () => {
18577
- setPicker(null);
18679
+ own.close();
18578
18680
  if (returnTo) returnTo();
18579
18681
  }
18580
18682
  });
@@ -18857,10 +18959,8 @@ var routeFromModel = (model, effort = null) => ({
18857
18959
  // src/tui/app/onboarding-steps.mjs
18858
18960
  function createOnboardingSteps({
18859
18961
  store,
18860
- setPicker,
18962
+ surface,
18861
18963
  setProviderPrompt,
18862
- setChannelPrompt,
18863
- setHookPrompt,
18864
18964
  setSettingsPrompt,
18865
18965
  setOnboardingActive,
18866
18966
  onboardingRef,
@@ -18899,11 +18999,13 @@ function createOnboardingSteps({
18899
18999
  };
18900
19000
  const openOnboardingAuthStep = async () => {
18901
19001
  prefetchOnboardingStep2();
19002
+ const own = surface.claim();
18902
19003
  let preloadedSetup = null;
18903
19004
  try {
18904
19005
  preloadedSetup = await store.getProviderSetup?.();
18905
19006
  } catch {
18906
19007
  }
19008
+ if (!own.owns()) return;
18907
19009
  void openProviderSetupPicker({
18908
19010
  title: "First Run \xB7 Step 1/4 \xB7 Provider Auth",
18909
19011
  returnTo: () => openOnboardingAuthStep(),
@@ -18943,7 +19045,7 @@ function createOnboardingSteps({
18943
19045
  const webSearchRoute = onboardingRef.current.webSearchRoute || null;
18944
19046
  const overrides = onboardingRef.current.agentRoutes || {};
18945
19047
  const hasOverrides = Object.keys(overrides).length > 0;
18946
- setPicker(null);
19048
+ surface.claim().close();
18947
19049
  setOnboardingActive(false);
18948
19050
  const done = () => store.pushNotice("First-run setup complete.", "info");
18949
19051
  const failed = (e) => store.pushNotice(`Couldn\u2019t save setup: ${e?.message || e}`, "error");
@@ -18965,6 +19067,7 @@ function createOnboardingSteps({
18965
19067
  void Promise.resolve().then(() => store.skipOnboarding?.()).then(done, failed);
18966
19068
  };
18967
19069
  const openOnboardingRoleModelPicker = async (target) => {
19070
+ const own = surface.claim();
18968
19071
  const isLead = target === "lead";
18969
19072
  const isWebSearch = target === "webSearch";
18970
19073
  let models;
@@ -18978,14 +19081,14 @@ function createOnboardingSteps({
18978
19081
  models = normalizeModelOptions(webSearchModels || []);
18979
19082
  if (models.length === 0) {
18980
19083
  store.pushNotice("no native web-search models available; connect OpenAI, Grok, Gemini, or Anthropic", "warn");
18981
- void openOnboardingWorkflowStep();
19084
+ if (own.owns()) void openOnboardingWorkflowStep();
18982
19085
  return;
18983
19086
  }
18984
19087
  } else {
18985
19088
  models = normalizeModelOptions(onboardingRef.current.providerModels || []);
18986
19089
  if (models.length === 0) {
18987
19090
  store.pushNotice("no provider models available; open /providers to sign in", "warn");
18988
- openOnboardingAuthStep();
19091
+ if (own.owns()) openOnboardingAuthStep();
18989
19092
  return;
18990
19093
  }
18991
19094
  }
@@ -19016,7 +19119,8 @@ function createOnboardingSteps({
19016
19119
  const matchIdx = models.findIndex((m) => routeMatchesModel(currentRoute, m));
19017
19120
  const initialIndex = isLead ? Math.max(0, matchIdx) : isUnset || matchIdx < 0 ? 0 : matchIdx + 1;
19018
19121
  const label = isLead ? "Main" : isWebSearch ? "Web Search" : (onboardingRef.current.agents || []).find((a) => a.id === target)?.label || target;
19019
- setPicker({
19122
+ if (!own.owns()) return;
19123
+ own.paint({
19020
19124
  title: `First Run \xB7 ${label}`,
19021
19125
  description: isLead ? "Pick the main model. Agents inherit this unless individually changed." : isWebSearch ? "Pick the native web-search model, or Default to follow the Main Model." : `Pick the model for ${label}, or Default to follow the Main Model.`,
19022
19126
  initialIndex,
@@ -19057,6 +19161,7 @@ function createOnboardingSteps({
19057
19161
  });
19058
19162
  };
19059
19163
  const openOnboardingWorkflowStep = async () => {
19164
+ const own = surface.claim();
19060
19165
  if (!Array.isArray(onboardingRef.current.providerModels) || onboardingRef.current.providerModels.length === 0) {
19061
19166
  try {
19062
19167
  onboardingRef.current.providerModels = await store.listProviderModels();
@@ -19071,7 +19176,7 @@ function createOnboardingSteps({
19071
19176
  onboardingRef.current.defaultRoute = null;
19072
19177
  onboardingRef.current.agentRoutes = {};
19073
19178
  store.pushNotice("no provider models available; open /providers to sign in", "warn");
19074
- openOnboardingAuthStep();
19179
+ if (own.owns()) openOnboardingAuthStep();
19075
19180
  return;
19076
19181
  }
19077
19182
  if (!Array.isArray(onboardingRef.current.agents) || onboardingRef.current.agents.length === 0) {
@@ -19086,11 +19191,10 @@ function createOnboardingSteps({
19086
19191
  const webSearchRoute = onboardingRef.current.webSearchRoute || null;
19087
19192
  const overrides = onboardingRef.current.agentRoutes || {};
19088
19193
  const agents = onboardingRef.current.agents || [];
19194
+ if (!own.owns()) return;
19089
19195
  setProviderPrompt(null);
19090
- setChannelPrompt(null);
19091
- setHookPrompt(null);
19092
19196
  setSettingsPrompt(null);
19093
- setPicker({
19197
+ own.paint({
19094
19198
  title: "First Run \xB7 Step 2/4 \xB7 Models",
19095
19199
  description: "Set the Main Model; each agent inherits it unless changed.",
19096
19200
  indexMode: "always",
@@ -19139,7 +19243,7 @@ function createOnboardingSteps({
19139
19243
  }
19140
19244
  },
19141
19245
  onCancel: () => {
19142
- setPicker(null);
19246
+ own.close();
19143
19247
  onboardingWarnReopen();
19144
19248
  }
19145
19249
  });
@@ -19159,12 +19263,9 @@ function createOnboardingSteps({
19159
19263
  // src/tui/app/provider-setup-picker.mjs
19160
19264
  function createProviderSetupPicker({
19161
19265
  store,
19162
- setPicker,
19266
+ surface,
19163
19267
  setProviderPrompt,
19164
- setChannelPrompt,
19165
- setHookPrompt,
19166
19268
  setSettingsPrompt,
19167
- setContextPanel,
19168
19269
  closeUsagePanel,
19169
19270
  oauthSubmitRef,
19170
19271
  clearModelCaches
@@ -19173,16 +19274,18 @@ function createProviderSetupPicker({
19173
19274
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
19174
19275
  const onContinue = typeof options.onContinue === "function" ? options.onContinue : returnTo;
19175
19276
  const onCancel = typeof options.onCancel === "function" ? options.onCancel : null;
19277
+ const own = surface.claim();
19176
19278
  setProviderPrompt(null);
19177
- setChannelPrompt(null);
19178
- setHookPrompt(null);
19179
19279
  setSettingsPrompt(null);
19180
- setContextPanel(null);
19280
+ own.context(null);
19181
19281
  closeUsagePanel();
19282
+ const ownsSurface = () => own.owns();
19283
+ const paintProviders = (panel) => own.paint(panel);
19284
+ const releaseSurface = () => own.paint(null);
19182
19285
  let setup = options.preloadedSetup && typeof options.preloadedSetup === "object" ? options.preloadedSetup : null;
19183
19286
  options.preloadedSetup = null;
19184
19287
  if (!setup) {
19185
- setPicker({
19288
+ paintProviders({
19186
19289
  title: options.title || "Providers",
19187
19290
  description: options.description || "Choose a provider to configure.",
19188
19291
  labelWidth: 18,
@@ -19199,7 +19302,7 @@ function createProviderSetupPicker({
19199
19302
  onSelect: () => {
19200
19303
  },
19201
19304
  onCancel: () => {
19202
- setPicker(null);
19305
+ own.close();
19203
19306
  if (onCancel) onCancel();
19204
19307
  }
19205
19308
  });
@@ -19292,7 +19395,8 @@ function createProviderSetupPicker({
19292
19395
  return idx >= 0 ? idx : 0;
19293
19396
  };
19294
19397
  const reopenProviders = () => {
19295
- void openProviderSetupPicker(options);
19398
+ if (!ownsSurface()) return;
19399
+ void Promise.resolve(openProviderSetupPicker(options)).catch((e) => store.pushNotice(`providers failed: ${e?.message || e}`, "error"));
19296
19400
  };
19297
19401
  const providerActionFooter = (provider) => provider ? [{
19298
19402
  glyph: providerIsActive(provider) ? "\u25CF" : "\u25CB",
@@ -19300,6 +19404,7 @@ function createProviderSetupPicker({
19300
19404
  text: [providerKindLabel(provider), providerStatusLabel(provider), providerDetailText(provider)].filter(Boolean).join(" \xB7 ")
19301
19405
  }] : "";
19302
19406
  const setApiKeyPrompt = (providerItem) => {
19407
+ if (!ownsSurface()) return;
19303
19408
  setProviderPrompt({
19304
19409
  kind: "api-key",
19305
19410
  providerId: providerItem._providerId,
@@ -19311,6 +19416,7 @@ function createProviderSetupPicker({
19311
19416
  });
19312
19417
  };
19313
19418
  const openApiProviderActions = (providerItem) => {
19419
+ if (!ownsSurface()) return;
19314
19420
  rememberProviderSelection(providerItem);
19315
19421
  const provider = providerItem._provider || {};
19316
19422
  const hasAuth = providerItem._authenticated || provider.authenticated;
@@ -19338,7 +19444,7 @@ function createProviderSetupPicker({
19338
19444
  _action: "usage-login-browser"
19339
19445
  });
19340
19446
  }
19341
- setPicker({
19447
+ paintProviders({
19342
19448
  title: `Provider \xB7 ${providerItem._providerName}`,
19343
19449
  description: "Choose an API-key action.",
19344
19450
  footer: () => providerActionFooter(provider),
@@ -19349,19 +19455,19 @@ function createProviderSetupPicker({
19349
19455
  initialIndex: 0,
19350
19456
  items: apiActions,
19351
19457
  onSelect: (_detailValue, detail) => {
19352
- setPicker(null);
19458
+ releaseSurface();
19353
19459
  if (detail._action === "set-key") {
19354
19460
  setApiKeyPrompt(providerItem);
19355
19461
  return;
19356
19462
  }
19357
19463
  if (detail._action === "forget-key") {
19358
- try {
19359
- store.forgetProviderAuth(providerItem._providerId);
19464
+ void Promise.resolve(store.forgetProviderAuth?.(providerItem._providerId)).then(() => {
19360
19465
  clearModelCaches("all");
19361
19466
  reopenProviders();
19362
- } catch (e) {
19467
+ }).catch((e) => {
19363
19468
  store.pushNotice(`auth-forget failed: ${e?.message || e}`, "error");
19364
- }
19469
+ openApiProviderActions(providerItem);
19470
+ });
19365
19471
  }
19366
19472
  if (detail._action === "usage-login-browser") {
19367
19473
  let backedOut = false;
@@ -19381,7 +19487,7 @@ function createProviderSetupPicker({
19381
19487
  _action: "back"
19382
19488
  }
19383
19489
  ];
19384
- setPicker({
19490
+ paintProviders({
19385
19491
  title: `Provider \xB7 ${providerItem._providerName}`,
19386
19492
  description: "Opening browser. Sign in at opencode.ai/auth; the auth cookie is captured automatically.",
19387
19493
  footer: () => providerActionFooter(provider),
@@ -19436,7 +19542,7 @@ function createProviderSetupPicker({
19436
19542
  _action: "back"
19437
19543
  }
19438
19544
  ];
19439
- setPicker({
19545
+ paintProviders({
19440
19546
  title: `Provider \xB7 ${providerItem._providerName}`,
19441
19547
  description: message,
19442
19548
  footer: () => providerActionFooter(provider),
@@ -19455,7 +19561,7 @@ function createProviderSetupPicker({
19455
19561
  };
19456
19562
  const showOAuthResult = (ok, message = "") => {
19457
19563
  setProviderPrompt(null);
19458
- setPicker({
19564
+ paintProviders({
19459
19565
  title: `Provider \xB7 ${providerItem._providerName}`,
19460
19566
  description: message || (ok ? "Login complete." : "Login did not complete."),
19461
19567
  footer: () => providerActionFooter(provider),
@@ -19504,7 +19610,8 @@ function createProviderSetupPicker({
19504
19610
  };
19505
19611
  void store.beginOAuthProviderLogin(providerItem._providerId).then((login) => {
19506
19612
  if (typeof login?.completeCode === "function") {
19507
- setPicker(null);
19613
+ if (!ownsSurface()) return;
19614
+ releaseSurface();
19508
19615
  const manualUrl = login?.manualUrl || "";
19509
19616
  setProviderPrompt({
19510
19617
  kind: "oauth-code",
@@ -19556,6 +19663,7 @@ function createProviderSetupPicker({
19556
19663
  });
19557
19664
  };
19558
19665
  const openOAuthProviderActions = (providerItem) => {
19666
+ if (!ownsSurface()) return;
19559
19667
  rememberProviderSelection(providerItem);
19560
19668
  const provider = providerItem._provider || {};
19561
19669
  const hasAuth = providerItem._authenticated || provider.authenticated || provider.reauthRequired === true;
@@ -19574,7 +19682,7 @@ function createProviderSetupPicker({
19574
19682
  _action: "forget-oauth"
19575
19683
  });
19576
19684
  }
19577
- setPicker({
19685
+ paintProviders({
19578
19686
  title: `Provider \xB7 ${providerItem._providerName}`,
19579
19687
  description: "Choose an OAuth login action.",
19580
19688
  footer: () => providerActionFooter(provider),
@@ -19590,19 +19698,20 @@ function createProviderSetupPicker({
19590
19698
  return;
19591
19699
  }
19592
19700
  if (detail._action === "forget-oauth") {
19593
- try {
19594
- store.forgetProviderAuth(providerItem._providerId);
19701
+ void Promise.resolve(store.forgetProviderAuth?.(providerItem._providerId)).then(() => {
19595
19702
  clearModelCaches("all");
19596
19703
  reopenProviders();
19597
- } catch (e) {
19704
+ }).catch((e) => {
19598
19705
  store.pushNotice(`auth-forget failed: ${e?.message || e}`, "error");
19599
- }
19706
+ openOAuthProviderActions(providerItem);
19707
+ });
19600
19708
  }
19601
19709
  },
19602
19710
  onCancel: reopenProviders
19603
19711
  });
19604
19712
  };
19605
19713
  const openLocalProviderActions = (providerItem) => {
19714
+ if (!ownsSurface()) return;
19606
19715
  rememberProviderSelection(providerItem);
19607
19716
  const provider = providerItem._provider || {};
19608
19717
  const localActions = [
@@ -19621,7 +19730,7 @@ function createProviderSetupPicker({
19621
19730
  _action: "disable-local"
19622
19731
  });
19623
19732
  }
19624
- setPicker({
19733
+ paintProviders({
19625
19734
  title: `Provider \xB7 ${providerItem._providerName}`,
19626
19735
  description: "Choose a local endpoint action.",
19627
19736
  footer: () => providerActionFooter(provider),
@@ -19632,7 +19741,7 @@ function createProviderSetupPicker({
19632
19741
  initialIndex: 0,
19633
19742
  items: localActions,
19634
19743
  onSelect: (_detailValue, detail) => {
19635
- setPicker(null);
19744
+ releaseSurface();
19636
19745
  if (detail._action === "set-local-url") {
19637
19746
  setProviderPrompt({
19638
19747
  kind: "local-url",
@@ -19644,19 +19753,19 @@ function createProviderSetupPicker({
19644
19753
  return;
19645
19754
  }
19646
19755
  if (detail._action === "disable-local") {
19647
- try {
19648
- store.setLocalProvider(providerItem._providerId, { enabled: false, baseURL: providerItem._baseURL });
19756
+ void Promise.resolve(store.setLocalProvider?.(providerItem._providerId, { enabled: false, baseURL: providerItem._baseURL })).then(() => {
19649
19757
  clearModelCaches("all");
19650
19758
  reopenProviders();
19651
- } catch (e) {
19759
+ }).catch((e) => {
19652
19760
  store.pushNotice(`local provider update failed: ${e?.message || e}`, "error");
19653
- }
19761
+ openLocalProviderActions(providerItem);
19762
+ });
19654
19763
  }
19655
19764
  },
19656
19765
  onCancel: reopenProviders
19657
19766
  });
19658
19767
  };
19659
- setPicker({
19768
+ paintProviders({
19660
19769
  title: options.title || "Providers",
19661
19770
  description: options.description || "Choose a provider. Enter opens provider actions.",
19662
19771
  footer: providerFooter,
@@ -19673,7 +19782,7 @@ function createProviderSetupPicker({
19673
19782
  if (item?._providerId) rememberProviderSelection(item);
19674
19783
  },
19675
19784
  onSelect: (_value, item) => {
19676
- setPicker(null);
19785
+ releaseSurface();
19677
19786
  if (item._type === "continue") {
19678
19787
  onContinue?.();
19679
19788
  return;
@@ -19691,7 +19800,7 @@ function createProviderSetupPicker({
19691
19800
  }
19692
19801
  },
19693
19802
  onCancel: () => {
19694
- setPicker(null);
19803
+ own.close();
19695
19804
  if (onCancel) onCancel();
19696
19805
  else if (returnTo) returnTo();
19697
19806
  }
@@ -19705,10 +19814,8 @@ var MODEL_CACHE_TTL_MS = 5 * 60 * 1e3;
19705
19814
  function createModelPicker({
19706
19815
  store,
19707
19816
  getState,
19708
- setPicker,
19817
+ surface,
19709
19818
  setProviderPrompt,
19710
- setChannelPrompt,
19711
- setHookPrompt,
19712
19819
  setSettingsPrompt,
19713
19820
  providerModelsCacheRef,
19714
19821
  webSearchModelsCacheRef,
@@ -19720,9 +19827,8 @@ function createModelPicker({
19720
19827
  let providerModelsTtlRefreshPromise = null;
19721
19828
  const openModelPicker = async (options = {}) => {
19722
19829
  const state = getState();
19830
+ const own = surface.claim();
19723
19831
  setProviderPrompt(null);
19724
- setChannelPrompt(null);
19725
- setHookPrompt(null);
19726
19832
  setSettingsPrompt(null);
19727
19833
  modelPickerRequestRef.current += 1;
19728
19834
  let modelPickerClosed = false;
@@ -19733,15 +19839,16 @@ function createModelPicker({
19733
19839
  const cancelModelPicker = () => {
19734
19840
  modelPickerClosed = true;
19735
19841
  if (returnTo) returnTo();
19736
- else setPicker(null);
19842
+ else own.close();
19737
19843
  };
19844
+ const paintModelPicker = (panel) => own.paint(panel);
19738
19845
  const cacheRef = options.cacheRef === "webSearch" ? webSearchModelsCacheRef : providerModelsCacheRef;
19739
19846
  const loadModels = typeof options.loadModels === "function" ? options.loadModels : store.listProviderModels;
19740
19847
  let providerModels = Array.isArray(cacheRef.current.models) ? cacheRef.current.models : [];
19741
19848
  let refreshModelsPromise = null;
19742
19849
  let renderedQuickModels = false;
19743
19850
  if (!providerModels.length || options.refreshModels === true) {
19744
- setPicker({
19851
+ paintModelPicker({
19745
19852
  title: options.title || "Model",
19746
19853
  description: options.loadingDescription || "Loading models...",
19747
19854
  help: returnTo ? `\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc ${returnLabel}` : "\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc Back",
@@ -19770,6 +19877,7 @@ function createModelPicker({
19770
19877
  const cacheIsStale = providerModels.length > 0 && options.refreshModels !== true && options.cacheRef !== "webSearch" && !refreshModelsPromise && Date.now() - cacheAt > MODEL_CACHE_TTL_MS;
19771
19878
  if (!providerModels || providerModels.length === 0) {
19772
19879
  store.pushNotice(options.emptyNotice || "no provider models available; open /providers to sign in", "warn");
19880
+ if (!own.owns()) return;
19773
19881
  void openProviderSetupPicker({
19774
19882
  title: "Providers",
19775
19883
  continueLabel: "Back to model setup",
@@ -20013,23 +20121,29 @@ ${model?.id || ""}`;
20013
20121
  if (typeof options.onImmediateSelect === "function") {
20014
20122
  options.onImmediateSelect(routeInput, selected, effort);
20015
20123
  } else {
20016
- setPicker(null);
20124
+ own.paint(null);
20017
20125
  }
20126
+ const afterSelect2 = own.defer(() => {
20127
+ if (typeof options.onAfterSelect === "function") options.onAfterSelect();
20128
+ });
20018
20129
  void savePromise.then((result) => {
20019
20130
  if (result) clearModelCaches("all");
20020
- if (typeof options.onAfterSelect === "function") options.onAfterSelect();
20131
+ afterSelect2();
20021
20132
  return result;
20022
20133
  }).catch((e) => store.pushNotice(`Couldn\u2019t save model: ${e?.message || e}`, "error"));
20023
20134
  return;
20024
20135
  }
20025
- setPicker(null);
20136
+ own.paint(null);
20137
+ const afterSelect = own.defer(() => {
20138
+ if (typeof options.onAfterSelect === "function") options.onAfterSelect();
20139
+ });
20026
20140
  void store.setRoute(routeInput).then((ok) => {
20027
20141
  if (ok) clearModelCaches("provider");
20028
20142
  store.pushNotice(
20029
20143
  ok ? modelSwitchNotice2() : "Model switch is already running",
20030
20144
  ok ? "info" : "warn"
20031
20145
  );
20032
- if (ok && typeof options.onAfterSelect === "function") options.onAfterSelect();
20146
+ if (ok) afterSelect();
20033
20147
  }).catch((e) => store.pushNotice(`Couldn\u2019t switch model: ${e?.message || e}`, "error"));
20034
20148
  };
20035
20149
  const renderProviderModels = () => {
@@ -20040,7 +20154,7 @@ ${model?.id || ""}`;
20040
20154
  (item) => item._provider === activeRoute?.provider && item._modelId === activeRoute?.model
20041
20155
  )
20042
20156
  );
20043
- setPicker({
20157
+ paintModelPicker({
20044
20158
  title: providerDisplayName(provider),
20045
20159
  description: options.modelDescription || "Select a model. Adjust Effort with \u2190/\u2192.",
20046
20160
  footer: (item) => modelFooter(item?._model),
@@ -20090,7 +20204,7 @@ ${model?.id || ""}`;
20090
20204
  0,
20091
20205
  providerItems.findIndex((item) => item._provider === providerHighlight)
20092
20206
  );
20093
- setPicker({
20207
+ paintModelPicker({
20094
20208
  title: options.title || "Model",
20095
20209
  description: options.providerDescription || "Choose a provider.",
20096
20210
  help: returnTo ? `\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc ${returnLabel}` : "\u2191/\u2193 Select \xB7 Enter Open \xB7 Esc Back",
@@ -20141,12 +20255,9 @@ var outputStyleNotice = (result) => {
20141
20255
  function createRoutePickers({
20142
20256
  store,
20143
20257
  state,
20144
- setPicker,
20258
+ surface,
20145
20259
  setProviderPrompt,
20146
- setChannelPrompt,
20147
- setHookPrompt,
20148
20260
  setSettingsPrompt,
20149
- setContextPanel,
20150
20261
  closeUsagePanel,
20151
20262
  clean: clean2,
20152
20263
  routeLabel: routeLabel2,
@@ -20158,7 +20269,9 @@ function createRoutePickers({
20158
20269
  const openWebSearchPicker = async (options = {}) => {
20159
20270
  const routeOverride = options.routeOverride || null;
20160
20271
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
20272
+ const own = surface.claim();
20161
20273
  const currentWebSearchRoute = routeOverride || await store.getWebSearchRoute?.() || null;
20274
+ if (!own.owns()) return;
20162
20275
  void openModelPicker({
20163
20276
  title: "Web Search Model",
20164
20277
  loadingDescription: "Loading web-search-capable models...",
@@ -20173,7 +20286,7 @@ function createRoutePickers({
20173
20286
  returnOnNestedCancel: options.returnOnNestedCancel === true,
20174
20287
  onImmediateSelect: () => {
20175
20288
  if (returnTo) returnTo();
20176
- else setPicker(null);
20289
+ else surface.claim().close();
20177
20290
  },
20178
20291
  onSelectRoute: async (routeInput) => {
20179
20292
  const result = await store.setWebSearchRoute?.(routeInput);
@@ -20188,6 +20301,7 @@ function createRoutePickers({
20188
20301
  });
20189
20302
  };
20190
20303
  const openAgentsPicker = async (options = {}) => {
20304
+ const own = surface.claim();
20191
20305
  let agents = [];
20192
20306
  try {
20193
20307
  agents = await store.listAgents?.() || [];
@@ -20205,13 +20319,12 @@ function createRoutePickers({
20205
20319
  description: agent.description || agent.definition?.description || "",
20206
20320
  _agent: agent
20207
20321
  }));
20322
+ if (!own.owns()) return;
20208
20323
  setProviderPrompt(null);
20209
- setChannelPrompt(null);
20210
- setHookPrompt(null);
20211
20324
  setSettingsPrompt(null);
20212
- setContextPanel(null);
20325
+ own.context(null);
20213
20326
  closeUsagePanel();
20214
- setPicker({
20327
+ own.paint({
20215
20328
  title: "Agents",
20216
20329
  description: "Workflow agents available for agent tasks.",
20217
20330
  help: "\u2191/\u2193 Select \xB7 Enter Set Model \xB7 Esc Back",
@@ -20241,7 +20354,7 @@ function createRoutePickers({
20241
20354
  store.pushNotice(`${agent.label} model set to ${agentModelProfile2(result)}`, "info");
20242
20355
  }
20243
20356
  });
20244
- setPicker({
20357
+ own.paint({
20245
20358
  title: agent.label,
20246
20359
  description: "Pick a model for this agent, or turn it off.",
20247
20360
  help: "\u2191/\u2193 Select \xB7 Enter Choose \xB7 Esc Back",
@@ -20267,6 +20380,9 @@ function createRoutePickers({
20267
20380
  openAgentModelPicker();
20268
20381
  return;
20269
20382
  }
20383
+ const reopenAgents = own.defer(() => {
20384
+ void openAgentsPicker();
20385
+ });
20270
20386
  try {
20271
20387
  const result = await store.setAgentRoute?.(agent.id, { disabled: true });
20272
20388
  if (!result) {
@@ -20277,7 +20393,7 @@ function createRoutePickers({
20277
20393
  } catch (e) {
20278
20394
  store.pushNotice(`could not turn off ${agent.label}: ${e?.message || e}`, "error");
20279
20395
  }
20280
- void openAgentsPicker();
20396
+ reopenAgents();
20281
20397
  },
20282
20398
  onCancel: () => {
20283
20399
  void openAgentsPicker();
@@ -20285,12 +20401,13 @@ function createRoutePickers({
20285
20401
  });
20286
20402
  },
20287
20403
  onCancel: () => {
20288
- setPicker(null);
20404
+ own.close();
20289
20405
  }
20290
20406
  });
20291
20407
  };
20292
20408
  const openWorkflowPicker = async (options = {}) => {
20293
20409
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
20410
+ const own = surface.claim();
20294
20411
  let workflows = [];
20295
20412
  try {
20296
20413
  workflows = await store.listWorkflows?.() || [];
@@ -20310,13 +20427,12 @@ function createRoutePickers({
20310
20427
  description: workflow.description || `${workflow.source || "workflow"} workflow`,
20311
20428
  _workflow: workflow
20312
20429
  }));
20430
+ if (!own.owns()) return;
20313
20431
  setProviderPrompt(null);
20314
- setChannelPrompt(null);
20315
- setHookPrompt(null);
20316
20432
  setSettingsPrompt(null);
20317
- setContextPanel(null);
20433
+ own.context(null);
20318
20434
  closeUsagePanel();
20319
- setPicker({
20435
+ own.paint({
20320
20436
  title: "Workflow",
20321
20437
  description: "Select active workflow.",
20322
20438
  help: returnTo ? "\u2191/\u2193 Select \xB7 Enter Choose \xB7 Esc Settings" : "\u2191/\u2193 Select \xB7 Enter Choose \xB7 Esc Back",
@@ -20325,18 +20441,21 @@ function createRoutePickers({
20325
20441
  onSelect: (_value, item) => {
20326
20442
  const workflow = item?._workflow;
20327
20443
  if (!workflow) return;
20328
- setPicker(null);
20444
+ own.paint(null);
20445
+ const returnAfterSwitch = own.defer(() => {
20446
+ if (returnTo) returnTo();
20447
+ });
20329
20448
  void store.setWorkflow?.(workflow.id).then((result) => {
20330
20449
  if (!result) {
20331
20450
  store.pushNotice("Workflow switch is already running.", "warn");
20332
20451
  return;
20333
20452
  }
20334
20453
  store.pushNotice(workflowSwitchNotice2(result), "info");
20335
- if (returnTo) returnTo();
20454
+ returnAfterSwitch();
20336
20455
  }).catch((e) => store.pushNotice(`Couldn\u2019t switch workflow: ${e?.message || e}`, "error"));
20337
20456
  },
20338
20457
  onCancel: () => {
20339
- setPicker(null);
20458
+ own.close();
20340
20459
  if (returnTo) returnTo();
20341
20460
  }
20342
20461
  });
@@ -20344,6 +20463,7 @@ function createRoutePickers({
20344
20463
  const openOutputStylePicker = async (options = {}) => {
20345
20464
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : null;
20346
20465
  const onboarding = options.onboarding || null;
20466
+ const own = surface.claim();
20347
20467
  let status = null;
20348
20468
  try {
20349
20469
  status = await store.listOutputStyles?.() || null;
@@ -20366,26 +20486,28 @@ function createRoutePickers({
20366
20486
  description: style.description || style.source || "output style",
20367
20487
  _style: style
20368
20488
  }));
20489
+ if (!own.owns()) return;
20369
20490
  setProviderPrompt(null);
20370
- setChannelPrompt(null);
20371
- setHookPrompt(null);
20372
20491
  setSettingsPrompt(null);
20373
- setContextPanel(null);
20492
+ own.context(null);
20374
20493
  closeUsagePanel();
20375
20494
  const saveStyle = (styleId, { advance = false } = {}) => {
20376
20495
  if (!styleId) return;
20377
- if (!(advance && onboarding)) setPicker(null);
20496
+ if (!(advance && onboarding)) own.paint(null);
20497
+ const advanceAfterSave = own.defer(() => {
20498
+ if (advance && onboarding) onboarding.onAdvance?.();
20499
+ else if (returnTo) returnTo();
20500
+ });
20378
20501
  void store.setOutputStyle?.(styleId).then((result) => {
20379
20502
  if (!result) {
20380
20503
  store.pushNotice("Output style switch is already running.", "warn");
20381
20504
  } else {
20382
20505
  store.pushNotice(outputStyleNotice(result), "info");
20383
20506
  }
20384
- if (advance && onboarding) onboarding.onAdvance?.();
20385
- else if (returnTo) returnTo();
20507
+ advanceAfterSave();
20386
20508
  }).catch((e) => store.pushNotice(`Couldn\u2019t switch output style: ${e?.message || e}`, "error"));
20387
20509
  };
20388
- setPicker({
20510
+ own.paint({
20389
20511
  title: "Output Style",
20390
20512
  description: "Select response style.",
20391
20513
  // Onboarding uses a ConfirmBar (←/→ = Back/Next); let the Picker supply
@@ -20400,7 +20522,7 @@ function createRoutePickers({
20400
20522
  ],
20401
20523
  onConfirm: (button) => {
20402
20524
  if (button.value === "back") {
20403
- setPicker(null);
20525
+ own.close();
20404
20526
  onboarding.onBack?.();
20405
20527
  return;
20406
20528
  }
@@ -20416,7 +20538,7 @@ function createRoutePickers({
20416
20538
  saveStyle(style.id, { advance: Boolean(onboarding) });
20417
20539
  },
20418
20540
  onCancel: () => {
20419
- setPicker(null);
20541
+ own.close();
20420
20542
  if (onboarding) onboarding.onCancel?.();
20421
20543
  else if (returnTo) returnTo();
20422
20544
  }
@@ -20541,12 +20663,11 @@ async function toggleVoice({ pushNotice, setProgressHint } = {}) {
20541
20663
  function createSettingsPicker({
20542
20664
  store,
20543
20665
  state,
20544
- setPicker,
20666
+ surface,
20545
20667
  setProviderPrompt,
20546
- setChannelPrompt,
20547
- setHookPrompt,
20548
20668
  setSettingsPrompt,
20549
20669
  settingsHeavyCacheRef,
20670
+ settingsRequestRef,
20550
20671
  formatDuration: formatDuration2,
20551
20672
  displayModelName: displayModelName3,
20552
20673
  routeModelLabel: routeModelLabel2,
@@ -20569,7 +20690,14 @@ function createSettingsPicker({
20569
20690
  openMemoryCorePicker,
20570
20691
  openUpdatePicker
20571
20692
  }) {
20572
- const openSettingsPicker = async (opts = {}) => {
20693
+ const nextSettingsRequest = () => {
20694
+ if (!settingsRequestRef) return 0;
20695
+ settingsRequestRef.current = (Number(settingsRequestRef.current) || 0) + 1;
20696
+ return settingsRequestRef.current;
20697
+ };
20698
+ const isCurrentSettingsRequest = (requestId) => !settingsRequestRef || settingsRequestRef.current === requestId;
20699
+ const buildSettingsPicker = async (opts = {}, requestId = 0) => {
20700
+ const own = surface.claim();
20573
20701
  const light = opts.light === true;
20574
20702
  const overrides = opts.overrides || null;
20575
20703
  const heavyCache = light ? settingsHeavyCacheRef.current : null;
@@ -20593,13 +20721,12 @@ function createSettingsPicker({
20593
20721
  const workflowLabel = workflowDisplayName2(workflow);
20594
20722
  const boolLabel = (enabled) => enabled ? "On" : "Off";
20595
20723
  const compactTypeDescription = "Uses Memory recall to rebuild context faster on large histories.";
20724
+ const deferredSettingsRefresh = () => own.defer(() => refreshSettings());
20596
20725
  const applyAutoClear = (patch = {}) => {
20597
20726
  void Promise.resolve(store.setAutoClear?.(patch)).then((next) => {
20598
20727
  if (!next) store.pushNotice("autoclear unavailable", "warn");
20599
20728
  else store.pushNotice(next.enabled ? `Auto-clear on \xB7 idle ${formatDuration2(next.idleMs)}` : "Auto-clear off", "info");
20600
- }).catch((e) => store.pushNotice(`autoclear failed: ${e?.message || e}`, "error")).finally(() => {
20601
- void openSettingsPicker({ light: true });
20602
- });
20729
+ }).catch((e) => store.pushNotice(`autoclear failed: ${e?.message || e}`, "error")).finally(deferredSettingsRefresh());
20603
20730
  };
20604
20731
  const autoClearEnabled = autoClear.enabled !== false;
20605
20732
  const toggleAutoClear = () => applyAutoClear({ enabled: !autoClearEnabled });
@@ -20610,22 +20737,20 @@ function createSettingsPicker({
20610
20737
  return;
20611
20738
  }
20612
20739
  store.pushNotice(`Compaction ${next.auto !== false ? "auto on" : "auto off"} \xB7 ${next.compactType === "recall-fasttrack" ? "Fast-track" : "Default"}`, "info");
20613
- }).catch((e) => store.pushNotice(`compaction failed: ${e?.message || e}`, "error")).finally(() => openSettingsPicker({ light: true }));
20740
+ }).catch((e) => store.pushNotice(`compaction failed: ${e?.message || e}`, "error")).finally(deferredSettingsRefresh());
20614
20741
  };
20615
20742
  const applyVoice = () => {
20616
20743
  if (isVoiceInstallBusy()) {
20617
20744
  store.pushNotice("Voice install is already running", "warn");
20618
20745
  return;
20619
20746
  }
20620
- void Promise.resolve(toggleVoice({ pushNotice: store.pushNotice, setProgressHint: store.setProgressHint })).finally(() => {
20621
- void openSettingsPicker({ light: true });
20622
- });
20747
+ void Promise.resolve(toggleVoice({ pushNotice: store.pushNotice, setProgressHint: store.setProgressHint })).catch((e) => store.pushNotice(`voice setup failed: ${e?.message || e}`, "error")).finally(deferredSettingsRefresh());
20623
20748
  };
20624
20749
  const applyToolModule = (label, setter, enabled) => {
20625
20750
  void Promise.resolve(setter?.(enabled)).then((next) => {
20626
20751
  if (!next) store.pushNotice(`${label} setting is busy`, "warn");
20627
20752
  else store.pushNotice(`${label} ${enabled ? "on" : "off"} \xB7 new sessions`, "info");
20628
- }).catch((e) => store.pushNotice(`${label} setting failed: ${e?.message || e}`, "error")).finally(() => openSettingsPicker({ light: true }));
20753
+ }).catch((e) => store.pushNotice(`${label} setting failed: ${e?.message || e}`, "error")).finally(deferredSettingsRefresh());
20629
20754
  };
20630
20755
  const toggleWebSearch = () => applyToolModule("Web search", store.setWebSearchEnabled, !webSearchOn);
20631
20756
  const toggleMemory = () => applyToolModule("Memory", store.setMemoryToolsEnabled, !memoryToolsOn);
@@ -20634,9 +20759,10 @@ function createSettingsPicker({
20634
20759
  void Promise.resolve(store.setRecapEnabled?.(enabled)).then((next) => {
20635
20760
  if (!next) store.pushNotice("Memory cycles setting is busy", "warn");
20636
20761
  else store.pushNotice(`Memory cycles ${enabled ? "on" : "off"}`, "info");
20637
- }).catch((e) => store.pushNotice(`Memory cycles setting failed: ${e?.message || e}`, "error")).finally(() => openSettingsPicker({ light: true }));
20762
+ }).catch((e) => store.pushNotice(`Memory cycles setting failed: ${e?.message || e}`, "error")).finally(deferredSettingsRefresh());
20638
20763
  };
20639
20764
  const cycleOutputStyle = async (direction = 1) => {
20765
+ const settled = deferredSettingsRefresh();
20640
20766
  let status = null;
20641
20767
  try {
20642
20768
  status = await store.listOutputStyles?.() || null;
@@ -20658,9 +20784,10 @@ function createSettingsPicker({
20658
20784
  return;
20659
20785
  }
20660
20786
  store.pushNotice(outputStyleNotice(result), "info");
20661
- }).catch((e) => store.pushNotice(`Couldn\u2019t switch output style: ${e?.message || e}`, "error")).finally(() => openSettingsPicker({ light: true }));
20787
+ }).catch((e) => store.pushNotice(`Couldn\u2019t switch output style: ${e?.message || e}`, "error")).finally(settled);
20662
20788
  };
20663
20789
  const cycleWorkflow = async (direction = 1) => {
20790
+ const settled = deferredSettingsRefresh();
20664
20791
  let workflows = [];
20665
20792
  try {
20666
20793
  workflows = await store.listWorkflows?.() || [];
@@ -20681,7 +20808,7 @@ function createSettingsPicker({
20681
20808
  return;
20682
20809
  }
20683
20810
  store.pushNotice(workflowSwitchNotice2(result), "info");
20684
- }).catch((e) => store.pushNotice(`Couldn\u2019t switch workflow: ${e?.message || e}`, "error")).finally(() => openSettingsPicker({ light: true }));
20811
+ }).catch((e) => store.pushNotice(`Couldn\u2019t switch workflow: ${e?.message || e}`, "error")).finally(settled);
20685
20812
  };
20686
20813
  const cycleTheme = (direction = 1) => {
20687
20814
  let themes = [];
@@ -20704,7 +20831,7 @@ function createSettingsPicker({
20704
20831
  } catch (e) {
20705
20832
  store.pushNotice(`Couldn\u2019t set theme: ${e?.message || e}`, "error");
20706
20833
  }
20707
- openSettingsPicker({ light: true });
20834
+ refreshSettings();
20708
20835
  };
20709
20836
  const items = [
20710
20837
  {
@@ -20717,7 +20844,10 @@ function createSettingsPicker({
20717
20844
  {
20718
20845
  value: "websearch",
20719
20846
  label: "Web search model",
20720
- meta: routeModelLabel2(store.getWebSearchRoute?.()),
20847
+ // From the one-shot snapshot: a direct getWebSearchRoute() here is an
20848
+ // unresolved promise on a daemon-backed store, so the row rendered
20849
+ // its "(unset)" default for every configured route.
20850
+ meta: routeModelLabel2(snapshot.webSearchRoute || null),
20721
20851
  description: "Native web-search model.",
20722
20852
  _action: "websearch"
20723
20853
  },
@@ -20868,11 +20998,11 @@ function createSettingsPicker({
20868
20998
  _action: "update"
20869
20999
  }
20870
21000
  ];
21001
+ if (!isCurrentSettingsRequest(requestId)) return;
21002
+ if (!own.owns()) return;
20871
21003
  setProviderPrompt(null);
20872
- setChannelPrompt(null);
20873
- setHookPrompt(null);
20874
21004
  setSettingsPrompt(null);
20875
- setPicker({
21005
+ own.paint({
20876
21006
  title: "Settings",
20877
21007
  description: "Runtime, model, tools, and integrations.",
20878
21008
  help: "\u2191/\u2193 Select \xB7 \u2190/\u2192 Change \xB7 Enter Open/Toggle \xB7 Esc Close",
@@ -20937,7 +21067,7 @@ function createSettingsPicker({
20937
21067
  else if (item._action === "skills") openSkillsPicker();
20938
21068
  else if (item._action === "memory") openMemoryCorePicker({ returnTo: openSettingsPicker });
20939
21069
  else if (item._action === "system-shell") {
20940
- setPicker(null);
21070
+ own.close();
20941
21071
  setSettingsPrompt({
20942
21072
  kind: "system-shell",
20943
21073
  label: "System shell",
@@ -20947,10 +21077,22 @@ function createSettingsPicker({
20947
21077
  } else if (item._action === "update") openUpdatePicker({ returnTo: openSettingsPicker });
20948
21078
  },
20949
21079
  onCancel: () => {
20950
- setPicker(null);
21080
+ nextSettingsRequest();
21081
+ own.close();
20951
21082
  }
20952
21083
  });
20953
21084
  };
21085
+ const openSettingsPicker = async (opts = {}) => {
21086
+ const requestId = nextSettingsRequest();
21087
+ try {
21088
+ await buildSettingsPicker(opts, requestId);
21089
+ } catch (error) {
21090
+ store.pushNotice(`settings unavailable: ${error?.message || error}`, "error");
21091
+ }
21092
+ };
21093
+ const refreshSettings = () => {
21094
+ void openSettingsPicker({ light: true });
21095
+ };
20954
21096
  return { openSettingsPicker };
20955
21097
  }
20956
21098
 
@@ -20965,7 +21107,7 @@ function createSlashDispatch({
20965
21107
  state,
20966
21108
  store,
20967
21109
  normalizeSlashCommandName: normalizeSlashCommandName2,
20968
- setContextPanel,
21110
+ surface,
20969
21111
  closeUsagePanel,
20970
21112
  openModelPicker,
20971
21113
  modelSwitchNotice: modelSwitchNotice2,
@@ -21001,7 +21143,7 @@ function createSlashDispatch({
21001
21143
  const runSlashCommand = (cmd, arg = "") => {
21002
21144
  const rawName = String(cmd || "").toLowerCase();
21003
21145
  cmd = normalizeSlashCommandName2(cmd);
21004
- if (cmd !== "context") setContextPanel(null);
21146
+ if (cmd !== "context") surface.claim().context(null);
21005
21147
  if (cmd !== "usage") closeUsagePanel();
21006
21148
  switch (cmd) {
21007
21149
  case "clear":
@@ -21286,12 +21428,9 @@ function createSlashDispatch({
21286
21428
  function createAppPickers({
21287
21429
  state,
21288
21430
  store,
21289
- setPicker,
21431
+ surface,
21290
21432
  setProviderPrompt,
21291
- setChannelPrompt,
21292
- setHookPrompt,
21293
21433
  setSettingsPrompt,
21294
- setContextPanel,
21295
21434
  setOnboardingActive,
21296
21435
  closeUsagePanel,
21297
21436
  oauthSubmitRef,
@@ -21302,6 +21441,7 @@ function createAppPickers({
21302
21441
  modelPickerRequestRef,
21303
21442
  onboardingPrefetchSeqRef,
21304
21443
  settingsHeavyCacheRef,
21444
+ settingsRequestRef,
21305
21445
  livePickerRef,
21306
21446
  disabledSkills,
21307
21447
  setDisabledSkills,
@@ -21314,24 +21454,21 @@ function createAppPickers({
21314
21454
  const { openThemePicker, openEffortPicker } = createThemeEffortPickers({
21315
21455
  state,
21316
21456
  store,
21317
- setPicker,
21457
+ surface,
21318
21458
  setProviderPrompt,
21319
- setChannelPrompt,
21320
- setHookPrompt,
21321
21459
  setSettingsPrompt,
21322
- setContextPanel,
21323
21460
  closeUsagePanel,
21324
21461
  clean
21325
21462
  });
21326
21463
  const { openResumePicker } = createResumePicker({
21327
21464
  store,
21328
- setPicker,
21465
+ surface,
21329
21466
  formatSessionUpdatedAt,
21330
21467
  formatSessionMessageCount
21331
21468
  });
21332
21469
  const { openMemoryCorePicker } = createCoreMemoryPicker({
21333
21470
  store,
21334
- setPicker,
21471
+ surface,
21335
21472
  setSettingsPrompt,
21336
21473
  parseMemoryCoreRows
21337
21474
  });
@@ -21351,11 +21488,9 @@ function createAppPickers({
21351
21488
  theme,
21352
21489
  clean,
21353
21490
  copyToClipboard,
21354
- setPicker,
21491
+ surface,
21355
21492
  getPicker: () => livePickerRef.current,
21356
21493
  setProviderPrompt,
21357
- setChannelPrompt,
21358
- setHookPrompt,
21359
21494
  setSettingsPrompt,
21360
21495
  getDisabledSkills: () => disabledSkills,
21361
21496
  setDisabledSkills
@@ -21368,20 +21503,15 @@ function createAppPickers({
21368
21503
  store,
21369
21504
  theme,
21370
21505
  formatDuration,
21371
- setPicker,
21506
+ surface,
21372
21507
  setProviderPrompt,
21373
- setChannelPrompt,
21374
- setHookPrompt,
21375
21508
  setSettingsPrompt,
21376
- setContextPanel,
21377
21509
  closeUsagePanel
21378
21510
  });
21379
21511
  const { onboardingWarnReopen, openOnboardingAuthStep } = createOnboardingSteps({
21380
21512
  store,
21381
- setPicker,
21513
+ surface,
21382
21514
  setProviderPrompt,
21383
- setChannelPrompt,
21384
- setHookPrompt,
21385
21515
  setSettingsPrompt,
21386
21516
  setOnboardingActive,
21387
21517
  onboardingRef,
@@ -21393,12 +21523,9 @@ function createAppPickers({
21393
21523
  });
21394
21524
  const { openProviderSetupPicker } = createProviderSetupPicker({
21395
21525
  store,
21396
- setPicker,
21526
+ surface,
21397
21527
  setProviderPrompt,
21398
- setChannelPrompt,
21399
- setHookPrompt,
21400
21528
  setSettingsPrompt,
21401
- setContextPanel,
21402
21529
  closeUsagePanel,
21403
21530
  oauthSubmitRef,
21404
21531
  clearModelCaches
@@ -21406,10 +21533,8 @@ function createAppPickers({
21406
21533
  const { openModelPicker } = createModelPicker({
21407
21534
  store,
21408
21535
  getState: () => state,
21409
- setPicker,
21536
+ surface,
21410
21537
  setProviderPrompt,
21411
- setChannelPrompt,
21412
- setHookPrompt,
21413
21538
  setSettingsPrompt,
21414
21539
  providerModelsCacheRef,
21415
21540
  webSearchModelsCacheRef,
@@ -21426,12 +21551,9 @@ function createAppPickers({
21426
21551
  } = createRoutePickers({
21427
21552
  store,
21428
21553
  state,
21429
- setPicker,
21554
+ surface,
21430
21555
  setProviderPrompt,
21431
- setChannelPrompt,
21432
- setHookPrompt,
21433
21556
  setSettingsPrompt,
21434
- setContextPanel,
21435
21557
  closeUsagePanel,
21436
21558
  clean,
21437
21559
  routeLabel,
@@ -21443,12 +21565,11 @@ function createAppPickers({
21443
21565
  const { openSettingsPicker } = createSettingsPicker({
21444
21566
  store,
21445
21567
  state,
21446
- setPicker,
21568
+ surface,
21447
21569
  setProviderPrompt,
21448
- setChannelPrompt,
21449
- setHookPrompt,
21450
21570
  setSettingsPrompt,
21451
21571
  settingsHeavyCacheRef,
21572
+ settingsRequestRef,
21452
21573
  formatDuration,
21453
21574
  displayModelName,
21454
21575
  routeModelLabel,
@@ -21475,7 +21596,7 @@ function createAppPickers({
21475
21596
  state,
21476
21597
  store,
21477
21598
  normalizeSlashCommandName,
21478
- setContextPanel,
21599
+ surface,
21479
21600
  closeUsagePanel,
21480
21601
  openModelPicker: (...a) => openModelPicker(...a),
21481
21602
  modelSwitchNotice,
@@ -21712,7 +21833,7 @@ function messageSelectorLabel(text, width = 56) {
21712
21833
  function useMessageSelector({
21713
21834
  store,
21714
21835
  state,
21715
- setPicker,
21836
+ surface,
21716
21837
  setPromptDraftOverride,
21717
21838
  syncPromptLayoutRows,
21718
21839
  showPromptHint,
@@ -21742,14 +21863,15 @@ function useMessageSelector({
21742
21863
  showPromptHint("No message to jump back to.", "info");
21743
21864
  return false;
21744
21865
  }
21745
- setPicker({
21866
+ const own = surface.claim();
21867
+ own.paint({
21746
21868
  _kind: "message-selector",
21747
21869
  title: "Jump back to a message",
21748
21870
  description: "Rewind the conversation to a previous prompt and edit it.",
21749
21871
  initialIndex: rows.length - 1,
21750
21872
  items: rows.map((row) => ({ value: row.id, label: messageSelectorLabel(row.text) })),
21751
21873
  onSelect: (value) => {
21752
- setPicker(null);
21874
+ own.close();
21753
21875
  let restored;
21754
21876
  try {
21755
21877
  restored = store.rewindToItem?.(value);
@@ -21763,10 +21885,10 @@ function useMessageSelector({
21763
21885
  }
21764
21886
  applyRewind(restored);
21765
21887
  },
21766
- onCancel: () => setPicker(null)
21888
+ onCancel: () => own.close()
21767
21889
  });
21768
21890
  return true;
21769
- }, [store, state.items, setPicker, applyRewind, showPromptHint]);
21891
+ }, [store, state.items, surface, applyRewind, showPromptHint]);
21770
21892
  return { hasUserMessages, openMessageSelector };
21771
21893
  }
21772
21894
 
@@ -22367,12 +22489,9 @@ function useTranscriptWindow({
22367
22489
  function createProjectPicker({
22368
22490
  state,
22369
22491
  store,
22370
- setPicker,
22492
+ surface,
22371
22493
  setProviderPrompt,
22372
- setChannelPrompt,
22373
- setHookPrompt,
22374
22494
  setSettingsPrompt,
22375
- setContextPanel,
22376
22495
  closeUsagePanel,
22377
22496
  projectNameFromPath: projectNameFromPath3,
22378
22497
  pickFolder: pickFolder2
@@ -22443,16 +22562,15 @@ function createProjectPicker({
22443
22562
  }
22444
22563
  },
22445
22564
  onCancel: () => {
22446
- setPicker(null);
22565
+ surface.claim().close();
22447
22566
  }
22448
22567
  };
22449
22568
  };
22450
22569
  const beginNewProjectManual = () => {
22451
- setPicker(null);
22570
+ const own = surface.claim();
22571
+ own.context(null);
22572
+ own.close();
22452
22573
  setProviderPrompt(null);
22453
- setChannelPrompt(null);
22454
- setHookPrompt(null);
22455
- setContextPanel(null);
22456
22574
  closeUsagePanel();
22457
22575
  setSettingsPrompt({
22458
22576
  kind: "project-new",
@@ -22461,12 +22579,11 @@ function createProjectPicker({
22461
22579
  });
22462
22580
  };
22463
22581
  const beginNewProject = () => {
22582
+ const own = surface.claim();
22464
22583
  setProviderPrompt(null);
22465
- setChannelPrompt(null);
22466
- setHookPrompt(null);
22467
- setContextPanel(null);
22584
+ own.context(null);
22468
22585
  closeUsagePanel();
22469
- setPicker({
22586
+ own.paint({
22470
22587
  kind: "project",
22471
22588
  title: "Project",
22472
22589
  description: "Opening folder picker\u2026 choose a folder in the dialog window.",
@@ -22482,6 +22599,7 @@ function createProjectPicker({
22482
22599
  title: "Select a project folder",
22483
22600
  initialPath: String(state.cwd || process.cwd() || "")
22484
22601
  }).then((result) => {
22602
+ if (!own.owns()) return;
22485
22603
  if (!result || result.available === false) {
22486
22604
  beginNewProjectManual();
22487
22605
  return;
@@ -22492,7 +22610,7 @@ function createProjectPicker({
22492
22610
  }
22493
22611
  void registerProject(result.path);
22494
22612
  }).catch(() => {
22495
- beginNewProjectManual();
22613
+ if (own.owns()) beginNewProjectManual();
22496
22614
  });
22497
22615
  };
22498
22616
  const registerProject = async (rawPath) => {
@@ -22501,9 +22619,11 @@ function createProjectPicker({
22501
22619
  store.pushNotice("project path is required", "warn");
22502
22620
  return false;
22503
22621
  }
22622
+ const own = surface.claim();
22504
22623
  try {
22505
22624
  const project = await serviceCall("addProject", path2);
22506
22625
  if (project?.name) store.pushNotice(`project added: ${project.name}`, "info");
22626
+ if (!own.owns()) return true;
22507
22627
  await openProjectPicker();
22508
22628
  return true;
22509
22629
  } catch (e) {
@@ -22517,7 +22637,7 @@ function createProjectPicker({
22517
22637
  store.pushNotice("project path is required", "warn");
22518
22638
  return false;
22519
22639
  }
22520
- setPicker(null);
22640
+ surface.claim().close();
22521
22641
  try {
22522
22642
  const resolved = await serviceCall("setCwd", path2, {
22523
22643
  notice: options?.notice !== false,
@@ -22532,11 +22652,10 @@ function createProjectPicker({
22532
22652
  };
22533
22653
  const beginRenameProject = (project) => {
22534
22654
  if (!project?.path) return;
22535
- setPicker(null);
22655
+ const own = surface.claim();
22656
+ own.context(null);
22657
+ own.close();
22536
22658
  setProviderPrompt(null);
22537
- setChannelPrompt(null);
22538
- setHookPrompt(null);
22539
- setContextPanel(null);
22540
22659
  closeUsagePanel();
22541
22660
  setSettingsPrompt({
22542
22661
  kind: "project-rename",
@@ -22547,28 +22666,27 @@ function createProjectPicker({
22547
22666
  });
22548
22667
  };
22549
22668
  const openProjectPicker = async ({ initialEntry = false } = {}) => {
22669
+ const own = surface.claim();
22550
22670
  setProviderPrompt(null);
22551
- setChannelPrompt(null);
22552
- setHookPrompt(null);
22553
22671
  setSettingsPrompt(null);
22554
- setContextPanel(null);
22672
+ own.context(null);
22555
22673
  closeUsagePanel();
22556
22674
  const requestId = /* @__PURE__ */ Symbol("project-picker-request");
22557
- setPicker(buildProjectPickerState({
22675
+ own.paint(buildProjectPickerState({
22558
22676
  initialEntry,
22559
22677
  loading: true,
22560
22678
  requestId
22561
22679
  }));
22562
22680
  try {
22563
22681
  const projects = await serviceCall("listProjects");
22564
- setPicker((current) => current?._projectRequestId === requestId ? buildProjectPickerState({
22682
+ own.paint((current) => current?._projectRequestId === requestId ? buildProjectPickerState({
22565
22683
  initialEntry,
22566
22684
  projects: Array.isArray(projects) ? projects : [],
22567
22685
  requestId
22568
22686
  }) : current);
22569
22687
  return projects;
22570
22688
  } catch (error) {
22571
- setPicker((current) => current?._projectRequestId === requestId ? buildProjectPickerState({ initialEntry, projects: [], requestId }) : current);
22689
+ own.paint((current) => current?._projectRequestId === requestId ? buildProjectPickerState({ initialEntry, projects: [], requestId }) : current);
22572
22690
  store.pushNotice(`project list failed: ${error?.message || error}`, "error");
22573
22691
  return [];
22574
22692
  }
@@ -22681,7 +22799,7 @@ function usePromptHandlers({
22681
22799
  setPastedImages,
22682
22800
  setPastedTexts,
22683
22801
  setPromptDraftOverride,
22684
- setContextPanel,
22802
+ surface,
22685
22803
  // derived / helper values + callbacks
22686
22804
  syncPromptLayoutRows,
22687
22805
  showPromptHint,
@@ -22822,7 +22940,7 @@ function usePromptHandlers({
22822
22940
  return true;
22823
22941
  }
22824
22942
  if (contextPanel) {
22825
- setContextPanel(null);
22943
+ surface.claim().context(null);
22826
22944
  return true;
22827
22945
  }
22828
22946
  if (meta.phase === "clear-arm") {
@@ -22996,7 +23114,9 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
22996
23114
  const [picker, setPickerState] = useState11(null);
22997
23115
  const livePickerRef = useRef15(null);
22998
23116
  const setPicker = useCallback13((next) => {
22999
- livePickerRef.current = typeof next === "function" ? next(livePickerRef.current) : next;
23117
+ const previousPicker = livePickerRef.current;
23118
+ livePickerRef.current = typeof next === "function" ? next(previousPicker) : next;
23119
+ if (shouldSupersedePanelEpoch(previousPicker, livePickerRef.current)) supersedePanelEpoch();
23000
23120
  setPickerState((prev) => {
23001
23121
  const resolved = typeof next === "function" ? next(prev) : next;
23002
23122
  if (resolved && typeof resolved === "object" && pickerOpenedFromEnterRef.current) {
@@ -23016,26 +23136,23 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23016
23136
  livePickerRef.current = picker;
23017
23137
  const [contextPanel, setContextPanel] = useState11(null);
23018
23138
  const [usagePanel, setUsagePanel] = useState11(null);
23019
- const usageRequestRef = useRef15(0);
23139
+ const surfaceRef = useRef15(null);
23140
+ if (!surfaceRef.current) {
23141
+ surfaceRef.current = createPanelSurface({ setPicker, setContextPanel, setUsagePanel });
23142
+ }
23143
+ const surface = surfaceRef.current;
23020
23144
  const settingsHeavyCacheRef = useRef15(null);
23021
- const closeUsagePanel = useCallback13(() => {
23022
- usageRequestRef.current += 1;
23023
- setUsagePanel(null);
23024
- }, []);
23145
+ const settingsRequestRef = useRef15(0);
23146
+ const closeUsagePanel = useCallback13(() => surface.closeUsage(), [surface]);
23025
23147
  const [providerPrompt, setProviderPrompt] = useState11(null);
23026
23148
  const oauthSubmitRef = useRef15(false);
23027
- const [channelPrompt, setChannelPrompt] = useState11(null);
23028
- const [hookPrompt, setHookPrompt] = useState11(null);
23029
23149
  const [settingsPrompt, setSettingsPrompt] = useState11(null);
23030
23150
  const projectPicker = createProjectPicker({
23031
23151
  state,
23032
23152
  store,
23033
- setPicker,
23153
+ surface,
23034
23154
  setProviderPrompt,
23035
- setChannelPrompt,
23036
- setHookPrompt,
23037
23155
  setSettingsPrompt,
23038
- setContextPanel,
23039
23156
  closeUsagePanel,
23040
23157
  projectNameFromPath,
23041
23158
  pickFolder
@@ -23206,12 +23323,9 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23206
23323
  } = createAppPickers({
23207
23324
  state,
23208
23325
  store,
23209
- setPicker,
23326
+ surface,
23210
23327
  setProviderPrompt,
23211
- setChannelPrompt,
23212
- setHookPrompt,
23213
23328
  setSettingsPrompt,
23214
- setContextPanel,
23215
23329
  setOnboardingActive,
23216
23330
  closeUsagePanel,
23217
23331
  oauthSubmitRef,
@@ -23222,6 +23336,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23222
23336
  modelPickerRequestRef,
23223
23337
  onboardingPrefetchSeqRef,
23224
23338
  settingsHeavyCacheRef,
23339
+ settingsRequestRef,
23225
23340
  livePickerRef,
23226
23341
  disabledSkills,
23227
23342
  setDisabledSkills,
@@ -23373,7 +23488,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23373
23488
  const { hasUserMessages, openMessageSelector } = useMessageSelector({
23374
23489
  store,
23375
23490
  state,
23376
- setPicker,
23491
+ surface,
23377
23492
  setPromptDraftOverride,
23378
23493
  syncPromptLayoutRows,
23379
23494
  showPromptHint,
@@ -23397,7 +23512,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23397
23512
  setPastedImages,
23398
23513
  setPastedTexts,
23399
23514
  setPromptDraftOverride,
23400
- setContextPanel,
23515
+ surface,
23401
23516
  syncPromptLayoutRows,
23402
23517
  showPromptHint,
23403
23518
  clearPromptHint,
@@ -23425,7 +23540,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23425
23540
  picker,
23426
23541
  usagePanel,
23427
23542
  contextPanel,
23428
- setContextPanel,
23543
+ surface,
23429
23544
  closeUsagePanel,
23430
23545
  isRawModeSupported,
23431
23546
  resizeState,
@@ -23445,14 +23560,9 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23445
23560
  const { openUsagePanel, openContextPicker } = createUsageContextPanels({
23446
23561
  store,
23447
23562
  state,
23448
- usageRequestRef,
23449
- setPicker,
23563
+ surface,
23450
23564
  setProviderPrompt,
23451
- setChannelPrompt,
23452
- setHookPrompt,
23453
23565
  setSettingsPrompt,
23454
- setContextPanel,
23455
- setUsagePanel,
23456
23566
  closeUsagePanel
23457
23567
  });
23458
23568
  useEffect14(() => {
@@ -23493,17 +23603,12 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23493
23603
  store,
23494
23604
  state,
23495
23605
  providerPrompt,
23496
- channelPrompt,
23497
- hookPrompt,
23498
23606
  settingsPrompt,
23499
23607
  setProviderPrompt,
23500
- setChannelPrompt,
23501
- setHookPrompt,
23502
23608
  setSettingsPrompt,
23503
23609
  oauthSubmitRef,
23504
23610
  clearModelCaches,
23505
23611
  openProviderSetupPicker,
23506
- openHooksPicker,
23507
23612
  openSettingsPicker,
23508
23613
  openProjectPicker,
23509
23614
  openAutoClearPicker,
@@ -23520,7 +23625,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23520
23625
  pastedImagesRef,
23521
23626
  pastedTextsRef
23522
23627
  });
23523
- const activeSlashQuery = providerPrompt || channelPrompt || hookPrompt || settingsPrompt || toolApproval || contextPanel || usagePanel ? null : slashQuery(promptDraft);
23628
+ const activeSlashQuery = providerPrompt || settingsPrompt || toolApproval || contextPanel || usagePanel ? null : slashQuery(promptDraft);
23524
23629
  const slashModeLive = activeSlashQuery !== null && !picker && !toolApproval && !contextPanel && !usagePanel && !exiting && !state.commandBusy;
23525
23630
  const slashCommands = !slashModeLive ? [] : SLASH_COMMANDS.filter((command) => slashCommandMatches(command, activeSlashQuery)).sort(compareSlashCommands);
23526
23631
  const slashPaletteOpen = slashModeLive && slashDismissedFor !== promptDraft;
@@ -23532,8 +23637,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23532
23637
  contextPanel: !!contextPanel,
23533
23638
  usagePanel: !!usagePanel,
23534
23639
  providerPrompt: !!providerPrompt,
23535
- channelPrompt: !!channelPrompt,
23536
- hookPrompt: !!hookPrompt,
23537
23640
  settingsPrompt: !!settingsPrompt
23538
23641
  };
23539
23642
  useEffect14(() => {
@@ -23542,8 +23645,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23542
23645
  const {
23543
23646
  onPromptDraftChange,
23544
23647
  cancelProviderPrompt,
23545
- cancelChannelPrompt,
23546
- cancelHookPrompt,
23547
23648
  cancelSettingsPrompt,
23548
23649
  acceptSlashPalette,
23549
23650
  completeSlashPalette,
@@ -23563,12 +23664,8 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23563
23664
  slashDismissedFor,
23564
23665
  setSlashDismissedFor,
23565
23666
  providerPrompt,
23566
- channelPrompt,
23567
- hookPrompt,
23568
23667
  settingsPrompt,
23569
23668
  setProviderPrompt,
23570
- setChannelPrompt,
23571
- setHookPrompt,
23572
23669
  setSettingsPrompt,
23573
23670
  oauthSubmitRef,
23574
23671
  openProjectPicker,
@@ -23584,8 +23681,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23584
23681
  const { agentRevision, activeToolsSignature, activeTools, statuslineStats } = useTranscriptActivity({ state });
23585
23682
  const layout = computeShellLayout({
23586
23683
  providerPrompt,
23587
- channelPrompt,
23588
- hookPrompt,
23589
23684
  settingsPrompt,
23590
23685
  panelTransitionEpoch,
23591
23686
  panelInkMaskEpoch,
@@ -23701,7 +23796,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23701
23796
  setMeasuredRowsVersion
23702
23797
  });
23703
23798
  const cycleWorkflowFromPrompt = useCallback13(() => {
23704
- if (slashPaletteOpen || toolApproval || picker || settingsPrompt || providerPrompt || channelPrompt || hookPrompt || contextPanel || usagePanel) return true;
23799
+ if (slashPaletteOpen || toolApproval || picker || settingsPrompt || providerPrompt || contextPanel || usagePanel) return true;
23705
23800
  const repeatGuardMs = 300;
23706
23801
  const cycleGuard = workflowTabCycleRef.current;
23707
23802
  const now = Date.now();
@@ -23736,19 +23831,16 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23736
23831
  cycleGuard.lastAt = Date.now();
23737
23832
  });
23738
23833
  return true;
23739
- }, [slashPaletteOpen, toolApproval, picker, settingsPrompt, providerPrompt, channelPrompt, hookPrompt, contextPanel, usagePanel, state.commandBusy, state.workflow, store]);
23834
+ }, [slashPaletteOpen, toolApproval, picker, settingsPrompt, providerPrompt, contextPanel, usagePanel, state.commandBusy, state.workflow, store]);
23740
23835
  return renderAppView({
23741
23836
  ...layout,
23742
23837
  acceptSlashPalette,
23743
23838
  activeSlashQuery,
23744
23839
  activeTools,
23745
23840
  agentRevision,
23746
- cancelChannelPrompt,
23747
- cancelHookPrompt,
23748
23841
  cancelProviderPrompt,
23749
23842
  cancelSettingsPrompt,
23750
23843
  cancelSlashPalette,
23751
- channelPrompt,
23752
23844
  clearPromptHint,
23753
23845
  completeSlashPalette,
23754
23846
  contextPanel,
@@ -23761,7 +23853,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23761
23853
  handlePromptInterrupt,
23762
23854
  handlePromptPaste,
23763
23855
  hasUserMessages,
23764
- hookPrompt,
23765
23856
  initialStatusLine,
23766
23857
  onPromptDraftChange,
23767
23858
  onSubmit,
@@ -23784,7 +23875,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23784
23875
  resizeEpoch,
23785
23876
  resizeState,
23786
23877
  restoreQueuedToPrompt,
23787
- setPicker,
23788
23878
  setSlashIndex,
23789
23879
  setTextEntryLayoutRows,
23790
23880
  settingsPrompt,
@@ -23794,6 +23884,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false, onboardin
23794
23884
  state,
23795
23885
  statuslineStats,
23796
23886
  store,
23887
+ surface,
23797
23888
  toolApproval,
23798
23889
  toolOutputExpanded,
23799
23890
  transcriptMeasureRef,