@xingular/harness 0.1.7 → 1.0.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 (683) hide show
  1. package/CHANGELOG.md +97 -1
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +22 -0
  4. package/README.md +187 -85
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +13701 -13498
  7. package/dist/sdk/accounts/accounts.d.ts +165 -0
  8. package/dist/sdk/accounts/accounts.js +730 -0
  9. package/dist/sdk/accounts/choices.d.ts +23 -0
  10. package/dist/sdk/accounts/choices.js +62 -0
  11. package/dist/sdk/accounts/env.d.ts +78 -0
  12. package/dist/sdk/accounts/env.js +294 -0
  13. package/dist/sdk/accounts/secrets.d.ts +16 -0
  14. package/dist/sdk/accounts/secrets.js +40 -0
  15. package/dist/sdk/accounts/store.d.ts +114 -0
  16. package/dist/sdk/accounts/store.js +255 -0
  17. package/dist/sdk/browser/config.d.ts +16 -0
  18. package/dist/sdk/browser/config.js +22 -0
  19. package/dist/sdk/browser/diagnostics.d.ts +4 -0
  20. package/dist/sdk/browser/diagnostics.js +38 -0
  21. package/dist/sdk/browser/index.d.ts +17 -0
  22. package/dist/sdk/browser/index.js +65 -0
  23. package/dist/sdk/browser/network.d.ts +10 -0
  24. package/dist/sdk/browser/network.js +59 -0
  25. package/dist/sdk/browser/session.d.ts +84 -0
  26. package/dist/sdk/browser/session.js +192 -0
  27. package/dist/sdk/browser/tools.d.ts +8 -0
  28. package/dist/sdk/browser/tools.js +329 -0
  29. package/dist/sdk/capabilities/api.d.ts +22 -0
  30. package/dist/sdk/capabilities/api.js +54 -0
  31. package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
  32. package/dist/sdk/capabilities/runSnapshot.js +47 -0
  33. package/dist/sdk/capabilities/types.d.ts +29 -0
  34. package/dist/sdk/capabilities/types.js +1 -0
  35. package/dist/sdk/cli.d.ts +2 -0
  36. package/dist/sdk/cli.js +142 -0
  37. package/dist/sdk/core/bus.d.ts +23 -0
  38. package/dist/sdk/core/bus.js +76 -0
  39. package/dist/sdk/core/caller.d.ts +22 -0
  40. package/dist/sdk/core/caller.js +16 -0
  41. package/dist/sdk/core/changes.d.ts +15 -0
  42. package/dist/sdk/core/changes.js +15 -0
  43. package/dist/sdk/core/effort.d.ts +2 -0
  44. package/dist/sdk/core/effort.js +1 -0
  45. package/dist/sdk/core/env.d.ts +18 -0
  46. package/dist/sdk/core/env.js +8 -0
  47. package/dist/sdk/core/errors.d.ts +15 -0
  48. package/dist/sdk/core/errors.js +24 -0
  49. package/dist/sdk/core/frontmatter.d.ts +12 -0
  50. package/dist/sdk/core/frontmatter.js +50 -0
  51. package/dist/sdk/core/fs.d.ts +18 -0
  52. package/dist/sdk/core/fs.js +106 -0
  53. package/dist/sdk/core/index.d.ts +24 -0
  54. package/dist/sdk/core/index.js +187 -0
  55. package/dist/sdk/core/path.d.ts +7 -0
  56. package/dist/sdk/core/path.js +79 -0
  57. package/dist/sdk/core/projects.d.ts +18 -0
  58. package/dist/sdk/core/projects.js +67 -0
  59. package/dist/sdk/core/secrets.d.ts +2 -0
  60. package/dist/sdk/core/secrets.js +5 -0
  61. package/dist/sdk/core/text.d.ts +7 -0
  62. package/dist/sdk/core/text.js +40 -0
  63. package/dist/sdk/doctor/checks.d.ts +5 -0
  64. package/dist/sdk/doctor/checks.js +208 -0
  65. package/dist/sdk/doctor/probe.d.ts +4 -0
  66. package/dist/sdk/doctor/probe.js +92 -0
  67. package/dist/sdk/doctor/service.d.ts +23 -0
  68. package/dist/sdk/doctor/service.js +144 -0
  69. package/dist/sdk/doctor/types.d.ts +141 -0
  70. package/dist/sdk/doctor/types.js +29 -0
  71. package/dist/sdk/harness.d.ts +133 -0
  72. package/dist/sdk/harness.js +299 -0
  73. package/dist/sdk/history/lessonPrompt.d.ts +2 -0
  74. package/dist/sdk/history/lessonPrompt.js +15 -0
  75. package/dist/sdk/history/lessons.d.ts +52 -0
  76. package/dist/sdk/history/lessons.js +173 -0
  77. package/dist/sdk/history/recall.d.ts +68 -0
  78. package/dist/sdk/history/recall.js +199 -0
  79. package/dist/sdk/history/trajectory.d.ts +7 -0
  80. package/dist/sdk/history/trajectory.js +216 -0
  81. package/dist/sdk/hub/catalog.json +123 -0
  82. package/dist/sdk/hub/cli.d.ts +7 -0
  83. package/dist/sdk/hub/cli.js +81 -0
  84. package/dist/sdk/hub/hub.d.ts +74 -0
  85. package/dist/sdk/hub/hub.js +474 -0
  86. package/dist/sdk/hub/schema.d.ts +280 -0
  87. package/dist/sdk/hub/schema.js +78 -0
  88. package/dist/sdk/index.d.ts +63 -0
  89. package/dist/sdk/index.js +48 -0
  90. package/dist/sdk/mcp/connections.d.ts +83 -0
  91. package/dist/sdk/mcp/connections.js +669 -0
  92. package/dist/sdk/mcp/manager.d.ts +26 -0
  93. package/dist/sdk/mcp/manager.js +124 -0
  94. package/dist/sdk/mcp/oauth.d.ts +35 -0
  95. package/dist/sdk/mcp/oauth.js +171 -0
  96. package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
  97. package/dist/sdk/mcp/scopeMigration.js +198 -0
  98. package/dist/sdk/mcp/service.d.ts +160 -0
  99. package/dist/sdk/mcp/service.js +510 -0
  100. package/dist/sdk/mcp/types.d.ts +131 -0
  101. package/dist/sdk/mcp/types.js +49 -0
  102. package/dist/sdk/pi/runtime.d.ts +13 -0
  103. package/dist/sdk/pi/runtime.js +31 -0
  104. package/dist/sdk/plugins/api.d.ts +66 -0
  105. package/dist/sdk/plugins/api.js +155 -0
  106. package/dist/sdk/plugins/attachments.d.ts +46 -0
  107. package/dist/sdk/plugins/attachments.js +111 -0
  108. package/dist/sdk/plugins/builtin.d.ts +6 -0
  109. package/dist/sdk/plugins/builtin.js +68 -0
  110. package/dist/sdk/plugins/catalogue.d.ts +29 -0
  111. package/dist/sdk/plugins/catalogue.js +196 -0
  112. package/dist/sdk/plugins/cli.d.ts +13 -0
  113. package/dist/sdk/plugins/cli.js +187 -0
  114. package/dist/sdk/plugins/discover.d.ts +42 -0
  115. package/dist/sdk/plugins/discover.js +115 -0
  116. package/dist/sdk/plugins/firstParty.d.ts +50 -0
  117. package/dist/sdk/plugins/firstParty.js +113 -0
  118. package/dist/sdk/plugins/hooks.d.ts +94 -0
  119. package/dist/sdk/plugins/hooks.js +162 -0
  120. package/dist/sdk/plugins/identity.d.ts +19 -0
  121. package/dist/sdk/plugins/identity.js +48 -0
  122. package/dist/sdk/plugins/install.d.ts +20 -0
  123. package/dist/sdk/plugins/install.js +110 -0
  124. package/dist/sdk/plugins/inventory.d.ts +22 -0
  125. package/dist/sdk/plugins/inventory.js +110 -0
  126. package/dist/sdk/plugins/manifest.d.ts +13 -0
  127. package/dist/sdk/plugins/manifest.js +56 -0
  128. package/dist/sdk/plugins/plugins.d.ts +104 -0
  129. package/dist/sdk/plugins/plugins.js +164 -0
  130. package/dist/sdk/plugins/runtime.d.ts +9 -0
  131. package/dist/sdk/plugins/runtime.js +95 -0
  132. package/dist/sdk/plugins/trust.d.ts +44 -0
  133. package/dist/sdk/plugins/trust.js +120 -0
  134. package/dist/sdk/plugins/types.d.ts +159 -0
  135. package/dist/sdk/plugins/types.js +7 -0
  136. package/dist/sdk/prompt/compile.d.ts +174 -0
  137. package/dist/sdk/prompt/compile.js +396 -0
  138. package/dist/sdk/refine/cli.d.ts +4 -0
  139. package/dist/sdk/refine/cli.js +186 -0
  140. package/dist/sdk/refine/demo.d.ts +21 -0
  141. package/dist/sdk/refine/demo.js +114 -0
  142. package/dist/sdk/refine/evidence.d.ts +55 -0
  143. package/dist/sdk/refine/evidence.js +330 -0
  144. package/dist/sdk/refine/host.d.ts +51 -0
  145. package/dist/sdk/refine/host.js +76 -0
  146. package/dist/sdk/refine/ledger.d.ts +48 -0
  147. package/dist/sdk/refine/ledger.js +76 -0
  148. package/dist/sdk/refine/library.d.ts +55 -0
  149. package/dist/sdk/refine/library.js +177 -0
  150. package/dist/sdk/refine/pi.d.ts +72 -0
  151. package/dist/sdk/refine/pi.js +248 -0
  152. package/dist/sdk/refine/prompts.d.ts +45 -0
  153. package/dist/sdk/refine/prompts.js +390 -0
  154. package/dist/sdk/refine/recursion.d.ts +113 -0
  155. package/dist/sdk/refine/recursion.js +258 -0
  156. package/dist/sdk/refine/runner.d.ts +81 -0
  157. package/dist/sdk/refine/runner.js +150 -0
  158. package/dist/sdk/refine/selection.d.ts +57 -0
  159. package/dist/sdk/refine/selection.js +251 -0
  160. package/dist/sdk/refine/service.d.ts +84 -0
  161. package/dist/sdk/refine/service.js +165 -0
  162. package/dist/sdk/refine/suite.d.ts +67 -0
  163. package/dist/sdk/refine/suite.js +174 -0
  164. package/dist/sdk/refine/trajectory.d.ts +9 -0
  165. package/dist/sdk/refine/trajectory.js +68 -0
  166. package/dist/sdk/refine/types.d.ts +77 -0
  167. package/dist/sdk/refine/types.js +10 -0
  168. package/dist/sdk/server/methods.d.ts +3 -0
  169. package/dist/sdk/server/methods.js +370 -0
  170. package/dist/sdk/server/remote.d.ts +19 -0
  171. package/dist/sdk/server/remote.js +84 -0
  172. package/dist/sdk/server/rpc.d.ts +20 -0
  173. package/dist/sdk/server/rpc.js +102 -0
  174. package/dist/sdk/server/serve.d.ts +10 -0
  175. package/dist/sdk/server/serve.js +18 -0
  176. package/dist/sdk/sessions/approvals.d.ts +47 -0
  177. package/dist/sdk/sessions/approvals.js +119 -0
  178. package/dist/sdk/sessions/continuation.d.ts +48 -0
  179. package/dist/sdk/sessions/continuation.js +85 -0
  180. package/dist/sdk/sessions/contracts.d.ts +534 -0
  181. package/dist/sdk/sessions/contracts.js +299 -0
  182. package/dist/sdk/sessions/extensionUi.d.ts +19 -0
  183. package/dist/sdk/sessions/extensionUi.js +64 -0
  184. package/dist/sdk/sessions/history.d.ts +16 -0
  185. package/dist/sdk/sessions/history.js +68 -0
  186. package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
  187. package/dist/sdk/sessions/lineageJoin.js +61 -0
  188. package/dist/sdk/sessions/planMode.d.ts +36 -0
  189. package/dist/sdk/sessions/planMode.js +84 -0
  190. package/dist/sdk/sessions/policy.d.ts +43 -0
  191. package/dist/sdk/sessions/policy.js +1 -0
  192. package/dist/sdk/sessions/pricing.d.ts +34 -0
  193. package/dist/sdk/sessions/pricing.js +40 -0
  194. package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
  195. package/dist/sdk/sessions/reasoningSummaries.js +61 -0
  196. package/dist/sdk/sessions/registry.d.ts +102 -0
  197. package/dist/sdk/sessions/registry.js +383 -0
  198. package/dist/sdk/sessions/runIndex.d.ts +21 -0
  199. package/dist/sdk/sessions/runIndex.js +65 -0
  200. package/dist/sdk/sessions/runStore.d.ts +66 -0
  201. package/dist/sdk/sessions/runStore.js +335 -0
  202. package/dist/sdk/sessions/runner.d.ts +213 -0
  203. package/dist/sdk/sessions/runner.js +589 -0
  204. package/dist/sdk/sessions/sessions.d.ts +140 -0
  205. package/dist/sdk/sessions/sessions.js +394 -0
  206. package/dist/sdk/sessions/subagentService.d.ts +41 -0
  207. package/dist/sdk/sessions/subagentService.js +247 -0
  208. package/dist/sdk/sessions/subagents.d.ts +50 -0
  209. package/dist/sdk/sessions/subagents.js +68 -0
  210. package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
  211. package/dist/sdk/terminal/accountsMenu.js +392 -0
  212. package/dist/sdk/terminal/cli.d.ts +20 -0
  213. package/dist/sdk/terminal/cli.js +121 -0
  214. package/dist/sdk/terminal/client.d.ts +15 -0
  215. package/dist/sdk/terminal/client.js +126 -0
  216. package/dist/sdk/terminal/control.d.ts +4 -0
  217. package/dist/sdk/terminal/control.js +25 -0
  218. package/dist/sdk/terminal/controller.d.ts +72 -0
  219. package/dist/sdk/terminal/controller.js +351 -0
  220. package/dist/sdk/terminal/hubMenu.d.ts +10 -0
  221. package/dist/sdk/terminal/hubMenu.js +34 -0
  222. package/dist/sdk/terminal/launch.d.ts +5 -0
  223. package/dist/sdk/terminal/launch.js +27 -0
  224. package/dist/sdk/terminal/logs.d.ts +14 -0
  225. package/dist/sdk/terminal/logs.js +59 -0
  226. package/dist/sdk/terminal/piExtension.d.ts +6 -0
  227. package/dist/sdk/terminal/piExtension.js +392 -0
  228. package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
  229. package/dist/sdk/terminal/pluginMenu.js +101 -0
  230. package/dist/sdk/terminal/socket.d.ts +70 -0
  231. package/dist/sdk/terminal/socket.js +256 -0
  232. package/dist/sdk/terminal/standalone.d.ts +18 -0
  233. package/dist/sdk/terminal/standalone.js +146 -0
  234. package/dist/sdk/terminal/terminals.d.ts +176 -0
  235. package/dist/sdk/terminal/terminals.js +767 -0
  236. package/dist/sdk/terminal/trajectory.d.ts +10 -0
  237. package/dist/sdk/terminal/trajectory.js +30 -0
  238. package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
  239. package/dist/sdk/terminal/tui/chrome.js +169 -0
  240. package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
  241. package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
  242. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -0
  243. package/dist/sdk/terminal/tui/commandPages.js +63 -0
  244. package/dist/sdk/terminal/tui/commands.d.ts +42 -0
  245. package/dist/sdk/terminal/tui/commands.js +276 -0
  246. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
  247. package/dist/sdk/terminal/tui/dialogGeometry.js +50 -0
  248. package/dist/sdk/terminal/tui/dialogs.d.ts +75 -0
  249. package/dist/sdk/terminal/tui/dialogs.js +363 -0
  250. package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
  251. package/dist/sdk/terminal/tui/keybindings.js +49 -0
  252. package/dist/sdk/terminal/tui/list.d.ts +73 -0
  253. package/dist/sdk/terminal/tui/list.js +196 -0
  254. package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
  255. package/dist/sdk/terminal/tui/modeChoices.js +70 -0
  256. package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
  257. package/dist/sdk/terminal/tui/modelPicker.js +155 -0
  258. package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
  259. package/dist/sdk/terminal/tui/mouse.js +3 -0
  260. package/dist/sdk/terminal/tui/page.d.ts +14 -0
  261. package/dist/sdk/terminal/tui/page.js +1 -0
  262. package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
  263. package/dist/sdk/terminal/tui/pageOverlay.js +145 -0
  264. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +54 -0
  265. package/dist/sdk/terminal/tui/pages/accountsPage.js +181 -0
  266. package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
  267. package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
  268. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +37 -0
  269. package/dist/sdk/terminal/tui/pages/doctorPage.js +145 -0
  270. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
  271. package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
  272. package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
  273. package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
  274. package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
  275. package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
  276. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
  277. package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
  278. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +55 -0
  279. package/dist/sdk/terminal/tui/pages/settingsPage.js +88 -0
  280. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +58 -0
  281. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +377 -0
  282. package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
  283. package/dist/sdk/terminal/tui/piAdapter.js +48 -0
  284. package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
  285. package/dist/sdk/terminal/tui/planMode.js +2 -0
  286. package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
  287. package/dist/sdk/terminal/tui/questionPicker.js +150 -0
  288. package/dist/sdk/terminal/tui/questions.d.ts +19 -0
  289. package/dist/sdk/terminal/tui/questions.js +42 -0
  290. package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
  291. package/dist/sdk/terminal/tui/runtime.js +441 -0
  292. package/dist/sdk/terminal/tui/search.d.ts +22 -0
  293. package/dist/sdk/terminal/tui/search.js +60 -0
  294. package/dist/sdk/terminal/tui/selection.d.ts +16 -0
  295. package/dist/sdk/terminal/tui/selection.js +16 -0
  296. package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
  297. package/dist/sdk/terminal/tui/sessionUi.js +30 -0
  298. package/dist/sdk/terminal/tui/settingsModel.d.ts +12 -0
  299. package/dist/sdk/terminal/tui/settingsModel.js +84 -0
  300. package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
  301. package/dist/sdk/terminal/tui/sideQuestion.js +197 -0
  302. package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
  303. package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
  304. package/dist/sdk/terminal/tui/status.d.ts +18 -0
  305. package/dist/sdk/terminal/tui/status.js +67 -0
  306. package/dist/sdk/terminal/tui/theme.d.ts +45 -0
  307. package/dist/sdk/terminal/tui/theme.js +176 -0
  308. package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
  309. package/dist/sdk/terminal/tui/treeModel.js +483 -0
  310. package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
  311. package/dist/sdk/terminal/tui/treePicker.js +251 -0
  312. package/dist/sdk/terminal/tui/ui.d.ts +47 -0
  313. package/dist/sdk/terminal/tui/ui.js +148 -0
  314. package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
  315. package/dist/sdk/terminal/tui/workingStatus.js +229 -0
  316. package/dist/sdk/tools/askUser.d.ts +6 -0
  317. package/dist/sdk/tools/askUser.js +74 -0
  318. package/dist/sdk/tools/checklist.d.ts +9 -0
  319. package/dist/sdk/tools/checklist.js +54 -0
  320. package/dist/sdk/tools/definitions.d.ts +30 -0
  321. package/dist/sdk/tools/definitions.js +117 -0
  322. package/dist/sdk/tools/dispatch.d.ts +16 -0
  323. package/dist/sdk/tools/dispatch.js +67 -0
  324. package/dist/sdk/tools/harnessTools.d.ts +6 -0
  325. package/dist/sdk/tools/harnessTools.js +20 -0
  326. package/dist/sdk/tools/sessionName.d.ts +7 -0
  327. package/dist/sdk/tools/sessionName.js +31 -0
  328. package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
  329. package/dist/sdk/tools/spawnSubagent.js +49 -0
  330. package/dist/sdk/tools/types.d.ts +48 -0
  331. package/dist/sdk/tools/types.js +1 -0
  332. package/dist/sdk/variant/components.d.ts +34 -0
  333. package/dist/sdk/variant/components.js +230 -0
  334. package/dist/sdk/variant/materialise.d.ts +66 -0
  335. package/dist/sdk/variant/materialise.js +81 -0
  336. package/dist/sdk/variant/migrate.d.ts +4 -0
  337. package/dist/sdk/variant/migrate.js +41 -0
  338. package/dist/sdk/variant/seed.d.ts +20 -0
  339. package/dist/sdk/variant/seed.js +116 -0
  340. package/dist/sdk/variant/store.d.ts +82 -0
  341. package/dist/sdk/variant/store.js +151 -0
  342. package/dist/sdk/variant/surface.d.ts +56 -0
  343. package/dist/sdk/variant/surface.js +81 -0
  344. package/dist/sdk/variant/trust.d.ts +27 -0
  345. package/dist/sdk/variant/trust.js +64 -0
  346. package/dist/sdk/variant/variant.d.ts +71 -0
  347. package/dist/sdk/variant/variant.js +331 -0
  348. package/dist/sdk/web/markdown.d.ts +10 -0
  349. package/dist/sdk/web/markdown.js +66 -0
  350. package/dist/sdk/web/safeRequest.d.ts +34 -0
  351. package/dist/sdk/web/safeRequest.js +175 -0
  352. package/dist/sdk/web/search.d.ts +53 -0
  353. package/dist/sdk/web/search.js +168 -0
  354. package/dist/sdk/web/text.d.ts +2 -0
  355. package/dist/sdk/web/text.js +7 -0
  356. package/dist/sdk/web/tools.d.ts +22 -0
  357. package/dist/sdk/web/tools.js +195 -0
  358. package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
  359. package/dist/sdk/wiki/notes.d.ts +68 -0
  360. package/dist/sdk/wiki/notes.js +297 -0
  361. package/dist/sdk/world/actions.d.ts +23 -0
  362. package/dist/sdk/world/actions.js +31 -0
  363. package/dist/sdk/world/cli.d.ts +12 -0
  364. package/dist/sdk/world/cli.js +166 -0
  365. package/dist/sdk/world/images.d.ts +20 -0
  366. package/dist/sdk/world/images.js +48 -0
  367. package/dist/sdk/world/untrusted.d.ts +12 -0
  368. package/dist/sdk/world/untrusted.js +20 -0
  369. package/dist/sdk/world/world.d.ts +65 -0
  370. package/dist/sdk/world/world.js +80 -0
  371. package/dist/terminal-opentui.js +13612 -0
  372. package/dist/terminal-pi.js +808 -151
  373. package/docs/README.md +22 -0
  374. package/docs/architecture/00-overview.md +159 -0
  375. package/docs/architecture/01-extension-points.md +78 -0
  376. package/docs/architecture/02-sessions-and-runs.md +146 -0
  377. package/docs/architecture/03-variants.md +95 -0
  378. package/docs/architecture/04-prompt.md +102 -0
  379. package/docs/architecture/05-refinement.md +107 -0
  380. package/docs/architecture/06-plugins-and-capabilities.md +93 -0
  381. package/docs/architecture/07-tools-and-gate.md +88 -0
  382. package/docs/architecture/08-memory-and-history.md +94 -0
  383. package/docs/architecture/09-accounts-and-connectors.md +90 -0
  384. package/docs/architecture/10-server-protocol.md +84 -0
  385. package/docs/architecture/11-terminal.md +81 -0
  386. package/docs/architecture/12-storage.md +61 -0
  387. package/docs/architecture/13-world-tools.md +23 -0
  388. package/docs/architecture/README.md +114 -0
  389. package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
  390. package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
  391. package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
  392. package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
  393. package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
  394. package/docs/architecture/proposals/PROP-0006-run-checklist.md +68 -0
  395. package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
  396. package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
  397. package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
  398. package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
  399. package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
  400. package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
  401. package/docs/architecture/proposals/README.md +76 -0
  402. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  403. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  404. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  405. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  406. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  407. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  408. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  409. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  410. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  411. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  412. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  413. package/docs/decisions/ADR-0013-doctor.md +27 -0
  414. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  415. package/docs/doctor.md +74 -0
  416. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  418. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  420. package/docs/features/README.md +20 -0
  421. package/docs/features/automations/README.md +41 -0
  422. package/docs/features/cores/README.md +39 -0
  423. package/docs/features/google-harness2/README.md +52 -0
  424. package/docs/features/integrations/README.md +40 -0
  425. package/docs/features/interfaces/README.md +29 -0
  426. package/docs/features/memory/README.md +28 -0
  427. package/docs/releases/1.0.0.md +40 -0
  428. package/docs/releases/README.md +36 -0
  429. package/docs/study/00-index.md +78 -0
  430. package/docs/study/arms/00-matrix.md +20 -0
  431. package/docs/study/arms/01-system-prompt.md +211 -0
  432. package/docs/study/arms/02-tools.md +79 -0
  433. package/docs/study/arms/03-subagents.md +90 -0
  434. package/docs/study/arms/04-skills.md +75 -0
  435. package/docs/study/arms/05-context-management.md +90 -0
  436. package/docs/study/arms/06-memory.md +90 -0
  437. package/docs/study/arms/07-governance.md +71 -0
  438. package/docs/study/arms/08-execution.md +69 -0
  439. package/docs/study/arms/09-observability.md +60 -0
  440. package/docs/study/arms/10-refinement.md +110 -0
  441. package/docs/study/btw-comparison.md +37 -0
  442. package/docs/study/feature-gap-review.md +42 -0
  443. package/docs/study/insights.md +123 -0
  444. package/docs/study/roadmap.md +72 -0
  445. package/docs/study/sources/claude-code.md +44 -0
  446. package/docs/study/sources/deepseek-harness.md +102 -0
  447. package/docs/study/sources/harness2.md +50 -0
  448. package/docs/study/sources/kimi-cli.md +42 -0
  449. package/docs/study/sources/omp.md +93 -0
  450. package/docs/study/sources/opencode.md +43 -0
  451. package/docs/study/sources/openhands.md +46 -0
  452. package/docs/study/sources/smolagents.md +40 -0
  453. package/docs/study/sources/swe-agent.md +34 -0
  454. package/docs/system-prompt-design.md +196 -0
  455. package/docs/terminal-tui.md +473 -56
  456. package/package.json +43 -13
  457. package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
  458. package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
  459. package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
  460. package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
  461. package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
  462. package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
  463. package/docs/evidence/terminal-2026-10-17/verification.json +0 -130
  464. package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
  465. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
  466. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
  467. package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
  468. package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
  469. package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
  470. package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
  471. package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
  472. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
  473. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
  474. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
  475. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
  476. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +0 -95
  477. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
  478. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
  479. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
  480. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
  481. package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +0 -27
  482. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
  483. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +0 -18
  484. package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +0 -95
  485. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
  486. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
  487. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +0 -60
  488. package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +0 -24
  489. package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
  490. package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +0 -57
  491. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
  492. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
  493. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +0 -58
  494. package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
  495. package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +0 -320
  496. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +0 -30
  497. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +0 -133
  498. package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +0 -20
  499. package/docs/evidence/terminal-2026-10-17-followup/verification.json +0 -207
  500. package/src/accounts/accounts.test.ts +0 -333
  501. package/src/accounts/accounts.ts +0 -658
  502. package/src/accounts/env.test.ts +0 -95
  503. package/src/accounts/env.ts +0 -338
  504. package/src/accounts/secrets.ts +0 -50
  505. package/src/accounts/store.ts +0 -338
  506. package/src/capabilities/api.ts +0 -75
  507. package/src/capabilities/runSnapshot.ts +0 -59
  508. package/src/capabilities/types.ts +0 -34
  509. package/src/cli.ts +0 -118
  510. package/src/core/bus.ts +0 -34
  511. package/src/core/changes.ts +0 -33
  512. package/src/core/env.ts +0 -27
  513. package/src/core/errors.ts +0 -32
  514. package/src/core/frontmatter.ts +0 -47
  515. package/src/core/fs.test.ts +0 -38
  516. package/src/core/fs.ts +0 -92
  517. package/src/core/index.ts +0 -193
  518. package/src/core/path.test.ts +0 -14
  519. package/src/core/path.ts +0 -79
  520. package/src/core/projects.ts +0 -90
  521. package/src/core/text.ts +0 -39
  522. package/src/harness.ts +0 -312
  523. package/src/hub/catalog.json +0 -123
  524. package/src/hub/cli.ts +0 -59
  525. package/src/hub/hub.test.ts +0 -205
  526. package/src/hub/hub.ts +0 -256
  527. package/src/hub/schema.ts +0 -81
  528. package/src/index.ts +0 -75
  529. package/src/mcp/connections.ts +0 -614
  530. package/src/mcp/manager.ts +0 -130
  531. package/src/mcp/oauth.ts +0 -195
  532. package/src/mcp/scopeMigration.test.ts +0 -79
  533. package/src/mcp/scopeMigration.ts +0 -204
  534. package/src/mcp/service.test.ts +0 -376
  535. package/src/mcp/service.ts +0 -549
  536. package/src/mcp/types.ts +0 -108
  537. package/src/memory/api.test.ts +0 -82
  538. package/src/memory/api.ts +0 -303
  539. package/src/memory/blocks.test.ts +0 -78
  540. package/src/memory/blocks.ts +0 -408
  541. package/src/memory/caller.ts +0 -69
  542. package/src/memory/curation.test.ts +0 -163
  543. package/src/memory/curation.ts +0 -64
  544. package/src/memory/dispatch.ts +0 -59
  545. package/src/memory/facts.test.ts +0 -41
  546. package/src/memory/facts.ts +0 -248
  547. package/src/memory/graph.ts +0 -103
  548. package/src/memory/health.test.ts +0 -130
  549. package/src/memory/health.ts +0 -74
  550. package/src/memory/maintainer.ts +0 -272
  551. package/src/memory/maintenance.test.ts +0 -176
  552. package/src/memory/maintenance.ts +0 -518
  553. package/src/memory/migrate.ts +0 -79
  554. package/src/memory/operations.ts +0 -150
  555. package/src/memory/proposals.test.ts +0 -168
  556. package/src/memory/proposals.ts +0 -584
  557. package/src/memory/recall.test.ts +0 -115
  558. package/src/memory/recall.ts +0 -278
  559. package/src/memory/references.ts +0 -77
  560. package/src/memory/runContext.ts +0 -93
  561. package/src/memory/secrets.ts +0 -6
  562. package/src/memory/store.test.ts +0 -66
  563. package/src/memory/store.ts +0 -385
  564. package/src/memory/wiki.test.ts +0 -47
  565. package/src/memory/wiki.ts +0 -422
  566. package/src/memory/wikiIndex.test.ts +0 -88
  567. package/src/memory/wikiIndex.ts +0 -116
  568. package/src/plugins/api.ts +0 -181
  569. package/src/plugins/attachments.test.ts +0 -84
  570. package/src/plugins/attachments.ts +0 -141
  571. package/src/plugins/builtin.ts +0 -82
  572. package/src/plugins/catalogue.test.ts +0 -254
  573. package/src/plugins/catalogue.ts +0 -251
  574. package/src/plugins/cli.ts +0 -184
  575. package/src/plugins/discover.ts +0 -151
  576. package/src/plugins/firstParty.test.ts +0 -143
  577. package/src/plugins/firstParty.ts +0 -129
  578. package/src/plugins/hooks.test.ts +0 -250
  579. package/src/plugins/hooks.ts +0 -239
  580. package/src/plugins/identity.ts +0 -37
  581. package/src/plugins/install.test.ts +0 -107
  582. package/src/plugins/install.ts +0 -106
  583. package/src/plugins/inventory.ts +0 -123
  584. package/src/plugins/manifest.ts +0 -76
  585. package/src/plugins/plugins.test.ts +0 -205
  586. package/src/plugins/plugins.ts +0 -189
  587. package/src/plugins/proposal.ts +0 -121
  588. package/src/plugins/runtime.test.ts +0 -40
  589. package/src/plugins/runtime.ts +0 -82
  590. package/src/plugins/trust.ts +0 -142
  591. package/src/plugins/types.ts +0 -149
  592. package/src/prompt/compile.test.ts +0 -261
  593. package/src/prompt/compile.ts +0 -732
  594. package/src/server/methods.ts +0 -349
  595. package/src/server/remote.ts +0 -77
  596. package/src/server/rpc.ts +0 -116
  597. package/src/server/serve.ts +0 -28
  598. package/src/server/server.test.ts +0 -174
  599. package/src/sessions/approvals.ts +0 -118
  600. package/src/sessions/contracts.ts +0 -336
  601. package/src/sessions/conversation.test.ts +0 -177
  602. package/src/sessions/extensionSession.test.ts +0 -74
  603. package/src/sessions/extensionUi.test.ts +0 -65
  604. package/src/sessions/extensionUi.ts +0 -102
  605. package/src/sessions/history.ts +0 -51
  606. package/src/sessions/lineageJoin.ts +0 -75
  607. package/src/sessions/policy.ts +0 -36
  608. package/src/sessions/pricing.ts +0 -60
  609. package/src/sessions/questionBatches.test.ts +0 -110
  610. package/src/sessions/reasoningSummaries.ts +0 -59
  611. package/src/sessions/registry.ts +0 -381
  612. package/src/sessions/runIndex.ts +0 -99
  613. package/src/sessions/runStore.test.ts +0 -152
  614. package/src/sessions/runStore.ts +0 -332
  615. package/src/sessions/runner.ts +0 -604
  616. package/src/sessions/runtimeResources.test.ts +0 -61
  617. package/src/sessions/sessions.test.ts +0 -549
  618. package/src/sessions/sessions.ts +0 -339
  619. package/src/skills/registry.test.ts +0 -104
  620. package/src/skills/registry.ts +0 -413
  621. package/src/terminal/accountsMenu.test.ts +0 -225
  622. package/src/terminal/accountsMenu.ts +0 -382
  623. package/src/terminal/cli.ts +0 -149
  624. package/src/terminal/client.ts +0 -74
  625. package/src/terminal/control.test.ts +0 -23
  626. package/src/terminal/control.ts +0 -23
  627. package/src/terminal/controller.ts +0 -291
  628. package/src/terminal/hubMenu.ts +0 -24
  629. package/src/terminal/launch.test.ts +0 -25
  630. package/src/terminal/launch.ts +0 -48
  631. package/src/terminal/piExtension.lifecycle.test.ts +0 -55
  632. package/src/terminal/piExtension.ts +0 -259
  633. package/src/terminal/pluginControl.test.ts +0 -146
  634. package/src/terminal/pluginMenu.ts +0 -112
  635. package/src/terminal/socket.test.ts +0 -71
  636. package/src/terminal/socket.ts +0 -232
  637. package/src/terminal/standalone.test.ts +0 -167
  638. package/src/terminal/standalone.ts +0 -153
  639. package/src/terminal/terminal.test.ts +0 -399
  640. package/src/terminal/terminals.ts +0 -553
  641. package/src/terminal/tui/application.test.ts +0 -114
  642. package/src/terminal/tui/application.ts +0 -491
  643. package/src/terminal/tui/commands.test.ts +0 -218
  644. package/src/terminal/tui/commands.ts +0 -361
  645. package/src/terminal/tui/dialogs.ts +0 -301
  646. package/src/terminal/tui/editor.test.ts +0 -84
  647. package/src/terminal/tui/editor.ts +0 -79
  648. package/src/terminal/tui/keybindings.test.ts +0 -22
  649. package/src/terminal/tui/keybindings.ts +0 -50
  650. package/src/terminal/tui/piAdapter.ts +0 -62
  651. package/src/terminal/tui/presentation.test.ts +0 -79
  652. package/src/terminal/tui/questions.test.ts +0 -41
  653. package/src/terminal/tui/questions.ts +0 -47
  654. package/src/terminal/tui/runtime.socket.test.ts +0 -104
  655. package/src/terminal/tui/runtime.test.ts +0 -215
  656. package/src/terminal/tui/runtime.ts +0 -388
  657. package/src/terminal/tui/sessionUi.ts +0 -24
  658. package/src/terminal/tui/settings.test.ts +0 -150
  659. package/src/terminal/tui/settings.ts +0 -188
  660. package/src/terminal/tui/status.test.ts +0 -70
  661. package/src/terminal/tui/status.ts +0 -109
  662. package/src/terminal/tui/theme.ts +0 -174
  663. package/src/terminal/tui/tools.test.ts +0 -145
  664. package/src/terminal/tui/tools.ts +0 -142
  665. package/src/terminal/tui/transcript.test.ts +0 -25
  666. package/src/terminal/tui/transcript.ts +0 -124
  667. package/src/terminal/tui/ui.test.ts +0 -313
  668. package/src/terminal/tui/ui.ts +0 -166
  669. package/src/terminal/tui/welcome.ts +0 -102
  670. package/src/tools/askUser.test.ts +0 -69
  671. package/src/tools/askUser.ts +0 -59
  672. package/src/tools/definitions.ts +0 -187
  673. package/src/tools/maintenance.ts +0 -24
  674. package/src/tools/memoryTools.ts +0 -22
  675. package/src/tools/pluginPropose.ts +0 -41
  676. package/src/tools/registryWrite.test.ts +0 -101
  677. package/src/tools/registryWrite.ts +0 -182
  678. package/src/tools/spawnSubagent.ts +0 -92
  679. package/src/tools/types.ts +0 -39
  680. package/src/web/safeRequest.ts +0 -171
  681. package/src/web/text.ts +0 -53
  682. package/src/web/tools.ts +0 -134
  683. package/src/web/web.test.ts +0 -141
@@ -1,218 +0,0 @@
1
- import type { AgentSession, ExtensionUIContext } from '@earendil-works/pi-coding-agent'
2
- import { describe, expect, it, vi } from 'vitest'
3
- import { createTerminalCommands, type TerminalCommandHost } from './commands'
4
-
5
- function setup() {
6
- const ui = {
7
- notify: vi.fn(), select: vi.fn(), confirm: vi.fn(), input: vi.fn(),
8
- theme: { name: 'harness-titanium' }
9
- } as unknown as ExtensionUIContext
10
- const session = {
11
- extensionRunner: { getRegisteredCommands: () => [{ name: 'accounts', description: 'Manage accounts' }] },
12
- resourceLoader: {
13
- getPrompts: () => ({ prompts: [{ name: 'review', description: 'Review code' }] }),
14
- getSkills: () => ({ skills: [{ name: 'diagnose', description: 'Diagnose a problem' }] })
15
- },
16
- settingsManager: { getEnableSkillCommands: () => true },
17
- compact: vi.fn(), reload: vi.fn(), setSessionName: vi.fn(),
18
- getLastAssistantText: vi.fn(() => 'Actual assistant response'),
19
- getSessionStats: () => ({ sessionId: 'real-session', tokens: { input: 7 } }),
20
- exportToHtml: vi.fn(async (path: string) => path), exportToJsonl: vi.fn((path: string) => path)
21
- } as unknown as AgentSession
22
- const runtime = { newSession: vi.fn(), switchSession: vi.fn(), fork: vi.fn(), importFromJsonl: vi.fn(), reload: vi.fn(), navigateTree: vi.fn(), installationDeviceId: vi.fn(async () => '12345678-1234-4234-8234-123456789abc') }
23
- const host: TerminalCommandHost = {
24
- session: () => session, runtime: () => runtime as unknown as ReturnType<TerminalCommandHost['runtime']>, ui,
25
- cwd: () => '/isolated/project', sessionDirectory: () => '/isolated/account/history',
26
- refresh: vi.fn(), shutdown: vi.fn(), setEditorText: vi.fn(), copyText: vi.fn(async () => {}),
27
- hotkeys: () => 'Escape: interrupt', changelog: async () => 'Harness release notes'
28
- }
29
- return { host, session, runtime, ui, commands: createTerminalCommands(host) }
30
- }
31
-
32
- describe('owned terminal commands', () => {
33
- it('leaves ordinary prompts and supported extension/resource commands for the SDK', async () => {
34
- const { commands, ui } = setup()
35
- for (const text of ['hello', '/accounts', '/review module', '/skill:diagnose trace']) {
36
- expect(await commands.execute(text)).toBe(false)
37
- }
38
- expect(ui.notify).not.toHaveBeenCalled()
39
- })
40
-
41
- it('consumes unknown slash commands without sending them to the model', async () => {
42
- const { commands, ui } = setup()
43
- expect(await commands.execute('/typo dangerous operation')).toBe(true)
44
- expect(ui.notify).toHaveBeenCalledWith(expect.stringContaining('Unknown command: /typo'), 'error')
45
- })
46
-
47
- it('populates completion from builtins and loaded resources', () => {
48
- const { commands } = setup()
49
- const names = commands.completions().map(item => item.name)
50
- expect(names).toEqual(expect.arrayContaining(['model', 'resume', 'accounts', 'review', 'skill:diagnose']))
51
- expect(new Set(names).size).toBe(names.length)
52
- })
53
-
54
- it('respects disabled skill commands', () => {
55
- const { commands, session } = setup()
56
- vi.spyOn(session.settingsManager, 'getEnableSkillCommands').mockReturnValue(false)
57
- expect(commands.completions().map(item => item.name)).not.toContain('skill:diagnose')
58
- })
59
-
60
- it('uses the scope checked runtime for explicit resume and import paths', async () => {
61
- const { commands, runtime } = setup()
62
- await commands.execute('/resume /isolated/account/history/session.jsonl')
63
- expect(runtime.switchSession).toHaveBeenCalledWith('/isolated/account/history/session.jsonl')
64
- await commands.execute('/import other.jsonl')
65
- expect(runtime.importFromJsonl).toHaveBeenCalledWith('/isolated/project/other.jsonl')
66
- await commands.execute('/new')
67
- expect(runtime.newSession).toHaveBeenCalledOnce()
68
- })
69
-
70
- it('passes the Harness installation device ID to direct OAuth sign-in', async () => {
71
- const { commands, session, runtime } = setup()
72
- const login = vi.fn(async (_provider: string, _type: string, _interaction: unknown, options?: { getDeviceId?: () => string }) => options)
73
- Object.assign(session, { modelRuntime: {
74
- getProviders: () => [{ id: 'openai', name: 'OpenAI', auth: { oauth: {}, apiKey: undefined } }],
75
- login
76
- } })
77
-
78
- await commands.execute('/login openai')
79
-
80
- expect(runtime.installationDeviceId).toHaveBeenCalledOnce()
81
- expect(login.mock.calls[0]?.[3]?.getDeviceId?.()).toBe('12345678-1234-4234-8234-123456789abc')
82
- })
83
-
84
- it('reports rejected navigation without claiming success', async () => {
85
- const { commands, runtime, ui } = setup()
86
- runtime.switchSession.mockRejectedValue(new Error('Session is outside the prepared project scope'))
87
- expect(await commands.execute('/resume /isolated/account/history/session.jsonl')).toBe(true)
88
- expect(ui.notify).toHaveBeenCalledWith('Session is outside the prepared project scope', 'error')
89
- })
90
-
91
- it('copies actual assistant text and handles missing responses', async () => {
92
- const { commands, host, session, ui } = setup()
93
- await commands.execute('/copy')
94
- expect(host.copyText).toHaveBeenCalledWith('Actual assistant response')
95
- vi.mocked(session.getLastAssistantText).mockReturnValue(undefined)
96
- await commands.execute('/copy')
97
- expect(ui.notify).toHaveBeenCalledWith('No assistant response to copy yet', 'error')
98
- })
99
-
100
- it('keeps multiline compaction instructions and session names', async () => {
101
- const { commands, session } = setup()
102
- await commands.execute('/compact Keep the API\nand authentication details')
103
- expect(session.compact).toHaveBeenCalledWith('Keep the API\nand authentication details')
104
- await commands.execute('/name Unicode 知識 🧠')
105
- expect(session.setSessionName).toHaveBeenCalledWith('Unicode 知識 🧠')
106
- })
107
-
108
- it('exports supported formats through native session APIs', async () => {
109
- const { commands, session } = setup()
110
- await commands.execute('/export notes.jsonl')
111
- expect(session.exportToJsonl).toHaveBeenCalledWith('/isolated/project/notes.jsonl')
112
- await commands.execute('/export notes.html')
113
- expect(session.exportToHtml).toHaveBeenCalledWith('/isolated/project/notes.html', { themeName: 'harness-titanium' })
114
- })
115
-
116
- it('does not upload anything after a declined share confirmation', async () => {
117
- const { commands, ui, session } = setup()
118
- vi.mocked(ui.confirm).mockResolvedValue(false)
119
- await commands.execute('/share')
120
- expect(ui.confirm).toHaveBeenCalledOnce()
121
- expect(session.exportToHtml).not.toHaveBeenCalled()
122
- })
123
-
124
- it('shows actual application keyboard bindings and release notes', async () => {
125
- const { commands, ui } = setup()
126
- await commands.execute('/hotkeys')
127
- expect(ui.notify).toHaveBeenCalledWith('Escape: interrupt', 'info')
128
- await commands.execute('/changelog')
129
- expect(ui.notify).toHaveBeenCalledWith('Harness release notes', 'info')
130
- })
131
-
132
- it('exits through the application lifecycle', async () => {
133
- const { commands, host } = setup()
134
- await commands.execute('/quit')
135
- expect(host.shutdown).toHaveBeenCalledOnce()
136
- })
137
- it('validates thinking levels before mutating the session', async () => {
138
- const { commands, session, ui } = setup()
139
- Object.assign(session, { getAvailableThinkingLevels: () => ['off', 'high'], setThinkingLevel: vi.fn() })
140
- await commands.execute('/thinking high')
141
- expect(session.setThinkingLevel).toHaveBeenCalledWith('high', { persist: true })
142
- await commands.execute('/thinking fabricated')
143
- expect(session.setThinkingLevel).toHaveBeenCalledTimes(1)
144
- expect(ui.notify).toHaveBeenCalledWith('Available thinking levels: off, high', 'error')
145
- })
146
-
147
- it('clones the real leaf through the runtime without inventing history', async () => {
148
- const { commands, session, runtime, host } = setup()
149
- Object.assign(session, { sessionManager: { getLeafId: () => 'leaf-id' } })
150
- runtime.fork.mockResolvedValue({ cancelled: false })
151
- await commands.execute('/clone')
152
- expect(runtime.fork).toHaveBeenCalledWith('leaf-id', { position: 'at' })
153
- expect(host.setEditorText).toHaveBeenCalledWith('')
154
- })
155
-
156
- it('uses masked input for secret provider credentials', async () => {
157
- const { commands, session, host, ui } = setup()
158
- const login = vi.fn(async (_provider, _type, interaction) => {
159
- expect(await interaction.prompt({ type: 'secret', message: 'API key' })).toBe('private-key')
160
- })
161
- Object.assign(session, { modelRuntime: {
162
- getProviders: () => [{ id: 'provider', name: 'Provider', auth: { apiKey: { login: true } } }], login
163
- } })
164
- host.secretInput = vi.fn(async () => 'private-key')
165
- await commands.execute('/login provider')
166
- expect(host.secretInput).toHaveBeenCalledWith('API key', undefined, { signal: undefined })
167
- expect(ui.input).not.toHaveBeenCalled()
168
- expect(ui.notify).not.toHaveBeenCalledWith(expect.stringContaining('private-key'), expect.anything())
169
- })
170
-
171
- it('fails closed when secure credential input is unavailable', async () => {
172
- const { commands, session, ui } = setup()
173
- Object.assign(session, { modelRuntime: {
174
- getProviders: () => [{ id: 'provider', name: 'Provider', auth: { apiKey: { login: true } } }],
175
- login: async (_provider: string, _type: string, interaction: { prompt(prompt: unknown): Promise<string> }) => interaction.prompt({ type: 'secret', message: 'API key' })
176
- } })
177
- await commands.execute('/login provider')
178
- expect(ui.input).not.toHaveBeenCalled()
179
- expect(ui.notify).toHaveBeenCalledWith('Secure credential entry is unavailable', 'error')
180
- })
181
-
182
- it('rejects resume paths outside account history before runtime navigation', async () => {
183
- const { commands, runtime, ui } = setup()
184
- await commands.execute('/resume /other-account/session.jsonl')
185
- expect(runtime.switchSession).not.toHaveBeenCalled()
186
- expect(ui.notify).toHaveBeenCalledWith(expect.stringContaining('this account history folder'), 'error')
187
- })
188
-
189
- it('routes trust through the existing protected plugin workflow', async () => {
190
- const { commands, session } = setup()
191
- Object.assign(session, { prompt: vi.fn(async () => {}) })
192
- vi.spyOn(session.extensionRunner, 'getRegisteredCommands').mockReturnValue([{ name: 'plugins' }] as never)
193
- await commands.execute('/trust')
194
- expect(session.prompt).toHaveBeenCalledWith('/plugins')
195
- })
196
-
197
- it('opens a reviewable Harness issue draft without attaching session history', async () => {
198
- const { commands, host, ui } = setup()
199
- host.openExternal = vi.fn(async () => {})
200
- vi.mocked(ui.confirm).mockResolvedValue(false)
201
- await commands.execute('/bug Unicode issue 知識')
202
- expect(host.openExternal).not.toHaveBeenCalled()
203
- vi.mocked(ui.confirm).mockResolvedValue(true)
204
- await commands.execute('/bug Unicode issue 知識')
205
- const url = new URL(vi.mocked(host.openExternal).mock.calls[0][0])
206
- expect(url.pathname).toBe('/tanntnny/xingular-harness/issues/new')
207
- expect(url.searchParams.get('title')).toBe('Unicode issue 知識')
208
- expect(url.searchParams.get('body')).toContain('Harness')
209
- })
210
-
211
- it('reloads through the stable runtime lifecycle', async () => {
212
- const { commands, runtime, session } = setup()
213
- await commands.execute('/reload')
214
- expect(runtime.reload).toHaveBeenCalledOnce()
215
- expect(session.reload).not.toHaveBeenCalled()
216
- })
217
-
218
- })
@@ -1,361 +0,0 @@
1
- import { execFile } from 'node:child_process'
2
- import { mkdtemp, rm } from 'node:fs/promises'
3
- import { tmpdir } from 'node:os'
4
- import { isAbsolute, join, relative, resolve } from 'node:path'
5
- import { promisify } from 'node:util'
6
- import { ModelSelectorComponent, TreeSelectorComponent, SessionManager, type AgentSession, type ExtensionUIContext } from '@earendil-works/pi-coding-agent'
7
- import { SettingsPanel, type TerminalSettingItem } from './settings'
8
- import manifest from '../../../package.json'
9
- import type { TerminalRuntime } from './runtime'
10
-
11
- export interface TerminalCommandHost {
12
- session(): AgentSession
13
- /** Navigation is scope checked by the Harness runtime adapter. */
14
- runtime(): Pick<TerminalRuntime, 'newSession' | 'switchSession' | 'fork' | 'importFromJsonl' | 'reload' | 'navigateTree' | 'installationDeviceId'>
15
- ui: ExtensionUIContext
16
- cwd(): string
17
- sessionDirectory(): string
18
- refresh(): void
19
- shutdown(): void
20
- setEditorText(text: string): void
21
- copyText(text: string): Promise<void>
22
- secretInput?(title: string, placeholder?: string, options?: { signal?: AbortSignal }): Promise<string | undefined>
23
- openExternal?(url: string): Promise<void>
24
- suspend?(): Promise<void>
25
- hotkeys?(): string
26
- changelog?(): Promise<string>
27
- }
28
-
29
- export interface TerminalCommandCompletion { name: string; description?: string }
30
-
31
- const BUILTINS: TerminalCommandCompletion[] = [
32
- { name: 'help', description: 'Available terminal commands' },
33
- { name: 'new', description: 'Start a new session' },
34
- { name: 'resume', description: 'Resume a session in this account and folder' },
35
- { name: 'tree', description: 'Navigate the session tree' },
36
- { name: 'fork', description: 'Fork from a user message' },
37
- { name: 'model', description: 'Choose a model' },
38
- { name: 'thinking', description: 'Choose thinking effort' },
39
- { name: 'clone', description: 'Clone the current branch to a new session' },
40
- { name: 'scoped-models', description: 'Choose models for cycling' },
41
- { name: 'settings', description: 'Session and terminal settings' },
42
- { name: 'name', description: 'Name the current session' },
43
- { name: 'session', description: 'Current session statistics' },
44
- { name: 'compact', description: 'Compact the current context' },
45
- { name: 'reload', description: 'Reload trusted resources and keyboard bindings' },
46
- { name: 'trust', description: 'Review plugin code and project trust' },
47
- { name: 'bug', description: 'Open a Harness issue draft' },
48
- { name: 'login', description: 'Sign in to a provider in this isolated account' },
49
- { name: 'logout', description: 'Remove a stored provider credential' },
50
- { name: 'export', description: 'Export this branch to HTML or JSONL' },
51
- { name: 'import', description: 'Import a session JSONL file' },
52
- { name: 'share', description: 'Share an HTML export as a secret GitHub gist' },
53
- { name: 'copy', description: 'Copy the last assistant response' },
54
- { name: 'changelog', description: 'Harness release notes' },
55
- { name: 'hotkeys', description: 'Keyboard controls' },
56
- { name: 'quit', description: 'Restore the terminal and exit' }
57
- ]
58
-
59
- export function createTerminalCommands(host: TerminalCommandHost) {
60
- const notify = (text: string) => host.ui.notify(text, 'info')
61
- const choose = async <T>(title: string, items: T[], label: (item: T, index: number) => string) => {
62
- const labels = items.map(label)
63
- const selected = await host.ui.select(title, labels)
64
- return selected === undefined ? undefined : items[labels.indexOf(selected)]
65
- }
66
- const completions = (): TerminalCommandCompletion[] => {
67
- const session = host.session()
68
- const commands = new Map(BUILTINS.map(command => [command.name, command]))
69
- for (const command of session.extensionRunner.getRegisteredCommands()) {
70
- if (!commands.has(command.name)) commands.set(command.name, { name: command.name, description: command.description })
71
- }
72
- for (const prompt of session.resourceLoader.getPrompts().prompts) {
73
- if (!commands.has(prompt.name)) commands.set(prompt.name, { name: prompt.name, description: prompt.description })
74
- }
75
- if (session.settingsManager.getEnableSkillCommands()) {
76
- for (const skill of session.resourceLoader.getSkills().skills) commands.set(`skill:${skill.name}`, { name: `skill:${skill.name}`, description: skill.description })
77
- }
78
- return [...commands.values()]
79
- }
80
-
81
- async function settings() {
82
- const session = host.session()
83
- const settings = session.settingsManager
84
- const booleanSettings = [
85
- ['Auto compaction', () => session.autoCompactionEnabled, (value: boolean) => session.setAutoCompactionEnabled(value)],
86
- ['Auto retry', () => session.autoRetryEnabled, (value: boolean) => session.setAutoRetryEnabled(value)],
87
- ['Show images', () => settings.getShowImages(), (value: boolean) => settings.setShowImages(value)],
88
- ['Resize images', () => settings.getImageAutoResize(), (value: boolean) => settings.setImageAutoResize(value)],
89
- ['Block images', () => settings.getBlockImages(), (value: boolean) => settings.setBlockImages(value)],
90
- ['Skill commands', () => settings.getEnableSkillCommands(), (value: boolean) => settings.setEnableSkillCommands(value)],
91
- ['Hide thinking', () => settings.getHideThinkingBlock(), (value: boolean) => settings.setHideThinkingBlock(value)],
92
- ['Hardware cursor', () => settings.getShowHardwareCursor(), (value: boolean) => settings.setShowHardwareCursor(value)],
93
- ['Terminal progress', () => settings.getShowTerminalProgress(), (value: boolean) => settings.setShowTerminalProgress(value)]
94
- ] as const
95
- let selectedId: string | undefined
96
- const locations = [
97
- ['Context', 'Compaction'], ['Model', 'Recovery'], ['Appearance', 'Images'], ['Appearance', 'Images'],
98
- ['Context', 'Images'], ['Interaction', 'Commands'], ['Appearance', 'Display'], ['Interaction', 'Editor'],
99
- ['Interaction', 'Terminal'], ['Model', 'Thinking'], ['Interaction', 'Queues'], ['Interaction', 'Queues'],
100
- ['Appearance', 'Theme'], ['Interaction', 'Keyboard']
101
- ]
102
- for (;;) {
103
- const options = [...booleanSettings.map(([label, get]) => `${label}: ${get() ? 'on' : 'off'}`),
104
- `Thinking: ${session.thinkingLevel}`, `Steering: ${session.steeringMode}`, `Follow-up: ${session.followUpMode}`,
105
- `Theme: ${host.ui.theme.name}`, 'Keyboard controls', 'Done']
106
- const descriptions = [
107
- 'Compact the context automatically when the session approaches its limit.', 'Retry eligible provider failures automatically.',
108
- 'Display actual image content returned by tools.', 'Resize image attachments before provider requests.',
109
- 'Block image attachments in provider requests.', 'Expose commands for the skills loaded in this session.',
110
- 'Collapse assistant thinking blocks in the transcript.', 'Display the terminal hardware cursor for editing and input methods.',
111
- 'Report active work through supported terminal progress controls.', 'Reasoning effort for the current model.',
112
- 'Delivery mode for messages that steer an active run.', 'Delivery mode for messages queued after a run.',
113
- 'Theme loaded from the trusted resource catalog.', 'View the current application keyboard bindings.'
114
- ]
115
- const items: TerminalSettingItem[] = options.slice(0, -1).map((option, index) => {
116
- const split = option.indexOf(':')
117
- return { id: String(index), tab: locations[index][0], group: locations[index][1], label: split < 0 ? option : option.slice(0, split), value: split < 0 ? '' : option.slice(split + 1).trim(), description: descriptions[index] }
118
- })
119
- const groups = ['Theme', 'Display', 'Images', 'Thinking', 'Recovery', 'Editor', 'Queues', 'Commands', 'Terminal', 'Keyboard', 'Compaction']
120
- items.sort((a, b) => groups.indexOf(a.group) - groups.indexOf(b.group))
121
- const id = await host.ui.custom<string | undefined>((tui, theme, _keys, done) => new SettingsPanel(tui, () => theme, items, done, selectedId), { overlay: true, overlayOptions: { width: '100%', maxHeight: '100%', anchor: 'top-left' } })
122
- if (id === undefined) return
123
- selectedId = id
124
- const index = Number(id)
125
- const selected = options[index]
126
- if (index < booleanSettings.length) {
127
- const [, get, set] = booleanSettings[index]!
128
- set(!get())
129
- } else if (selected.startsWith('Thinking:')) {
130
- const level = await host.ui.select('Thinking effort', session.getAvailableThinkingLevels())
131
- if (level) session.setThinkingLevel(level as AgentSession['thinkingLevel'], { persist: true })
132
- } else if (selected.startsWith('Steering:') || selected.startsWith('Follow-up:')) {
133
- const mode = await host.ui.select('Queue delivery', ['all', 'one-at-a-time'])
134
- if (mode === 'all' || mode === 'one-at-a-time') {
135
- if (selected.startsWith('Steering:')) session.setSteeringMode(mode)
136
- else session.setFollowUpMode(mode)
137
- }
138
- } else if (selected.startsWith('Theme:')) {
139
- const theme = await host.ui.select('Theme', host.ui.getAllThemes().map(item => item.name))
140
- if (theme) {
141
- const result = host.ui.setTheme(theme)
142
- if (!result.success) throw new Error(result.error)
143
- settings.setTheme(theme)
144
- }
145
- } else notify(host.hotkeys?.() ?? 'Use /help for commands. Keyboard bindings are managed by the terminal application.')
146
- host.refresh()
147
- }
148
- }
149
-
150
- async function login(providerRef: string) {
151
- const runtime = host.session().modelRuntime
152
- const providers = runtime.getProviders().filter(provider => provider.auth.oauth || provider.auth.apiKey?.login)
153
- const provider = providerRef
154
- ? providers.find(item => item.id === providerRef || item.name.toLowerCase() === providerRef.toLowerCase())
155
- : await choose('Sign in to provider', providers, item => `${item.name} (${item.id})`)
156
- if (!provider) { if (providerRef) throw new Error(`No sign-in provider matches ${providerRef}`); return }
157
- const types = [...(provider.auth.oauth ? ['oauth' as const] : []), ...(provider.auth.apiKey?.login ? ['api_key' as const] : [])]
158
- const type = types.length === 1 ? types[0] : await host.ui.select('Authentication method', types)
159
- if (type !== 'oauth' && type !== 'api_key') return
160
- const deviceId = type === 'oauth' ? await host.runtime().installationDeviceId() : undefined
161
- await runtime.login(provider.id, type, {
162
- prompt: async prompt => {
163
- let result: string | undefined
164
- if (prompt.type === 'select') {
165
- const option = await choose(prompt.message, [...prompt.options], item => item.label)
166
- result = option?.id
167
- } else if (prompt.type === 'secret') {
168
- if (!host.secretInput) throw new Error('Secure credential entry is unavailable')
169
- result = await host.secretInput(prompt.message, prompt.placeholder, { signal: prompt.signal })
170
- } else result = await host.ui.input(prompt.message, prompt.placeholder, { signal: prompt.signal })
171
- if (result === undefined) throw new Error('Sign-in cancelled')
172
- return result
173
- },
174
- notify: event => {
175
- if (event.type === 'auth_url') {
176
- notify(`${event.instructions ?? 'Open this sign-in URL:'}\n${event.url}`)
177
- void host.openExternal?.(event.url).catch(error => host.ui.notify(String(error), 'warning'))
178
- } else if (event.type === 'device_code') notify(`${event.verificationUri}\nCode: ${event.userCode}`)
179
- else notify(event.message)
180
- }
181
- }, deviceId ? { getDeviceId: () => deviceId } : undefined)
182
- notify(`Signed in to ${provider.name}`)
183
- }
184
-
185
- async function share() {
186
- if (!await host.ui.confirm('Share session', 'Upload the current session as a secret GitHub gist? Anyone with its link can read its contents.')) return
187
- const directory = await mkdtemp(join(tmpdir(), 'harness-share-'))
188
- try {
189
- const path = await host.session().exportToHtml(join(directory, 'session.html'), { themeName: host.ui.theme.name })
190
- const result = await promisify(execFile)('gh', ['gist', 'create', '--public=false', path], { timeout: 60_000, maxBuffer: 1024 * 1024 })
191
- notify(`Session shared: ${result.stdout.trim()}`)
192
- } finally { await rm(directory, { recursive: true, force: true }) }
193
- }
194
-
195
- async function execute(text: string): Promise<boolean> {
196
- const match = /^\/([^\s]+)(?:\s+([\s\S]*))?$/.exec(text.trim())
197
- if (!match) return false
198
- const name = match[1]!
199
- const argument = match[2]?.trim() ?? ''
200
- if (!BUILTINS.some(item => item.name === name)) {
201
- if (completions().some(item => item.name === name)) return false
202
- host.ui.notify(`Unknown command: /${name}. Use /help to list commands.`, 'error')
203
- return true
204
- }
205
- try {
206
- const session = host.session()
207
- switch (name) {
208
- case 'help': notify(completions().map(item => `/${item.name} ${item.description ?? ''}`).join('\n')); break
209
- case 'quit': host.shutdown(); break
210
- case 'new': await host.runtime().newSession(); break
211
- case 'resume': {
212
- let path = argument
213
- if (!path) {
214
- const sessions = await SessionManager.list(host.cwd(), host.sessionDirectory())
215
- const selected = await choose('Resume session', sessions, (item, index) => `${index + 1}. ${item.name ?? item.firstMessage ?? item.id} ${item.modified.toLocaleString()}`)
216
- if (!selected) break
217
- path = selected.path
218
- }
219
- const target = resolve(host.cwd(), path)
220
- const within = relative(host.sessionDirectory(), target)
221
- if (within === '..' || within.startsWith('../') || within.startsWith('..\\') || isAbsolute(within)) {
222
- throw new Error('Resume sessions from this account history folder. Use /import to explicitly import a session.')
223
- }
224
- await host.runtime().switchSession(target)
225
- break
226
- }
227
- case 'fork': {
228
- const message = await choose('Fork before message', session.getUserMessagesForForking(), (item, index) => `${index + 1}. ${item.text.replace(/\s+/g, ' ').slice(0, 160)}`)
229
- if (message) {
230
- const result = await host.runtime().fork(message.entryId)
231
- if (!result.cancelled && result.selectedText) host.setEditorText(result.selectedText)
232
- }
233
- break
234
- }
235
- case 'clone': {
236
- const leaf = session.sessionManager.getLeafId()
237
- if (!leaf) throw new Error('Nothing to clone yet')
238
- const result = await host.runtime().fork(leaf, { position: 'at' })
239
- if (!result.cancelled) { host.setEditorText(''); notify('Cloned to new session') }
240
- break
241
- }
242
- case 'tree': {
243
- const tree = session.sessionManager.getTree()
244
- if (!tree.length) throw new Error('No entries in this session')
245
- const selected = await host.ui.custom<string | undefined>((tui, _theme, _keys, done) => {
246
- const selector = new TreeSelectorComponent(tree, session.sessionManager.getLeafId(), tui.terminal.rows,
247
- done, () => done(undefined), (entryId, label) => session.sessionManager.appendLabelChange(entryId, label),
248
- undefined, session.settingsManager.getTreeFilterMode())
249
- selector.onCopy = text => { if (text) void host.copyText(text).catch(error => host.ui.notify(String(error), 'error')) }
250
- return selector
251
- })
252
- if (selected && selected !== session.sessionManager.getLeafId()) {
253
- const summarize = await host.ui.confirm('Navigate session', 'Summarize the abandoned branch before navigating?')
254
- const result = await host.runtime().navigateTree(selected, { summarize })
255
- if (!result.cancelled && result.editorText) host.setEditorText(result.editorText)
256
- }
257
- break
258
- }
259
- case 'thinking': {
260
- const levels = session.getAvailableThinkingLevels()
261
- const level = argument || await host.ui.select('Thinking effort', levels)
262
- if (!level) break
263
- if (!levels.includes(level as AgentSession['thinkingLevel'])) throw new Error(`Available thinking levels: ${levels.join(', ')}`)
264
- session.setThinkingLevel(level as AgentSession['thinkingLevel'], { persist: true })
265
- break
266
- }
267
- case 'model': {
268
- const provider = session.settingsManager.getDefaultProvider()
269
- const id = session.settingsManager.getDefaultModel()
270
- const selected = await host.ui.custom<{ model: NonNullable<AgentSession['model']>; persist: boolean } | undefined>((tui, _theme, _keys, done) =>
271
- new ModelSelectorComponent(tui, session.model, session.modelRuntime, session.scopedModels,
272
- model => done({ model, persist: false }), () => done(undefined), argument || undefined,
273
- model => done({ model, persist: true }), provider && id ? { provider, id } : undefined))
274
- if (selected) await session.setModel(selected.model, { persist: selected.persist })
275
- break
276
- }
277
- case 'scoped-models': {
278
- const models = await session.modelRuntime.getAvailable()
279
- const selected = new Set(session.scopedModels.map(item => `${item.model.provider}/${item.model.id}`))
280
- for (;;) {
281
- const labels = models.map(model => `${selected.has(`${model.provider}/${model.id}`) ? '☑' : '☐'} ${model.provider}/${model.id}`)
282
- const choice = await host.ui.select('Models for cycling', [...labels, 'Save', 'Cancel'])
283
- if (!choice || choice === 'Cancel') break
284
- if (choice === 'Save') {
285
- session.setScopedModels(models.filter(model => selected.has(`${model.provider}/${model.id}`)).map(model => ({ model })))
286
- session.settingsManager.setEnabledModels([...selected])
287
- break
288
- }
289
- const model = models[labels.indexOf(choice)]
290
- if (model) { const key = `${model.provider}/${model.id}`; if (selected.has(key)) selected.delete(key); else selected.add(key) }
291
- }
292
- break
293
- }
294
- case 'settings': await settings(); break
295
- case 'name': {
296
- const name = argument || await host.ui.input('Session name', session.sessionName)
297
- if (name !== undefined) session.setSessionName(name)
298
- break
299
- }
300
- case 'session': notify(JSON.stringify(session.getSessionStats(), null, 2)); break
301
- case 'compact': await session.compact(argument || undefined); break
302
- case 'reload': await host.runtime().reload(); notify('Trusted resources reloaded'); break
303
- case 'trust': {
304
- if (!session.extensionRunner.getRegisteredCommands().some(command => command.name === 'plugins')) throw new Error('Plugin trust controls are unavailable in this session.')
305
- await session.prompt('/plugins')
306
- break
307
- }
308
- case 'bug': {
309
- const description = argument || await host.ui.input('Describe the Harness issue')
310
- if (!description) break
311
- const repository = manifest.repository.url.replace(/^git\+/, '').replace(/\.git$/, '')
312
- const url = new URL(`${repository}/issues/new`)
313
- url.searchParams.set('title', description.split('\n')[0]!.slice(0, 120))
314
- url.searchParams.set('body', `${description}\n\nHarness ${manifest.version} · ${process.platform} ${process.arch} · Node ${process.version}`)
315
- if (!host.openExternal) throw new Error(`Open the issue draft: ${url}`)
316
- if (await host.ui.confirm('Open issue draft?', `${description}\n\nOpen the Harness issue form in your browser to review and submit.`)) await host.openExternal(url.href)
317
- break
318
- }
319
- case 'login': await login(argument); break
320
- case 'logout': {
321
- const credentials = await session.modelRuntime.listCredentials()
322
- const provider = argument || await host.ui.select('Sign out of provider', credentials.map(item => item.providerId))
323
- if (provider && await host.ui.confirm('Sign out', `Remove the stored credential for ${provider} from this account?`)) {
324
- await session.modelRuntime.logout(provider)
325
- notify(`Signed out of ${provider}`)
326
- }
327
- break
328
- }
329
- case 'copy': {
330
- const response = session.getLastAssistantText()
331
- if (!response) throw new Error('No assistant response to copy yet')
332
- await host.copyText(response)
333
- notify('Copied last assistant response')
334
- break
335
- }
336
- case 'export': {
337
- const output = argument || await host.ui.input('Export path (.html or .jsonl)', 'session.html')
338
- if (!output) break
339
- const path = resolve(host.cwd(), output)
340
- notify(`Exported to ${path.endsWith('.jsonl') ? session.exportToJsonl(path) : await session.exportToHtml(path, { themeName: host.ui.theme.name })}`)
341
- break
342
- }
343
- case 'import': {
344
- const input = argument || await host.ui.input('Import session JSONL path')
345
- if (input) await host.runtime().importFromJsonl(resolve(host.cwd(), input))
346
- break
347
- }
348
- case 'share': await share(); break
349
- case 'hotkeys': notify(host.hotkeys?.() ?? 'Keyboard bindings are managed by the terminal application.'); break
350
- case 'changelog': {
351
- if (!host.changelog) throw new Error('No Harness release notes are installed')
352
- notify(await host.changelog())
353
- break
354
- }
355
- }
356
- host.refresh()
357
- } catch (error) { host.ui.notify(error instanceof Error ? error.message : String(error), 'error') }
358
- return true
359
- }
360
- return { execute, completions }
361
- }