@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,370 @@
1
+ // Everything a host process can ask of the harness, by name. Each method takes one JSON object
2
+ // and returns JSON; the in-process API these call is the same one a Node application uses
3
+ // directly. Methods are grouped by the part of the harness they belong to.
4
+ import { ensureSharedDir, nativeConfig } from "../accounts/env.js";
5
+ import { audit, readAudit, summaryAuthentication } from "../accounts/store.js";
6
+ import { HarnessError, invalid } from "../core/errors.js";
7
+ import * as capabilities from "../capabilities/api.js";
8
+ import { loadRun as loadCapabilitySnapshot } from "../capabilities/runSnapshot.js";
9
+ import { capabilitySet } from "../capabilities/runSnapshot.js";
10
+ import { validateScopeIds } from "../mcp/connections.js";
11
+ import * as recall from "../history/recall.js";
12
+ import * as plugins from "../plugins/api.js";
13
+ import * as install from "../plugins/install.js";
14
+ import { compile, load, render } from "../prompt/compile.js";
15
+ import { readSummary } from "../refine/runner.js";
16
+ import { continuationOf } from "../sessions/continuation.js";
17
+ import { selectHistory } from "../sessions/history.js";
18
+ import { runsSince } from "../sessions/runIndex.js";
19
+ import { findRun, listRuns, loadRun, pendingDecisions, readEvents, runFamily, snapshot } from "../sessions/runStore.js";
20
+ import { checklistOf } from "../tools/checklist.js";
21
+ import { dispatch } from "../tools/dispatch.js";
22
+ import * as components from "../variant/components.js";
23
+ import { materialise } from "../variant/materialise.js";
24
+ import { seedVariant } from "../variant/seed.js";
25
+ import * as variants from "../variant/store.js";
26
+ import { PI_SURFACE } from "../variant/surface.js";
27
+ import { applyEdit, autotrigger, VariantError, validate } from "../variant/variant.js";
28
+ import * as notes from "../wiki/notes.js";
29
+ const text = (params, name) => {
30
+ const value = params[name];
31
+ if (typeof value !== 'string' || !value)
32
+ throw invalid(`${name} is required.`);
33
+ return value;
34
+ };
35
+ const optional = (params, name) => (typeof params[name] === 'string' && params[name] ? params[name] : null);
36
+ const questionAnswer = (value) => {
37
+ const answer = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
38
+ return {
39
+ selected: Array.isArray(answer.selected) ? answer.selected.filter((label) => typeof label === 'string') : [],
40
+ ...(typeof answer.text === 'string' && answer.text ? { text: answer.text } : {}),
41
+ ...(answer.notes && typeof answer.notes === 'object' && !Array.isArray(answer.notes)
42
+ ? { notes: Object.fromEntries(Object.entries(answer.notes).filter((entry) => typeof entry[1] === 'string')) }
43
+ : {})
44
+ };
45
+ };
46
+ const pluginScope = (params) => ({ cwd: optional(params, 'cwd'), accountId: optional(params, 'accountId'), agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId') });
47
+ const variantOf = (value) => {
48
+ if (!value || typeof value !== 'object' || Array.isArray(value))
49
+ throw invalid('variant must be an object of path → text.');
50
+ const out = {};
51
+ for (const [path, body] of Object.entries(value)) {
52
+ if (typeof body !== 'string')
53
+ throw invalid(`${path} must be text.`);
54
+ out[path] = body;
55
+ }
56
+ return out;
57
+ };
58
+ /** Validates a variant without throwing: its census, or every problem. */
59
+ function check(variant) {
60
+ try {
61
+ return { ok: true, census: validate(PI_SURFACE, variant) };
62
+ }
63
+ catch (error) {
64
+ return { ok: false, problems: error instanceof VariantError ? error.problems : [error instanceof Error ? error.message : String(error)] };
65
+ }
66
+ }
67
+ /** Only the named fields of a parameter object. */
68
+ function pick(params, keys) {
69
+ return Object.fromEntries(keys.filter((key) => key in params).map((key) => [key, params[key]]));
70
+ }
71
+ export function methods(harness) {
72
+ const { accounts, approvals, apps, runs, sessions, terminals, env } = harness;
73
+ const root = () => env.root;
74
+ const variantsChanged = (scope) => harness.bus.emit({ type: 'variants.changed', scope });
75
+ return {
76
+ // ---- The harness itself --------------------------------------------------------------------
77
+ 'web.status': () => harness.world.searchStatus(),
78
+ 'web.setKey': (params) => harness.world.setSearchKey(text(params, 'provider'), typeof params.key === 'string' ? params.key : null),
79
+ 'browser.config': () => harness.world.browserConfig(),
80
+ 'browser.configure': (params) => harness.world.configureBrowser(pick(params, ['headed', 'cdpUrl', 'executablePath', 'allowPrivate', 'allowedDomains'])),
81
+ 'harness.status': () => ({ dataRoot: harness.dataRoot, productName: env.productName, recovery: harness.recovery, activeRuns: runs.activeRunIds() }),
82
+ 'doctor.start': (params) => harness.doctor.start(params),
83
+ 'doctor.read': (params) => harness.doctor.read(text(params, 'id')),
84
+ 'doctor.cancel': (params) => harness.doctor.cancel(text(params, 'id')),
85
+ 'harness.open': (params) => harness.open(text(params, 'dataRoot'), Array.isArray(params.agentIds) ? params.agentIds : []),
86
+ 'harness.rebuildIndex': () => harness.rebuildIndex(),
87
+ 'hub.list': (params) => harness.hub.list(params.refresh === true),
88
+ 'hub.get': (params) => harness.hub.get(text(params, 'id'), text(params, 'version'), params.preview === true),
89
+ 'hub.install': (params) => harness.hub.install(text(params, 'id'), text(params, 'version')),
90
+ 'hub.preview': (params) => harness.hub.preview(text(params, 'id'), text(params, 'version'), typeof params.offset === 'number' ? params.offset : 0),
91
+ 'hub.uninstall': (params) => harness.hub.uninstall(text(params, 'id'), text(params, 'version')),
92
+ 'hub.readDocument': (params) => harness.hub.readDocument(text(params, 'id'), text(params, 'version')),
93
+ // ---- Accounts --------------------------------------------------------------------------------
94
+ 'accounts.list': () => accounts.overview(),
95
+ 'accounts.find': (params) => accounts.find(text(params, 'accountId')),
96
+ 'accounts.resolve': (params) => accounts.resolve(optional(params, 'accountId'), optional(params, 'poolId')),
97
+ 'accounts.create': (params) => accounts.create(text(params, 'label'), optional(params, 'authKind') ?? 'subscription'),
98
+ 'accounts.rename': (params) => accounts.rename(text(params, 'accountId'), text(params, 'label')),
99
+ 'accounts.setDefault': (params) => accounts.setDefault(text(params, 'accountId')),
100
+ 'accounts.remove': (params) => accounts.remove(text(params, 'accountId')),
101
+ 'accounts.savePool': (params) => accounts.savePool(params.pool),
102
+ 'accounts.removePool': (params) => accounts.removePool(text(params, 'poolId')),
103
+ 'accounts.audit': (params) => readAudit(accounts.dir, optional(params, 'accountId'), typeof params.limit === 'number' ? params.limit : 100),
104
+ // A line in the account audit log for something the application did with the account (pinning a session to it).
105
+ 'accounts.record': (params) => audit(accounts.dir, optional(params, 'accountId'), text(params, 'action'), typeof params.detail === 'string' ? params.detail : ''),
106
+ 'accounts.nativeConfig': () => nativeConfig(accounts.dir),
107
+ // The folder every account shares, created if no account has linked it yet.
108
+ 'accounts.sharedDir': () => ensureSharedDir(accounts.dir),
109
+ 'accounts.refresh': (params) => accounts.refresh(optional(params, 'accountId')),
110
+ 'accounts.loginStart': (params) => accounts.loginStart(text(params, 'accountId'), text(params, 'provider'), optional(params, 'method')),
111
+ 'accounts.loginStatus': (params) => accounts.loginStatus(text(params, 'accountId')),
112
+ 'accounts.loginRespond': (params) => accounts.loginRespond(text(params, 'loginId'), text(params, 'promptId'), typeof params.value === 'string' ? params.value : null),
113
+ 'accounts.loginCancel': (params) => accounts.loginCancel(text(params, 'accountId'), optional(params, 'loginId')),
114
+ 'accounts.setApiKey': (params) => accounts.setApiKey(text(params, 'accountId'), text(params, 'key'), text(params, 'provider')),
115
+ 'accounts.removeProvider': (params) => accounts.removeProvider(text(params, 'accountId'), text(params, 'provider')),
116
+ 'accounts.signOut': (params) => accounts.signOut(text(params, 'accountId')),
117
+ 'accounts.providers': () => accounts.providers(),
118
+ 'accounts.models': (params) => accounts.models(optional(params, 'accountId')),
119
+ 'accounts.choices': (params) => accounts.choices(text(params, 'accountId')),
120
+ 'accounts.choose': (params) => accounts.choose(text(params, 'accountId'), text(params, 'mode'), {
121
+ ...(typeof params.model === 'string' ? { model: params.model } : {}),
122
+ ...(typeof params.effort === 'string' ? { effort: params.effort } : {})
123
+ }),
124
+ 'accounts.authentication': () => summaryAuthentication(accounts.dir),
125
+ 'accounts.status': (params) => accounts.status(optional(params, 'accountId')),
126
+ // ---- Standing approvals ----------------------------------------------------------------------
127
+ 'approvals.get': () => approvals.read(),
128
+ 'approvals.setAuto': (params) => approvals.setAuto(text(params, 'key'), params.on === true),
129
+ 'approvals.remember': (params) => approvals.remember(text(params, 'sessionId'), text(params, 'target')),
130
+ 'approvals.forget': (params) => approvals.forget(text(params, 'sessionId'), text(params, 'target')),
131
+ 'approvals.forgetSession': (params) => approvals.forgetSession(text(params, 'sessionId')),
132
+ // ---- Connected apps --------------------------------------------------------------------------
133
+ 'connections.list': () => apps.connections.list(),
134
+ 'connections.forScope': (params) => apps.connections.forScope({ agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId') }),
135
+ 'connections.save': (params) => apps.save(params.input),
136
+ 'connections.allowTool': (params) => apps.connections.allowTool(text(params, 'connectionId'), text(params, 'tool')),
137
+ 'connections.remove': (params) => apps.remove(text(params, 'connectionId')),
138
+ 'connections.test': (params) => apps.test(text(params, 'connectionId')),
139
+ 'connections.signIn': (params) => apps.signIn(text(params, 'connectionId')),
140
+ 'connections.signOut': (params) => apps.signOut(text(params, 'connectionId')),
141
+ 'connections.runContext': (params) => apps.runContext(text(params, 'runId')),
142
+ 'connections.refreshSource': (params) => apps.refreshSource(text(params, 'runId'), text(params, 'traceId'), text(params, 'sourceUri')),
143
+ 'connections.setAgentScope': (params) => apps.setAgentScope(params.creator ?? {}, text(params, 'agentId'), Array.isArray(params.ids) ? params.ids : []),
144
+ 'connections.removeAgentScope': (params) => apps.removeAgentScope(text(params, 'agentId')),
145
+ 'connections.revision': () => apps.connections.revision(),
146
+ 'connections.appClients': () => apps.appClients(),
147
+ 'connections.validateScope': (params) => validateScopeIds(apps.connections.list(), { agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId') }, Array.isArray(params.ids) ? params.ids : []),
148
+ // ---- Variants: the eight components that shape an agent ---------------------------------
149
+ 'variants.surface': () => PI_SURFACE,
150
+ 'variants.list': () => variants.scopes(root()).map((scope) => {
151
+ const head = variants.head(root(), scope);
152
+ return { scope, head, version: head ? variants.versionRecord(root(), scope, head.fingerprint) : null };
153
+ }),
154
+ 'variants.get': (params) => {
155
+ const scope = text(params, 'scope');
156
+ const head = variants.head(root(), scope);
157
+ const fp = optional(params, 'version') ?? head?.fingerprint ?? null;
158
+ if (!fp)
159
+ return { scope, head: null, version: null, variant: null, plugins: [] };
160
+ const variant = variants.readVersion(root(), scope, fp);
161
+ return { scope, head, version: variants.versionRecord(root(), scope, fp), variant, plugins: harness.trust.review(variant), probeCode: harness.trust.probeCode(scope) };
162
+ },
163
+ 'variants.lineage': (params) => variants.lineage(root(), text(params, 'scope')),
164
+ 'variants.compare': (params) => variants.compare(root(), text(params, 'scope'), text(params, 'from'), text(params, 'to')),
165
+ 'variants.validate': (params) => {
166
+ const variant = variantOf(params.variant);
167
+ const repaired = params.repair === true ? autotrigger(PI_SURFACE, variant) : [];
168
+ return { ...check(variant), repaired, variant };
169
+ },
170
+ // A whole variant, or an edit of the head that names only the files it changes (null removes one).
171
+ 'variants.save': (params) => {
172
+ const scope = text(params, 'scope');
173
+ const base = variants.headVariant(root(), scope)?.variant ?? {};
174
+ const variant = params.variant !== undefined ? variantOf(params.variant) : applyEdit(base, (params.edit ?? {}));
175
+ if (params.repair === true)
176
+ autotrigger(PI_SURFACE, variant);
177
+ const record = variants.commit(root(), scope, variant, { kind: params.source === 'import' ? 'import' : 'edit', note: optional(params, 'note') ?? undefined, components: Array.isArray(params.components) ? params.components : undefined });
178
+ variantsChanged(scope);
179
+ return record;
180
+ },
181
+ 'variants.restore': (params) => {
182
+ const scope = text(params, 'scope');
183
+ const head = variants.restore(root(), scope, text(params, 'version'), optional(params, 'note') ?? undefined);
184
+ variantsChanged(scope);
185
+ return head;
186
+ },
187
+ // A first version: the variant given, or one built from what shaped the caller before variants.
188
+ 'variants.seed': (params) => {
189
+ const scope = text(params, 'scope');
190
+ const variant = params.variant !== undefined ? variantOf(params.variant) : seedVariant(root(), { agentId: optional(params, 'agentId') ?? scope, projectId: optional(params, 'projectId'), instructions: typeof params.instructions === 'string' ? params.instructions : '' });
191
+ const head = variants.seed(root(), scope, variant, optional(params, 'note') ?? undefined);
192
+ variantsChanged(scope);
193
+ return head;
194
+ },
195
+ 'variants.legacy': (params) => seedVariant(root(), { agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId'), instructions: typeof params.instructions === 'string' ? params.instructions : '' }),
196
+ 'variants.trusted': () => harness.trust.list(),
197
+ 'variants.trust': (params) => {
198
+ const scope = text(params, 'scope');
199
+ const variant = variants.headVariant(root(), scope)?.variant ?? {};
200
+ const path = text(params, 'path');
201
+ const body = typeof params.text === 'string' ? params.text : variant[path];
202
+ if (typeof body !== 'string')
203
+ throw invalid('That plugin file is not in the harness.');
204
+ const entry = harness.trust.grant(body, path, scope);
205
+ variantsChanged(scope);
206
+ return entry;
207
+ },
208
+ 'variants.untrust': (params) => {
209
+ harness.trust.revoke(text(params, 'hash'));
210
+ harness.bus.emit({ type: 'variants.changed' });
211
+ },
212
+ 'variants.setProbeCode': (params) => {
213
+ const scope = text(params, 'scope');
214
+ harness.trust.setProbeCode(scope, params.on === true);
215
+ variantsChanged(scope);
216
+ },
217
+ // The component library (skills, rules and prompts kept as files), and adding one to a variant.
218
+ 'variants.components': () => components.list(root()),
219
+ 'variants.importComponents': (params) => components.importItems(root(), (optional(params, 'kind') ?? 'skills'), Array.isArray(params.items) ? params.items : []),
220
+ 'variants.addComponent': (params) => {
221
+ const scope = text(params, 'scope');
222
+ const base = params.variant !== undefined ? variantOf(params.variant) : variants.headVariant(root(), scope)?.variant ?? {};
223
+ const variant = components.addToVariant(root(), base, text(params, 'id'));
224
+ return { variant, ...check(variant) };
225
+ },
226
+ 'variants.materialise': (params) => {
227
+ const built = materialise(root(), params.variant, { trust: harness.trust });
228
+ return { ...built, files: undefined };
229
+ },
230
+ // ---- Refinement: improving a harness from evidence -------------------------------------------
231
+ 'refine.start': (params) => harness.refine.start({ task: params.task, k: typeof params.k === 'number' ? params.k : 1, mode: params.mode === 'sequential' ? 'sequential' : 'parallel', improver: params.improver ?? {}, executor: params.executor ?? undefined, baseVersion: optional(params, 'baseVersion'), retainWorkspaces: params.retainWorkspaces === true, id: optional(params, 'id') ?? undefined }),
232
+ 'refine.get': (params) => harness.refine.get(text(params, 'id')),
233
+ 'refine.list': (params) => harness.refine.list({ scope: optional(params, 'scope'), limit: typeof params.limit === 'number' ? params.limit : undefined }),
234
+ 'refine.running': () => harness.refine.running(),
235
+ 'refine.cancel': async (params) => {
236
+ await harness.refine.cancel(text(params, 'id'));
237
+ return readSummary(root(), text(params, 'id'));
238
+ },
239
+ 'refine.candidates': (params) => harness.refine.candidates(text(params, 'id')),
240
+ 'refine.adopt': (params) => harness.refine.adopt(text(params, 'id'), { label: optional(params, 'label') }),
241
+ 'library.list': (params) => harness.refine.library(text(params, 'scope')),
242
+ 'library.read': (params) => harness.refine.libraryEntry(text(params, 'scope'), text(params, 'area'), text(params, 'task')),
243
+ 'library.forget': (params) => harness.refine.forget(text(params, 'scope'), text(params, 'area'), Array.isArray(params.tasks) ? params.tasks : []),
244
+ // ---- The Wiki: project notes ------------------------------------------------------------------
245
+ 'wiki.list': (params) => notes.list(root(), params.project === undefined ? {} : { project: optional(params, 'project') }),
246
+ 'wiki.read': (params) => notes.read(root(), text(params, 'path')),
247
+ 'wiki.write': (params) => {
248
+ const note = notes.write(root(), text(params, 'path'), typeof params.text === 'string' ? params.text : '', { expectedUpdatedAt: optional(params, 'expectedUpdatedAt') });
249
+ harness.bus.emit({ type: 'wiki.changed' });
250
+ return note;
251
+ },
252
+ 'wiki.remove': (params) => {
253
+ notes.remove(root(), text(params, 'path'));
254
+ harness.bus.emit({ type: 'wiki.changed' });
255
+ },
256
+ 'wiki.search': (params) => notes.search(root(), typeof params.query === 'string' ? params.query : '', { project: optional(params, 'project'), limit: typeof params.limit === 'number' ? params.limit : undefined }),
257
+ 'wiki.graph': () => notes.graph(root()),
258
+ 'wiki.versions': (params) => notes.versions(root(), text(params, 'path')),
259
+ 'wiki.version': (params) => notes.version(root(), text(params, 'path'), text(params, 'id')),
260
+ 'wiki.ensureProject': () => {
261
+ notes.ensureLayout(root(), env.productName);
262
+ harness.bus.emit({ type: 'wiki.changed' });
263
+ },
264
+ // ---- What a session calls, on behalf of a caller the host names -------------------------------
265
+ 'harness.call': (params) => dispatch(env, (params.context ?? {}), text(params, 'call'), params.params ?? {}, { variantDir: optional(params, 'variantDir') }),
266
+ // ---- Recall ------------------------------------------------------------------------------------
267
+ 'recall.search': (params) => recall.searchAll(env, typeof params.query === 'string' ? params.query : '', params.filter ?? {}),
268
+ 'recall.read': (params) => recall.read(root(), text(params, 'runId')),
269
+ // ---- The compiled prompt -----------------------------------------------------------------------
270
+ 'context.compile': (params) => {
271
+ const variant = params.variant ? materialise(root(), params.variant, { trust: harness.trust }) : null;
272
+ const pack = compile(env, (params.context ?? {}), (params.launch ?? {}), variant);
273
+ return params.render ? { pack, text: render(env, pack) } : pack;
274
+ },
275
+ 'context.runPack': (params) => load(root(), text(params, 'runId')),
276
+ // ---- Plugins: everything that shapes a session, and the trust a working folder's code needs ---
277
+ // A host that is not a Node program describes its own parts here instead of in the options.
278
+ 'plugins.describe': (params) => {
279
+ harness.describe(Array.isArray(params.plugins) ? params.plugins : []);
280
+ harness.bus.emit({ type: 'plugins.changed' });
281
+ return { described: [...harness.applicationPlugins] };
282
+ },
283
+ 'plugins.list': (params) => plugins.list(harness, pluginScope(params)),
284
+ 'plugins.get': async (params) => (await plugins.list(harness, pluginScope(params))).find((plugin) => plugin.id === text(params, 'pluginId')) ?? null,
285
+ 'plugins.attach': (params) => plugins.attach(harness, { ...pluginScope(params), id: text(params, 'id'), scope: params.scope ?? null }, true),
286
+ 'plugins.detach': (params) => plugins.attach(harness, { ...pluginScope(params), id: text(params, 'id'), scope: params.scope ?? null }, false),
287
+ 'plugins.install': (params) => install.install(harness, { ...pluginScope(params), source: text(params, 'source') }),
288
+ 'plugins.remove': (params) => install.remove(harness, { ...pluginScope(params), pluginId: text(params, 'pluginId') }),
289
+ 'plugins.update': (params) => install.update(harness, { ...pluginScope(params), pluginId: optional(params, 'pluginId') }),
290
+ 'plugins.configure': (params) => plugins.configure(harness, { ...pluginScope(params), pluginId: text(params, 'pluginId'), settings: (params.settings && typeof params.settings === 'object' ? params.settings : {}) }),
291
+ 'plugins.forgetAgent': (params) => plugins.forgetAgent(harness, text(params, 'agentId')),
292
+ 'plugins.inventory': (params) => plugins.inventoryFor(harness, { ...pluginScope(params), context: (params.context ?? {}), launch: (params.launch ?? {}), tools: params.tools, connections: params.connections, variant: (params.variant ?? null) }),
293
+ 'plugins.trust': (params) => plugins.trust(harness, { cwd: optional(params, 'cwd'), accountId: optional(params, 'accountId'), hash: text(params, 'hash') }),
294
+ 'plugins.untrust': (params) => plugins.untrust(harness, { cwd: optional(params, 'cwd'), accountId: optional(params, 'accountId'), hash: text(params, 'hash') }),
295
+ // ---- Capabilities: the caller-facing view over the existing stores -------------------------
296
+ 'capabilities.list': (params) => capabilities.list(harness, pluginScope(params)),
297
+ 'capabilities.inventory': (params) => capabilities.inventory(harness, { ...pluginScope(params), context: (params.context ?? {}), launch: (params.launch ?? {}), tools: Array.isArray(params.tools) ? params.tools : [], connections: params.connections }),
298
+ 'capabilities.attach': (params) => capabilities.switchCapability(harness, { ...pluginScope(params), id: text(params, 'id'), scope: params.scope ?? null }, true),
299
+ 'capabilities.detach': (params) => capabilities.switchCapability(harness, { ...pluginScope(params), id: text(params, 'id'), scope: params.scope ?? null }, false),
300
+ 'capabilities.resolve': (params) => capabilities.resolve(harness, { ...pluginScope(params), tools: Array.isArray(params.tools) ? params.tools.filter((item) => typeof item === 'string') : [] }),
301
+ 'capabilities.run': (params) => loadCapabilitySnapshot(root(), text(params, 'runId')),
302
+ 'capabilities.intersect': (params) => capabilities.toolIntersection(capabilitySet(params.parent), capabilitySet(params.assignee), params.tools === undefined ? undefined : Array.isArray(params.tools) ? params.tools.filter((item) => typeof item === 'string') : []),
303
+ // ---- Runs --------------------------------------------------------------------------------------
304
+ 'runs.load': (params) => snapshot(root(), text(params, 'runId')),
305
+ 'runs.family': (params) => runFamily(root(), text(params, 'runId')),
306
+ 'runs.find': (params) => findRun(root(), text(params, 'runId')),
307
+ 'runs.list': (params) => listRuns(root(), params.filter ?? {}),
308
+ // Ids of the runs one session, agent, or account made since an instant, oldest first.
309
+ 'runs.since': (params) => runsSince(root(), { session: optional(params.filter ?? {}, 'session'), agent: optional(params.filter ?? {}, 'agent'), account: optional(params.filter ?? {}, 'account') }, optional(params, 'since')),
310
+ 'runs.events': (params) => readEvents(root(), text(params, 'runId')),
311
+ 'runs.pending': (params) => pendingDecisions(readEvents(root(), text(params, 'runId'))),
312
+ 'runs.checklist': (params) => checklistOf(readEvents(root(), text(params, 'runId'))),
313
+ 'runs.continuation': (params) => continuationOf(root(), text(params, 'runId'), optional(params, 'sessionDir')),
314
+ 'runs.active': () => runs.activeRunIds(),
315
+ 'runs.interrupt': async (params) => {
316
+ const runId = text(params, 'runId');
317
+ loadRun(root(), runId);
318
+ await runs.interrupt(runId);
319
+ return loadRun(root(), runId);
320
+ },
321
+ // A message the person sends into a live reply. It reaches the model after the current step;
322
+ // `message.steered` marks the moment, and a message the run never takes is reported by its end.
323
+ 'runs.steer': async (params) => {
324
+ const runId = text(params, 'runId');
325
+ await runs.steer(runId, text(params, 'text'));
326
+ return { runId };
327
+ },
328
+ // What the application reports into a live run, and an approval it asks a person for.
329
+ 'runs.emit': (params) => {
330
+ const run = runs.active(text(params, 'runId'));
331
+ if (!run)
332
+ throw new HarnessError('run_not_active', 'This run is not active.');
333
+ run.emit(params.type, params.payload ?? {});
334
+ },
335
+ 'runs.requestApproval': async (params) => {
336
+ const run = runs.active(text(params, 'runId'));
337
+ if (!run)
338
+ throw new HarnessError('run_not_active', 'The requesting run has ended.');
339
+ const decision = await run.requestApproval({
340
+ target: text(params, 'target'),
341
+ action: typeof params.action === 'string' ? params.action : '',
342
+ ...(typeof params.screenshotRef === 'string' ? { screenshotRef: params.screenshotRef } : {}),
343
+ ...(params.operation ? { operation: params.operation } : {}),
344
+ standing: params.standing === 'none' || params.standing === 'switch' ? params.standing : 'full',
345
+ ...(typeof params.timeoutMs === 'number' ? { timeoutMs: params.timeoutMs } : {})
346
+ });
347
+ return { decision };
348
+ },
349
+ 'runs.resolveApproval': (params) => runs.resolveApproval(text(params, 'runId'), text(params, 'approvalId'), params.decision),
350
+ 'runs.answerQuestion': (params) => runs.answerQuestion(text(params, 'runId'), text(params, 'questionId'), questionAnswer(params.answer)),
351
+ 'runs.answerQuestions': (params) => {
352
+ if (!Array.isArray(params.answers))
353
+ throw invalid('answers must be an array.');
354
+ runs.answerQuestions(text(params, 'runId'), text(params, 'batchId'), params.answers.map((item) => ({ questionId: text(item, 'questionId'), answer: questionAnswer(item.answer) })));
355
+ },
356
+ // ---- Sessions ----------------------------------------------------------------------------------
357
+ 'subagents.spawn': (params) => harness.subagents.spawn(params),
358
+ 'subagents.wait': (params) => harness.subagents.wait(params),
359
+ 'subagents.results': (params) => harness.subagents.results(params),
360
+ 'sessions.spawnSubagent': (params) => sessions.spawnSubagent(params),
361
+ 'sessions.run': (params) => sessions.run(params),
362
+ 'sessions.history': (params) => ({ sessionFile: selectHistory({ sessionDir: text(params, 'sessionDir'), resume: params.resume ?? null }) }),
363
+ // ---- Terminal sessions -------------------------------------------------------------------------
364
+ 'terminal.prepare': (params) => terminals.prepare(params),
365
+ 'terminal.send': (params) => terminals.send({ sessionId: text(params, 'sessionId'), runId: optional(params, 'runId'), text: text(params, 'text') }),
366
+ 'terminal.input': (params) => terminals.input(text(params, 'sessionId'), typeof params.data === 'string' ? params.data : ''),
367
+ 'terminal.state': (params) => terminals.state(text(params, 'sessionId')),
368
+ 'terminal.dispose': (params) => terminals.dispose(text(params, 'sessionId'))
369
+ };
370
+ }
@@ -0,0 +1,19 @@
1
+ import type { SecretStore } from "../accounts/secrets.js";
2
+ import type { Directory } from "../core/env.js";
3
+ import type { ToolPolicy } from "../sessions/policy.js";
4
+ import type { ToolProvider } from "../tools/types.js";
5
+ import type { RpcPeer } from "./rpc.js";
6
+ /** `secrets.get`, `secrets.set`, `secrets.delete` on the host. */
7
+ export declare function remoteSecrets(peer: RpcPeer): SecretStore;
8
+ /** `policy.scope`, `policy.authorize`, `policy.approval`, `policy.connections` on the host. */
9
+ export declare function remotePolicy(peer: RpcPeer): ToolPolicy;
10
+ /**
11
+ * Names the host knows and the harness shows in what it writes. The host pushes them with the
12
+ * `directory.set` method, because the lookups are synchronous.
13
+ */
14
+ export declare function remoteDirectory(peer: RpcPeer): Directory;
15
+ /**
16
+ * Tools the host registers with `tools.register` and runs when the harness calls `tools.call`
17
+ * back. A session is given those its `allow` list names.
18
+ */
19
+ export declare function remoteTools(peer: RpcPeer): ToolProvider;
@@ -0,0 +1,84 @@
1
+ // What a host that is not a Node program supplies over the protocol instead of in-process:
2
+ // its secret store, its policy, its names for agents, and its own tools. Each is a call to the
3
+ // host; the harness works without any of them.
4
+ import { z } from 'zod';
5
+ import { findingSchema } from "../doctor/types.js";
6
+ /** `secrets.get`, `secrets.set`, `secrets.delete` on the host. */
7
+ export function remoteSecrets(peer) {
8
+ return {
9
+ get: (key) => peer.callHost('secrets.get', { key }),
10
+ set: async (key, value) => void (await peer.callHost('secrets.set', { key, value })),
11
+ delete: async (key) => void (await peer.callHost('secrets.delete', { key }))
12
+ };
13
+ }
14
+ /** `policy.scope`, `policy.authorize`, `policy.approval`, `policy.connections` on the host. */
15
+ export function remotePolicy(peer) {
16
+ const identify = (call) => ({ runId: call.run.id, sessionId: call.run.sessionId, caller: call.caller, tool: call.tool, args: call.args });
17
+ return {
18
+ scope: (call) => peer.callHost('policy.scope', identify(call), 90_000),
19
+ authorize: async (call) => void (await peer.callHost('policy.authorize', identify(call), 90_000)),
20
+ approval: (input) => peer.callHost('policy.approval', { runId: input.run.id, sessionId: input.run.sessionId, target: input.target, operation: input.operation ?? null }),
21
+ connections: (input) => peer.callHost('policy.connections', input)
22
+ };
23
+ }
24
+ /**
25
+ * Names the host knows and the harness shows in what it writes. The host pushes them with the
26
+ * `directory.set` method, because the lookups are synchronous.
27
+ */
28
+ export function remoteDirectory(peer) {
29
+ let agents = {};
30
+ let sessions = {};
31
+ peer.handle('directory.set', (params) => {
32
+ if (params.agents)
33
+ agents = params.agents;
34
+ if (params.sessions)
35
+ sessions = { ...sessions, ...params.sessions };
36
+ });
37
+ return { agentName: (id) => agents[id] ?? null, sessionAgent: (id) => sessions[id] ?? null };
38
+ }
39
+ /**
40
+ * Tools the host registers with `tools.register` and runs when the harness calls `tools.call`
41
+ * back. A session is given those its `allow` list names.
42
+ */
43
+ export function remoteTools(peer) {
44
+ let registered = [];
45
+ const descriptor = z.object({
46
+ id: z.string().min(1), category: z.string(), title: z.string(), tools: z.array(z.string()),
47
+ probe: z.object({ notice: z.string(), tool: z.string(), input: z.record(z.string(), z.unknown()), contains: z.string().min(1) }).optional()
48
+ });
49
+ let diagnostics = [];
50
+ peer.handle('tools.register', (params) => {
51
+ diagnostics = z.array(descriptor).parse(params.diagnostics ?? []);
52
+ registered = Array.isArray(params.tools) ? params.tools : [];
53
+ return { registered: registered.map((tool) => tool.name) };
54
+ });
55
+ const provider = (session) => registered
56
+ .filter((tool) => session.allow.includes(tool.name))
57
+ .map((tool) => ({
58
+ name: tool.name,
59
+ label: tool.label ?? tool.name,
60
+ description: tool.description,
61
+ parameters: (Type) => Type.Unsafe(tool.parameters),
62
+ execute: async (input) => {
63
+ const result = await peer.callHost('tools.call', { name: tool.name, input, runId: session.run.runId, sessionId: session.run.sessionId, caller: session.caller, depth: session.depth, cwd: session.cwd }, 1_230_000);
64
+ return typeof result === 'string' ? result : JSON.stringify(result);
65
+ }
66
+ }));
67
+ provider.diagnostics = context => diagnostics.map(check => ({
68
+ id: `host.${check.id}`, category: check.category, title: check.title, tools: check.tools,
69
+ local: async (signal) => {
70
+ signal.throwIfAborted();
71
+ const result = await peer.callHost('tools.diagnose', { id: check.id, context }, 8000);
72
+ return findingSchema.pick({ status: true, evidence: true, remedy: true }).parse(result);
73
+ },
74
+ live: check.probe ? {
75
+ notice: check.probe.notice,
76
+ run: async (probe) => {
77
+ const result = await probe.call(check.probe.tool, check.probe.input);
78
+ const text = typeof result === 'string' ? result : result.text;
79
+ return { status: text.includes(check.probe.contains) ? 'pass' : 'fail', evidence: 'The registered host tool probe completed; the expected response marker was checked.' };
80
+ }
81
+ } : undefined
82
+ }));
83
+ return provider;
84
+ }
@@ -0,0 +1,20 @@
1
+ export declare const PROTOCOL_VERSION = 1;
2
+ export type Handler = (params: any) => Promise<unknown> | unknown;
3
+ export interface Transport {
4
+ write(line: string): void;
5
+ onLine(listener: (line: string) => void): void;
6
+ }
7
+ export declare function stdioTransport(): Transport;
8
+ export declare class RpcPeer {
9
+ private readonly transport;
10
+ private readonly handlers;
11
+ private readonly pendingCalls;
12
+ private nextCallId;
13
+ constructor(transport: Transport);
14
+ handle(method: string, handler: Handler): void;
15
+ methods(): string[];
16
+ send(message: Record<string, unknown>): void;
17
+ /** Asks the host to perform a named operation. */
18
+ callHost<T = unknown>(call: string, params: unknown, timeoutMs?: number): Promise<T>;
19
+ private receive;
20
+ }
@@ -0,0 +1,102 @@
1
+ // Newline-delimited JSON between the harness and a host process that embeds it.
2
+ //
3
+ // host → harness { v, id, method, params } request
4
+ // harness → host { v, id, result } | { v, id, error }
5
+ // harness → host { v, event } run event (validated before sending)
6
+ // harness → host { v, notice } some state changed and should be read again
7
+ // harness → host { v, id, call, params } the harness asks the host for a named operation
8
+ // host → harness { v, id, result } | { v, id, error } reply to a call
9
+ //
10
+ // stdout carries only protocol lines; diagnostics go to stderr.
11
+ import { createInterface } from 'node:readline';
12
+ import { log } from "../core/bus.js";
13
+ import { HarnessError, toErrorShape } from "../core/errors.js";
14
+ export const PROTOCOL_VERSION = 1;
15
+ export function stdioTransport() {
16
+ const reader = createInterface({ input: process.stdin, crlfDelay: Infinity });
17
+ return {
18
+ write: (line) => void process.stdout.write(`${line}\n`),
19
+ onLine: (listener) => void reader.on('line', listener)
20
+ };
21
+ }
22
+ export class RpcPeer {
23
+ transport;
24
+ handlers = new Map();
25
+ pendingCalls = new Map();
26
+ nextCallId = 0;
27
+ constructor(transport) {
28
+ this.transport = transport;
29
+ transport.onLine((line) => void this.receive(line));
30
+ }
31
+ handle(method, handler) {
32
+ this.handlers.set(method, handler);
33
+ }
34
+ methods() {
35
+ return [...this.handlers.keys()].sort();
36
+ }
37
+ send(message) {
38
+ this.transport.write(JSON.stringify({ v: PROTOCOL_VERSION, ...message }));
39
+ }
40
+ /** Asks the host to perform a named operation. */
41
+ callHost(call, params, timeoutMs = 30_000) {
42
+ const id = `s${++this.nextCallId}`;
43
+ return new Promise((resolve, reject) => {
44
+ const timer = setTimeout(() => {
45
+ this.pendingCalls.delete(id);
46
+ reject(new HarnessError('host_timeout', `The host did not answer ${call}.`));
47
+ }, timeoutMs);
48
+ this.pendingCalls.set(id, {
49
+ resolve: (value) => {
50
+ clearTimeout(timer);
51
+ resolve(value);
52
+ },
53
+ reject: (error) => {
54
+ clearTimeout(timer);
55
+ reject(error);
56
+ }
57
+ });
58
+ this.send({ id, call, params });
59
+ });
60
+ }
61
+ async receive(line) {
62
+ let message;
63
+ try {
64
+ message = JSON.parse(line);
65
+ }
66
+ catch {
67
+ log('ignored a non-JSON line');
68
+ return;
69
+ }
70
+ if (message.v !== PROTOCOL_VERSION || typeof message.id !== 'string') {
71
+ log('ignored a message with an unknown version or no id');
72
+ return;
73
+ }
74
+ const id = message.id;
75
+ if (typeof message.method === 'string') {
76
+ const handler = this.handlers.get(message.method);
77
+ if (!handler) {
78
+ this.send({ id, error: { code: 'unknown_method', message: `Unknown method ${message.method}.` } });
79
+ return;
80
+ }
81
+ try {
82
+ const result = await handler(message.params ?? {});
83
+ this.send({ id, result: result ?? null });
84
+ }
85
+ catch (error) {
86
+ this.send({ id, error: toErrorShape(error) });
87
+ }
88
+ return;
89
+ }
90
+ const pending = this.pendingCalls.get(id);
91
+ if (pending) {
92
+ this.pendingCalls.delete(id);
93
+ if (message.error) {
94
+ const shape = message.error;
95
+ pending.reject(new HarnessError(shape.code, shape.message, shape.retryHint ?? null));
96
+ }
97
+ else {
98
+ pending.resolve(message.result);
99
+ }
100
+ }
101
+ }
102
+ }
@@ -0,0 +1,10 @@
1
+ import type { Harness } from "../harness.js";
2
+ import { RpcPeer, type Transport } from "./rpc.js";
3
+ export interface Served {
4
+ peer: RpcPeer;
5
+ /** Stops live work and releases what the harness holds. */
6
+ shutdown(): Promise<void>;
7
+ }
8
+ /** Registers the method table on `peer` and forwards events and notices to it. */
9
+ export declare function attach(harness: Harness, peer: RpcPeer): void;
10
+ export declare function serve(harness: Harness, transport: Transport): Served;
@@ -0,0 +1,18 @@
1
+ import { methods } from "./methods.js";
2
+ import { RpcPeer } from "./rpc.js";
3
+ /** Registers the method table on `peer` and forwards events and notices to it. */
4
+ export function attach(harness, peer) {
5
+ for (const [name, handler] of Object.entries(methods(harness)))
6
+ peer.handle(name, handler);
7
+ peer.handle('harness.methods', () => peer.methods());
8
+ harness.runs.listen((event) => peer.send({ event }));
9
+ harness.bus.on((notice) => peer.send({ notice }));
10
+ }
11
+ export function serve(harness, transport) {
12
+ const peer = new RpcPeer(transport);
13
+ attach(harness, peer);
14
+ let closing = null;
15
+ const shutdown = () => (closing ??= harness.close());
16
+ peer.handle('harness.shutdown', () => shutdown());
17
+ return { peer, shutdown };
18
+ }