@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
@@ -15,7 +15,7 @@ export function listTerminalTrajectoryRuns(root, sessionId, nativeSessionId) {
15
15
  if (!nativeSessionId)
16
16
  return [];
17
17
  return listRuns(root, { sessionId })
18
- .filter(run => run.nativeSessionId === nativeSessionId)
18
+ .filter(run => run.nativeSessionId === nativeSessionId || run.trigger === 'side-question' && run.sessionId === sessionId)
19
19
  .map(summary);
20
20
  }
21
21
  /** Read a run only when it belongs to both this terminal and its current native conversation. */
@@ -23,7 +23,7 @@ export function readTerminalTrajectory(root, sessionId, nativeSessionId, runId,
23
23
  if (!nativeSessionId || !Number.isSafeInteger(afterSequence ?? 0) || (afterSequence ?? 0) < 0)
24
24
  throw notFound('Run');
25
25
  const run = findRun(root, runId);
26
- if (!run || run.sessionId !== sessionId || run.nativeSessionId !== nativeSessionId)
26
+ if (!run || run.sessionId !== sessionId || (run.nativeSessionId !== nativeSessionId && run.trigger !== 'side-question'))
27
27
  throw notFound('Run');
28
28
  const events = readEvents(root, runId).filter(event => afterSequence === undefined || event.sequence > afterSequence);
29
29
  return { run: summary(run), events };
@@ -0,0 +1,3 @@
1
+ import type { AnnotateStart } from "./pages/annotatePage.js";
2
+ /** `/annotate:annotate` accepts a page address, DevTools target, or page-bridge target. */
3
+ export declare function parseAnnotate(argument: string): AnnotateStart | string;
@@ -0,0 +1,22 @@
1
+ /** `/annotate:annotate` accepts a page address, DevTools target, or page-bridge target. */
2
+ export function parseAnnotate(argument) {
3
+ const words = argument.trim().split(/\s+/).filter(Boolean);
4
+ if (!words.length)
5
+ return { kind: 'web' };
6
+ if (words[0] === '--app') {
7
+ const endpoint = words[1];
8
+ if (!endpoint)
9
+ return 'Give the app\'s DevTools address: /annotate:annotate --app http://127.0.0.1:9229';
10
+ const address = /^\d+$/.test(endpoint) ? `http://127.0.0.1:${endpoint}` : endpoint;
11
+ const name = words.slice(2).join(' ');
12
+ return { kind: 'cdp', endpoint: address, ...(name ? { name } : {}) };
13
+ }
14
+ if (words[0] === '--bridge') {
15
+ const name = words.slice(1).join(' ');
16
+ return { kind: 'bridge', ...(name ? { name } : {}) };
17
+ }
18
+ if (words.length > 1 || words[0].startsWith('--'))
19
+ return 'Use /annotate:annotate [url], /annotate:annotate --app <DevTools address>, or /annotate:annotate --bridge.';
20
+ const url = /^[a-z][a-z0-9+.-]*:\/\//i.test(words[0]) ? words[0] : /^(localhost|127\.0\.0\.1)(:\d+)?(\/|$)/.test(words[0]) ? `http://${words[0]}` : `https://${words[0]}`;
21
+ return { kind: 'web', url };
22
+ }
@@ -1,7 +1,13 @@
1
1
  import type { TerminalPage } from "./page.js";
2
2
  import type { TerminalCommandHost } from "./commands.js";
3
- export type CommandPageId = 'doctor' | 'accounts' | 'permissions' | 'plugins' | 'hub' | 'components' | 'settings' | 'trajectory' | 'log';
3
+ import { type AnnotateStart } from "./pages/annotatePage.js";
4
+ export type CommandPageId = 'doctor' | 'accounts' | 'permissions' | 'plugins' | 'hub' | 'components' | 'settings' | 'trajectory' | 'log' | 'harness' | 'skills' | 'connections' | 'tools' | 'worktree' | 'notes' | 'annotate' | 'subagents' | 'agents' | 'usage';
4
5
  /** Construct one independent full-screen page for a slash command. */
5
6
  export declare function createCommandPage(host: TerminalCommandHost, id: CommandPageId, options?: {
6
7
  runId?: string;
8
+ url?: string;
9
+ annotate?: AnnotateStart;
10
+ usageTab?: 'analysis' | 'limit';
11
+ usagePeriod?: 'today' | '7d' | '30d' | 'all';
12
+ close?(): void;
7
13
  }): TerminalPage;
@@ -1,18 +1,24 @@
1
1
  import { DoctorPage } from "./pages/doctorPage.js";
2
2
  import { AccountsPage } from "./pages/accountsPage.js";
3
- import { ComponentsPage } from "./pages/componentsPage.js";
4
- import { HubPage } from "./pages/hubPage.js";
3
+ import { BrowserPage } from "./pages/browserPage.js";
5
4
  import { LogPage, formatRunEventLog } from "./pages/logPage.js";
6
5
  import { PermissionsPage } from "./pages/permissionsPage.js";
7
- import { PluginsPage } from "./pages/pluginsPage.js";
8
6
  import { SettingsPage } from "./pages/settingsPage.js";
9
7
  import { TrajectoryPage } from "./pages/trajectoryPage.js";
8
+ import { WorktreesPage } from "./pages/worktreesPage.js";
9
+ import { NotesPage } from "./pages/notesPage.js";
10
+ import { AnnotatePage } from "./pages/annotatePage.js";
11
+ import { SubagentsPage } from "./pages/subagentsPage.js";
12
+ import { AgentsPage } from "./pages/agentsPage.js";
13
+ import { UsagePage } from "./pages/usagePage.js";
10
14
  import { createSettingsModel } from "./settingsModel.js";
11
15
  /** Construct one independent full-screen page for a slash command. */
12
16
  export function createCommandPage(host, id, options = {}) {
13
17
  const theme = () => host.ui.theme;
14
18
  const notify = (message, type) => host.ui.notify(message, type === 'error' || type === 'warning' ? type : 'info');
15
19
  switch (id) {
20
+ case 'usage':
21
+ return new UsagePage({ theme, call: host.control, changed: host.changed, initialTab: options.usageTab === 'limit' ? 'limits' : 'analysis', ...(options.usagePeriod ? { initialPeriod: options.usagePeriod } : {}) });
16
22
  case 'doctor':
17
23
  return new DoctorPage({ theme, call: host.control, confirm: host.ui.confirm.bind(host.ui), select: host.ui.select.bind(host.ui), changed: host.changed,
18
24
  selection: () => {
@@ -34,12 +40,50 @@ export function createCommandPage(host, id, options = {}) {
34
40
  activeTools: () => host.session().getActiveToolNames(),
35
41
  confirm: (title, message) => host.ui.confirm(title, message), notify, changed: host.changed
36
42
  });
43
+ case 'harness':
44
+ case 'skills':
45
+ case 'connections':
46
+ case 'tools':
37
47
  case 'plugins':
38
- return new PluginsPage({ theme, call: host.control, ui: host.ui, changed: host.changed });
39
48
  case 'hub':
40
- return new HubPage({ theme, call: host.control, ui: host.ui, changed: host.changed });
41
49
  case 'components':
42
- return new ComponentsPage({ theme, call: host.control, ui: host.ui, notify, changed: host.changed });
50
+ return new BrowserPage({
51
+ theme, call: host.control, changed: host.changed,
52
+ section: id === 'harness' || id === 'hub' ? 'overview' : id === 'components' ? 'library' : id,
53
+ source: id === 'hub' ? 'discover' : 'installed',
54
+ ui: {
55
+ select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui),
56
+ secretInput: (title, placeholder) => {
57
+ const ui = host.ui;
58
+ if (!ui.secretInput)
59
+ throw new Error('Masked credential entry is unavailable in this host.');
60
+ return ui.secretInput(title, placeholder);
61
+ }
62
+ },
63
+ runtime: () => ({ skills: host.session().resourceLoader.getSkills().skills,
64
+ tools: host.session().getAllTools(), activeTools: host.session().getActiveToolNames(), skillCommands: host.session().settingsManager.getEnableSkillCommands() }),
65
+ permissions: () => host.runtime().permissions(), setGlobalTool: (tool, allowed) => host.runtime().setGlobalTool(tool, allowed),
66
+ useSkill: name => {
67
+ const draft = host.ui.getEditorText();
68
+ host.setEditorText(`$${name}${draft ? ' ' + draft : ' '}`);
69
+ options.close?.();
70
+ }
71
+ });
72
+ case 'worktree':
73
+ return new WorktreesPage({
74
+ theme, call: host.control, changed: host.changed, relaunch: host.shutdown,
75
+ ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
76
+ });
77
+ case 'notes':
78
+ return new NotesPage({
79
+ theme, call: host.control, changed: host.changed, ...(options.url !== undefined ? { start: options.url ? { url: options.url } : {} } : {}),
80
+ ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
81
+ });
82
+ case 'annotate':
83
+ return new AnnotatePage({
84
+ theme, call: host.control, changed: host.changed, start: options.annotate ?? { kind: 'web' },
85
+ ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
86
+ });
43
87
  case 'settings':
44
88
  return new SettingsPage({ theme, ...createSettingsModel(host), notify, changed: host.changed });
45
89
  case 'trajectory':
@@ -47,6 +91,13 @@ export function createCommandPage(host, id, options = {}) {
47
91
  theme, runs: host.trajectory.list, read: host.trajectory.read, copy: host.copyText,
48
92
  initialRunId: options.runId || undefined, notify, changed: host.changed
49
93
  });
94
+ case 'subagents':
95
+ return new SubagentsPage({ theme, snapshot: host.subagents, changed: host.changed });
96
+ case 'agents':
97
+ return new AgentsPage({
98
+ theme, call: host.control, changed: host.changed, ...(host.editFile ? { edit: host.editFile.bind(host) } : {}),
99
+ ui: { select: host.ui.select.bind(host.ui), confirm: host.ui.confirm.bind(host.ui), notify: host.ui.notify.bind(host.ui), input: host.ui.input.bind(host.ui) }
100
+ });
50
101
  case 'log':
51
102
  return new LogPage({
52
103
  theme, changed: host.changed,
@@ -2,6 +2,10 @@ import { type AgentSession, type ExtensionUIContext } from '@earendil-works/pi-c
2
2
  import { type SkillEntry } from "./skillInvocation.js";
3
3
  import type { TerminalRuntime } from "./runtime.js";
4
4
  import type { TerminalTrajectoryRun, TerminalTrajectorySnapshot } from "../trajectory.js";
5
+ import type { TerminalSubagentActivity } from "../subagentMonitor.js";
6
+ import { type TerminalCommandCompletion, type TerminalCommandHelpGroup } from "../commandHelp.js";
7
+ export type { TerminalCommandCompletion } from "../commandHelp.js";
8
+ export { parseAnnotate } from "./pluginCommands.js";
5
9
  export interface TerminalCommandHost {
6
10
  session(): AgentSession;
7
11
  /** Navigation is scope checked by the Harness runtime adapter. */
@@ -11,9 +15,11 @@ export interface TerminalCommandHost {
11
15
  control: <T = unknown>(method: string, params?: Record<string, unknown>) => Promise<T>;
12
16
  ui: ExtensionUIContext;
13
17
  cwd(): string;
18
+ branch(): string | null;
14
19
  sessionDirectory(): string;
15
20
  refresh(): void;
16
21
  changed(): void;
22
+ showHelp(groups: TerminalCommandHelpGroup[]): void;
17
23
  plan(brief: string): void;
18
24
  /** Asks a side question in its own tool-free session; empty text dismisses the one showing. */
19
25
  btw(question: string): Promise<void>;
@@ -21,22 +27,22 @@ export interface TerminalCommandHost {
21
27
  setEditorText(text: string): void;
22
28
  copyText(text: string): Promise<void>;
23
29
  suspend?(): Promise<void>;
30
+ /** Opens a file in the person's editor and resolves once the editor closes. */
31
+ editFile?(path: string): Promise<void>;
24
32
  hotkeys?(): string;
25
33
  logs: {
26
34
  read(): Promise<string>;
27
35
  };
36
+ subagents(): readonly TerminalSubagentActivity[];
28
37
  trajectory: {
29
38
  list(): Promise<TerminalTrajectoryRun[]>;
30
39
  read(runId: string, afterSequence?: number): Promise<TerminalTrajectorySnapshot>;
31
40
  };
32
41
  }
33
- export interface TerminalCommandCompletion {
34
- name: string;
35
- description?: string;
36
- }
37
42
  export declare function createTerminalCommands(host: TerminalCommandHost): {
38
43
  execute: (text: string) => Promise<boolean>;
39
44
  completions: () => TerminalCommandCompletion[];
40
45
  skills: () => SkillEntry[];
41
46
  expandSkill: (text: string) => string;
47
+ legacyAliases: () => string[];
42
48
  };
@@ -1,41 +1,34 @@
1
1
  import { isAbsolute, relative, resolve } from 'node:path';
2
2
  import { SessionManager } from '@earendil-works/pi-coding-agent';
3
+ import { CORE_COMMANDS, coreCommand } from "../../commands/registry.js";
4
+ import { commandRoutes, promptCommandAvailable } from "../../commands/routes.js";
5
+ import { BUILTIN_PLUGIN_REGISTRY } from "../../plugins/builtin.js";
6
+ import { pluginCommandPrefix } from "../../plugins/commandPrefix.js";
3
7
  import { PageOverlay } from "./pageOverlay.js";
4
8
  import { ModelPicker } from "./modelPicker.js";
5
9
  import { TreePicker } from "./treePicker.js";
6
10
  import { createCommandPage } from "./commandPages.js";
7
11
  import { pageOverlayOptions } from "./dialogGeometry.js";
12
+ import { ResumeSessionsPage } from "./sessionPicker.js";
8
13
  import { expandSkillInvocation } from "./skillInvocation.js";
9
- const BUILTINS = [
10
- { name: 'doctor', description: 'Check account, model, tools and runtime readiness' },
11
- { name: 'help', description: 'List the commands' },
12
- { name: 'plan', description: 'Plan one request, read-only: /plan <brief>' },
13
- { name: 'btw', description: 'Ask a side question without interrupting: /btw <question>' },
14
- { name: 'new', description: 'Start a new session' },
15
- { name: 'stop', description: 'Stop the current reply' },
16
- { name: 'resume', description: 'Resume a session in this account and folder' },
17
- { name: 'tree', description: 'Navigate the session tree' },
18
- { name: 'fork', description: 'Fork from an earlier message' },
19
- { name: 'clone', description: 'Clone this branch into a new session' },
20
- { name: 'model', description: 'Choose the model' },
21
- { name: 'effort', description: 'Choose the thinking effort' },
22
- { name: 'thinking', description: 'Toggle transcript thinking visibility: /thinking [show|hide]' },
23
- { name: 'name', description: 'Name this session' },
24
- { name: 'compact', description: 'Compact the context' },
25
- { name: 'copy', description: 'Copy the last reply' },
26
- { name: 'export', description: 'Export this branch to HTML or JSONL' },
27
- { name: 'reload', description: 'Reload trusted resources and keybindings' },
28
- { name: 'accounts', description: 'Sign in, switch, check and remove Pi accounts' },
29
- { name: 'permissions', description: 'Full Permission and per-tool approvals' },
30
- { name: 'plugins', description: 'Switch plugins on or off and trust their code' },
31
- { name: 'hub', description: 'Browse and install reviewed skills, plugins and documents' },
32
- { name: 'components', description: 'Browse skills, prompts and rules for this Harness scope' },
33
- { name: 'settings', description: 'Session and terminal settings' },
34
- { name: 'trajectory', description: 'Inspect the recorded runs of this session' },
35
- { name: 'log', description: "Harness diagnostics and this conversation's run events" },
36
- { name: 'hotkeys', description: 'Keyboard controls' },
37
- { name: 'quit', description: 'Restore the terminal and exit' }
38
- ];
14
+ import { groupTerminalCommands } from "../commandHelp.js";
15
+ import { createBuiltinPluginCommandHandlers } from "./pluginCommands.js";
16
+ export { parseAnnotate } from "./pluginCommands.js";
17
+ const BUILTINS = CORE_COMMANDS.map((command) => ({
18
+ name: command.name,
19
+ ...('aliases' in command ? { aliases: [...command.aliases] } : {}),
20
+ description: command.description,
21
+ group: command.group
22
+ }));
23
+ const COMMAND_ALIASES = new Map(BUILTINS.flatMap(command => (command.aliases ?? []).map(alias => [alias, command.name])));
24
+ const CORE_PROMPT_NAMES = new Set([...BUILTINS.map(command => command.name), ...COMMAND_ALIASES.keys()]);
25
+ const LEGACY_BUILTIN_COMMAND_ALIASES = new Map([
26
+ ['doctor:doctor', 'doctor'], ['plugin:doctor', 'doctor'],
27
+ ['worktrees:worktree', 'worktree'], ['plugin:worktree', 'worktree'],
28
+ ['history:trajectory', 'trajectory'], ['plugin:trajectory', 'trajectory'],
29
+ ['subagents:subagents', 'subagents'], ['plugin:subagents', 'subagents'],
30
+ ['subagents:agents', 'agents'], ['plugin:agents', 'agents']
31
+ ]);
39
32
  export function createTerminalCommands(host) {
40
33
  const notify = (text) => host.ui.notify(text, 'info');
41
34
  const choose = async (title, items, label) => {
@@ -43,19 +36,6 @@ export function createTerminalCommands(host) {
43
36
  const selected = await host.ui.select(title, labels);
44
37
  return selected === undefined ? undefined : items[labels.indexOf(selected)];
45
38
  };
46
- const completions = () => {
47
- const session = host.session();
48
- const commands = new Map(BUILTINS.map(command => [command.name, command]));
49
- for (const command of session.extensionRunner.getRegisteredCommands()) {
50
- if (!commands.has(command.name))
51
- commands.set(command.name, { name: command.name, description: command.description });
52
- }
53
- for (const prompt of session.resourceLoader.getPrompts().prompts) {
54
- if (!commands.has(prompt.name))
55
- commands.set(prompt.name, { name: prompt.name, description: prompt.description });
56
- }
57
- return [...commands.values()];
58
- };
59
39
  /** The skills this session may be asked to use, each invoked as `$name`. Off with the "Skill commands" setting. */
60
40
  const skills = () => {
61
41
  const session = host.session();
@@ -66,31 +46,223 @@ export function createTerminalCommands(host) {
66
46
  /** The text to send: a leading `$name` of a loaded skill becomes the `/skill:name` form Pi expands. */
67
47
  const expandSkill = (text) => expandSkillInvocation(text, new Set(skills().map((skill) => skill.name)));
68
48
  async function openPage(id, options = {}) {
69
- await host.ui.custom((tui, _theme, _keys, done) => new PageOverlay({
70
- page: createCommandPage(host, id, options), tui, theme: () => host.ui.theme,
71
- close: () => done(undefined), changed: host.changed
72
- }), { overlay: true, overlayOptions: pageOverlayOptions() });
49
+ let close = () => { };
50
+ const page = createCommandPage(host, id, { ...options, close: () => close() });
51
+ await host.ui.custom((tui, _theme, _keys, done) => {
52
+ close = () => done(undefined);
53
+ return new PageOverlay({ page, tui, theme: () => host.ui.theme, close, changed: host.changed });
54
+ }, { overlay: true, overlayOptions: pageOverlayOptions(page.presentation) });
73
55
  }
56
+ const pluginHandlers = createBuiltinPluginCommandHandlers(host, openPage);
57
+ const pluginCommands = BUILTIN_PLUGIN_REGISTRY.commands();
58
+ const builtinPrefixes = new Map(pluginCommands.map(command => [command.prefix, command.pluginId]));
59
+ const prefixCache = new WeakMap();
60
+ const extensionCommands = () => {
61
+ return commandRoutes(host.session().extensionRunner.getRegisteredCommands().map(command => {
62
+ const source = command.sourceInfo;
63
+ let prefix = prefixCache.get(source);
64
+ if (!prefix) {
65
+ prefix = pluginCommandPrefix(source);
66
+ prefixCache.set(source, prefix);
67
+ }
68
+ const owner = source.origin === 'package'
69
+ ? `package:${source.baseDir ?? source.source}`
70
+ : `extension:${source.path}`;
71
+ return { ...command, prefix, owner, path: source.path };
72
+ }));
73
+ };
74
+ const coreCommandNames = (session) => new Set([
75
+ ...BUILTINS.flatMap(command => [command.name, ...(command.aliases ?? [])]),
76
+ ...session.resourceLoader.getPrompts().prompts.map(prompt => prompt.name)
77
+ ]);
78
+ const runBuiltinPluginCommand = async (command, argument) => {
79
+ try {
80
+ const handler = pluginHandlers.get(`${command.pluginId}:${command.name}`);
81
+ if (!handler)
82
+ throw new Error(`No terminal handler for built-in plugin command ${command.pluginId}:${command.name}.`);
83
+ await handler(argument);
84
+ host.refresh();
85
+ }
86
+ catch (error) {
87
+ host.ui.notify(error instanceof Error ? error.message : String(error), 'error');
88
+ }
89
+ };
90
+ const runExtensionCommand = async (registered, argument, route) => {
91
+ try {
92
+ const command = host.session().extensionRunner.getCommand(registered.invocationName);
93
+ if (!command)
94
+ throw new Error(`Plugin command /${route} is no longer registered. Reload trusted resources.`);
95
+ await command.handler(argument, host.session().extensionRunner.createCommandContext());
96
+ host.refresh();
97
+ }
98
+ catch (error) {
99
+ host.ui.notify(error instanceof Error ? error.message : String(error), 'error');
100
+ }
101
+ };
102
+ const runLegacyPluginCommand = async (name, argument) => {
103
+ const session = host.session();
104
+ if (coreCommandNames(session).has(name)) {
105
+ host.ui.notify(`Use /${name}; /plugin:${name} is unavailable because a core command or prompt already uses that name.`, 'error');
106
+ return;
107
+ }
108
+ const builtins = BUILTIN_PLUGIN_REGISTRY.commandsNamed(name);
109
+ const extensions = extensionCommands();
110
+ if (builtins.length > 1) {
111
+ host.ui.notify(`Legacy plugin command /plugin:${name} is ambiguous. Use its owner-qualified command.`, 'error');
112
+ return;
113
+ }
114
+ if (builtins.length === 1) {
115
+ const competitors = extensions.byName.get(name) ?? [];
116
+ if (competitors.length) {
117
+ host.ui.notify(`Extension command /plugin:${name} from ${competitors.map(command => command.sourceInfo.path).join(', ')} is unavailable because the name belongs to the built-in ${builtins[0].pluginId} plugin.`, 'error');
118
+ }
119
+ await runBuiltinPluginCommand(builtins[0], argument);
120
+ return;
121
+ }
122
+ const matches = extensions.byName.get(name) ?? [];
123
+ if (matches.length > 1) {
124
+ host.ui.notify(`Legacy plugin command /plugin:${name} is ambiguous. Registered by: ${matches.map(command => command.sourceInfo.path).join(', ')}. Use its owner-qualified command.`, 'error');
125
+ return;
126
+ }
127
+ if (matches.length === 1) {
128
+ if (extensions.conflictingPrefixes.has(matches[0].prefix)) {
129
+ host.ui.notify(`Plugin prefix /${matches[0].prefix}: is ambiguous or reserved. Owners: ${extensions.conflictingPrefixes.get(matches[0].prefix).join(', ')}.`, 'error');
130
+ return;
131
+ }
132
+ await runExtensionCommand(matches[0], argument, `plugin:${name}`);
133
+ return;
134
+ }
135
+ host.ui.notify(`Unknown plugin command: /plugin:${name}. Use /help to list the commands.`, 'error');
136
+ };
137
+ const runNamespacedCommand = async (typedName, argument) => {
138
+ const separator = typedName.indexOf(':');
139
+ if (separator < 1)
140
+ return false;
141
+ const prefix = typedName.slice(0, separator);
142
+ const name = typedName.slice(separator + 1);
143
+ if (prefix === 'plugin') {
144
+ await runLegacyPluginCommand(name, argument);
145
+ return true;
146
+ }
147
+ const builtin = name ? BUILTIN_PLUGIN_REGISTRY.command(prefix, name) : BUILTIN_PLUGIN_REGISTRY.defaultCommand(prefix);
148
+ const extensions = extensionCommands();
149
+ const isBuiltinPrefix = builtinPrefixes.has(prefix);
150
+ const isExtensionPrefix = extensions.ownersByPrefix.has(prefix);
151
+ if (!builtin && !isBuiltinPrefix && !isExtensionPrefix)
152
+ return false;
153
+ if (builtin) {
154
+ const competitors = extensions.routes.get(`${prefix}:${builtin.name}`) ?? [];
155
+ if (competitors.length) {
156
+ host.ui.notify(`Extension command /${prefix}:${builtin.name} from ${competitors.map(command => command.sourceInfo.path).join(', ')} is unavailable because the prefix belongs to built-in ${builtin.pluginId}.`, 'error');
157
+ }
158
+ await runBuiltinPluginCommand(builtin, argument);
159
+ return true;
160
+ }
161
+ if (extensions.conflictingPrefixes.has(prefix)) {
162
+ host.ui.notify(`Plugin prefix /${prefix}: is ambiguous or reserved. Owners: ${extensions.conflictingPrefixes.get(prefix).join(', ')}.`, 'error');
163
+ return true;
164
+ }
165
+ if (!name) {
166
+ host.ui.notify(`Plugin /${prefix}: has no default command. Use /help to list its commands.`, 'error');
167
+ return true;
168
+ }
169
+ const matches = extensions.routes.get(`${prefix}:${name}`) ?? [];
170
+ if (matches.length > 1) {
171
+ host.ui.notify(`Plugin command /${prefix}:${name} is ambiguous. Registered by: ${matches.map(command => command.sourceInfo.path).join(', ')}.`, 'error');
172
+ return true;
173
+ }
174
+ if (matches.length === 1) {
175
+ await runExtensionCommand(matches[0], argument, `${prefix}:${name}`);
176
+ return true;
177
+ }
178
+ host.ui.notify(`Unknown plugin command: /${typedName}. Use /help to list the commands.`, 'error');
179
+ return true;
180
+ };
181
+ const legacyAliases = () => {
182
+ const session = host.session();
183
+ const coreNames = coreCommandNames(session);
184
+ const aliases = new Set(LEGACY_BUILTIN_COMMAND_ALIASES.keys());
185
+ for (const command of pluginCommands) {
186
+ if (coreNames.has(command.name))
187
+ continue;
188
+ aliases.add(`plugin:${command.name}`);
189
+ if (command.legacyBare)
190
+ aliases.add(command.name);
191
+ }
192
+ for (const name of extensionCommands().byName.keys()) {
193
+ if (!coreNames.has(name))
194
+ aliases.add(`plugin:${name}`);
195
+ }
196
+ return [...aliases];
197
+ };
198
+ const completions = () => {
199
+ const session = host.session();
200
+ const prompts = session.resourceLoader.getPrompts().prompts;
201
+ const commands = new Map(BUILTINS.map(command => [command.name, command]));
202
+ for (const command of pluginCommands) {
203
+ const invocation = `${command.prefix}:${command.name}`;
204
+ commands.set(invocation, { name: invocation, description: command.description, group: 'Plugins' });
205
+ }
206
+ for (const module of BUILTIN_PLUGIN_REGISTRY.modules) {
207
+ const defaultCommand = module.defaultCommand && BUILTIN_PLUGIN_REGISTRY.command(module.commandPrefix ?? module.descriptor.id, module.defaultCommand);
208
+ if (defaultCommand) {
209
+ const invocation = `${defaultCommand.prefix}:`;
210
+ commands.set(invocation, { name: invocation, description: defaultCommand.description, group: 'Plugins' });
211
+ }
212
+ }
213
+ const extensions = extensionCommands();
214
+ for (const [route, matches] of extensions.routes) {
215
+ const prefix = route.slice(0, route.indexOf(':'));
216
+ if (matches.length !== 1 || extensions.conflictingPrefixes.has(prefix))
217
+ continue;
218
+ if (BUILTIN_PLUGIN_REGISTRY.command(prefix, matches[0].name))
219
+ continue;
220
+ commands.set(route, { name: route, description: matches[0].description, group: 'Plugins' });
221
+ }
222
+ const extensionNames = new Set(extensions.byName.keys());
223
+ for (const prompt of prompts) {
224
+ if (promptCommandAvailable(prompt.name, new Set([...commands.keys(), ...COMMAND_ALIASES.keys()]), extensionNames))
225
+ commands.set(prompt.name, { name: prompt.name, description: prompt.description, group: 'Prompts' });
226
+ }
227
+ return [...commands.values()];
228
+ };
74
229
  async function execute(text) {
75
230
  const match = /^\/([^\s]+)(?:\s+([\s\S]*))?$/.exec(text.trim());
76
231
  if (!match)
77
232
  return false;
78
- const name = match[1];
233
+ const typedName = match[1];
79
234
  const argument = match[2]?.trim() ?? '';
80
- if (!BUILTINS.some(item => item.name === name)) {
81
- if (completions().some(item => item.name === name))
82
- return false;
235
+ const legacyBuiltin = LEGACY_BUILTIN_COMMAND_ALIASES.get(typedName);
236
+ if (!legacyBuiltin && await runNamespacedCommand(typedName, argument))
237
+ return true;
238
+ const session = host.session();
239
+ const name = coreCommand(legacyBuiltin ?? typedName)?.name ?? legacyBuiltin ?? typedName;
240
+ const builtin = BUILTINS.find(item => item.name === name);
241
+ if (!builtin && !coreCommandNames(session).has(name)) {
242
+ const legacyBare = BUILTIN_PLUGIN_REGISTRY.commandsNamed(name).filter(command => command.legacyBare);
243
+ if (legacyBare.length > 1) {
244
+ host.ui.notify(`Legacy command /${name} is ambiguous. Use its owner-qualified command.`, 'error');
245
+ return true;
246
+ }
247
+ if (legacyBare.length === 1) {
248
+ await runBuiltinPluginCommand(legacyBare[0], argument);
249
+ return true;
250
+ }
251
+ }
252
+ if (!builtin) {
83
253
  // A skill is offered as $name; the typed /skill:name form still reaches the SDK, which expands it.
84
254
  if (skills().some(skill => `skill:${skill.name}` === name))
85
255
  return false;
256
+ const prompt = session.resourceLoader.getPrompts().prompts.some(item => item.name === name);
257
+ if (prompt && promptCommandAvailable(name, CORE_PROMPT_NAMES, new Set(extensionCommands().byName.keys())))
258
+ return false;
86
259
  host.ui.notify(`Unknown command: /${name}. Use /help to list commands.`, 'error');
87
260
  return true;
88
261
  }
89
262
  try {
90
- const session = host.session();
91
263
  switch (name) {
92
264
  case 'help':
93
- notify(completions().map(item => `/${item.name} ${item.description ?? ''}`).join('\n'));
265
+ host.showHelp(groupTerminalCommands(completions()));
94
266
  break;
95
267
  case 'plan': {
96
268
  if (!argument || ['on', 'off', 'toggle'].includes(argument.toLowerCase()))
@@ -105,7 +277,7 @@ export function createTerminalCommands(host) {
105
277
  await host.btw(argument);
106
278
  break;
107
279
  case 'stop': {
108
- if (!session.isStreaming)
280
+ if (session.isIdle)
109
281
  throw new Error('Nothing is running.');
110
282
  await host.runtime().interrupt();
111
283
  break;
@@ -113,14 +285,24 @@ export function createTerminalCommands(host) {
113
285
  case 'new':
114
286
  await host.runtime().newSession();
115
287
  break;
116
- case 'resume': {
288
+ case 'session': {
117
289
  let path = argument;
118
290
  if (!path) {
119
- const sessions = await SessionManager.list(host.cwd(), host.sessionDirectory());
120
- const selected = await choose('Resume session', sessions, (item, index) => `${index + 1}. ${item.name ?? item.firstMessage ?? item.id} ${item.modified.toLocaleString()}`);
291
+ const selected = await host.ui.custom((tui, _theme, _keys, done) => {
292
+ const page = new ResumeSessionsPage({
293
+ theme: () => host.ui.theme,
294
+ cwd: () => host.cwd(),
295
+ branch: () => host.branch(),
296
+ listSessions: signal => SessionManager.list(host.cwd(), host.sessionDirectory(), undefined, signal),
297
+ select: done,
298
+ cancel: () => done(undefined),
299
+ changed: host.changed
300
+ });
301
+ return new PageOverlay({ page, tui, theme: () => host.ui.theme, close: () => done(undefined), changed: host.changed });
302
+ }, { overlay: true, overlayOptions: pageOverlayOptions('fullscreen') });
121
303
  if (!selected)
122
304
  break;
123
- path = selected.path;
305
+ path = selected;
124
306
  }
125
307
  const target = resolve(host.cwd(), path);
126
308
  const within = relative(host.sessionDirectory(), target);
@@ -150,7 +332,7 @@ export function createTerminalCommands(host) {
150
332
  }
151
333
  break;
152
334
  }
153
- case 'tree': {
335
+ case 'history': {
154
336
  const tree = session.sessionManager.getTree();
155
337
  if (!tree.length)
156
338
  throw new Error('No entries in this session');
@@ -205,11 +387,23 @@ export function createTerminalCommands(host) {
205
387
  await session.setModel(selected.model, { persist: selected.persist });
206
388
  break;
207
389
  }
390
+ case 'settings':
391
+ await openPage('settings');
392
+ break;
208
393
  case 'doctor':
209
394
  await openPage('doctor');
210
395
  break;
211
- case 'settings':
212
- await openPage('settings');
396
+ case 'worktree':
397
+ await openPage('worktree');
398
+ break;
399
+ case 'trajectory':
400
+ await openPage('trajectory', { runId: argument });
401
+ break;
402
+ case 'subagents':
403
+ await openPage('subagents');
404
+ break;
405
+ case 'agents':
406
+ await openPage('agents');
213
407
  break;
214
408
  case 'permissions':
215
409
  await openPage('permissions');
@@ -217,6 +411,19 @@ export function createTerminalCommands(host) {
217
411
  case 'accounts':
218
412
  await openPage('accounts');
219
413
  break;
414
+ case 'harness':
415
+ await openPage('harness');
416
+ break;
417
+ case 'skills':
418
+ await openPage('skills');
419
+ break;
420
+ case 'connections':
421
+ case 'mcp':
422
+ await openPage('connections');
423
+ break;
424
+ case 'tools':
425
+ await openPage('tools');
426
+ break;
220
427
  case 'plugins':
221
428
  await openPage('plugins');
222
429
  break;
@@ -232,9 +439,6 @@ export function createTerminalCommands(host) {
232
439
  session.setSessionName(name);
233
440
  break;
234
441
  }
235
- case 'trajectory':
236
- await openPage('trajectory', { runId: argument });
237
- break;
238
442
  case 'log':
239
443
  await openPage('log');
240
444
  break;
@@ -272,5 +476,5 @@ export function createTerminalCommands(host) {
272
476
  }
273
477
  return true;
274
478
  }
275
- return { execute, completions, skills, expandSkill };
479
+ return { execute, completions, skills, expandSkill, legacyAliases };
276
480
  }
@@ -23,5 +23,5 @@ export declare function centeredDialogHost(tui: TUI): boolean;
23
23
  export declare function pageRows(tui: TUI): number;
24
24
  /** Centers a rectangle on the screen, clamped so it never starts outside the terminal. */
25
25
  export declare function centeredRect(columns: number, rows: number, width: number, height: number): DialogRect;
26
- /** The overlay options every full-screen page command passes; OpenTUI reads the marker. */
27
- export declare function pageOverlayOptions(): HarnessOverlayOptions;
26
+ /** Page commands declare their presentation; OpenTUI centers only marked dialogs. */
27
+ export declare function pageOverlayOptions(presentation?: 'centered' | 'fullscreen'): HarnessOverlayOptions;