@xingular/harness 0.1.6 → 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 (593) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +60 -0
  4. package/README.md +265 -71
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +14842 -9445
  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 +1170 -62
  373. package/docs/README.md +34 -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-0001-owned-terminal.md +87 -0
  403. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  404. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  405. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  406. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  407. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  408. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  409. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  410. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  411. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  412. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  413. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  414. package/docs/decisions/ADR-0013-doctor.md +27 -0
  415. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  416. package/docs/doctor.md +74 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  418. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  420. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  421. package/docs/features/README.md +20 -0
  422. package/docs/features/automations/README.md +41 -0
  423. package/docs/features/cores/README.md +39 -0
  424. package/docs/features/google-harness2/README.md +52 -0
  425. package/docs/features/integrations/README.md +40 -0
  426. package/docs/features/interfaces/README.md +29 -0
  427. package/docs/features/memory/README.md +28 -0
  428. package/docs/releases/1.0.0.md +40 -0
  429. package/docs/releases/README.md +36 -0
  430. package/docs/study/00-index.md +78 -0
  431. package/docs/study/arms/00-matrix.md +20 -0
  432. package/docs/study/arms/01-system-prompt.md +211 -0
  433. package/docs/study/arms/02-tools.md +79 -0
  434. package/docs/study/arms/03-subagents.md +90 -0
  435. package/docs/study/arms/04-skills.md +75 -0
  436. package/docs/study/arms/05-context-management.md +90 -0
  437. package/docs/study/arms/06-memory.md +90 -0
  438. package/docs/study/arms/07-governance.md +71 -0
  439. package/docs/study/arms/08-execution.md +69 -0
  440. package/docs/study/arms/09-observability.md +60 -0
  441. package/docs/study/arms/10-refinement.md +110 -0
  442. package/docs/study/btw-comparison.md +37 -0
  443. package/docs/study/feature-gap-review.md +42 -0
  444. package/docs/study/insights.md +123 -0
  445. package/docs/study/roadmap.md +72 -0
  446. package/docs/study/sources/claude-code.md +44 -0
  447. package/docs/study/sources/deepseek-harness.md +102 -0
  448. package/docs/study/sources/harness2.md +50 -0
  449. package/docs/study/sources/kimi-cli.md +42 -0
  450. package/docs/study/sources/omp.md +93 -0
  451. package/docs/study/sources/opencode.md +43 -0
  452. package/docs/study/sources/openhands.md +46 -0
  453. package/docs/study/sources/smolagents.md +40 -0
  454. package/docs/study/sources/swe-agent.md +34 -0
  455. package/docs/system-prompt-design.md +196 -0
  456. package/docs/terminal-tui.md +671 -0
  457. package/package.json +48 -12
  458. package/src/accounts/accounts.test.ts +0 -223
  459. package/src/accounts/accounts.ts +0 -522
  460. package/src/accounts/env.test.ts +0 -95
  461. package/src/accounts/env.ts +0 -338
  462. package/src/accounts/secrets.ts +0 -50
  463. package/src/accounts/store.ts +0 -338
  464. package/src/capabilities/api.ts +0 -75
  465. package/src/capabilities/runSnapshot.ts +0 -59
  466. package/src/capabilities/types.ts +0 -34
  467. package/src/cli.ts +0 -114
  468. package/src/core/bus.ts +0 -34
  469. package/src/core/changes.ts +0 -33
  470. package/src/core/env.ts +0 -27
  471. package/src/core/errors.ts +0 -32
  472. package/src/core/frontmatter.ts +0 -47
  473. package/src/core/fs.test.ts +0 -38
  474. package/src/core/fs.ts +0 -92
  475. package/src/core/index.ts +0 -193
  476. package/src/core/path.test.ts +0 -14
  477. package/src/core/path.ts +0 -79
  478. package/src/core/projects.ts +0 -90
  479. package/src/core/text.ts +0 -39
  480. package/src/harness.ts +0 -299
  481. package/src/index.ts +0 -70
  482. package/src/mcp/connections.ts +0 -614
  483. package/src/mcp/manager.ts +0 -130
  484. package/src/mcp/oauth.ts +0 -195
  485. package/src/mcp/scopeMigration.test.ts +0 -79
  486. package/src/mcp/scopeMigration.ts +0 -204
  487. package/src/mcp/service.test.ts +0 -376
  488. package/src/mcp/service.ts +0 -549
  489. package/src/mcp/types.ts +0 -108
  490. package/src/memory/api.test.ts +0 -82
  491. package/src/memory/api.ts +0 -289
  492. package/src/memory/blocks.test.ts +0 -78
  493. package/src/memory/blocks.ts +0 -406
  494. package/src/memory/caller.ts +0 -57
  495. package/src/memory/dispatch.ts +0 -59
  496. package/src/memory/facts.test.ts +0 -41
  497. package/src/memory/facts.ts +0 -248
  498. package/src/memory/graph.ts +0 -103
  499. package/src/memory/health.test.ts +0 -130
  500. package/src/memory/health.ts +0 -74
  501. package/src/memory/maintainer.ts +0 -272
  502. package/src/memory/maintenance.test.ts +0 -176
  503. package/src/memory/maintenance.ts +0 -330
  504. package/src/memory/migrate.ts +0 -79
  505. package/src/memory/operations.ts +0 -138
  506. package/src/memory/proposals.test.ts +0 -168
  507. package/src/memory/proposals.ts +0 -576
  508. package/src/memory/recall.test.ts +0 -104
  509. package/src/memory/recall.ts +0 -271
  510. package/src/memory/references.ts +0 -77
  511. package/src/memory/runContext.ts +0 -93
  512. package/src/memory/secrets.ts +0 -6
  513. package/src/memory/store.test.ts +0 -66
  514. package/src/memory/store.ts +0 -385
  515. package/src/memory/wiki.test.ts +0 -47
  516. package/src/memory/wiki.ts +0 -422
  517. package/src/memory/wikiIndex.test.ts +0 -88
  518. package/src/memory/wikiIndex.ts +0 -116
  519. package/src/plugins/api.ts +0 -181
  520. package/src/plugins/attachments.test.ts +0 -84
  521. package/src/plugins/attachments.ts +0 -141
  522. package/src/plugins/builtin.ts +0 -82
  523. package/src/plugins/catalogue.test.ts +0 -254
  524. package/src/plugins/catalogue.ts +0 -251
  525. package/src/plugins/cli.ts +0 -184
  526. package/src/plugins/discover.ts +0 -151
  527. package/src/plugins/firstParty.test.ts +0 -143
  528. package/src/plugins/firstParty.ts +0 -129
  529. package/src/plugins/hooks.test.ts +0 -250
  530. package/src/plugins/hooks.ts +0 -239
  531. package/src/plugins/identity.ts +0 -37
  532. package/src/plugins/install.test.ts +0 -107
  533. package/src/plugins/install.ts +0 -106
  534. package/src/plugins/inventory.ts +0 -123
  535. package/src/plugins/manifest.ts +0 -76
  536. package/src/plugins/plugins.test.ts +0 -205
  537. package/src/plugins/plugins.ts +0 -189
  538. package/src/plugins/proposal.ts +0 -121
  539. package/src/plugins/runtime.test.ts +0 -40
  540. package/src/plugins/runtime.ts +0 -82
  541. package/src/plugins/trust.ts +0 -142
  542. package/src/plugins/types.ts +0 -149
  543. package/src/prompt/compile.test.ts +0 -261
  544. package/src/prompt/compile.ts +0 -732
  545. package/src/server/methods.ts +0 -314
  546. package/src/server/remote.ts +0 -77
  547. package/src/server/rpc.ts +0 -116
  548. package/src/server/serve.ts +0 -28
  549. package/src/server/server.test.ts +0 -174
  550. package/src/sessions/approvals.ts +0 -118
  551. package/src/sessions/contracts.ts +0 -310
  552. package/src/sessions/conversation.test.ts +0 -150
  553. package/src/sessions/extensionSession.test.ts +0 -74
  554. package/src/sessions/extensionUi.test.ts +0 -65
  555. package/src/sessions/extensionUi.ts +0 -102
  556. package/src/sessions/history.ts +0 -51
  557. package/src/sessions/lineageJoin.ts +0 -75
  558. package/src/sessions/policy.ts +0 -32
  559. package/src/sessions/pricing.ts +0 -60
  560. package/src/sessions/reasoningSummaries.ts +0 -59
  561. package/src/sessions/registry.ts +0 -294
  562. package/src/sessions/runIndex.ts +0 -99
  563. package/src/sessions/runStore.test.ts +0 -152
  564. package/src/sessions/runStore.ts +0 -332
  565. package/src/sessions/runner.ts +0 -569
  566. package/src/sessions/runtimeResources.test.ts +0 -61
  567. package/src/sessions/sessions.test.ts +0 -455
  568. package/src/sessions/sessions.ts +0 -295
  569. package/src/skills/registry.test.ts +0 -104
  570. package/src/skills/registry.ts +0 -407
  571. package/src/terminal/cli.ts +0 -149
  572. package/src/terminal/client.ts +0 -74
  573. package/src/terminal/controller.ts +0 -227
  574. package/src/terminal/launch.test.ts +0 -34
  575. package/src/terminal/launch.ts +0 -88
  576. package/src/terminal/piExtension.ts +0 -210
  577. package/src/terminal/pluginControl.test.ts +0 -146
  578. package/src/terminal/pluginMenu.ts +0 -112
  579. package/src/terminal/socket.test.ts +0 -71
  580. package/src/terminal/socket.ts +0 -221
  581. package/src/terminal/standalone.test.ts +0 -130
  582. package/src/terminal/standalone.ts +0 -144
  583. package/src/terminal/terminal.test.ts +0 -330
  584. package/src/terminal/terminals.ts +0 -443
  585. package/src/tools/askUser.ts +0 -45
  586. package/src/tools/definitions.ts +0 -187
  587. package/src/tools/memoryTools.ts +0 -22
  588. package/src/tools/pluginPropose.ts +0 -41
  589. package/src/tools/types.ts +0 -39
  590. package/src/web/safeRequest.ts +0 -171
  591. package/src/web/text.ts +0 -53
  592. package/src/web/tools.ts +0 -134
  593. package/src/web/web.test.ts +0 -141
@@ -0,0 +1,255 @@
1
+ // Accounts. One profile (settings, registry, memory) and any number of Pi accounts, each with
2
+ // its own isolated agent folder, stored credentials, sign-in state, limits, health, and audit
3
+ // trail.
4
+ //
5
+ // Device-local layout under `<state dir>/accounts/`:
6
+ // accounts.json accounts, the default, pools (no secrets)
7
+ // <id>/state.json health, plan, limits, last error (no secrets)
8
+ // <id>/home/pi/ Pi's own agent folder for this account
9
+ // _shared/pi/ settings, skills, prompts linked into every account's agent folder
10
+ // audit.jsonl append-only account actions (secrets scrubbed)
11
+ //
12
+ // Switching is always manual. A pool only chooses an account when a session starts; a running
13
+ // or resumed session keeps the account it started with.
14
+ import { mkdirSync, readFileSync } from 'node:fs';
15
+ import { join } from 'node:path';
16
+ import { HarnessError, invalid, notFound } from "../core/errors.js";
17
+ import { appendLine, newId, now, readJsonOr, safeId, writeJson } from "../core/fs.js";
18
+ import { charCount, compareText, lines, takeChars } from "../core/text.js";
19
+ /** The only provider the harness runs. Records of other providers are kept in the file and ignored. */
20
+ export const PROVIDER = 'pi';
21
+ export const emptyState = () => ({ health: 'unknown', signedIn: null, authMethod: null, plan: null, identity: null, limits: [], lastError: null, lastCheckedAt: null, cliVersion: null, capabilities: [], piProviders: [] });
22
+ // ---- Files ------------------------------------------------------------------------------
23
+ const registryPath = (dir) => join(dir, 'accounts.json');
24
+ const statePath = (dir, accountId) => join(dir, safeId(accountId), 'state.json');
25
+ export function loadRegistry(dir) {
26
+ const stored = readJsonOr(registryPath(dir), {}) ?? {};
27
+ return { accounts: stored.accounts ?? [], defaults: stored.defaults ?? {}, pools: stored.pools ?? [], migratedProviderKeys: stored.migratedProviderKeys ?? false };
28
+ }
29
+ export function saveRegistry(dir, registry) {
30
+ mkdirSync(dir, { recursive: true });
31
+ writeJson(registryPath(dir), registry);
32
+ }
33
+ export function loadState(dir, accountId) {
34
+ try {
35
+ return { ...emptyState(), ...(readJsonOr(statePath(dir, accountId), {}) ?? {}) };
36
+ }
37
+ catch {
38
+ return emptyState();
39
+ }
40
+ }
41
+ function saveState(dir, accountId, state) {
42
+ writeJson(statePath(dir, accountId), state);
43
+ }
44
+ /** Replaces anything that looks like a token so audit lines and stored errors never hold secrets. */
45
+ export function scrub(text) {
46
+ const words = text.split(' ').map((word) => {
47
+ const bytes = Buffer.byteLength(word);
48
+ const tokenLike = bytes >= 24 && (word.match(/[A-Za-z0-9]/g)?.length ?? 0) * 10 >= bytes * 8;
49
+ return tokenLike || word.startsWith('sk-') || word.startsWith('sess-') ? '[redacted]' : word;
50
+ });
51
+ return takeChars(words.join(' '), 500);
52
+ }
53
+ export function audit(dir, accountId, action, detail) {
54
+ try {
55
+ mkdirSync(dir, { recursive: true });
56
+ appendLine(join(dir, 'audit.jsonl'), JSON.stringify({ at: now(), accountId, action, detail: scrub(detail) }));
57
+ }
58
+ catch {
59
+ // An audit line that cannot be written never fails the action it describes.
60
+ }
61
+ }
62
+ /** The newest audit entries first, optionally for one account. */
63
+ export function readAudit(dir, accountId, limit = 100) {
64
+ let text = '';
65
+ try {
66
+ text = readFileSync(join(dir, 'audit.jsonl'), 'utf8');
67
+ }
68
+ catch {
69
+ text = '';
70
+ }
71
+ const entries = lines(text).flatMap((line) => {
72
+ try {
73
+ const entry = JSON.parse(line);
74
+ return entry && typeof entry.at === 'string' && typeof entry.action === 'string' && (!accountId || entry.accountId === accountId) ? [entry] : [];
75
+ }
76
+ catch {
77
+ return [];
78
+ }
79
+ });
80
+ return entries.reverse().slice(0, Math.min(limit, 1000));
81
+ }
82
+ // ---- Health -----------------------------------------------------------------------------
83
+ function inFuture(timestamp) {
84
+ const time = timestamp ? Date.parse(timestamp) : Number.NaN;
85
+ return !Number.isNaN(time) && time > Date.now();
86
+ }
87
+ // How long a limit error that came without a reset time keeps the account limited. Providers
88
+ // report no limit windows, so nothing else would ever lift it.
89
+ const UNTIMED_LIMIT_ERROR_SECS = 3600;
90
+ export const isLimitCategory = (category) => category === 'rate_limited' || category === 'quota';
91
+ /**
92
+ * Whether a `rate_limited` or `quota` error still counts. With a reset time it counts until
93
+ * then; without one it counts for a short while after it was recorded.
94
+ */
95
+ export function limitErrorActive(issue) {
96
+ if (issue.resetsAt)
97
+ return inFuture(issue.resetsAt);
98
+ const at = Date.parse(issue.at);
99
+ return !Number.isNaN(at) && Math.trunc((Date.now() - at) / 1000) < UNTIMED_LIMIT_ERROR_SECS;
100
+ }
101
+ export function deriveHealth(state) {
102
+ const limitedByWindow = state.limits.some((limit) => (limit.status === 'rejected' || (limit.usedPercent ?? 0) >= 100) && (!limit.resetsAt || inFuture(limit.resetsAt)));
103
+ const issue = state.lastError;
104
+ if (issue?.category === 'auth_expired')
105
+ return 'auth_expired';
106
+ if (issue && isLimitCategory(issue.category) && limitErrorActive(issue))
107
+ return 'limited';
108
+ if (state.signedIn === false)
109
+ return 'signed_out';
110
+ if (limitedByWindow)
111
+ return 'limited';
112
+ if (issue && !isLimitCategory(issue.category))
113
+ return 'error';
114
+ return state.signedIn === true ? 'ok' : 'unknown';
115
+ }
116
+ /** Read-modify-write on one account's state. Returns the previous health and the new state. */
117
+ export function updateState(dir, accountId, change) {
118
+ const state = loadState(dir, accountId);
119
+ const previous = state.health;
120
+ change(state);
121
+ state.health = deriveHealth(state);
122
+ saveState(dir, accountId, state);
123
+ return { previous, state };
124
+ }
125
+ // ---- Lookup and pinning -----------------------------------------------------------------
126
+ export function find(dir, accountId) {
127
+ const account = loadRegistry(dir).accounts.find((entry) => entry.id === accountId);
128
+ if (!account)
129
+ throw new HarnessError('account_required', "This session's account was removed.", 'Choose another account for it.');
130
+ return account;
131
+ }
132
+ const usable = (state) => state.health === 'ok' || state.health === 'unknown';
133
+ /**
134
+ * Chooses the account for a new session: the explicit account, else the pool's first usable
135
+ * account, else the default, else the first account. It never skips to another one silently.
136
+ */
137
+ export function resolve(dir, accountId, poolId) {
138
+ const registry = loadRegistry(dir);
139
+ if (accountId) {
140
+ const account = find(dir, accountId);
141
+ if (account.provider !== PROVIDER)
142
+ throw invalid('That account belongs to another provider.');
143
+ return account;
144
+ }
145
+ if (poolId) {
146
+ const pool = registry.pools.find((entry) => entry.id === poolId);
147
+ if (!pool)
148
+ throw notFound('Pool');
149
+ const members = pool.accountIds.flatMap((id) => registry.accounts.find((account) => account.id === id) ?? []);
150
+ const ready = members.find((account) => usable(loadState(dir, account.id)));
151
+ if (ready)
152
+ return ready;
153
+ const resets = members.flatMap((account) => {
154
+ const state = loadState(dir, account.id);
155
+ return [...state.limits.map((limit) => limit.resetsAt), state.lastError?.resetsAt].filter((reset) => Boolean(reset));
156
+ });
157
+ const earliest = resets.sort(compareText)[0];
158
+ throw new HarnessError('account_unavailable', `Every account in ${pool.label} is unavailable.`, earliest ? `The earliest reset is ${earliest}.` : 'Reauthenticate an account in Accounts.');
159
+ }
160
+ const account = registry.accounts.find((entry) => entry.id === registry.defaults[PROVIDER]) ?? registry.accounts.find((entry) => entry.provider === PROVIDER);
161
+ if (!account)
162
+ throw new HarnessError('account_required', 'Add a Pi account first.', 'Open Accounts (⌘4) to sign in.');
163
+ return account;
164
+ }
165
+ /** The default account, if any exists. */
166
+ export function defaultAccount(dir) {
167
+ try {
168
+ return resolve(dir);
169
+ }
170
+ catch {
171
+ return null;
172
+ }
173
+ }
174
+ export function summaryAuthentication(dir) {
175
+ const states = loadRegistry(dir).accounts.filter((account) => account.provider === PROVIDER).map((account) => loadState(dir, account.id));
176
+ if (states.some((state) => state.signedIn === true))
177
+ return 'authenticated';
178
+ return states.some((state) => state.signedIn === false) ? 'unauthenticated' : 'unknown';
179
+ }
180
+ export function overview(dir) {
181
+ const registry = loadRegistry(dir);
182
+ return {
183
+ accounts: registry.accounts.filter((account) => account.provider === PROVIDER).map((account) => ({ ...account, isDefault: registry.defaults[account.provider] === account.id, state: loadState(dir, account.id) })),
184
+ pools: registry.pools.filter((pool) => pool.provider === PROVIDER),
185
+ defaults: registry.defaults
186
+ };
187
+ }
188
+ // ---- Changes ----------------------------------------------------------------------------
189
+ export function cleanLabel(label) {
190
+ const cleaned = label.trim();
191
+ if (!cleaned || charCount(cleaned) > 60)
192
+ throw invalid('Give the account a name of 1–60 characters.');
193
+ return cleaned;
194
+ }
195
+ export function addAccount(dir, label, authKind) {
196
+ if (authKind !== 'subscription' && authKind !== 'apiKey')
197
+ throw invalid('Unknown sign-in type.');
198
+ const account = { id: newId(), provider: PROVIDER, label: cleanLabel(label), authKind, credentialStore: 'keyring', createdAt: now() };
199
+ const registry = loadRegistry(dir);
200
+ registry.defaults[PROVIDER] ??= account.id;
201
+ registry.accounts.push(account);
202
+ saveRegistry(dir, registry);
203
+ return account;
204
+ }
205
+ export function renameAccount(dir, accountId, label) {
206
+ const cleaned = cleanLabel(label);
207
+ const registry = loadRegistry(dir);
208
+ const account = registry.accounts.find((entry) => entry.id === accountId);
209
+ if (!account)
210
+ throw notFound('Account');
211
+ account.label = cleaned;
212
+ saveRegistry(dir, registry);
213
+ }
214
+ export function setDefault(dir, accountId) {
215
+ const account = find(dir, accountId);
216
+ const registry = loadRegistry(dir);
217
+ registry.defaults[account.provider] = account.id;
218
+ saveRegistry(dir, registry);
219
+ return account;
220
+ }
221
+ /** Drops the account from the registry, its pools, and the default. Its folder and secrets are the caller's to remove. */
222
+ export function forgetAccount(dir, account) {
223
+ const registry = loadRegistry(dir);
224
+ registry.accounts = registry.accounts.filter((entry) => entry.id !== account.id);
225
+ if (registry.defaults[account.provider] === account.id) {
226
+ const next = registry.accounts.find((entry) => entry.provider === account.provider);
227
+ if (next)
228
+ registry.defaults[account.provider] = next.id;
229
+ else
230
+ delete registry.defaults[account.provider];
231
+ }
232
+ for (const pool of registry.pools)
233
+ pool.accountIds = pool.accountIds.filter((id) => id !== account.id);
234
+ saveRegistry(dir, registry);
235
+ }
236
+ export function savePool(dir, pool) {
237
+ const label = cleanLabel(pool.label);
238
+ const registry = loadRegistry(dir);
239
+ for (const id of pool.accountIds) {
240
+ const account = registry.accounts.find((entry) => entry.id === id);
241
+ if (!account)
242
+ throw notFound('Account');
243
+ if (account.provider !== PROVIDER)
244
+ throw invalid('A pool holds accounts of one provider.');
245
+ }
246
+ const next = { id: pool.id ? safeId(pool.id) : newId(), provider: PROVIDER, label, accountIds: [...pool.accountIds] };
247
+ registry.pools = [...registry.pools.filter((existing) => existing.id !== next.id), next];
248
+ saveRegistry(dir, registry);
249
+ return next;
250
+ }
251
+ export function removePool(dir, poolId) {
252
+ const registry = loadRegistry(dir);
253
+ registry.pools = registry.pools.filter((pool) => pool.id !== poolId);
254
+ saveRegistry(dir, registry);
255
+ }
@@ -0,0 +1,16 @@
1
+ export interface BrowserConfig {
2
+ /** Show the browser window instead of running it headless. */
3
+ headed: boolean;
4
+ /** Attach to a browser a person already runs (its DevTools address) instead of launching one. */
5
+ cdpUrl: string | null;
6
+ /** A browser program to launch; otherwise Chrome, then Edge, then Playwright's Chromium. */
7
+ executablePath: string | null;
8
+ /** Let pages reach this machine and private networks (local development servers). */
9
+ allowPrivate: boolean;
10
+ /** When set, pages may only reach these sites (and their subdomains). */
11
+ allowedDomains: string[];
12
+ }
13
+ export declare const DEFAULT_BROWSER_CONFIG: BrowserConfig;
14
+ export declare const configPath: (stateDir: string) => string;
15
+ export declare function readBrowserConfig(stateDir: string): BrowserConfig;
16
+ export declare function writeBrowserConfig(stateDir: string, change: Partial<BrowserConfig>): BrowserConfig;
@@ -0,0 +1,22 @@
1
+ // How the harness's browser runs, kept on this device: `<state dir>/browser.json`. Only a person
2
+ // (through a command or the application) writes it; no tool argument can point the browser at
3
+ // another endpoint or profile.
4
+ import { join } from 'node:path';
5
+ import { readJsonOr, writeJson } from "../core/fs.js";
6
+ export const DEFAULT_BROWSER_CONFIG = { headed: false, cdpUrl: null, executablePath: null, allowPrivate: false, allowedDomains: [] };
7
+ export const configPath = (stateDir) => join(stateDir, 'browser.json');
8
+ export function readBrowserConfig(stateDir) {
9
+ const saved = readJsonOr(configPath(stateDir), {});
10
+ return {
11
+ headed: saved.headed === true,
12
+ cdpUrl: typeof saved.cdpUrl === 'string' && /^(?:https?|wss?):\/\/(?:127\.0\.0\.1|localhost|\[::1\])(?::\d+)?(?:\/|$)/.test(saved.cdpUrl) ? saved.cdpUrl : null,
13
+ executablePath: typeof saved.executablePath === 'string' && saved.executablePath.trim() ? saved.executablePath : null,
14
+ allowPrivate: saved.allowPrivate === true,
15
+ allowedDomains: Array.isArray(saved.allowedDomains) ? saved.allowedDomains.filter((domain) => typeof domain === 'string' && /^[a-z0-9.-]+$/i.test(domain)).map((domain) => domain.toLowerCase()) : []
16
+ };
17
+ }
18
+ export function writeBrowserConfig(stateDir, change) {
19
+ const next = { ...readBrowserConfig(stateDir), ...change };
20
+ writeJson(configPath(stateDir), next);
21
+ return readBrowserConfig(stateDir);
22
+ }
@@ -0,0 +1,4 @@
1
+ import type { BrowserConfig } from "./config.js";
2
+ import type { DoctorCheck } from "../doctor/types.js";
3
+ /** Exercises the production tool path against a synthetic page in a throwaway profile. */
4
+ export declare function browserDiagnostic(configure: () => BrowserConfig): DoctorCheck;
@@ -0,0 +1,38 @@
1
+ import { accessSync, constants } from 'node:fs';
2
+ const outputText = (result) => typeof result === 'string' ? result : result.text;
3
+ /** Exercises the production tool path against a synthetic page in a throwaway profile. */
4
+ export function browserDiagnostic(configure) {
5
+ return {
6
+ id: 'browser', category: 'browser', title: 'Isolated browser',
7
+ tools: ['browser_navigate', 'browser_read', 'browser_snapshot', 'browser_click'],
8
+ local: async () => {
9
+ const config = configure();
10
+ if (config.executablePath)
11
+ accessSync(config.executablePath, constants.X_OK);
12
+ return { status: 'pass', evidence: `Browser tools are installed. ${config.cdpUrl ? 'A CDP endpoint is configured; diagnostics will not attach to it.' : 'A dedicated browser will be launched only after live-check confirmation.'} Browser launch is unverified.` };
13
+ },
14
+ live: {
15
+ notice: 'Launch a dedicated headless browser with a disposable profile, open an offline synthetic page, read its marker, and click its test button. No existing browser or profile is used.',
16
+ run: async (probe) => {
17
+ if (configure().cdpUrl)
18
+ return { status: 'blocked', evidence: 'This backend is configured to attach to a browser. Isolated diagnostics will not attach to it.', remedy: 'Use a dedicated launch configuration to test browser interaction.' };
19
+ const needed = ['browser_navigate', 'browser_read', 'browser_snapshot', 'browser_click'];
20
+ if (needed.some(name => !probe.context.tools.includes(name)))
21
+ return { status: 'blocked', evidence: 'The browser interaction test requires navigate, read, snapshot, and click capabilities.' };
22
+ const html = '<!doctype html><title>Harness Doctor</title><p>doctor-ready</p><button onclick="document.querySelector(\'p\').textContent=\'doctor-clicked\'">Diagnostic test</button>';
23
+ await probe.call('browser_navigate', { url: `data:text/html,${encodeURIComponent(html)}` });
24
+ const before = outputText(await probe.call('browser_read', {}));
25
+ if (!before.includes('doctor-ready'))
26
+ return { status: 'fail', evidence: 'The diagnostic page marker could not be read.' };
27
+ const snapshot = outputText(await probe.call('browser_snapshot', {}));
28
+ const line = snapshot.split('\n').find(line => line.includes('button') && line.includes('Diagnostic test'));
29
+ const ref = line && /\b(e\d+)\b/.exec(line)?.[1];
30
+ if (!ref)
31
+ return { status: 'fail', evidence: 'The test button was absent from the browser snapshot.' };
32
+ await probe.call('browser_click', { ref });
33
+ const after = outputText(await probe.call('browser_read', {}));
34
+ return after.includes('doctor-clicked') ? { status: 'pass', evidence: 'Navigation, reading, element discovery, and clicking succeeded in the disposable diagnostic browser.' } : { status: 'fail', evidence: 'Clicking did not change the expected page marker.' };
35
+ }
36
+ }
37
+ };
38
+ }
@@ -0,0 +1,17 @@
1
+ import type { PluginDescriptor } from "../plugins/types.js";
2
+ import type { WorldPart } from "../world/world.js";
3
+ import { NetworkPolicy } from "./network.js";
4
+ import { BrowserSession, type Launcher } from "./session.js";
5
+ export declare const BROWSER_PLUGIN: PluginDescriptor;
6
+ /** A browser closes after this long without a call. */
7
+ export declare const IDLE_MS: number;
8
+ export interface BrowserPartOptions {
9
+ stateDir: string;
10
+ launch?: Launcher;
11
+ /** Replaces the address check in tests. */
12
+ network?: NetworkPolicy;
13
+ idleMs?: number;
14
+ }
15
+ export declare function browserPart(options: BrowserPartOptions): WorldPart & {
16
+ sessions: Map<string, BrowserSession>;
17
+ };
@@ -0,0 +1,65 @@
1
+ // The browser, as one part of the harness's world tools: a plugin a person can switch off, and one
2
+ // live browser per session.
3
+ import { rmSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { readBrowserConfig } from "./config.js";
6
+ import { browserDiagnostic } from "./diagnostics.js";
7
+ import { NetworkPolicy } from "./network.js";
8
+ import { BrowserSession, fileName, launchBrowser } from "./session.js";
9
+ import { BROWSER_TOOL_NAMES, browserTools } from "./tools.js";
10
+ export const BROWSER_PLUGIN = {
11
+ id: 'browser',
12
+ title: 'Browser',
13
+ description: 'A browser the agent drives: open pages that need scripts, read them, click, type and choose. Each session has its own; sign-ins are kept per agent on this device. Sending, buying, deleting, account changes and granting access always ask you.',
14
+ manage: 'tools',
15
+ switchable: { on: true },
16
+ // Its tools are listed in the World group, which the Web plugin owns.
17
+ tools: BROWSER_TOOL_NAMES.map((name) => ({ name }))
18
+ };
19
+ /** A browser closes after this long without a call. */
20
+ export const IDLE_MS = 15 * 60_000;
21
+ export function browserPart(options) {
22
+ const sessions = new Map();
23
+ const diagnosticKeys = new Set();
24
+ const config = () => readBrowserConfig(options.stateDir);
25
+ const network = options.network ?? new NetworkPolicy(config);
26
+ const sessionFor = (context) => {
27
+ let session = sessions.get(context.sessionKey);
28
+ if (!session) {
29
+ const owner = context.caller.agentId ?? context.caller.projectId ?? 'default';
30
+ const key = context.sessionKey;
31
+ const diagnostic = context.caller.surface === 'doctor';
32
+ if (diagnostic)
33
+ diagnosticKeys.add(key);
34
+ session = new BrowserSession({
35
+ key,
36
+ profileDir: diagnostic ? null : join(options.stateDir, 'browser', 'profiles', fileName(owner)),
37
+ downloadsDir: join(options.stateDir, 'browser', 'downloads', fileName(key)),
38
+ config: diagnostic ? () => ({ ...config(), cdpUrl: null, headed: false }) : config,
39
+ network,
40
+ launch: options.launch ?? launchBrowser,
41
+ idleMs: options.idleMs ?? IDLE_MS,
42
+ onIdle: () => void release(key)
43
+ });
44
+ sessions.set(key, session);
45
+ }
46
+ return session;
47
+ };
48
+ const release = async (key) => {
49
+ const session = sessions.get(key);
50
+ sessions.delete(key);
51
+ await session?.close();
52
+ if (diagnosticKeys.delete(key))
53
+ rmSync(join(options.stateDir, 'browser', 'downloads', fileName(key)), { recursive: true, force: true });
54
+ };
55
+ return {
56
+ plugin: BROWSER_PLUGIN,
57
+ diagnostics: () => [browserDiagnostic(config)],
58
+ sessions,
59
+ tools: (context) => browserTools(context, () => sessionFor(context)),
60
+ release,
61
+ close: async () => {
62
+ await Promise.all([...sessions.keys()].map(release));
63
+ }
64
+ };
65
+ }
@@ -0,0 +1,10 @@
1
+ import type { BrowserConfig } from "./config.js";
2
+ export declare class NetworkPolicy {
3
+ private readonly config;
4
+ private readonly resolve;
5
+ private readonly hosts;
6
+ constructor(config: () => BrowserConfig, resolve?: (host: string) => Promise<string[]>);
7
+ /** Why an address may not be loaded, or null when it may. */
8
+ refusal(address: string): Promise<string | null>;
9
+ private isPublic;
10
+ }
@@ -0,0 +1,59 @@
1
+ // What a page in the harness's browser may reach. The same rule as `web_fetch`: public addresses
2
+ // only, unless a person allowed private ones for local development. This filters the browser's
3
+ // requests; it is a guard, not a sandbox (a page's own DNS can still differ from ours).
4
+ import { lookup } from 'node:dns/promises';
5
+ import { isIP } from 'node:net';
6
+ import { isPublicAddress } from "../web/safeRequest.js";
7
+ const OPEN_SCHEMES = new Set(['data:', 'blob:', 'about:']);
8
+ const CACHE_MS = 60_000;
9
+ export class NetworkPolicy {
10
+ config;
11
+ resolve;
12
+ hosts = new Map();
13
+ constructor(config, resolve = async (host) => (await lookup(host, { all: true, verbatim: true })).map((entry) => entry.address)) {
14
+ this.config = config;
15
+ this.resolve = resolve;
16
+ }
17
+ /** Why an address may not be loaded, or null when it may. */
18
+ async refusal(address) {
19
+ let url;
20
+ try {
21
+ url = new URL(address);
22
+ }
23
+ catch {
24
+ return 'That is not a web address.';
25
+ }
26
+ if (OPEN_SCHEMES.has(url.protocol))
27
+ return null;
28
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
29
+ return `${url.protocol} addresses cannot be opened.`;
30
+ if (url.username || url.password)
31
+ return 'Addresses with a username or password cannot be opened.';
32
+ const host = url.hostname.replace(/^\[|\]$/g, '').toLowerCase();
33
+ const { allowedDomains, allowPrivate } = this.config();
34
+ if (allowedDomains.length && !allowedDomains.some((domain) => host === domain || host.endsWith(`.${domain}`)))
35
+ return `${host} is not among the sites this browser may reach.`;
36
+ if (allowPrivate)
37
+ return null;
38
+ return (await this.isPublic(host)) ? null : `${host} is not a public address. A person can allow private addresses in the browser settings.`;
39
+ }
40
+ async isPublic(host) {
41
+ if (isIP(host))
42
+ return isPublicAddress(host);
43
+ if (host === 'localhost' || host.endsWith('.localhost'))
44
+ return false;
45
+ const cached = this.hosts.get(host);
46
+ if (cached && Date.now() - cached.at < CACHE_MS)
47
+ return cached.ok;
48
+ let ok = false;
49
+ try {
50
+ const addresses = await this.resolve(host);
51
+ ok = addresses.length > 0 && addresses.every(isPublicAddress);
52
+ }
53
+ catch {
54
+ ok = false;
55
+ }
56
+ this.hosts.set(host, { at: Date.now(), ok });
57
+ return ok;
58
+ }
59
+ }
@@ -0,0 +1,84 @@
1
+ import type { Browser, BrowserContext, Page } from 'playwright-core';
2
+ import type { BrowserConfig } from "./config.js";
3
+ import type { NetworkPolicy } from "./network.js";
4
+ /** Any name as a file or folder name: other characters become `_`. */
5
+ export declare const fileName: (name: string) => string;
6
+ export declare const VIEWPORT: {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ export declare const ACTION_TIMEOUT_MS = 15000;
11
+ export declare const NAVIGATION_TIMEOUT_MS = 30000;
12
+ export interface Tab {
13
+ id: string;
14
+ page: Page;
15
+ /** Bumped on every navigation of the tab's main frame: refs of an earlier generation are stale. */
16
+ generation: number;
17
+ /** Refs of the latest snapshot, with the snapshot line that names each. */
18
+ refs: Map<string, string>;
19
+ refsGeneration: number;
20
+ }
21
+ export interface Download {
22
+ tab: string;
23
+ path: string;
24
+ name: string;
25
+ }
26
+ /** Opens a browser context; tests replace it. */
27
+ export type Launcher = (input: {
28
+ profileDir: string | null;
29
+ downloads: string;
30
+ config: BrowserConfig;
31
+ }) => Promise<{
32
+ context: BrowserContext;
33
+ browser: Browser | null;
34
+ attached: boolean;
35
+ }>;
36
+ export declare const launchBrowser: Launcher;
37
+ export interface BrowserSessionOptions {
38
+ key: string;
39
+ /** The profile kept for this caller, or null for a throwaway one. */
40
+ profileDir: string | null;
41
+ downloadsDir: string;
42
+ config: () => BrowserConfig;
43
+ network: NetworkPolicy;
44
+ launch: Launcher;
45
+ idleMs: number;
46
+ onIdle: () => void;
47
+ }
48
+ export declare class BrowserSession {
49
+ private readonly options;
50
+ private closed;
51
+ private context;
52
+ private browser;
53
+ private attached;
54
+ private starting;
55
+ private readonly tabs;
56
+ private current;
57
+ private nextTab;
58
+ private queue;
59
+ private idle;
60
+ private temporaryProfile;
61
+ readonly downloads: Download[];
62
+ /** Set when the kept profile was in use and a throwaway one was opened instead. */
63
+ profileNote: string | null;
64
+ constructor(options: BrowserSessionOptions);
65
+ /** Runs `work` after every earlier call of this session has finished. */
66
+ run<T>(work: () => Promise<T>): Promise<T>;
67
+ private touch;
68
+ private start;
69
+ private adopt;
70
+ /** A tab by id, or the current one, starting the browser and opening a first tab when needed. */
71
+ tab(id?: string | null): Promise<Tab>;
72
+ open(): Promise<Tab>;
73
+ select(id: string): Tab;
74
+ list(): {
75
+ id: string;
76
+ url: string;
77
+ current: boolean;
78
+ }[];
79
+ /** What pages in this browser may reach. */
80
+ get network(): NetworkPolicy;
81
+ get currentId(): string | null;
82
+ get started(): boolean;
83
+ close(): Promise<void>;
84
+ }