@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,146 +0,0 @@
1
- import { existsSync, mkdtempSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { join } from 'node:path'
4
- import { afterEach, describe, expect, it } from 'vitest'
5
-
6
- import { memorySecretStore } from '../accounts/secrets'
7
- import { createHarness, type Harness } from '../harness'
8
- import { runPluginsCli } from '../plugins/cli'
9
- import type { Plugin } from '../plugins/types'
10
- import { rootWithProject, writeFile } from '../../tests/helpers'
11
- import { SOCKET_ENV, TOKEN_ENV, socketCall, type SocketConnection } from './client'
12
- import { menuRows, rowActions, runPluginsMenu, type MenuUi } from './pluginMenu'
13
-
14
- const open: Harness[] = []
15
- afterEach(async () => {
16
- for (const harness of open.splice(0)) await harness.close()
17
- })
18
-
19
- function kit(folder: string): void {
20
- writeFile(join(folder, 'package.json'), JSON.stringify({ name: 'review-kit', description: 'Review helpers.', version: '1.0.0' }))
21
- writeFile(join(folder, 'extensions/guard.ts'), 'export default function () {}\n')
22
- writeFile(join(folder, 'skills/audit/SKILL.md'), '---\nname: audit\ndescription: Audit a change.\n---\nSteps.\n')
23
- }
24
-
25
- async function session() {
26
- const root = rootWithProject()
27
- const base = mkdtempSync(join(tmpdir(), 'control-'))
28
- writeFile(join(root, 'registry/rules/tests.md'), '---\nname: Run tests\ndescription: Always test.\n---\nAlways run the tests.\n')
29
- const harness = createHarness({ dataRoot: root, stateDir: join(base, 'state'), secrets: memorySecretStore(), piProgram: () => '/opt/pi/bin/pi', assets: { node: '/opt/node', cli: '/opt/harness/cli.js', piExtension: '/opt/harness/terminal-pi.js' } })
30
- open.push(harness)
31
- const account = harness.accounts.create('Main', 'apiKey').accounts[0]
32
- harness.plugins.trust.adopt([])
33
- kit(join(root, 'plugins/review-kit'))
34
- const launch = await harness.terminals.prepare({ sessionId: 'term-1', accountId: account.id, projectId: 'p1', cwd: base, sessionFolder: join(root, 'sessions', 'p1', 'term-1') })
35
- const connection: SocketConnection = { socket: String(launch.env[SOCKET_ENV]), token: String(launch.env[TOKEN_ENV]) }
36
- return { harness, root, base, connection }
37
- }
38
-
39
- /** A person at the terminal, answering each dialog in turn from a script. */
40
- function person(answers: (string | boolean | undefined)[]) {
41
- const shown: string[] = []
42
- const said: string[] = []
43
- const ui: MenuUi = {
44
- select: async (title, options) => {
45
- shown.push(`${title} → ${options.join(' | ')}`)
46
- return answers.shift() as string | undefined
47
- },
48
- confirm: async (title, message) => {
49
- shown.push(`${title} ${message}`)
50
- return answers.shift() === true
51
- },
52
- notify: (message) => void said.push(message)
53
- }
54
- return { ui, shown, said }
55
- }
56
-
57
- describe('plugin control from a terminal session', () => {
58
- it("lists for anyone in the session, and changes only for the session's own extension", async () => {
59
- const { connection } = await session()
60
- const listed = await socketCall<Plugin[]>(connection, 'plugins.list')
61
- const plugin = listed.find((candidate) => candidate.id === 'package:review-kit')!
62
- expect(plugin).toMatchObject({ trust: 'untrusted' })
63
- // A command the model runs in the shell has the session token and nothing more.
64
- await expect(socketCall(connection, 'plugins.trust', { hash: plugin.code!.hash })).rejects.toThrow('Only a person at this terminal can change plugins')
65
- await expect(socketCall(connection, 'plugins.detach', { id: plugin.id })).rejects.toThrow('Only a person at this terminal')
66
- await expect(socketCall(connection, 'plugins.trust', { hash: plugin.code!.hash }, 5_000, 'guessed')).rejects.toThrow('Only a person at this terminal')
67
-
68
- // The extension claims the key as it loads. It is given out once.
69
- const { key } = await socketCall<{ key: string }>(connection, 'control.claim')
70
- await expect(socketCall(connection, 'control.claim')).rejects.toThrow('already claimed')
71
- const trusted = await socketCall<Plugin[]>(connection, 'plugins.trust', { hash: plugin.code!.hash }, 5_000, key)
72
- expect(trusted.find((candidate) => candidate.id === plugin.id)).toMatchObject({ trust: 'trusted' })
73
- // Without "everywhere", a switch from a terminal is for the session's project.
74
- const off = await socketCall<Plugin[]>(connection, 'plugins.detach', { id: plugin.id }, 5_000, key)
75
- expect(off.find((candidate) => candidate.id === plugin.id)!.attachment).toEqual({ global: true, on: { agentIds: [], projectIds: [] }, off: { agentIds: [], projectIds: ['p1'] } })
76
- })
77
-
78
- it('walks a person through switching and trusting, and changes nothing they did not choose', async () => {
79
- const { harness, connection } = await session()
80
- const { key } = await socketCall<{ key: string }>(connection, 'control.claim')
81
- const call = <T>(method: string, params?: Record<string, unknown>) => socketCall<T>(connection, method, params ?? {}, 5_000, key)
82
- const rows = menuRows(await call<Plugin[]>('plugins.list'), 'p1')
83
- expect(rows.map((row) => row.label)).toEqual(['● review-kit · code not trusted', '○ Run tests · instruction in Yours', '○ Budget guard · runs code', '○ Output trim · runs code'])
84
- expect(rowActions(rows[0], 'p1')).toEqual(['Switch off for this project', 'Switch off everywhere', 'Trust its code', 'Back'])
85
- expect(rowActions(rows[1], null)).toEqual(['Switch on everywhere', 'Back'])
86
- // A part that ships with the harness needs no trust: it is the harness's own code.
87
- expect(rowActions(rows[2], 'p1')).toEqual(['Switch on for this project', 'Switch on everywhere', 'Back'])
88
-
89
- // Declining the trust question leaves the code untrusted; then they trust it, switch a rule on, and leave.
90
- const { ui, shown, said } = person(['● review-kit · code not trusted', 'Trust its code', false, '● review-kit · code not trusted', 'Trust its code', true, '○ Run tests · instruction in Yours', 'Switch on for this project', 'Done'])
91
- await runPluginsMenu(ui, call, 'p1')
92
- expect(shown.find((line) => line.startsWith('Trust this code?'))).toContain('extensions/guard.ts')
93
- expect(shown.find((line) => line.startsWith('Trust this code?'))).toContain('can do anything this app can')
94
- expect(said).toEqual(['Saved. It applies when this session restarts.'])
95
- const after = await call<Plugin[]>('plugins.list')
96
- expect(after.find((plugin) => plugin.id === 'package:review-kit')).toMatchObject({ trust: 'trusted' })
97
- expect(after.flatMap((plugin) => plugin.contributions).find((entry) => entry.id === 'yours/rules/tests')).toMatchObject({ state: 'on', scope: 'App' })
98
- expect(harness.plugins.trust.list()).toHaveLength(1)
99
-
100
- // Leaving at once changes nothing and says nothing.
101
- const idle = person([undefined])
102
- await runPluginsMenu(idle.ui, call, 'p1')
103
- expect(idle.said).toEqual([])
104
- })
105
- })
106
-
107
- describe('the plugins command', () => {
108
- it('lists, installs, switches, trusts only on a yes, and removes, on its own data', async () => {
109
- const base = mkdtempSync(join(tmpdir(), 'plugins-cli-'))
110
- kit(join(base, 'kit'))
111
- const lines: string[] = []
112
- const run = (argv: string[], answer?: string) => runPluginsCli([...argv, '--data', join(base, 'data'), '--state', join(base, 'state')], { home: base, cwd: base, write: (text) => void lines.push(text), ...(answer === undefined ? {} : { ask: async () => answer }) })
113
- const last = (): string => lines.at(-1) ?? ''
114
-
115
- expect(await run(['list'])).toBe(0)
116
- expect(last()).toMatch(/^memory\s+required\s+Memory$/m)
117
- expect(await run(['install', join(base, 'kit')])).toBe(0)
118
- expect(last()).toContain('Installed, switched off.')
119
- expect(last()).toContain('trust its code with "plugins trust <id>"')
120
- expect(await run(['list'])).toBe(0)
121
- expect(last()).toMatch(/^package:review-kit\s+off, code not trusted\s+review-kit$/m)
122
-
123
- expect(await run(['attach', 'package:review-kit'])).toBe(0)
124
- expect(last()).toBe('package:review-kit is on everywhere. It applies from the next session start.\n')
125
- // No terminal to ask on and no --yes: the files are shown and nothing is trusted.
126
- expect(await run(['trust', 'package:review-kit'])).toBe(1)
127
- expect(lines.at(-2)).toContain('extensions/guard.ts')
128
- expect(last()).toBe('Read the files, then run this again with --yes to trust them.\n')
129
- expect(await run(['trust', 'package:review-kit'], 'no')).toBe(1)
130
- expect(last()).toBe('Not trusted.\n')
131
- expect(await run(['trust', 'package:review-kit'], 'yes')).toBe(0)
132
- expect(await run(['show', 'package:review-kit'])).toBe(0)
133
- expect(last()).toContain('State: on')
134
- expect(last()).toContain('Code (trusted)')
135
- expect(last()).toContain('● skill audit (package:review-kit/skill/audit)')
136
-
137
- expect(await run(['detach', 'memory'])).toBe(1)
138
- expect(last()).toContain('Memory cannot be switched off.')
139
- expect(await run(['untrust', 'package:review-kit'])).toBe(0)
140
- expect(await run(['remove', 'package:review-kit'])).toBe(0)
141
- expect(await run(['show', 'package:review-kit'])).toBe(1)
142
- expect(await run(['nonsense'])).toBe(2)
143
- // The folder that was installed in place is still the person's.
144
- expect(existsSync(join(base, 'kit/package.json'))).toBe(true)
145
- })
146
- })
@@ -1,112 +0,0 @@
1
- // The `/plugins` command of a terminal session, without Pi: what it lists, what it offers for
2
- // each row, and the conversation it has with the person. It asks through whatever interface it
3
- // is given (Pi's own dialogs in a terminal) and changes things through one function, so the
4
- // same flow is tested without a terminal.
5
- import type { Attachment } from '../plugins/attachments'
6
- import type { Contribution, Plugin } from '../plugins/types'
7
-
8
- export interface MenuUi {
9
- select(title: string, options: string[]): Promise<string | undefined>
10
- confirm(title: string, message: string): Promise<boolean>
11
- notify(message: string, level?: 'info' | 'warning' | 'error'): void
12
- }
13
-
14
- /** `plugins.list`, `plugins.attach`, `plugins.detach`, `plugins.trust`, `plugins.untrust`. */
15
- export type MenuCall = <T = unknown>(method: string, params?: Record<string, unknown>) => Promise<T>
16
-
17
- export interface MenuRow {
18
- /** The plugin's id, or one contribution's. */
19
- id: string
20
- label: string
21
- on: boolean
22
- /** The plugin it is, or belongs to. */
23
- plugin: Plugin
24
- /** Set when the row is the whole plugin. */
25
- whole: boolean
26
- }
27
-
28
- const here = (attachment: Attachment, projectId: string | null): boolean => {
29
- if (projectId && attachment.on.projectIds.includes(projectId)) return true
30
- if (projectId && attachment.off.projectIds.includes(projectId)) return false
31
- return attachment.global
32
- }
33
-
34
- const mark = (on: boolean): string => (on ? '●' : '○')
35
-
36
- /** What can be switched or trusted from here: each found or installed plugin, and each item of the rest that has a switch. */
37
- export function menuRows(plugins: readonly Plugin[], projectId: string | null): MenuRow[] {
38
- const rows: MenuRow[] = []
39
- for (const plugin of plugins) {
40
- if (plugin.attachment) {
41
- const on = here(plugin.attachment, projectId)
42
- rows.push({ id: plugin.id, plugin, whole: true, on, label: `${mark(on)} ${plugin.title}${plugin.trust === 'untrusted' ? ' · code not trusted' : plugin.runsCode ? ' · runs code' : ''}` })
43
- continue
44
- }
45
- if (plugin.trust !== 'none') rows.push({ id: plugin.id, plugin, whole: true, on: plugin.trust === 'trusted', label: `${mark(plugin.trust === 'trusted')} ${plugin.title} · ${plugin.trust === 'trusted' ? 'code trusted' : 'code not trusted'}` })
46
- for (const entry of plugin.contributions) {
47
- if (!entry.attachment) continue
48
- rows.push({ id: entry.id, plugin, whole: false, on: entry.state === 'on', label: `${mark(entry.state === 'on')} ${entry.name} · ${kindWord(entry)} in ${plugin.title}` })
49
- }
50
- }
51
- return rows
52
- }
53
-
54
- const kindWord = (entry: Contribution): string => (entry.kind === 'connection' ? 'connected app' : entry.kind === 'code' ? 'extension' : entry.kind)
55
-
56
- const SWITCH_OFF_PROJECT = 'Switch off for this project'
57
- const SWITCH_ON_PROJECT = 'Switch on for this project'
58
- const SWITCH_OFF_EVERYWHERE = 'Switch off everywhere'
59
- const SWITCH_ON_EVERYWHERE = 'Switch on everywhere'
60
- const TRUST = 'Trust its code'
61
- const UNTRUST = 'Stop trusting its code'
62
- const BACK = 'Back'
63
- const DONE = 'Done'
64
-
65
- /** What a person can do with one row. A whole plugin whose code waits for trust can be trusted here. */
66
- export function rowActions(row: MenuRow, projectId: string | null): string[] {
67
- const switchable = row.whole ? row.plugin.attachment !== null : true
68
- const actions: string[] = []
69
- if (switchable) {
70
- if (projectId) actions.push(row.on ? SWITCH_OFF_PROJECT : SWITCH_ON_PROJECT)
71
- actions.push(row.on ? SWITCH_OFF_EVERYWHERE : SWITCH_ON_EVERYWHERE)
72
- }
73
- if (row.whole && row.plugin.code) actions.push(row.plugin.trust === 'untrusted' ? TRUST : UNTRUST)
74
- return [...actions, BACK]
75
- }
76
-
77
- /**
78
- * Runs the command: list, pick a row, pick what to do, until the person is done. Nothing changes
79
- * without a choice made here, and trusting code asks once more with the files in view.
80
- */
81
- export async function runPluginsMenu(ui: MenuUi, call: MenuCall, projectId: string | null): Promise<void> {
82
- let changed = false
83
- for (;;) {
84
- const rows = menuRows(await call<Plugin[]>('plugins.list'), projectId)
85
- if (!rows.length) {
86
- ui.notify('There is nothing to switch or trust here yet.', 'info')
87
- return
88
- }
89
- const picked = await ui.select(`Plugins${changed ? ' (changes apply when this session restarts)' : ''}`, [...rows.map((row) => row.label), DONE])
90
- const row = rows.find((candidate) => candidate.label === picked)
91
- if (!row) break
92
- const action = await ui.select(`${row.plugin.title}: ${row.plugin.description || 'No description.'}`, rowActions(row, projectId))
93
- if (!action || action === BACK) continue
94
- try {
95
- if (action === TRUST || action === UNTRUST) {
96
- const code = row.plugin.code!
97
- if (action === TRUST) {
98
- const sure = await ui.confirm('Trust this code?', `${code.files.join('\n')}\n\nFingerprint ${code.hash.slice(0, 12)}. It runs inside the session and can do anything this app can, including reading your files and credentials.`)
99
- if (!sure) continue
100
- }
101
- await call(action === TRUST ? 'plugins.trust' : 'plugins.untrust', { hash: code.hash })
102
- } else {
103
- const on = action === SWITCH_ON_PROJECT || action === SWITCH_ON_EVERYWHERE
104
- await call(on ? 'plugins.attach' : 'plugins.detach', { id: row.id, everywhere: action === SWITCH_ON_EVERYWHERE || action === SWITCH_OFF_EVERYWHERE })
105
- }
106
- changed = true
107
- } catch (error) {
108
- ui.notify(error instanceof Error ? error.message : String(error), 'error')
109
- }
110
- }
111
- if (changed) ui.notify('Saved. It applies when this session restarts.', 'info')
112
- }
@@ -1,71 +0,0 @@
1
- import { chmodSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'
2
- import { createConnection } from 'node:net'
3
- import { tmpdir } from 'node:os'
4
- import { join } from 'node:path'
5
- import { describe, expect, it } from 'vitest'
6
-
7
- import { SessionSocket, socketPath } from './socket'
8
-
9
- const handlers = { memory: () => '', apps: async () => null }
10
-
11
- /** Runs `body` as if on another operating system; `process.platform` is read at call time. */
12
- function onPlatform<T>(platform: NodeJS.Platform, body: () => T): T {
13
- const original = Object.getOwnPropertyDescriptor(process, 'platform')!
14
- Object.defineProperty(process, 'platform', { value: platform })
15
- try {
16
- return body()
17
- } finally {
18
- Object.defineProperty(process, 'platform', original)
19
- }
20
- }
21
-
22
- describe('session socket path', () => {
23
- it('keeps the socket file in the state folder on Unix', () => {
24
- expect(onPlatform('darwin', () => socketPath('/tmp/state'))).toBe(join('/tmp/state', 'run', 'harness.sock'))
25
- })
26
-
27
- it('uses a named pipe on Windows, with a random name each time', () => {
28
- const first = onPlatform('win32', () => socketPath('C:\\Users\\someone\\.xingular-harness\\state'))
29
- const second = onPlatform('win32', () => socketPath('C:\\Users\\someone\\.xingular-harness\\state'))
30
- expect(first).toMatch(/^\\\\\.\\pipe\\xingular-harness-[0-9a-f]{24}$/)
31
- expect(second).not.toBe(first)
32
- })
33
- })
34
-
35
- describe('session socket', () => {
36
- it.skipIf(process.platform !== 'win32')('listens on a named pipe and answers a request on Windows', async () => {
37
- const socket = new SessionSocket(socketPath('unused'), handlers)
38
- await socket.listen()
39
- try {
40
- const reply = await new Promise<string>((resolve, reject) => {
41
- const client = createConnection(socket.path)
42
- let buffer = ''
43
- client.on('connect', () => client.write('{"token":"nope","call":"wiki.read"}\n'))
44
- client.on('data', (chunk) => (buffer += chunk.toString('utf8')))
45
- client.on('end', () => resolve(buffer))
46
- client.on('error', reject)
47
- })
48
- expect(JSON.parse(reply)).toMatchObject({ error: { code: 'unauthorized' } })
49
- } finally {
50
- await socket.close()
51
- }
52
- })
53
-
54
- it('names the folder and the user when the operating system refuses to create the socket', async () => {
55
- // Root can write anywhere, so the refusal cannot be produced there.
56
- if (process.platform === 'win32' || process.getuid?.() === 0) return
57
- const base = mkdtempSync(join(tmpdir(), 'sock-'))
58
- const run = join(base, 'run')
59
- mkdirSync(run)
60
- chmodSync(run, 0o500)
61
- try {
62
- await expect(new SessionSocket(join(run, 'harness.sock'), handlers).listen()).rejects.toMatchObject({
63
- code: 'session_socket_denied',
64
- message: expect.stringMatching(/could not be created \((?:EACCES|EPERM)\)\. .*mode 500; this process runs as uid \d+\./)
65
- })
66
- } finally {
67
- chmodSync(run, 0o700)
68
- rmSync(base, { recursive: true, force: true })
69
- }
70
- })
71
- })
@@ -1,221 +0,0 @@
1
- // The session socket: how a process the harness did not start in-process (the `pi` command in
2
- // a terminal, with its extension and the `xagent-wiki` / `xagent-mcp` commands) reaches the
3
- // session it belongs to. Owner-only Unix socket (a named pipe on Windows), newline-delimited JSON,
4
- // one request per connection. Each terminal session holds a random token bound to its caller, its
5
- // connected-apps grant, and its controller; the token stops working when the terminal ends.
6
- import { createHash, randomBytes } from 'node:crypto'
7
- import { chmodSync, mkdirSync, rmSync, statSync } from 'node:fs'
8
- import { createServer, type Server, type Socket } from 'node:net'
9
- import { tmpdir } from 'node:os'
10
- import { dirname, join } from 'node:path'
11
-
12
- import { log } from '../core/bus'
13
- import { HarnessError, toErrorShape } from '../core/errors'
14
- import { newId } from '../core/fs'
15
- import type { BrokerSession } from '../mcp/service'
16
- import type { CallerContext } from '../memory/caller'
17
-
18
- /** What a token stands for. */
19
- export interface SocketGrant {
20
- sessionId: string
21
- /** Who memory, Wiki, and recall calls are made as. The run is filled in while a turn is live. */
22
- caller: () => CallerContext
23
- /** The session's connected-apps grant, when it has one. */
24
- broker: BrokerSession | null
25
- /** Telemetry from the native process, and what to do when it hangs up mid-request. */
26
- terminal?: { accept(event: string, data: Record<string, unknown>): Promise<unknown>; disconnected(): void }
27
- }
28
-
29
- export interface SocketHandlers {
30
- /** `wiki.*`, `memory.*`, `recall.*`. */
31
- memory(caller: CallerContext, call: string, params: Record<string, unknown>): string
32
- /** `mcp.list`, `mcp.call`, `mcp.revision`, `tools.list`, `tools.call`. */
33
- apps(session: BrokerSession, call: string, params: Record<string, unknown>): Promise<unknown>
34
- /**
35
- * `plugins.*`. `control` is true only for the session's own extension, which holds a key the
36
- * session's shell never sees; anything that changes what loads needs it.
37
- */
38
- plugins?(grant: SocketGrant, call: string, params: Record<string, unknown>, control: boolean): Promise<unknown>
39
- }
40
-
41
- const MAX_REQUEST_BYTES = 1024 * 1024
42
- /** macOS refuses a socket path longer than 103 bytes. */
43
- const MAX_SOCKET_PATH = 100
44
-
45
- /**
46
- * Windows has no socket files for Node's `net`: it listens on a named pipe, which lives in a
47
- * machine-wide namespace. A random name keeps another local process from guessing it and standing
48
- * in front of the session; the token still decides what a caller may do.
49
- */
50
- export function socketPath(stateDir: string): string {
51
- if (process.platform === 'win32') return `\\\\.\\pipe\\xingular-harness-${randomBytes(12).toString('hex')}`
52
- const path = join(stateDir, 'run', 'harness.sock')
53
- if (Buffer.byteLength(path) <= MAX_SOCKET_PATH) return path
54
- return join(tmpdir(), `xh-${createHash('sha256').update(path).digest('hex').slice(0, 16)}.sock`)
55
- }
56
-
57
- /** A named pipe has no folder, file mode, or owner to check or clean up. */
58
- const isPipePath = (path: string): boolean => path.startsWith('\\\\.\\pipe\\')
59
-
60
- /** Names the folder and the user when the operating system refuses the socket, so the cause shows. */
61
- function refusedBind(path: string, error: unknown): unknown {
62
- const code = (error as { code?: unknown } | null)?.code
63
- if (code !== 'EACCES' && code !== 'EPERM') return error
64
- if (isPipePath(path)) {
65
- return new HarnessError(
66
- 'session_socket_denied',
67
- `The session pipe ${path} could not be created (${code}).`,
68
- 'Start the harness again from your own user session. If it keeps failing, report this code and the Windows version.'
69
- )
70
- }
71
- let folder: string
72
- try {
73
- const stat = statSync(dirname(path))
74
- folder = `${dirname(path)} is owned by uid ${stat.uid} with mode ${(stat.mode & 0o777).toString(8)}`
75
- } catch {
76
- folder = `${dirname(path)} could not be read`
77
- }
78
- const uid = process.getuid?.() ?? 'unknown'
79
- return new HarnessError(
80
- 'session_socket_denied',
81
- `The session socket ${path} could not be created (${code}). ${folder}; this process runs as uid ${uid}.`,
82
- 'Run the harness from your own terminal, as the user that owns its state folder, or choose a state folder you own with --state.'
83
- )
84
- }
85
-
86
- export class SessionSocket {
87
- private server: Server | null = null
88
- private listening: Promise<void> | null = null
89
- private readonly grants = new Map<string, SocketGrant>()
90
- /**
91
- * A second key per token, handed out once. The token is in the session's environment, where a
92
- * command the model runs can read it; this key is claimed by the session's extension as it
93
- * loads, before any model turn, and kept in its memory only.
94
- */
95
- private readonly controls = new Map<string, string>()
96
- private readonly clients = new Set<Socket>()
97
-
98
- constructor(
99
- readonly path: string,
100
- private readonly handlers: SocketHandlers
101
- ) {}
102
-
103
- issue(grant: SocketGrant): string {
104
- const token = `${newId()}${newId()}`.replaceAll('-', '')
105
- this.grants.set(token, grant)
106
- return token
107
- }
108
-
109
- revoke(token: string): void {
110
- this.grants.delete(token)
111
- this.controls.delete(token)
112
- }
113
-
114
- revokeSession(sessionId: string): void {
115
- for (const [token, grant] of this.grants) if (grant.sessionId === sessionId) this.revoke(token)
116
- }
117
-
118
- /** Runs one request line and returns the reply line's object. */
119
- async handle(line: string, connection?: { waiting: (grant: SocketGrant | null) => void }): Promise<{ result: unknown } | { error: unknown }> {
120
- try {
121
- let request: Record<string, unknown>
122
- try {
123
- request = JSON.parse(line) as Record<string, unknown>
124
- } catch {
125
- throw new HarnessError('invalid_request', 'The request is not JSON.')
126
- }
127
- const token = typeof request.token === 'string' ? request.token : ''
128
- const grant = this.grants.get(token)
129
- if (!grant) throw new HarnessError('unauthorized', 'This session token is not valid. It ends when its terminal session ends.')
130
- if (typeof request.event === 'string') {
131
- if (!grant.terminal) throw new HarnessError('unknown_method', 'This session has no terminal controller.')
132
- connection?.waiting(grant)
133
- try {
134
- return { result: (await grant.terminal.accept(request.event, (request.data ?? {}) as Record<string, unknown>)) ?? {} }
135
- } finally {
136
- connection?.waiting(null)
137
- }
138
- }
139
- const call = typeof request.call === 'string' ? request.call : ''
140
- const params = (request.params && typeof request.params === 'object' ? request.params : {}) as Record<string, unknown>
141
- if (['wiki.', 'memory.', 'recall.'].some((prefix) => call.startsWith(prefix))) return { result: this.handlers.memory(grant.caller(), call, params) }
142
- if (['mcp.', 'tools.'].some((prefix) => call.startsWith(prefix))) {
143
- if (!grant.broker) throw new HarnessError('mcp_unauthorized', 'Connected apps are not available to this session.')
144
- return { result: await this.handlers.apps(grant.broker, call, params) }
145
- }
146
- if (call === 'control.claim') {
147
- if (this.controls.has(token)) throw new HarnessError('unauthorized', "This session's control key was already claimed.")
148
- const key = `${newId()}${newId()}`.replaceAll('-', '')
149
- this.controls.set(token, key)
150
- return { result: { key } }
151
- }
152
- if (call.startsWith('plugins.') && this.handlers.plugins) {
153
- const key = this.controls.get(token)
154
- return { result: await this.handlers.plugins(grant, call, params, key !== undefined && request.control === key) }
155
- }
156
- throw new HarnessError('unknown_method', `Unknown call ${call}.`)
157
- } catch (error) {
158
- return { error: toErrorShape(error) }
159
- }
160
- }
161
-
162
- private serve(client: Socket): void {
163
- let buffer = ''
164
- let waiting: SocketGrant | null = null
165
- this.clients.add(client)
166
- client.on('error', () => {})
167
- client.once('close', () => {
168
- this.clients.delete(client)
169
- // A decision the native process was waiting on can no longer reach it.
170
- waiting?.terminal?.disconnected()
171
- })
172
- client.on('data', (chunk) => {
173
- buffer += chunk.toString('utf8')
174
- if (Buffer.byteLength(buffer) > MAX_REQUEST_BYTES) {
175
- client.destroy()
176
- return
177
- }
178
- const newline = buffer.indexOf('\n')
179
- if (newline < 0) return
180
- client.pause()
181
- void this.handle(buffer.slice(0, newline), { waiting: (grant) => void (waiting = grant) }).then((reply) => client.end(`${JSON.stringify(reply)}\n`))
182
- })
183
- }
184
-
185
- /** Binds the socket once; later calls wait for the same bind. */
186
- listen(): Promise<void> {
187
- this.listening ??= new Promise<void>((resolve, reject) => {
188
- if (!isPipePath(this.path)) {
189
- mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 })
190
- rmSync(this.path, { force: true })
191
- }
192
- const server = createServer((client) => this.serve(client))
193
- server.once('error', (error) => {
194
- this.listening = null
195
- reject(refusedBind(this.path, error))
196
- })
197
- server.listen(this.path, () => {
198
- if (!isPipePath(this.path)) {
199
- try {
200
- chmodSync(this.path, 0o600)
201
- } catch (error) {
202
- log('session socket permissions', error instanceof Error ? error.message : String(error))
203
- }
204
- }
205
- this.server = server
206
- resolve()
207
- })
208
- })
209
- return this.listening
210
- }
211
-
212
- async close(): Promise<void> {
213
- this.grants.clear()
214
- const server = this.server
215
- this.server = null
216
- this.listening = null
217
- for (const client of this.clients) client.destroy()
218
- if (server) await new Promise<void>((resolve) => server.close(() => resolve()))
219
- if (!isPipePath(this.path)) rmSync(this.path, { force: true })
220
- }
221
- }