@xingular/harness 0.1.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (593) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +60 -0
  4. package/README.md +265 -71
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +14842 -9445
  7. package/dist/sdk/accounts/accounts.d.ts +165 -0
  8. package/dist/sdk/accounts/accounts.js +730 -0
  9. package/dist/sdk/accounts/choices.d.ts +23 -0
  10. package/dist/sdk/accounts/choices.js +62 -0
  11. package/dist/sdk/accounts/env.d.ts +78 -0
  12. package/dist/sdk/accounts/env.js +294 -0
  13. package/dist/sdk/accounts/secrets.d.ts +16 -0
  14. package/dist/sdk/accounts/secrets.js +40 -0
  15. package/dist/sdk/accounts/store.d.ts +114 -0
  16. package/dist/sdk/accounts/store.js +255 -0
  17. package/dist/sdk/browser/config.d.ts +16 -0
  18. package/dist/sdk/browser/config.js +22 -0
  19. package/dist/sdk/browser/diagnostics.d.ts +4 -0
  20. package/dist/sdk/browser/diagnostics.js +38 -0
  21. package/dist/sdk/browser/index.d.ts +17 -0
  22. package/dist/sdk/browser/index.js +65 -0
  23. package/dist/sdk/browser/network.d.ts +10 -0
  24. package/dist/sdk/browser/network.js +59 -0
  25. package/dist/sdk/browser/session.d.ts +84 -0
  26. package/dist/sdk/browser/session.js +192 -0
  27. package/dist/sdk/browser/tools.d.ts +8 -0
  28. package/dist/sdk/browser/tools.js +329 -0
  29. package/dist/sdk/capabilities/api.d.ts +22 -0
  30. package/dist/sdk/capabilities/api.js +54 -0
  31. package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
  32. package/dist/sdk/capabilities/runSnapshot.js +47 -0
  33. package/dist/sdk/capabilities/types.d.ts +29 -0
  34. package/dist/sdk/capabilities/types.js +1 -0
  35. package/dist/sdk/cli.d.ts +2 -0
  36. package/dist/sdk/cli.js +142 -0
  37. package/dist/sdk/core/bus.d.ts +23 -0
  38. package/dist/sdk/core/bus.js +76 -0
  39. package/dist/sdk/core/caller.d.ts +22 -0
  40. package/dist/sdk/core/caller.js +16 -0
  41. package/dist/sdk/core/changes.d.ts +15 -0
  42. package/dist/sdk/core/changes.js +15 -0
  43. package/dist/sdk/core/effort.d.ts +2 -0
  44. package/dist/sdk/core/effort.js +1 -0
  45. package/dist/sdk/core/env.d.ts +18 -0
  46. package/dist/sdk/core/env.js +8 -0
  47. package/dist/sdk/core/errors.d.ts +15 -0
  48. package/dist/sdk/core/errors.js +24 -0
  49. package/dist/sdk/core/frontmatter.d.ts +12 -0
  50. package/dist/sdk/core/frontmatter.js +50 -0
  51. package/dist/sdk/core/fs.d.ts +18 -0
  52. package/dist/sdk/core/fs.js +106 -0
  53. package/dist/sdk/core/index.d.ts +24 -0
  54. package/dist/sdk/core/index.js +187 -0
  55. package/dist/sdk/core/path.d.ts +7 -0
  56. package/dist/sdk/core/path.js +79 -0
  57. package/dist/sdk/core/projects.d.ts +18 -0
  58. package/dist/sdk/core/projects.js +67 -0
  59. package/dist/sdk/core/secrets.d.ts +2 -0
  60. package/dist/sdk/core/secrets.js +5 -0
  61. package/dist/sdk/core/text.d.ts +7 -0
  62. package/dist/sdk/core/text.js +40 -0
  63. package/dist/sdk/doctor/checks.d.ts +5 -0
  64. package/dist/sdk/doctor/checks.js +208 -0
  65. package/dist/sdk/doctor/probe.d.ts +4 -0
  66. package/dist/sdk/doctor/probe.js +92 -0
  67. package/dist/sdk/doctor/service.d.ts +23 -0
  68. package/dist/sdk/doctor/service.js +144 -0
  69. package/dist/sdk/doctor/types.d.ts +141 -0
  70. package/dist/sdk/doctor/types.js +29 -0
  71. package/dist/sdk/harness.d.ts +133 -0
  72. package/dist/sdk/harness.js +299 -0
  73. package/dist/sdk/history/lessonPrompt.d.ts +2 -0
  74. package/dist/sdk/history/lessonPrompt.js +15 -0
  75. package/dist/sdk/history/lessons.d.ts +52 -0
  76. package/dist/sdk/history/lessons.js +173 -0
  77. package/dist/sdk/history/recall.d.ts +68 -0
  78. package/dist/sdk/history/recall.js +199 -0
  79. package/dist/sdk/history/trajectory.d.ts +7 -0
  80. package/dist/sdk/history/trajectory.js +216 -0
  81. package/dist/sdk/hub/catalog.json +123 -0
  82. package/dist/sdk/hub/cli.d.ts +7 -0
  83. package/dist/sdk/hub/cli.js +81 -0
  84. package/dist/sdk/hub/hub.d.ts +74 -0
  85. package/dist/sdk/hub/hub.js +474 -0
  86. package/dist/sdk/hub/schema.d.ts +280 -0
  87. package/dist/sdk/hub/schema.js +78 -0
  88. package/dist/sdk/index.d.ts +63 -0
  89. package/dist/sdk/index.js +48 -0
  90. package/dist/sdk/mcp/connections.d.ts +83 -0
  91. package/dist/sdk/mcp/connections.js +669 -0
  92. package/dist/sdk/mcp/manager.d.ts +26 -0
  93. package/dist/sdk/mcp/manager.js +124 -0
  94. package/dist/sdk/mcp/oauth.d.ts +35 -0
  95. package/dist/sdk/mcp/oauth.js +171 -0
  96. package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
  97. package/dist/sdk/mcp/scopeMigration.js +198 -0
  98. package/dist/sdk/mcp/service.d.ts +160 -0
  99. package/dist/sdk/mcp/service.js +510 -0
  100. package/dist/sdk/mcp/types.d.ts +131 -0
  101. package/dist/sdk/mcp/types.js +49 -0
  102. package/dist/sdk/pi/runtime.d.ts +13 -0
  103. package/dist/sdk/pi/runtime.js +31 -0
  104. package/dist/sdk/plugins/api.d.ts +66 -0
  105. package/dist/sdk/plugins/api.js +155 -0
  106. package/dist/sdk/plugins/attachments.d.ts +46 -0
  107. package/dist/sdk/plugins/attachments.js +111 -0
  108. package/dist/sdk/plugins/builtin.d.ts +6 -0
  109. package/dist/sdk/plugins/builtin.js +68 -0
  110. package/dist/sdk/plugins/catalogue.d.ts +29 -0
  111. package/dist/sdk/plugins/catalogue.js +196 -0
  112. package/dist/sdk/plugins/cli.d.ts +13 -0
  113. package/dist/sdk/plugins/cli.js +187 -0
  114. package/dist/sdk/plugins/discover.d.ts +42 -0
  115. package/dist/sdk/plugins/discover.js +115 -0
  116. package/dist/sdk/plugins/firstParty.d.ts +50 -0
  117. package/dist/sdk/plugins/firstParty.js +113 -0
  118. package/dist/sdk/plugins/hooks.d.ts +94 -0
  119. package/dist/sdk/plugins/hooks.js +162 -0
  120. package/dist/sdk/plugins/identity.d.ts +19 -0
  121. package/dist/sdk/plugins/identity.js +48 -0
  122. package/dist/sdk/plugins/install.d.ts +20 -0
  123. package/dist/sdk/plugins/install.js +110 -0
  124. package/dist/sdk/plugins/inventory.d.ts +22 -0
  125. package/dist/sdk/plugins/inventory.js +110 -0
  126. package/dist/sdk/plugins/manifest.d.ts +13 -0
  127. package/dist/sdk/plugins/manifest.js +56 -0
  128. package/dist/sdk/plugins/plugins.d.ts +104 -0
  129. package/dist/sdk/plugins/plugins.js +164 -0
  130. package/dist/sdk/plugins/runtime.d.ts +9 -0
  131. package/dist/sdk/plugins/runtime.js +95 -0
  132. package/dist/sdk/plugins/trust.d.ts +44 -0
  133. package/dist/sdk/plugins/trust.js +120 -0
  134. package/dist/sdk/plugins/types.d.ts +159 -0
  135. package/dist/sdk/plugins/types.js +7 -0
  136. package/dist/sdk/prompt/compile.d.ts +174 -0
  137. package/dist/sdk/prompt/compile.js +396 -0
  138. package/dist/sdk/refine/cli.d.ts +4 -0
  139. package/dist/sdk/refine/cli.js +186 -0
  140. package/dist/sdk/refine/demo.d.ts +21 -0
  141. package/dist/sdk/refine/demo.js +114 -0
  142. package/dist/sdk/refine/evidence.d.ts +55 -0
  143. package/dist/sdk/refine/evidence.js +330 -0
  144. package/dist/sdk/refine/host.d.ts +51 -0
  145. package/dist/sdk/refine/host.js +76 -0
  146. package/dist/sdk/refine/ledger.d.ts +48 -0
  147. package/dist/sdk/refine/ledger.js +76 -0
  148. package/dist/sdk/refine/library.d.ts +55 -0
  149. package/dist/sdk/refine/library.js +177 -0
  150. package/dist/sdk/refine/pi.d.ts +72 -0
  151. package/dist/sdk/refine/pi.js +248 -0
  152. package/dist/sdk/refine/prompts.d.ts +45 -0
  153. package/dist/sdk/refine/prompts.js +390 -0
  154. package/dist/sdk/refine/recursion.d.ts +113 -0
  155. package/dist/sdk/refine/recursion.js +258 -0
  156. package/dist/sdk/refine/runner.d.ts +81 -0
  157. package/dist/sdk/refine/runner.js +150 -0
  158. package/dist/sdk/refine/selection.d.ts +57 -0
  159. package/dist/sdk/refine/selection.js +251 -0
  160. package/dist/sdk/refine/service.d.ts +84 -0
  161. package/dist/sdk/refine/service.js +165 -0
  162. package/dist/sdk/refine/suite.d.ts +67 -0
  163. package/dist/sdk/refine/suite.js +174 -0
  164. package/dist/sdk/refine/trajectory.d.ts +9 -0
  165. package/dist/sdk/refine/trajectory.js +68 -0
  166. package/dist/sdk/refine/types.d.ts +77 -0
  167. package/dist/sdk/refine/types.js +10 -0
  168. package/dist/sdk/server/methods.d.ts +3 -0
  169. package/dist/sdk/server/methods.js +370 -0
  170. package/dist/sdk/server/remote.d.ts +19 -0
  171. package/dist/sdk/server/remote.js +84 -0
  172. package/dist/sdk/server/rpc.d.ts +20 -0
  173. package/dist/sdk/server/rpc.js +102 -0
  174. package/dist/sdk/server/serve.d.ts +10 -0
  175. package/dist/sdk/server/serve.js +18 -0
  176. package/dist/sdk/sessions/approvals.d.ts +47 -0
  177. package/dist/sdk/sessions/approvals.js +119 -0
  178. package/dist/sdk/sessions/continuation.d.ts +48 -0
  179. package/dist/sdk/sessions/continuation.js +85 -0
  180. package/dist/sdk/sessions/contracts.d.ts +534 -0
  181. package/dist/sdk/sessions/contracts.js +299 -0
  182. package/dist/sdk/sessions/extensionUi.d.ts +19 -0
  183. package/dist/sdk/sessions/extensionUi.js +64 -0
  184. package/dist/sdk/sessions/history.d.ts +16 -0
  185. package/dist/sdk/sessions/history.js +68 -0
  186. package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
  187. package/dist/sdk/sessions/lineageJoin.js +61 -0
  188. package/dist/sdk/sessions/planMode.d.ts +36 -0
  189. package/dist/sdk/sessions/planMode.js +84 -0
  190. package/dist/sdk/sessions/policy.d.ts +43 -0
  191. package/dist/sdk/sessions/policy.js +1 -0
  192. package/dist/sdk/sessions/pricing.d.ts +34 -0
  193. package/dist/sdk/sessions/pricing.js +40 -0
  194. package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
  195. package/dist/sdk/sessions/reasoningSummaries.js +61 -0
  196. package/dist/sdk/sessions/registry.d.ts +102 -0
  197. package/dist/sdk/sessions/registry.js +383 -0
  198. package/dist/sdk/sessions/runIndex.d.ts +21 -0
  199. package/dist/sdk/sessions/runIndex.js +65 -0
  200. package/dist/sdk/sessions/runStore.d.ts +66 -0
  201. package/dist/sdk/sessions/runStore.js +335 -0
  202. package/dist/sdk/sessions/runner.d.ts +213 -0
  203. package/dist/sdk/sessions/runner.js +589 -0
  204. package/dist/sdk/sessions/sessions.d.ts +140 -0
  205. package/dist/sdk/sessions/sessions.js +394 -0
  206. package/dist/sdk/sessions/subagentService.d.ts +41 -0
  207. package/dist/sdk/sessions/subagentService.js +247 -0
  208. package/dist/sdk/sessions/subagents.d.ts +50 -0
  209. package/dist/sdk/sessions/subagents.js +68 -0
  210. package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
  211. package/dist/sdk/terminal/accountsMenu.js +392 -0
  212. package/dist/sdk/terminal/cli.d.ts +20 -0
  213. package/dist/sdk/terminal/cli.js +121 -0
  214. package/dist/sdk/terminal/client.d.ts +15 -0
  215. package/dist/sdk/terminal/client.js +126 -0
  216. package/dist/sdk/terminal/control.d.ts +4 -0
  217. package/dist/sdk/terminal/control.js +25 -0
  218. package/dist/sdk/terminal/controller.d.ts +72 -0
  219. package/dist/sdk/terminal/controller.js +351 -0
  220. package/dist/sdk/terminal/hubMenu.d.ts +10 -0
  221. package/dist/sdk/terminal/hubMenu.js +34 -0
  222. package/dist/sdk/terminal/launch.d.ts +5 -0
  223. package/dist/sdk/terminal/launch.js +27 -0
  224. package/dist/sdk/terminal/logs.d.ts +14 -0
  225. package/dist/sdk/terminal/logs.js +59 -0
  226. package/dist/sdk/terminal/piExtension.d.ts +6 -0
  227. package/dist/sdk/terminal/piExtension.js +392 -0
  228. package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
  229. package/dist/sdk/terminal/pluginMenu.js +101 -0
  230. package/dist/sdk/terminal/socket.d.ts +70 -0
  231. package/dist/sdk/terminal/socket.js +256 -0
  232. package/dist/sdk/terminal/standalone.d.ts +18 -0
  233. package/dist/sdk/terminal/standalone.js +146 -0
  234. package/dist/sdk/terminal/terminals.d.ts +176 -0
  235. package/dist/sdk/terminal/terminals.js +767 -0
  236. package/dist/sdk/terminal/trajectory.d.ts +10 -0
  237. package/dist/sdk/terminal/trajectory.js +30 -0
  238. package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
  239. package/dist/sdk/terminal/tui/chrome.js +169 -0
  240. package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
  241. package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
  242. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -0
  243. package/dist/sdk/terminal/tui/commandPages.js +63 -0
  244. package/dist/sdk/terminal/tui/commands.d.ts +42 -0
  245. package/dist/sdk/terminal/tui/commands.js +276 -0
  246. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
  247. package/dist/sdk/terminal/tui/dialogGeometry.js +50 -0
  248. package/dist/sdk/terminal/tui/dialogs.d.ts +75 -0
  249. package/dist/sdk/terminal/tui/dialogs.js +363 -0
  250. package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
  251. package/dist/sdk/terminal/tui/keybindings.js +49 -0
  252. package/dist/sdk/terminal/tui/list.d.ts +73 -0
  253. package/dist/sdk/terminal/tui/list.js +196 -0
  254. package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
  255. package/dist/sdk/terminal/tui/modeChoices.js +70 -0
  256. package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
  257. package/dist/sdk/terminal/tui/modelPicker.js +155 -0
  258. package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
  259. package/dist/sdk/terminal/tui/mouse.js +3 -0
  260. package/dist/sdk/terminal/tui/page.d.ts +14 -0
  261. package/dist/sdk/terminal/tui/page.js +1 -0
  262. package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
  263. package/dist/sdk/terminal/tui/pageOverlay.js +145 -0
  264. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +54 -0
  265. package/dist/sdk/terminal/tui/pages/accountsPage.js +181 -0
  266. package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
  267. package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
  268. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +37 -0
  269. package/dist/sdk/terminal/tui/pages/doctorPage.js +145 -0
  270. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
  271. package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
  272. package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
  273. package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
  274. package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
  275. package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
  276. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
  277. package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
  278. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +55 -0
  279. package/dist/sdk/terminal/tui/pages/settingsPage.js +88 -0
  280. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +58 -0
  281. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +377 -0
  282. package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
  283. package/dist/sdk/terminal/tui/piAdapter.js +48 -0
  284. package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
  285. package/dist/sdk/terminal/tui/planMode.js +2 -0
  286. package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
  287. package/dist/sdk/terminal/tui/questionPicker.js +150 -0
  288. package/dist/sdk/terminal/tui/questions.d.ts +19 -0
  289. package/dist/sdk/terminal/tui/questions.js +42 -0
  290. package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
  291. package/dist/sdk/terminal/tui/runtime.js +441 -0
  292. package/dist/sdk/terminal/tui/search.d.ts +22 -0
  293. package/dist/sdk/terminal/tui/search.js +60 -0
  294. package/dist/sdk/terminal/tui/selection.d.ts +16 -0
  295. package/dist/sdk/terminal/tui/selection.js +16 -0
  296. package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
  297. package/dist/sdk/terminal/tui/sessionUi.js +30 -0
  298. package/dist/sdk/terminal/tui/settingsModel.d.ts +12 -0
  299. package/dist/sdk/terminal/tui/settingsModel.js +84 -0
  300. package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
  301. package/dist/sdk/terminal/tui/sideQuestion.js +197 -0
  302. package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
  303. package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
  304. package/dist/sdk/terminal/tui/status.d.ts +18 -0
  305. package/dist/sdk/terminal/tui/status.js +67 -0
  306. package/dist/sdk/terminal/tui/theme.d.ts +45 -0
  307. package/dist/sdk/terminal/tui/theme.js +176 -0
  308. package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
  309. package/dist/sdk/terminal/tui/treeModel.js +483 -0
  310. package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
  311. package/dist/sdk/terminal/tui/treePicker.js +251 -0
  312. package/dist/sdk/terminal/tui/ui.d.ts +47 -0
  313. package/dist/sdk/terminal/tui/ui.js +148 -0
  314. package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
  315. package/dist/sdk/terminal/tui/workingStatus.js +229 -0
  316. package/dist/sdk/tools/askUser.d.ts +6 -0
  317. package/dist/sdk/tools/askUser.js +74 -0
  318. package/dist/sdk/tools/checklist.d.ts +9 -0
  319. package/dist/sdk/tools/checklist.js +54 -0
  320. package/dist/sdk/tools/definitions.d.ts +30 -0
  321. package/dist/sdk/tools/definitions.js +117 -0
  322. package/dist/sdk/tools/dispatch.d.ts +16 -0
  323. package/dist/sdk/tools/dispatch.js +67 -0
  324. package/dist/sdk/tools/harnessTools.d.ts +6 -0
  325. package/dist/sdk/tools/harnessTools.js +20 -0
  326. package/dist/sdk/tools/sessionName.d.ts +7 -0
  327. package/dist/sdk/tools/sessionName.js +31 -0
  328. package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
  329. package/dist/sdk/tools/spawnSubagent.js +49 -0
  330. package/dist/sdk/tools/types.d.ts +48 -0
  331. package/dist/sdk/tools/types.js +1 -0
  332. package/dist/sdk/variant/components.d.ts +34 -0
  333. package/dist/sdk/variant/components.js +230 -0
  334. package/dist/sdk/variant/materialise.d.ts +66 -0
  335. package/dist/sdk/variant/materialise.js +81 -0
  336. package/dist/sdk/variant/migrate.d.ts +4 -0
  337. package/dist/sdk/variant/migrate.js +41 -0
  338. package/dist/sdk/variant/seed.d.ts +20 -0
  339. package/dist/sdk/variant/seed.js +116 -0
  340. package/dist/sdk/variant/store.d.ts +82 -0
  341. package/dist/sdk/variant/store.js +151 -0
  342. package/dist/sdk/variant/surface.d.ts +56 -0
  343. package/dist/sdk/variant/surface.js +81 -0
  344. package/dist/sdk/variant/trust.d.ts +27 -0
  345. package/dist/sdk/variant/trust.js +64 -0
  346. package/dist/sdk/variant/variant.d.ts +71 -0
  347. package/dist/sdk/variant/variant.js +331 -0
  348. package/dist/sdk/web/markdown.d.ts +10 -0
  349. package/dist/sdk/web/markdown.js +66 -0
  350. package/dist/sdk/web/safeRequest.d.ts +34 -0
  351. package/dist/sdk/web/safeRequest.js +175 -0
  352. package/dist/sdk/web/search.d.ts +53 -0
  353. package/dist/sdk/web/search.js +168 -0
  354. package/dist/sdk/web/text.d.ts +2 -0
  355. package/dist/sdk/web/text.js +7 -0
  356. package/dist/sdk/web/tools.d.ts +22 -0
  357. package/dist/sdk/web/tools.js +195 -0
  358. package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
  359. package/dist/sdk/wiki/notes.d.ts +68 -0
  360. package/dist/sdk/wiki/notes.js +297 -0
  361. package/dist/sdk/world/actions.d.ts +23 -0
  362. package/dist/sdk/world/actions.js +31 -0
  363. package/dist/sdk/world/cli.d.ts +12 -0
  364. package/dist/sdk/world/cli.js +166 -0
  365. package/dist/sdk/world/images.d.ts +20 -0
  366. package/dist/sdk/world/images.js +48 -0
  367. package/dist/sdk/world/untrusted.d.ts +12 -0
  368. package/dist/sdk/world/untrusted.js +20 -0
  369. package/dist/sdk/world/world.d.ts +65 -0
  370. package/dist/sdk/world/world.js +80 -0
  371. package/dist/terminal-opentui.js +13612 -0
  372. package/dist/terminal-pi.js +1170 -62
  373. package/docs/README.md +34 -0
  374. package/docs/architecture/00-overview.md +159 -0
  375. package/docs/architecture/01-extension-points.md +78 -0
  376. package/docs/architecture/02-sessions-and-runs.md +146 -0
  377. package/docs/architecture/03-variants.md +95 -0
  378. package/docs/architecture/04-prompt.md +102 -0
  379. package/docs/architecture/05-refinement.md +107 -0
  380. package/docs/architecture/06-plugins-and-capabilities.md +93 -0
  381. package/docs/architecture/07-tools-and-gate.md +88 -0
  382. package/docs/architecture/08-memory-and-history.md +94 -0
  383. package/docs/architecture/09-accounts-and-connectors.md +90 -0
  384. package/docs/architecture/10-server-protocol.md +84 -0
  385. package/docs/architecture/11-terminal.md +81 -0
  386. package/docs/architecture/12-storage.md +61 -0
  387. package/docs/architecture/13-world-tools.md +23 -0
  388. package/docs/architecture/README.md +114 -0
  389. package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
  390. package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
  391. package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
  392. package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
  393. package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
  394. package/docs/architecture/proposals/PROP-0006-run-checklist.md +68 -0
  395. package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
  396. package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
  397. package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
  398. package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
  399. package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
  400. package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
  401. package/docs/architecture/proposals/README.md +76 -0
  402. package/docs/decisions/ADR-0001-owned-terminal.md +87 -0
  403. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  404. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  405. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  406. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  407. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  408. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  409. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  410. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  411. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  412. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  413. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  414. package/docs/decisions/ADR-0013-doctor.md +27 -0
  415. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  416. package/docs/doctor.md +74 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  418. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  420. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  421. package/docs/features/README.md +20 -0
  422. package/docs/features/automations/README.md +41 -0
  423. package/docs/features/cores/README.md +39 -0
  424. package/docs/features/google-harness2/README.md +52 -0
  425. package/docs/features/integrations/README.md +40 -0
  426. package/docs/features/interfaces/README.md +29 -0
  427. package/docs/features/memory/README.md +28 -0
  428. package/docs/releases/1.0.0.md +40 -0
  429. package/docs/releases/README.md +36 -0
  430. package/docs/study/00-index.md +78 -0
  431. package/docs/study/arms/00-matrix.md +20 -0
  432. package/docs/study/arms/01-system-prompt.md +211 -0
  433. package/docs/study/arms/02-tools.md +79 -0
  434. package/docs/study/arms/03-subagents.md +90 -0
  435. package/docs/study/arms/04-skills.md +75 -0
  436. package/docs/study/arms/05-context-management.md +90 -0
  437. package/docs/study/arms/06-memory.md +90 -0
  438. package/docs/study/arms/07-governance.md +71 -0
  439. package/docs/study/arms/08-execution.md +69 -0
  440. package/docs/study/arms/09-observability.md +60 -0
  441. package/docs/study/arms/10-refinement.md +110 -0
  442. package/docs/study/btw-comparison.md +37 -0
  443. package/docs/study/feature-gap-review.md +42 -0
  444. package/docs/study/insights.md +123 -0
  445. package/docs/study/roadmap.md +72 -0
  446. package/docs/study/sources/claude-code.md +44 -0
  447. package/docs/study/sources/deepseek-harness.md +102 -0
  448. package/docs/study/sources/harness2.md +50 -0
  449. package/docs/study/sources/kimi-cli.md +42 -0
  450. package/docs/study/sources/omp.md +93 -0
  451. package/docs/study/sources/opencode.md +43 -0
  452. package/docs/study/sources/openhands.md +46 -0
  453. package/docs/study/sources/smolagents.md +40 -0
  454. package/docs/study/sources/swe-agent.md +34 -0
  455. package/docs/system-prompt-design.md +196 -0
  456. package/docs/terminal-tui.md +671 -0
  457. package/package.json +48 -12
  458. package/src/accounts/accounts.test.ts +0 -223
  459. package/src/accounts/accounts.ts +0 -522
  460. package/src/accounts/env.test.ts +0 -95
  461. package/src/accounts/env.ts +0 -338
  462. package/src/accounts/secrets.ts +0 -50
  463. package/src/accounts/store.ts +0 -338
  464. package/src/capabilities/api.ts +0 -75
  465. package/src/capabilities/runSnapshot.ts +0 -59
  466. package/src/capabilities/types.ts +0 -34
  467. package/src/cli.ts +0 -114
  468. package/src/core/bus.ts +0 -34
  469. package/src/core/changes.ts +0 -33
  470. package/src/core/env.ts +0 -27
  471. package/src/core/errors.ts +0 -32
  472. package/src/core/frontmatter.ts +0 -47
  473. package/src/core/fs.test.ts +0 -38
  474. package/src/core/fs.ts +0 -92
  475. package/src/core/index.ts +0 -193
  476. package/src/core/path.test.ts +0 -14
  477. package/src/core/path.ts +0 -79
  478. package/src/core/projects.ts +0 -90
  479. package/src/core/text.ts +0 -39
  480. package/src/harness.ts +0 -299
  481. package/src/index.ts +0 -70
  482. package/src/mcp/connections.ts +0 -614
  483. package/src/mcp/manager.ts +0 -130
  484. package/src/mcp/oauth.ts +0 -195
  485. package/src/mcp/scopeMigration.test.ts +0 -79
  486. package/src/mcp/scopeMigration.ts +0 -204
  487. package/src/mcp/service.test.ts +0 -376
  488. package/src/mcp/service.ts +0 -549
  489. package/src/mcp/types.ts +0 -108
  490. package/src/memory/api.test.ts +0 -82
  491. package/src/memory/api.ts +0 -289
  492. package/src/memory/blocks.test.ts +0 -78
  493. package/src/memory/blocks.ts +0 -406
  494. package/src/memory/caller.ts +0 -57
  495. package/src/memory/dispatch.ts +0 -59
  496. package/src/memory/facts.test.ts +0 -41
  497. package/src/memory/facts.ts +0 -248
  498. package/src/memory/graph.ts +0 -103
  499. package/src/memory/health.test.ts +0 -130
  500. package/src/memory/health.ts +0 -74
  501. package/src/memory/maintainer.ts +0 -272
  502. package/src/memory/maintenance.test.ts +0 -176
  503. package/src/memory/maintenance.ts +0 -330
  504. package/src/memory/migrate.ts +0 -79
  505. package/src/memory/operations.ts +0 -138
  506. package/src/memory/proposals.test.ts +0 -168
  507. package/src/memory/proposals.ts +0 -576
  508. package/src/memory/recall.test.ts +0 -104
  509. package/src/memory/recall.ts +0 -271
  510. package/src/memory/references.ts +0 -77
  511. package/src/memory/runContext.ts +0 -93
  512. package/src/memory/secrets.ts +0 -6
  513. package/src/memory/store.test.ts +0 -66
  514. package/src/memory/store.ts +0 -385
  515. package/src/memory/wiki.test.ts +0 -47
  516. package/src/memory/wiki.ts +0 -422
  517. package/src/memory/wikiIndex.test.ts +0 -88
  518. package/src/memory/wikiIndex.ts +0 -116
  519. package/src/plugins/api.ts +0 -181
  520. package/src/plugins/attachments.test.ts +0 -84
  521. package/src/plugins/attachments.ts +0 -141
  522. package/src/plugins/builtin.ts +0 -82
  523. package/src/plugins/catalogue.test.ts +0 -254
  524. package/src/plugins/catalogue.ts +0 -251
  525. package/src/plugins/cli.ts +0 -184
  526. package/src/plugins/discover.ts +0 -151
  527. package/src/plugins/firstParty.test.ts +0 -143
  528. package/src/plugins/firstParty.ts +0 -129
  529. package/src/plugins/hooks.test.ts +0 -250
  530. package/src/plugins/hooks.ts +0 -239
  531. package/src/plugins/identity.ts +0 -37
  532. package/src/plugins/install.test.ts +0 -107
  533. package/src/plugins/install.ts +0 -106
  534. package/src/plugins/inventory.ts +0 -123
  535. package/src/plugins/manifest.ts +0 -76
  536. package/src/plugins/plugins.test.ts +0 -205
  537. package/src/plugins/plugins.ts +0 -189
  538. package/src/plugins/proposal.ts +0 -121
  539. package/src/plugins/runtime.test.ts +0 -40
  540. package/src/plugins/runtime.ts +0 -82
  541. package/src/plugins/trust.ts +0 -142
  542. package/src/plugins/types.ts +0 -149
  543. package/src/prompt/compile.test.ts +0 -261
  544. package/src/prompt/compile.ts +0 -732
  545. package/src/server/methods.ts +0 -314
  546. package/src/server/remote.ts +0 -77
  547. package/src/server/rpc.ts +0 -116
  548. package/src/server/serve.ts +0 -28
  549. package/src/server/server.test.ts +0 -174
  550. package/src/sessions/approvals.ts +0 -118
  551. package/src/sessions/contracts.ts +0 -310
  552. package/src/sessions/conversation.test.ts +0 -150
  553. package/src/sessions/extensionSession.test.ts +0 -74
  554. package/src/sessions/extensionUi.test.ts +0 -65
  555. package/src/sessions/extensionUi.ts +0 -102
  556. package/src/sessions/history.ts +0 -51
  557. package/src/sessions/lineageJoin.ts +0 -75
  558. package/src/sessions/policy.ts +0 -32
  559. package/src/sessions/pricing.ts +0 -60
  560. package/src/sessions/reasoningSummaries.ts +0 -59
  561. package/src/sessions/registry.ts +0 -294
  562. package/src/sessions/runIndex.ts +0 -99
  563. package/src/sessions/runStore.test.ts +0 -152
  564. package/src/sessions/runStore.ts +0 -332
  565. package/src/sessions/runner.ts +0 -569
  566. package/src/sessions/runtimeResources.test.ts +0 -61
  567. package/src/sessions/sessions.test.ts +0 -455
  568. package/src/sessions/sessions.ts +0 -295
  569. package/src/skills/registry.test.ts +0 -104
  570. package/src/skills/registry.ts +0 -407
  571. package/src/terminal/cli.ts +0 -149
  572. package/src/terminal/client.ts +0 -74
  573. package/src/terminal/controller.ts +0 -227
  574. package/src/terminal/launch.test.ts +0 -34
  575. package/src/terminal/launch.ts +0 -88
  576. package/src/terminal/piExtension.ts +0 -210
  577. package/src/terminal/pluginControl.test.ts +0 -146
  578. package/src/terminal/pluginMenu.ts +0 -112
  579. package/src/terminal/socket.test.ts +0 -71
  580. package/src/terminal/socket.ts +0 -221
  581. package/src/terminal/standalone.test.ts +0 -130
  582. package/src/terminal/standalone.ts +0 -144
  583. package/src/terminal/terminal.test.ts +0 -330
  584. package/src/terminal/terminals.ts +0 -443
  585. package/src/tools/askUser.ts +0 -45
  586. package/src/tools/definitions.ts +0 -187
  587. package/src/tools/memoryTools.ts +0 -22
  588. package/src/tools/pluginPropose.ts +0 -41
  589. package/src/tools/types.ts +0 -39
  590. package/src/web/safeRequest.ts +0 -171
  591. package/src/web/text.ts +0 -53
  592. package/src/web/tools.ts +0 -134
  593. package/src/web/web.test.ts +0 -141
@@ -0,0 +1,669 @@
1
+ // Device-local connected apps: the saved connections, who may reach each one, how each is
2
+ // launched, and what must never be persisted from their results.
3
+ import { chmodSync } from 'node:fs';
4
+ import { isAbsolute, join } from 'node:path';
5
+ import { secretKey } from "../accounts/secrets.js";
6
+ import { HarnessError, invalid, notFound } from "../core/errors.js";
7
+ import { newId, readJson, safeId, writeJson } from "../core/fs.js";
8
+ import { findBinary, pathVariableName, searchPath } from "../core/path.js";
9
+ import { isDir } from "../core/fs.js";
10
+ import * as attachments from "../plugins/attachments.js";
11
+ import { connectionScopeMigrationComplete } from "./scopeMigration.js";
12
+ import { connectionCapabilityId, connectionInputSchema, connectionSchema } from "./types.js";
13
+ const OAUTH_STATE = 'oauth';
14
+ const OAUTH_CLIENT_ID = 'oauth_client_id';
15
+ const OAUTH_CLIENT_SECRET = 'oauth_client_secret';
16
+ const headerItem = (name) => `header:${name}`;
17
+ /** Remote servers and sign-in pages must use TLS; plain HTTP is only for servers on this machine. */
18
+ export function webUrl(text) {
19
+ try {
20
+ const url = new URL(text ?? '');
21
+ const loopback = ['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname);
22
+ return url.protocol === 'https:' || (url.protocol === 'http:' && loopback) ? url : null;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ /** Whether a session with this scope may reach the connection. */
29
+ export function allowed(connection, scope) {
30
+ if (!connection.enabled)
31
+ return false;
32
+ if (scope.agentId && connection.excludedAgentIds.includes(scope.agentId))
33
+ return false;
34
+ if (scope.projectId && connection.excludedProjectIds.includes(scope.projectId))
35
+ return false;
36
+ return connection.global || Boolean(scope.agentId && connection.agentIds.includes(scope.agentId)) || Boolean(scope.projectId && connection.projectIds.includes(scope.projectId));
37
+ }
38
+ /** Gives one agent exactly these connections, leaving every other agent's access as it was. */
39
+ export function setAgentScope(all, agentId, ids) {
40
+ for (const connection of all) {
41
+ connection.agentIds = connection.agentIds.filter((id) => id !== agentId);
42
+ connection.excludedAgentIds = connection.excludedAgentIds.filter((id) => id !== agentId);
43
+ if (ids.includes(connection.id)) {
44
+ if (!connection.global)
45
+ connection.agentIds.push(agentId);
46
+ }
47
+ else if (connection.global) {
48
+ connection.excludedAgentIds.push(agentId);
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Switches one connection on or off for everyone, for one agent, or for one project, leaving
54
+ * every other agent's and project's access as it was.
55
+ */
56
+ export function setScope(connection, scope, on) {
57
+ const without = (ids, id) => ids.filter((item) => item !== id);
58
+ if (scope.agentId) {
59
+ connection.agentIds = without(connection.agentIds, scope.agentId);
60
+ connection.excludedAgentIds = without(connection.excludedAgentIds, scope.agentId);
61
+ if (on && !connection.global)
62
+ connection.agentIds.push(scope.agentId);
63
+ // Off must hold in a project that has the connection too.
64
+ else if (!on && (connection.global || connection.projectIds.length))
65
+ connection.excludedAgentIds.push(scope.agentId);
66
+ }
67
+ else if (scope.projectId) {
68
+ connection.projectIds = without(connection.projectIds, scope.projectId);
69
+ connection.excludedProjectIds = without(connection.excludedProjectIds, scope.projectId);
70
+ if (on && !connection.global)
71
+ connection.projectIds.push(scope.projectId);
72
+ else if (!on && connection.global)
73
+ connection.excludedProjectIds.push(scope.projectId);
74
+ }
75
+ else {
76
+ connection.global = on;
77
+ }
78
+ }
79
+ /** Why these connections cannot be given to a session with this scope, or nothing. */
80
+ export function validateScopeIds(all, scope, ids) {
81
+ for (const id of ids) {
82
+ const connection = all.find((item) => item.id === id);
83
+ if (!connection)
84
+ throw notFound('Connection');
85
+ if (!allowed(connection, scope))
86
+ throw new HarnessError('required_connections_unavailable', `${connection.name} is disabled or outside your connection scope.`);
87
+ }
88
+ }
89
+ // ---- Redaction ----------------------------------------------------------------------------------
90
+ const SENSITIVE_FIELDS = new Set(['approvaltoken', 'token', 'apikey', 'accesstoken', 'refreshtoken', 'idtoken', 'clientsecret', 'secret', 'password', 'passwd', 'authorization', 'cookie', 'setcookie', 'env', 'credentials', 'locators']);
91
+ const SENSITIVE_KEYS = ['approvalToken', 'token', 'apiKey', 'api_key', 'accessToken', 'access_token', 'refreshToken', 'refresh_token', 'clientSecret', 'client_secret', 'password', 'authorization', 'cookie'];
92
+ function sensitiveField(key) {
93
+ return SENSITIVE_FIELDS.has(key.replace(/[^A-Za-z0-9]/g, '').toLowerCase());
94
+ }
95
+ /** Replaces the value of every `"key": "…"` in text that is not valid JSON (a truncated summary). */
96
+ export function redactJsonField(text, key) {
97
+ const marker = `"${key}"`;
98
+ let output = text;
99
+ let offset = 0;
100
+ for (;;) {
101
+ const found = output.indexOf(marker, offset);
102
+ if (found < 0)
103
+ return output;
104
+ const start = found + marker.length;
105
+ const match = /^\s*:\s*"/.exec(output.slice(start));
106
+ if (!match) {
107
+ offset = start;
108
+ continue;
109
+ }
110
+ const valueStart = start + match[0].length;
111
+ const quote = output.indexOf('"', valueStart);
112
+ const end = quote < 0 ? output.length : quote;
113
+ output = `${output.slice(0, valueStart)}[redacted]${output.slice(end)}`;
114
+ offset = valueStart + '[redacted]'.length;
115
+ }
116
+ }
117
+ function parsedContainer(text) {
118
+ try {
119
+ const parsed = JSON.parse(text);
120
+ return parsed && typeof parsed === 'object' ? parsed : undefined;
121
+ }
122
+ catch {
123
+ return undefined;
124
+ }
125
+ }
126
+ /** Drops credential-like fields from a value, including from JSON carried as text. */
127
+ export function scrubSensitive(value) {
128
+ return scrubWith(value, []);
129
+ }
130
+ /** `scrubSensitive`, and every one of `secrets` replaced wherever it appears in text. */
131
+ export function scrubWith(value, secrets) {
132
+ if (Array.isArray(value))
133
+ return value.map((item) => scrubWith(item, secrets));
134
+ if (value && typeof value === 'object')
135
+ return Object.fromEntries(Object.entries(value).filter(([key]) => !sensitiveField(key)).map(([key, item]) => [key, scrubWith(item, secrets)]));
136
+ if (typeof value !== 'string')
137
+ return value;
138
+ let output = value;
139
+ for (const secret of secrets)
140
+ if (secret)
141
+ output = output.replaceAll(secret, '[redacted]');
142
+ // Text representations of structured previews must not persist approval tokens.
143
+ const parsed = parsedContainer(output);
144
+ if (parsed !== undefined)
145
+ return JSON.stringify(scrubWith(parsed, secrets));
146
+ // Summaries can contain truncated JSON, which cannot be parsed above.
147
+ for (const key of SENSITIVE_KEYS)
148
+ output = redactJsonField(output, key);
149
+ return output;
150
+ }
151
+ export function revisionOf(all) {
152
+ return all.map((item) => ({ id: item.id, enabled: item.enabled, global: item.global, agents: item.agentIds, projects: item.projectIds, excludedAgents: item.excludedAgentIds, excludedProjects: item.excludedProjectIds, checkedAt: item.checkedAt, error: item.error }));
153
+ }
154
+ function sameScope(left, right) {
155
+ const ids = (values) => [...values].sort();
156
+ return left.global === right.global
157
+ && JSON.stringify(ids(left.agentIds)) === JSON.stringify(ids(right.agentIds))
158
+ && JSON.stringify(ids(left.projectIds)) === JSON.stringify(ids(right.projectIds))
159
+ && JSON.stringify(ids(left.excludedAgentIds)) === JSON.stringify(ids(right.excludedAgentIds))
160
+ && JSON.stringify(ids(left.excludedProjectIds)) === JSON.stringify(ids(right.excludedProjectIds));
161
+ }
162
+ function hasScope(connection) {
163
+ return connection.global || connection.agentIds.length > 0 || connection.projectIds.length > 0
164
+ || connection.excludedAgentIds.length > 0 || connection.excludedProjectIds.length > 0;
165
+ }
166
+ function scopeMigrationError() {
167
+ return new HarnessError('connection_scope_migration_pending', 'Connector access settings cannot be changed until their scope migration succeeds. Reopen the data root to retry it.');
168
+ }
169
+ // ---- The store --------------------------------------------------------------------------------
170
+ export class Connections {
171
+ secrets;
172
+ bus;
173
+ attachmentRoot;
174
+ appClients;
175
+ path;
176
+ /** Every secret value a connection holds, so results can be redacted without waiting on the store. */
177
+ known = new Map();
178
+ constructor(stateDir, secrets, bus, attachmentRoot = () => null, appClients = null) {
179
+ this.secrets = secrets;
180
+ this.bus = bus;
181
+ this.attachmentRoot = attachmentRoot;
182
+ this.appClients = appClients;
183
+ this.path = join(stateDir, 'connections.json');
184
+ }
185
+ list() {
186
+ const stored = readJson(this.path) ?? [];
187
+ const root = this.attachmentRoot();
188
+ const choices = root ? attachments.load(root) : null;
189
+ return stored.flatMap((item) => {
190
+ const parsed = connectionSchema.safeParse(item);
191
+ if (!parsed.success)
192
+ return [];
193
+ const connection = parsed.data;
194
+ // Records saved before remote servers existed have no `auth`.
195
+ if (!connection.auth)
196
+ connection.auth = 'none';
197
+ // The preset was saved as "X Workspace" before the product was renamed.
198
+ if (connection.kind === 'workspace' && connection.name === 'X Workspace')
199
+ connection.name = 'Xingular Workspace';
200
+ if (choices) {
201
+ const id = connectionCapabilityId(connection.id);
202
+ const hasChoice = choices.global.on.includes(id) || choices.global.off.includes(id)
203
+ || Object.values(choices.agents).some((entry) => entry.on.includes(id) || entry.off.includes(id))
204
+ || Object.values(choices.projects).some((entry) => entry.on.includes(id) || entry.off.includes(id));
205
+ // Before the first successful root open, keep old records readable. After migration the
206
+ // returned fields are a view over attachments; they are never written back to connections.json.
207
+ if (hasChoice || !(connection.global || connection.agentIds.length || connection.projectIds.length || connection.excludedAgentIds.length || connection.excludedProjectIds.length)) {
208
+ const attachment = attachments.describe(choices, id, connection.global);
209
+ connection.global = attachment.global;
210
+ connection.agentIds = attachment.on.agentIds;
211
+ connection.projectIds = attachment.on.projectIds;
212
+ connection.excludedAgentIds = attachment.off.agentIds;
213
+ connection.excludedProjectIds = attachment.off.projectIds;
214
+ }
215
+ }
216
+ return [connection];
217
+ });
218
+ }
219
+ find(id) {
220
+ const connection = this.list().find((item) => item.id === id);
221
+ if (!connection)
222
+ throw notFound('Connection');
223
+ return connection;
224
+ }
225
+ forScope(scope) {
226
+ return this.list().filter((connection) => allowed(connection, scope));
227
+ }
228
+ revision() {
229
+ return revisionOf(this.list());
230
+ }
231
+ write(all) {
232
+ const root = this.attachmentRoot();
233
+ let stored = all;
234
+ if (root && connectionScopeMigrationComplete(root)) {
235
+ stored = all.map(({ global: _global, agentIds: _agentIds, projectIds: _projectIds, excludedAgentIds: _excludedAgentIds, excludedProjectIds: _excludedProjectIds, ...connection }) => connection);
236
+ }
237
+ else if (root) {
238
+ // A non-scope edit is allowed while migration is pending, but its legacy scopes must stay
239
+ // in connections.json until the attachment store has been verified.
240
+ const previous = new Map();
241
+ for (const item of readJson(this.path) ?? []) {
242
+ const parsed = connectionSchema.safeParse(item);
243
+ if (parsed.success)
244
+ previous.set(parsed.data.id, parsed.data);
245
+ }
246
+ stored = all.map((connection) => {
247
+ const legacy = previous.get(connection.id);
248
+ return legacy ? {
249
+ ...connection,
250
+ global: legacy.global,
251
+ agentIds: legacy.agentIds,
252
+ projectIds: legacy.projectIds,
253
+ excludedAgentIds: legacy.excludedAgentIds,
254
+ excludedProjectIds: legacy.excludedProjectIds
255
+ } : connection;
256
+ });
257
+ }
258
+ writeJson(this.path, stored);
259
+ try {
260
+ chmodSync(this.path, 0o600);
261
+ }
262
+ catch {
263
+ // The file was written; a mode that cannot be set is not worth failing the change.
264
+ }
265
+ }
266
+ writeScope(root, connection) {
267
+ const choices = attachments.load(root);
268
+ const id = connectionCapabilityId(connection.id);
269
+ attachments.forgetId(choices, id);
270
+ attachments.set(choices, [id], {}, connection.global, false);
271
+ for (const agentId of new Set([...connection.agentIds, ...connection.excludedAgentIds])) {
272
+ const on = connection.agentIds.includes(agentId) && !connection.excludedAgentIds.includes(agentId);
273
+ attachments.set(choices, [id], { agentId }, on, connection.global);
274
+ }
275
+ for (const projectId of new Set([...connection.projectIds, ...connection.excludedProjectIds])) {
276
+ const on = connection.projectIds.includes(projectId) && !connection.excludedProjectIds.includes(projectId);
277
+ attachments.set(choices, [id], { projectId }, on, connection.global);
278
+ }
279
+ attachments.save(root, choices);
280
+ }
281
+ changed() {
282
+ this.bus.emit({ type: 'connections.changed' });
283
+ }
284
+ /** Read-modify-write of one connection. */
285
+ update(id, change) {
286
+ const all = this.list();
287
+ const connection = all.find((item) => item.id === id);
288
+ if (!connection)
289
+ throw notFound('Connection');
290
+ const before = { ...connection, agentIds: [...connection.agentIds], projectIds: [...connection.projectIds], excludedAgentIds: [...connection.excludedAgentIds], excludedProjectIds: [...connection.excludedProjectIds] };
291
+ change(connection);
292
+ const root = this.attachmentRoot();
293
+ if (root && !connectionScopeMigrationComplete(root) && !sameScope(before, connection))
294
+ throw scopeMigrationError();
295
+ this.write(all);
296
+ return connection;
297
+ }
298
+ /** Read-modify-write of every connection. */
299
+ updateAll(change) {
300
+ const all = this.list();
301
+ const before = new Map(all.map((connection) => [connection.id, {
302
+ ...connection,
303
+ agentIds: [...connection.agentIds],
304
+ projectIds: [...connection.projectIds],
305
+ excludedAgentIds: [...connection.excludedAgentIds],
306
+ excludedProjectIds: [...connection.excludedProjectIds]
307
+ }]));
308
+ change(all);
309
+ const root = this.attachmentRoot();
310
+ if (root && !connectionScopeMigrationComplete(root)) {
311
+ const remainingIds = new Set(all.map((connection) => connection.id));
312
+ const scopeChanged = all.some((connection) => {
313
+ const previous = before.get(connection.id);
314
+ return previous ? !sameScope(previous, connection) : hasScope(connection);
315
+ }) || [...before].some(([id, connection]) => !remainingIds.has(id) && hasScope(connection));
316
+ if (scopeChanged)
317
+ throw scopeMigrationError();
318
+ }
319
+ this.write(all);
320
+ this.changed();
321
+ }
322
+ /** Switches one connector in the shared attachment store, preserving all other scopes. */
323
+ setScope(connectionId, scope, on) {
324
+ const connection = this.find(connectionId);
325
+ const root = this.attachmentRoot();
326
+ if (root && !connectionScopeMigrationComplete(root))
327
+ throw scopeMigrationError();
328
+ if (!root) {
329
+ this.update(connectionId, (item) => setScope(item, scope, on));
330
+ this.changed();
331
+ return this.forScope(scope);
332
+ }
333
+ const choices = attachments.load(root);
334
+ const fallback = connection.global;
335
+ attachments.set(choices, [connectionCapabilityId(connectionId)], scope, on, fallback);
336
+ attachments.save(root, choices);
337
+ this.changed();
338
+ return this.forScope(scope);
339
+ }
340
+ /** Gives one agent an exact connector set without changing project or global choices. */
341
+ setAgentScope(agentId, ids) {
342
+ const all = this.list();
343
+ const root = this.attachmentRoot();
344
+ if (root && !connectionScopeMigrationComplete(root))
345
+ throw scopeMigrationError();
346
+ if (!root) {
347
+ setAgentScope(all, agentId, ids);
348
+ this.write(all);
349
+ this.changed();
350
+ return this.forScope({ agentId });
351
+ }
352
+ const choices = attachments.load(root);
353
+ for (const connection of all) {
354
+ attachments.set(choices, [connectionCapabilityId(connection.id)], { agentId }, ids.includes(connection.id), connection.global);
355
+ }
356
+ attachments.save(root, choices);
357
+ this.changed();
358
+ return this.forScope({ agentId });
359
+ }
360
+ /** Removes only connector choices when an agent is deleted; other capability choices are separate. */
361
+ removeAgentScope(agentId) {
362
+ const root = this.attachmentRoot();
363
+ // This is cleanup for a deleted caller. Leave stale ids inert until migration can safely
364
+ // move the remaining scopes; failing helper cleanup must not leave an orphan agent behind.
365
+ if (root && !connectionScopeMigrationComplete(root))
366
+ return;
367
+ if (!root) {
368
+ this.updateAll((all) => {
369
+ for (const connection of all) {
370
+ connection.agentIds = connection.agentIds.filter((id) => id !== agentId);
371
+ connection.excludedAgentIds = connection.excludedAgentIds.filter((id) => id !== agentId);
372
+ }
373
+ });
374
+ return;
375
+ }
376
+ const choices = attachments.load(root);
377
+ const entry = choices.agents[agentId];
378
+ if (!entry)
379
+ return;
380
+ const isConnector = (id) => id.startsWith('connected-apps/connection/');
381
+ entry.on = entry.on.filter((id) => !isConnector(id));
382
+ entry.off = entry.off.filter((id) => !isConnector(id));
383
+ if (!entry.on.length && !entry.off.length)
384
+ delete choices.agents[agentId];
385
+ attachments.save(root, choices);
386
+ this.changed();
387
+ }
388
+ secret(connectionId, name) {
389
+ return this.secrets.get(secretKey(`mcp--${connectionId}`, name));
390
+ }
391
+ setSecret(connectionId, name, value) {
392
+ return this.secrets.set(secretKey(`mcp--${connectionId}`, name), value);
393
+ }
394
+ deleteSecret(connectionId, name) {
395
+ return this.secrets.delete(secretKey(`mcp--${connectionId}`, name));
396
+ }
397
+ /** Everything the secret store holds for a connection: environment and header values, and OAuth credentials. */
398
+ async secretValues(connection) {
399
+ const values = [];
400
+ for (const key of connection.envKeys) {
401
+ const value = await this.secret(connection.id, key);
402
+ if (value)
403
+ values.push(value);
404
+ }
405
+ for (const key of connection.headerKeys) {
406
+ const value = await this.secret(connection.id, headerItem(key));
407
+ if (!value)
408
+ continue;
409
+ // "Authorization: Bearer <key>" must not leak the key on its own either.
410
+ const space = value.indexOf(' ');
411
+ if (space >= 0)
412
+ values.push(value.slice(space + 1).trim());
413
+ values.push(value);
414
+ }
415
+ if (connection.auth === 'oauth') {
416
+ const client = await this.secret(connection.id, OAUTH_CLIENT_SECRET);
417
+ if (client)
418
+ values.push(client);
419
+ const saved = (parsedContainer((await this.secret(connection.id, OAUTH_STATE)) ?? '') ?? {});
420
+ for (const field of ['access_token', 'refresh_token', 'id_token'])
421
+ if (typeof saved.tokens?.[field] === 'string')
422
+ values.push(saved.tokens[field]);
423
+ }
424
+ return values.filter(Boolean);
425
+ }
426
+ /** Reloads the secret values used for redaction. Called at start and whenever a connection's secrets change. */
427
+ async refreshSecrets() {
428
+ const next = new Map();
429
+ for (const connection of this.list())
430
+ next.set(connection.id, await this.secretValues(connection).catch(() => []));
431
+ this.known.clear();
432
+ for (const [id, values] of next)
433
+ this.known.set(id, values);
434
+ }
435
+ /** A connection's result, safe to persist. */
436
+ scrub(value, connectionId) {
437
+ return scrubWith(value, this.known.get(connectionId) ?? []);
438
+ }
439
+ /** Removes credentials from the evidence a run event carries. */
440
+ redactEvent(event) {
441
+ if (!event.type.startsWith('tool.') && !['context.snapshot', 'retry.started', 'retry.ended', 'compaction.started', 'compaction.ended'].includes(event.type))
442
+ return;
443
+ const secrets = [...this.known.values()].flat();
444
+ event.payload = scrubWith(event.payload, secrets);
445
+ if (event.native !== undefined)
446
+ event.native = scrubWith(event.native, secrets);
447
+ }
448
+ // ---- Launching ----------------------------------------------------------------------------
449
+ async launch(connection) {
450
+ if (connection.kind === 'remote') {
451
+ const headers = {};
452
+ for (const key of connection.headerKeys) {
453
+ const value = await this.secret(connection.id, headerItem(key));
454
+ if (value !== null)
455
+ headers[key] = value;
456
+ }
457
+ return { id: connection.id, name: connection.name, transport: 'http', url: connection.url ?? '', headers, auth: connection.auth, scopes: connection.oauthScopes };
458
+ }
459
+ let command = findBinary(connection.command) ?? (isAbsolute(connection.command) ? connection.command : null);
460
+ if (!command)
461
+ throw new HarnessError('mcp_unavailable', 'MCP executable was not found. Select its absolute path.');
462
+ const env = { [pathVariableName(process.env)]: searchPath() };
463
+ for (const key of ['HOME', 'TMPDIR', 'LANG'])
464
+ if (process.env[key])
465
+ env[key] = process.env[key];
466
+ for (const key of connection.envKeys) {
467
+ const value = await this.secret(connection.id, key);
468
+ if (value !== null)
469
+ env[key] = value;
470
+ }
471
+ const args = [...connection.args];
472
+ if (connection.kind === 'workspace') {
473
+ // The first-party launcher is JavaScript; run it on this process's Node even where none is on PATH.
474
+ args.unshift(command);
475
+ command = process.execPath;
476
+ if (connection.expectedVaultId && !args.includes('--expected-vault-id'))
477
+ args.push('--expected-vault-id', connection.expectedVaultId);
478
+ }
479
+ return { id: connection.id, name: connection.name, transport: 'stdio', command, args, cwd: connection.cwd, env };
480
+ }
481
+ // ---- OAuth state --------------------------------------------------------------------------
482
+ requireOauth(id) {
483
+ const connection = this.list().find((item) => item.id === id && item.kind === 'remote' && item.auth === 'oauth');
484
+ if (!connection)
485
+ throw notFound('Connection');
486
+ return connection;
487
+ }
488
+ /** The saved sign-in of a connection, with the client the user registered, or the application's own. */
489
+ async oauthLoad(id) {
490
+ const connection = this.requireOauth(id);
491
+ const saved = (parsedContainer((await this.secret(id, OAUTH_STATE)) ?? '') ?? {});
492
+ const state = Array.isArray(saved) ? {} : saved;
493
+ delete state.staticClient;
494
+ if (connection.oauthClient === 'app') {
495
+ const client = await this.appClient(connection);
496
+ if (client)
497
+ state.staticClient = { client_id: client.clientId, ...(client.clientSecret ? { client_secret: client.clientSecret } : {}) };
498
+ }
499
+ else if (connection.oauthClient === 'user' || connection.oauthClient === null) {
500
+ const clientId = await this.secret(id, OAUTH_CLIENT_ID);
501
+ if (clientId) {
502
+ const clientSecret = await this.secret(id, OAUTH_CLIENT_SECRET);
503
+ state.staticClient = { client_id: clientId, ...(clientSecret ? { client_secret: clientSecret } : {}) };
504
+ }
505
+ }
506
+ return state;
507
+ }
508
+ /** The client this application registered for a catalog entry, if it has one. */
509
+ async appClient(connection) {
510
+ if (!connection.catalogId)
511
+ return null;
512
+ return (await this.appClients?.get(connection.catalogId)) ?? null;
513
+ }
514
+ /** Whether a sign-in can be started: a dynamic server registers itself, the others need a client. */
515
+ async hasSignInClient(connection) {
516
+ if (connection.oauthClient === 'user')
517
+ return (await this.secret(connection.id, OAUTH_CLIENT_ID)) !== null;
518
+ if (connection.oauthClient === 'app')
519
+ return (await this.appClient(connection)) !== null;
520
+ return true;
521
+ }
522
+ /** The catalog entries this application can sign in for without asking for a client. */
523
+ availableAppClients() {
524
+ return this.appClients?.ids() ?? [];
525
+ }
526
+ async oauthSave(id, state) {
527
+ this.requireOauth(id);
528
+ const { staticClient: _static, ...saved } = state ?? {};
529
+ await this.setSecret(id, OAUTH_STATE, JSON.stringify(saved));
530
+ await this.refreshSecrets();
531
+ }
532
+ async hasOauthClient(id) {
533
+ return (await this.secret(id, OAUTH_CLIENT_ID)) !== null;
534
+ }
535
+ forgetSignIn(id) {
536
+ return this.deleteSecret(id, OAUTH_STATE);
537
+ }
538
+ // ---- Changes ------------------------------------------------------------------------------
539
+ async save(input) {
540
+ const parsed = connectionInputSchema.safeParse(input);
541
+ if (!parsed.success)
542
+ throw invalid('A name, executable, and supported connection kind are required.');
543
+ const { env, removeEnv, headers, removeHeaders, oauthCredentials, ...connection } = parsed.data;
544
+ if (!connection.id)
545
+ connection.id = newId();
546
+ safeId(connection.id);
547
+ const remote = connection.kind === 'remote';
548
+ if (!connection.name.trim() || !['workspace', 'local', 'remote'].includes(connection.kind) || (!remote && !connection.command.trim())) {
549
+ throw invalid('A name, executable, and supported connection kind are required.');
550
+ }
551
+ if (remote) {
552
+ if (!webUrl(connection.url))
553
+ throw invalid('Server URL must be an https:// address.');
554
+ if (!['none', 'headers', 'oauth'].includes(connection.auth))
555
+ throw invalid('Unsupported sign-in method.');
556
+ if (connection.oauthClient && !['dynamic', 'user', 'app'].includes(connection.oauthClient))
557
+ throw invalid('Unsupported OAuth client.');
558
+ Object.assign(connection, { command: '', args: [], cwd: null });
559
+ if (connection.auth !== 'oauth')
560
+ Object.assign(connection, { oauthClient: null, oauthScopes: [] });
561
+ }
562
+ else {
563
+ Object.assign(connection, { url: null, auth: 'none', oauthClient: null, oauthScopes: [] });
564
+ }
565
+ if (connection.args.some((value) => value.includes('\0')) || connection.command.includes('\0'))
566
+ throw invalid('Invalid executable or argument.');
567
+ if (connection.cwd && (!isAbsolute(connection.cwd) || !isDir(connection.cwd)))
568
+ throw invalid('Working directory must be an existing absolute directory.');
569
+ const all = this.list();
570
+ const existing = all.find((item) => item.id === connection.id);
571
+ const root = this.attachmentRoot();
572
+ if (root && !connectionScopeMigrationComplete(root) && (existing ? !sameScope(existing, connection) : hasScope(connection))) {
573
+ throw scopeMigrationError();
574
+ }
575
+ connection.envKeys = [...(existing?.envKeys ?? [])];
576
+ connection.headerKeys = [...(existing?.headerKeys ?? [])];
577
+ // A sign-in belongs to one server and one client; never carry it to another.
578
+ const sameServer = (existing?.url ?? null) === connection.url && (existing?.auth ?? '') === connection.auth && existing?.oauthClient === connection.oauthClient && existing?.catalogId === connection.catalogId && !oauthCredentials;
579
+ if (!sameServer || connection.auth !== 'oauth')
580
+ await this.forgetSignIn(connection.id);
581
+ connection.authState = connection.auth === 'oauth' ? (sameServer ? (existing?.authState ?? 'signed_out') : 'signed_out') : null;
582
+ if (oauthCredentials) {
583
+ if (!oauthCredentials.clientId.trim())
584
+ throw invalid('An OAuth client ID is required.');
585
+ await this.setSecret(connection.id, OAUTH_CLIENT_ID, oauthCredentials.clientId.trim());
586
+ if (oauthCredentials.clientSecret)
587
+ await this.setSecret(connection.id, OAUTH_CLIENT_SECRET, oauthCredentials.clientSecret);
588
+ else
589
+ await this.deleteSecret(connection.id, OAUTH_CLIENT_SECRET);
590
+ }
591
+ for (const [key, value] of Object.entries(headers ?? {})) {
592
+ if (!/^[A-Za-z0-9_-]+$/.test(key) || /[\r\n\0]/.test(value))
593
+ throw invalid('Invalid header name or value.');
594
+ await this.setSecret(connection.id, headerItem(key), value);
595
+ if (!connection.headerKeys.includes(key))
596
+ connection.headerKeys.push(key);
597
+ }
598
+ for (const key of removeHeaders ?? []) {
599
+ await this.deleteSecret(connection.id, headerItem(key));
600
+ connection.headerKeys = connection.headerKeys.filter((value) => value !== key);
601
+ }
602
+ for (const [key, value] of Object.entries(env ?? {})) {
603
+ if (!/^[A-Za-z0-9_]+$/.test(key))
604
+ throw invalid('Invalid environment variable name.');
605
+ await this.setSecret(connection.id, key, value);
606
+ if (!connection.envKeys.includes(key))
607
+ connection.envKeys.push(key);
608
+ }
609
+ for (const key of removeEnv ?? []) {
610
+ await this.deleteSecret(connection.id, key);
611
+ connection.envKeys = connection.envKeys.filter((value) => value !== key);
612
+ }
613
+ Object.assign(connection, { checkedAt: null, tools: [], serverName: null, error: null });
614
+ if (root && connectionScopeMigrationComplete(root))
615
+ this.writeScope(root, connection);
616
+ this.write([...all.filter((item) => item.id !== connection.id), connection]);
617
+ await this.refreshSecrets();
618
+ this.changed();
619
+ return connection;
620
+ }
621
+ /**
622
+ * Adds one tool to a connection's no-approval list. Unlike a full save this keeps the
623
+ * connection's pending approvals, so the request the user is answering can still be approved.
624
+ */
625
+ allowTool(connectionId, tool) {
626
+ if (!tool.trim())
627
+ throw invalid('A tool is required.');
628
+ if (this.list().some((item) => item.id === connectionId && item.kind === 'workspace'))
629
+ throw invalid('Changes to Xingular Workspace are approved one at a time.');
630
+ const connection = this.update(connectionId, (item) => {
631
+ if (!item.readTools.includes(tool))
632
+ item.readTools.push(tool);
633
+ });
634
+ this.changed();
635
+ return connection;
636
+ }
637
+ async remove(connectionId) {
638
+ const all = this.list();
639
+ const connection = all.find((item) => item.id === connectionId);
640
+ if (connection) {
641
+ for (const key of connection.envKeys)
642
+ await this.deleteSecret(connection.id, key);
643
+ for (const key of connection.headerKeys)
644
+ await this.deleteSecret(connection.id, headerItem(key));
645
+ for (const name of [OAUTH_STATE, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET])
646
+ await this.deleteSecret(connection.id, name);
647
+ }
648
+ this.write(all.filter((item) => item.id !== connectionId));
649
+ const root = this.attachmentRoot();
650
+ if (root) {
651
+ const choices = attachments.load(root);
652
+ attachments.forgetId(choices, connectionCapabilityId(connectionId));
653
+ attachments.save(root, choices);
654
+ }
655
+ this.known.delete(connectionId);
656
+ this.changed();
657
+ }
658
+ async signOut(connectionId) {
659
+ await this.forgetSignIn(connectionId);
660
+ const connection = this.update(connectionId, (item) => {
661
+ if (item.auth === 'oauth')
662
+ item.authState = 'signed_out';
663
+ Object.assign(item, { checkedAt: null, tools: [], error: null });
664
+ });
665
+ await this.refreshSecrets();
666
+ this.changed();
667
+ return connection;
668
+ }
669
+ }