@bastani/atomic 0.8.28-alpha.1 → 0.8.28-alpha.3

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 (428) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +120 -118
  3. package/dist/builtin/intercom/package.json +1 -1
  4. package/dist/builtin/mcp/package.json +1 -1
  5. package/dist/builtin/subagents/package.json +1 -1
  6. package/dist/builtin/web-access/package.json +1 -1
  7. package/dist/builtin/workflows/CHANGELOG.md +26 -0
  8. package/dist/builtin/workflows/README.md +1 -1
  9. package/dist/builtin/workflows/builtin/open-claude-design.ts +150 -13
  10. package/dist/builtin/workflows/package.json +1 -1
  11. package/dist/builtin/workflows/src/authoring.d.ts +5 -2
  12. package/dist/builtin/workflows/src/extension/dispatcher.ts +2 -0
  13. package/dist/builtin/workflows/src/extension/index.ts +8 -0
  14. package/dist/builtin/workflows/src/extension/render-result.ts +5 -2
  15. package/dist/builtin/workflows/src/extension/workflow-schema.ts +18 -0
  16. package/dist/builtin/workflows/src/runs/background/status.ts +4 -0
  17. package/dist/builtin/workflows/src/runs/foreground/executor.ts +1251 -110
  18. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +34 -10
  19. package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +10 -2
  20. package/dist/builtin/workflows/src/shared/persistence-restore.ts +28 -9
  21. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +9 -3
  22. package/dist/builtin/workflows/src/shared/store-types.ts +10 -3
  23. package/dist/builtin/workflows/src/shared/store.ts +29 -7
  24. package/dist/builtin/workflows/src/shared/types.ts +12 -10
  25. package/dist/builtin/workflows/src/tui/chat-surface.ts +32 -33
  26. package/dist/builtin/workflows/src/tui/run-detail.ts +23 -4
  27. package/dist/builtin/workflows/src/tui/status-helpers.ts +4 -0
  28. package/dist/builtin/workflows/src/tui/status-list.ts +47 -3
  29. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +1 -1
  30. package/dist/builtin/workflows/src/tui/widget.ts +12 -3
  31. package/dist/builtin/workflows/src/workflows/define-workflow.ts +3 -3
  32. package/dist/cli/args.d.ts +4 -0
  33. package/dist/cli/args.d.ts.map +1 -1
  34. package/dist/cli/args.js +35 -0
  35. package/dist/cli/args.js.map +1 -1
  36. package/dist/cli/project-trust.d.ts +10 -0
  37. package/dist/cli/project-trust.d.ts.map +1 -0
  38. package/dist/cli/project-trust.js +36 -0
  39. package/dist/cli/project-trust.js.map +1 -0
  40. package/dist/cli/startup-ui.d.ts +7 -0
  41. package/dist/cli/startup-ui.d.ts.map +1 -0
  42. package/dist/cli/startup-ui.js +57 -0
  43. package/dist/cli/startup-ui.js.map +1 -0
  44. package/dist/config.d.ts.map +1 -1
  45. package/dist/config.js +24 -3
  46. package/dist/config.js.map +1 -1
  47. package/dist/core/agent-session-runtime.d.ts +3 -1
  48. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  49. package/dist/core/agent-session-runtime.js +1 -0
  50. package/dist/core/agent-session-runtime.js.map +1 -1
  51. package/dist/core/agent-session-services.d.ts +3 -1
  52. package/dist/core/agent-session-services.d.ts.map +1 -1
  53. package/dist/core/agent-session-services.js +3 -2
  54. package/dist/core/agent-session-services.js.map +1 -1
  55. package/dist/core/agent-session.d.ts +9 -1
  56. package/dist/core/agent-session.d.ts.map +1 -1
  57. package/dist/core/agent-session.js +70 -21
  58. package/dist/core/agent-session.js.map +1 -1
  59. package/dist/core/auth-storage.d.ts.map +1 -1
  60. package/dist/core/auth-storage.js +4 -3
  61. package/dist/core/auth-storage.js.map +1 -1
  62. package/dist/core/compaction/branch-summarization.d.ts +3 -1
  63. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  64. package/dist/core/compaction/branch-summarization.js +9 -3
  65. package/dist/core/compaction/branch-summarization.js.map +1 -1
  66. package/dist/core/compaction/compaction.d.ts.map +1 -1
  67. package/dist/core/compaction/compaction.js +18 -24
  68. package/dist/core/compaction/compaction.js.map +1 -1
  69. package/dist/core/compaction/utils.d.ts +1 -1
  70. package/dist/core/compaction/utils.d.ts.map +1 -1
  71. package/dist/core/compaction/utils.js +1 -1
  72. package/dist/core/compaction/utils.js.map +1 -1
  73. package/dist/core/experimental.d.ts +2 -0
  74. package/dist/core/experimental.d.ts.map +1 -0
  75. package/dist/core/experimental.js +5 -0
  76. package/dist/core/experimental.js.map +1 -0
  77. package/dist/core/export-html/template.js +19 -6
  78. package/dist/core/extensions/index.d.ts +1 -1
  79. package/dist/core/extensions/index.d.ts.map +1 -1
  80. package/dist/core/extensions/index.js.map +1 -1
  81. package/dist/core/extensions/loader.d.ts +1 -1
  82. package/dist/core/extensions/loader.d.ts.map +1 -1
  83. package/dist/core/extensions/loader.js +6 -4
  84. package/dist/core/extensions/loader.js.map +1 -1
  85. package/dist/core/extensions/runner.d.ts +11 -4
  86. package/dist/core/extensions/runner.d.ts.map +1 -1
  87. package/dist/core/extensions/runner.js +53 -3
  88. package/dist/core/extensions/runner.js.map +1 -1
  89. package/dist/core/extensions/types.d.ts +34 -4
  90. package/dist/core/extensions/types.d.ts.map +1 -1
  91. package/dist/core/extensions/types.js.map +1 -1
  92. package/dist/core/footer-data-provider.d.ts +2 -0
  93. package/dist/core/footer-data-provider.d.ts.map +1 -1
  94. package/dist/core/footer-data-provider.js +27 -1
  95. package/dist/core/footer-data-provider.js.map +1 -1
  96. package/dist/core/index.d.ts +2 -0
  97. package/dist/core/index.d.ts.map +1 -1
  98. package/dist/core/index.js +2 -0
  99. package/dist/core/index.js.map +1 -1
  100. package/dist/core/model-registry.d.ts.map +1 -1
  101. package/dist/core/model-registry.js +64 -7
  102. package/dist/core/model-registry.js.map +1 -1
  103. package/dist/core/model-resolver.d.ts.map +1 -1
  104. package/dist/core/model-resolver.js +1 -0
  105. package/dist/core/model-resolver.js.map +1 -1
  106. package/dist/core/output-guard.d.ts +1 -0
  107. package/dist/core/output-guard.d.ts.map +1 -1
  108. package/dist/core/output-guard.js +52 -22
  109. package/dist/core/output-guard.js.map +1 -1
  110. package/dist/core/package-manager.d.ts +1 -0
  111. package/dist/core/package-manager.d.ts.map +1 -1
  112. package/dist/core/package-manager.js +20 -8
  113. package/dist/core/package-manager.js.map +1 -1
  114. package/dist/core/project-trust.d.ts +15 -0
  115. package/dist/core/project-trust.d.ts.map +1 -0
  116. package/dist/core/project-trust.js +58 -0
  117. package/dist/core/project-trust.js.map +1 -0
  118. package/dist/core/prompt-templates.d.ts +5 -4
  119. package/dist/core/prompt-templates.d.ts.map +1 -1
  120. package/dist/core/prompt-templates.js +30 -29
  121. package/dist/core/prompt-templates.js.map +1 -1
  122. package/dist/core/provider-attribution.d.ts +4 -0
  123. package/dist/core/provider-attribution.d.ts.map +1 -0
  124. package/dist/core/provider-attribution.js +73 -0
  125. package/dist/core/provider-attribution.js.map +1 -0
  126. package/dist/core/provider-display-names.d.ts.map +1 -1
  127. package/dist/core/provider-display-names.js +3 -0
  128. package/dist/core/provider-display-names.js.map +1 -1
  129. package/dist/core/resolve-config-value.d.ts +9 -1
  130. package/dist/core/resolve-config-value.d.ts.map +1 -1
  131. package/dist/core/resolve-config-value.js +134 -11
  132. package/dist/core/resolve-config-value.js.map +1 -1
  133. package/dist/core/resource-loader.d.ts +12 -2
  134. package/dist/core/resource-loader.d.ts.map +1 -1
  135. package/dist/core/resource-loader.js +108 -18
  136. package/dist/core/resource-loader.js.map +1 -1
  137. package/dist/core/sdk.d.ts +4 -2
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +13 -42
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts +6 -7
  142. package/dist/core/session-manager.d.ts.map +1 -1
  143. package/dist/core/session-manager.js +99 -35
  144. package/dist/core/session-manager.js.map +1 -1
  145. package/dist/core/settings-manager.d.ts +15 -2
  146. package/dist/core/settings-manager.d.ts.map +1 -1
  147. package/dist/core/settings-manager.js +69 -10
  148. package/dist/core/settings-manager.js.map +1 -1
  149. package/dist/core/slash-commands.d.ts.map +1 -1
  150. package/dist/core/slash-commands.js +1 -0
  151. package/dist/core/slash-commands.js.map +1 -1
  152. package/dist/core/system-prompt.d.ts.map +1 -1
  153. package/dist/core/system-prompt.js +0 -3
  154. package/dist/core/system-prompt.js.map +1 -1
  155. package/dist/core/tools/ask-user-question/state/inline-input.d.ts +28 -0
  156. package/dist/core/tools/ask-user-question/state/inline-input.d.ts.map +1 -0
  157. package/dist/core/tools/ask-user-question/state/inline-input.js +56 -0
  158. package/dist/core/tools/ask-user-question/state/inline-input.js.map +1 -0
  159. package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
  160. package/dist/core/tools/ask-user-question/state/key-router.js +30 -4
  161. package/dist/core/tools/ask-user-question/state/key-router.js.map +1 -1
  162. package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
  163. package/dist/core/tools/ask-user-question/state/questionnaire-session.js +9 -8
  164. package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
  165. package/dist/core/tools/ask-user-question/state/row-intent.d.ts +3 -2
  166. package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
  167. package/dist/core/tools/ask-user-question/state/row-intent.js +1 -1
  168. package/dist/core/tools/ask-user-question/state/row-intent.js.map +1 -1
  169. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts +2 -0
  170. package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
  171. package/dist/core/tools/ask-user-question/state/selectors/contract.js.map +1 -1
  172. package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
  173. package/dist/core/tools/ask-user-question/state/selectors/projections.js +2 -0
  174. package/dist/core/tools/ask-user-question/state/selectors/projections.js.map +1 -1
  175. package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
  176. package/dist/core/tools/ask-user-question/state/state-reducer.js +36 -24
  177. package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
  178. package/dist/core/tools/ask-user-question/state/state.d.ts +8 -0
  179. package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
  180. package/dist/core/tools/ask-user-question/state/state.js.map +1 -1
  181. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts +6 -0
  182. package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
  183. package/dist/core/tools/ask-user-question/tool/format-answer.js +19 -1
  184. package/dist/core/tools/ask-user-question/tool/format-answer.js.map +1 -1
  185. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts +3 -2
  186. package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
  187. package/dist/core/tools/ask-user-question/tool/response-envelope.js +15 -3
  188. package/dist/core/tools/ask-user-question/tool/response-envelope.js.map +1 -1
  189. package/dist/core/tools/ask-user-question/tool/types.d.ts +2 -1
  190. package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
  191. package/dist/core/tools/ask-user-question/tool/types.js.map +1 -1
  192. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts +5 -2
  193. package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
  194. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +2 -0
  195. package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
  196. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +1 -0
  197. package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
  198. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +2 -1
  199. package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
  200. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts +3 -3
  201. package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
  202. package/dist/core/tools/ask-user-question/view/props-adapter.js +11 -4
  203. package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
  204. package/dist/core/tools/bash-policy.d.ts +62 -0
  205. package/dist/core/tools/bash-policy.d.ts.map +1 -0
  206. package/dist/core/tools/bash-policy.js +1069 -0
  207. package/dist/core/tools/bash-policy.js.map +1 -0
  208. package/dist/core/tools/bash.d.ts +5 -0
  209. package/dist/core/tools/bash.d.ts.map +1 -1
  210. package/dist/core/tools/bash.js +9 -1
  211. package/dist/core/tools/bash.js.map +1 -1
  212. package/dist/core/tools/edit.d.ts.map +1 -1
  213. package/dist/core/tools/edit.js +7 -10
  214. package/dist/core/tools/edit.js.map +1 -1
  215. package/dist/core/tools/find.d.ts.map +1 -1
  216. package/dist/core/tools/find.js +1 -1
  217. package/dist/core/tools/find.js.map +1 -1
  218. package/dist/core/tools/grep.d.ts.map +1 -1
  219. package/dist/core/tools/grep.js +1 -1
  220. package/dist/core/tools/grep.js.map +1 -1
  221. package/dist/core/tools/index.d.ts +1 -0
  222. package/dist/core/tools/index.d.ts.map +1 -1
  223. package/dist/core/tools/index.js +1 -0
  224. package/dist/core/tools/index.js.map +1 -1
  225. package/dist/core/tools/ls.d.ts.map +1 -1
  226. package/dist/core/tools/ls.js +1 -1
  227. package/dist/core/tools/ls.js.map +1 -1
  228. package/dist/core/tools/oversized-tool-result.d.ts +53 -0
  229. package/dist/core/tools/oversized-tool-result.d.ts.map +1 -0
  230. package/dist/core/tools/oversized-tool-result.js +206 -0
  231. package/dist/core/tools/oversized-tool-result.js.map +1 -0
  232. package/dist/core/tools/read.d.ts +12 -0
  233. package/dist/core/tools/read.d.ts.map +1 -1
  234. package/dist/core/tools/read.js +99 -34
  235. package/dist/core/tools/read.js.map +1 -1
  236. package/dist/core/tools/render-utils.d.ts +6 -0
  237. package/dist/core/tools/render-utils.d.ts.map +1 -1
  238. package/dist/core/tools/render-utils.js +17 -1
  239. package/dist/core/tools/render-utils.js.map +1 -1
  240. package/dist/core/tools/tool-definition-wrapper.d.ts +6 -0
  241. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  242. package/dist/core/tools/tool-definition-wrapper.js +2 -0
  243. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  244. package/dist/core/tools/tool-limits.d.ts +25 -0
  245. package/dist/core/tools/tool-limits.d.ts.map +1 -0
  246. package/dist/core/tools/tool-limits.js +25 -0
  247. package/dist/core/tools/tool-limits.js.map +1 -0
  248. package/dist/core/tools/write.d.ts.map +1 -1
  249. package/dist/core/tools/write.js +1 -1
  250. package/dist/core/tools/write.js.map +1 -1
  251. package/dist/core/trust-manager.d.ts +31 -0
  252. package/dist/core/trust-manager.d.ts.map +1 -0
  253. package/dist/core/trust-manager.js +196 -0
  254. package/dist/core/trust-manager.js.map +1 -0
  255. package/dist/index.d.ts +11 -6
  256. package/dist/index.d.ts.map +1 -1
  257. package/dist/index.js +6 -2
  258. package/dist/index.js.map +1 -1
  259. package/dist/main.d.ts.map +1 -1
  260. package/dist/main.js +142 -30
  261. package/dist/main.js.map +1 -1
  262. package/dist/migrations.d.ts +3 -1
  263. package/dist/migrations.d.ts.map +1 -1
  264. package/dist/migrations.js +325 -7
  265. package/dist/migrations.js.map +1 -1
  266. package/dist/modes/index.d.ts +1 -1
  267. package/dist/modes/index.d.ts.map +1 -1
  268. package/dist/modes/index.js.map +1 -1
  269. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  270. package/dist/modes/interactive/components/bash-execution.js +2 -2
  271. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  272. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  273. package/dist/modes/interactive/components/footer.js +6 -0
  274. package/dist/modes/interactive/components/footer.js.map +1 -1
  275. package/dist/modes/interactive/components/index.d.ts +1 -0
  276. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  277. package/dist/modes/interactive/components/index.js +1 -0
  278. package/dist/modes/interactive/components/index.js.map +1 -1
  279. package/dist/modes/interactive/components/login-dialog.d.ts +1 -1
  280. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/login-dialog.js +9 -16
  282. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  283. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  284. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  285. package/dist/modes/interactive/components/settings-selector.js +20 -0
  286. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  287. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  288. package/dist/modes/interactive/components/tool-execution.js +22 -0
  289. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  290. package/dist/modes/interactive/components/trust-selector.d.ts +23 -0
  291. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -0
  292. package/dist/modes/interactive/components/trust-selector.js +85 -0
  293. package/dist/modes/interactive/components/trust-selector.js.map +1 -0
  294. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  295. package/dist/modes/interactive/components/user-message.js +1 -1
  296. package/dist/modes/interactive/components/user-message.js.map +1 -1
  297. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  298. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  299. package/dist/modes/interactive/interactive-mode.js +130 -9
  300. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  301. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  302. package/dist/modes/interactive/theme/theme.js +10 -0
  303. package/dist/modes/interactive/theme/theme.js.map +1 -1
  304. package/dist/modes/print-mode.d.ts.map +1 -1
  305. package/dist/modes/print-mode.js +1 -0
  306. package/dist/modes/print-mode.js.map +1 -1
  307. package/dist/modes/rpc/rpc-client.d.ts +3 -0
  308. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  309. package/dist/modes/rpc/rpc-client.js +50 -6
  310. package/dist/modes/rpc/rpc-client.js.map +1 -1
  311. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  312. package/dist/modes/rpc/rpc-mode.js +23 -4
  313. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  314. package/dist/modes/rpc/rpc-types.d.ts +1 -0
  315. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  316. package/dist/modes/rpc/rpc-types.js.map +1 -1
  317. package/dist/package-manager-cli.d.ts +6 -2
  318. package/dist/package-manager-cli.d.ts.map +1 -1
  319. package/dist/package-manager-cli.js +104 -10
  320. package/dist/package-manager-cli.js.map +1 -1
  321. package/dist/utils/changelog.d.ts +1 -0
  322. package/dist/utils/changelog.d.ts.map +1 -1
  323. package/dist/utils/changelog.js +72 -0
  324. package/dist/utils/changelog.js.map +1 -1
  325. package/dist/utils/deprecation.d.ts +4 -0
  326. package/dist/utils/deprecation.d.ts.map +1 -0
  327. package/dist/utils/deprecation.js +13 -0
  328. package/dist/utils/deprecation.js.map +1 -0
  329. package/dist/utils/git.d.ts.map +1 -1
  330. package/dist/utils/git.js +54 -22
  331. package/dist/utils/git.js.map +1 -1
  332. package/dist/utils/json.d.ts +3 -0
  333. package/dist/utils/json.d.ts.map +1 -0
  334. package/dist/utils/json.js +7 -0
  335. package/dist/utils/json.js.map +1 -0
  336. package/dist/utils/open-browser.d.ts +9 -0
  337. package/dist/utils/open-browser.d.ts.map +1 -0
  338. package/dist/utils/open-browser.js +22 -0
  339. package/dist/utils/open-browser.js.map +1 -0
  340. package/docs/containerization.md +111 -0
  341. package/docs/custom-provider.md +9 -9
  342. package/docs/development.md +1 -1
  343. package/docs/docs.json +2 -0
  344. package/docs/extensions.md +40 -4
  345. package/docs/index.md +2 -0
  346. package/docs/models.md +10 -10
  347. package/docs/packages.md +1 -1
  348. package/docs/prompt-templates.md +9 -2
  349. package/docs/providers.md +18 -5
  350. package/docs/quickstart.md +1 -0
  351. package/docs/rpc.md +3 -2
  352. package/docs/sdk.md +47 -0
  353. package/docs/security.md +58 -0
  354. package/docs/session-format.md +2 -2
  355. package/docs/sessions.md +8 -0
  356. package/docs/settings.md +21 -4
  357. package/docs/skills.md +1 -1
  358. package/docs/terminal-setup.md +44 -2
  359. package/docs/themes.md +1 -1
  360. package/docs/tmux.md +4 -2
  361. package/docs/tui.md +14 -5
  362. package/docs/usage.md +17 -3
  363. package/docs/workflows.md +127 -15
  364. package/examples/README.md +1 -1
  365. package/examples/extensions/README.md +8 -5
  366. package/examples/extensions/bash-spawn-hook.ts +1 -1
  367. package/examples/extensions/built-in-tool-renderer.ts +1 -1
  368. package/examples/extensions/claude-rules.ts +1 -1
  369. package/examples/extensions/commands.ts +1 -1
  370. package/examples/extensions/custom-header.ts +1 -1
  371. package/examples/extensions/custom-provider-anthropic/index.ts +3 -3
  372. package/examples/extensions/custom-provider-anthropic/package-lock.json +4 -4
  373. package/examples/extensions/custom-provider-anthropic/package.json +6 -6
  374. package/examples/extensions/custom-provider-gitlab-duo/index.ts +55 -4
  375. package/examples/extensions/custom-provider-gitlab-duo/package.json +3 -3
  376. package/examples/extensions/doom-overlay/README.md +1 -1
  377. package/examples/extensions/doom-overlay/index.ts +2 -2
  378. package/examples/extensions/git-merge-and-resolve.ts +115 -0
  379. package/examples/extensions/gondolin/index.ts +523 -0
  380. package/examples/extensions/gondolin/package-lock.json +185 -0
  381. package/examples/extensions/gondolin/package.json +19 -0
  382. package/examples/extensions/handoff.ts +1 -1
  383. package/examples/extensions/hidden-thinking-label.ts +1 -1
  384. package/examples/extensions/inline-bash.ts +2 -2
  385. package/examples/extensions/input-transform-streaming.ts +39 -0
  386. package/examples/extensions/input-transform.ts +3 -3
  387. package/examples/extensions/interactive-shell.ts +2 -2
  388. package/examples/extensions/mac-system-theme.ts +2 -2
  389. package/examples/extensions/minimal-mode.ts +1 -1
  390. package/examples/extensions/modal-editor.ts +1 -1
  391. package/examples/extensions/model-status.ts +1 -1
  392. package/examples/extensions/overlay-qa-tests.ts +198 -179
  393. package/examples/extensions/overlay-test.ts +1 -1
  394. package/examples/extensions/pirate.ts +1 -1
  395. package/examples/extensions/preset.ts +14 -12
  396. package/examples/extensions/project-trust.ts +64 -0
  397. package/examples/extensions/prompt-customizer.ts +1 -1
  398. package/examples/extensions/qna.ts +1 -1
  399. package/examples/extensions/question.ts +1 -1
  400. package/examples/extensions/questionnaire.ts +1 -1
  401. package/examples/extensions/rainbow-editor.ts +1 -1
  402. package/examples/extensions/sandbox/index.ts +16 -14
  403. package/examples/extensions/sandbox/package-lock.json +90 -90
  404. package/examples/extensions/sandbox/package.json +17 -17
  405. package/examples/extensions/snake.ts +1 -1
  406. package/examples/extensions/space-invaders.ts +1 -1
  407. package/examples/extensions/ssh.ts +2 -2
  408. package/examples/extensions/subagent/README.md +13 -13
  409. package/examples/extensions/subagent/agents.ts +4 -2
  410. package/examples/extensions/subagent/index.ts +6 -6
  411. package/examples/extensions/summarize.ts +1 -1
  412. package/examples/extensions/tic-tac-toe.ts +1 -1
  413. package/examples/extensions/titlebar-spinner.ts +1 -1
  414. package/examples/extensions/todo.ts +1 -1
  415. package/examples/extensions/tool-override.ts +1 -1
  416. package/examples/extensions/tools.ts +6 -1
  417. package/examples/extensions/with-deps/package-lock.json +4 -4
  418. package/examples/extensions/with-deps/package.json +7 -7
  419. package/examples/extensions/working-indicator.ts +4 -4
  420. package/examples/extensions/working-message-test.ts +1 -1
  421. package/examples/sdk/01-minimal.ts +1 -1
  422. package/examples/sdk/03-custom-prompt.ts +1 -1
  423. package/examples/sdk/04-skills.ts +1 -1
  424. package/examples/sdk/06-extensions.ts +2 -2
  425. package/examples/sdk/08-prompt-templates.ts +1 -1
  426. package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
  427. package/examples/sdk/README.md +2 -2
  428. package/package.json +4 -4
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Overlay QA Tests - comprehensive overlay positioning and edge case tests
3
3
  *
4
- * Usage: pi --extension ./examples/extensions/overlay-qa-tests.ts
4
+ * Usage: atomic --extension ./examples/extensions/overlay-qa-tests.ts
5
5
  *
6
6
  * Commands:
7
7
  * /overlay-animation - Real-time animation demo (~30 FPS, proves DOOM-like rendering works)
@@ -15,20 +15,20 @@
15
15
  * /overlay-sidepanel - Responsive sidepanel (hides when terminal < 100 cols)
16
16
  * /overlay-toggle - Toggle visibility demo (demonstrates OverlayHandle.setHidden)
17
17
  * /overlay-passive - Non-capturing overlay demo (passive info panel alongside active overlay)
18
- * /overlay-focus - Focus cycling and rendering order with non-capturing overlays
18
+ * /overlay-focus - Focus cycling, input routing, dismissal, and rendering order with overlays
19
19
  * /overlay-streaming - Multiple input panels with simulated streaming (Tab to cycle focus)
20
20
  */
21
21
 
22
22
  import type { ExtensionAPI, ExtensionCommandContext, Theme } from "@bastani/atomic";
23
23
  import type { Component, OverlayAnchor, OverlayHandle, OverlayOptions, TUI } from "@earendil-works/pi-tui";
24
- import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
24
+ import { Input, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
25
25
  import { spawn } from "child_process";
26
26
 
27
27
  // Global handle for toggle demo (in real code, use a more elegant pattern)
28
28
  let globalToggleHandle: OverlayHandle | null = null;
29
29
 
30
30
  export default function (pi: ExtensionAPI) {
31
- // Animation demo - proves overlays can handle real-time updates (like pi-doom would need)
31
+ // Animation demo - proves overlays can handle real-time updates (like Atomic doom would need)
32
32
  pi.registerCommand("overlay-animation", {
33
33
  description: "Test real-time animation in overlay (~30 FPS)",
34
34
  handler: async (_args: string, ctx: ExtensionCommandContext) => {
@@ -272,9 +272,9 @@ export default function (pi: ExtensionAPI) {
272
272
  },
273
273
  });
274
274
 
275
- // Focus cycling demo - demonstrates focus(), unfocus(), isFocused() and rendering order
275
+ // Focus cycling demo - demonstrates focus(), input routing, per-panel dismissal, and rendering order
276
276
  pi.registerCommand("overlay-focus", {
277
- description: "Test focus cycling and rendering order with non-capturing overlays",
277
+ description: "Test focus cycling, input routing, dismissal, and rendering order with overlays",
278
278
  handler: async (_args: string, ctx: ExtensionCommandContext) => {
279
279
  ctx.ui.setEditorText("");
280
280
  await ctx.ui.custom<void>((tui, theme, _kb, done) => new FocusDemoController(tui, theme, done), {
@@ -303,7 +303,7 @@ function sleep(ms: number): Promise<void> {
303
303
 
304
304
  // Base overlay component with common rendering
305
305
  abstract class BaseOverlay {
306
- declare protected theme: Theme;
306
+ protected theme: Theme;
307
307
 
308
308
  constructor(theme: Theme) {
309
309
  this.theme = theme;
@@ -334,14 +334,10 @@ abstract class BaseOverlay {
334
334
 
335
335
  // Anchor position test
336
336
  class AnchorTestComponent extends BaseOverlay {
337
- declare private anchor: OverlayAnchor;
338
- declare private done: (result: "next" | "confirm" | "cancel") => void;
337
+ private anchor: OverlayAnchor;
338
+ private done: (result: "next" | "confirm" | "cancel") => void;
339
339
 
340
- constructor(
341
- theme: Theme,
342
- anchor: OverlayAnchor,
343
- done: (result: "next" | "confirm" | "cancel") => void,
344
- ) {
340
+ constructor(theme: Theme, anchor: OverlayAnchor, done: (result: "next" | "confirm" | "cancel") => void) {
345
341
  super(theme);
346
342
  this.anchor = anchor;
347
343
  this.done = done;
@@ -377,8 +373,8 @@ class AnchorTestComponent extends BaseOverlay {
377
373
 
378
374
  // Margin/offset test
379
375
  class MarginTestComponent extends BaseOverlay {
380
- declare private config: { name: string; options: OverlayOptions };
381
- declare private done: (result: "next" | "close") => void;
376
+ private config: { name: string; options: OverlayOptions };
377
+ private done: (result: "next" | "close") => void;
382
378
 
383
379
  constructor(
384
380
  theme: Theme,
@@ -417,16 +413,11 @@ class MarginTestComponent extends BaseOverlay {
417
413
 
418
414
  // Stacked overlay test
419
415
  class StackOverlayComponent extends BaseOverlay {
420
- declare private num: number;
421
- declare private position: string;
422
- declare private done: (result: string) => void;
416
+ private num: number;
417
+ private position: string;
418
+ private done: (result: string) => void;
423
419
 
424
- constructor(
425
- theme: Theme,
426
- num: number,
427
- position: string,
428
- done: (result: string) => void,
429
- ) {
420
+ constructor(theme: Theme, num: number, position: string, done: (result: string) => void) {
430
421
  super(theme);
431
422
  this.num = num;
432
423
  this.position = position;
@@ -467,21 +458,16 @@ class StackOverlayComponent extends BaseOverlay {
467
458
 
468
459
  // Streaming overflow test - spawns real process with colored output (original crash scenario)
469
460
  class StreamingOverflowComponent extends BaseOverlay {
461
+ private tui: TUI;
470
462
  private lines: string[] = [];
471
463
  private proc: ReturnType<typeof spawn> | null = null;
472
464
  private scrollOffset = 0;
473
465
  private maxVisibleLines = 15;
474
466
  private finished = false;
475
467
  private disposed = false;
468
+ private done: () => void;
476
469
 
477
- declare private tui: TUI;
478
- declare private done: () => void;
479
-
480
- constructor(
481
- tui: TUI,
482
- theme: Theme,
483
- done: () => void,
484
- ) {
470
+ constructor(tui: TUI, theme: Theme, done: () => void) {
485
471
  super(theme);
486
472
  this.tui = tui;
487
473
  this.done = done;
@@ -499,13 +485,13 @@ class StreamingOverflowComponent extends BaseOverlay {
499
485
  echo ""
500
486
  for i in $(seq 1 100); do
501
487
  # Simulate long file paths with OSC 8 hyperlinks (clickable) - tests width overflow
502
- DIR="/Users/nicobailon/Documents/development/pi-mono/packages/coding-agent/src/modes/interactive"
488
+ DIR="/Users/example/Documents/development/atomic/packages/coding-agent/src/modes/interactive"
503
489
  FILE="\${DIR}/components/very-long-component-name-that-exceeds-width-\${i}.ts"
504
490
  echo -e "\\033]8;;file://\${FILE}\\007▶ read: \${FILE}\\033]8;;\\007"
505
491
 
506
492
  # Add some colored status messages with long text
507
493
  if [ $((i % 5)) -eq 0 ]; then
508
- echo -e " \\033[32m✓ Successfully processed \${i} files in /Users/nicobailon/Documents/development/pi-mono\\033[0m"
494
+ echo -e " \\033[32m✓ Successfully processed \${i} files in /Users/example/Documents/development/atomic\\033[0m"
509
495
  fi
510
496
  if [ $((i % 7)) -eq 0 ]; then
511
497
  echo -e " \\033[33m⚠ Warning: potential issue detected at line \${i} in very-long-component-name-that-exceeds-width.ts\\033[0m"
@@ -605,12 +591,9 @@ class StreamingOverflowComponent extends BaseOverlay {
605
591
 
606
592
  // Edge position test
607
593
  class EdgeTestComponent extends BaseOverlay {
608
- declare private done: () => void;
594
+ private done: () => void;
609
595
 
610
- constructor(
611
- theme: Theme,
612
- done: () => void,
613
- ) {
596
+ constructor(theme: Theme, done: () => void) {
614
597
  super(theme);
615
598
  this.done = done;
616
599
  }
@@ -643,8 +626,8 @@ class EdgeTestComponent extends BaseOverlay {
643
626
 
644
627
  // Percentage positioning test
645
628
  class PercentTestComponent extends BaseOverlay {
646
- declare private config: { name: string; row: number; col: number };
647
- declare private done: (result: "next" | "close") => void;
629
+ private config: { name: string; row: number; col: number };
630
+ private done: (result: "next" | "close") => void;
648
631
 
649
632
  constructor(
650
633
  theme: Theme,
@@ -683,12 +666,9 @@ class PercentTestComponent extends BaseOverlay {
683
666
 
684
667
  // MaxHeight test - renders 20 lines, truncated to 10 by maxHeight
685
668
  class MaxHeightTestComponent extends BaseOverlay {
686
- declare private done: () => void;
669
+ private done: () => void;
687
670
 
688
- constructor(
689
- theme: Theme,
690
- done: () => void,
691
- ) {
671
+ constructor(theme: Theme, done: () => void) {
692
672
  super(theme);
693
673
  this.done = done;
694
674
  }
@@ -721,17 +701,12 @@ class MaxHeightTestComponent extends BaseOverlay {
721
701
 
722
702
  // Responsive sidepanel - demonstrates percentage width and visibility callback
723
703
  class SidepanelComponent extends BaseOverlay {
704
+ private tui: TUI;
724
705
  private items = ["Dashboard", "Messages", "Settings", "Help", "About"];
725
706
  private selectedIndex = 0;
707
+ private done: () => void;
726
708
 
727
- declare private tui: TUI;
728
- declare private done: () => void;
729
-
730
- constructor(
731
- tui: TUI,
732
- theme: Theme,
733
- done: () => void,
734
- ) {
709
+ constructor(tui: TUI, theme: Theme, done: () => void) {
735
710
  super(theme);
736
711
  this.tui = tui;
737
712
  this.done = done;
@@ -785,22 +760,17 @@ class SidepanelComponent extends BaseOverlay {
785
760
  }
786
761
  }
787
762
 
788
- // Animation demo - proves overlays can handle real-time updates like pi-doom
763
+ // Animation demo - proves overlays can handle real-time updates like Atomic doom
789
764
  class AnimationDemoComponent extends BaseOverlay {
765
+ private tui: TUI;
790
766
  private frame = 0;
791
767
  private interval: ReturnType<typeof setInterval> | null = null;
792
768
  private fps = 0;
793
769
  private lastFpsUpdate = Date.now();
794
770
  private framesSinceLastFps = 0;
771
+ private done: () => void;
795
772
 
796
- declare private tui: TUI;
797
- declare private done: () => void;
798
-
799
- constructor(
800
- tui: TUI,
801
- theme: Theme,
802
- done: () => void,
803
- ) {
773
+ constructor(tui: TUI, theme: Theme, done: () => void) {
804
774
  super(theme);
805
775
  this.tui = tui;
806
776
  this.done = done;
@@ -866,7 +836,7 @@ class AnimationDemoComponent extends BaseOverlay {
866
836
  lines.push(border("│") + padLine(``) + border("│"));
867
837
  lines.push(border("│") + padLine(th.fg("dim", " This proves overlays can handle")) + border("│"));
868
838
  lines.push(border("│") + padLine(th.fg("dim", " real-time game-like rendering.")) + border("│"));
869
- lines.push(border("│") + padLine(th.fg("dim", " (pi-doom uses same approach)")) + border("│"));
839
+ lines.push(border("│") + padLine(th.fg("dim", " (Atomic doom uses same approach)")) + border("│"));
870
840
  lines.push(border("│") + padLine(``) + border("│"));
871
841
  lines.push(border("│") + padLine(th.fg("dim", " Press Esc to close")) + border("│"));
872
842
  lines.push(border(`╰${"─".repeat(innerW)}╯`));
@@ -907,17 +877,12 @@ function hslToRgb(h: number, s: number, l: number): [number, number, number] {
907
877
 
908
878
  // Toggle demo - demonstrates OverlayHandle.setHidden() via onHandle callback
909
879
  class ToggleDemoComponent extends BaseOverlay {
880
+ private tui: TUI;
910
881
  private toggleCount = 0;
911
882
  private isToggling = false;
883
+ private done: () => void;
912
884
 
913
- declare private tui: TUI;
914
- declare private done: () => void;
915
-
916
- constructor(
917
- tui: TUI,
918
- theme: Theme,
919
- done: () => void,
920
- ) {
885
+ constructor(tui: TUI, theme: Theme, done: () => void) {
921
886
  super(theme);
922
887
  this.tui = tui;
923
888
  this.done = done;
@@ -975,21 +940,16 @@ class ToggleDemoComponent extends BaseOverlay {
975
940
 
976
941
  class PassiveDemoController extends BaseOverlay {
977
942
  focused = false;
943
+ private tui: TUI;
978
944
  private typed = "";
979
945
  private timerComponent: TimerPanel;
980
946
  private timerHandle: OverlayHandle | null = null;
981
947
  private interval: ReturnType<typeof setInterval> | null = null;
982
948
  private inputCount = 0;
983
949
  private lastInputDebug = "";
950
+ private done: () => void;
984
951
 
985
- declare private tui: TUI;
986
- declare private done: () => void;
987
-
988
- constructor(
989
- tui: TUI,
990
- theme: Theme,
991
- done: () => void,
992
- ) {
952
+ constructor(tui: TUI, theme: Theme, done: () => void) {
993
953
  super(theme);
994
954
  this.tui = tui;
995
955
  this.done = done;
@@ -1071,62 +1031,66 @@ class TimerPanel extends BaseOverlay {
1071
1031
 
1072
1032
  // === Focus cycling demo ===
1073
1033
 
1074
- class FocusDemoController extends BaseOverlay {
1075
- private panels: FocusPanel[] = [];
1076
- private handles: OverlayHandle[] = [];
1077
- private focusIndex = -1;
1034
+ type FocusPanelColor = "error" | "success" | "accent";
1035
+ type FocusPanelConfig = { label: string; color: FocusPanelColor; options: OverlayOptions };
1036
+ type FocusPanelEntry = { panel: FocusPanel; handle: OverlayHandle };
1078
1037
 
1079
- declare private tui: TUI;
1080
- declare private done: () => void;
1038
+ const FOCUS_PANEL_CONFIGS = [
1039
+ { label: "Alpha", color: "error", options: { row: 2, col: 4, width: 34 } },
1040
+ { label: "Beta", color: "success", options: { row: 5, col: 28, width: 34 } },
1041
+ { label: "Gamma", color: "accent", options: { row: 8, col: 52, width: 34 } },
1042
+ ] satisfies FocusPanelConfig[];
1081
1043
 
1082
- constructor(
1083
- tui: TUI,
1084
- theme: Theme,
1085
- done: () => void,
1086
- ) {
1044
+ class FocusDemoController extends BaseOverlay {
1045
+ private readonly tui: TUI;
1046
+ private entries: FocusPanelEntry[] = [];
1047
+ private readonly done: () => void;
1048
+ private closed = false;
1049
+
1050
+ constructor(tui: TUI, theme: Theme, done: () => void) {
1087
1051
  super(theme);
1088
1052
  this.tui = tui;
1089
1053
  this.done = done;
1090
- const colors = ["error", "success", "accent"] as const;
1091
- const labels = ["Alpha", "Beta", "Gamma"];
1092
1054
 
1093
- for (let i = 0; i < 3; i++) {
1094
- const panel = new FocusPanel(
1095
- theme,
1096
- labels[i]!,
1097
- colors[i]!,
1098
- () => this.cycleFocus(),
1099
- () => this.close(),
1100
- );
1101
- const handle = this.tui.showOverlay(panel, {
1102
- nonCapturing: true,
1103
- row: 2,
1104
- col: 5 + i * 6,
1105
- width: 28,
1106
- });
1107
- panel.handle = handle;
1108
- this.panels.push(panel);
1109
- this.handles.push(handle);
1055
+ for (const config of FOCUS_PANEL_CONFIGS) {
1056
+ const panel = new FocusPanel({ theme, config, controller: this });
1057
+ const handle = this.tui.showOverlay(panel, { nonCapturing: true, ...config.options });
1058
+ this.entries.push({ panel, handle });
1110
1059
  }
1060
+
1061
+ this.focusFirstOpenPanel();
1111
1062
  }
1112
1063
 
1113
- private cycleFocus(): void {
1114
- if (this.focusIndex >= 0 && this.focusIndex < this.handles.length) {
1115
- this.handles[this.focusIndex]!.unfocus();
1116
- }
1117
- this.focusIndex++;
1118
- if (this.focusIndex >= this.handles.length) {
1119
- this.focusIndex = -1;
1120
- } else {
1121
- this.handles[this.focusIndex]!.focus();
1064
+ focusNext(current: FocusPanel, direction: 1 | -1 = 1): void {
1065
+ const openEntries = this.openEntries();
1066
+ const currentOpenPosition = openEntries.findIndex((entry) => entry.panel === current);
1067
+ if (currentOpenPosition === -1) throw new Error(`Panel ${current.label} is not open`);
1068
+ const nextOpenPosition = (currentOpenPosition + direction + openEntries.length) % openEntries.length;
1069
+ this.focusEntryAt(openEntries, nextOpenPosition);
1070
+ }
1071
+
1072
+ dismiss(panel: FocusPanel): void {
1073
+ const openEntries = this.openEntries();
1074
+ const currentOpenPosition = openEntries.findIndex((candidate) => candidate.panel === panel);
1075
+ if (currentOpenPosition === -1) return;
1076
+ const entry = openEntries[currentOpenPosition];
1077
+ if (!entry) throw new Error(`Invalid focus panel index ${currentOpenPosition}`);
1078
+ const remainingEntries = openEntries.filter((candidate) => candidate.panel !== panel);
1079
+
1080
+ entry.panel.closed = true;
1081
+ entry.handle.hide();
1082
+ if (remainingEntries.length === 0) {
1083
+ this.close();
1084
+ return;
1122
1085
  }
1123
- this.tui.requestRender();
1086
+
1087
+ this.focusEntryAt(remainingEntries, currentOpenPosition % remainingEntries.length);
1124
1088
  }
1125
1089
 
1126
- private close(): void {
1127
- for (const handle of this.handles) handle.hide();
1128
- this.handles = [];
1129
- this.panels = [];
1090
+ close(): void {
1091
+ if (this.closed) return;
1092
+ this.closed = true;
1093
+ this.hidePanels();
1130
1094
  this.done();
1131
1095
  }
1132
1096
 
@@ -1134,87 +1098,148 @@ class FocusDemoController extends BaseOverlay {
1134
1098
  if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
1135
1099
  this.close();
1136
1100
  } else if (matchesKey(data, "tab")) {
1137
- this.cycleFocus();
1101
+ this.focusFirstOpenPanel();
1138
1102
  }
1139
1103
  }
1140
1104
 
1141
1105
  render(width: number): string[] {
1142
1106
  const th = this.theme;
1143
- const focused = this.focusIndex === -1 ? "Controller" : (this.panels[this.focusIndex]?.label ?? "?");
1107
+ const focused = this.entries.find((entry) => entry.handle.isFocused())?.panel.label ?? "Controller";
1144
1108
  return this.box(
1145
1109
  [
1146
1110
  "",
1147
1111
  ` Current focus: ${th.fg("accent", focused)}`,
1148
1112
  "",
1149
1113
  " Three overlapping panels above are",
1150
- ` all ${th.fg("accent", "nonCapturing")}. Press Tab to`,
1151
- " cycle focus() between them.",
1114
+ ` ${th.fg("accent", "nonCapturing")} overlays controlled with`,
1115
+ " raw OverlayHandle.focus()/hide().",
1152
1116
  "",
1153
- " Focused panel renders on top",
1154
- " (focus-based rendering order).",
1117
+ " Type in the focused panel's input.",
1118
+ " Focused panel renders on top.",
1155
1119
  "",
1156
- th.fg("dim", " Tab = cycle focus | Esc = close"),
1120
+ th.fg("dim", " Tab/Shift+Tab = cycle panels"),
1121
+ th.fg("dim", " Esc/Ctrl+D = dismiss panel"),
1122
+ th.fg("dim", " Ctrl+C = close all"),
1157
1123
  "",
1158
1124
  ],
1159
1125
  width,
1160
- "Focus Demo",
1126
+ "Focus + Input Demo",
1161
1127
  );
1162
1128
  }
1163
1129
 
1164
1130
  override dispose(): void {
1165
- for (const handle of this.handles) handle.hide();
1131
+ if (this.closed) return;
1132
+ this.closed = true;
1133
+ this.hidePanels();
1134
+ }
1135
+
1136
+ private focusFirstOpenPanel(): void {
1137
+ const firstOpen = this.openEntries()[0];
1138
+ if (firstOpen) {
1139
+ firstOpen.handle.focus();
1140
+ this.tui.requestRender();
1141
+ }
1142
+ }
1143
+
1144
+ private focusEntryAt(entries: FocusPanelEntry[], index: number): void {
1145
+ const entry = entries[index];
1146
+ if (!entry) throw new Error(`Invalid focus panel index ${index}`);
1147
+ entry.handle.focus();
1148
+ this.tui.requestRender();
1149
+ }
1150
+
1151
+ private hidePanels(): void {
1152
+ for (const entry of this.entries) {
1153
+ if (!entry.panel.closed) {
1154
+ entry.panel.closed = true;
1155
+ entry.handle.hide();
1156
+ }
1157
+ }
1158
+ this.entries = [];
1159
+ }
1160
+
1161
+ private openEntries(): FocusPanelEntry[] {
1162
+ return this.entries.filter((entry) => !entry.panel.closed);
1166
1163
  }
1167
1164
  }
1168
1165
 
1169
1166
  class FocusPanel extends BaseOverlay {
1170
- handle: OverlayHandle | null = null;
1167
+ focused = false;
1168
+ closed = false;
1171
1169
  readonly label: string;
1172
-
1173
- declare private color: "error" | "success" | "accent";
1174
- declare private onTab: () => void;
1175
- declare private onClose: () => void;
1176
-
1177
- constructor(
1178
- theme: Theme,
1179
- label: string,
1180
- color: "error" | "success" | "accent",
1181
- onTab: () => void,
1182
- onClose: () => void,
1183
- ) {
1170
+ private readonly color: FocusPanelColor;
1171
+ private readonly controller: FocusDemoController;
1172
+ private readonly input = new Input();
1173
+ private inputs: string[] = [];
1174
+
1175
+ constructor({
1176
+ theme,
1177
+ config,
1178
+ controller,
1179
+ }: {
1180
+ theme: Theme;
1181
+ config: FocusPanelConfig;
1182
+ controller: FocusDemoController;
1183
+ }) {
1184
1184
  super(theme);
1185
- this.color = color;
1186
- this.onTab = onTab;
1187
- this.onClose = onClose;
1188
- this.label = label;
1185
+ this.label = config.label;
1186
+ this.color = config.color;
1187
+ this.controller = controller;
1189
1188
  }
1190
1189
 
1191
1190
  handleInput(data: string): void {
1192
1191
  if (matchesKey(data, "tab")) {
1193
- this.onTab();
1194
- } else if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
1195
- this.onClose();
1192
+ this.controller.focusNext(this);
1193
+ } else if (matchesKey(data, "shift+tab")) {
1194
+ this.controller.focusNext(this, -1);
1195
+ } else if (matchesKey(data, "escape") || matchesKey(data, "ctrl+d")) {
1196
+ this.controller.dismiss(this);
1197
+ } else if (matchesKey(data, "ctrl+c")) {
1198
+ this.controller.close();
1199
+ } else if (matchesKey(data, "return")) {
1200
+ this.inputs.push("Enter");
1201
+ } else if (matchesKey(data, "up")) {
1202
+ this.inputs.push("↑");
1203
+ } else if (matchesKey(data, "down")) {
1204
+ this.inputs.push("↓");
1205
+ } else if (matchesKey(data, "left")) {
1206
+ this.input.handleInput(data);
1207
+ this.inputs.push("←");
1208
+ } else if (matchesKey(data, "right")) {
1209
+ this.input.handleInput(data);
1210
+ this.inputs.push("→");
1211
+ } else if (matchesKey(data, "backspace")) {
1212
+ this.input.handleInput(data);
1213
+ this.inputs.push("Backspace");
1214
+ } else {
1215
+ this.input.handleInput(data);
1216
+ this.inputs.push(JSON.stringify(data));
1196
1217
  }
1197
1218
  }
1198
1219
 
1199
1220
  render(width: number): string[] {
1200
1221
  const th = this.theme;
1201
- const focused = this.handle?.isFocused() ?? false;
1202
1222
  const innerW = Math.max(1, width - 2);
1203
- const border = (c: string) => th.fg(this.color, c);
1223
+ const border = (c: string) => th.fg(this.focused ? this.color : "dim", c);
1204
1224
  const padLine = (s: string) => truncateToWidth(s, innerW, "...", true);
1225
+ const recent = this.inputs.length === 0 ? "(none)" : this.inputs.slice(-6).join(" ");
1205
1226
  const lines: string[] = [];
1206
1227
 
1228
+ this.input.focused = this.focused;
1229
+ const [inputLine = ""] = this.input.render(Math.max(1, innerW - 8));
1207
1230
  lines.push(border(`╭${"─".repeat(innerW)}╮`));
1208
- lines.push(border("│") + padLine(` ${th.fg("accent", this.label)}`) + border("│"));
1209
- lines.push(border("│") + padLine("") + border("│"));
1210
- if (focused) {
1211
- lines.push(border("│") + padLine(th.fg("success", "FOCUSED")) + border(""));
1212
- lines.push(border("│") + padLine(th.fg("dim", " (receiving input)")) + border("│"));
1213
- } else {
1214
- lines.push(border("│") + padLine(th.fg("dim", " ○ unfocused")) + border("│"));
1215
- lines.push(border("│") + padLine(th.fg("dim", " (passive)")) + border("│"));
1216
- }
1231
+ lines.push(
1232
+ border("│") +
1233
+ padLine(
1234
+ ` ${th.fg(this.color, this.label)} ${this.focused ? th.fg("success", "FOCUSED") : th.fg("dim", "visible")}`,
1235
+ ) +
1236
+ border("│"),
1237
+ );
1217
1238
  lines.push(border("│") + padLine("") + border("│"));
1239
+ lines.push(border("│") + padLine(` Input: ${inputLine}`) + border("│"));
1240
+ lines.push(border("│") + padLine(` Keys: ${recent}`) + border("│"));
1241
+ lines.push(border("│") + padLine(th.fg("dim", " Tab/Shift+Tab focus")) + border("│"));
1242
+ lines.push(border("│") + padLine(th.fg("dim", " Esc/Ctrl+D dismiss")) + border("│"));
1218
1243
  lines.push(border(`╰${"─".repeat(innerW)}╯`));
1219
1244
 
1220
1245
  return lines;
@@ -1224,21 +1249,16 @@ class FocusPanel extends BaseOverlay {
1224
1249
  // === Streaming input panel test (/overlay-streaming) ===
1225
1250
 
1226
1251
  class StreamingInputController extends BaseOverlay {
1252
+ private tui: TUI;
1227
1253
  private panels: StreamingInputPanel[] = [];
1228
1254
  private handles: OverlayHandle[] = [];
1229
1255
  private focusIndex = -1; // -1 = controller focused, 0-2 = panel focused
1230
1256
  private streamLines: string[] = [];
1231
1257
  private streamInterval: ReturnType<typeof setInterval> | null = null;
1232
1258
  private lineCount = 0;
1259
+ private done: () => void;
1233
1260
 
1234
- declare private tui: TUI;
1235
- declare private done: () => void;
1236
-
1237
- constructor(
1238
- tui: TUI,
1239
- theme: Theme,
1240
- done: () => void,
1241
- ) {
1261
+ constructor(tui: TUI, theme: Theme, done: () => void) {
1242
1262
  super(theme);
1243
1263
  this.tui = tui;
1244
1264
  this.done = done;
@@ -1361,13 +1381,12 @@ class StreamingInputController extends BaseOverlay {
1361
1381
 
1362
1382
  class StreamingInputPanel implements Component {
1363
1383
  handle: OverlayHandle | null = null;
1384
+ private theme: Theme;
1364
1385
  private typed = "";
1365
1386
  readonly label: string;
1366
-
1367
- declare private theme: Theme;
1368
- declare private color: "error" | "success" | "accent";
1369
- declare private onTab: () => void;
1370
- declare private onClose: () => void;
1387
+ private color: "error" | "success" | "accent";
1388
+ private onTab: () => void;
1389
+ private onClose: () => void;
1371
1390
 
1372
1391
  constructor(
1373
1392
  theme: Theme,
@@ -1377,10 +1396,10 @@ class StreamingInputPanel implements Component {
1377
1396
  onClose: () => void,
1378
1397
  ) {
1379
1398
  this.theme = theme;
1399
+ this.label = label;
1380
1400
  this.color = color;
1381
1401
  this.onTab = onTab;
1382
1402
  this.onClose = onClose;
1383
- this.label = label;
1384
1403
  }
1385
1404
 
1386
1405
  handleInput(data: string): void {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Overlay Test - validates overlay compositing with inline text inputs
3
3
  *
4
- * Usage: pi --extension ./examples/extensions/overlay-test.ts
4
+ * Usage: atomic --extension ./examples/extensions/overlay-test.ts
5
5
  *
6
6
  * Run /overlay-test to show a floating overlay with:
7
7
  * - Inline text inputs within menu items
@@ -5,7 +5,7 @@
5
5
  * change agent behavior based on extension state.
6
6
  *
7
7
  * Usage:
8
- * 1. Copy this file to ~/.pi/agent/extensions/ or your project's .pi/extensions/
8
+ * 1. Copy this file to ~/.atomic/agent/extensions/ or your project's .atomic/extensions/ (legacy .pi/extensions/ also works)
9
9
  * 2. Use /pirate to toggle pirate mode
10
10
  * 3. When enabled, the agent will respond like a pirate
11
11
  */