@xingular/harness 1.0.0 → 1.2.0

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 (397) hide show
  1. package/CHANGELOG.md +46 -5
  2. package/README.md +75 -21
  3. package/dist/cli.js +17421 -8711
  4. package/dist/sdk/accounts/accounts.d.ts +27 -3
  5. package/dist/sdk/accounts/accounts.js +78 -24
  6. package/dist/sdk/accounts/secrets.d.ts +12 -0
  7. package/dist/sdk/accounts/secrets.js +114 -7
  8. package/dist/sdk/accounts/store.d.ts +26 -1
  9. package/dist/sdk/accounts/store.js +1 -1
  10. package/dist/sdk/agents/builtin.d.ts +2 -0
  11. package/dist/sdk/agents/builtin.js +48 -0
  12. package/dist/sdk/agents/narrow.d.ts +13 -0
  13. package/dist/sdk/agents/narrow.js +29 -0
  14. package/dist/sdk/agents/planResearch.d.ts +5 -0
  15. package/dist/sdk/agents/planResearch.js +19 -0
  16. package/dist/sdk/agents/profiles.d.ts +81 -0
  17. package/dist/sdk/agents/profiles.js +226 -0
  18. package/dist/sdk/annotations/bridge.d.ts +42 -0
  19. package/dist/sdk/annotations/bridge.js +264 -0
  20. package/dist/sdk/annotations/capture.d.ts +116 -0
  21. package/dist/sdk/annotations/capture.js +308 -0
  22. package/dist/sdk/annotations/delivery.d.ts +72 -0
  23. package/dist/sdk/annotations/delivery.js +130 -0
  24. package/dist/sdk/annotations/inspect.d.ts +10 -0
  25. package/dist/sdk/annotations/inspect.js +33 -0
  26. package/dist/sdk/annotations/isolated.d.ts +6 -0
  27. package/dist/sdk/annotations/isolated.js +51 -0
  28. package/dist/sdk/annotations/pageScript.d.ts +28 -0
  29. package/dist/sdk/annotations/pageScript.js +871 -0
  30. package/dist/sdk/annotations/part.d.ts +10 -0
  31. package/dist/sdk/annotations/part.js +155 -0
  32. package/dist/sdk/annotations/queue.d.ts +4 -0
  33. package/dist/sdk/annotations/queue.js +40 -0
  34. package/dist/sdk/annotations/serverMethods.d.ts +3 -0
  35. package/dist/sdk/annotations/serverMethods.js +62 -0
  36. package/dist/sdk/annotations/store.d.ts +167 -0
  37. package/dist/sdk/annotations/store.js +394 -0
  38. package/dist/sdk/browser/backend.d.ts +16 -0
  39. package/dist/sdk/browser/backend.js +17 -0
  40. package/dist/sdk/browser/contracts.d.ts +19 -0
  41. package/dist/sdk/browser/contracts.js +116 -0
  42. package/dist/sdk/browser/index.d.ts +14 -3
  43. package/dist/sdk/browser/index.js +11 -4
  44. package/dist/sdk/browser/serverMethods.d.ts +3 -0
  45. package/dist/sdk/browser/serverMethods.js +7 -0
  46. package/dist/sdk/browser/session.d.ts +1 -0
  47. package/dist/sdk/browser/session.js +45 -9
  48. package/dist/sdk/browser/tools.d.ts +1 -4
  49. package/dist/sdk/browser/tools.js +14 -91
  50. package/dist/sdk/cli.js +24 -15
  51. package/dist/sdk/commands/list.d.ts +3 -0
  52. package/dist/sdk/commands/list.js +75 -0
  53. package/dist/sdk/commands/registry.d.ts +250 -0
  54. package/dist/sdk/commands/registry.js +47 -0
  55. package/dist/sdk/commands/routes.d.ts +16 -0
  56. package/dist/sdk/commands/routes.js +33 -0
  57. package/dist/sdk/core/bus.js +1 -1
  58. package/dist/sdk/core/commandBudget.d.ts +23 -0
  59. package/dist/sdk/core/commandBudget.js +57 -0
  60. package/dist/sdk/core/env.d.ts +1 -1
  61. package/dist/sdk/core/env.js +1 -1
  62. package/dist/sdk/core/index.js +17 -1
  63. package/dist/sdk/core/interactiveProfile.d.ts +46 -0
  64. package/dist/sdk/core/interactiveProfile.js +143 -0
  65. package/dist/sdk/core/workspace.d.ts +13 -0
  66. package/dist/sdk/core/workspace.js +88 -0
  67. package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
  68. package/dist/sdk/core/workspaceBashTool.js +36 -0
  69. package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
  70. package/dist/sdk/core/workspaceSandbox.js +320 -0
  71. package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
  72. package/dist/sdk/core/workspaceWriteOperations.js +206 -0
  73. package/dist/sdk/doctor/serverMethods.d.ts +3 -0
  74. package/dist/sdk/doctor/serverMethods.js +8 -0
  75. package/dist/sdk/doctor/types.d.ts +2 -2
  76. package/dist/sdk/harness.d.ts +22 -0
  77. package/dist/sdk/harness.js +84 -5
  78. package/dist/sdk/history/recall.js +8 -8
  79. package/dist/sdk/history/serverMethods.d.ts +3 -0
  80. package/dist/sdk/history/serverMethods.js +8 -0
  81. package/dist/sdk/hub/cli.d.ts +1 -1
  82. package/dist/sdk/hub/cli.js +1 -1
  83. package/dist/sdk/hub/schema.d.ts +1 -1
  84. package/dist/sdk/hub/serverMethods.d.ts +3 -0
  85. package/dist/sdk/hub/serverMethods.js +11 -0
  86. package/dist/sdk/index.d.ts +16 -1
  87. package/dist/sdk/index.js +10 -0
  88. package/dist/sdk/mcp/connections.js +14 -7
  89. package/dist/sdk/mcp/serverMethods.d.ts +3 -0
  90. package/dist/sdk/mcp/serverMethods.js +22 -0
  91. package/dist/sdk/pi/runtime.d.ts +2 -1
  92. package/dist/sdk/pi/runtime.js +2 -2
  93. package/dist/sdk/plugins/builtin.d.ts +1 -0
  94. package/dist/sdk/plugins/builtin.js +145 -33
  95. package/dist/sdk/plugins/builtinRegistry.d.ts +60 -0
  96. package/dist/sdk/plugins/builtinRegistry.js +71 -0
  97. package/dist/sdk/plugins/catalogue.js +2 -1
  98. package/dist/sdk/plugins/cli.d.ts +1 -1
  99. package/dist/sdk/plugins/cli.js +4 -3
  100. package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
  101. package/dist/sdk/plugins/commandPrefix.js +21 -0
  102. package/dist/sdk/plugins/firstParty.d.ts +1 -1
  103. package/dist/sdk/plugins/firstParty.js +8 -2
  104. package/dist/sdk/plugins/inventory.js +4 -3
  105. package/dist/sdk/plugins/manifest.d.ts +2 -0
  106. package/dist/sdk/plugins/manifest.js +2 -1
  107. package/dist/sdk/plugins/surfaces.d.ts +5 -0
  108. package/dist/sdk/plugins/surfaces.js +11 -0
  109. package/dist/sdk/plugins/types.d.ts +15 -0
  110. package/dist/sdk/prompt/compile.d.ts +19 -2
  111. package/dist/sdk/prompt/compile.js +79 -26
  112. package/dist/sdk/prompt/standard.d.ts +17 -0
  113. package/dist/sdk/prompt/standard.js +21 -0
  114. package/dist/sdk/refine/cli.d.ts +1 -1
  115. package/dist/sdk/refine/cli.js +2 -2
  116. package/dist/sdk/refine/serverMethods.d.ts +3 -0
  117. package/dist/sdk/refine/serverMethods.js +20 -0
  118. package/dist/sdk/server/methods.js +27 -86
  119. package/dist/sdk/server/params.d.ts +4 -0
  120. package/dist/sdk/server/params.js +11 -0
  121. package/dist/sdk/server/remote.js +36 -11
  122. package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
  123. package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
  124. package/dist/sdk/sessions/continuation.d.ts +3 -0
  125. package/dist/sdk/sessions/continuation.js +5 -1
  126. package/dist/sdk/sessions/contracts.d.ts +185 -0
  127. package/dist/sdk/sessions/contracts.js +101 -4
  128. package/dist/sdk/sessions/control.d.ts +72 -0
  129. package/dist/sdk/sessions/control.js +158 -0
  130. package/dist/sdk/sessions/initialBash.d.ts +7 -0
  131. package/dist/sdk/sessions/initialBash.js +7 -0
  132. package/dist/sdk/sessions/planMode.d.ts +18 -4
  133. package/dist/sdk/sessions/planMode.js +82 -16
  134. package/dist/sdk/sessions/reasoningSummaries.d.ts +2 -2
  135. package/dist/sdk/sessions/reasoningSummaries.js +3 -3
  136. package/dist/sdk/sessions/registry.d.ts +2 -1
  137. package/dist/sdk/sessions/registry.js +6 -3
  138. package/dist/sdk/sessions/runIndex.js +7 -7
  139. package/dist/sdk/sessions/runStore.d.ts +14 -0
  140. package/dist/sdk/sessions/runStore.js +38 -1
  141. package/dist/sdk/sessions/runner.d.ts +40 -2
  142. package/dist/sdk/sessions/runner.js +163 -15
  143. package/dist/sdk/sessions/sessions.d.ts +40 -8
  144. package/dist/sdk/sessions/sessions.js +279 -27
  145. package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
  146. package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
  147. package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
  148. package/dist/sdk/sessions/sideQuestions.js +290 -0
  149. package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
  150. package/dist/sdk/sessions/subagentServerMethods.js +41 -0
  151. package/dist/sdk/sessions/subagentService.d.ts +22 -2
  152. package/dist/sdk/sessions/subagentService.js +93 -16
  153. package/dist/sdk/sessions/subagents.d.ts +9 -1
  154. package/dist/sdk/sessions/subagents.js +19 -0
  155. package/dist/sdk/sessions/workSlice.d.ts +103 -0
  156. package/dist/sdk/sessions/workSlice.js +297 -0
  157. package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
  158. package/dist/sdk/sessions/workspaceBoundary.js +46 -0
  159. package/dist/sdk/terminal/browser.d.ts +62 -0
  160. package/dist/sdk/terminal/browser.js +41 -0
  161. package/dist/sdk/terminal/browserControl.d.ts +29 -0
  162. package/dist/sdk/terminal/browserControl.js +187 -0
  163. package/dist/sdk/terminal/commandHelp.d.ts +17 -0
  164. package/dist/sdk/terminal/commandHelp.js +20 -0
  165. package/dist/sdk/terminal/controller.d.ts +15 -1
  166. package/dist/sdk/terminal/controller.js +67 -8
  167. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
  168. package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
  169. package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
  170. package/dist/sdk/terminal/opentui/theme.js +87 -0
  171. package/dist/sdk/terminal/piExtension.d.ts +6 -1
  172. package/dist/sdk/terminal/piExtension.js +169 -84
  173. package/dist/sdk/terminal/socket.d.ts +6 -3
  174. package/dist/sdk/terminal/socket.js +40 -9
  175. package/dist/sdk/terminal/standalone.d.ts +9 -0
  176. package/dist/sdk/terminal/standalone.js +118 -19
  177. package/dist/sdk/terminal/subagentMonitor.d.ts +47 -0
  178. package/dist/sdk/terminal/subagentMonitor.js +152 -0
  179. package/dist/sdk/terminal/terminals.d.ts +60 -7
  180. package/dist/sdk/terminal/terminals.js +598 -47
  181. package/dist/sdk/terminal/trajectory.js +2 -2
  182. package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
  183. package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
  184. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -1
  185. package/dist/sdk/terminal/tui/commandPages.js +57 -6
  186. package/dist/sdk/terminal/tui/commands.d.ts +10 -4
  187. package/dist/sdk/terminal/tui/commands.js +269 -65
  188. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +2 -2
  189. package/dist/sdk/terminal/tui/dialogGeometry.js +4 -2
  190. package/dist/sdk/terminal/tui/dialogs.d.ts +6 -1
  191. package/dist/sdk/terminal/tui/dialogs.js +9 -2
  192. package/dist/sdk/terminal/tui/list.d.ts +14 -1
  193. package/dist/sdk/terminal/tui/list.js +96 -14
  194. package/dist/sdk/terminal/tui/modelPicker.js +1 -6
  195. package/dist/sdk/terminal/tui/page.d.ts +3 -0
  196. package/dist/sdk/terminal/tui/pageOverlay.js +27 -7
  197. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +26 -4
  198. package/dist/sdk/terminal/tui/pages/accountsPage.js +264 -36
  199. package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
  200. package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
  201. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
  202. package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
  203. package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
  204. package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
  205. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +2 -0
  206. package/dist/sdk/terminal/tui/pages/doctorPage.js +103 -15
  207. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
  208. package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
  209. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
  210. package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
  211. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +8 -0
  212. package/dist/sdk/terminal/tui/pages/settingsPage.js +16 -1
  213. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +24 -0
  214. package/dist/sdk/terminal/tui/pages/subagentsPage.js +152 -0
  215. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +12 -5
  216. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +156 -83
  217. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
  218. package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
  219. package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
  220. package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
  221. package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
  222. package/dist/sdk/terminal/tui/piAdapter.js +3 -5
  223. package/dist/sdk/terminal/tui/planMode.d.ts +1 -1
  224. package/dist/sdk/terminal/tui/planMode.js +1 -1
  225. package/dist/sdk/terminal/tui/pluginCommands.d.ts +16 -0
  226. package/dist/sdk/terminal/tui/pluginCommands.js +31 -0
  227. package/dist/sdk/terminal/tui/questions.d.ts +2 -0
  228. package/dist/sdk/terminal/tui/runtime.js +27 -5
  229. package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
  230. package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
  231. package/dist/sdk/terminal/tui/settingsModel.d.ts +2 -0
  232. package/dist/sdk/terminal/tui/settingsModel.js +32 -2
  233. package/dist/sdk/terminal/tui/sideQuestion.d.ts +26 -26
  234. package/dist/sdk/terminal/tui/sideQuestion.js +131 -98
  235. package/dist/sdk/terminal/tui/ui.d.ts +2 -0
  236. package/dist/sdk/terminal/tui/ui.js +1 -0
  237. package/dist/sdk/tools/askUser.js +26 -8
  238. package/dist/sdk/tools/checklist.js +3 -2
  239. package/dist/sdk/tools/checkpoint.d.ts +27 -0
  240. package/dist/sdk/tools/checkpoint.js +154 -0
  241. package/dist/sdk/tools/getCapabilities.d.ts +31 -0
  242. package/dist/sdk/tools/getCapabilities.js +34 -0
  243. package/dist/sdk/tools/harnessTools.d.ts +2 -0
  244. package/dist/sdk/tools/harnessTools.js +1 -1
  245. package/dist/sdk/tools/spawnSubagent.js +14 -4
  246. package/dist/sdk/usage/analytics.d.ts +20 -0
  247. package/dist/sdk/usage/analytics.js +151 -0
  248. package/dist/sdk/usage/ledger.d.ts +38 -0
  249. package/dist/sdk/usage/ledger.js +142 -0
  250. package/dist/sdk/usage/limits/adapters.d.ts +11 -0
  251. package/dist/sdk/usage/limits/adapters.js +349 -0
  252. package/dist/sdk/usage/limits/capture.d.ts +8 -0
  253. package/dist/sdk/usage/limits/capture.js +47 -0
  254. package/dist/sdk/usage/limits/http.d.ts +12 -0
  255. package/dist/sdk/usage/limits/http.js +51 -0
  256. package/dist/sdk/usage/limits/normalize.d.ts +15 -0
  257. package/dist/sdk/usage/limits/normalize.js +211 -0
  258. package/dist/sdk/usage/limits/service.d.ts +30 -0
  259. package/dist/sdk/usage/limits/service.js +176 -0
  260. package/dist/sdk/usage/limits/types.d.ts +65 -0
  261. package/dist/sdk/usage/limits/types.js +1 -0
  262. package/dist/sdk/usage/serverMethods.d.ts +3 -0
  263. package/dist/sdk/usage/serverMethods.js +22 -0
  264. package/dist/sdk/usage/service.d.ts +32 -0
  265. package/dist/sdk/usage/service.js +66 -0
  266. package/dist/sdk/usage/settings.d.ts +7 -0
  267. package/dist/sdk/usage/settings.js +28 -0
  268. package/dist/sdk/usage/types.d.ts +60 -0
  269. package/dist/sdk/usage/types.js +4 -0
  270. package/dist/sdk/web/part.d.ts +10 -0
  271. package/dist/sdk/web/part.js +6 -0
  272. package/dist/sdk/web/serverMethods.d.ts +3 -0
  273. package/dist/sdk/web/serverMethods.js +7 -0
  274. package/dist/sdk/wiki/serverMethods.d.ts +3 -0
  275. package/dist/sdk/wiki/serverMethods.js +26 -0
  276. package/dist/sdk/worktrees/cli.d.ts +11 -0
  277. package/dist/sdk/worktrees/cli.js +146 -0
  278. package/dist/sdk/worktrees/copy.d.ts +9 -0
  279. package/dist/sdk/worktrees/copy.js +111 -0
  280. package/dist/sdk/worktrees/git.d.ts +16 -0
  281. package/dist/sdk/worktrees/git.js +81 -0
  282. package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
  283. package/dist/sdk/worktrees/serverMethods.js +30 -0
  284. package/dist/sdk/worktrees/service.d.ts +73 -0
  285. package/dist/sdk/worktrees/service.js +483 -0
  286. package/dist/sdk/worktrees/setup.d.ts +23 -0
  287. package/dist/sdk/worktrees/setup.js +65 -0
  288. package/dist/sdk/worktrees/types.d.ts +91 -0
  289. package/dist/sdk/worktrees/types.js +1 -0
  290. package/dist/sdk/world/cli.d.ts +2 -2
  291. package/dist/sdk/world/cli.js +6 -6
  292. package/dist/sdk/world/world.d.ts +3 -1
  293. package/dist/sdk/world/world.js +8 -9
  294. package/dist/terminal-opentui.js +16456 -5966
  295. package/dist/terminal-pi.js +1579 -573
  296. package/docs/README.md +22 -2
  297. package/docs/architecture/00-overview.md +28 -16
  298. package/docs/architecture/02-sessions-and-runs.md +184 -25
  299. package/docs/architecture/03-variants.md +10 -2
  300. package/docs/architecture/04-prompt.md +65 -7
  301. package/docs/architecture/06-plugins-and-capabilities.md +57 -4
  302. package/docs/architecture/07-tools-and-gate.md +112 -17
  303. package/docs/architecture/08-memory-and-history.md +4 -2
  304. package/docs/architecture/09-accounts-and-connectors.md +39 -1
  305. package/docs/architecture/10-server-protocol.md +168 -4
  306. package/docs/architecture/11-terminal.md +251 -8
  307. package/docs/architecture/12-storage.md +45 -3
  308. package/docs/architecture/13-world-tools.md +49 -6
  309. package/docs/architecture/14-surfaces-and-parity.md +136 -0
  310. package/docs/architecture/README.md +17 -4
  311. package/docs/architecture/proposals/PROP-0006-run-checklist.md +4 -2
  312. package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
  313. package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
  314. package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
  315. package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
  316. package/docs/architecture/proposals/PROP-0017-page-annotations.md +131 -0
  317. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
  318. package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
  319. package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
  320. package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
  321. package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
  322. package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
  323. package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
  324. package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
  325. package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
  326. package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
  327. package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
  328. package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
  329. package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
  330. package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
  331. package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
  332. package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
  333. package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
  334. package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
  335. package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
  336. package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
  337. package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
  338. package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
  339. package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
  340. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
  341. package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
  342. package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
  343. package/docs/architecture/proposals/README.md +39 -0
  344. package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
  345. package/docs/decisions/ADR-0009-xharness-command.md +6 -5
  346. package/docs/decisions/ADR-0014-public-release-baseline.md +3 -2
  347. package/docs/decisions/ADR-0015-resource-browser.md +28 -0
  348. package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
  349. package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
  350. package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
  351. package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
  352. package/docs/decisions/ADR-0020-page-annotations.md +37 -0
  353. package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
  354. package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
  355. package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
  356. package/docs/decisions/ADR-0024-xagent-command.md +40 -0
  357. package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
  358. package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
  359. package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
  360. package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
  361. package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
  362. package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
  363. package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
  364. package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
  365. package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
  366. package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
  367. package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
  368. package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
  369. package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
  370. package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
  371. package/docs/doctor.md +10 -4
  372. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
  373. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
  374. package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
  375. package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
  376. package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
  377. package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
  378. package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
  379. package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
  380. package/docs/features/README.md +26 -0
  381. package/docs/features/interfaces/README.md +1 -1
  382. package/docs/future-work.md +48 -0
  383. package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
  384. package/docs/parity.md +134 -0
  385. package/docs/releases/1.0.0.md +2 -2
  386. package/docs/releases/1.1.1.md +28 -0
  387. package/docs/releases/1.2.0.md +49 -0
  388. package/docs/releases/4.0.0.md +47 -0
  389. package/docs/releases/README.md +37 -27
  390. package/docs/study/00-index.md +8 -0
  391. package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
  392. package/docs/study/autonomous-engineering-sources.md +277 -0
  393. package/docs/study/autonomy-sources.md +147 -0
  394. package/docs/study/proactive-autonomy.md +408 -0
  395. package/docs/study/tui-resource-browser.md +78 -0
  396. package/docs/terminal-tui.md +386 -113
  397. package/package.json +6 -5
@@ -44,7 +44,9 @@ export function centeredRect(columns, rows, width, height) {
44
44
  height: boxHeight
45
45
  };
46
46
  }
47
- /** The overlay options every full-screen page command passes; OpenTUI reads the marker. */
48
- export function pageOverlayOptions() {
47
+ /** Page commands declare their presentation; OpenTUI centers only marked dialogs. */
48
+ export function pageOverlayOptions(presentation = 'centered') {
49
+ if (presentation === 'fullscreen')
50
+ return { anchor: 'top-left', width: '100%', maxHeight: '100%' };
49
51
  return { anchor: 'top-left', width: '100%', maxHeight: '100%', dialog: 'page' };
50
52
  }
@@ -1,6 +1,10 @@
1
1
  import type { ExtensionUIContext, ExtensionUIDialogOptions, KeybindingsManager, Theme } from '@earendil-works/pi-coding-agent';
2
2
  import { Input, type Component, type Focusable, type SelectListTheme, type TUI, type TuiMouseEventResult } from '@earendil-works/pi-tui';
3
3
  import type { TerminalMouseInput } from "./mouse.js";
4
+ export interface GroupedSelectOption {
5
+ label: string;
6
+ group?: string;
7
+ }
4
8
  /** `page` asks for a full-screen dialog; Pi's own dialogs ignore the field. */
5
9
  export type TerminalDialogOptions = ExtensionUIDialogOptions & {
6
10
  page?: boolean;
@@ -19,7 +23,7 @@ export declare class SearchableSelect implements Component, Focusable {
19
23
  private readonly list;
20
24
  private readonly labels;
21
25
  private focusedValue;
22
- constructor(options: string[], tui: TUI, theme: () => Theme, select: (index: number) => void, cancel: () => void, search?: 'always' | 'never');
26
+ constructor(options: string[], tui: TUI, theme: () => Theme, select: (index: number) => void, cancel: () => void, search?: 'always' | 'never', groups?: readonly (string | undefined)[]);
23
27
  get focused(): boolean;
24
28
  set focused(value: boolean);
25
29
  get pinnedRows(): number;
@@ -66,6 +70,7 @@ export declare class TerminalDialogs {
66
70
  constructor(tui: TUI, theme: () => Theme, keybindings: KeybindingsManager, changed: () => void);
67
71
  private show;
68
72
  select(title: string, options: string[], opts?: TerminalDialogOptions): Promise<string | undefined>;
73
+ selectGrouped(title: string, options: readonly GroupedSelectOption[], opts?: ExtensionUIDialogOptions): Promise<string | undefined>;
69
74
  confirm(title: string, message: string, opts?: ExtensionUIDialogOptions): Promise<boolean>;
70
75
  input(title: string, placeholder?: string, opts?: ExtensionUIDialogOptions, secret?: boolean): Promise<string | undefined>;
71
76
  editor(title: string, prefill?: string): Promise<string | undefined>;
@@ -31,14 +31,14 @@ export class SearchableSelect {
31
31
  list;
32
32
  labels;
33
33
  focusedValue = false;
34
- constructor(options, tui, theme, select, cancel, search = 'always') {
34
+ constructor(options, tui, theme, select, cancel, search = 'always', groups) {
35
35
  this.tui = tui;
36
36
  this.select = select;
37
37
  this.cancel = cancel;
38
38
  this.labels = options.map(safe);
39
39
  this.list = new FilterList({
40
40
  theme, search,
41
- rows: this.labels.map((label, index) => ({ id: String(index), label, data: index })),
41
+ rows: this.labels.map((label, index) => ({ id: String(index), label, ...(groups?.[index] ? { group: groups[index] } : {}), data: index })),
42
42
  limit: () => this.windowRows(),
43
43
  noun: ['option', 'options'],
44
44
  onActivate: row => this.select(row.data ?? 0),
@@ -265,6 +265,13 @@ export class TerminalDialogs {
265
265
  return new DialogPanel(title, list, this.theme, '↑/↓ select · Enter confirm · Esc cancel', undefined, opts?.page ? 'page' : 'block');
266
266
  }, opts);
267
267
  }
268
+ selectGrouped(title, options, opts) {
269
+ const labels = options.map(option => option.label);
270
+ return this.show(done => {
271
+ const list = new SearchableSelect(labels, this.tui, this.theme, index => done(labels[index]), () => done(undefined), 'always', options.map(option => option.group));
272
+ return new DialogPanel(title, list, this.theme, '↑/↓ select · Enter confirm · Esc cancel');
273
+ }, opts);
274
+ }
268
275
  async confirm(title, message, opts) {
269
276
  return (await this.show(done => {
270
277
  const list = new SearchableSelect(['Yes', 'No'], this.tui, this.theme, index => done(index === 0), () => done(undefined), 'never');
@@ -2,11 +2,20 @@ import type { Theme } from '@earendil-works/pi-coding-agent';
2
2
  import { type Component, type Focusable, type TuiMouseEventResult } from '@earendil-works/pi-tui';
3
3
  import { type TerminalMouseInput } from "./mouse.js";
4
4
  export type RowTone = 'success' | 'warning' | 'error' | 'muted' | 'dim' | 'accent';
5
+ export interface ListLabelPart {
6
+ text: string;
7
+ color?: string;
8
+ tone?: RowTone;
9
+ }
5
10
  export interface ListRow<T = unknown> {
6
11
  id: string;
7
12
  label: string;
13
+ /** Optional colored spans for the label; selected rows keep the shared high-contrast text. */
14
+ labelParts?: readonly ListLabelPart[];
8
15
  /** Shown at the right edge, in `tone`. */
9
16
  detail?: string;
17
+ /** An optional muted second line beneath the label. */
18
+ subtitle?: string;
10
19
  tone?: RowTone;
11
20
  /** Rows with the same consecutive group share a heading (not shown while searching). */
12
21
  group?: string;
@@ -22,6 +31,8 @@ export interface FilterListOptions<T> {
22
31
  search?: 'always' | 'never';
23
32
  /** Rows the list may use; the search field is part of it. Defaults to what `render` is given. */
24
33
  limit?: () => number;
34
+ /** Blank lines between visible rows. */
35
+ rowGap?: number;
25
36
  empty?: string;
26
37
  noun?: readonly [string, string];
27
38
  /** Short context included in the search row while a query is active. */
@@ -59,6 +70,7 @@ export declare class FilterList<T = unknown> implements Component, Focusable {
59
70
  handleMouse(event: TerminalMouseInput): TuiMouseEventResult | undefined;
60
71
  invalidate(): void;
61
72
  private limit;
73
+ private rowGap;
62
74
  private mode;
63
75
  private canSearch;
64
76
  private searchVisible;
@@ -67,7 +79,8 @@ export declare class FilterList<T = unknown> implements Component, Focusable {
67
79
  private move;
68
80
  handleInput(data: string): boolean;
69
81
  private entries;
70
- private line;
82
+ private lines;
83
+ private labelParts;
71
84
  /** `rows` is the most the list may use, the search row included. */
72
85
  render(width: number, rows?: number): string[];
73
86
  }
@@ -1,4 +1,4 @@
1
- import { fuzzyFilter, matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
1
+ import { fuzzyFilter, matchesKey, parseColor, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
2
2
  import { safeText, selectedRow, selectionMuted, selectionText } from "./chrome.js";
3
3
  import { SEARCH_FIELD_ROWS, SearchField, searchFieldRowsFor } from "./search.js";
4
4
  import { isPrimaryClick } from "./mouse.js";
@@ -25,7 +25,10 @@ export class FilterList {
25
25
  get total() { return this.rows.length; }
26
26
  get shown() { return this.visible.length; }
27
27
  /** Rows the list would use if nothing cut it: the search field, headings and rows. */
28
- get height() { return (this.searchVisible() ? this.renderedSearchRows : 0) + this.entries().length; }
28
+ get height() {
29
+ return (this.searchVisible() ? this.renderedSearchRows : 0)
30
+ + this.entries().reduce((height, entry) => height + (entry.row?.subtitle === undefined ? 1 : 2), 0);
31
+ }
29
32
  /** Rows at the top of `render` that a frame must keep when it has to cut the list. */
30
33
  get pinnedRows() { return this.searchVisible() ? this.renderedSearchRows : 0; }
31
34
  setRows(rows) {
@@ -61,6 +64,10 @@ export class FilterList {
61
64
  }
62
65
  invalidate() { this.search.invalidate(); }
63
66
  limit() { return Math.max(1, Math.floor(this.options.limit?.() ?? Number.POSITIVE_INFINITY)); }
67
+ rowGap() {
68
+ const gap = this.options.rowGap ?? 0;
69
+ return Number.isFinite(gap) ? Math.max(0, Math.floor(gap)) : 0;
70
+ }
64
71
  mode() { return this.options.search ?? 'always'; }
65
72
  canSearch() { return this.mode() === 'always'; }
66
73
  searchVisible() { return this.canSearch() || this.query.length > 0; }
@@ -68,7 +75,7 @@ export class FilterList {
68
75
  refilter() {
69
76
  const query = this.query.trim();
70
77
  this.visible = query
71
- ? fuzzyFilter(this.rows, query, row => row.searchText ?? `${row.label} ${row.detail ?? ''} ${row.group ?? ''}`)
78
+ ? fuzzyFilter(this.rows, query, row => row.searchText ?? `${row.label} ${row.subtitle ?? ''} ${row.detail ?? ''} ${row.group ?? ''}`)
72
79
  : this.rows;
73
80
  if (!this.visible.some(row => row.id === this.selectedId && !row.disabled))
74
81
  this.selectedId = this.firstSelectable()?.id;
@@ -136,15 +143,20 @@ export class FilterList {
136
143
  entries() {
137
144
  const entries = [];
138
145
  let last;
139
- for (const row of this.visible) {
146
+ const gap = this.rowGap();
147
+ for (const [index, row] of this.visible.entries()) {
140
148
  if (!this.query && row.group && row.group !== last)
141
149
  entries.push({ heading: row.group });
142
150
  last = row.group;
143
151
  entries.push({ row });
152
+ if (index < this.visible.length - 1) {
153
+ for (let line = 0; line < gap; line += 1)
154
+ entries.push({ spacer: true });
155
+ }
144
156
  }
145
157
  return entries;
146
158
  }
147
- line(row, width) {
159
+ lines(row, width) {
148
160
  const theme = this.options.theme();
149
161
  const selected = row.id === this.selectedId;
150
162
  const detail = row.detail ? safeText(row.detail) : '';
@@ -153,10 +165,40 @@ export class FilterList {
153
165
  const label = truncateToWidth(safeText(row.label), Math.max(0, room - (showDetail ? visibleWidth(detail) + 2 : 0)), '…');
154
166
  const gap = ' '.repeat(Math.max(0, room - visibleWidth(label) - (showDetail ? visibleWidth(detail) : 0)));
155
167
  const tone = (text) => theme.fg(row.tone ?? 'muted', text);
156
- const main = (selected ? '❯ ' : ' ') + label;
157
- if (selected)
158
- return selectedRow(selectionText(theme, main) + gap + (showDetail ? selectionMuted(theme, detail) : ''), width, theme);
159
- return (row.disabled ? theme.fg('dim', main) : main) + gap + (showDetail ? tone(detail) : '');
168
+ const prefix = selected ? '❯ ' : ' ';
169
+ const labelText = selected || row.disabled || !row.labelParts?.length ? label : this.labelParts(row.labelParts, label, theme);
170
+ const main = prefix + label;
171
+ const primary = selected
172
+ ? selectedRow(selectionText(theme, main) + gap + (showDetail ? selectionMuted(theme, detail) : ''), width, theme)
173
+ : (row.disabled ? theme.fg('dim', main) : prefix + labelText) + gap + (showDetail ? tone(detail) : '');
174
+ if (row.subtitle === undefined)
175
+ return [primary];
176
+ const subtitle = truncateToWidth(` ${safeText(row.subtitle)}`, width, '…');
177
+ const secondary = selected
178
+ ? selectedRow(selectionMuted(theme, subtitle), width, theme)
179
+ : theme.fg(row.disabled ? 'dim' : 'muted', subtitle);
180
+ return [primary, secondary];
181
+ }
182
+ labelParts(parts, visibleLabel, theme) {
183
+ const source = parts.map(part => safeText(part.text)).join('');
184
+ const truncated = visibleWidth(source) > visibleWidth(visibleLabel);
185
+ let remaining = Math.max(0, visibleWidth(visibleLabel) - (truncated ? 1 : 0));
186
+ const output = [];
187
+ for (const part of parts) {
188
+ if (remaining <= 0)
189
+ break;
190
+ const text = safeText(part.text);
191
+ const fitted = truncateToWidth(text, remaining, '');
192
+ if (fitted) {
193
+ output.push(part.color ? theme.style(fitted, { fg: parseColor(part.color) }) : part.tone ? theme.fg(part.tone, fitted) : fitted);
194
+ }
195
+ remaining -= visibleWidth(fitted);
196
+ if (visibleWidth(fitted) < visibleWidth(text))
197
+ break;
198
+ }
199
+ if (truncated)
200
+ output.push('…');
201
+ return output.join('');
160
202
  }
161
203
  /** `rows` is the most the list may use, the search row included. */
162
204
  render(width, rows) {
@@ -186,11 +228,51 @@ export class FilterList {
186
228
  return lines.map(line => truncateToWidth(line, width, ''));
187
229
  }
188
230
  const at = Math.max(0, entries.findIndex(entry => entry.row?.id === this.selectedId));
189
- const start = Math.max(0, Math.min(Math.max(0, entries.length - budget), at - Math.floor(budget / 2)));
190
- for (const entry of entries.slice(start, start + budget)) {
191
- lines.push(entry.row ? this.line(entry.row, width) : theme.fg('dim', safeText(entry.heading ?? '')));
192
- this.renderedRows.push(entry.row);
231
+ let start = at;
232
+ let end = at + 1;
233
+ let used = entries[at]?.row?.subtitle === undefined ? 1 : 2;
234
+ let preferBefore = true;
235
+ while (start > 0 || end < entries.length) {
236
+ const before = entries[start - 1];
237
+ const after = entries[end];
238
+ const beforeHeight = before ? (before.row?.subtitle === undefined ? 1 : 2) : Number.POSITIVE_INFINITY;
239
+ const afterHeight = after ? (after.row?.subtitle === undefined ? 1 : 2) : Number.POSITIVE_INFINITY;
240
+ if (preferBefore && before && used + beforeHeight <= budget) {
241
+ start -= 1;
242
+ used += beforeHeight;
243
+ }
244
+ else if (after && used + afterHeight <= budget) {
245
+ end += 1;
246
+ used += afterHeight;
247
+ }
248
+ else if (before && used + beforeHeight <= budget) {
249
+ start -= 1;
250
+ used += beforeHeight;
251
+ }
252
+ else
253
+ break;
254
+ preferBefore = !preferBefore;
255
+ }
256
+ if (entries[start]?.spacer)
257
+ start += 1;
258
+ if (entries[end - 1]?.spacer)
259
+ end -= 1;
260
+ for (const entry of entries.slice(start, end)) {
261
+ if (entry.row) {
262
+ const rendered = this.lines(entry.row, width);
263
+ lines.push(...rendered);
264
+ this.renderedRows.push(...rendered.map(() => entry.row));
265
+ }
266
+ else if (entry.spacer) {
267
+ lines.push('');
268
+ this.renderedRows.push(undefined);
269
+ }
270
+ else {
271
+ lines.push(theme.fg('dim', safeText(entry.heading ?? '')));
272
+ this.renderedRows.push(undefined);
273
+ }
193
274
  }
194
- return lines.map(line => truncateToWidth(line, width, ''));
275
+ this.renderedRows = this.renderedRows.slice(0, rowBudget);
276
+ return lines.slice(0, rowBudget).map(line => truncateToWidth(line, width, ''));
195
277
  }
196
278
  }
@@ -67,11 +67,8 @@ export class ModelPicker {
67
67
  this.error = 'Model refresh timed out; showing cached models.';
68
68
  else if (result.errors.size)
69
69
  this.error = `Could not refresh ${[...result.errors.keys()].join(', ')}; showing cached models.`;
70
- else {
70
+ else
71
71
  this.error = this.options.runtime.getError();
72
- if (!this.error)
73
- this.status = 'Model catalogs refreshed.';
74
- }
75
72
  this.load();
76
73
  }
77
74
  catch (error) {
@@ -135,10 +132,8 @@ export class ModelPicker {
135
132
  return [];
136
133
  const centered = centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
137
134
  const inner = centered ? centerDialogContentWidth(width) : contentWidth(width);
138
- const selected = this.list.selected?.data;
139
135
  const notes = [
140
136
  this.status ? theme.fg('muted', this.status) : '',
141
- selected ? theme.fg('muted', `Model name: ${safeText(selected.name ?? selected.id)}`) : '',
142
137
  this.error ? theme.fg('error', this.error) : ''
143
138
  ].filter(Boolean);
144
139
  const chromeRows = centered ? centerDialogChromeRows(rows) : 4;
@@ -2,6 +2,9 @@ import type { TuiMouseEventResult } from '@earendil-works/pi-tui';
2
2
  import type { TabInfo } from "./chrome.js";
3
3
  import type { TerminalMouseInput } from "./mouse.js";
4
4
  export interface TerminalPage {
5
+ presentation?: 'centered' | 'fullscreen';
6
+ ownsNavigation?: boolean;
7
+ selectTab?(id: string): void;
5
8
  tabs(): readonly TabInfo[];
6
9
  activeTab(): string;
7
10
  render(width: number, rows: number): string[];
@@ -1,4 +1,4 @@
1
- import { matchesKey } from '@earendil-works/pi-tui';
1
+ import { matchesKey, visibleWidth } from '@earendil-works/pi-tui';
2
2
  import { CENTER_DIALOG_PAD, CHROME_PAD, centerDialogBodyRows, centerDialogContentWidth, centerDialogFrame, centerDialogVerticalPad, contentWidth, pageBodyRows, pageFrame, tabIndexAt, tabStrip } from "./chrome.js";
3
3
  import { centeredDialogHost, dialogFits, pageRows } from "./dialogGeometry.js";
4
4
  export class PageOverlay {
@@ -23,6 +23,12 @@ export class PageOverlay {
23
23
  if (this.disposed)
24
24
  return undefined;
25
25
  if (event.type === 'wheel') {
26
+ const layout = this.pointerLayout;
27
+ if (layout && event.y >= layout.bodyStart) {
28
+ const handled = this.page.handleMouse?.({ ...event, x: event.x - layout.contentX, y: event.y - layout.bodyStart });
29
+ if (handled?.handled)
30
+ return handled;
31
+ }
26
32
  const key = event.wheelDelta !== undefined && event.wheelDelta < 0 ? '\x1b[5~' : '\x1b[6~';
27
33
  this.handleInput(key);
28
34
  return { handled: true, render: true };
@@ -49,6 +55,11 @@ export class PageOverlay {
49
55
  const target = tabIndex ?? (tabX < layout.contentWidth / 2
50
56
  ? (current - 1 + tabs.length) % tabs.length
51
57
  : (current + 1) % tabs.length);
58
+ if (this.page.selectTab) {
59
+ this.page.selectTab(tabs[target].id);
60
+ this.hoveredTab = undefined;
61
+ return { handled: true, render: true };
62
+ }
52
63
  const delta = (target - Math.max(0, current) + tabs.length) % tabs.length;
53
64
  const reverse = (Math.max(0, current) - target + tabs.length) % tabs.length;
54
65
  const direction = delta <= reverse ? '\t' : '\x1b[Z';
@@ -75,9 +86,9 @@ export class PageOverlay {
75
86
  this.options.close();
76
87
  return;
77
88
  }
78
- const centered = centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
89
+ const centered = this.page.presentation !== 'fullscreen' && centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
79
90
  const tabs = this.options.page.tabs();
80
- const input = centered && tabs.length > 1
91
+ const input = centered && tabs.length > 1 && !this.options.page.ownsNavigation
81
92
  ? matchesKey(data, 'right') ? '\t' : matchesKey(data, 'left') ? '\x1b[Z' : data
82
93
  : data;
83
94
  if (this.options.page.handleInput(input)) {
@@ -90,13 +101,13 @@ export class PageOverlay {
90
101
  render(width) {
91
102
  if (this.disposed)
92
103
  return [];
93
- const rows = pageRows(this.options.tui);
104
+ const rows = this.page.presentation === 'fullscreen' ? this.options.tui.terminal.rows : pageRows(this.options.tui);
94
105
  const page = this.options.page;
95
106
  const tabs = page.tabs();
96
107
  if (width < 1 || rows < 1 || !tabs.length)
97
108
  return [];
98
109
  const theme = this.options.theme();
99
- const centered = centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
110
+ const centered = this.page.presentation !== 'fullscreen' && centeredDialogHost(this.options.tui) && dialogFits(this.options.tui.terminal.columns, this.options.tui.terminal.rows);
100
111
  const inner = centered ? centerDialogContentWidth(width) : contentWidth(width);
101
112
  if (centered) {
102
113
  const tabRows = tabs.length > 1 ? 1 : 0;
@@ -121,11 +132,20 @@ export class PageOverlay {
121
132
  contentWidth: contentWidth(width),
122
133
  centered
123
134
  };
124
- const footer = [
135
+ const escapeHint = page.ownsNavigation ? 'Esc back/close' : 'Esc close';
136
+ const fullFooter = page.ownsNavigation ? `${escapeHint} · ${page.hint()}` : [
125
137
  page.hint(),
126
138
  tabs.length > 1 ? 'Tab/Shift+Tab sections' : '',
127
- 'Esc close'
139
+ escapeHint
140
+ ].filter(Boolean).join(' · ');
141
+ const footerWidth = Math.max(0, width - CHROME_PAD * 2);
142
+ const primaryHint = page.hint().split(' · ')[0] ?? '';
143
+ const compactFooter = [
144
+ primaryHint,
145
+ !page.ownsNavigation && tabs.length > 1 ? 'Tab/⇧Tab' : '',
146
+ escapeHint
128
147
  ].filter(Boolean).join(' · ');
148
+ const footer = visibleWidth(fullFooter) <= footerWidth ? fullFooter : compactFooter;
129
149
  return pageFrame({
130
150
  title: '',
131
151
  headerLine: tabStrip(tabs, page.activeTab(), inner, theme, 'top', this.hoveredTab),
@@ -1,10 +1,11 @@
1
1
  /**
2
- * The Accounts page: one row per account with its health, the selected account's details beneath,
3
- * and Pools as a second section. Enter on an account opens its actions; the actions themselves are
4
- * the ones the `/accounts` menu of a native `pi` session uses.
2
+ * The Accounts page: one row per account with its health and Pools as a second section. Opening
3
+ * an account shows its details and grouped actions in a wide inspector or a compact detail page;
4
+ * the actions themselves are the ones the `/accounts` menu of a native `pi` session uses.
5
5
  */
6
6
  import type { Theme } from '@earendil-works/pi-coding-agent';
7
7
  import { type AccountsCall, type AccountsUi, type SessionAccount } from "../../accountsMenu.js";
8
+ import type { GroupedSelectOption } from "../dialogs.js";
8
9
  import type { TerminalPage } from "../page.js";
9
10
  import type { TerminalMouseInput } from "../mouse.js";
10
11
  export interface AccountsPageOptions {
@@ -12,19 +13,30 @@ export interface AccountsPageOptions {
12
13
  call: AccountsCall;
13
14
  /** The account this session runs on. */
14
15
  session: () => SessionAccount | null;
15
- ui: AccountsUi;
16
+ ui: AccountsUi & {
17
+ selectGrouped?(title: string, options: readonly GroupedSelectOption[]): Promise<string | undefined>;
18
+ };
16
19
  /** The session is switching accounts: the host ends it so the launcher can start it again. */
17
20
  relaunch(): void;
18
21
  changed(): void;
19
22
  }
20
23
  export declare class AccountsPage implements TerminalPage {
21
24
  private readonly options;
25
+ readonly presentation = "fullscreen";
26
+ readonly ownsNavigation = true;
22
27
  private overview;
23
28
  private error;
24
29
  private section;
30
+ private focus;
31
+ private detailOpen;
32
+ private detailAccountId;
25
33
  private busy;
26
34
  private disposed;
35
+ private compact;
36
+ private wideListWidth;
37
+ private actionRowsStart;
27
38
  private readonly list;
39
+ private readonly actionList;
28
40
  constructor(options: AccountsPageOptions);
29
41
  get focused(): boolean;
30
42
  set focused(value: boolean);
@@ -38,6 +50,7 @@ export declare class AccountsPage implements TerminalPage {
38
50
  readonly title: "Pools";
39
51
  }];
40
52
  activeTab(): string;
53
+ selectTab(id: string): void;
41
54
  hint(): string;
42
55
  private reload;
43
56
  /** Searching looks through accounts and pools together; otherwise the page shows the current section. */
@@ -45,9 +58,18 @@ export declare class AccountsPage implements TerminalPage {
45
58
  private accountRows;
46
59
  private poolRows;
47
60
  private account;
61
+ private detailAccount;
62
+ private selectGrouped;
63
+ private accountActionGroup;
64
+ private fillActions;
65
+ private detailLines;
48
66
  /** Runs one thing at a time and always reads the accounts again afterwards. */
49
67
  private guarded;
68
+ private closeDetails;
69
+ private openDetails;
50
70
  private activateRow;
71
+ private activateAction;
72
+ private moveSection;
51
73
  handleMouse(event: TerminalMouseInput): import("@earendil-works/pi-tui").TuiMouseEventResult | undefined;
52
74
  handleInput(data: string): boolean;
53
75
  render(width: number, rows: number): string[];