@xingular/harness 0.1.6 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (593) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +60 -0
  4. package/README.md +265 -71
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +14842 -9445
  7. package/dist/sdk/accounts/accounts.d.ts +165 -0
  8. package/dist/sdk/accounts/accounts.js +730 -0
  9. package/dist/sdk/accounts/choices.d.ts +23 -0
  10. package/dist/sdk/accounts/choices.js +62 -0
  11. package/dist/sdk/accounts/env.d.ts +78 -0
  12. package/dist/sdk/accounts/env.js +294 -0
  13. package/dist/sdk/accounts/secrets.d.ts +16 -0
  14. package/dist/sdk/accounts/secrets.js +40 -0
  15. package/dist/sdk/accounts/store.d.ts +114 -0
  16. package/dist/sdk/accounts/store.js +255 -0
  17. package/dist/sdk/browser/config.d.ts +16 -0
  18. package/dist/sdk/browser/config.js +22 -0
  19. package/dist/sdk/browser/diagnostics.d.ts +4 -0
  20. package/dist/sdk/browser/diagnostics.js +38 -0
  21. package/dist/sdk/browser/index.d.ts +17 -0
  22. package/dist/sdk/browser/index.js +65 -0
  23. package/dist/sdk/browser/network.d.ts +10 -0
  24. package/dist/sdk/browser/network.js +59 -0
  25. package/dist/sdk/browser/session.d.ts +84 -0
  26. package/dist/sdk/browser/session.js +192 -0
  27. package/dist/sdk/browser/tools.d.ts +8 -0
  28. package/dist/sdk/browser/tools.js +329 -0
  29. package/dist/sdk/capabilities/api.d.ts +22 -0
  30. package/dist/sdk/capabilities/api.js +54 -0
  31. package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
  32. package/dist/sdk/capabilities/runSnapshot.js +47 -0
  33. package/dist/sdk/capabilities/types.d.ts +29 -0
  34. package/dist/sdk/capabilities/types.js +1 -0
  35. package/dist/sdk/cli.d.ts +2 -0
  36. package/dist/sdk/cli.js +142 -0
  37. package/dist/sdk/core/bus.d.ts +23 -0
  38. package/dist/sdk/core/bus.js +76 -0
  39. package/dist/sdk/core/caller.d.ts +22 -0
  40. package/dist/sdk/core/caller.js +16 -0
  41. package/dist/sdk/core/changes.d.ts +15 -0
  42. package/dist/sdk/core/changes.js +15 -0
  43. package/dist/sdk/core/effort.d.ts +2 -0
  44. package/dist/sdk/core/effort.js +1 -0
  45. package/dist/sdk/core/env.d.ts +18 -0
  46. package/dist/sdk/core/env.js +8 -0
  47. package/dist/sdk/core/errors.d.ts +15 -0
  48. package/dist/sdk/core/errors.js +24 -0
  49. package/dist/sdk/core/frontmatter.d.ts +12 -0
  50. package/dist/sdk/core/frontmatter.js +50 -0
  51. package/dist/sdk/core/fs.d.ts +18 -0
  52. package/dist/sdk/core/fs.js +106 -0
  53. package/dist/sdk/core/index.d.ts +24 -0
  54. package/dist/sdk/core/index.js +187 -0
  55. package/dist/sdk/core/path.d.ts +7 -0
  56. package/dist/sdk/core/path.js +79 -0
  57. package/dist/sdk/core/projects.d.ts +18 -0
  58. package/dist/sdk/core/projects.js +67 -0
  59. package/dist/sdk/core/secrets.d.ts +2 -0
  60. package/dist/sdk/core/secrets.js +5 -0
  61. package/dist/sdk/core/text.d.ts +7 -0
  62. package/dist/sdk/core/text.js +40 -0
  63. package/dist/sdk/doctor/checks.d.ts +5 -0
  64. package/dist/sdk/doctor/checks.js +208 -0
  65. package/dist/sdk/doctor/probe.d.ts +4 -0
  66. package/dist/sdk/doctor/probe.js +92 -0
  67. package/dist/sdk/doctor/service.d.ts +23 -0
  68. package/dist/sdk/doctor/service.js +144 -0
  69. package/dist/sdk/doctor/types.d.ts +141 -0
  70. package/dist/sdk/doctor/types.js +29 -0
  71. package/dist/sdk/harness.d.ts +133 -0
  72. package/dist/sdk/harness.js +299 -0
  73. package/dist/sdk/history/lessonPrompt.d.ts +2 -0
  74. package/dist/sdk/history/lessonPrompt.js +15 -0
  75. package/dist/sdk/history/lessons.d.ts +52 -0
  76. package/dist/sdk/history/lessons.js +173 -0
  77. package/dist/sdk/history/recall.d.ts +68 -0
  78. package/dist/sdk/history/recall.js +199 -0
  79. package/dist/sdk/history/trajectory.d.ts +7 -0
  80. package/dist/sdk/history/trajectory.js +216 -0
  81. package/dist/sdk/hub/catalog.json +123 -0
  82. package/dist/sdk/hub/cli.d.ts +7 -0
  83. package/dist/sdk/hub/cli.js +81 -0
  84. package/dist/sdk/hub/hub.d.ts +74 -0
  85. package/dist/sdk/hub/hub.js +474 -0
  86. package/dist/sdk/hub/schema.d.ts +280 -0
  87. package/dist/sdk/hub/schema.js +78 -0
  88. package/dist/sdk/index.d.ts +63 -0
  89. package/dist/sdk/index.js +48 -0
  90. package/dist/sdk/mcp/connections.d.ts +83 -0
  91. package/dist/sdk/mcp/connections.js +669 -0
  92. package/dist/sdk/mcp/manager.d.ts +26 -0
  93. package/dist/sdk/mcp/manager.js +124 -0
  94. package/dist/sdk/mcp/oauth.d.ts +35 -0
  95. package/dist/sdk/mcp/oauth.js +171 -0
  96. package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
  97. package/dist/sdk/mcp/scopeMigration.js +198 -0
  98. package/dist/sdk/mcp/service.d.ts +160 -0
  99. package/dist/sdk/mcp/service.js +510 -0
  100. package/dist/sdk/mcp/types.d.ts +131 -0
  101. package/dist/sdk/mcp/types.js +49 -0
  102. package/dist/sdk/pi/runtime.d.ts +13 -0
  103. package/dist/sdk/pi/runtime.js +31 -0
  104. package/dist/sdk/plugins/api.d.ts +66 -0
  105. package/dist/sdk/plugins/api.js +155 -0
  106. package/dist/sdk/plugins/attachments.d.ts +46 -0
  107. package/dist/sdk/plugins/attachments.js +111 -0
  108. package/dist/sdk/plugins/builtin.d.ts +6 -0
  109. package/dist/sdk/plugins/builtin.js +68 -0
  110. package/dist/sdk/plugins/catalogue.d.ts +29 -0
  111. package/dist/sdk/plugins/catalogue.js +196 -0
  112. package/dist/sdk/plugins/cli.d.ts +13 -0
  113. package/dist/sdk/plugins/cli.js +187 -0
  114. package/dist/sdk/plugins/discover.d.ts +42 -0
  115. package/dist/sdk/plugins/discover.js +115 -0
  116. package/dist/sdk/plugins/firstParty.d.ts +50 -0
  117. package/dist/sdk/plugins/firstParty.js +113 -0
  118. package/dist/sdk/plugins/hooks.d.ts +94 -0
  119. package/dist/sdk/plugins/hooks.js +162 -0
  120. package/dist/sdk/plugins/identity.d.ts +19 -0
  121. package/dist/sdk/plugins/identity.js +48 -0
  122. package/dist/sdk/plugins/install.d.ts +20 -0
  123. package/dist/sdk/plugins/install.js +110 -0
  124. package/dist/sdk/plugins/inventory.d.ts +22 -0
  125. package/dist/sdk/plugins/inventory.js +110 -0
  126. package/dist/sdk/plugins/manifest.d.ts +13 -0
  127. package/dist/sdk/plugins/manifest.js +56 -0
  128. package/dist/sdk/plugins/plugins.d.ts +104 -0
  129. package/dist/sdk/plugins/plugins.js +164 -0
  130. package/dist/sdk/plugins/runtime.d.ts +9 -0
  131. package/dist/sdk/plugins/runtime.js +95 -0
  132. package/dist/sdk/plugins/trust.d.ts +44 -0
  133. package/dist/sdk/plugins/trust.js +120 -0
  134. package/dist/sdk/plugins/types.d.ts +159 -0
  135. package/dist/sdk/plugins/types.js +7 -0
  136. package/dist/sdk/prompt/compile.d.ts +174 -0
  137. package/dist/sdk/prompt/compile.js +396 -0
  138. package/dist/sdk/refine/cli.d.ts +4 -0
  139. package/dist/sdk/refine/cli.js +186 -0
  140. package/dist/sdk/refine/demo.d.ts +21 -0
  141. package/dist/sdk/refine/demo.js +114 -0
  142. package/dist/sdk/refine/evidence.d.ts +55 -0
  143. package/dist/sdk/refine/evidence.js +330 -0
  144. package/dist/sdk/refine/host.d.ts +51 -0
  145. package/dist/sdk/refine/host.js +76 -0
  146. package/dist/sdk/refine/ledger.d.ts +48 -0
  147. package/dist/sdk/refine/ledger.js +76 -0
  148. package/dist/sdk/refine/library.d.ts +55 -0
  149. package/dist/sdk/refine/library.js +177 -0
  150. package/dist/sdk/refine/pi.d.ts +72 -0
  151. package/dist/sdk/refine/pi.js +248 -0
  152. package/dist/sdk/refine/prompts.d.ts +45 -0
  153. package/dist/sdk/refine/prompts.js +390 -0
  154. package/dist/sdk/refine/recursion.d.ts +113 -0
  155. package/dist/sdk/refine/recursion.js +258 -0
  156. package/dist/sdk/refine/runner.d.ts +81 -0
  157. package/dist/sdk/refine/runner.js +150 -0
  158. package/dist/sdk/refine/selection.d.ts +57 -0
  159. package/dist/sdk/refine/selection.js +251 -0
  160. package/dist/sdk/refine/service.d.ts +84 -0
  161. package/dist/sdk/refine/service.js +165 -0
  162. package/dist/sdk/refine/suite.d.ts +67 -0
  163. package/dist/sdk/refine/suite.js +174 -0
  164. package/dist/sdk/refine/trajectory.d.ts +9 -0
  165. package/dist/sdk/refine/trajectory.js +68 -0
  166. package/dist/sdk/refine/types.d.ts +77 -0
  167. package/dist/sdk/refine/types.js +10 -0
  168. package/dist/sdk/server/methods.d.ts +3 -0
  169. package/dist/sdk/server/methods.js +370 -0
  170. package/dist/sdk/server/remote.d.ts +19 -0
  171. package/dist/sdk/server/remote.js +84 -0
  172. package/dist/sdk/server/rpc.d.ts +20 -0
  173. package/dist/sdk/server/rpc.js +102 -0
  174. package/dist/sdk/server/serve.d.ts +10 -0
  175. package/dist/sdk/server/serve.js +18 -0
  176. package/dist/sdk/sessions/approvals.d.ts +47 -0
  177. package/dist/sdk/sessions/approvals.js +119 -0
  178. package/dist/sdk/sessions/continuation.d.ts +48 -0
  179. package/dist/sdk/sessions/continuation.js +85 -0
  180. package/dist/sdk/sessions/contracts.d.ts +534 -0
  181. package/dist/sdk/sessions/contracts.js +299 -0
  182. package/dist/sdk/sessions/extensionUi.d.ts +19 -0
  183. package/dist/sdk/sessions/extensionUi.js +64 -0
  184. package/dist/sdk/sessions/history.d.ts +16 -0
  185. package/dist/sdk/sessions/history.js +68 -0
  186. package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
  187. package/dist/sdk/sessions/lineageJoin.js +61 -0
  188. package/dist/sdk/sessions/planMode.d.ts +36 -0
  189. package/dist/sdk/sessions/planMode.js +84 -0
  190. package/dist/sdk/sessions/policy.d.ts +43 -0
  191. package/dist/sdk/sessions/policy.js +1 -0
  192. package/dist/sdk/sessions/pricing.d.ts +34 -0
  193. package/dist/sdk/sessions/pricing.js +40 -0
  194. package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
  195. package/dist/sdk/sessions/reasoningSummaries.js +61 -0
  196. package/dist/sdk/sessions/registry.d.ts +102 -0
  197. package/dist/sdk/sessions/registry.js +383 -0
  198. package/dist/sdk/sessions/runIndex.d.ts +21 -0
  199. package/dist/sdk/sessions/runIndex.js +65 -0
  200. package/dist/sdk/sessions/runStore.d.ts +66 -0
  201. package/dist/sdk/sessions/runStore.js +335 -0
  202. package/dist/sdk/sessions/runner.d.ts +213 -0
  203. package/dist/sdk/sessions/runner.js +589 -0
  204. package/dist/sdk/sessions/sessions.d.ts +140 -0
  205. package/dist/sdk/sessions/sessions.js +394 -0
  206. package/dist/sdk/sessions/subagentService.d.ts +41 -0
  207. package/dist/sdk/sessions/subagentService.js +247 -0
  208. package/dist/sdk/sessions/subagents.d.ts +50 -0
  209. package/dist/sdk/sessions/subagents.js +68 -0
  210. package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
  211. package/dist/sdk/terminal/accountsMenu.js +392 -0
  212. package/dist/sdk/terminal/cli.d.ts +20 -0
  213. package/dist/sdk/terminal/cli.js +121 -0
  214. package/dist/sdk/terminal/client.d.ts +15 -0
  215. package/dist/sdk/terminal/client.js +126 -0
  216. package/dist/sdk/terminal/control.d.ts +4 -0
  217. package/dist/sdk/terminal/control.js +25 -0
  218. package/dist/sdk/terminal/controller.d.ts +72 -0
  219. package/dist/sdk/terminal/controller.js +351 -0
  220. package/dist/sdk/terminal/hubMenu.d.ts +10 -0
  221. package/dist/sdk/terminal/hubMenu.js +34 -0
  222. package/dist/sdk/terminal/launch.d.ts +5 -0
  223. package/dist/sdk/terminal/launch.js +27 -0
  224. package/dist/sdk/terminal/logs.d.ts +14 -0
  225. package/dist/sdk/terminal/logs.js +59 -0
  226. package/dist/sdk/terminal/piExtension.d.ts +6 -0
  227. package/dist/sdk/terminal/piExtension.js +392 -0
  228. package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
  229. package/dist/sdk/terminal/pluginMenu.js +101 -0
  230. package/dist/sdk/terminal/socket.d.ts +70 -0
  231. package/dist/sdk/terminal/socket.js +256 -0
  232. package/dist/sdk/terminal/standalone.d.ts +18 -0
  233. package/dist/sdk/terminal/standalone.js +146 -0
  234. package/dist/sdk/terminal/terminals.d.ts +176 -0
  235. package/dist/sdk/terminal/terminals.js +767 -0
  236. package/dist/sdk/terminal/trajectory.d.ts +10 -0
  237. package/dist/sdk/terminal/trajectory.js +30 -0
  238. package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
  239. package/dist/sdk/terminal/tui/chrome.js +169 -0
  240. package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
  241. package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
  242. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -0
  243. package/dist/sdk/terminal/tui/commandPages.js +63 -0
  244. package/dist/sdk/terminal/tui/commands.d.ts +42 -0
  245. package/dist/sdk/terminal/tui/commands.js +276 -0
  246. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
  247. package/dist/sdk/terminal/tui/dialogGeometry.js +50 -0
  248. package/dist/sdk/terminal/tui/dialogs.d.ts +75 -0
  249. package/dist/sdk/terminal/tui/dialogs.js +363 -0
  250. package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
  251. package/dist/sdk/terminal/tui/keybindings.js +49 -0
  252. package/dist/sdk/terminal/tui/list.d.ts +73 -0
  253. package/dist/sdk/terminal/tui/list.js +196 -0
  254. package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
  255. package/dist/sdk/terminal/tui/modeChoices.js +70 -0
  256. package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
  257. package/dist/sdk/terminal/tui/modelPicker.js +155 -0
  258. package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
  259. package/dist/sdk/terminal/tui/mouse.js +3 -0
  260. package/dist/sdk/terminal/tui/page.d.ts +14 -0
  261. package/dist/sdk/terminal/tui/page.js +1 -0
  262. package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
  263. package/dist/sdk/terminal/tui/pageOverlay.js +145 -0
  264. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +54 -0
  265. package/dist/sdk/terminal/tui/pages/accountsPage.js +181 -0
  266. package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
  267. package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
  268. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +37 -0
  269. package/dist/sdk/terminal/tui/pages/doctorPage.js +145 -0
  270. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
  271. package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
  272. package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
  273. package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
  274. package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
  275. package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
  276. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
  277. package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
  278. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +55 -0
  279. package/dist/sdk/terminal/tui/pages/settingsPage.js +88 -0
  280. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +58 -0
  281. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +377 -0
  282. package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
  283. package/dist/sdk/terminal/tui/piAdapter.js +48 -0
  284. package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
  285. package/dist/sdk/terminal/tui/planMode.js +2 -0
  286. package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
  287. package/dist/sdk/terminal/tui/questionPicker.js +150 -0
  288. package/dist/sdk/terminal/tui/questions.d.ts +19 -0
  289. package/dist/sdk/terminal/tui/questions.js +42 -0
  290. package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
  291. package/dist/sdk/terminal/tui/runtime.js +441 -0
  292. package/dist/sdk/terminal/tui/search.d.ts +22 -0
  293. package/dist/sdk/terminal/tui/search.js +60 -0
  294. package/dist/sdk/terminal/tui/selection.d.ts +16 -0
  295. package/dist/sdk/terminal/tui/selection.js +16 -0
  296. package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
  297. package/dist/sdk/terminal/tui/sessionUi.js +30 -0
  298. package/dist/sdk/terminal/tui/settingsModel.d.ts +12 -0
  299. package/dist/sdk/terminal/tui/settingsModel.js +84 -0
  300. package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
  301. package/dist/sdk/terminal/tui/sideQuestion.js +197 -0
  302. package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
  303. package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
  304. package/dist/sdk/terminal/tui/status.d.ts +18 -0
  305. package/dist/sdk/terminal/tui/status.js +67 -0
  306. package/dist/sdk/terminal/tui/theme.d.ts +45 -0
  307. package/dist/sdk/terminal/tui/theme.js +176 -0
  308. package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
  309. package/dist/sdk/terminal/tui/treeModel.js +483 -0
  310. package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
  311. package/dist/sdk/terminal/tui/treePicker.js +251 -0
  312. package/dist/sdk/terminal/tui/ui.d.ts +47 -0
  313. package/dist/sdk/terminal/tui/ui.js +148 -0
  314. package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
  315. package/dist/sdk/terminal/tui/workingStatus.js +229 -0
  316. package/dist/sdk/tools/askUser.d.ts +6 -0
  317. package/dist/sdk/tools/askUser.js +74 -0
  318. package/dist/sdk/tools/checklist.d.ts +9 -0
  319. package/dist/sdk/tools/checklist.js +54 -0
  320. package/dist/sdk/tools/definitions.d.ts +30 -0
  321. package/dist/sdk/tools/definitions.js +117 -0
  322. package/dist/sdk/tools/dispatch.d.ts +16 -0
  323. package/dist/sdk/tools/dispatch.js +67 -0
  324. package/dist/sdk/tools/harnessTools.d.ts +6 -0
  325. package/dist/sdk/tools/harnessTools.js +20 -0
  326. package/dist/sdk/tools/sessionName.d.ts +7 -0
  327. package/dist/sdk/tools/sessionName.js +31 -0
  328. package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
  329. package/dist/sdk/tools/spawnSubagent.js +49 -0
  330. package/dist/sdk/tools/types.d.ts +48 -0
  331. package/dist/sdk/tools/types.js +1 -0
  332. package/dist/sdk/variant/components.d.ts +34 -0
  333. package/dist/sdk/variant/components.js +230 -0
  334. package/dist/sdk/variant/materialise.d.ts +66 -0
  335. package/dist/sdk/variant/materialise.js +81 -0
  336. package/dist/sdk/variant/migrate.d.ts +4 -0
  337. package/dist/sdk/variant/migrate.js +41 -0
  338. package/dist/sdk/variant/seed.d.ts +20 -0
  339. package/dist/sdk/variant/seed.js +116 -0
  340. package/dist/sdk/variant/store.d.ts +82 -0
  341. package/dist/sdk/variant/store.js +151 -0
  342. package/dist/sdk/variant/surface.d.ts +56 -0
  343. package/dist/sdk/variant/surface.js +81 -0
  344. package/dist/sdk/variant/trust.d.ts +27 -0
  345. package/dist/sdk/variant/trust.js +64 -0
  346. package/dist/sdk/variant/variant.d.ts +71 -0
  347. package/dist/sdk/variant/variant.js +331 -0
  348. package/dist/sdk/web/markdown.d.ts +10 -0
  349. package/dist/sdk/web/markdown.js +66 -0
  350. package/dist/sdk/web/safeRequest.d.ts +34 -0
  351. package/dist/sdk/web/safeRequest.js +175 -0
  352. package/dist/sdk/web/search.d.ts +53 -0
  353. package/dist/sdk/web/search.js +168 -0
  354. package/dist/sdk/web/text.d.ts +2 -0
  355. package/dist/sdk/web/text.js +7 -0
  356. package/dist/sdk/web/tools.d.ts +22 -0
  357. package/dist/sdk/web/tools.js +195 -0
  358. package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
  359. package/dist/sdk/wiki/notes.d.ts +68 -0
  360. package/dist/sdk/wiki/notes.js +297 -0
  361. package/dist/sdk/world/actions.d.ts +23 -0
  362. package/dist/sdk/world/actions.js +31 -0
  363. package/dist/sdk/world/cli.d.ts +12 -0
  364. package/dist/sdk/world/cli.js +166 -0
  365. package/dist/sdk/world/images.d.ts +20 -0
  366. package/dist/sdk/world/images.js +48 -0
  367. package/dist/sdk/world/untrusted.d.ts +12 -0
  368. package/dist/sdk/world/untrusted.js +20 -0
  369. package/dist/sdk/world/world.d.ts +65 -0
  370. package/dist/sdk/world/world.js +80 -0
  371. package/dist/terminal-opentui.js +13612 -0
  372. package/dist/terminal-pi.js +1170 -62
  373. package/docs/README.md +34 -0
  374. package/docs/architecture/00-overview.md +159 -0
  375. package/docs/architecture/01-extension-points.md +78 -0
  376. package/docs/architecture/02-sessions-and-runs.md +146 -0
  377. package/docs/architecture/03-variants.md +95 -0
  378. package/docs/architecture/04-prompt.md +102 -0
  379. package/docs/architecture/05-refinement.md +107 -0
  380. package/docs/architecture/06-plugins-and-capabilities.md +93 -0
  381. package/docs/architecture/07-tools-and-gate.md +88 -0
  382. package/docs/architecture/08-memory-and-history.md +94 -0
  383. package/docs/architecture/09-accounts-and-connectors.md +90 -0
  384. package/docs/architecture/10-server-protocol.md +84 -0
  385. package/docs/architecture/11-terminal.md +81 -0
  386. package/docs/architecture/12-storage.md +61 -0
  387. package/docs/architecture/13-world-tools.md +23 -0
  388. package/docs/architecture/README.md +114 -0
  389. package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
  390. package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
  391. package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
  392. package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
  393. package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
  394. package/docs/architecture/proposals/PROP-0006-run-checklist.md +68 -0
  395. package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
  396. package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
  397. package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
  398. package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
  399. package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
  400. package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
  401. package/docs/architecture/proposals/README.md +76 -0
  402. package/docs/decisions/ADR-0001-owned-terminal.md +87 -0
  403. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  404. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  405. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  406. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  407. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  408. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  409. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  410. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  411. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  412. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  413. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  414. package/docs/decisions/ADR-0013-doctor.md +27 -0
  415. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  416. package/docs/doctor.md +74 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  418. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  420. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  421. package/docs/features/README.md +20 -0
  422. package/docs/features/automations/README.md +41 -0
  423. package/docs/features/cores/README.md +39 -0
  424. package/docs/features/google-harness2/README.md +52 -0
  425. package/docs/features/integrations/README.md +40 -0
  426. package/docs/features/interfaces/README.md +29 -0
  427. package/docs/features/memory/README.md +28 -0
  428. package/docs/releases/1.0.0.md +40 -0
  429. package/docs/releases/README.md +36 -0
  430. package/docs/study/00-index.md +78 -0
  431. package/docs/study/arms/00-matrix.md +20 -0
  432. package/docs/study/arms/01-system-prompt.md +211 -0
  433. package/docs/study/arms/02-tools.md +79 -0
  434. package/docs/study/arms/03-subagents.md +90 -0
  435. package/docs/study/arms/04-skills.md +75 -0
  436. package/docs/study/arms/05-context-management.md +90 -0
  437. package/docs/study/arms/06-memory.md +90 -0
  438. package/docs/study/arms/07-governance.md +71 -0
  439. package/docs/study/arms/08-execution.md +69 -0
  440. package/docs/study/arms/09-observability.md +60 -0
  441. package/docs/study/arms/10-refinement.md +110 -0
  442. package/docs/study/btw-comparison.md +37 -0
  443. package/docs/study/feature-gap-review.md +42 -0
  444. package/docs/study/insights.md +123 -0
  445. package/docs/study/roadmap.md +72 -0
  446. package/docs/study/sources/claude-code.md +44 -0
  447. package/docs/study/sources/deepseek-harness.md +102 -0
  448. package/docs/study/sources/harness2.md +50 -0
  449. package/docs/study/sources/kimi-cli.md +42 -0
  450. package/docs/study/sources/omp.md +93 -0
  451. package/docs/study/sources/opencode.md +43 -0
  452. package/docs/study/sources/openhands.md +46 -0
  453. package/docs/study/sources/smolagents.md +40 -0
  454. package/docs/study/sources/swe-agent.md +34 -0
  455. package/docs/system-prompt-design.md +196 -0
  456. package/docs/terminal-tui.md +671 -0
  457. package/package.json +48 -12
  458. package/src/accounts/accounts.test.ts +0 -223
  459. package/src/accounts/accounts.ts +0 -522
  460. package/src/accounts/env.test.ts +0 -95
  461. package/src/accounts/env.ts +0 -338
  462. package/src/accounts/secrets.ts +0 -50
  463. package/src/accounts/store.ts +0 -338
  464. package/src/capabilities/api.ts +0 -75
  465. package/src/capabilities/runSnapshot.ts +0 -59
  466. package/src/capabilities/types.ts +0 -34
  467. package/src/cli.ts +0 -114
  468. package/src/core/bus.ts +0 -34
  469. package/src/core/changes.ts +0 -33
  470. package/src/core/env.ts +0 -27
  471. package/src/core/errors.ts +0 -32
  472. package/src/core/frontmatter.ts +0 -47
  473. package/src/core/fs.test.ts +0 -38
  474. package/src/core/fs.ts +0 -92
  475. package/src/core/index.ts +0 -193
  476. package/src/core/path.test.ts +0 -14
  477. package/src/core/path.ts +0 -79
  478. package/src/core/projects.ts +0 -90
  479. package/src/core/text.ts +0 -39
  480. package/src/harness.ts +0 -299
  481. package/src/index.ts +0 -70
  482. package/src/mcp/connections.ts +0 -614
  483. package/src/mcp/manager.ts +0 -130
  484. package/src/mcp/oauth.ts +0 -195
  485. package/src/mcp/scopeMigration.test.ts +0 -79
  486. package/src/mcp/scopeMigration.ts +0 -204
  487. package/src/mcp/service.test.ts +0 -376
  488. package/src/mcp/service.ts +0 -549
  489. package/src/mcp/types.ts +0 -108
  490. package/src/memory/api.test.ts +0 -82
  491. package/src/memory/api.ts +0 -289
  492. package/src/memory/blocks.test.ts +0 -78
  493. package/src/memory/blocks.ts +0 -406
  494. package/src/memory/caller.ts +0 -57
  495. package/src/memory/dispatch.ts +0 -59
  496. package/src/memory/facts.test.ts +0 -41
  497. package/src/memory/facts.ts +0 -248
  498. package/src/memory/graph.ts +0 -103
  499. package/src/memory/health.test.ts +0 -130
  500. package/src/memory/health.ts +0 -74
  501. package/src/memory/maintainer.ts +0 -272
  502. package/src/memory/maintenance.test.ts +0 -176
  503. package/src/memory/maintenance.ts +0 -330
  504. package/src/memory/migrate.ts +0 -79
  505. package/src/memory/operations.ts +0 -138
  506. package/src/memory/proposals.test.ts +0 -168
  507. package/src/memory/proposals.ts +0 -576
  508. package/src/memory/recall.test.ts +0 -104
  509. package/src/memory/recall.ts +0 -271
  510. package/src/memory/references.ts +0 -77
  511. package/src/memory/runContext.ts +0 -93
  512. package/src/memory/secrets.ts +0 -6
  513. package/src/memory/store.test.ts +0 -66
  514. package/src/memory/store.ts +0 -385
  515. package/src/memory/wiki.test.ts +0 -47
  516. package/src/memory/wiki.ts +0 -422
  517. package/src/memory/wikiIndex.test.ts +0 -88
  518. package/src/memory/wikiIndex.ts +0 -116
  519. package/src/plugins/api.ts +0 -181
  520. package/src/plugins/attachments.test.ts +0 -84
  521. package/src/plugins/attachments.ts +0 -141
  522. package/src/plugins/builtin.ts +0 -82
  523. package/src/plugins/catalogue.test.ts +0 -254
  524. package/src/plugins/catalogue.ts +0 -251
  525. package/src/plugins/cli.ts +0 -184
  526. package/src/plugins/discover.ts +0 -151
  527. package/src/plugins/firstParty.test.ts +0 -143
  528. package/src/plugins/firstParty.ts +0 -129
  529. package/src/plugins/hooks.test.ts +0 -250
  530. package/src/plugins/hooks.ts +0 -239
  531. package/src/plugins/identity.ts +0 -37
  532. package/src/plugins/install.test.ts +0 -107
  533. package/src/plugins/install.ts +0 -106
  534. package/src/plugins/inventory.ts +0 -123
  535. package/src/plugins/manifest.ts +0 -76
  536. package/src/plugins/plugins.test.ts +0 -205
  537. package/src/plugins/plugins.ts +0 -189
  538. package/src/plugins/proposal.ts +0 -121
  539. package/src/plugins/runtime.test.ts +0 -40
  540. package/src/plugins/runtime.ts +0 -82
  541. package/src/plugins/trust.ts +0 -142
  542. package/src/plugins/types.ts +0 -149
  543. package/src/prompt/compile.test.ts +0 -261
  544. package/src/prompt/compile.ts +0 -732
  545. package/src/server/methods.ts +0 -314
  546. package/src/server/remote.ts +0 -77
  547. package/src/server/rpc.ts +0 -116
  548. package/src/server/serve.ts +0 -28
  549. package/src/server/server.test.ts +0 -174
  550. package/src/sessions/approvals.ts +0 -118
  551. package/src/sessions/contracts.ts +0 -310
  552. package/src/sessions/conversation.test.ts +0 -150
  553. package/src/sessions/extensionSession.test.ts +0 -74
  554. package/src/sessions/extensionUi.test.ts +0 -65
  555. package/src/sessions/extensionUi.ts +0 -102
  556. package/src/sessions/history.ts +0 -51
  557. package/src/sessions/lineageJoin.ts +0 -75
  558. package/src/sessions/policy.ts +0 -32
  559. package/src/sessions/pricing.ts +0 -60
  560. package/src/sessions/reasoningSummaries.ts +0 -59
  561. package/src/sessions/registry.ts +0 -294
  562. package/src/sessions/runIndex.ts +0 -99
  563. package/src/sessions/runStore.test.ts +0 -152
  564. package/src/sessions/runStore.ts +0 -332
  565. package/src/sessions/runner.ts +0 -569
  566. package/src/sessions/runtimeResources.test.ts +0 -61
  567. package/src/sessions/sessions.test.ts +0 -455
  568. package/src/sessions/sessions.ts +0 -295
  569. package/src/skills/registry.test.ts +0 -104
  570. package/src/skills/registry.ts +0 -407
  571. package/src/terminal/cli.ts +0 -149
  572. package/src/terminal/client.ts +0 -74
  573. package/src/terminal/controller.ts +0 -227
  574. package/src/terminal/launch.test.ts +0 -34
  575. package/src/terminal/launch.ts +0 -88
  576. package/src/terminal/piExtension.ts +0 -210
  577. package/src/terminal/pluginControl.test.ts +0 -146
  578. package/src/terminal/pluginMenu.ts +0 -112
  579. package/src/terminal/socket.test.ts +0 -71
  580. package/src/terminal/socket.ts +0 -221
  581. package/src/terminal/standalone.test.ts +0 -130
  582. package/src/terminal/standalone.ts +0 -144
  583. package/src/terminal/terminal.test.ts +0 -330
  584. package/src/terminal/terminals.ts +0 -443
  585. package/src/tools/askUser.ts +0 -45
  586. package/src/tools/definitions.ts +0 -187
  587. package/src/tools/memoryTools.ts +0 -22
  588. package/src/tools/pluginPropose.ts +0 -41
  589. package/src/tools/types.ts +0 -39
  590. package/src/web/safeRequest.ts +0 -171
  591. package/src/web/text.ts +0 -53
  592. package/src/web/tools.ts +0 -134
  593. package/src/web/web.test.ts +0 -141
@@ -1,130 +0,0 @@
1
- import { EventEmitter } from 'node:events'
2
- import { createHash } from 'node:crypto'
3
- import { existsSync, mkdtempSync, rmSync } from 'node:fs'
4
- import { tmpdir } from 'node:os'
5
- import { join, resolve } from 'node:path'
6
- import type { ChildProcess, spawn as nodeSpawn } from 'node:child_process'
7
- import { afterEach, describe, expect, it, vi } from 'vitest'
8
-
9
- import { memorySecretStore } from '../accounts/secrets'
10
- import { createHarness, type Harness, type HarnessOptions } from '../harness'
11
- import { defaultAssets } from './terminals'
12
- import { parseStandaloneOptions, runStandaloneTerminal, standaloneArguments } from './standalone'
13
- import { socketPath } from './socket'
14
-
15
- const scratch: string[] = []
16
- const harnesses: Harness[] = []
17
-
18
- afterEach(async () => {
19
- for (const harness of harnesses.splice(0)) await harness.close()
20
- for (const path of scratch.splice(0)) rmSync(path, { recursive: true, force: true })
21
- vi.restoreAllMocks()
22
- })
23
-
24
- function temporaryDirectory(prefix: string): string {
25
- const path = mkdtempSync(join(tmpdir(), prefix))
26
- scratch.push(path)
27
- return path
28
- }
29
-
30
- function fakeSpawn(onSpawn: (program: string, args: string[], options: { cwd?: string; env?: NodeJS.ProcessEnv; stdio?: string }) => void, outcome: { code?: number; error?: Error } = {}): typeof nodeSpawn {
31
- return ((program: string, args: string[], options: { cwd?: string; env?: NodeJS.ProcessEnv; stdio?: string }) => {
32
- onSpawn(program, args, options)
33
- const child = new EventEmitter() as ChildProcess
34
- child.kill = vi.fn(() => true)
35
- queueMicrotask(() => {
36
- if (outcome.error) child.emit('error', outcome.error)
37
- else child.emit('exit', outcome.code ?? 0, null)
38
- })
39
- return child
40
- }) as unknown as typeof nodeSpawn
41
- }
42
-
43
- function harnessFactory(options: HarnessOptions): Harness {
44
- const harness = createHarness({ ...options, secrets: memorySecretStore(), piProgram: () => '/opt/pi/bin/pi' })
45
- harnesses.push(harness)
46
- return harness
47
- }
48
-
49
- describe('standalone terminal startup', () => {
50
- it('routes the no-command and terminal invocations to Pi, leaving host commands explicit', () => {
51
- expect(standaloneArguments([])).toEqual([])
52
- expect(standaloneArguments(['--data', '/tmp/data'])).toEqual(['--data', '/tmp/data'])
53
- expect(standaloneArguments(['terminal', '--state', '/tmp/state'])).toEqual(['--state', '/tmp/state'])
54
- expect(standaloneArguments(['serve', '--state', '/tmp/state'])).toBeNull()
55
- })
56
-
57
- it('uses a dedicated default data and state root and accepts path overrides', () => {
58
- expect(parseStandaloneOptions([], '/home/test', '/work/project')).toEqual({
59
- dataRoot: '/home/test/.xingular-harness/data',
60
- stateDir: '/home/test/.xingular-harness/state'
61
- })
62
- expect(parseStandaloneOptions(['--data', './knowledge', '--state', './device'], '/home/test', '/work/project')).toEqual({
63
- dataRoot: '/work/project/knowledge',
64
- stateDir: '/work/project/device'
65
- })
66
- expect(() => parseStandaloneOptions(['--data'])).toThrow('--data needs a directory path.')
67
- expect(() => parseStandaloneOptions(['--model', 'unknown'])).toThrow('Unknown standalone option: --model')
68
- })
69
-
70
- it('refuses default folders under a home that is not a folder path, and accepts explicit absolute folders', () => {
71
- expect(() => parseStandaloneOptions([], 'HOME', '/work/project')).toThrow('is not an absolute path')
72
- expect(parseStandaloneOptions(['--data', '/data', '--state', '/state'], 'HOME', '/work/project')).toEqual({ dataRoot: '/data', stateDir: '/state' })
73
- })
74
-
75
- it('starts Pi in the current directory, creates the first isolated account, and cleans up on exit', async () => {
76
- const home = temporaryDirectory('harness-standalone-')
77
- const cwd = temporaryDirectory('harness-cwd-')
78
- const paths = parseStandaloneOptions([], home)
79
- let invocation: { program: string; args: string[]; options: { cwd?: string; env?: NodeJS.ProcessEnv; stdio?: string } } | undefined
80
- const spawn = fakeSpawn((program, args, options) => {
81
- invocation = { program, args, options }
82
- })
83
-
84
- expect(await runStandaloneTerminal([], { home, cwd, stdinIsTTY: true, stdoutIsTTY: true, createSessionId: () => 'standalone', createHarness: harnessFactory, spawn })).toBe(0)
85
-
86
- const harness = harnesses.shift()!
87
- expect(harness.accounts.overview().accounts).toMatchObject([{ label: 'Default', isDefault: true }])
88
- expect(invocation?.program).toBe('/opt/pi/bin/pi')
89
- expect(invocation?.options).toMatchObject({ cwd, stdio: 'inherit' })
90
- expect(invocation?.args).toContain('--extension')
91
- expect(invocation?.args).toContain(defaultAssets().piExtension)
92
- expect(invocation?.args).toContain(join(paths.dataRoot, 'sessions', 'terminal', createHash('sha256').update(resolve(cwd)).digest('hex'), 'pi'))
93
- expect(invocation?.options.env?.PI_CODING_AGENT_DIR).toContain(join(paths.stateDir, 'accounts'))
94
- expect(invocation?.options.env?.XINGULAR_HARNESS_SOCKET).toBeTruthy()
95
- expect(invocation?.options.env?.XINGULAR_HARNESS_TOKEN).toBeTruthy()
96
- expect(existsSync(join(paths.stateDir, 'accounts', harness.accounts.overview().accounts[0].id, 'home', 'pi', 'auth.json'))).toBe(false)
97
- expect(existsSync(socketPath(paths.stateDir))).toBe(false)
98
- expect(harness.terminals.has('standalone')).toBe(false)
99
- })
100
-
101
- it('requires an interactive TTY before creating Harness data', async () => {
102
- const create = vi.fn(harnessFactory)
103
- await expect(runStandaloneTerminal([], { stdinIsTTY: false, stdoutIsTTY: true, createHarness: create })).rejects.toThrow('needs a TTY')
104
- expect(create).not.toHaveBeenCalled()
105
- })
106
-
107
- it('cleans up the prepared terminal when Pi cannot be spawned', async () => {
108
- const home = temporaryDirectory('harness-standalone-fail-')
109
- const cwd = temporaryDirectory('harness-cwd-fail-')
110
- const spawn = fakeSpawn(() => undefined, { error: new Error('spawn failed') })
111
-
112
- await expect(runStandaloneTerminal([], { home, cwd, stdinIsTTY: true, stdoutIsTTY: true, createSessionId: () => 'failed', createHarness: harnessFactory, spawn })).rejects.toThrow('spawn failed')
113
-
114
- const harness = harnesses.shift()!
115
- const account = harness.accounts.overview().accounts[0]
116
- expect(existsSync(join(harness.accounts.dir, account.id, 'home', 'pi', 'auth.json'))).toBe(false)
117
- expect(existsSync(socketPath(harness.stateDir))).toBe(false)
118
- expect(harness.terminals.has('failed')).toBe(false)
119
- })
120
-
121
- it('explains a missing Pi executable in terms of the terminal launch', async () => {
122
- const home = temporaryDirectory('harness-standalone-enoent-')
123
- const cwd = temporaryDirectory('harness-cwd-enoent-')
124
- const error = Object.assign(new Error('spawn /opt/pi/bin/pi ENOENT'), { code: 'ENOENT' })
125
- const spawn = fakeSpawn(() => undefined, { error })
126
-
127
- await expect(runStandaloneTerminal([], { home, cwd, stdinIsTTY: true, stdoutIsTTY: true, createSessionId: () => 'missing-pi', createHarness: harnessFactory, spawn }))
128
- .rejects.toThrow(/Could not start Pi terminal.*Pi executable.*\/opt\/pi\/bin\/pi/)
129
- })
130
- })
@@ -1,144 +0,0 @@
1
- // The standalone entry point for people using the harness directly. Pi owns the interface;
2
- // the harness prepares the isolated account, context, extension, and session socket.
3
- import { spawn as nodeSpawn } from 'node:child_process'
4
- import { createHash, randomUUID } from 'node:crypto'
5
- import { homedir } from 'node:os'
6
- import { isAbsolute, join, resolve } from 'node:path'
7
-
8
- import { createHarness, type Harness, type HarnessOptions } from '../harness'
9
- import type { TerminalLaunch } from './terminals'
10
-
11
- export interface StandalonePaths {
12
- dataRoot: string
13
- stateDir: string
14
- }
15
-
16
- export interface StandaloneDependencies {
17
- home?: string
18
- cwd?: string
19
- stdinIsTTY?: boolean
20
- stdoutIsTTY?: boolean
21
- createSessionId?: () => string
22
- createHarness?: (options: HarnessOptions) => Harness
23
- spawn?: typeof nodeSpawn
24
- }
25
-
26
- export function standaloneArguments(argv: string[]): string[] | null {
27
- const command = argv[0]
28
- if (!command || command.startsWith('--') || command === '-h') return argv
29
- return command === 'terminal' ? argv.slice(1) : null
30
- }
31
-
32
- export function parseStandaloneOptions(argv: string[], home = homedir(), cwd = process.cwd()): StandalonePaths {
33
- const root = join(home, '.xingular-harness')
34
- const paths: StandalonePaths = {
35
- dataRoot: join(root, 'data'),
36
- stateDir: join(root, 'state')
37
- }
38
-
39
- const given = new Set<string>()
40
- for (let index = 0; index < argv.length; index += 1) {
41
- const argument = argv[index]
42
- if (argument !== '--data' && argument !== '--state') throw new Error(`Unknown standalone option: ${argument}`)
43
- const value = argv[index + 1]
44
- if (!value || value.startsWith('--')) throw new Error(`${argument} needs a directory path.`)
45
- paths[argument === '--data' ? 'dataRoot' : 'stateDir'] = resolve(cwd, value)
46
- given.add(argument)
47
- index += 1
48
- }
49
-
50
- // A home that is not a folder path (for example HOME set to the word "HOME") would put the
51
- // defaults, and the session socket, in whatever folder the command was started from.
52
- if (!isAbsolute(home) && !(given.has('--data') && given.has('--state'))) {
53
- throw new Error(`The home folder "${home}" is not an absolute path, so the default data and state folders cannot be placed. Set HOME to your home folder, or pass --data and --state with absolute folders.`)
54
- }
55
-
56
- return paths
57
- }
58
-
59
- function processEnvironment(overrides: Record<string, string | null>): NodeJS.ProcessEnv {
60
- const environment = { ...process.env }
61
- for (const [name, value] of Object.entries(overrides)) {
62
- if (value === null) delete environment[name]
63
- else environment[name] = value
64
- }
65
- return environment
66
- }
67
-
68
- function exitCode(code: number | null, signal: NodeJS.Signals | null): number {
69
- if (code !== null) return code
70
- if (signal === 'SIGINT') return 130
71
- if (signal === 'SIGTERM') return 143
72
- if (signal === 'SIGHUP') return 129
73
- return 1
74
- }
75
-
76
- function spawnError(error: Error, launch: TerminalLaunch): Error {
77
- const code = (error as NodeJS.ErrnoException).code
78
- if (code !== 'ENOENT' && code !== 'EACCES' && code !== 'EPERM') return error
79
- if (launch.program === process.execPath || launch.env.XINGULAR_HARNESS_NODE === launch.program) {
80
- return new Error(`Could not start the Pi terminal because Node could not run "${launch.args[0] ?? 'the bundled Pi CLI'}" (${code}). Verify Node and the bundled Pi package are installed.`, { cause: error })
81
- }
82
- const problem = code === 'ENOENT' ? 'was not found' : `could not start (${code})`
83
- return new Error(`Could not start Pi terminal. Pi executable "${launch.program}" ${problem}; verify it is installed and executable or check the configured terminal executable.`, { cause: error })
84
- }
85
-
86
- function spawnPi(launch: TerminalLaunch, cwd: string, spawn = nodeSpawn): Promise<number> {
87
- return new Promise((resolveExit, reject) => {
88
- const child = spawn(launch.program, launch.args, {
89
- cwd,
90
- env: processEnvironment(launch.env),
91
- stdio: 'inherit'
92
- })
93
- let settled = false
94
- const cleanup = (): void => {
95
- process.off('SIGINT', onInterrupt)
96
- process.off('SIGTERM', onTerminate)
97
- process.off('SIGHUP', onHangup)
98
- }
99
- const finish = (action: () => void): void => {
100
- if (settled) return
101
- settled = true
102
- cleanup()
103
- action()
104
- }
105
- // Ctrl+C is delivered to both processes in the foreground process group. Keep this host
106
- // alive while Pi handles it so the account credentials and harness socket are cleaned up.
107
- const onInterrupt = (): void => undefined
108
- const onTerminate = (): void => {
109
- child.kill('SIGTERM')
110
- }
111
- const onHangup = (): void => undefined
112
-
113
- process.on('SIGINT', onInterrupt)
114
- process.on('SIGTERM', onTerminate)
115
- process.on('SIGHUP', onHangup)
116
- child.once('error', (error) => finish(() => reject(spawnError(error, launch))))
117
- child.once('exit', (code, signal) => finish(() => resolveExit(exitCode(code, signal))))
118
- })
119
- }
120
-
121
- export async function runStandaloneTerminal(argv: string[], dependencies: StandaloneDependencies = {}): Promise<number> {
122
- if (!(dependencies.stdinIsTTY ?? process.stdin.isTTY) || !(dependencies.stdoutIsTTY ?? process.stdout.isTTY)) {
123
- throw new Error('The interactive Harness terminal needs a TTY. Run it from a terminal, or use `xingular-harness serve` for a host process.')
124
- }
125
-
126
- const cwd = resolve(dependencies.cwd ?? process.cwd())
127
- const paths = parseStandaloneOptions(argv, dependencies.home, cwd)
128
- const makeHarness = dependencies.createHarness ?? createHarness
129
- const harness = makeHarness({ dataRoot: paths.dataRoot, stateDir: paths.stateDir, productName: 'Xingular Harness' })
130
- const sessionId = (dependencies.createSessionId ?? randomUUID)()
131
-
132
- try {
133
- await harness.ready
134
- if (harness.accounts.overview().accounts.length === 0) harness.accounts.create('Default', 'subscription')
135
-
136
- const cwdHash = createHash('sha256').update(cwd).digest('hex')
137
- const sessionFolder = join(paths.dataRoot, 'sessions', 'terminal', cwdHash)
138
- const launch = await harness.terminals.prepare({ sessionId, cwd, sessionFolder })
139
- return await spawnPi(launch, cwd, dependencies.spawn)
140
- } finally {
141
- await harness.terminals.dispose(sessionId)
142
- await harness.close()
143
- }
144
- }
@@ -1,330 +0,0 @@
1
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
2
- import { spawnSync } from 'node:child_process'
3
- import { connect } from 'node:net'
4
- import { tmpdir } from 'node:os'
5
- import { join } from 'node:path'
6
- import { afterEach, describe, expect, it, vi } from 'vitest'
7
-
8
- import { memorySecretStore } from '../accounts/secrets'
9
- import { createHarness, type Harness } from '../harness'
10
- import type { RunEvent } from '../sessions/contracts'
11
- import type { ToolPolicy } from '../sessions/policy'
12
- import { loadRun } from '../sessions/runStore'
13
- import type { Found } from '../plugins/discover'
14
- import { rootWithProject, writeFile } from '../../tests/helpers'
15
- import { parseCli } from './cli'
16
- import { SOCKET_ENV, TOKEN_ENV, socketCall, type SocketConnection } from './client'
17
- import { SessionSocket } from './socket'
18
-
19
- const open: Harness[] = []
20
- afterEach(async () => {
21
- vi.useRealTimers()
22
- for (const harness of open.splice(0)) await harness.close()
23
- })
24
-
25
- async function setup(policy: ToolPolicy = {}) {
26
- const root = rootWithProject()
27
- const harness = createHarness({ dataRoot: root, stateDir: mkdtempSync(join(tmpdir(), 'hs-')), secrets: memorySecretStore(), policy, piProgram: () => '/opt/pi/bin/pi', assets: { node: '/opt/node', cli: '/opt/harness/cli.js', piExtension: '/opt/harness/terminal-pi.js' } })
28
- const legacyBin = join(harness.stateDir, 'run', 'bin')
29
- mkdirSync(legacyBin, { recursive: true })
30
- writeFileSync(join(legacyBin, 'agentx-wiki'), 'old wrapper')
31
- writeFileSync(join(legacyBin, 'agentx-mcp'), 'old wrapper')
32
- open.push(harness)
33
- const account = harness.accounts.create('Main', 'apiKey').accounts[0]
34
- const events: RunEvent[] = []
35
- const notices: Record<string, unknown>[] = []
36
- harness.runs.listen((event) => void events.push(event))
37
- harness.bus.on((notice) => void notices.push(notice))
38
- const sessionFolder = join(root, 'sessions', 'p1', 'term-1')
39
- const launch = await harness.terminals.prepare({ sessionId: 'term-1', accountId: account.id, projectId: 'p1', cwd: root, sessionFolder, model: 'chosen-model', launch: { connections: 'Use mcp_list_tools.' } })
40
- const connection: SocketConnection = { socket: String(launch.env[SOCKET_ENV]), token: String(launch.env[TOKEN_ENV]) }
41
- /** One telemetry line, as the native extension sends it. */
42
- const tell = (event: string, data: Record<string, unknown> = {}) =>
43
- new Promise<any>((resolve, reject) => {
44
- const stream = connect(connection.socket)
45
- let buffer = ''
46
- stream.on('connect', () => stream.write(`${JSON.stringify({ token: connection.token, event, data })}\n`))
47
- stream.on('data', (chunk) => {
48
- buffer += chunk.toString()
49
- if (!buffer.includes('\n')) return
50
- const reply = JSON.parse(buffer.slice(0, buffer.indexOf('\n')))
51
- stream.end()
52
- if (reply.error) reject(new Error(reply.error.message))
53
- else resolve(reply.result)
54
- })
55
- stream.on('error', reject)
56
- })
57
- return { harness, root, account, events, notices, launch, connection, tell, sessionFolder }
58
- }
59
-
60
- describe('a pi terminal session', () => {
61
- it('launches on the pinned account with compiled instructions, the extension, and the session socket', async () => {
62
- const { launch, account, harness, sessionFolder, root } = await setup()
63
- expect(launch.program).toBe('/opt/pi/bin/pi')
64
- expect(launch.accountId).toBe(account.id)
65
- expect(launch.args[0]).toBe('--append-system-prompt')
66
- expect(launch.args[1]).toContain('# Xingular Harness context')
67
- expect(launch.args[1]).toContain('xagent-wiki')
68
- // Pi's own discovery is off; its command's built-in extensions are named, and the harness's comes last.
69
- expect(launch.args.slice(2)).toEqual([
70
- '--model', 'chosen-model', '--no-extensions', '--no-skills', '--no-prompt-templates', '--no-themes',
71
- '--extension', 'builtin:llama.cpp', '--extension', 'builtin:codemode', '--extension', 'builtin:tool-search', '--extension', 'builtin:mcp',
72
- '--extension', '/opt/harness/terminal-pi.js', '--session-dir', join(sessionFolder, 'pi')
73
- ])
74
- expect(launch.env.PI_CODING_AGENT_DIR).toBe(join(harness.accounts.dir, account.id, 'home', 'pi'))
75
- expect(String(launch.env.PATH).split(':')[0]).toBe(join(harness.stateDir, 'run', 'bin'))
76
- expect(readFileSync(join(harness.stateDir, 'run', 'bin', 'xagent-wiki'), 'utf8')).toBe("#!/bin/sh\nexec '/opt/node' '/opt/harness/cli.js' wiki \"$@\"\n")
77
- expect(readFileSync(join(harness.stateDir, 'run', 'bin', 'xagent-mcp'), 'utf8')).toContain("'/opt/harness/cli.js' mcp")
78
- expect(existsSync(join(harness.stateDir, 'run', 'bin', 'agentx-wiki'))).toBe(false)
79
- expect(existsSync(join(harness.stateDir, 'run', 'bin', 'agentx-mcp'))).toBe(false)
80
- // The session keeps the pack it started with.
81
- expect(JSON.parse(readFileSync(join(sessionFolder, 'context.json'), 'utf8')).profile).toBe('session')
82
- expect(root).toBeTruthy()
83
- })
84
-
85
- it.skipIf(process.platform !== 'win32')('starts the resolved Pi CLI through Node without a model or interactive terminal', async () => {
86
- const root = rootWithProject()
87
- const stateDir = mkdtempSync(join(tmpdir(), 'hs-pi-smoke-'))
88
- const harness = createHarness({ dataRoot: root, stateDir, secrets: memorySecretStore() })
89
- open.push(harness)
90
- harness.accounts.create('Main', 'subscription')
91
- const launch = await harness.terminals.prepare({ sessionId: 'pi-smoke', cwd: root, sessionFolder: join(root, 'sessions', 'pi-smoke') })
92
- const cli = launch.args[0]
93
- const pathKeys = Object.keys(launch.env).filter((name) => name.toLowerCase() === 'path')
94
-
95
- expect(launch.program).toBe(process.execPath)
96
- expect(pathKeys).toHaveLength(1)
97
- expect(launch.env[pathKeys[0]]).toContain(';')
98
- expect(launch.env.XINGULAR_HARNESS_NODE).toBe(process.execPath)
99
- expect(readFileSync(join(stateDir, 'run', 'bin', 'xagent-wiki.cmd'), 'utf8')).toContain(' wiki %*\r\n')
100
- const result = spawnSync(launch.program, [cli, '--help'], { cwd: root, encoding: 'utf8', timeout: 20_000 })
101
- expect(result.error).toBeUndefined()
102
- expect(result.status).toBe(0)
103
- expect(`${result.stdout}${result.stderr}`).toMatch(/usage|options|pi coding agent/i)
104
- })
105
-
106
- it('passes what the harness found as paths, the enabled registry items with them, and its own extension last', async () => {
107
- const root = rootWithProject()
108
- writeFile(join(root, 'registry/skills/release/SKILL.md'), '# Release\n')
109
- writeFile(join(root, 'registry/prompts/review.md'), 'Review this.\n')
110
- writeFile(join(root, 'config/registry-enabled.json'), JSON.stringify({ p1: ['skills/release', 'prompts/review'] }))
111
- writeFile(join(root, '.pi/extensions/local.ts'), 'export default function () {}\n')
112
- const item = (kind: Found['kind'], path: string, origin: Found['origin'], enabled = true): Found => ({ kind, path, origin, project: origin === 'project', packageRoot: null, source: null, enabled })
113
- const found = [
114
- item('extension', join(root, '.pi/extensions/local.ts'), 'project'),
115
- item('extension', '/shared/extensions/mine.ts', 'shared'),
116
- item('extension', '/shared/extensions/off.ts', 'shared', false),
117
- item('extension', 'builtin:mcp', 'builtin'),
118
- item('skill', '/shared/skills/alpha/SKILL.md', 'shared'),
119
- item('prompt', '/shared/prompts/p.md', 'shared'),
120
- item('theme', '/shared/themes/dark.json', 'shared')
121
- ]
122
- const harness = createHarness({ dataRoot: root, stateDir: mkdtempSync(join(tmpdir(), 'hs-')), secrets: memorySecretStore(), piProgram: () => '/opt/pi/bin/pi', assets: { node: '/opt/node', cli: '/opt/harness/cli.js', piExtension: '/opt/harness/terminal-pi.js' }, resolver: async () => found })
123
- open.push(harness)
124
- const account = harness.accounts.create('Main', 'apiKey').accounts[0]
125
- const prepare = async () => (await harness.terminals.prepare({ sessionId: 'term-1', accountId: account.id, projectId: 'p1', cwd: root, sessionFolder: join(root, 'sessions', 'p1', 'term-1') })).args.slice(2)
126
-
127
- const loaded = [
128
- '--extension', '/shared/extensions/mine.ts', '--extension', 'builtin:mcp',
129
- '--skill', join(root, 'registry/skills/release/SKILL.md'), '--skill', '/shared/skills/alpha/SKILL.md',
130
- '--prompt-template', join(root, 'registry/prompts/review.md'), '--prompt-template', '/shared/prompts/p.md',
131
- '--theme', '/shared/themes/dark.json',
132
- '--extension', '/opt/harness/terminal-pi.js', '--session-dir', join(root, 'sessions', 'p1', 'term-1', 'pi')
133
- ]
134
- const flags = ['--no-extensions', '--no-skills', '--no-prompt-templates', '--no-themes']
135
- expect(await prepare()).toEqual([...flags, ...loaded])
136
-
137
- // The working folder's own code joins only once a person trusted it.
138
- const code = (await harness.plugins.loading({ cwd: root, agentDir: join(harness.accounts.dir, account.id, 'home', 'pi') })).projectCode!
139
- harness.plugins.trust.grant(code, root)
140
- expect(await prepare()).toEqual([...flags, '--extension', join(root, '.pi/extensions/local.ts'), ...loaded])
141
- })
142
-
143
- it('refuses to launch without the pi command, and never on another account', async () => {
144
- const harness = createHarness({ dataRoot: rootWithProject(), stateDir: mkdtempSync(join(tmpdir(), 'hs-')), secrets: memorySecretStore(), piProgram: () => null })
145
- open.push(harness)
146
- harness.accounts.create('Main', 'apiKey')
147
- await expect(harness.terminals.prepare({ sessionId: 's', cwd: '/tmp', sessionFolder: join(harness.env.root, 'sessions', 's') })).rejects.toMatchObject({ code: 'harness_unavailable' })
148
- const other = createHarness({ dataRoot: rootWithProject(), stateDir: mkdtempSync(join(tmpdir(), 'hs-')), secrets: memorySecretStore(), piProgram: () => '/opt/pi' })
149
- open.push(other)
150
- other.accounts.create('Main', 'apiKey')
151
- await expect(other.terminals.prepare({ sessionId: 's', accountId: 'missing-account', cwd: '/tmp', sessionFolder: join(other.env.root, 'sessions', 's') })).rejects.toThrow()
152
- expect(other.terminals.has('s')).toBe(false)
153
- })
154
-
155
- it('records what the person typed as a run and follows it to the end', async () => {
156
- const { tell, events, harness, root, notices } = await setup()
157
- await tell('startup', { phase: 'Pi extension loaded' })
158
- await tell('ready', { nativeSessionId: '/history/native.jsonl' })
159
- expect(notices).toContainEqual({ type: 'terminal.native', sessionId: 'term-1', nativeSessionId: '/history/native.jsonl' })
160
- await tell('begin', { text: 'Fix the build' })
161
- const runId = events[0].runId
162
- expect(loadRun(root, runId)).toMatchObject({ mode: 'code', harness: 'pi', sessionType: 'terminal', sessionId: 'term-1', projectId: 'p1', goal: 'Fix the build', nativeSessionId: '/history/native.jsonl' })
163
- await tell('tool', { phase: 'start', id: 't1', name: 'read', summary: '{"path":"a"}' })
164
- await tell('tool', { phase: 'end', id: 't1', name: 'read', ok: true, durationMs: 4, resultChars: 12 })
165
- await tell('message', { text: 'Done.' })
166
- await tell('usage', { inputTokens: 5, outputTokens: 2, cacheReadTokens: 0, cacheWriteTokens: 0, requests: 1 })
167
- await tell('settled', {})
168
- expect(events.map((event) => event.type)).toEqual(['started', 'status.changed', 'message.completed', 'tool.started', 'tool.completed', 'message.completed', 'usage.updated', 'completed'])
169
- expect(loadRun(root, runId).status).toBe('completed')
170
- expect(harness.terminals.state('term-1')).toEqual({ ready: true, dirty: false, active: false })
171
- // The run has the pack its session started with.
172
- expect(JSON.parse(readFileSync(join(root, 'runs', runId, 'context.json'), 'utf8')).runId).toBe(runId)
173
- })
174
-
175
- it('delivers an instruction through the extension and reserves its run first', async () => {
176
- const { tell, harness, root, events } = await setup()
177
- await tell('ready', {})
178
- const sent = harness.terminals.send({ sessionId: 'term-1', runId: 'reserved', text: 'Run the tests' })
179
- await vi.waitFor(async () => expect(await tell('poll')).toEqual({ command: { type: 'send', text: 'Run the tests' } }))
180
- expect(loadRun(root, 'reserved')).toMatchObject({ status: 'queued', goal: 'Run the tests' })
181
- await tell('begin', { text: 'Run the tests' })
182
- expect(await sent).toEqual({ runId: 'reserved' })
183
- expect(events[0]).toMatchObject({ runId: 'reserved', type: 'started' })
184
- await expect(harness.terminals.send({ sessionId: 'term-1', text: 'Another' })).rejects.toMatchObject({ code: 'session_busy' })
185
- await harness.runs.interrupt('reserved')
186
- expect(await tell('poll')).toEqual({ command: { type: 'interrupt' } })
187
- expect(loadRun(root, 'reserved').status).toBe('interrupted')
188
- })
189
-
190
- it('sends a memory block that changed since the session started along with the next instruction', async () => {
191
- const { tell, harness, connection } = await setup()
192
- await tell('ready', {})
193
- await socketCall(connection, 'memory.append', { block: 'project', text: 'Prefers pnpm.' })
194
- const first = harness.terminals.send({ sessionId: 'term-1', text: 'Continue' })
195
- let delivered = ''
196
- await vi.waitFor(async () => {
197
- const { command } = await tell('poll')
198
- expect(command?.type).toBe('send')
199
- delivered = command.text
200
- })
201
- await tell('begin', { text: delivered })
202
- await first
203
- expect(delivered.startsWith('[Memory updated since this session')).toBe(true)
204
- expect(delivered).toContain('Prefers pnpm.')
205
- expect(delivered.endsWith('\n\nContinue')).toBe(true)
206
- })
207
-
208
- it('will not send over a draft the person is typing, and fails a delivery the native session never acknowledges', async () => {
209
- const { tell, harness, root } = await setup()
210
- await tell('ready', {})
211
- harness.terminals.input('term-1', 'half a thought')
212
- await expect(harness.terminals.send({ sessionId: 'term-1', runId: 'draft', text: 'Task' })).rejects.toMatchObject({ code: 'terminal_has_draft' })
213
- expect(loadRun(root, 'draft').status).toBe('failed')
214
- harness.terminals.input('term-1', '\u0015')
215
- vi.useFakeTimers()
216
- const send = harness.terminals.send({ sessionId: 'term-1', runId: 'lost', text: 'Task' })
217
- const rejected = expect(send).rejects.toMatchObject({ code: 'delivery_uncertain' })
218
- await vi.advanceTimersByTimeAsync(25_001)
219
- await rejected
220
- vi.useRealTimers()
221
- expect(loadRun(root, 'lost').status).toBe('failed')
222
- // A late acknowledgement does not start a run for an instruction reported as lost.
223
- await expect(tell('begin', { text: 'Task' })).rejects.toThrow('will not be resent')
224
- expect(await tell('poll')).toEqual({ command: { type: 'interrupt' } })
225
- })
226
-
227
- it('asks before a native action unless the policy allows it, and reads never ask', async () => {
228
- const { tell, events, harness } = await setup()
229
- await tell('ready', {})
230
- await tell('begin', { text: 'Edit' })
231
- expect(await tell('policy', { tool: 'read', args: { path: 'a' } })).toEqual({ allowed: true })
232
- expect(await tell('policy', { tool: 'bash', args: { command: 'rm -rf x' } })).toMatchObject({ allowed: false, requiresApproval: true })
233
- const decision = tell('approval', { requestId: 'call-1', target: 'bash', action: '{"command":"rm -rf x"}', tool: 'bash', args: { command: 'rm -rf x' } })
234
- await vi.waitFor(() => expect(events.some((event) => event.type === 'approval.requested')).toBe(true))
235
- const request = events.find((event) => event.type === 'approval.requested')!
236
- harness.runs.resolveApproval(request.runId, (request.payload as { approvalId: string }).approvalId, 'approved')
237
- expect(await decision).toEqual({ decision: 'approved' })
238
- })
239
-
240
- it('applies the application policy to native tool calls', async () => {
241
- const seen: string[] = []
242
- const { tell } = await setup({
243
- scope: async (call) => {
244
- seen.push(`${call.run.sessionId}:${call.tool}`)
245
- return call.tool === 'bash' ? { allowed: false, reason: 'Outside the task.' } : { allowed: true }
246
- },
247
- authorize: async (call) => {
248
- if (call.tool === 'write') throw new Error('Switched off.')
249
- }
250
- })
251
- await tell('ready', {})
252
- await tell('begin', { text: 'Go' })
253
- expect(await tell('policy', { tool: 'bash', args: {} })).toEqual({ allowed: false, reason: 'Outside the task.' })
254
- expect(await tell('policy', { tool: 'write', args: {} })).toEqual({ allowed: false, reason: 'Switched off.' })
255
- expect(await tell('policy', { tool: 'edit', args: {} })).toMatchObject({ allowed: true })
256
- expect(seen).toEqual(['term-1:bash', 'term-1:write', 'term-1:edit'])
257
- })
258
-
259
- it('fails the turn and releases its decisions when the native process hangs up mid-question', async () => {
260
- const { tell, events, harness, connection } = await setup()
261
- await tell('ready', {})
262
- await tell('begin', { text: 'task' })
263
- const socket = connect(connection.socket)
264
- await new Promise<void>((resolve, reject) => {
265
- socket.once('connect', resolve)
266
- socket.once('error', reject)
267
- })
268
- socket.write(`${JSON.stringify({ token: connection.token, event: 'question', data: { requestId: 'native-one', question: 'Continue?' } })}\n`)
269
- await vi.waitFor(() => expect(events.some((event) => event.type === 'question.requested')).toBe(true))
270
- socket.destroy()
271
- await vi.waitFor(() => expect(events.some((event) => event.type === 'failed')).toBe(true))
272
- expect((events.find((event) => event.type === 'failed')!.payload as { message: string }).message).toContain('callback disconnected')
273
- expect(harness.runs.activeRunIds()).toEqual([])
274
- expect(harness.terminals.state('term-1').ready).toBe(false)
275
- })
276
-
277
- it('serves memory and connected apps to the session over the socket, until the terminal ends', async () => {
278
- const { connection, harness, tell } = await setup()
279
- await tell('ready', {})
280
- expect(await socketCall<string>(connection, 'wiki.entrypoint')).toContain('# Xingular Harness context')
281
- expect(await socketCall<string>(connection, 'wiki.list')).toContain('library')
282
- const listed = await socketCall<{ tools: { name: string; parameters: { type: string } }[] }>(connection, 'tools.list')
283
- expect(listed.tools.map((tool) => tool.name)).toEqual(['mcp_list_tools', 'mcp_call_tool'])
284
- expect(listed.tools[0].parameters.type).toBe('object')
285
- await expect(socketCall(connection, 'accounts.list')).rejects.toMatchObject({ code: 'unknown_method' })
286
- await expect(socketCall({ ...connection, token: 'guess' }, 'wiki.list')).rejects.toMatchObject({ code: 'unauthorized' })
287
- await harness.terminals.dispose('term-1')
288
- await expect(socketCall(connection, 'wiki.list')).rejects.toMatchObject({ code: 'unauthorized' })
289
- expect(harness.terminals.has('term-1')).toBe(false)
290
- })
291
-
292
- it('writes the account credentials for the pi command only while a terminal runs', async () => {
293
- const { harness, account } = await setup()
294
- const auth = join(harness.accounts.dir, account.id, 'home', 'pi', 'auth.json')
295
- expect(JSON.parse(readFileSync(auth, 'utf8'))).toEqual({})
296
- await harness.terminals.dispose('term-1')
297
- expect(() => readFileSync(auth, 'utf8')).toThrow()
298
- })
299
- })
300
-
301
- describe('the session socket', () => {
302
- it('answers only calls it knows, for tokens it issued', async () => {
303
- const socket = new SessionSocket(join(mkdtempSync(join(tmpdir(), 'sock-')), 's.sock'), { memory: (caller, call) => `${caller.runId}:${call}`, apps: async () => 'apps' })
304
- const token = socket.issue({ sessionId: 's1', caller: () => ({ runId: 'r1' }), broker: null })
305
- expect(await socket.handle(JSON.stringify({ token, call: 'wiki.search', params: { query: 'x' } }))).toEqual({ result: 'r1:wiki.search' })
306
- expect(await socket.handle(JSON.stringify({ token, call: 'agents.create' }))).toMatchObject({ error: { code: 'unknown_method' } })
307
- expect(await socket.handle(JSON.stringify({ token, call: 'mcp.list' }))).toMatchObject({ error: { code: 'mcp_unauthorized' } })
308
- expect(await socket.handle(JSON.stringify({ token: 'guess', call: 'wiki.search' }))).toMatchObject({ error: { code: 'unauthorized' } })
309
- expect(await socket.handle('not json')).toMatchObject({ error: { code: 'invalid_request' } })
310
- socket.revokeSession('s1')
311
- expect(await socket.handle(JSON.stringify({ token, call: 'wiki.search' }))).toMatchObject({ error: { code: 'unauthorized' } })
312
- })
313
- })
314
-
315
- describe('xagent-wiki command', () => {
316
- it('maps commands onto memory and Wiki calls', () => {
317
- expect(parseCli(['search', 'deploy', 'steps', '--kind', 'page'])).toEqual({ kind: 'call', call: 'wiki.search', params: { query: 'deploy steps', kinds: ['page'] } })
318
- expect(parseCli(['read', '/projects/app/arch'])).toEqual({ kind: 'call', call: 'wiki.read', params: { id: '/projects/app/arch' } })
319
- expect(parseCli(['list'])).toEqual({ kind: 'call', call: 'wiki.list', params: {} })
320
- expect(parseCli(['skill', 'review'])).toEqual({ kind: 'call', call: 'wiki.skill', params: { name: 'review' } })
321
- expect(parseCli(['memory', '--namespace', '/projects/app'])).toEqual({ kind: 'call', call: 'wiki.memory', params: { namespace: '/projects/app' } })
322
- expect(parseCli(['recall', 'the', 'outage', '--scope', 'all'])).toEqual({ kind: 'call', call: 'recall.search', params: { query: 'the outage', scope: 'all' } })
323
- expect(parseCli(['propose', '{"kind":"memory","title":"t","body":"b"}'])).toMatchObject({ kind: 'call', call: 'wiki.propose', params: { kind: 'memory' } })
324
- expect(parseCli(['propose', '-'])).toEqual({ kind: 'stdin-propose' })
325
- expect(parseCli(['block', 'append', 'project', 'Uses', 'pnpm.'])).toEqual({ kind: 'call', call: 'memory.append', params: { block: 'project', text: 'Uses pnpm.' } })
326
- expect(parseCli(['block', 'replace', 'project', '--old', 'npm', '--new', 'pnpm'])).toEqual({ kind: 'call', call: 'memory.replace', params: { block: 'project', old: 'npm', new: 'pnpm' } })
327
- expect(parseCli(['search'])).toEqual({ kind: 'help' })
328
- expect(parseCli(['nonsense'])).toEqual({ kind: 'help' })
329
- })
330
- })