@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,376 +0,0 @@
1
- import { createServer } from 'node:http'
2
- import type { AddressInfo } from 'node:net'
3
- import { mkdtempSync } from 'node:fs'
4
- import { tmpdir } from 'node:os'
5
- import { dirname, join } from 'node:path'
6
- import { fileURLToPath } from 'node:url'
7
- import { McpServer, WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server'
8
- import { afterEach, describe, expect, it } from 'vitest'
9
-
10
- import { memorySecretStore } from '../accounts/secrets'
11
- import { createHarness, type Harness } from '../harness'
12
- import type { RunEvent } from '../sessions/contracts'
13
- import type { ToolPolicy } from '../sessions/policy'
14
- import type { PiSessionLike } from '../sessions/runner'
15
- import { allowed, redactJsonField, scrubSensitive, scrubWith, setAgentScope, validateScopeIds, webUrl } from './connections'
16
- import type { BrokerSession } from './service'
17
- import { compactTools, pageTools } from './service'
18
- import { connectionSchema, type Connection } from './types'
19
-
20
- const fixture = join(dirname(fileURLToPath(import.meta.url)), '../../tests/mcp-fixture.mjs')
21
- const connection = (fields: Partial<Connection>): Connection => connectionSchema.parse(fields)
22
- const scope = { agentId: 'agent-test', projectId: 'project-test' }
23
-
24
- describe('who may reach a connection', () => {
25
- it('global access applies to future agents and honors overrides', () => {
26
- const item = connection({ enabled: true, global: true })
27
- expect(allowed(item, scope)).toBe(true)
28
- expect(allowed({ ...item, excludedAgentIds: ['agent-test'] }, scope)).toBe(false)
29
- expect(allowed({ ...item, excludedProjectIds: ['project-test'] }, scope)).toBe(false)
30
- expect(allowed({ ...item, enabled: false }, scope)).toBe(false)
31
- })
32
-
33
- it('local access requires an explicit agent or project', () => {
34
- const item = connection({ enabled: true })
35
- expect(allowed(item, scope)).toBe(false)
36
- expect(allowed({ ...item, agentIds: ['agent-test'] }, scope)).toBe(true)
37
- expect(allowed({ ...item, projectIds: ['project-test'] }, scope)).toBe(true)
38
- })
39
-
40
- it('giving an agent its connections is exact and preserves other scopes', () => {
41
- const creator = { agentId: 'creator' }
42
- const all = [
43
- connection({ id: 'global', name: 'Global', enabled: true, global: true, agentIds: ['existing'] }),
44
- connection({ id: 'scoped', name: 'Scoped', enabled: true, agentIds: ['creator', 'existing'] }),
45
- connection({ id: 'private', name: 'Private', enabled: true, agentIds: ['existing'] })
46
- ]
47
- expect(() => validateScopeIds(all, creator, ['scoped'])).not.toThrow()
48
- expect(() => validateScopeIds(all, creator, ['private'])).toThrow('outside your connection scope')
49
- expect(() => validateScopeIds(all, creator, ['missing'])).toThrow()
50
- setAgentScope(all, 'helper', ['scoped'])
51
- const helper = { agentId: 'helper' }
52
- expect(all.map((item) => allowed(item, helper))).toEqual([false, true, false])
53
- expect(all.every((item) => item.agentIds.includes('existing'))).toBe(true)
54
- expect([allowed(all[0], creator), allowed(all[1], creator)]).toEqual([true, true])
55
- all[1].enabled = false
56
- expect(() => validateScopeIds(all, creator, ['scoped'])).toThrow()
57
- setAgentScope(all, 'helper', [])
58
- expect(all.some((item) => allowed(item, helper))).toBe(false)
59
- })
60
-
61
- it('remote servers and sign-in pages must use TLS unless local', () => {
62
- for (const accepted of ['https://mcp.linear.app/mcp', 'http://127.0.0.1:8080/mcp', 'http://localhost:8080/mcp']) expect(webUrl(accepted)).not.toBeNull()
63
- for (const rejected of ['http://mcp.example.com/mcp', 'file:///etc/passwd', 'javascript:alert(1)', 'mcp.linear.app']) expect(webUrl(rejected)).toBeNull()
64
- })
65
-
66
- it('connections saved before remote servers still load', () => {
67
- const saved = connection(JSON.parse('{"id":"old","name":"Old","kind":"local","command":"server","args":[],"envKeys":["KEY"],"enabled":true}'))
68
- expect([saved.url, saved.authState, saved.catalogId, saved.headerKeys.length, saved.auth, saved.envKeys]).toEqual([null, null, null, 0, '', ['KEY']])
69
- })
70
- })
71
-
72
- describe('what is never persisted', () => {
73
- it('drops tokens and stored secrets, including from JSON carried as text', () => {
74
- const result = JSON.stringify(scrubWith({ structuredContent: { approvalToken: 'preview-secret', data: 'fixture-secret' }, content: [{ text: '{"approvalToken":"preview-secret","data":"fixture-secret"}' }] }, ['fixture-secret']))
75
- expect(result).not.toContain('preview-secret')
76
- expect(result).not.toContain('fixture-secret')
77
- expect(result).toContain('[redacted]')
78
- expect(JSON.stringify(scrubWith('{"approvalToken":"truncated-preview', []))).not.toContain('truncated-preview')
79
- const evidence = JSON.stringify(scrubSensitive({ apiKey: 'top-secret', Authorization: 'Bearer private', nested: { password: 'not saved', query: 'keep this' } }))
80
- for (const leaked of ['top-secret', 'private', 'not saved']) expect(evidence).not.toContain(leaked)
81
- expect(evidence).toContain('keep this')
82
- expect(JSON.stringify(scrubSensitive('{"password":"cut-off-secret'))).not.toContain('cut-off-secret')
83
- expect(redactJsonField('{"token" : "abc", "other": "token"}', 'token')).toBe('{"token" : "[redacted]", "other": "token"}')
84
- })
85
-
86
- it('lists tools as names and summaries, a page at a time', () => {
87
- const tools = Array.from({ length: 45 }, (_, index) => ({ name: `tool_${index}`, description: index === 3 ? 'x'.repeat(300) : `Tool ${index}`, inputSchema: { type: 'object' } }))
88
- expect(compactTools(tools, 'tool_3')).toEqual([tools[3]])
89
- const page = pageTools(tools)
90
- expect([page.tools.length, page.total, page.more, page.nextOffset]).toEqual([40, 45, 5, 40])
91
- expect(page.tools[0]).not.toHaveProperty('inputSchema')
92
- expect((page.tools[3].description ?? '').length).toBeLessThanOrEqual(161)
93
- expect(pageTools(tools, { query: 'TOOL_44' }).tools.map((tool) => tool.name)).toEqual(['tool_44'])
94
- })
95
- })
96
-
97
- // ---- A real server, a real run -------------------------------------------------------------
98
-
99
- const open: Harness[] = []
100
- const servers: Array<() => void> = []
101
- afterEach(async () => {
102
- for (const harness of open.splice(0)) await harness.close()
103
- for (const close of servers.splice(0)) close()
104
- })
105
-
106
- const tick = (ms = 30) => new Promise((resolve) => setTimeout(resolve, ms))
107
-
108
- /** A harness with one live run whose session keeps going until the test releases it. */
109
- async function live(policy: ToolPolicy = {}) {
110
- let release: () => void = () => undefined
111
- const stateDir = mkdtempSync(join(tmpdir(), 'harness-mcp-state-'))
112
- const secrets = memorySecretStore()
113
- const session: PiSessionLike = { sessionId: 'native', subscribe: () => () => undefined, prompt: () => new Promise<void>((resolve) => (release = resolve)), sendCustomMessage: async () => undefined, abort: async () => release(), dispose: () => undefined }
114
- const harness = createHarness({ dataRoot: mkdtempSync(join(tmpdir(), 'harness-mcp-data-')), stateDir, secrets, policy, sessionFactory: async () => session })
115
- open.push(harness)
116
- harness.accounts.create('Main', 'apiKey')
117
- const events: RunEvent[] = []
118
- harness.runs.listen((event) => void events.push(event))
119
- await harness.sessions.run({ run: { id: 'run-1', sessionId: 'session-1' }, cwd: harness.env.root, sessionDir: join(harness.env.root, 'history'), text: 'go', caller: { agentId: 'agent-1', actor: 'Chat' }, tools: { allow: [] } })
120
- const granted: BrokerSession = harness.apps.grant({ sessionId: 'session-1', runId: 'run-1', caller: { agentId: 'agent-1', actor: 'Chat' }, readOnly: false, depth: 0 })
121
- return { harness, events, granted, secrets, release: () => release() }
122
- }
123
-
124
- const local = { name: 'Fixture', kind: 'local', command: process.execPath, args: [fixture], enabled: true, global: true, env: { MCP_FIXTURE_VALUE: 'personal task outside repo' } }
125
-
126
- describe('connected apps for a session', () => {
127
- it('discovers and calls a real stdio server, asking before a change and recording a redacted trace', async () => {
128
- const { harness, events, granted, secrets } = await live()
129
- const saved = await harness.apps.save({ ...local, readTools: ['read_record'] })
130
- expect(saved.envKeys).toEqual(['MCP_FIXTURE_VALUE'])
131
- expect(JSON.stringify(harness.apps.connections.list())).not.toContain('personal task')
132
- expect([...secrets.values.keys()]).toEqual([`mcp--${saved.id}/MCP_FIXTURE_VALUE`])
133
-
134
- const tested = await harness.apps.test(saved.id)
135
- expect([tested.serverName, tested.error, tested.tools.length]).toEqual(['fixture', null, 2])
136
-
137
- const listed = await harness.apps.list(granted)
138
- expect(listed.errors).toEqual([])
139
- const read = listed.tools.find((tool) => tool.tool === 'read_record')!
140
- expect(read.name).toMatch(/^mcp_[0-9a-f]{12}_read_record$/)
141
- // A read runs without asking; its result is stored with the connection's secret value removed.
142
- expect(await harness.apps.invoke(granted, read.name, {})).toMatchObject({ content: [{ type: 'text', text: 'personal task outside repo' }] })
143
- const trace = harness.apps.runContext('run-1')
144
- expect(trace).toHaveLength(1)
145
- expect(trace[0]).toMatchObject({ connectionName: 'Fixture', tool: 'read_record', ok: true })
146
- expect(trace[0].result).toContain('[redacted]')
147
- expect(trace[0].result).not.toContain('personal task')
148
- expect(events.filter((event) => event.type === 'approval.requested')).toHaveLength(0)
149
-
150
- // A change waits for a person, and does not run when they say no.
151
- const change = listed.tools.find((tool) => tool.tool === 'change_record')!
152
- const denied = harness.apps.invoke(granted, change.name, {})
153
- await tick(200)
154
- const request = events.find((event) => event.type === 'approval.requested')!.payload as { approvalId: string; target: string; action: string }
155
- expect(request.approvalId.startsWith('mcp-')).toBe(true)
156
- expect([request.target, request.action]).toEqual(['Fixture', 'change_record\n{}'])
157
- harness.runs.resolveApproval('run-1', request.approvalId, 'denied')
158
- await expect(denied).rejects.toMatchObject({ code: 'mcp_denied' })
159
- expect(harness.apps.runContext('run-1')).toHaveLength(1)
160
-
161
- // "Always allow" for one tool keeps the connection as it was tested.
162
- expect(harness.apps.connections.allowTool(saved.id, 'change_record').readTools).toEqual(['read_record', 'change_record'])
163
- expect(await harness.apps.invoke(granted, change.name, {})).toMatchObject({ content: [{ type: 'text', text: 'changed' }] })
164
- expect(harness.apps.connections.find(saved.id).checkedAt).toBe(tested.checkedAt)
165
- })
166
-
167
- it('offers the two broker tools and the application\'s own tools through them', async () => {
168
- const { harness, granted } = await live()
169
- harness.apps.expose({ list: async () => [{ name: 'get_capabilities', description: 'What you can do', inputSchema: { type: 'object' } }], has: (name) => name === 'get_capabilities', call: async () => ({ tools: ['a'] }) })
170
- const [list, call] = harness.apps.brokerTools(granted)
171
- expect([list.name, call.name]).toEqual(['mcp_list_tools', 'mcp_call_tool'])
172
- const listed = JSON.parse((await list.execute({})) as string)
173
- expect(listed.tools).toEqual([{ name: 'get_capabilities', description: 'What you can do', origin: 'app', connectionId: '__app__', tool: 'get_capabilities' }])
174
- expect(listed.note).toContain('Names and summaries only')
175
- expect(JSON.parse((await list.execute({ tool: 'get_capabilities' })) as string).tools[0].inputSchema).toEqual({ type: 'object' })
176
- expect(JSON.parse((await call.execute({ name: 'get_capabilities', arguments: {} })) as string)).toEqual({ content: [{ type: 'text', text: '{"tools":["a"]}' }], structuredContent: { tools: ['a'] } })
177
- })
178
-
179
- it('reports an unavailable executable without exposing diagnostics, and marks the connection', async () => {
180
- const { harness, granted } = await live()
181
- const saved = await harness.apps.save({ ...local, command: '/missing/mcp-fixture' })
182
- const result = await harness.apps.list(granted)
183
- expect(result.tools).toEqual([])
184
- expect(result.errors[0].message).toContain('Capability → Connectors')
185
- expect(harness.apps.connections.find(saved.id).error).toContain('executable and arguments')
186
- })
187
-
188
- it('lets the application narrow what a session reaches, and nothing is reachable once the run ends', async () => {
189
- let allow = true
190
- const { harness, granted, release } = await live({ connections: async ({ connectionIds }) => (allow ? connectionIds : []) })
191
- await harness.apps.save({ ...local, readTools: ['read_record'] })
192
- expect((await harness.apps.list(granted)).tools).toHaveLength(2)
193
- allow = false
194
- expect((await harness.apps.list(granted)).tools).toEqual([])
195
- allow = true
196
- const read = (await harness.apps.list(granted)).tools.find((tool) => tool.tool === 'read_record')!
197
- release()
198
- await tick()
199
- expect(() => harness.apps.session(granted.token)).toThrow('no longer authorized')
200
- await expect(harness.apps.invoke(granted, read.name, {})).rejects.toMatchObject({ code: 'run_not_active' })
201
- })
202
-
203
- it('a read-only session may only read', async () => {
204
- const { harness } = await live()
205
- await harness.apps.save({ ...local, readTools: ['read_record'] })
206
- const readOnly = harness.apps.grant({ sessionId: 'session-1', runId: 'run-1', caller: { agentId: 'agent-1', actor: 'Chat' }, readOnly: true, depth: 0 })
207
- const tools = (await harness.apps.list(readOnly)).tools
208
- await expect(harness.apps.invoke(readOnly, tools.find((tool) => tool.tool === 'change_record')!.name, {})).rejects.toMatchObject({ code: 'mcp_read_only' })
209
- expect(await harness.apps.invoke(readOnly, tools.find((tool) => tool.tool === 'read_record')!.name, {})).toMatchObject({ content: [{ type: 'text' }] })
210
- })
211
- })
212
-
213
- /** A stateless Streamable HTTP server; `status` makes it refuse every request instead. */
214
- async function remoteFixture(status?: number) {
215
- const requests: Array<Record<string, unknown>> = []
216
- const server = createServer(async (request, response) => {
217
- requests.push(request.headers)
218
- if (status || request.method !== 'POST') return void response.writeHead(status ?? 405).end()
219
- const chunks: Buffer[] = []
220
- for await (const chunk of request) chunks.push(chunk as Buffer)
221
- const mcp = new McpServer({ name: 'remote-fixture', version: '1' })
222
- mcp.registerTool('read_record', { description: 'Read remote record' }, async () => ({ content: [{ type: 'text', text: 'remote record' }] }))
223
- const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true })
224
- await mcp.connect(transport)
225
- const reply = await transport.handleRequest(new Request(`http://127.0.0.1${request.url}`, { method: 'POST', headers: request.headers as Record<string, string>, body: Buffer.concat(chunks) }))
226
- response.writeHead(reply.status, Object.fromEntries(reply.headers)).end(Buffer.from(await reply.arrayBuffer()))
227
- })
228
- await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve))
229
- servers.push(() => {
230
- server.close()
231
- server.closeAllConnections()
232
- })
233
- return { url: `http://127.0.0.1:${(server.address() as AddressInfo).port}/mcp`, requests }
234
- }
235
-
236
- describe('remote connected apps', () => {
237
- const remote = { name: 'Remote', kind: 'remote', enabled: true, global: true, readTools: ['read_record'] }
238
-
239
- it('reaches a Streamable HTTP server with its saved headers, which stay out of the file', async () => {
240
- const server = await remoteFixture()
241
- const { harness, granted } = await live()
242
- const saved = await harness.apps.save({ ...remote, url: server.url, auth: 'headers', headers: { 'X-Api-Key': 'fixture-key' } })
243
- expect([saved.headerKeys, saved.command, saved.authState]).toEqual([['X-Api-Key'], '', null])
244
- const read = (await harness.apps.list(granted)).tools.find((tool) => tool.tool === 'read_record')!
245
- expect(await harness.apps.invoke(granted, read.name, {})).toMatchObject({ content: [{ type: 'text', text: 'remote record' }] })
246
- expect(server.requests.every((headers) => headers['x-api-key'] === 'fixture-key')).toBe(true)
247
- expect(JSON.stringify(harness.apps.connections.list())).not.toContain('fixture-key')
248
- })
249
-
250
- it('reports an unreachable server without naming its credentials', async () => {
251
- const server = await remoteFixture(500)
252
- const { harness, granted } = await live()
253
- const saved = await harness.apps.save({ ...remote, url: server.url, auth: 'headers', headers: { Authorization: 'Bearer fixture-key' } })
254
- const result = await harness.apps.list(granted)
255
- expect(result.tools).toEqual([])
256
- expect(JSON.stringify(result)).not.toContain('fixture-key')
257
- expect(harness.apps.connections.find(saved.id).error).toContain('address and sign-in')
258
- })
259
-
260
- it('asks for sign-in instead of contacting an OAuth server without saved tokens, and never opens a browser from a run', async () => {
261
- const server = await remoteFixture()
262
- const { harness, granted } = await live()
263
- const opened: unknown[] = []
264
- harness.bus.on((notice) => void (notice.type === 'connections.openUrl' && opened.push(notice)))
265
- const saved = await harness.apps.save({ ...remote, url: server.url, auth: 'oauth' })
266
- expect(saved.authState).toBe('signed_out')
267
- const result = await harness.apps.list(granted)
268
- expect(result.errors[0].message).toContain('sign in again')
269
- expect(server.requests).toEqual([])
270
- expect(opened).toEqual([])
271
- expect(harness.apps.connections.find(saved.id).authState).toBe('expired')
272
- })
273
-
274
- it('rejects what a connection must not be', async () => {
275
- const { harness } = await live()
276
- await expect(harness.apps.save({ ...remote, url: 'http://mcp.example.com/mcp', auth: 'none' })).rejects.toThrow('https://')
277
- await expect(harness.apps.save({ name: '', kind: 'local', command: 'x' })).rejects.toThrow('A name, executable')
278
- await expect(harness.apps.save({ ...local, env: { 'BAD NAME': 'x' } })).rejects.toThrow('environment variable')
279
- await expect(harness.apps.save({ ...remote, url: 'https://x.example/mcp', auth: 'headers', headers: { 'X-Key': 'a\nb' } })).rejects.toThrow('header')
280
- const workspace = await harness.apps.save({ name: 'Xingular Workspace', kind: 'workspace', command: process.execPath, enabled: true, global: true })
281
- expect(() => harness.apps.connections.allowTool(workspace.id, 'x_workspace_mutation_apply')).toThrow('one at a time')
282
- await harness.apps.remove(workspace.id)
283
- expect(harness.apps.connections.list()).toEqual([])
284
- })
285
- })
286
-
287
- /** A protected MCP server together with its authorization server, as hosted providers run them. */
288
- async function oauthFixture() {
289
- const seen = { registered: 0, tokenRequests: [] as string[], authorizeUrls: [] as URL[] }
290
- const server = createServer(async (request, response) => {
291
- const base = `http://127.0.0.1:${(server.address() as AddressInfo).port}`
292
- const url = new URL(request.url ?? '/', base)
293
- const chunks: Buffer[] = []
294
- for await (const chunk of request) chunks.push(chunk as Buffer)
295
- const body = Buffer.concat(chunks)
296
- const json = (status: number, value: unknown) => response.writeHead(status, { 'content-type': 'application/json' }).end(JSON.stringify(value))
297
- if (url.pathname.startsWith('/.well-known/oauth-protected-resource')) return json(200, { resource: `${base}/mcp`, authorization_servers: [base] })
298
- if (url.pathname.startsWith('/.well-known/oauth-authorization-server')) return json(200, { issuer: base, authorization_endpoint: `${base}/authorize`, token_endpoint: `${base}/token`, registration_endpoint: `${base}/register`, response_types_supported: ['code'], grant_types_supported: ['authorization_code', 'refresh_token'], code_challenge_methods_supported: ['S256'], token_endpoint_auth_methods_supported: ['none', 'client_secret_post', 'client_secret_basic'] })
299
- if (url.pathname === '/register') {
300
- seen.registered += 1
301
- return json(201, { ...JSON.parse(body.toString()), client_id: 'registered-client' })
302
- }
303
- if (url.pathname === '/authorize') {
304
- seen.authorizeUrls.push(url)
305
- return response.writeHead(302, { location: `${url.searchParams.get('redirect_uri')}?code=fixture-code&state=${url.searchParams.get('state')}` }).end()
306
- }
307
- if (url.pathname === '/token') {
308
- seen.tokenRequests.push(`${request.headers.authorization ?? ''} ${body.toString()}`)
309
- return json(200, { access_token: 'fixture-access', token_type: 'Bearer', expires_in: 3600, refresh_token: 'fixture-refresh' })
310
- }
311
- if (url.pathname !== '/mcp' || request.method !== 'POST') return response.writeHead(404).end()
312
- if (request.headers.authorization !== 'Bearer fixture-access') return response.writeHead(401, { 'www-authenticate': `Bearer resource_metadata="${base}/.well-known/oauth-protected-resource"` }).end()
313
- const mcp = new McpServer({ name: 'oauth-fixture', version: '1' })
314
- mcp.registerTool('read_record', { description: 'Read protected record' }, async () => ({ content: [{ type: 'text', text: 'protected record' }] }))
315
- const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true })
316
- await mcp.connect(transport)
317
- const reply = await transport.handleRequest(new Request(`${base}/mcp`, { method: 'POST', headers: request.headers as Record<string, string>, body }))
318
- response.writeHead(reply.status, Object.fromEntries(reply.headers)).end(Buffer.from(await reply.arrayBuffer()))
319
- })
320
- await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve))
321
- servers.push(() => {
322
- server.close()
323
- server.closeAllConnections()
324
- })
325
- return { url: `http://127.0.0.1:${(server.address() as AddressInfo).port}/mcp`, seen }
326
- }
327
-
328
- describe('signing in to a remote connected app', () => {
329
- it('signs in through the browser with dynamic registration, then a session uses the saved tokens', async () => {
330
- const server = await oauthFixture()
331
- const { harness, granted, secrets } = await live()
332
- let opened = 0
333
- // Stands in for the application: a browser that approves at once.
334
- harness.bus.on((notice) => {
335
- if (notice.type !== 'connections.openUrl') return
336
- opened += 1
337
- void fetch(String(notice.url))
338
- })
339
- const saved = await harness.apps.save({ name: 'OAuth', kind: 'remote', enabled: true, global: true, url: server.url, auth: 'oauth', oauthScopes: ['read'], readTools: ['read_record'] })
340
- expect((await harness.apps.signIn(saved.id)).authState).toBe('signed_in')
341
- expect(JSON.parse(secrets.values.get(`mcp--${saved.id}/oauth`)!).tokens).toMatchObject({ access_token: 'fixture-access', refresh_token: 'fixture-refresh' })
342
- expect(server.seen.registered).toBe(1)
343
- expect(server.seen.authorizeUrls[0].searchParams.get('scope')).toBe('read')
344
- expect(server.seen.authorizeUrls[0].searchParams.get('code_challenge_method')).toBe('S256')
345
- const listed = await harness.apps.list(granted)
346
- expect(listed.errors).toEqual([])
347
- const read = listed.tools.find((tool) => tool.tool === 'read_record')!
348
- await harness.apps.invoke(granted, read.name, {})
349
- expect(opened).toBe(1)
350
- // The tokens a result might quote are removed from what is stored.
351
- expect(harness.apps.connections.scrub({ content: [{ text: 'fixture-access fixture-refresh kept' }] }, saved.id)).toEqual({ content: [{ text: '[redacted] [redacted] kept' }] })
352
- expect((await harness.apps.signOut(saved.id)).authState).toBe('signed_out')
353
- expect(secrets.values.has(`mcp--${saved.id}/oauth`)).toBe(false)
354
- })
355
-
356
- it('uses a client the user registered, and ignores a callback that does not carry this sign-in\'s state', async () => {
357
- const server = await oauthFixture()
358
- const { harness } = await live()
359
- let forged = 0
360
- harness.bus.on((notice) => {
361
- if (notice.type !== 'connections.openUrl') return
362
- void (async () => {
363
- forged = (await fetch('http://127.0.0.1:47823/oauth/callback?code=stolen&state=wrong')).status
364
- await fetch(String(notice.url))
365
- })()
366
- })
367
- const saved = await harness.apps.save({ name: 'Own client', kind: 'remote', enabled: true, global: true, url: server.url, auth: 'oauth', oauthClient: 'user', oauthCredentials: { clientId: 'own-client', clientSecret: 'own-secret' } })
368
- await harness.apps.signIn(saved.id)
369
- expect(forged).toBe(400)
370
- expect(server.seen.registered).toBe(0)
371
- expect(server.seen.authorizeUrls[0].searchParams.get('client_id')).toBe('own-client')
372
- expect(server.seen.tokenRequests).toHaveLength(1)
373
- expect(server.seen.tokenRequests[0]).toContain('fixture-code')
374
- expect(server.seen.tokenRequests[0]).toMatch(/own-client|b3duLWNsaWVudDpvd24tc2VjcmV0/)
375
- })
376
- })