@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
@@ -0,0 +1,192 @@
1
+ // One live browser for one session: an isolated profile, numbered tabs, and the refs of each
2
+ // tab's latest snapshot. Calls run one at a time; the browser starts on first use and closes when
3
+ // the session ends or sits idle.
4
+ import { mkdirSync, mkdtempSync, rmSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
7
+ /** Any name as a file or folder name: other characters become `_`. */
8
+ export const fileName = (name) => name.replace(/[^A-Za-z0-9._-]/g, '_').replace(/^\.+/, '_').slice(0, 100) || '_';
9
+ export const VIEWPORT = { width: 1280, height: 800 };
10
+ export const ACTION_TIMEOUT_MS = 15_000;
11
+ export const NAVIGATION_TIMEOUT_MS = 30_000;
12
+ export const launchBrowser = async ({ profileDir, downloads, config }) => {
13
+ const { chromium } = await import('playwright-core');
14
+ if (config.cdpUrl) {
15
+ // A browser a person runs: we open our own context in it and never close the browser itself.
16
+ const browser = await chromium.connectOverCDP(config.cdpUrl);
17
+ const context = await browser.newContext({ viewport: VIEWPORT, acceptDownloads: true });
18
+ return { context, browser, attached: true };
19
+ }
20
+ const options = { headless: !config.headed, viewport: VIEWPORT, acceptDownloads: true, downloadsPath: downloads };
21
+ const attempts = config.executablePath ? [{ executablePath: config.executablePath }] : [{ channel: 'chrome' }, { channel: 'msedge' }, {}];
22
+ let last = null;
23
+ for (const attempt of attempts) {
24
+ try {
25
+ const context = profileDir
26
+ ? await chromium.launchPersistentContext(profileDir, { ...options, ...attempt })
27
+ : await (await chromium.launch({ ...options, ...attempt })).newContext({ viewport: VIEWPORT, acceptDownloads: true });
28
+ return { context, browser: context.browser(), attached: false };
29
+ }
30
+ catch (error) {
31
+ last = error;
32
+ }
33
+ }
34
+ throw new Error(`No browser could be started. Install Google Chrome, or run \`npx playwright install chromium\`. (${last instanceof Error ? last.message.split('\n')[0] : String(last)})`);
35
+ };
36
+ export class BrowserSession {
37
+ options;
38
+ closed = false;
39
+ context = null;
40
+ browser = null;
41
+ attached = false;
42
+ starting = null;
43
+ tabs = new Map();
44
+ current = null;
45
+ nextTab = 1;
46
+ queue = Promise.resolve();
47
+ idle = null;
48
+ temporaryProfile = null;
49
+ downloads = [];
50
+ /** Set when the kept profile was in use and a throwaway one was opened instead. */
51
+ profileNote = null;
52
+ constructor(options) {
53
+ this.options = options;
54
+ }
55
+ /** Runs `work` after every earlier call of this session has finished. */
56
+ run(work) {
57
+ const next = this.queue.then(work, work);
58
+ this.queue = next.catch(() => undefined);
59
+ this.touch();
60
+ return next;
61
+ }
62
+ touch() {
63
+ if (this.idle)
64
+ clearTimeout(this.idle);
65
+ this.idle = setTimeout(() => this.options.onIdle(), this.options.idleMs);
66
+ this.idle.unref?.();
67
+ }
68
+ async start() {
69
+ if (this.closed)
70
+ throw new Error('The browser session has ended.');
71
+ if (this.context)
72
+ return;
73
+ this.starting ??= (async () => {
74
+ mkdirSync(this.options.downloadsDir, { recursive: true });
75
+ let launched;
76
+ try {
77
+ launched = await this.options.launch({ profileDir: this.options.profileDir, downloads: this.options.downloadsDir, config: this.options.config() });
78
+ }
79
+ catch (error) {
80
+ // Another session holds the kept profile: work in a throwaway one rather than wait.
81
+ if (!this.options.profileDir || !/ProcessSingleton|already in use|lock/i.test(String(error)))
82
+ throw error;
83
+ this.temporaryProfile = mkdtempSync(join(tmpdir(), `harness-browser-${fileName(this.options.key)}-`));
84
+ launched = await this.options.launch({ profileDir: this.temporaryProfile, downloads: this.options.downloadsDir, config: this.options.config() });
85
+ this.profileNote = 'The saved browser profile is in use by another session, so this one started without its sign-ins.';
86
+ }
87
+ this.context = launched.context;
88
+ this.browser = launched.browser;
89
+ this.attached = launched.attached;
90
+ this.context.setDefaultTimeout(ACTION_TIMEOUT_MS);
91
+ this.context.setDefaultNavigationTimeout(NAVIGATION_TIMEOUT_MS);
92
+ await this.context.route('**/*', async (route) => {
93
+ const refusal = await this.options.network.refusal(route.request().url());
94
+ if (refusal)
95
+ await route.abort('blockedbyclient');
96
+ else
97
+ await route.continue();
98
+ });
99
+ this.context.on('page', (page) => this.adopt(page));
100
+ for (const page of this.context.pages())
101
+ this.adopt(page);
102
+ })();
103
+ try {
104
+ await this.starting;
105
+ if (this.closed)
106
+ throw new Error('The browser session has ended.');
107
+ }
108
+ finally {
109
+ this.starting = null;
110
+ }
111
+ }
112
+ adopt(page) {
113
+ const existing = [...this.tabs.values()].find((tab) => tab.page === page);
114
+ if (existing)
115
+ return existing;
116
+ const tab = { id: `t${this.nextTab++}`, page, generation: 0, refs: new Map(), refsGeneration: -1 };
117
+ this.tabs.set(tab.id, tab);
118
+ this.current ??= tab.id;
119
+ page.on('framenavigated', (frame) => {
120
+ if (frame === page.mainFrame())
121
+ tab.generation += 1;
122
+ });
123
+ page.on('close', () => {
124
+ this.tabs.delete(tab.id);
125
+ if (this.current === tab.id)
126
+ this.current = this.tabs.keys().next().value ?? null;
127
+ });
128
+ page.on('download', (download) => {
129
+ const name = fileName(download.suggestedFilename() || 'download');
130
+ const path = join(this.options.downloadsDir, `${Date.now()}-${name}`);
131
+ void download.saveAs(path).then(() => this.downloads.push({ tab: tab.id, path, name })).catch(() => undefined);
132
+ });
133
+ return tab;
134
+ }
135
+ /** A tab by id, or the current one, starting the browser and opening a first tab when needed. */
136
+ async tab(id) {
137
+ await this.start();
138
+ if (id) {
139
+ const tab = this.tabs.get(id);
140
+ if (!tab)
141
+ throw new Error(`There is no tab ${id}. browser_tabs lists them.`);
142
+ return tab;
143
+ }
144
+ if (this.current && this.tabs.has(this.current))
145
+ return this.tabs.get(this.current);
146
+ return this.open();
147
+ }
148
+ async open() {
149
+ await this.start();
150
+ const tab = this.adopt(await this.context.newPage());
151
+ this.current = tab.id;
152
+ return tab;
153
+ }
154
+ select(id) {
155
+ const tab = this.tabs.get(id);
156
+ if (!tab)
157
+ throw new Error(`There is no tab ${id}.`);
158
+ this.current = id;
159
+ return tab;
160
+ }
161
+ list() {
162
+ return [...this.tabs.values()].map((tab) => ({ id: tab.id, url: tab.page.url(), current: tab.id === this.current }));
163
+ }
164
+ /** What pages in this browser may reach. */
165
+ get network() {
166
+ return this.options.network;
167
+ }
168
+ get currentId() {
169
+ return this.current;
170
+ }
171
+ get started() {
172
+ return this.context !== null;
173
+ }
174
+ async close() {
175
+ this.closed = true;
176
+ await this.starting?.catch(() => undefined);
177
+ if (this.idle)
178
+ clearTimeout(this.idle);
179
+ const { context, browser, attached } = this;
180
+ this.context = null;
181
+ this.browser = null;
182
+ this.tabs.clear();
183
+ this.current = null;
184
+ await context?.close().catch(() => undefined);
185
+ // An attached browser belongs to a person: only our context goes.
186
+ if (!attached)
187
+ await browser?.close().catch(() => undefined);
188
+ if (this.temporaryProfile)
189
+ rmSync(this.temporaryProfile, { recursive: true, force: true });
190
+ this.temporaryProfile = null;
191
+ }
192
+ }
@@ -0,0 +1,8 @@
1
+ import type { ToolSpec } from "../tools/types.js";
2
+ import type { WorldContext } from "../world/world.js";
3
+ import type { BrowserSession } from "./session.js";
4
+ /** Longest snapshot sent, in lines and characters. */
5
+ export declare const SNAPSHOT_LINES = 500;
6
+ export declare const SNAPSHOT_CHARS = 40000;
7
+ export declare const BROWSER_TOOL_NAMES: readonly ["browser_navigate", "browser_snapshot", "browser_read", "browser_screenshot", "browser_click", "browser_type", "browser_select", "browser_press", "browser_scroll", "browser_wait", "browser_tabs"];
8
+ export declare function browserTools(context: WorldContext, session: () => BrowserSession): ToolSpec[];
@@ -0,0 +1,329 @@
1
+ import { askForAction, classifyAction, SENSITIVE_FIELD } from "../world/actions.js";
2
+ import { untrusted } from "../world/untrusted.js";
3
+ import { htmlToMarkdown } from "../web/markdown.js";
4
+ import { PAGE_CHARS } from "../web/tools.js";
5
+ /** Longest snapshot sent, in lines and characters. */
6
+ export const SNAPSHOT_LINES = 500;
7
+ export const SNAPSHOT_CHARS = 40_000;
8
+ export const BROWSER_TOOL_NAMES = ['browser_navigate', 'browser_snapshot', 'browser_read', 'browser_screenshot', 'browser_click', 'browser_type', 'browser_select', 'browser_press', 'browser_scroll', 'browser_wait', 'browser_tabs'];
9
+ const message = (error) => (error instanceof Error ? error.message.split('\n')[0] : String(error));
10
+ const isTimeout = (error) => error instanceof Error && (error.name === 'TimeoutError' || /Timeout \d+ms exceeded/.test(error.message));
11
+ const UNKNOWN = 'Its outcome is unknown: take browser_snapshot before trying again, so nothing is clicked, sent or bought twice.';
12
+ const tabParam = { type: 'string', description: 'Tab id from browser_tabs, such as t2. Defaults to the current tab.' };
13
+ const refParam = { type: 'string', description: 'The element\'s ref from the latest browser_snapshot of the tab, such as e12.' };
14
+ const text = (value) => (typeof value === 'string' ? value : '');
15
+ async function where(tab) {
16
+ const title = await tab.page.title().catch(() => '');
17
+ return `Tab ${tab.id}: ${tab.page.url()}${title ? ` — ${title}` : ''}`;
18
+ }
19
+ /** An element named by a ref of the tab's latest snapshot. */
20
+ function element(tab, ref) {
21
+ const id = ref.trim().replace(/^@/, '').replace(/^ref=/, '');
22
+ if (tab.refsGeneration !== tab.generation)
23
+ throw new Error(`The page in ${tab.id} changed since its last snapshot. Take browser_snapshot again and use a ref from it.`);
24
+ const line = tab.refs.get(id);
25
+ if (!line)
26
+ throw new Error(`There is no ref ${id} in the latest snapshot of ${tab.id}. Take browser_snapshot again.`);
27
+ return { locator: tab.page.getByRef(id), line };
28
+ }
29
+ /** Asks the person when the action falls in a category that needs them; null when it may go ahead. */
30
+ async function approve(context, tool, tab, target, args) {
31
+ const verdict = classifyAction(target);
32
+ if (!verdict)
33
+ return null;
34
+ if (!context.attended || !context.run)
35
+ return `Refused: this would ${verdict.reason}, and nobody can approve it in this run.`;
36
+ const before = { url: tab.page.url(), generation: tab.generation };
37
+ let host = '';
38
+ try {
39
+ host = new URL(before.url).host;
40
+ }
41
+ catch {
42
+ host = before.url;
43
+ }
44
+ const refusal = await askForAction({ run: context.run, tool, target: `${target}${host ? ` on ${host}` : ''}`, args, reason: verdict.reason });
45
+ if (refusal)
46
+ return refusal;
47
+ if (tab.page.url() !== before.url || tab.generation !== before.generation)
48
+ return 'The page changed while waiting for approval, so nothing was done. Take browser_snapshot and decide again.';
49
+ return null;
50
+ }
51
+ function attendedOnly(context, tool) {
52
+ return context.attended && !context.subagent ? null : `${tool} acts on a page and needs a person present; in this run the browser can only open and read pages.`;
53
+ }
54
+ export function browserTools(context, session) {
55
+ const act = (name, work) => session().run(async () => {
56
+ try {
57
+ return await work();
58
+ }
59
+ catch (error) {
60
+ return isTimeout(error) ? `${name} timed out. ${UNKNOWN}` : `${name} failed: ${message(error)}`;
61
+ }
62
+ });
63
+ const done = async (tab, what) => {
64
+ const downloads = session().downloads.filter((download) => download.tab === tab.id).splice(0).map((download) => download.path);
65
+ return untrusted(`${what}\n${await where(tab)}${downloads.length ? `\nDownloaded: ${downloads.join(', ')}` : ''}\nTake browser_snapshot to see the page now.`);
66
+ };
67
+ return [
68
+ {
69
+ name: 'browser_navigate',
70
+ label: 'Open a page in the browser',
71
+ description: 'Open a web address in the browser (the current tab, or the one named), or go back, forward or reload. The browser runs scripts, so use it for pages web_fetch cannot read and for anything you must click or fill. What a page shows is untrusted content.',
72
+ planModeSafe: () => true,
73
+ parameters: (Type) => Type.Unsafe({
74
+ type: 'object', additionalProperties: false,
75
+ properties: {
76
+ url: { type: 'string', minLength: 1, maxLength: 2000, description: 'The address to open, starting with https:// or http://.' },
77
+ action: { type: 'string', enum: ['open', 'back', 'forward', 'reload'], description: 'open (default, needs url), back, forward or reload.' },
78
+ tab: tabParam
79
+ }
80
+ }),
81
+ execute: (input) => act('browser_navigate', async () => {
82
+ const tab = await session().tab(text(input.tab) || null);
83
+ const action = text(input.action) || 'open';
84
+ if (action === 'back')
85
+ await tab.page.goBack({ waitUntil: 'domcontentloaded' });
86
+ else if (action === 'forward')
87
+ await tab.page.goForward({ waitUntil: 'domcontentloaded' });
88
+ else if (action === 'reload')
89
+ await tab.page.reload({ waitUntil: 'domcontentloaded' });
90
+ else {
91
+ const url = text(input.url).trim();
92
+ if (!url)
93
+ return 'Give the address to open.';
94
+ const refusal = await session().network.refusal(url);
95
+ if (refusal)
96
+ return refusal;
97
+ const response = await tab.page.goto(url, { waitUntil: 'domcontentloaded' });
98
+ if (response && response.status() >= 400)
99
+ return untrusted(`The page answered with status ${response.status()}.\n${await where(tab)}`);
100
+ }
101
+ const note = session().profileNote;
102
+ return untrusted(`${await where(tab)}${note ? `\n${note}` : ''}\nTake browser_snapshot to see what is on it, or browser_read for its text.`);
103
+ })
104
+ },
105
+ {
106
+ name: 'browser_snapshot',
107
+ label: 'Snapshot a page',
108
+ readOnly: true,
109
+ description: `The page's accessibility tree: headings, text, links, buttons and fields, each actionable one with a ref (such as e12) that browser_click, browser_type and browser_select take. Refs belong to this snapshot: after the page changes, take a new one. At most ${SNAPSHOT_LINES} lines; pass depth to see less.`,
110
+ parameters: (Type) => Type.Unsafe({
111
+ type: 'object', additionalProperties: false,
112
+ properties: { tab: tabParam, depth: { type: 'integer', minimum: 1, maximum: 40, description: 'Only this many levels of the tree.' } }
113
+ }),
114
+ execute: (input) => act('browser_snapshot', async () => {
115
+ const tab = await session().tab(text(input.tab) || null);
116
+ const depth = Number(input.depth);
117
+ const snapshot = await tab.page.ariaSnapshot({ mode: 'ai', ...(Number.isInteger(depth) && depth > 0 ? { depth } : {}), timeout: 15_000 });
118
+ tab.refs = new Map();
119
+ for (const line of snapshot.split('\n')) {
120
+ const ref = /\[ref=([a-z0-9]+)\]/i.exec(line)?.[1];
121
+ if (ref)
122
+ tab.refs.set(ref, line.trim().replace(/^- /, '').slice(0, 240));
123
+ }
124
+ tab.refsGeneration = tab.generation;
125
+ const lines = snapshot.split('\n');
126
+ let shown = lines.slice(0, SNAPSHOT_LINES).join('\n');
127
+ const cut = lines.length > SNAPSHOT_LINES || shown.length > SNAPSHOT_CHARS;
128
+ if (shown.length > SNAPSHOT_CHARS)
129
+ shown = shown.slice(0, SNAPSHOT_CHARS);
130
+ return untrusted(`${await where(tab)}\n\n${shown}${cut ? `\n\n(The snapshot was cut at ${SNAPSHOT_LINES} lines. Pass a smaller depth, scroll, or use browser_read for the text.)` : ''}`);
131
+ })
132
+ },
133
+ {
134
+ name: 'browser_read',
135
+ label: 'Read a page as text',
136
+ readOnly: true,
137
+ description: `The visible text of the tab's page as Markdown, after its scripts ran. Up to ${PAGE_CHARS.toLocaleString('en-US')} characters; pass offset to read on.`,
138
+ parameters: (Type) => Type.Unsafe({
139
+ type: 'object', additionalProperties: false,
140
+ properties: { tab: tabParam, offset: { type: 'integer', minimum: 0, description: 'Character to start from.' } }
141
+ }),
142
+ execute: (input) => act('browser_read', async () => {
143
+ const tab = await session().tab(text(input.tab) || null);
144
+ const { title, text: markdown } = htmlToMarkdown(await tab.page.content());
145
+ const offset = Math.max(0, Math.floor(Number(input.offset)) || 0);
146
+ const end = Math.min(markdown.length, offset + PAGE_CHARS);
147
+ const more = end < markdown.length ? `\n\n(More: call browser_read with offset ${end}.)` : '';
148
+ return untrusted(`Tab ${tab.id}: ${tab.page.url()}${title ? ` — ${title}` : ''}\nCharacters ${offset}–${end} of ${markdown.length}\n\n${markdown.slice(offset, end)}${more}`);
149
+ })
150
+ },
151
+ {
152
+ name: 'browser_screenshot',
153
+ label: 'Screenshot a page',
154
+ readOnly: true,
155
+ description: 'A picture of what the tab shows (1280×800), or of one element by ref. Use it when layout or images matter; a snapshot is cheaper for finding what to click.',
156
+ parameters: (Type) => Type.Unsafe({ type: 'object', additionalProperties: false, properties: { tab: tabParam, ref: refParam } }),
157
+ execute: (input) => act('browser_screenshot', async () => {
158
+ const tab = await session().tab(text(input.tab) || null);
159
+ const ref = text(input.ref);
160
+ const shot = ref ? await element(tab, ref).locator.screenshot({ type: 'jpeg', quality: 70 }) : await tab.page.screenshot({ type: 'jpeg', quality: 70 });
161
+ return { text: untrusted(`Screenshot of ${ref ? `element ${ref} in ` : ''}${await where(tab)}`), image: { data: shot.toString('base64'), mimeType: 'image/jpeg' } };
162
+ })
163
+ },
164
+ {
165
+ name: 'browser_click',
166
+ label: 'Click on a page',
167
+ description: 'Click an element by its ref. A click that would send, buy, delete, change an account or grant access asks the user first.',
168
+ parameters: (Type) => Type.Unsafe({
169
+ type: 'object', additionalProperties: false, required: ['ref'],
170
+ properties: { ref: refParam, tab: tabParam, double: { type: 'boolean', description: 'Double-click.' }, button: { type: 'string', enum: ['left', 'right', 'middle'] } }
171
+ }),
172
+ execute: async (input) => attendedOnly(context, 'browser_click') ?? act('browser_click', async () => {
173
+ const tab = await session().tab(text(input.tab) || null);
174
+ const { locator, line } = element(tab, text(input.ref));
175
+ const refusal = await approve(context, 'browser_click', tab, line, input);
176
+ if (refusal)
177
+ return refusal;
178
+ const button = input.button === 'right' || input.button === 'middle' ? input.button : 'left';
179
+ if (input.double === true)
180
+ await locator.dblclick({ button });
181
+ else
182
+ await locator.click({ button });
183
+ return done(tab, `Clicked ${line}.`);
184
+ })
185
+ },
186
+ {
187
+ name: 'browser_type',
188
+ label: 'Type into a page',
189
+ description: 'Type text into a field by its ref, replacing what is there; submit presses Enter afterwards. Password, card and one-time-code fields are refused: ask the user to fill those. Submitting a form that sends, buys or deletes asks the user first.',
190
+ parameters: (Type) => Type.Unsafe({
191
+ type: 'object', additionalProperties: false, required: ['ref', 'text'],
192
+ properties: { ref: refParam, text: { type: 'string', maxLength: 20_000 }, submit: { type: 'boolean', description: 'Press Enter after typing.' }, tab: tabParam }
193
+ }),
194
+ execute: async (input) => attendedOnly(context, 'browser_type') ?? act('browser_type', async () => {
195
+ const tab = await session().tab(text(input.tab) || null);
196
+ const { locator, line } = element(tab, text(input.ref));
197
+ const secret = SENSITIVE_FIELD.test(line) || await locator.evaluate(field => field.getAttribute('type') === 'password' || /cc-|one-time-code|current-password|new-password/.test(field.getAttribute('autocomplete') ?? '')).catch(() => false);
198
+ if (secret)
199
+ return 'That field takes a password, a card number or a code. Ask the user to fill it themselves.';
200
+ if (input.submit === true) {
201
+ const refusal = await approve(context, 'browser_type', tab, `submit ${line}`, { ...input, text: `[${text(input.text).length} characters]` });
202
+ if (refusal)
203
+ return refusal;
204
+ }
205
+ await locator.fill(text(input.text));
206
+ if (input.submit === true)
207
+ await locator.press('Enter');
208
+ return done(tab, `Typed ${text(input.text).length} characters into ${line}${input.submit === true ? ' and submitted' : ''}.`);
209
+ })
210
+ },
211
+ {
212
+ name: 'browser_select',
213
+ label: 'Choose in a list',
214
+ description: 'Choose one or more options of a drop-down list by its ref, by the options\' labels or values.',
215
+ parameters: (Type) => Type.Unsafe({
216
+ type: 'object', additionalProperties: false, required: ['ref', 'values'],
217
+ properties: { ref: refParam, values: { type: 'array', minItems: 1, items: { type: 'string' } }, tab: tabParam }
218
+ }),
219
+ execute: async (input) => attendedOnly(context, 'browser_select') ?? act('browser_select', async () => {
220
+ const tab = await session().tab(text(input.tab) || null);
221
+ const { locator, line } = element(tab, text(input.ref));
222
+ const values = Array.isArray(input.values) ? input.values.filter((value) => typeof value === 'string') : [];
223
+ const chosen = await locator.selectOption(values);
224
+ return done(tab, `Chose ${chosen.join(', ') || 'nothing'} in ${line}.`);
225
+ })
226
+ },
227
+ {
228
+ name: 'browser_press',
229
+ label: 'Press a key on a page',
230
+ description: 'Press a key or a combination in the tab, such as Enter, Escape, Tab, ArrowDown or Control+A. Enter in a message box asks the user first.',
231
+ parameters: (Type) => Type.Unsafe({
232
+ type: 'object', additionalProperties: false, required: ['key'],
233
+ properties: { key: { type: 'string', minLength: 1, maxLength: 60 }, tab: tabParam }
234
+ }),
235
+ execute: async (input) => attendedOnly(context, 'browser_press') ?? act('browser_press', async () => {
236
+ const tab = await session().tab(text(input.tab) || null);
237
+ const key = text(input.key).trim();
238
+ if (/(^|\+)Enter$/i.test(key)) {
239
+ // Runs in the page: what has focus, and whether Enter there would send something.
240
+ const focused = await tab.page.evaluate(`(() => {
241
+ const node = document.activeElement
242
+ if (!node) return ''
243
+ const sends = node.tagName === 'TEXTAREA' || node.isContentEditable || !!node.closest('form')
244
+ return sends ? 'submit ' + (node.getAttribute('aria-label') || node.getAttribute('placeholder') || node.tagName.toLowerCase()) + ' form' : ''
245
+ })()`).then((value) => String(value ?? '')).catch(() => '');
246
+ if (focused) {
247
+ const refusal = await approve(context, 'browser_press', tab, `${focused} (send)`, input);
248
+ if (refusal)
249
+ return refusal;
250
+ }
251
+ }
252
+ await tab.page.keyboard.press(key);
253
+ return done(tab, `Pressed ${key}.`);
254
+ })
255
+ },
256
+ {
257
+ name: 'browser_scroll',
258
+ label: 'Scroll a page',
259
+ readOnly: true,
260
+ description: 'Scroll the tab up or down by about a screen, or bring an element (by ref) into view.',
261
+ parameters: (Type) => Type.Unsafe({
262
+ type: 'object', additionalProperties: false,
263
+ properties: { direction: { type: 'string', enum: ['up', 'down'] }, ref: refParam, tab: tabParam }
264
+ }),
265
+ execute: (input) => act('browser_scroll', async () => {
266
+ const tab = await session().tab(text(input.tab) || null);
267
+ if (text(input.ref))
268
+ await element(tab, text(input.ref)).locator.scrollIntoViewIfNeeded();
269
+ else
270
+ await tab.page.mouse.wheel(0, input.direction === 'up' ? -650 : 650);
271
+ return untrusted(`Scrolled. ${await where(tab)}`);
272
+ })
273
+ },
274
+ {
275
+ name: 'browser_wait',
276
+ label: 'Wait on a page',
277
+ readOnly: true,
278
+ description: 'Wait until some text appears in the tab (up to 30 seconds), or for a number of milliseconds (up to 10,000).',
279
+ parameters: (Type) => Type.Unsafe({
280
+ type: 'object', additionalProperties: false,
281
+ properties: { text: { type: 'string', minLength: 1, maxLength: 200 }, ms: { type: 'integer', minimum: 1, maximum: 10_000 }, tab: tabParam }
282
+ }),
283
+ execute: (input) => act('browser_wait', async () => {
284
+ const tab = await session().tab(text(input.tab) || null);
285
+ if (text(input.text)) {
286
+ await tab.page.getByText(text(input.text)).first().waitFor({ timeout: 30_000 });
287
+ return untrusted(`"${text(input.text)}" is on the page. ${await where(tab)}`);
288
+ }
289
+ await tab.page.waitForTimeout(Math.min(10_000, Math.max(1, Math.floor(Number(input.ms)) || 1000)));
290
+ return untrusted(`Waited. ${await where(tab)}`);
291
+ })
292
+ },
293
+ {
294
+ name: 'browser_tabs',
295
+ label: 'Browser tabs',
296
+ description: 'List the tabs, open a new one (optionally at an address), switch to one, or close one.',
297
+ planModeSafe: (input) => input.op !== 'close',
298
+ parameters: (Type) => Type.Unsafe({
299
+ type: 'object', additionalProperties: false, required: ['op'],
300
+ properties: { op: { type: 'string', enum: ['list', 'new', 'switch', 'close'] }, tab: tabParam, url: { type: 'string', maxLength: 2000 } }
301
+ }),
302
+ execute: (input) => act('browser_tabs', async () => {
303
+ const browser = session();
304
+ if (input.op === 'new') {
305
+ const url = text(input.url).trim();
306
+ if (url) {
307
+ const refusal = await browser.network.refusal(url);
308
+ if (refusal)
309
+ return refusal;
310
+ }
311
+ const tab = await browser.open();
312
+ if (url)
313
+ await tab.page.goto(url, { waitUntil: 'domcontentloaded' });
314
+ return untrusted(`Opened ${await where(tab)}`);
315
+ }
316
+ if (input.op === 'switch')
317
+ return untrusted(`Now in ${await where(browser.select(text(input.tab)))}`);
318
+ if (input.op === 'close') {
319
+ const tab = await browser.tab(text(input.tab) || null);
320
+ await tab.page.close();
321
+ return `Closed ${tab.id}.`;
322
+ }
323
+ if (!browser.started)
324
+ return 'No tabs are open yet. browser_navigate opens one.';
325
+ return untrusted(browser.list().map((tab) => `${tab.current ? '*' : ' '} ${tab.id} ${tab.url}`).join('\n'));
326
+ })
327
+ }
328
+ ];
329
+ }
@@ -0,0 +1,22 @@
1
+ import type { Harness } from "../harness.js";
2
+ import type { CallerContext } from "../core/caller.js";
3
+ import type { Launch } from "../prompt/compile.js";
4
+ import * as pluginApi from "../plugins/api.js";
5
+ import type { CapabilityCatalogue, CapabilityScope, CapabilitySet } from "./types.js";
6
+ export interface ListParams extends CapabilityScope {
7
+ }
8
+ export interface InventoryParams extends CapabilityScope {
9
+ context?: CallerContext;
10
+ launch?: Launch;
11
+ tools?: string[];
12
+ connections?: boolean;
13
+ }
14
+ export declare function list(harness: Harness, params?: ListParams): Promise<CapabilityCatalogue>;
15
+ /** The resolved callable set for one caller, based on the stores and caller-supplied tool list. */
16
+ export declare function resolve(harness: Harness, params: ListParams & {
17
+ tools?: readonly string[];
18
+ }): Promise<CapabilitySet>;
19
+ export declare function toolIntersection(parent: CapabilitySet, assignee: CapabilitySet, taskTools?: readonly string[]): CapabilitySet;
20
+ export declare function inventory(harness: Harness, params?: InventoryParams): Promise<import("../index.js").Inventory>;
21
+ export declare function attach(harness: Harness, params: pluginApi.AttachParams, on: boolean): Promise<CapabilityCatalogue>;
22
+ export declare function switchCapability(harness: Harness, params: pluginApi.AttachParams, on: boolean): Promise<CapabilityCatalogue>;
@@ -0,0 +1,54 @@
1
+ // A generic view of what is available to a caller. The existing plugin, registry, and connector
2
+ // stores remain the source of truth; this module gives hosts one capability-shaped contract.
3
+ import { invalid } from "../core/errors.js";
4
+ import * as pluginApi from "../plugins/api.js";
5
+ const unique = (values) => [...new Set(values.filter((value) => value.length > 0))];
6
+ function contributions(plugins) {
7
+ return plugins.flatMap((plugin) => plugin.contributions.map((item) => ({
8
+ id: item.id,
9
+ pluginId: plugin.id,
10
+ kind: item.kind,
11
+ name: item.name,
12
+ description: item.description,
13
+ source: plugin.source,
14
+ state: item.state,
15
+ attachment: item.attachment
16
+ })));
17
+ }
18
+ export async function list(harness, params = {}) {
19
+ const plugins = await pluginApi.list(harness, params);
20
+ return { plugins, capabilities: contributions(plugins) };
21
+ }
22
+ /** The resolved callable set for one caller, based on the stores and caller-supplied tool list. */
23
+ export async function resolve(harness, params) {
24
+ const caller = { agentId: params.agentId ?? null, projectId: params.projectId ?? null };
25
+ const catalogue = await list(harness, params);
26
+ const connectors = harness.apps.connections.forScope(caller).map((connection) => connection.id);
27
+ return {
28
+ version: 1,
29
+ tools: unique(params.tools ?? []),
30
+ connectors: unique(connectors),
31
+ contributions: catalogue.capabilities.filter((item) => item.state === 'on').map((item) => item.id)
32
+ };
33
+ }
34
+ export function toolIntersection(parent, assignee, taskTools) {
35
+ const permitted = taskTools === undefined ? null : new Set(taskTools);
36
+ return {
37
+ version: 1,
38
+ tools: parent.tools.filter((tool) => assignee.tools.includes(tool) && (!permitted || permitted.has(tool))),
39
+ connectors: parent.connectors.filter((id) => assignee.connectors.includes(id)),
40
+ contributions: parent.contributions.filter((id) => assignee.contributions.includes(id))
41
+ };
42
+ }
43
+ export function inventory(harness, params = {}) {
44
+ return pluginApi.inventoryFor(harness, params);
45
+ }
46
+ export async function attach(harness, params, on) {
47
+ const plugins = await pluginApi.attach(harness, params, on);
48
+ return { plugins, capabilities: contributions(plugins) };
49
+ }
50
+ export async function switchCapability(harness, params, on) {
51
+ if (!params.id.trim())
52
+ throw invalid('A capability id is required.');
53
+ return attach(harness, params, on);
54
+ }
@@ -0,0 +1,18 @@
1
+ import type { CapabilitySet } from "./types.js";
2
+ export interface RunCapabilitySnapshot {
3
+ version: 1;
4
+ caller: {
5
+ agentId: string | null;
6
+ projectId: string | null;
7
+ };
8
+ tools: string[];
9
+ connectors: string[];
10
+ contributions: string[];
11
+ }
12
+ export declare function capabilitySet(value: unknown): CapabilitySet;
13
+ /** Writes a run's capability set once. A resumed or duplicate launch cannot replace it. */
14
+ export declare function freezeRun(root: string, runId: string, caller: {
15
+ agentId?: string | null;
16
+ projectId?: string | null;
17
+ }, set: CapabilitySet): RunCapabilitySnapshot;
18
+ export declare function loadRun(root: string, runId: string): RunCapabilitySnapshot | null;