@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
@@ -1,130 +0,0 @@
1
- // Live MCP client sessions: one per (session, connection), opened on first use and closed when
2
- // the session's run ends or the connection changes.
3
- import { Client, SSEClientTransport, StreamableHTTPClientTransport, UnauthorizedError } from '@modelcontextprotocol/client'
4
- import { StdioClientTransport } from '@modelcontextprotocol/client/stdio'
5
- import { randomUUID } from 'node:crypto'
6
-
7
- import { HarnessError } from '../core/errors'
8
- import { StoredOAuthProvider, type OAuthHost } from './oauth'
9
- import type { HttpConfig, LaunchConfig, StdioConfig } from './types'
10
-
11
- interface Live {
12
- client: Client
13
- transport: { close(): Promise<void> }
14
- config: string
15
- }
16
-
17
- export const signInRequired = (config: Pick<LaunchConfig, 'name'>): HarnessError => new HarnessError('mcp_unauthorized', `${config.name} needs you to sign in again in Connections.`)
18
- export const isSignInRequired = (error: unknown): boolean => error instanceof UnauthorizedError || (error instanceof HarnessError && error.code === 'mcp_unauthorized')
19
-
20
- export class McpManager {
21
- private readonly sessions = new Map<string, Promise<Live>>()
22
-
23
- constructor(private readonly oauth: OAuthHost) {}
24
-
25
- async close(connectionId?: string, sessionId?: string): Promise<void> {
26
- const closing = [...this.sessions].filter(([key]) => (!connectionId || key.endsWith(`:${connectionId}`)) && (!sessionId || key.startsWith(`${sessionId}:`)))
27
- for (const [key] of closing) this.sessions.delete(key)
28
- await Promise.allSettled(
29
- closing.map(async ([, session]) => {
30
- const live = await session
31
- await live.client.close()
32
- await live.transport.close()
33
- })
34
- )
35
- }
36
-
37
- /** The client for a connection in one scope, reconnecting when the connection's configuration changed. */
38
- async client(scope: string, config: LaunchConfig): Promise<Client> {
39
- const key = `${scope}:${config.id}`
40
- const fingerprint = JSON.stringify(config)
41
- const existing = this.sessions.get(key)
42
- if (existing) {
43
- const live = await existing.catch(() => null)
44
- if (live?.config === fingerprint) return live.client
45
- await live?.client.close().catch(() => undefined)
46
- this.sessions.delete(key)
47
- }
48
- const pending: Promise<Live> = (async () => {
49
- const { client, transport } = config.transport === 'http' ? await this.connectHttp(config) : await this.connectStdio(config)
50
- client.onclose = () => {
51
- if (this.sessions.get(key) === pending) this.sessions.delete(key)
52
- }
53
- return { client, transport, config: fingerprint }
54
- })()
55
- this.sessions.set(key, pending)
56
- try {
57
- return (await pending).client
58
- } catch (error) {
59
- this.sessions.delete(key)
60
- throw error
61
- }
62
- }
63
-
64
- private async connectStdio(config: StdioConfig) {
65
- const client = new Client({ name: 'xagent', version: '0.1.0' })
66
- const transport = new StdioClientTransport({ command: config.command, args: config.args, cwd: config.cwd ?? undefined, env: config.env, stderr: 'pipe' })
67
- try {
68
- await client.connect(transport, { timeout: 30000 })
69
- } catch {
70
- await transport.close()
71
- throw new HarnessError('mcp_unavailable', `${config.name} could not start or initialize. Check its executable and arguments.`)
72
- }
73
- // Servers' diagnostics may contain secrets; do not persist or forward stderr.
74
- transport.stderr?.on('data', () => undefined)
75
- return { client, transport }
76
- }
77
-
78
- private async connectHttp(config: HttpConfig) {
79
- const authProvider = config.auth === 'oauth' ? new StoredOAuthProvider(this.oauth, config, false) : undefined
80
- // Without saved tokens the only way forward is the browser, which a session may not open.
81
- if (authProvider && !(await authProvider.tokens())) throw signInRequired(config)
82
- const options = { authProvider, requestInit: { headers: config.headers } }
83
- // Servers that predate Streamable HTTP only answer on SSE.
84
- for (const Transport of [StreamableHTTPClientTransport, SSEClientTransport]) {
85
- const client = new Client({ name: 'xagent', version: '0.1.0' })
86
- const transport = new Transport(new URL(config.url), options)
87
- try {
88
- await client.connect(transport, { timeout: 30000 })
89
- return { client, transport }
90
- } catch (error) {
91
- await transport.close().catch(() => undefined)
92
- if (isSignInRequired(error)) throw signInRequired(config)
93
- }
94
- }
95
- throw new HarnessError('mcp_unavailable', `${config.name} could not be reached. Check its address and credentials.`)
96
- }
97
-
98
- /** Runs `work` on a connection opened only for it. */
99
- private async once<T>(prefix: string, config: LaunchConfig, work: (client: Client) => Promise<T>): Promise<T> {
100
- const scope = `${prefix}-${randomUUID()}`
101
- try {
102
- return await work(await this.client(scope, config))
103
- } finally {
104
- const key = `${scope}:${config.id}`
105
- const session = this.sessions.get(key)
106
- this.sessions.delete(key)
107
- if (session) await (await session).client.close().catch(() => undefined)
108
- }
109
- }
110
-
111
- /** What a connection offers, read on a connection of its own. */
112
- probe(config: LaunchConfig): Promise<{ serverName: string; tools: unknown[]; vaultId: string | null }> {
113
- return this.once('probe', config, async (client) => {
114
- const tools = (await client.listTools()).tools
115
- let vaultId: string | null = null
116
- if (tools.some((tool) => tool.name === 'x_workspace_status')) {
117
- const status = await client.callTool({ name: 'x_workspace_status', arguments: {} })
118
- const envelope = status.structuredContent as { ok?: boolean; vaultId?: string; error?: { message?: string } } | undefined
119
- if (!envelope?.ok) throw new HarnessError('mcp_unavailable', envelope?.error?.message ?? 'Workspace vault is not bound.')
120
- vaultId = envelope.vaultId ?? null
121
- }
122
- return { serverName: client.getServerVersion()?.name ?? config.name, tools, vaultId }
123
- })
124
- }
125
-
126
- /** One read on a connection of its own, outside any session. */
127
- readSource(config: LaunchConfig, tool: string, args: Record<string, unknown>): Promise<unknown> {
128
- return this.once('source', config, (client) => client.callTool({ name: tool, arguments: args }, { timeout: 60000 }))
129
- }
130
- }
package/src/mcp/oauth.ts DELETED
@@ -1,195 +0,0 @@
1
- // OAuth sign-in for a remote connection. State is kept with the connection's other secrets.
2
- // Only an interactive provider (a sign-in a person started) may open a browser; a session that
3
- // needs a new sign-in fails instead.
4
- import { auth, UnauthorizedError } from '@modelcontextprotocol/client'
5
- import type { OAuthClientInformationContext, OAuthClientMetadata, OAuthClientProvider, OAuthDiscoveryState, StoredOAuthClientInformation, StoredOAuthTokens } from '@modelcontextprotocol/client'
6
- import { randomUUID } from 'node:crypto'
7
- import { createServer } from 'node:http'
8
-
9
- import { HarnessError } from '../core/errors'
10
- import { MCP_OAUTH_PORT, MCP_OAUTH_REDIRECT_URL, type HttpConfig } from './types'
11
-
12
- interface Saved {
13
- client?: StoredOAuthClientInformation
14
- tokens?: StoredOAuthTokens
15
- discovery?: OAuthDiscoveryState
16
- staticClient?: StoredOAuthClientInformation
17
- staticIssuer?: string
18
- }
19
-
20
- /** Where a connection's OAuth state is read and written, and how a sign-in page is shown. */
21
- export interface OAuthHost {
22
- load(connectionId: string): Promise<Record<string, unknown>>
23
- save(connectionId: string, state: Record<string, unknown>): Promise<void>
24
- openUrl(url: string): Promise<void> | void
25
- /** The name shown on the provider's consent page. */
26
- clientName: string
27
- }
28
-
29
- export class StoredOAuthProvider implements OAuthClientProvider {
30
- readonly expectedState = randomUUID()
31
- private verifier: string | null = null
32
-
33
- constructor(
34
- private readonly host: OAuthHost,
35
- private readonly config: Pick<HttpConfig, 'id' | 'scopes'>,
36
- private readonly interactive: boolean
37
- ) {}
38
-
39
- get redirectUrl(): string {
40
- return MCP_OAUTH_REDIRECT_URL
41
- }
42
-
43
- get clientMetadata(): OAuthClientMetadata {
44
- return {
45
- client_name: this.host.clientName,
46
- redirect_uris: [MCP_OAUTH_REDIRECT_URL],
47
- grant_types: ['authorization_code', 'refresh_token'],
48
- response_types: ['code'],
49
- token_endpoint_auth_method: 'none',
50
- ...(this.config.scopes.length ? { scope: this.config.scopes.join(' ') } : {})
51
- }
52
- }
53
-
54
- state(): string {
55
- return this.expectedState
56
- }
57
-
58
- private load(): Promise<Saved> {
59
- return this.host.load(this.config.id) as Promise<Saved>
60
- }
61
-
62
- private async change(edit: (saved: Saved) => Saved): Promise<void> {
63
- await this.host.save(this.config.id, edit(await this.load()) as Record<string, unknown>)
64
- }
65
-
66
- async clientInformation(context?: OAuthClientInformationContext): Promise<StoredOAuthClientInformation | undefined> {
67
- const saved = await this.load()
68
- if (!saved.staticClient) return saved.client
69
- // A client the user registered themselves (providers without dynamic registration) wins. It is
70
- // tied to the authorization server seen at sign-in, so a session never offers it to another one.
71
- if (this.interactive && context && saved.staticIssuer !== context.issuer) await this.change((current) => ({ ...current, staticIssuer: context.issuer }))
72
- const issuer = this.interactive ? context?.issuer : saved.staticIssuer
73
- return issuer ? { ...saved.staticClient, issuer } : saved.staticClient
74
- }
75
-
76
- async saveClientInformation(client: StoredOAuthClientInformation): Promise<void> {
77
- await this.change((saved) => ({ ...saved, client }))
78
- }
79
-
80
- async tokens(): Promise<StoredOAuthTokens | undefined> {
81
- return (await this.load()).tokens
82
- }
83
-
84
- async saveTokens(tokens: StoredOAuthTokens): Promise<void> {
85
- await this.change((saved) => ({ ...saved, tokens }))
86
- }
87
-
88
- async discoveryState(): Promise<OAuthDiscoveryState | undefined> {
89
- return (await this.load()).discovery
90
- }
91
-
92
- async saveDiscoveryState(discovery: OAuthDiscoveryState): Promise<void> {
93
- await this.change((saved) => ({ ...saved, discovery }))
94
- }
95
-
96
- saveCodeVerifier(verifier: string): void {
97
- this.verifier = verifier
98
- }
99
-
100
- codeVerifier(): string {
101
- if (!this.verifier) throw new UnauthorizedError('Sign-in was not started from this app.')
102
- return this.verifier
103
- }
104
-
105
- async invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise<void> {
106
- if (scope === 'verifier' || scope === 'all') this.verifier = null
107
- if (scope === 'verifier') return
108
- await this.change((saved) => (scope === 'all' ? {} : { ...saved, [scope]: undefined }))
109
- }
110
-
111
- async redirectToAuthorization(url: URL): Promise<void> {
112
- if (!this.interactive) throw new UnauthorizedError('Sign in again in Connections.')
113
- // Google only returns a refresh token when offline access is requested with a consent prompt.
114
- if (url.hostname === 'accounts.google.com') {
115
- url.searchParams.set('access_type', 'offline')
116
- url.searchParams.set('prompt', 'consent')
117
- }
118
- await this.host.openUrl(url.toString())
119
- }
120
- }
121
-
122
- const page = (title: string, message: string): string => `<!doctype html><meta charset="utf-8"><title>${title}</title><body style="font:16px system-ui;margin:20vh auto;max-width:28rem;text-align:center"><p>${message}</p></body>`
123
-
124
- // One sign-in owns the loopback port. Starting another ends the one still waiting, so a closed
125
- // browser tab never blocks a retry.
126
- let cancelActive: (() => Promise<void>) | null = null
127
-
128
- /** Waits on the fixed loopback address for the provider to send the browser back. */
129
- function listenForCallback(expectedState: string, clientName: string): Promise<{ result: Promise<{ code: string; iss?: string }>; close: () => Promise<void> }> {
130
- return new Promise((ready, failed) => {
131
- let settle: { resolve: (value: { code: string; iss?: string }) => void; reject: (error: Error) => void }
132
- const result = new Promise<{ code: string; iss?: string }>((resolve, reject) => {
133
- settle = { resolve, reject }
134
- })
135
- result.catch(() => undefined)
136
- const server = createServer((request, response) => {
137
- const url = new URL(request.url ?? '/', MCP_OAUTH_REDIRECT_URL)
138
- const reply = (status: number, message: string): void => {
139
- response.writeHead(status, { 'content-type': 'text/html; charset=utf-8' })
140
- response.end(page(clientName, message))
141
- }
142
- if (url.pathname !== new URL(MCP_OAUTH_REDIRECT_URL).pathname) return reply(404, 'Not found.')
143
- // Anything on this machine can reach the port; only the request carrying this sign-in's state counts.
144
- if (url.searchParams.get('state') !== expectedState) return reply(400, `This sign-in link is not the one ${clientName} is waiting for.`)
145
- const code = url.searchParams.get('code')
146
- if (!code) {
147
- reply(400, 'Sign-in was not completed. You can close this window.')
148
- return settle.reject(new HarnessError('mcp_unauthorized', url.searchParams.get('error') === 'access_denied' ? 'Sign-in was cancelled.' : 'The provider did not complete the sign-in.'))
149
- }
150
- reply(200, `Signed in. You can close this window and return to ${clientName}.`)
151
- settle.resolve({ code, iss: url.searchParams.get('iss') ?? undefined })
152
- })
153
- const timer = setTimeout(() => settle.reject(new HarnessError('mcp_unauthorized', 'Sign-in timed out. Try again.')), 300000)
154
- server.once('error', (error: NodeJS.ErrnoException) => {
155
- clearTimeout(timer)
156
- failed(new HarnessError('invalid_request', error.code === 'EADDRINUSE' ? `Port ${MCP_OAUTH_PORT} is in use. Finish or cancel the other sign-in, or quit the program using that port, then try again.` : 'The sign-in listener could not start.'))
157
- })
158
- const closed = new Promise<void>((resolve) => server.once('close', resolve))
159
- const close = (): Promise<void> => {
160
- clearTimeout(timer)
161
- if (cancelActive === cancel) cancelActive = null
162
- server.close()
163
- server.closeAllConnections()
164
- return closed
165
- }
166
- const cancel = (): Promise<void> => {
167
- settle.reject(new HarnessError('mcp_unauthorized', 'Sign-in was cancelled.'))
168
- return close()
169
- }
170
- server.listen(MCP_OAUTH_PORT, '127.0.0.1', () => {
171
- cancelActive = cancel
172
- ready({ result, close })
173
- })
174
- })
175
- }
176
-
177
- /** Opens the provider's sign-in page and waits for the browser to return to the loopback address. */
178
- export async function signIn(host: OAuthHost, config: HttpConfig): Promise<void> {
179
- const provider = new StoredOAuthProvider(host, config, true)
180
- const scope = config.scopes.join(' ') || undefined
181
- await cancelActive?.()
182
- const callback = await listenForCallback(provider.expectedState, host.clientName)
183
- try {
184
- if ((await auth(provider, { serverUrl: config.url, scope, forceReauthorization: true })) === 'REDIRECT') {
185
- const { code, iss } = await callback.result
186
- if ((await auth(provider, { serverUrl: config.url, scope, authorizationCode: code, iss })) !== 'AUTHORIZED') throw new HarnessError('mcp_unauthorized', 'The provider did not complete the sign-in.')
187
- }
188
- } catch (error) {
189
- if (error instanceof HarnessError) throw error
190
- // Provider responses can quote credentials; report only that it failed.
191
- throw new HarnessError('mcp_unauthorized', `${config.name} sign-in failed. Check the connection's address and OAuth client, then try again.`)
192
- } finally {
193
- await callback.close()
194
- }
195
- }
@@ -1,79 +0,0 @@
1
- import { createHash } from 'node:crypto'
2
- import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
3
- import { tmpdir } from 'node:os'
4
- import { join } from 'node:path'
5
- import { afterEach, describe, expect, it } from 'vitest'
6
-
7
- import * as attachments from '../plugins/attachments'
8
- import { migrateConnectionScopes, rollbackConnectionScopeMigration } from './scopeMigration'
9
-
10
- const roots: string[] = []
11
- function fixture(): { root: string; stateDir: string; sessionPath: string } {
12
- const base = mkdtempSync(join(tmpdir(), 'xingular-scope-migration-'))
13
- roots.push(base)
14
- const root = join(base, 'data')
15
- const stateDir = join(base, 'state')
16
- mkdirSync(join(root, 'config'), { recursive: true })
17
- mkdirSync(join(root, 'sessions', 'agent'), { recursive: true })
18
- mkdirSync(stateDir, { recursive: true })
19
- const sessionPath = join(root, 'sessions', 'agent', 'thread.json')
20
- writeFileSync(sessionPath, Buffer.from('{ "session": "keep these bytes\\nexactly" }\n'))
21
- mkdirSync(join(root, 'agents', 'agent-a'), { recursive: true })
22
- writeFileSync(join(root, 'agents', 'agent-a', 'agent.md'), Buffer.from('tools: [read, bash, mcp_call_tool]\n'))
23
- return { root, stateDir, sessionPath }
24
- }
25
-
26
- function digest(path: string): string {
27
- return createHash('sha256').update(readFileSync(path)).digest('hex')
28
- }
29
-
30
- afterEach(() => {
31
- for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
32
- })
33
-
34
- describe('connector scope migration', () => {
35
- it('moves scopes, verifies assignments, keeps session bytes, and restores exact backups', () => {
36
- const { root, stateDir, sessionPath } = fixture()
37
- const sessionHash = digest(sessionPath)
38
- const agentToolsPath = join(root, 'agents', 'agent-a', 'agent.md')
39
- const agentToolsHash = digest(agentToolsPath)
40
- const connectionBytes = Buffer.from(`[{"id":"linear","name":"Linear","kind":"remote","enabled":true,"global":true,"agentIds":["agent-a"],"excludedAgentIds":["agent-b"],"projectIds":["project-a"],"excludedProjectIds":["project-b"],"url":"https://mcp.example"}]\n`)
41
- const oldAttachmentsBytes = Buffer.from('{"version":1,"global":{"on":["existing"],"off":[]},"agents":{},"projects":{},"settings":{"keep":{"x":1}}}\n')
42
- const connectionsPath = join(stateDir, 'connections.json')
43
- const attachmentsPath = join(root, 'config', 'plugin-attachments.json')
44
- writeFileSync(connectionsPath, connectionBytes)
45
- writeFileSync(attachmentsPath, oldAttachmentsBytes)
46
-
47
- const result = migrateConnectionScopes(root, stateDir)
48
- expect(result).toMatchObject({ status: 'complete', connectionCount: 1, scopeAssignmentCount: 5, hadAttachments: true })
49
- const saved = JSON.parse(readFileSync(connectionsPath, 'utf8'))[0]
50
- expect(saved).toMatchObject({ id: 'linear', url: 'https://mcp.example' })
51
- for (const key of ['global', 'agentIds', 'excludedAgentIds', 'projectIds', 'excludedProjectIds']) expect(saved).not.toHaveProperty(key)
52
-
53
- const migrated = attachments.load(root)
54
- expect(migrated.global.on).toContain('connected-apps/connection/linear')
55
- expect(migrated.agents['agent-a'].on).toContain('connected-apps/connection/linear')
56
- expect(migrated.agents['agent-b'].off).toContain('connected-apps/connection/linear')
57
- expect(migrated.projects['project-a'].on).toContain('connected-apps/connection/linear')
58
- expect(migrated.projects['project-b'].off).toContain('connected-apps/connection/linear')
59
- expect(digest(sessionPath)).toBe(sessionHash)
60
- expect(digest(agentToolsPath)).toBe(agentToolsHash)
61
- expect(readFileSync(join(stateDir, 'connections.pre-capability-scope.json'))).toEqual(connectionBytes)
62
- expect(readFileSync(join(root, 'config', 'plugin-attachments.pre-capability-scope.json'))).toEqual(oldAttachmentsBytes)
63
-
64
- rollbackConnectionScopeMigration(root, stateDir)
65
- expect(readFileSync(connectionsPath)).toEqual(connectionBytes)
66
- expect(readFileSync(attachmentsPath)).toEqual(oldAttachmentsBytes)
67
- expect(digest(sessionPath)).toBe(sessionHash)
68
- expect(digest(agentToolsPath)).toBe(agentToolsHash)
69
- })
70
-
71
- it('is idempotent after completion without rewriting session data', () => {
72
- const { root, stateDir, sessionPath } = fixture()
73
- writeFileSync(join(stateDir, 'connections.json'), '[{"id":"linear","global":false}]\n')
74
- const before = digest(sessionPath)
75
- const first = migrateConnectionScopes(root, stateDir)
76
- expect(migrateConnectionScopes(root, stateDir)).toEqual(first)
77
- expect(digest(sessionPath)).toBe(before)
78
- })
79
- })
@@ -1,204 +0,0 @@
1
- // Moves who can reach each connected app out of the device-local connection records and into
2
- // the data root's shared capability attachment store. The originals remain as owner-only backups.
3
- import { chmodSync, existsSync, readFileSync, unlinkSync } from 'node:fs'
4
- import { join } from 'node:path'
5
-
6
- import { atomicWrite, readJson, writeJson } from '../core/fs'
7
- import * as attachments from '../plugins/attachments'
8
- import { connectionCapabilityId, connectionSchema, type Connection } from './types'
9
-
10
- interface MigrationRecord {
11
- version: 1
12
- status: 'attachments-written' | 'complete'
13
- connectionCount: number
14
- scopeAssignmentCount: number
15
- connectionsBackup: string | null
16
- attachmentsBackup: string | null
17
- hadAttachments: boolean
18
- }
19
-
20
- const recordPath = (root: string): string => join(root, 'config/capability-scope-migration.json')
21
- const attachmentsPath = (root: string): string => join(root, 'config/plugin-attachments.json')
22
- const connectionPath = (stateDir: string): string => join(stateDir, 'connections.json')
23
- const connectionsBackupPath = (stateDir: string): string => join(stateDir, 'connections.pre-capability-scope.json')
24
- const attachmentsBackupPath = (root: string): string => join(root, 'config/plugin-attachments.pre-capability-scope.json')
25
-
26
- /** Scope writes are safe only after the legacy records have been copied and stripped. */
27
- export function connectionScopeMigrationComplete(root: string): boolean {
28
- try {
29
- const marker = readJson<MigrationRecord>(recordPath(root))
30
- return marker?.version === 1 && marker.status === 'complete'
31
- } catch {
32
- return false
33
- }
34
- }
35
-
36
- interface ScopeRows {
37
- global: boolean
38
- agents: Map<string, boolean>
39
- projects: Map<string, boolean>
40
- }
41
-
42
- function unique(values: readonly string[]): string[] {
43
- return [...new Set(values)]
44
- }
45
-
46
- function scopeRows(connection: Connection): ScopeRows {
47
- const agents = new Map<string, boolean>()
48
- const projects = new Map<string, boolean>()
49
- for (const id of unique([...connection.agentIds, ...connection.excludedAgentIds])) {
50
- agents.set(id, !connection.excludedAgentIds.includes(id))
51
- }
52
- for (const id of unique([...connection.projectIds, ...connection.excludedProjectIds])) {
53
- projects.set(id, !connection.excludedProjectIds.includes(id))
54
- }
55
- return { global: connection.global, agents, projects }
56
- }
57
-
58
- function assignmentCount(rows: ScopeRows): number {
59
- return 1 + rows.agents.size + rows.projects.size
60
- }
61
-
62
- function removeId(choices: attachments.Attachments, id: string): void {
63
- attachments.forgetId(choices, id)
64
- }
65
-
66
- function put(map: { on: string[]; off: string[] }, id: string, value: boolean): void {
67
- map.on = map.on.filter((item) => item !== id)
68
- map.off = map.off.filter((item) => item !== id)
69
- map[value ? 'on' : 'off'].push(id)
70
- }
71
-
72
- function writeRows(choices: attachments.Attachments, id: string, rows: ScopeRows): void {
73
- removeId(choices, id)
74
- put(choices.global, id, rows.global)
75
- for (const [scopeId, on] of rows.agents) {
76
- const target = (choices.agents[scopeId] ??= { on: [], off: [] })
77
- put(target, id, on)
78
- }
79
- for (const [scopeId, on] of rows.projects) {
80
- const target = (choices.projects[scopeId] ??= { on: [], off: [] })
81
- put(target, id, on)
82
- }
83
- }
84
-
85
- function readValue(item: { on: string[]; off: string[] } | undefined, id: string): boolean | null {
86
- if (item?.off.includes(id)) return false
87
- if (item?.on.includes(id)) return true
88
- return null
89
- }
90
-
91
- function verifyRows(choices: attachments.Attachments, id: string, expected: ScopeRows): boolean {
92
- if (readValue(choices.global, id) !== expected.global) return false
93
- for (const [scopeId, on] of expected.agents) {
94
- if (readValue(choices.agents[scopeId], id) !== on) return false
95
- }
96
- for (const [scopeId, on] of expected.projects) {
97
- if (readValue(choices.projects[scopeId], id) !== on) return false
98
- }
99
- return true
100
- }
101
-
102
- function backup(source: string, target: string): boolean {
103
- if (!existsSync(source)) return false
104
- if (!existsSync(target)) atomicWrite(target, readFileSync(source))
105
- chmodSync(target, 0o600)
106
- return true
107
- }
108
-
109
- function setPrivate(path: string): void {
110
- try { chmodSync(path, 0o600) } catch { /* The atomic write remains usable if chmod is unavailable. */ }
111
- }
112
-
113
- function stripScopes(stateDir: string): void {
114
- const path = connectionPath(stateDir)
115
- if (!existsSync(path)) return
116
- const stored = readJson<unknown>(path)
117
- if (!Array.isArray(stored)) throw new Error('Stored connector data must be a list before its scopes can be migrated.')
118
- const records = stored.map((item) => {
119
- if (!item || typeof item !== 'object' || Array.isArray(item)) throw new Error('A stored connector record is invalid; no scope data was removed.')
120
- const { global: _global, agentIds: _agentIds, projectIds: _projectIds, excludedAgentIds: _excludedAgentIds, excludedProjectIds: _excludedProjectIds, ...connection } = item as Record<string, unknown>
121
- return connection
122
- })
123
- writeJson(path, records)
124
- setPrivate(path)
125
- }
126
-
127
- /**
128
- * Runs once when a data root opens. Both source files are backed up before either is changed;
129
- * a stage marker makes an interrupted migration safe to finish on the next open.
130
- */
131
- export function migrateConnectionScopes(root: string, stateDir: string): MigrationRecord {
132
- const marker = readJson<MigrationRecord>(recordPath(root))
133
- if (marker?.version === 1 && marker.status === 'complete') return marker
134
-
135
- if (marker?.version === 1 && marker.status === 'attachments-written') {
136
- stripScopes(stateDir)
137
- const complete = { ...marker, status: 'complete' as const }
138
- writeJson(recordPath(root), complete)
139
- return complete
140
- }
141
-
142
- const connectionsFile = connectionPath(stateDir)
143
- const hadConnections = existsSync(connectionsFile)
144
- const raw = hadConnections ? readJson<unknown>(connectionsFile) : []
145
- if (!Array.isArray(raw)) throw new Error('Stored connector data must be a list before its scopes can be migrated.')
146
- const parsed = raw.map((item) => {
147
- const result = connectionSchema.safeParse(item)
148
- if (!result.success) throw new Error('A stored connector record is invalid; no scope data was removed.')
149
- return result.data
150
- })
151
- const connectionBackup = hadConnections ? connectionsBackupPath(stateDir) : null
152
- const hadAttachments = existsSync(attachmentsPath(root))
153
- const attachmentBackup = hadAttachments ? attachmentsBackupPath(root) : null
154
- const migration: MigrationRecord = {
155
- version: 1,
156
- status: 'attachments-written',
157
- connectionCount: parsed.length,
158
- scopeAssignmentCount: parsed.reduce((count, connection) => count + assignmentCount(scopeRows(connection)), 0),
159
- connectionsBackup: connectionBackup,
160
- attachmentsBackup: attachmentBackup,
161
- hadAttachments
162
- }
163
- backup(connectionsFile, connectionBackup ?? '')
164
- backup(attachmentsPath(root), attachmentBackup ?? '')
165
-
166
- try {
167
- const choices = attachments.load(root)
168
- const expected = new Map<string, ScopeRows>()
169
- for (const connection of parsed) {
170
- const id = connectionCapabilityId(connection.id)
171
- const rows = scopeRows(connection)
172
- expected.set(id, rows)
173
- writeRows(choices, id, rows)
174
- }
175
- const migratedAssignments = [...expected.values()].reduce((count, rows) => count + assignmentCount(rows), 0)
176
- if (migratedAssignments !== migration.scopeAssignmentCount || [...expected].some(([id, rows]) => !verifyRows(choices, id, rows))) {
177
- throw new Error('Connector scope count check failed; the original files were restored.')
178
- }
179
- attachments.save(root, choices)
180
- const saved = attachments.load(root)
181
- if ([...expected].some(([id, rows]) => !verifyRows(saved, id, rows))) throw new Error('Connector scope count check failed after saving; the original files were restored.')
182
- writeJson(recordPath(root), migration)
183
- stripScopes(stateDir)
184
- const complete = { ...migration, status: 'complete' as const }
185
- writeJson(recordPath(root), complete)
186
- return complete
187
- } catch (error) {
188
- if (attachmentBackup && existsSync(attachmentBackup)) atomicWrite(attachmentsPath(root), readFileSync(attachmentBackup))
189
- else if (!hadAttachments && existsSync(attachmentsPath(root))) unlinkSync(attachmentsPath(root))
190
- if (connectionBackup && existsSync(connectionBackup)) atomicWrite(connectionsFile, readFileSync(connectionBackup))
191
- try { unlinkSync(recordPath(root)) } catch { /* No marker is also a valid retry state. */ }
192
- throw error
193
- }
194
- }
195
-
196
- /** Restores the byte-identical pre-migration files from the backups if an operator rolls back. */
197
- export function rollbackConnectionScopeMigration(root: string, stateDir: string): void {
198
- const marker = readJson<MigrationRecord>(recordPath(root))
199
- if (!marker || marker.version !== 1) return
200
- if (marker.attachmentsBackup && existsSync(marker.attachmentsBackup)) atomicWrite(attachmentsPath(root), readFileSync(marker.attachmentsBackup))
201
- else if (!marker.hadAttachments && existsSync(attachmentsPath(root))) unlinkSync(attachmentsPath(root))
202
- if (marker.connectionsBackup && existsSync(marker.connectionsBackup)) atomicWrite(connectionPath(stateDir), readFileSync(marker.connectionsBackup))
203
- unlinkSync(recordPath(root))
204
- }