elanous 0.2.31 → 0.2.32

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 (282) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/{1834-50625904996a8fa8.js → 1834-98b64172bc1efe77.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/69-0a2c8209c6d4a158.js +1 -0
  5. package/apps/pwa/out/_next/static/chunks/8097-9530c03bcc550f02.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/app/approvals/page-504204b58c82c253.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-3535a4a69f1fafaa.js → page-a9717a67c2eecbaf.js} +1 -1
  8. package/apps/pwa/out/_next/static/chunks/app/board/page-5c9ec30aee62dfbf.js +1 -0
  9. package/apps/pwa/out/_next/static/chunks/app/botlab/page-584191533721fa16.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/app/bots/page-73c4b4bb3ac7ab5f.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/app/ceo/{page-5a503541353e60a8.js → page-c0f1ca371f710b06.js} +1 -1
  12. package/apps/pwa/out/_next/static/chunks/app/chat/{page-6025101384e361a5.js → page-46430d45a9e04eac.js} +1 -1
  13. package/apps/pwa/out/_next/static/chunks/app/consult/page-3b2ebf1dc64ff0be.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/app/control/{page-a645f00a06483e9a.js → page-a27b1e5a0d1b308f.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/app/decisions/page-25654b82094f7d22.js +1 -0
  16. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-e9bab7413b028b28.js → page-8ea49a4c6dd2c6e7.js} +1 -1
  17. package/apps/pwa/out/_next/static/chunks/app/editor/page-ce5113aefea0a8d1.js +1 -0
  18. package/apps/pwa/out/_next/static/chunks/app/exec/{page-e547e6ce55f1fb33.js → page-0e5a41fac1c75396.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/field/{page-d27e1b9850fd54bf.js → page-31aaf1ed37c6df9a.js} +1 -1
  20. package/apps/pwa/out/_next/static/chunks/app/inside/page-3dcc1fa411e1f4e0.js +1 -0
  21. package/apps/pwa/out/_next/static/chunks/app/intake/{page-0fec29c7ba01894b.js → page-c69247e7134d329d.js} +1 -1
  22. package/apps/pwa/out/_next/static/chunks/app/{layout-339a07410cd6f36b.js → layout-66dc5cd3a0999abe.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/live/page-26ff7ff651a7217d.js +1 -0
  24. package/apps/pwa/out/_next/static/chunks/app/live-run/page-617b3976981efa96.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/app/loops/{page-2fd93ed8c9f16580.js → page-d256f5d5d9552823.js} +1 -1
  26. package/apps/pwa/out/_next/static/chunks/app/market/{page-9b564dbff0fefc35.js → page-ce8f1907b8a6101c.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-33e182a316263116.js +1 -0
  28. package/apps/pwa/out/_next/static/chunks/app/morning/{page-814ba51385225776.js → page-32866485913d6a04.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/app/{not-found-397d479626e5a459.js → not-found-7607cca9b84950c6.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/observatory/{page-af1bba4e3251b728.js → page-eeab86176b03dc3b.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-3ad3be5e7d3fdce9.js → page-5b93dbae3432b996.js} +1 -1
  32. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-77a6cb90a9cf2b10.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/app/ops/seats/{page-4da93ad35d4a8d28.js → page-f47e768b5b242b5a.js} +1 -1
  34. package/apps/pwa/out/_next/static/chunks/app/outputs/page-eb41aa3367fc2505.js +1 -0
  35. package/apps/pwa/out/_next/static/chunks/app/page-4d13ab0b8a267e3f.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/reflection/page-84dad32ff0fc0831.js +1 -0
  37. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-3a658d5fa6d16a25.js → page-95306f892aa2d0ee.js} +1 -1
  38. package/apps/pwa/out/_next/static/chunks/app/sessions/{page-0157de6e85f8bb6b.js → page-940fb6c217f6b470.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-0a07363b130182a1.js → page-8c66a3b24a745630.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/app/settings/{page-841d73d4ac44ed49.js → page-7b675dfd35c36fc9.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-6f43a3d1146e6377.js → page-8bd0d3cf7665bcfc.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/app/setup/{page-521ee23ac8c0abfa.js → page-c219f2ed171131be.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/app/share/{page-a9992ee285efaa83.js → page-40f8fa21bdae955b.js} +1 -1
  44. package/apps/pwa/out/_next/static/chunks/app/showroom/{page-3d48e85fa89ec04f.js → page-468f8313e4f1fbd9.js} +1 -1
  45. package/apps/pwa/out/_next/static/chunks/app/tasks/page-7bbb8fa353a246c4.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/app/term/page-04d00ae9b0890349.js +1 -0
  47. package/apps/pwa/out/_next/static/chunks/app/today/{page-233c71cd5f68f0d7.js → page-4214b855d9233ea8.js} +1 -1
  48. package/apps/pwa/out/_next/static/chunks/app/trace/{page-70151d78de2f375e.js → page-936752c7aa58762e.js} +1 -1
  49. package/apps/pwa/out/_next/static/chunks/app/vault/{page-dcac33a3e2cb72c0.js → page-ec052ad359df1797.js} +1 -1
  50. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-8305570551091338.js +1 -0
  51. package/apps/pwa/out/_next/static/chunks/app/workflows/{page-0448145ccd5c45c1.js → page-fad650e4793adb65.js} +1 -1
  52. package/apps/pwa/out/_next/static/chunks/app/workspace/page-d90e64743826e1d8.js +1 -0
  53. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-a16bcfd49af86a32.js +1 -0
  54. package/apps/pwa/out/_next/static/css/b5d88eba78a3d7bf.css +1 -0
  55. package/apps/pwa/out/approvals/index.html +1 -1
  56. package/apps/pwa/out/approvals/index.txt +14 -14
  57. package/apps/pwa/out/autopilot/index.html +1 -1
  58. package/apps/pwa/out/autopilot/index.txt +14 -14
  59. package/apps/pwa/out/board/index.html +1 -1
  60. package/apps/pwa/out/board/index.txt +14 -14
  61. package/apps/pwa/out/botlab/index.html +1 -1
  62. package/apps/pwa/out/botlab/index.txt +14 -14
  63. package/apps/pwa/out/bots/index.html +1 -1
  64. package/apps/pwa/out/bots/index.txt +14 -14
  65. package/apps/pwa/out/ceo/index.html +1 -1
  66. package/apps/pwa/out/ceo/index.txt +14 -14
  67. package/apps/pwa/out/chat/index.html +1 -1
  68. package/apps/pwa/out/chat/index.txt +14 -14
  69. package/apps/pwa/out/consult/index.html +1 -1
  70. package/apps/pwa/out/consult/index.txt +14 -14
  71. package/apps/pwa/out/control/index.html +1 -1
  72. package/apps/pwa/out/control/index.txt +14 -14
  73. package/apps/pwa/out/decisions/index.html +1 -1
  74. package/apps/pwa/out/decisions/index.txt +14 -14
  75. package/apps/pwa/out/design-check/index.html +1 -1
  76. package/apps/pwa/out/design-check/index.txt +14 -14
  77. package/apps/pwa/out/editor/index.html +1 -1
  78. package/apps/pwa/out/editor/index.txt +14 -14
  79. package/apps/pwa/out/exec/index.html +1 -1
  80. package/apps/pwa/out/exec/index.txt +14 -14
  81. package/apps/pwa/out/field/index.html +1 -1
  82. package/apps/pwa/out/field/index.txt +14 -14
  83. package/apps/pwa/out/healthz +1 -1
  84. package/apps/pwa/out/index.html +1 -1
  85. package/apps/pwa/out/index.txt +14 -14
  86. package/apps/pwa/out/inside/index.html +1 -1
  87. package/apps/pwa/out/inside/index.txt +14 -14
  88. package/apps/pwa/out/intake/index.html +1 -1
  89. package/apps/pwa/out/intake/index.txt +14 -14
  90. package/apps/pwa/out/live/index.html +1 -1
  91. package/apps/pwa/out/live/index.txt +17 -14
  92. package/apps/pwa/out/live-run/index.html +1 -1
  93. package/apps/pwa/out/live-run/index.txt +14 -14
  94. package/apps/pwa/out/loops/index.html +1 -1
  95. package/apps/pwa/out/loops/index.txt +14 -14
  96. package/apps/pwa/out/market/index.html +1 -1
  97. package/apps/pwa/out/market/index.txt +14 -14
  98. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  99. package/apps/pwa/out/missions/placeholder/index.txt +14 -14
  100. package/apps/pwa/out/morning/index.html +1 -1
  101. package/apps/pwa/out/morning/index.txt +14 -14
  102. package/apps/pwa/out/observatory/index.html +1 -1
  103. package/apps/pwa/out/observatory/index.txt +14 -14
  104. package/apps/pwa/out/ops/checklist/index.html +1 -1
  105. package/apps/pwa/out/ops/checklist/index.txt +14 -14
  106. package/apps/pwa/out/ops/release/index.html +1 -1
  107. package/apps/pwa/out/ops/release/index.txt +14 -14
  108. package/apps/pwa/out/ops/seats/index.html +1 -1
  109. package/apps/pwa/out/ops/seats/index.txt +14 -14
  110. package/apps/pwa/out/outputs/index.html +1 -1
  111. package/apps/pwa/out/outputs/index.txt +14 -14
  112. package/apps/pwa/out/reflection/index.html +1 -1
  113. package/apps/pwa/out/reflection/index.txt +15 -15
  114. package/apps/pwa/out/scheduler/index.html +1 -1
  115. package/apps/pwa/out/scheduler/index.txt +14 -14
  116. package/apps/pwa/out/sessions/index.html +1 -1
  117. package/apps/pwa/out/sessions/index.txt +14 -14
  118. package/apps/pwa/out/settings/devices/index.html +1 -1
  119. package/apps/pwa/out/settings/devices/index.txt +14 -14
  120. package/apps/pwa/out/settings/index.html +1 -1
  121. package/apps/pwa/out/settings/index.txt +14 -14
  122. package/apps/pwa/out/setup/done/index.html +1 -1
  123. package/apps/pwa/out/setup/done/index.txt +14 -14
  124. package/apps/pwa/out/setup/index.html +1 -1
  125. package/apps/pwa/out/setup/index.txt +14 -14
  126. package/apps/pwa/out/share/index.html +1 -1
  127. package/apps/pwa/out/share/index.txt +14 -14
  128. package/apps/pwa/out/showroom/index.html +1 -1
  129. package/apps/pwa/out/showroom/index.txt +14 -14
  130. package/apps/pwa/out/tasks/index.html +1 -1
  131. package/apps/pwa/out/tasks/index.txt +14 -14
  132. package/apps/pwa/out/term/index.html +1 -1
  133. package/apps/pwa/out/term/index.txt +14 -14
  134. package/apps/pwa/out/today/index.html +1 -1
  135. package/apps/pwa/out/today/index.txt +14 -14
  136. package/apps/pwa/out/trace/index.html +1 -1
  137. package/apps/pwa/out/trace/index.txt +14 -14
  138. package/apps/pwa/out/vault/index.html +1 -1
  139. package/apps/pwa/out/vault/index.txt +14 -14
  140. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  141. package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
  142. package/apps/pwa/out/workflows/index.html +1 -1
  143. package/apps/pwa/out/workflows/index.txt +14 -14
  144. package/apps/pwa/out/workspace/index.html +1 -1
  145. package/apps/pwa/out/workspace/index.txt +14 -14
  146. package/apps/pwa/out/worktrees/index.html +1 -1
  147. package/apps/pwa/out/worktrees/index.txt +14 -14
  148. package/graphs/implement-loop.yaml +5 -0
  149. package/package.json +1 -1
  150. package/scripts/ci-typecheck-changed.ts +26 -1
  151. package/scripts/measure-si-task-cpu.ts +143 -0
  152. package/scripts/ratchets/test-interference-patterns.allowlist.txt +0 -2
  153. package/scripts/release-loop/prepare-node.ts +102 -4
  154. package/src/acp/core-turn-bridge.ts +16 -4
  155. package/src/acp/elanous-extensions.ts +3 -0
  156. package/src/acp/server.ts +3 -0
  157. package/src/acp/tool-trace.ts +186 -11
  158. package/src/agent/self-ambient-cache.ts +156 -0
  159. package/src/agent/self-ambient.ts +8 -1
  160. package/src/agent/task-notification.ts +5 -0
  161. package/src/agent-substrate/pr-reviewer.ts +3 -1
  162. package/src/ask-user-question/tool.ts +22 -0
  163. package/src/autopilot/build/llm-conflict-merge.ts +56 -10
  164. package/src/autopilot/pr-manager.ts +23 -5
  165. package/src/capture/frame-state-detect.ts +39 -0
  166. package/src/capture/tui-self-report.ts +134 -6
  167. package/src/chat/index.ts +61 -15
  168. package/src/chat/pickers/modal-runtime.ts +6 -0
  169. package/src/chat/pickers/modals.ts +8 -2
  170. package/src/cli/ask-bare.ts +1 -0
  171. package/src/cli/import-cli.ts +12 -0
  172. package/src/cli/log-event-names.ts +10 -0
  173. package/src/cli/msg-cli.ts +1 -0
  174. package/src/cli/pod-cli.ts +14 -3
  175. package/src/cli/pr-cli.ts +67 -32
  176. package/src/cli/pr-land-base-read.ts +34 -0
  177. package/src/cli/pr-land-heavy-remote.ts +81 -25
  178. package/src/cli/pr-land-overlap-evidence.ts +46 -2
  179. package/src/cli/pr-land-pod-shadow-job.ts +26 -3
  180. package/src/cli/pr-land-refusal.ts +20 -5
  181. package/src/cli/pty-takeover-cli.ts +88 -14
  182. package/src/cli/sim-cli.ts +18 -0
  183. package/src/context-bus/ops-events.ts +6 -2
  184. package/src/core-turn/run-core-turn.ts +1 -0
  185. package/src/core-turn/run-goal-loop.ts +21 -0
  186. package/src/core-turn/types.ts +3 -0
  187. package/src/dashboard/acp-active-model.ts +42 -1
  188. package/src/dashboard/background-jobs-status.ts +66 -0
  189. package/src/dashboard/index.ts +117 -44
  190. package/src/dashboard/input/agent-wake.ts +242 -0
  191. package/src/dashboard/input/chat-main-entry-runtime.ts +5 -0
  192. package/src/dashboard/input/external-input-host.ts +23 -9
  193. package/src/dashboard/input/mouse-wiring.ts +108 -11
  194. package/src/dashboard/log-click-runtime.ts +118 -2
  195. package/src/dashboard/turn-preamble.ts +116 -40
  196. package/src/dashboard/turn-session-layers.ts +4 -2
  197. package/src/dashboard/turn-start-segments.ts +222 -0
  198. package/src/display/prompt-row-owner.ts +146 -0
  199. package/src/display/resize-listener.ts +33 -2
  200. package/src/fold-stack.ts +4 -2
  201. package/src/git-fs/index.ts +263 -36
  202. package/src/harness/gate-reserve.ts +87 -0
  203. package/src/harness/harness-incidents.ts +13 -0
  204. package/src/harness/harness-queue.ts +15 -0
  205. package/src/index.ts +8 -6
  206. package/src/input/external-input-queue.ts +34 -9
  207. package/src/llm/route-decision.ts +36 -0
  208. package/src/llm/tool-loop-steered-rejection.ts +8 -0
  209. package/src/llm-request-shape.ts +209 -0
  210. package/src/llm.ts +166 -267
  211. package/src/loops/orchestrator/tick.ts +24 -2
  212. package/src/maturity/feature-maturity.ts +1 -1
  213. package/src/mss/logging/render-categories.ts +5 -0
  214. package/src/ops/overview.ts +59 -2
  215. package/src/pr-tool/census.ts +19 -4
  216. package/src/pr-tool/inflight-registry.ts +143 -0
  217. package/src/pty-shell/pty-manifest.ts +12 -3
  218. package/src/pty-shell/tui-run-state.ts +34 -3
  219. package/src/seat-loop/traffic-signal.ts +2 -1
  220. package/src/self-dev/ask-launch-flow.ts +13 -0
  221. package/src/self-dev/draft-residue.ts +243 -24
  222. package/src/self-dev/shard-plan.ts +11 -3
  223. package/src/self-dev/shard-run.ts +103 -10
  224. package/src/self-implement/elanous-tui-spawn.ts +14 -0
  225. package/src/self-implement/follow-up-placement.ts +79 -0
  226. package/src/self-implement/gate-artifacts.ts +15 -4
  227. package/src/self-implement/gate-baseline.ts +96 -5
  228. package/src/self-implement/gate-cli.ts +7 -2
  229. package/src/self-implement/gate-remote.ts +26 -1
  230. package/src/self-implement/host-regate.ts +36 -4
  231. package/src/self-implement/orchestrator.ts +101 -11
  232. package/src/self-implement/run-ledger.ts +16 -14
  233. package/src/session-runtime/index.ts +22 -267
  234. package/src/shell-runner/background-surface.ts +15 -5
  235. package/src/skills/tools/agent.ts +39 -6
  236. package/src/skills/tools/list-dir.ts +11 -0
  237. package/src/skills/tools/schedule-wakeup.ts +408 -0
  238. package/src/skills/tools/shell.ts +245 -3
  239. package/src/status/bar.ts +26 -0
  240. package/src/steward/digest-delivery.ts +118 -0
  241. package/src/steward/hold-hygiene.ts +120 -0
  242. package/src/steward/triage.ts +10 -0
  243. package/src/surface/shell-runner-boot.ts +5 -2
  244. package/src/task-agent/task-hand.ts +24 -0
  245. package/src/task-orchestrator/surfaces/pod-command-job.ts +65 -11
  246. package/src/task-orchestrator/surfaces/pod-lease.ts +98 -0
  247. package/src/task-orchestrator/surfaces/pod-ledger-events.ts +1 -1
  248. package/src/task-orchestrator/surfaces/pod-pool.ts +3 -1
  249. package/src/task-orchestrator/surfaces/pod-reuse-cleanup.ts +10 -6
  250. package/src/task-orchestrator/surfaces/pod-warm-worker-pod.ts +525 -0
  251. package/src/task-orchestrator/surfaces/pod-warm-worker-runner.ts +90 -0
  252. package/src/task-orchestrator/surfaces/pod-warm-worker-runtime.ts +156 -2
  253. package/src/task-orchestrator/surfaces/self-implement-pod.ts +7 -5
  254. package/src/tui/chat/execution-badge.ts +5 -1
  255. package/src/tui/input-lag-probe.ts +230 -0
  256. package/src/tui.ts +4 -0
  257. package/src/ux-sim/scenario.ts +255 -0
  258. package/src/version/packed-revision.json +1 -1
  259. package/apps/pwa/out/_next/static/chunks/8097-92f87bd108322f66.js +0 -1
  260. package/apps/pwa/out/_next/static/chunks/app/approvals/page-bf3634a117322df7.js +0 -1
  261. package/apps/pwa/out/_next/static/chunks/app/board/page-b9f51447f757fbf2.js +0 -1
  262. package/apps/pwa/out/_next/static/chunks/app/botlab/page-2ebb8fd59b9461f9.js +0 -1
  263. package/apps/pwa/out/_next/static/chunks/app/bots/page-a2fc4e49a4fa4ba8.js +0 -1
  264. package/apps/pwa/out/_next/static/chunks/app/consult/page-f4b630cc8b5273cd.js +0 -1
  265. package/apps/pwa/out/_next/static/chunks/app/decisions/page-61ac22cbab1ee4ec.js +0 -1
  266. package/apps/pwa/out/_next/static/chunks/app/editor/page-c992eafe028b642e.js +0 -1
  267. package/apps/pwa/out/_next/static/chunks/app/inside/page-805ac2e137b7a121.js +0 -1
  268. package/apps/pwa/out/_next/static/chunks/app/live/page-349f2752d8cd37ad.js +0 -1
  269. package/apps/pwa/out/_next/static/chunks/app/live-run/page-d5c6dcf31c25cecc.js +0 -1
  270. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/page-62f4475d3c38fb9b.js +0 -1
  271. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-f219ccdbc0bf27df.js +0 -1
  272. package/apps/pwa/out/_next/static/chunks/app/outputs/page-456666766e5ce6fc.js +0 -1
  273. package/apps/pwa/out/_next/static/chunks/app/page-7404e377e8adb8c5.js +0 -1
  274. package/apps/pwa/out/_next/static/chunks/app/reflection/page-14456240ed2a36ad.js +0 -1
  275. package/apps/pwa/out/_next/static/chunks/app/tasks/page-d2ced71132fac9b2.js +0 -1
  276. package/apps/pwa/out/_next/static/chunks/app/term/page-f08358bdf251adb9.js +0 -1
  277. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-149dc1caba411bb9.js +0 -1
  278. package/apps/pwa/out/_next/static/chunks/app/workspace/page-9cb0c444903da65d.js +0 -1
  279. package/apps/pwa/out/_next/static/chunks/app/worktrees/page-17e504c396e0e389.js +0 -1
  280. package/apps/pwa/out/_next/static/css/3f5fc6f96e2cf7b2.css +0 -1
  281. /package/apps/pwa/out/_next/static/{LSXfY0u9QtfDbejY0Ukf_ → IVKr3AlRUVLKsw2fh7eXF}/_buildManifest.js +0 -0
  282. /package/apps/pwa/out/_next/static/{LSXfY0u9QtfDbejY0Ukf_ → IVKr3AlRUVLKsw2fh7eXF}/_ssgManifest.js +0 -0
@@ -176,6 +176,7 @@ import {
176
176
  } from '../chat/turn-typeahead.js';
177
177
  import { dispatchStreamingTurnTypeaheadSubmission } from './input/streaming-turn-typeahead.js';
178
178
  import { composeVertical, type LayoutZone } from '../layout/composer.js';
179
+ import { createPromptBandRenderObserver, createPromptRowOwner, renderPromptOwnerHintRow, withPromptRowOwner } from '../display/prompt-row-owner.js';
179
180
  import type { CoreTurnDispatchTool } from '../core-turn/index.js';
180
181
  // streamGrok kept as back-compat shim in chat.ts — not imported here
181
182
  // directly anymore. Dashboard runs every turn through the in-process
@@ -201,6 +202,7 @@ import { startThinking, startPinnedThinking, type ThinkingHandle } from '../thin
201
202
  import { goalLoopIterationThinking } from './goal-loop-thinking.js';
202
203
  import { debug, getAmbientSessionId } from '../debug/log.js';
203
204
  import { startEventLoopStallMonitor, thinkingVerbFromFooter } from './event-loop-stall-monitor.js';
205
+ import { createInputLagProbe, noteInputLagPaint, setInputLagProbe } from '../tui/input-lag-probe.js';
204
206
  import { getPushcutClient } from '../pushcut/client.js';
205
207
  // P2-3 + P4 + P5 — input-core wiring. Aliased on import to dodge the
206
208
  // many existing `resolveInputEvent`-ish names elsewhere in this file.
@@ -434,6 +436,7 @@ import { collectSignals, signalsSummary } from '../tool-hints/signals.js';
434
436
  import { resetProbes } from '../tool-hints/probe.js';
435
437
  import type { HintScope } from '../tool-hints/types.js';
436
438
  import { globalAgentRegistry, type AgentToolCallEvent } from '../agent/registry.js';
439
+ import { createBackgroundJobsStatus } from './background-jobs-status.js';
437
440
  import { SELF_IMPLEMENT_TOOL_NAMES } from '../boot/daemon-tools/self-implement-names.js';
438
441
  import { type FoldMode } from '../log-entry.js';
439
442
  import { renderToolCallEvent, renderToolResultVariants } from '../chat/tool-render/index.js';
@@ -631,7 +634,7 @@ import {
631
634
  } from '../user-config.js';
632
635
  import { streamLLM, anyProviderAvailable, getProviderForConfig, nextReasoningLevel, reasoningLevelLabel, effectiveReasoningLevel, modelSupportsReasoning, type LLMMessage, type LLMToolSpec } from '../llm.js';
633
636
  import { currentRouteDecision, formatRouteDecisionSummary } from '../llm/route-decision.js';
634
- import { resolveDashboardActiveModel } from './acp-active-model.js';
637
+ import { recordDashboardTurnExecution, resolveDashboardActiveModel } from './acp-active-model.js';
635
638
  import { getModelFamily, getModelTier } from '../models/prompts.js';
636
639
  import { buildPromptInjection, getPromptBankStore } from '../prompt-bank/index.js';
637
640
  import { getInputHistoryStore } from '../input-history.js';
@@ -665,7 +668,7 @@ import { registerDashboardPaneArtifactRuntimes } from './pane-artifact-runtime-r
665
668
  import { handleDashboardAttachmentPopupAction } from './attachment-popup-actions.js';
666
669
  import { renderDashboardAttachmentSummary } from './attachment-summary.js';
667
670
  import { openDashboardFolderAttachModal } from './folder-attach-modal-runtime.js';
668
- import { createDashboardLogClickDeps } from './log-click-runtime.js';
671
+ import { createDashboardLogClickDeps, createFoldClickScrollAnchor } from './log-click-runtime.js';
669
672
  import { runDashboardSidebarSessionJoin } from './sidebar-session-join-runtime.js';
670
673
  import {
671
674
  runDashboardAutoRouteCountdown,
@@ -877,7 +880,9 @@ import {
877
880
  getGitStatusView,
878
881
  subscribeGitChanges,
879
882
  refreshDirtyAsync as refreshGitDirtyAsync,
883
+ refreshGitSnapshotAsync,
880
884
  } from '../git-fs/index.js';
885
+ import { refreshSelfAmbientCache } from '../agent/self-ambient-cache.js';
881
886
  import { getPty, listPty, requestPtyTakeover } from '../pty-shell/registry.js';
882
887
  import { listPtyManifestRowsAt } from '../pty-shell/pty-manifest.js';
883
888
  import { ptyManifestTargets } from '../domains/fleet.js';
@@ -1027,6 +1032,7 @@ import { consumeTurnEndInterrupted, handoffTurnTypeaheadAtTurnEnd, releaseTurnTy
1027
1032
  import { abortTurnOnly } from '../turn-abort-scope.js';
1028
1033
  import { consumeInternalTurnYield, createInternalTurnGate, formatInternalTurnBanner, resolveInternalTurnSubmitIntent, type InternalTurnRequest } from './input/internal-turn.js';
1029
1034
  import { createSeatAutowake } from './input/seat-autowake.js';
1035
+ import { createDashboardWakeupScheduler, registerScheduleWakeupHostTool } from '../skills/tools/schedule-wakeup.js';
1030
1036
  import { createAttachmentRowMap } from '../log-pane/attachment-row-map.js';
1031
1037
  import { createAttachmentPopup, type AttachmentPopupAction } from '../log-pane/attachment-popup.js';
1032
1038
  import { findLogMatches, findVisibleLogMatches, type LogSearchResult } from '../log-pane/search.js';
@@ -1147,6 +1153,8 @@ import { agentBatchScratchTitle, renderAgentBatchScratch } from '../display/agen
1147
1153
  import { type ExecutionSurfaceHandle } from '../display/index.js';
1148
1154
  import { AgentSurfaceStore, renderAgentDetail, renderAgentRoster, type AgentSurfaceState } from '../display/agent-surface.js';
1149
1155
  import { globalAgentFlash } from '../display/agent-flash.js';
1156
+ import { globalTaskNotificationQueue } from '../agent/task-notification.js';
1157
+ import { createDashboardAgentWakeNotify, installAgentWake, wrapAgentWakePort } from './input/agent-wake.js';
1150
1158
  import { renderDebugEventDetail, renderDebugEventRows, renderDebugStack, renderPromptInjectionDebug } from '../display/debug-surface.js';
1151
1159
  import { buildDebugCallStack } from '../debug/call-stack.js';
1152
1160
  import { buildAstGrepHostTool } from '../skills/tools/ast-grep.js';
@@ -1307,7 +1315,7 @@ import {
1307
1315
  type SpaceLongPressDetector,
1308
1316
  } from './input/space-longpress-detector.js';
1309
1317
  import { isAllowlistedDictationSurface } from './input/dictation-surface-allowlist.js';
1310
- import { createDashboardExternalInputHost, stopTurnViaEscGate } from './input/external-input-host.js';
1318
+ import { createDashboardExternalInputHost, stopTurnViaEscGate, updateDashboardExternalInputQueueNotice } from './input/external-input-host.js';
1311
1319
  import { registerExternalInputHost } from '../input/external-input-queue.js';
1312
1320
  // H3 #6 follow-up #3 — background sessions render as a distinct sidebar
1313
1321
  // kind with live state badge + tap-to-Join. Dashboard pulls BG records
@@ -1913,8 +1921,11 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
1913
1921
  const dashboardQuitConfirmationState = createQuitConfirmationState();
1914
1922
  const signalQuitConfirmationState = createQuitConfirmationState();
1915
1923
  let disposeDashboardEventLoopMonitor = (): void => {};
1924
+ // TUI-AGENT-IDLE-WAKE — 이 대시보드 «자기» 완료 알림 구독만 푼다(배선 지점에서 채운다).
1925
+ let disposeDashboardAgentWake = (): void => {};
1916
1926
  const closeDashboardTui = (): void => {
1917
1927
  disposeDashboardEventLoopMonitor();
1928
+ try { disposeDashboardAgentWake(); } catch { /* never block exit */ }
1918
1929
  closeTui();
1919
1930
  };
1920
1931
  const exitDashboardTui = (): void => {
@@ -2233,6 +2244,7 @@ export async function showDashboard(opts: ShowDashboardOptions = {}): Promise<Da
2233
2244
  pillRowGetter: () => pillRowGetterForClick?.() ?? null,
2234
2245
  onPillClick: () => onPillClickForClick?.(),
2235
2246
  foldStack,
2247
+ foldClickAnchor,
2236
2248
  });
2237
2249
 
2238
2250
  // Dispatcher for attachment-popup actions (log-pane click → popup
@@ -3392,7 +3404,12 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3392
3404
  getCwd: () => workingDir.cwd,
3393
3405
  notify: (line) => { chatLines.push(C.muted(line)); draw(); },
3394
3406
  });
3395
- const internalTurnYieldPort = seatAutowake.wrapPort(internalTurnGate.port);
3407
+ const internalTurnYieldPort = wrapAgentWakePort(seatAutowake.wrapPort(internalTurnGate.port));
3408
+ // ⭐ H5 자기 예약 깨움(TUI-H5-SCHEDULE-WAKEUP) — 프로세스 안 타이머가 그 시각에 H2 문으로 한 턴을 청한다.
3409
+ // 직전 회차 판정 = 그 예약이 연 내부 턴이 아직 도나. 도구 등록은 아래 host tool 자리(하니스 자식 제외).
3410
+ const wakeupScheduler = createDashboardWakeupScheduler(internalTurnGate, {
3411
+ notify: (line) => { chatLines.push(C.muted(line)); draw(); },
3412
+ });
3396
3413
  // ⭐ `B3` — 큐를 «도는 턴»에 넣으려면 그 턴이 도는 ***ACP 세션 id*** 가 필요하다.
3397
3414
  // ⛔ `attachedSessionId`(대화 세션)와 «다른 축»이다 — 루프는 ACP 세션으로 스코프를 연다.
3398
3415
  // ⚠️ 세션은 이 함수 «뒤»에서 만들어지므로 참조로 둔다(호출 시점엔 채워져 있다).
@@ -3421,6 +3438,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3421
3438
  });
3422
3439
  }
3423
3440
  try { process.stdout.write(paint); } catch { /* fail-soft */ }
3441
+ noteInputLagPaint();
3424
3442
  };
3425
3443
 
3426
3444
  // Use this instead of bare `chatScrollOffset = -1` inside streaming
@@ -3450,9 +3468,17 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3450
3468
  }),
3451
3469
  log: (category, event, data) => debug.log(category, event, data),
3452
3470
  });
3471
+ // ⌨️ TUI-TYPING-LAG-OBS — 키→칠 ms ⊕ 턴 시작 창 루프 지연(`tui.input-lag`). 훅은 tui.ts·chat·turn-preamble.
3472
+ const inputLagProbe = createInputLagProbe({
3473
+ isBusy: () => streamingInFlight,
3474
+ log: (category, event, data) => debug.log(category, event, { ...data }),
3475
+ });
3476
+ setInputLagProbe(inputLagProbe);
3453
3477
  const disposeEventLoopStallMonitorOnBeforeExit = (): void => disposeDashboardEventLoopMonitor();
3454
3478
  disposeDashboardEventLoopMonitor = (): void => {
3455
3479
  disposeEventLoopStallMonitor();
3480
+ setInputLagProbe(null);
3481
+ inputLagProbe.dispose();
3456
3482
  process.removeListener('beforeExit', disposeEventLoopStallMonitorOnBeforeExit);
3457
3483
  };
3458
3484
  process.once('beforeExit', disposeEventLoopStallMonitorOnBeforeExit);
@@ -3461,14 +3487,24 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3461
3487
  // batch status during skill execution, plus static folds already
3462
3488
  // committed to chatLines. The runtime helper owns registration;
3463
3489
  // `f` just toggles the most recent target.
3490
+ // A click toggle keeps the viewport top (#81 — pinning to the tail
3491
+ // moved the clicked header, so the same spot no longer folded back).
3492
+ const foldClickAnchor = createFoldClickScrollAnchor({
3493
+ getScrollOffset: () => chatScrollOffset,
3494
+ setScrollOffset: (offset) => { chatScrollOffset = offset; },
3495
+ maxScroll: () => logScrollMax(computeLogH(termSize().rows)),
3496
+ getFrozenTail: () => logFrozenTailIndex,
3497
+ setFrozenTail: (index) => { logFrozenTailIndex = index; },
3498
+ lineCount: () => chatLines.length,
3499
+ }, () => {
3500
+ // Pin back to tail if the user hadn't scrolled away — expanding
3501
+ // a batch tree adds rows, and losing the bottom anchor is
3502
+ // disorienting when `f` was supposed to reveal more content.
3503
+ chatScrollOffset = -1;
3504
+ });
3464
3505
  const foldStack = new FoldStack({
3465
3506
  chatLines,
3466
- onAfterToggle: () => {
3467
- // Pin back to tail if the user hadn't scrolled away — expanding
3468
- // a batch tree adds rows, and losing the bottom anchor is
3469
- // disorienting when `f` was supposed to reveal more content.
3470
- chatScrollOffset = -1;
3471
- },
3507
+ onAfterToggle: (target, delta) => foldClickAnchor.onAfterToggle(target, delta),
3472
3508
  });
3473
3509
  // The most recent streamed assistant response — kept in both raw and
3474
3510
  // formatted form so Ctrl+Y can copy clean markdown and `r` in log
@@ -3700,7 +3736,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3700
3736
  // boot block via bgSurface.onUpdate; read on every status redraw.
3701
3737
  // Null until the first handle is tracked so we don't render an empty
3702
3738
  // pill on a fresh session.
3703
- let latestShellRollup: { running: number; backgrounded: number } | null = null;
3739
+ let latestShellRollup: { running: number; backgrounded: number; background: number } | null = null;
3740
+ // TUI-BG-JOB-VISIBILITY (#71) — «⧗ 백그라운드 N»(턴을 넘어 사는 셸 일). 관측은 모듈, 여기선 배선만
3741
+ // (깨우기 0 — TUI-AGENT-IDLE-WAKE 몫).
3742
+ const backgroundJobsStatus = createBackgroundJobsStatus();
3704
3743
  // The ACP bridge is created later during dashboard boot. Keep status renders
3705
3744
  // safe before then, and bind this reader once the bridge exists.
3706
3745
  let activeAcpRuntimeModel = (): string | undefined => undefined;
@@ -3740,6 +3779,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3740
3779
  sshLabel: sshStatusLabel,
3741
3780
  host: hostLabel,
3742
3781
  runningAgents: globalAgentRegistry.list().filter((agent) => agent.state === 'running').length,
3782
+ backgroundJobs: backgroundJobsStatus.summary(),
3743
3783
  controller: process.env.ELANOUS_CONTROLLER?.trim() || undefined,
3744
3784
  shellCount: liveShells,
3745
3785
  shellRollup: latestShellRollup ?? undefined,
@@ -3767,7 +3807,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3767
3807
  let drawQueued = false;
3768
3808
  let queuedDrawForce = false;
3769
3809
  let lastDrawDebugAt = 0;
3770
- let repaintPromptAfterRender: (opts?: { force?: boolean }) => void = () => {};
3810
+ const promptRowOwner = createPromptRowOwner({ requestFrame: () => draw() });
3811
+ const observePromptBand = createPromptBandRenderObserver();
3771
3812
  const displayEvents = createDisplayEventBus();
3772
3813
  const recentTerminalMouseIntents: Array<{
3773
3814
  surfaceId: string;
@@ -3924,11 +3965,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
3924
3965
  // and fires onPush/onPop. The modal-surface-adapter (registered
3925
3966
  // below after widgetHost discovery) fans those into the global
3926
3967
  // SurfaceRegistry. Existing pushModal callsites unchanged.
3927
- const identityHooks = composeIdentityHooks({
3928
- afterRender: (request) => {
3929
- try { repaintPromptAfterRender({ force: request.force }); } catch { /* noop */ }
3930
- },
3931
- });
3968
+ const identityHooks = composeIdentityHooks({});
3932
3969
  // U4 Bundle B — layer the workspace host wiring on top of modal
3933
3970
  // identity wiring so popup/dialog/terminal modal mounts
3934
3971
  // automatically project into a host-managed workspace set. This is
@@ -4110,7 +4147,17 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
4110
4147
  // out-of-process modifications (external editor, another PTY,
4111
4148
  // etc.). Throttle inside git-fs prevents back-to-back subprocess
4112
4149
  // spawns when this and a post-Edit refresh overlap.
4150
+ // TUI-TYPING-LAG — keep the turn-preamble caches warm off the event loop (boot ⊕ every tick):
4151
+ // the git snapshot (async subprocesses) and the self-ambient store scan (worker thread). A turn
4152
+ // then serves them from cache instead of rebuilding synchronously on the turn path. Both are
4153
+ // no-ops while the cached value is younger than the threshold; failures are fail-soft.
4154
+ const warmTurnPreambleCaches = (): void => {
4155
+ try { void refreshGitSnapshotAsync(getSessionCwd(), { ifOlderThanMs: 30_000 }); } catch { /* noop */ }
4156
+ try { void refreshSelfAmbientCache({}, { ifOlderThanMs: 25_000 }); } catch { /* noop */ }
4157
+ };
4158
+ warmTurnPreambleCaches();
4113
4159
  const gitDirtyTimer: ReturnType<typeof setInterval> = setInterval(() => {
4160
+ warmTurnPreambleCaches();
4114
4161
  try {
4115
4162
  const before = getGitStatusView(getSessionCwd());
4116
4163
  // TUI-TYPING-LAG — the 5s probe ran `git status` synchronously (130ms+, hundreds under load).
@@ -4236,7 +4283,13 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
4236
4283
  wireShellRunnerSurface,
4237
4284
  createFileCaptureEngine,
4238
4285
  setShellRunnerDeps,
4239
- setLatestShellRollup: (rollup) => { latestShellRollup = rollup; },
4286
+ setLatestShellRollup: (rollup) => {
4287
+ latestShellRollup = rollup;
4288
+ // 유휴 중 백그라운드가 끝나도 상태줄이 고쳐지도록 — 수가 바뀔 때만 다시 그린다.
4289
+ if (backgroundJobsStatus.noteRollup(rollup)) {
4290
+ try { draw(); } catch { /* TUI torn down */ }
4291
+ }
4292
+ },
4240
4293
  });
4241
4294
  }
4242
4295
  const { setShellApprover } = await import('../shell-primitive/index.js');
@@ -9974,6 +10027,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
9974
10027
  // kept alive per cwd; reaped on 10-min idle. See
9975
10028
  // 내부 문서 `CAPABILITIES-lsp` for the op surface.
9976
10029
  pluginHost.registerHostTool(buildLspHostTool());
10030
+ // H5 — 이 TUI 로 돌아오는 자기 예약. 하니스 자식(ELANOUS_HARNESS_ROLE 있음)은 무인 런이라 싣지 않는다.
10031
+ registerScheduleWakeupHostTool(pluginHost, wakeupScheduler);
9977
10032
  pluginHost.registerHostTool({
9978
10033
  name: 'view_getConfig',
9979
10034
  description: 'Return dashboard view configuration: native and custom views, order, enabled state, shortcuts, baseView, pane rows, ratios, primary pane, and active view.',
@@ -11301,6 +11356,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
11301
11356
  // actually scrolled up. If something else (streaming, slash reply)
11302
11357
  // pulls the offset back to -1 (tail), the freeze is no-op'd so the
11303
11358
  // user sees full content at tail regardless of stale index state.
11359
+ foldClickAnchor.reconcile();
11304
11360
  const logProjection = buildDashboardLogProjection({
11305
11361
  chatScrollOffset,
11306
11362
  logFrozenTailIndex,
@@ -11361,7 +11417,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
11361
11417
  height: 1,
11362
11418
  render: (_h, c) => [suppressPromptArea ? ' '.repeat(c) : hLine(c)],
11363
11419
  });
11364
- const inputPromptZone = buildDashboardTurnTypeaheadPromptZone({
11420
+ const inputPromptZone = withPromptRowOwner(buildDashboardTurnTypeaheadPromptZone({
11365
11421
  frame: promptFrame,
11366
11422
  height: promptFrame.inputHeight,
11367
11423
  placeholder: C.muted('\u276f '),
@@ -11371,7 +11427,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
11371
11427
  width: totalW,
11372
11428
  suppressPromptArea,
11373
11429
  onPaint: paint => { promptCaret = paint.caret; },
11374
- });
11430
+ }), promptRowOwner, { suppressPromptArea, onCaret: (caret) => { promptCaret = caret; }, observe: observePromptBand });
11375
11431
  zones.push(observeDashboardTurnTypeaheadPromptZone(inputPromptZone, {
11376
11432
  promptBottomRow: promptFrame.promptBottomRow,
11377
11433
  state: turnTypeaheadRef.state,
@@ -11383,7 +11439,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
11383
11439
  });
11384
11440
 
11385
11441
  // Essential bottom area: status line only; no dock row.
11386
- zones.push({ id: 'status-gap-top', height: 1, render: () => [''] });
11442
+ zones.push({ id: 'status-gap-top', height: 1, render: () => [renderPromptOwnerHintRow(promptRowOwner, { suppressPromptArea })] });
11387
11443
  zones.push({
11388
11444
  id: 'status',
11389
11445
  height: 1,
@@ -11604,11 +11660,10 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
11604
11660
  if (debug.enabled) {
11605
11661
  debug.log('dashboard.draw', 'flush-microtask', {
11606
11662
  force,
11607
- promptRepainted: true,
11663
+ promptRepainted: false,
11608
11664
  });
11609
11665
  }
11610
11666
  drawNow({ force });
11611
- try { repaintPromptAfterRender({ force }); } catch { /* noop */ }
11612
11667
  });
11613
11668
  };
11614
11669
 
@@ -12411,18 +12466,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
12411
12466
  submit?: (request?: string | TextInputExternalSubmitRequest) => void;
12412
12467
  getBufferText?: () => string;
12413
12468
  } = { repaint: () => {} };
12414
- repaintPromptAfterRender = () => {
12415
- if (shouldSuppressDashboardBottomArea()) {
12416
- display.setCursor(null);
12417
- return;
12418
- }
12419
- promptCtl.repaint();
12420
- };
12421
- // V3 note: repaintPromptAfterRender receives {force} from the
12422
- // coordinator hook but promptCtl.repaint() has no diff state of its
12423
- // own — the main render's force=true already did eraseDown before
12424
- // this runs, so prompt rows are clean. Forwarding force is a no-op
12425
- // today but the signature is there for future direct-paint callers.
12426
12469
 
12427
12470
  // Terminal resize wiring — CAPABILITIES-display.md §1.3 defines the
12428
12471
  // coordinator entry triplet as "readKey / mouse / resize" but the
@@ -12431,14 +12474,36 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
12431
12474
  // resize to a forced dashboard redraw plus the prompt repaint hook;
12432
12475
  // the hook is a no-op while input is idle so the call is always
12433
12476
  // safe. Dispose on process exit to keep the listener set clean.
12434
- const disposeResizeListener = installResizeListener({ draw: (opts) => draw(opts), promptCtl });
12477
+ // TUI-PICKER-RESIZE-SHRINK (#76) — the forced coordinator frame
12478
+ // re-emits open overlays (slash picker) AFTER the prompt chrome, so
12479
+ // the divider repaint cannot erase the picker's bottom border.
12480
+ const disposeResizeListener = installResizeListener({
12481
+ draw: (opts) => draw(opts),
12482
+ promptCtl,
12483
+ requestOverlayFrame: () => display.requestRender({ force: true }),
12484
+ });
12435
12485
  process.on('exit', disposeResizeListener);
12436
12486
  // 외부 주입(`pty text`)을 사용자 타이핑과 섞지 않고 별도 대기열로 — 결함 #6(10-14).
12487
+ let externalInputQueueNotice: string | null = null;
12488
+ const setExternalInputQueueNotice = (line: string | null): void => {
12489
+ const changed = updateDashboardExternalInputQueueNotice(
12490
+ chatLines,
12491
+ externalInputQueueNotice,
12492
+ line,
12493
+ (notice) => C.muted(` ${notice}`),
12494
+ );
12495
+ externalInputQueueNotice = line;
12496
+ if (changed) {
12497
+ chatScrollOffset = -1;
12498
+ draw();
12499
+ }
12500
+ };
12437
12501
  const disposeExternalInputHost = registerExternalInputHost(createDashboardExternalInputHost({
12438
12502
  isTurnActive: () => streamingInFlight,
12439
12503
  getTurnStop: () => currentTurnExternalStop,
12440
12504
  promptCtl,
12441
12505
  pushNotice: (line) => { chatLines.push(C.muted(` ${line}`)); chatScrollOffset = -1; draw(); },
12506
+ setQueueNotice: setExternalInputQueueNotice,
12442
12507
  }));
12443
12508
  process.on('exit', disposeExternalInputHost);
12444
12509
 
@@ -13034,6 +13099,17 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
13034
13099
  try { draw(); } catch { /* TUI torn down */ }
13035
13100
  });
13036
13101
  process.once('beforeExit', () => agentDoneRedraw.dispose());
13102
+ // ⭐ TUI-AGENT-IDLE-WAKE — 배경 자식(⊕ RunShell bg) 완료 큐의 «유일한» 구독(onEnqueue 구독 0 → 1).
13103
+ // 채팅 한 줄 «✓ 위임 끝: <이름> — 다음 턴에 결과» · 결과는 다음 턴 preamble 이 싣는다.
13104
+ // ⛔ 입력칸·injectKey·pty 주입 0(대표 비침투). dedupe·수명은 모듈, 여기선 배선만.
13105
+ const agentWake = installAgentWake({
13106
+ subscribe: (listener) => globalTaskNotificationQueue.onEnqueue(listener),
13107
+ // 그리기 실패는 삼키지 않는다 — 모듈이 잡아 notified{shown:false} 로 남긴다.
13108
+ notify: createDashboardAgentWakeNotify((line) => { chatLines.push(C.muted(line)); }, () => draw()),
13109
+ // 조각 2 — 자리 TUI ∧ 유휴면 H2 문으로 다음 턴(origin child-complete) · 판정은 모듈.
13110
+ openTurn: { startTurnIfIdle: (text, opts) => internalTurnGate.startTurnIfIdle(text, opts), getCwd: () => workingDir.cwd, isPending: (taskId) => globalTaskNotificationQueue.has(taskId) },
13111
+ });
13112
+ disposeDashboardAgentWake = () => agentWake.dispose();
13037
13113
 
13038
13114
  // PLAN-chat-hud-multi-surface-port-2026-05-13 §4 M5 — 1Hz ticker
13039
13115
  // that pushes the current token-gauge + variant values onto the
@@ -14766,10 +14842,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
14766
14842
  userText,
14767
14843
  hostTools: pluginHost.hostLLMTools(),
14768
14844
  runtimeTools: runtime.listToolRuntimes('tui'),
14769
- pluginTools: pluginHost.activePluginLLMTools(),
14770
14845
  optionalTools: acpTurnRef.optionalSpecs,
14771
14846
  surface: acpTurnRef.turnProfile?.surface,
14772
- rich: false,
14773
14847
  })
14774
14848
  : [];
14775
14849
  return [
@@ -14785,7 +14859,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
14785
14859
  // codex-only behavioral addendum (fix L-1) inside the
14786
14860
  // universal preamble.
14787
14861
  modelFamily: getModelFamily(inspectActiveProvider().model),
14788
- rich: false,
14789
14862
  enabledTools: tools.map(t => t.name),
14790
14863
  seatBoot: true,
14791
14864
  }),
@@ -14798,10 +14871,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
14798
14871
  userText,
14799
14872
  hostTools: pluginHost.hostLLMTools(),
14800
14873
  runtimeTools: runtime.listToolRuntimes('tui'),
14801
- pluginTools: pluginHost.activePluginLLMTools(),
14802
14874
  optionalTools: acpTurnRef.optionalSpecs,
14803
14875
  surface: acpTurnRef.turnProfile?.surface,
14804
- rich: false,
14805
14876
  });
14806
14877
  // ⭐ Remember this turn's catalog so a spawned sub-agent can inherit it.
14807
14878
  //
@@ -16192,6 +16263,7 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
16192
16263
  // C-d-1 — 하단 슬롯 결정 뷰 활성 시 composer 페인트 정지(단일 소유자).
16193
16264
  shouldPaint: () => !shouldSuppressDashboardBottomArea() && !bottomSlotModalActive(),
16194
16265
  promptCtl,
16266
+ promptRowOwner,
16195
16267
  setInputLines: (n) => dashboardState.setInputLines(n),
16196
16268
  redraw: draw,
16197
16269
  dispatchGlobalAction: runChatMainGlobalAction,
@@ -18367,10 +18439,8 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
18367
18439
  userText: args.userText,
18368
18440
  hostTools: pluginHost.hostLLMTools(),
18369
18441
  runtimeTools: runtime.listToolRuntimes('tui'),
18370
- pluginTools: pluginHost.activePluginLLMTools(),
18371
18442
  optionalTools: acpTurnRef.optionalSpecs,
18372
18443
  surface: acpTurnRef.turnProfile?.surface,
18373
- rich: false,
18374
18444
  })
18375
18445
  : [];
18376
18446
  return [
@@ -18380,7 +18450,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
18380
18450
  cwd: args.cwd,
18381
18451
  turnProfile: args.turnProfile as SessionTurnProfile,
18382
18452
  userConfig: args.userConfig,
18383
- rich: false,
18384
18453
  enabledTools: tools.map(t => t.name),
18385
18454
  seatBoot: true,
18386
18455
  }),
@@ -18505,6 +18574,9 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
18505
18574
  },
18506
18575
  runTurnUsageRuntime: (usage) => {
18507
18576
  latestTurnUsage = usage as import('../prompt-cache/types.js').LLMUsage;
18577
+ // 이번 턴의 «실제» 공급자·모델(폴백이면 넘어간 쪽) — 완료 배지가 «A → B» 로 보인다(TUI-MODEL-BADGE-ACTUAL).
18578
+ // 원격 데몬 세션은 적지 않는다(결정이 데몬 쪽 · 후속 칸 TUI-MODEL-BADGE-REMOTE).
18579
+ recordDashboardTurnExecution(usage as { model?: string; routeProvider?: string }, { remote: daemonAttached });
18508
18580
  runDashboardTurnUsageRuntime({
18509
18581
  // The plain-turn pipeline threads usage as `unknown` for
18510
18582
  // decoupling; at this consumer it is the concrete LLM usage
@@ -18842,5 +18914,6 @@ Mode- and sync-specific instructions are injected per-turn when relevant — do
18842
18914
  } finally {
18843
18915
  setSelfImplementSoftStopSpaceObserver(null);
18844
18916
  if (tuiSeatAskTimer) clearInterval(tuiSeatAskTimer);
18917
+ wakeupScheduler.dispose();
18845
18918
  }
18846
18919
  }