@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,569 +0,0 @@
1
- // A session turn on Pi. Pi owns the model loop, native history, and tool use; this module opens
2
- // the session with the compiled prompt and the session's tools, and maps Pi's events onto the
3
- // run-event contract. Gated tools pause for the user's approval before they run.
4
- import type { CreateAgentSessionOptions, ModelRuntime, SettingsManager } from '@earendil-works/pi-coding-agent'
5
-
6
- import { classifyMessage } from '../accounts/accounts'
7
- import type { AccountContext } from '../accounts/env'
8
- import { HarnessError } from '../core/errors'
9
- import type { InlineExtension } from '../plugins/firstParty'
10
- import type { Loading, Registered } from '../plugins/plugins'
11
- import { CONTEXT_MESSAGE_TYPE, CONTEXT_SNAPSHOT_KEY, type ContextUpdate } from '../prompt/compile'
12
- import type { RegistryResources } from '../skills/registry'
13
- import type { ToolSpec } from '../tools/types'
14
- import { toolAttachmentRefsSchema, type UsageRequest } from './contracts'
15
- import { completedReasoningSummary, REASONING_SUMMARY_APIS, requestConciseReasoningSummary } from './reasoningSummaries'
16
- import { extensionUi, type ExtensionHost } from './extensionUi'
17
- import { observeResources, registrationHash } from '../plugins/runtime'
18
- import type { ActiveRun } from './registry'
19
-
20
- export const EFFORTS = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'] as const
21
- export type Effort = (typeof EFFORTS)[number]
22
-
23
- /** What one turn needs once its prompt is compiled and its tools are chosen. */
24
- export interface TurnParams {
25
- runId: string
26
- cwd: string
27
- sessionDir: string
28
- /** The native history to open, or `null` to start a fresh one. */
29
- historyFile: string | null
30
- model: string | null
31
- effort?: Effort | null
32
- text: string
33
- images?: { mediaType: string; data: string }[]
34
- requiresImageInput?: boolean
35
- /** App-origin notes placed before the text of the request. */
36
- preamble?: string | null
37
- /** Unattended: no project extensions, no context files, settings held in memory. */
38
- automatic?: boolean
39
- account: AccountContext
40
- resources?: RegistryResources
41
- /**
42
- * What the harness found for this session to load, and where it reports what loaded. Pi's own
43
- * discovery is off whenever this is set, so only these paths and the registry's reach the session.
44
- */
45
- plugins?: { loading(): Promise<Loading>; loaded(extensions: Registered[]): void }
46
- /** The harness's own switched-on extensions. They are code in this process, so they load in every kind of run. */
47
- inline?: InlineExtension[]
48
- /** The stable part of the compiled prompt: the only text added to Pi's own. */
49
- system: string
50
- /** Changed state, saved as a hidden message in native history before the request. */
51
- update: ContextUpdate | null
52
- }
53
-
54
- // ---- Pi session seam (real implementation below; tests inject a fake) ----------------
55
-
56
- /** Structural view of the Pi events the harness consumes. */
57
- export type PiEvent =
58
- | { type: 'message_start'; message: { role: string } }
59
- | { type: 'message_update'; message: { role: string }; assistantMessageEvent: { type: string; delta?: string } }
60
- | {
61
- type: 'message_end'
62
- message: {
63
- role: string
64
- content?: Array<{ type: string; text?: string; thinkingSignature?: string }>
65
- api?: string
66
- usage?: { input?: number; output?: number; cacheRead?: number; cacheWrite?: number; reasoning?: number; cost?: { total?: number } }
67
- model?: string
68
- provider?: string
69
- responseId?: string
70
- stopReason?: string
71
- errorMessage?: string
72
- }
73
- }
74
- | { type: 'tool_execution_start'; toolCallId: string; toolName: string; args: unknown }
75
- | { type: 'tool_execution_end'; toolCallId: string; toolName: string; isError: boolean; result?: unknown }
76
- | { type: string }
77
-
78
- export interface PiSessionLike {
79
- sessionId: string
80
- systemPrompt?: string
81
- extensionCommands?: readonly string[]
82
- model?: { input: string[]; contextWindow?: number }
83
- getActiveToolNames?(): string[]
84
- getAllTools?(): Array<{ name: string; description?: string; parameters?: unknown }>
85
- subscribe(listener: (event: PiEvent) => void): () => void
86
- prompt(text: string, options?: { images?: unknown[] }): Promise<void>
87
- sendCustomMessage?(message: { customType: string; content: string; display: boolean; details: unknown }, options: { triggerTurn: boolean }): Promise<void>
88
- abort(): Promise<void>
89
- dispose(): void
90
- }
91
-
92
- export interface ToolGate {
93
- /** Resolves to a block reason, or null to let the call run. */
94
- check(toolName: string, input: unknown): Promise<string | null>
95
- /** Makes these tools ask before each call. Used for tools an extension brought, which no one switched on by name. */
96
- ask?(toolNames: readonly string[]): void
97
- }
98
-
99
- export type SessionFactory = (input: {
100
- params: TurnParams
101
- /** Pi's own tools and the custom tools switched on for this turn, in order. */
102
- allow: string[]
103
- gate: ToolGate
104
- /** Custom tools already bound to this run. */
105
- tools: ToolSpec[]
106
- runtime: () => Promise<ModelRuntime>
107
- /** Where a loaded extension's dialogs and notices go. Without it extensions have no interface. */
108
- extensions?: ExtensionHost
109
- }) => Promise<PiSessionLike>
110
-
111
- /** A one-line description of a tool call, for an approval request or the activity list. */
112
- export function summarize(input: unknown, toolName = ''): string {
113
- if (input && typeof input === 'object') {
114
- const record = input as Record<string, unknown>
115
- // Typed text is never recorded, only its length.
116
- if (/_type$/.test(toolName) && typeof record.text === 'string') return `${String(record.selector ?? record.app ?? '')} (${record.text.length} characters)`.trim()
117
- const primary = record.command ?? record.path ?? record.file_path ?? record.query
118
- if (typeof primary === 'string') return primary.slice(0, 200)
119
- }
120
- return JSON.stringify(input ?? {}).slice(0, 200)
121
- }
122
-
123
- function assistantText(message: { content?: Array<{ type: string; text?: string }> }): string {
124
- return (message.content ?? []).filter((part) => part.type === 'text' && typeof part.text === 'string').map((part) => part.text).join('')
125
- }
126
-
127
- /** How much text a tool handed back to the model: what its result adds to every later request. */
128
- export function resultSize(result: unknown): number | null {
129
- if (typeof result === 'string') return result.length
130
- const content = (result as { content?: unknown } | null | undefined)?.content
131
- if (!Array.isArray(content)) return null
132
- return content.reduce((total: number, part: { type?: string; text?: unknown }) => total + (part?.type === 'text' && typeof part.text === 'string' ? part.text.length : 0), 0)
133
- }
134
-
135
- const MAX_EVIDENCE_CHARS = 24_000
136
- const MAX_SYSTEM_PROMPT_CHARS = 100_000
137
- const MAX_TOOL_SPECS = 120
138
-
139
- function limitedText(value: string, maximum = MAX_EVIDENCE_CHARS): { text: string; truncated: boolean } {
140
- const characters = Array.from(value)
141
- const marker = '\n…[truncated]'
142
- return characters.length > maximum ? { text: `${characters.slice(0, Math.max(0, maximum - Array.from(marker).length)).join('')}${marker}`, truncated: true } : { text: value, truncated: false }
143
- }
144
-
145
- function evidenceText(value: unknown): string | null {
146
- if (typeof value === 'string') return value
147
- if (value === undefined) return null
148
- const content = (value as { content?: unknown } | null)?.content
149
- if (Array.isArray(content)) {
150
- const parts = content.flatMap((part) => {
151
- if (!part || typeof part !== 'object') return []
152
- const item = part as { type?: unknown; text?: unknown }
153
- if (item.type === 'text' && typeof item.text === 'string') return [item.text]
154
- return item.type === 'image' ? ['[image content omitted]'] : []
155
- })
156
- if (parts.length) return parts.join('\n')
157
- }
158
- try {
159
- return JSON.stringify(value, null, 2) ?? String(value)
160
- } catch {
161
- return String(value)
162
- }
163
- }
164
-
165
- /** Pi keeps provider-only metadata in `details`; only a bounded, generic reference enters the event. */
166
- function toolAttachmentRefs(result: unknown) {
167
- const details = (result as { details?: unknown } | null | undefined)?.details
168
- const refs = details && typeof details === 'object' ? (details as { attachments?: unknown }).attachments : undefined
169
- const parsed = toolAttachmentRefsSchema.safeParse(refs)
170
- return parsed.success && parsed.data.length ? parsed.data : undefined
171
- }
172
-
173
- function boundedSchema(value: unknown, budget: { remaining: number }, depth = 0): { value: unknown; truncated: boolean } {
174
- if (budget.remaining <= 0 || depth > 12) return { value: '[truncated]', truncated: true }
175
- if (typeof value === 'string') {
176
- const { text, truncated } = limitedText(value, Math.min(MAX_EVIDENCE_CHARS, budget.remaining))
177
- budget.remaining -= Array.from(text).length
178
- return { value: text, truncated }
179
- }
180
- if (Array.isArray(value)) {
181
- const values: unknown[] = []
182
- let truncated = value.length > 200
183
- for (const item of value.slice(0, 200)) {
184
- const next = boundedSchema(item, budget, depth + 1)
185
- values.push(next.value)
186
- truncated ||= next.truncated
187
- if (budget.remaining <= 0) break
188
- }
189
- return { value: values, truncated: truncated || values.length < value.length }
190
- }
191
- if (value && typeof value === 'object') {
192
- const entries = Object.entries(value as Record<string, unknown>)
193
- const output: Record<string, unknown> = {}
194
- let truncated = entries.length > 200
195
- for (const [key, item] of entries.slice(0, 200)) {
196
- if (budget.remaining <= 0) {
197
- truncated = true
198
- break
199
- }
200
- const next = boundedSchema(item, budget, depth + 1)
201
- output[key] = next.value
202
- truncated ||= next.truncated
203
- }
204
- return { value: output, truncated }
205
- }
206
- return { value: value ?? null, truncated: false }
207
- }
208
-
209
- function contextToolSpecs(session: PiSessionLike): { tools: Array<{ name: string; description: string; parameters: unknown }>; truncated: boolean } {
210
- const allTools = session.getAllTools?.() ?? []
211
- const activeNames = session.getActiveToolNames?.()
212
- const source = activeNames ? allTools.filter((tool) => activeNames.includes(tool.name)) : allTools
213
- const tools = source.slice(0, MAX_TOOL_SPECS).map((tool) => {
214
- const description = limitedText(tool.description ?? '', 2_000)
215
- const parameters = boundedSchema(tool.parameters ?? {}, { remaining: 4_000 })
216
- return { spec: { name: tool.name, description: description.text, parameters: parameters.value }, truncated: description.truncated || parameters.truncated }
217
- })
218
- return { tools: tools.map((entry) => entry.spec), truncated: source.length > MAX_TOOL_SPECS || tools.some((entry) => entry.truncated) }
219
- }
220
-
221
- const numberField = (event: Record<string, unknown>, key: string, fallback = 0): number => (typeof event[key] === 'number' && Number.isFinite(event[key]) ? (event[key] as number) : fallback)
222
- const stringField = (event: Record<string, unknown>, key: string, fallback = ''): string => (typeof event[key] === 'string' ? (event[key] as string) : fallback)
223
-
224
- /** Streams one request through a Pi session, translating events for the run. */
225
- export async function runTurn(run: ActiveRun, session: PiSessionLike, params: TurnParams): Promise<void> {
226
- let messageIndex = 0
227
- let requestIndex = 0
228
- let currentMessageId: string | null = null
229
- let lastError: string | null = null
230
- let aborted = false
231
- const usage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costUsd: 0, requests: 0 }
232
- let usageReported = false
233
- // Only some providers report a reasoning split; absent stays absent rather than zero.
234
- let reasoningTokens: number | undefined
235
- // One model request runs from a turn's start to its assistant message's end.
236
- let requestStartedAt: number | null = null
237
- let firstOutputAt: number | null = null
238
- let costReported = false
239
- const toolStartedAt = new Map<string, number>()
240
-
241
- const systemPrompt = limitedText(session.systemPrompt ?? params.system, MAX_SYSTEM_PROMPT_CHARS)
242
- const contextUpdate = limitedText(params.update?.content ?? '', MAX_SYSTEM_PROMPT_CHARS)
243
- const toolSpecs = contextToolSpecs(session)
244
- run.emit('context.snapshot', {
245
- systemPrompt: systemPrompt.text,
246
- ...(contextUpdate.text ? { contextUpdate: contextUpdate.text } : {}),
247
- tools: toolSpecs.tools,
248
- ...(systemPrompt.truncated ? { systemPromptTruncated: true } : {}),
249
- ...(contextUpdate.truncated ? { contextUpdateTruncated: true } : {}),
250
- ...(toolSpecs.truncated ? { toolsTruncated: true } : {})
251
- })
252
-
253
- run.onInterrupt(async () => {
254
- aborted = true
255
- await session.abort()
256
- })
257
-
258
- const unsubscribe = session.subscribe((event) => {
259
- switch (event.type) {
260
- case 'message_start': {
261
- const { message } = event as Extract<PiEvent, { type: 'message_start' }>
262
- if (message.role === 'assistant') currentMessageId = `${run.runId}:m${messageIndex++}`
263
- break
264
- }
265
- case 'turn_start': {
266
- requestStartedAt = Date.now()
267
- firstOutputAt = null
268
- break
269
- }
270
- case 'message_update': {
271
- const update = event as Extract<PiEvent, { type: 'message_update' }>
272
- if (update.message.role === 'assistant') firstOutputAt ??= Date.now()
273
- if (update.message.role === 'assistant' && update.assistantMessageEvent.type === 'text_delta' && update.assistantMessageEvent.delta) {
274
- currentMessageId ??= `${run.runId}:m${messageIndex++}`
275
- run.emit('message.delta', { messageId: currentMessageId, text: update.assistantMessageEvent.delta })
276
- }
277
- break
278
- }
279
- case 'message_end': {
280
- const { message } = event as Extract<PiEvent, { type: 'message_end' }>
281
- if (message.role !== 'assistant') break
282
- requestIndex += 1
283
- const messageId = currentMessageId ?? `${run.runId}:m${messageIndex++}`
284
- currentMessageId = null
285
- const text = assistantText(message)
286
- if (text) run.emit('message.completed', { messageId, role: 'assistant', text })
287
- const reasoningSummary = completedReasoningSummary(message)
288
- if (message.usage || reasoningSummary) {
289
- const reported = message.usage
290
- if (reported) {
291
- usageReported = true
292
- usage.inputTokens += reported.input ?? 0
293
- usage.outputTokens += reported.output ?? 0
294
- usage.cacheReadTokens += reported.cacheRead ?? 0
295
- usage.cacheWriteTokens += reported.cacheWrite ?? 0
296
- usage.costUsd += reported.cost?.total ?? 0
297
- if (typeof reported.reasoning === 'number') reasoningTokens = (reasoningTokens ?? 0) + reported.reasoning
298
- }
299
- usage.requests = requestIndex
300
- const cost = reported?.cost?.total
301
- if (typeof cost === 'number') costReported = true
302
- const ended = Date.now()
303
- const request: UsageRequest = {
304
- index: requestIndex,
305
- ...(message.responseId ? { responseId: message.responseId } : {}),
306
- ...(message.model ? { model: message.model } : {}),
307
- ...(message.provider ? { provider: message.provider } : {}),
308
- ...(reported
309
- ? {
310
- inputTokens: reported.input ?? 0,
311
- cacheReadTokens: reported.cacheRead ?? 0,
312
- cacheWriteTokens: reported.cacheWrite ?? 0,
313
- outputTokens: reported.output ?? 0,
314
- ...(typeof reported.reasoning === 'number' ? { reasoningTokens: reported.reasoning } : {})
315
- }
316
- : {}),
317
- ...(reasoningSummary ? { reasoningSummary } : {}),
318
- ...(typeof cost === 'number' ? { costUsd: cost, costSource: 'harness' as const } : {}),
319
- ...(requestStartedAt === null ? {} : { durationMs: ended - requestStartedAt }),
320
- ...(requestStartedAt === null || firstOutputAt === null ? {} : { ttftMs: Math.max(0, firstOutputAt - requestStartedAt) }),
321
- ...(message.stopReason ? { stopReason: message.stopReason } : {})
322
- }
323
- requestStartedAt = null
324
- const contextWindow = session.model?.contextWindow
325
- const { costUsd, ...tokens } = usage
326
- run.emit('usage.updated', {
327
- ...(usageReported ? tokens : { requests: requestIndex }),
328
- // A cost nobody reported is unknown, not zero.
329
- ...(usageReported && costReported ? { costUsd, costSource: 'harness' as const } : {}),
330
- ...(reasoningTokens === undefined ? {} : { reasoningTokens }),
331
- ...(reported ? { contextTokens: (reported.input ?? 0) + (reported.cacheRead ?? 0) + (reported.cacheWrite ?? 0) } : {}),
332
- ...(contextWindow ? { contextWindow } : {}),
333
- ...(message.model ? { model: message.model } : {}),
334
- ...(message.provider ? { provider: message.provider } : {}),
335
- request
336
- })
337
- }
338
- if (message.stopReason === 'error' && message.errorMessage) {
339
- lastError = message.errorMessage
340
- const category = classifyMessage(message.errorMessage)
341
- if (category) run.emit('account.status', { accountId: params.account.id, category, message: message.errorMessage.slice(0, 500) })
342
- }
343
- if (message.stopReason === 'aborted') aborted = true
344
- break
345
- }
346
- case 'tool_execution_start': {
347
- const tool = event as Extract<PiEvent, { type: 'tool_execution_start' }>
348
- toolStartedAt.set(tool.toolCallId, Date.now())
349
- const input = evidenceText(tool.args)
350
- const boundedInput = input === null ? null : limitedText(input)
351
- run.emit('tool.started', {
352
- toolCallId: tool.toolCallId,
353
- name: tool.toolName,
354
- summary: summarize(tool.args, tool.toolName),
355
- ...(boundedInput ? { input: boundedInput.text, ...(boundedInput.truncated ? { inputTruncated: true } : {}) } : {})
356
- })
357
- break
358
- }
359
- case 'tool_execution_end': {
360
- const tool = event as Extract<PiEvent, { type: 'tool_execution_end' }>
361
- const started = toolStartedAt.get(tool.toolCallId)
362
- toolStartedAt.delete(tool.toolCallId)
363
- const resultChars = resultSize(tool.result)
364
- const output = evidenceText(tool.result)
365
- const boundedOutput = output === null ? null : limitedText(output)
366
- const attachments = toolAttachmentRefs(tool.result)
367
- run.emit('tool.completed', {
368
- toolCallId: tool.toolCallId,
369
- name: tool.toolName,
370
- ok: !tool.isError,
371
- ...(started === undefined ? {} : { durationMs: Date.now() - started }),
372
- ...(resultChars === null ? {} : { resultChars }),
373
- ...(attachments ? { attachments } : {}),
374
- ...(boundedOutput ? { output: boundedOutput.text, ...(boundedOutput.truncated ? { outputTruncated: true } : {}) } : {})
375
- })
376
- break
377
- }
378
- case 'auto_retry_start': {
379
- const retry = event as unknown as Record<string, unknown>
380
- run.emit('retry.started', {
381
- attempt: numberField(retry, 'attempt', 1),
382
- maxAttempts: numberField(retry, 'maxAttempts', 1),
383
- delayMs: numberField(retry, 'delayMs'),
384
- ...(stringField(retry, 'errorMessage') ? { error: stringField(retry, 'errorMessage').slice(0, 1000) } : {})
385
- })
386
- break
387
- }
388
- case 'auto_retry_end': {
389
- const retry = event as unknown as Record<string, unknown>
390
- run.emit('retry.ended', { attempt: numberField(retry, 'attempt', 1), success: retry.success === true, ...(stringField(retry, 'finalError') ? { error: stringField(retry, 'finalError').slice(0, 1000) } : {}) })
391
- break
392
- }
393
- case 'compaction_start': {
394
- run.emit('compaction.started', { reason: stringField(event as unknown as Record<string, unknown>, 'reason', 'context limit') })
395
- break
396
- }
397
- case 'compaction_end': {
398
- const compaction = event as unknown as Record<string, unknown>
399
- const summary = evidenceText(compaction.result)
400
- const boundedSummary = summary ? limitedText(summary) : null
401
- run.emit('compaction.ended', {
402
- reason: stringField(compaction, 'reason', 'context limit'),
403
- aborted: compaction.aborted === true,
404
- ...(typeof compaction.willRetry === 'boolean' ? { willRetry: compaction.willRetry } : {}),
405
- ...(stringField(compaction, 'errorMessage') ? { error: stringField(compaction, 'errorMessage').slice(0, 1000) } : {}),
406
- ...(boundedSummary ? { summary: boundedSummary.text, ...(boundedSummary.truncated ? { summaryTruncated: true } : {}) } : {})
407
- })
408
- break
409
- }
410
- }
411
- })
412
-
413
- try {
414
- if (params.update) {
415
- if (!session.sendCustomMessage) throw new HarnessError('provider_error', 'The Pi session cannot receive the compiled context update.')
416
- // The delivered snapshot is saved with the message, so the next turn compares against what Pi really holds.
417
- await session.sendCustomMessage({ customType: CONTEXT_MESSAGE_TYPE, content: params.update.content, display: false, details: { [CONTEXT_SNAPSHOT_KEY]: params.update.snapshot } }, { triggerTurn: false })
418
- }
419
- const command = /^\/(\S+)/.exec(params.text)?.[1]
420
- const extensionCommand = command && session.extensionCommands?.includes(command)
421
- if (params.preamble && extensionCommand) {
422
- if (!session.sendCustomMessage) throw new HarnessError('provider_error', 'The Pi session cannot receive the command context.')
423
- await session.sendCustomMessage({ customType: 'xingular-preamble', content: params.preamble, display: false, details: {} }, { triggerTurn: false })
424
- }
425
- const prompt = params.preamble && !extensionCommand ? `${params.preamble}\n\n${params.text}` : params.text
426
- const images = (params.images ?? []).map((image) => ({ type: 'image', mimeType: image.mediaType, data: image.data }))
427
- await session.prompt(prompt, images.length ? { images } : undefined)
428
- if (aborted) run.finish('interrupted')
429
- else if (lastError) run.finish('failed', { code: 'provider_error', message: lastError })
430
- else run.finish('completed')
431
- } catch (error) {
432
- if (aborted) run.finish('interrupted')
433
- else run.finish('failed', { code: 'provider_error', message: error instanceof Error ? error.message : String(error) })
434
- } finally {
435
- unsubscribe()
436
- session.dispose()
437
- }
438
- }
439
-
440
- /**
441
- * Loads what a session may use besides its tools: Pi's context files, the registry's skills and
442
- * prompts, and what the harness found for it. `gate` is loaded after every extension on disk.
443
- */
444
- export async function loadResources(pi: typeof import('@earendil-works/pi-coding-agent'), params: Pick<TurnParams, 'cwd' | 'account' | 'automatic' | 'resources' | 'plugins' | 'system' | 'inline'>, gate: unknown, automaticSettings?: SettingsManager) {
445
- const loading = params.automatic ? null : ((await params.plugins?.loading()) ?? null)
446
- const resourceLoader = new pi.DefaultResourceLoader({
447
- ...(automaticSettings ? { settingsManager: automaticSettings, noExtensions: true, noContextFiles: true } : {}),
448
- // The loader gets empty settings and no discovery of its own: it loads the paths below and
449
- // nothing else. The session still reads the account's real settings for everything but resources.
450
- ...(loading ? { settingsManager: pi.SettingsManager.inMemory({}), noExtensions: true, noSkills: true, noPromptTemplates: true, noThemes: true, additionalExtensionPaths: loading.extensionPaths } : {}),
451
- cwd: params.cwd,
452
- agentDir: params.account.configDir,
453
- // Inline extensions load after the ones on disk, and the gate after all of them, so it sees
454
- // what every plugin made of a call.
455
- extensionFactories: [...(params.inline ?? []).map((extension) => ({ name: extension.name, factory: extension.factory as never, hidden: true })), { name: 'xagent-approvals', factory: gate as never, hidden: true }],
456
- additionalSkillPaths: [...(params.resources?.skillPaths ?? []), ...(loading?.skillPaths ?? [])],
457
- additionalPromptTemplatePaths: [...(params.resources?.promptPaths ?? []), ...(loading?.promptPaths ?? [])],
458
- // The compiler writes one prompt; nothing else is appended here.
459
- appendSystemPromptOverride: (base) => [...base, ...(params.system.trim() ? [params.system] : [])]
460
- })
461
- await resourceLoader.reload()
462
- if (loading) {
463
- const records = registeredBy(resourceLoader).map((record) => ({ ...record, hash: registrationHash(loading, record.path) }))
464
- const publish = () => params.plugins?.loaded(records)
465
- observeResources(pi, resourceLoader, loading, records, publish)
466
- publish()
467
- }
468
- return resourceLoader
469
- }
470
-
471
- /** What each extension on disk registered when it was loaded. The harness's own gate is not one of them. */
472
- export function registeredBy(loader: { getExtensions(): { extensions: readonly unknown[] } }): Registered[] {
473
- const names = (map: { keys(): Iterable<unknown> } | undefined): string[] => (map ? [...map.keys()].map(String) : [])
474
- type Loaded = { hidden?: boolean; path: string; resolvedPath?: string } & Record<'handlers' | 'tools' | 'commands' | 'flags' | 'shortcuts', { keys(): Iterable<unknown> } | undefined>
475
- return (loader.getExtensions().extensions as Loaded[])
476
- .filter((extension) => !extension.hidden)
477
- .map((extension) => ({ path: extension.resolvedPath || extension.path, hooks: names(extension.handlers), tools: names(extension.tools), commands: names(extension.commands), flags: names(extension.flags), shortcuts: names(extension.shortcuts) }))
478
- }
479
-
480
- /** Opens a Pi session for one turn: the account's runtime, the compiled prompt, and the gated tools. */
481
- export const piSessionFactory: SessionFactory = async ({ params, allow, gate, tools, runtime: loadRuntime, extensions: host }) => {
482
- const pi = await import('@earendil-works/pi-coding-agent')
483
- const { Type } = await import('typebox')
484
- const runtime = await loadRuntime()
485
-
486
- let model: unknown
487
- let thinkingLevel: CreateAgentSessionOptions['thinkingLevel'] = params.effort ?? undefined
488
- if (params.model) {
489
- const resolved = pi.resolveCliModel({ cliModel: params.model, modelRuntime: runtime })
490
- if (resolved.error || !resolved.model) throw new HarnessError('provider_unavailable', resolved.error ?? `Model ${params.model} is not available.`)
491
- model = resolved.model
492
- thinkingLevel ??= resolved.thinkingLevel
493
- }
494
-
495
- const gatedExtension = (api: { on: (event: 'tool_call', handler: (event: { toolName: string; input: unknown }) => Promise<unknown>) => void }) => {
496
- api.on('tool_call', async (event) => {
497
- const reason = await gate.check(event.toolName, event.input)
498
- return reason ? { block: true, reason } : undefined
499
- })
500
- }
501
-
502
- const agentDir = params.account.configDir
503
- const automaticSettings = params.automatic ? pi.SettingsManager.inMemory({}) : undefined
504
- const resourceLoader = await loadResources(pi, params, gatedExtension, automaticSettings)
505
- const loaded = registeredBy(resourceLoader)
506
- // A tool an extension brought is offered to the model, and asks before every call: the person
507
- // trusted the code to load, and still decides each thing it does through a tool.
508
- const extensionTools = [...new Set(loaded.flatMap((extension) => extension.tools))].filter((name) => !allow.includes(name))
509
- gate.ask?.([...new Set(loaded.flatMap((extension) => extension.tools))])
510
-
511
- let supportsImageInput = false
512
- const customTools = tools
513
- .filter((tool) => allow.includes(tool.name))
514
- .map((spec) =>
515
- pi.defineTool({
516
- name: spec.name,
517
- label: spec.label,
518
- description: spec.description,
519
- parameters: spec.parameters(Type) as never,
520
- execute: async (_toolCallId, input) => {
521
- const result = await spec.execute(input as Record<string, unknown>)
522
- const output = typeof result === 'string' ? { text: result } : result
523
- if (output.image && !supportsImageInput) throw new HarnessError('image_input_unsupported', 'This model cannot inspect images. Choose a model that supports image input.')
524
- return {
525
- content: [{ type: 'text', text: output.text }, ...(output.image ? [{ type: 'image', data: output.image.data, mimeType: output.image.mimeType }] : [])] as never,
526
- details: output.attachments?.length ? { attachments: output.attachments } : {}
527
- }
528
- }
529
- })
530
- )
531
-
532
- const { session } = await pi.createAgentSession({
533
- cwd: params.cwd,
534
- agentDir,
535
- modelRuntime: runtime,
536
- ...(model ? { model: model as never } : {}),
537
- ...(thinkingLevel ? { thinkingLevel } : {}),
538
- tools: [...allow, ...extensionTools],
539
- customTools: customTools as never,
540
- resourceLoader,
541
- ...(automaticSettings ? { settingsManager: automaticSettings } : {}),
542
- sessionManager: params.historyFile ? pi.SessionManager.open(params.historyFile, params.sessionDir, params.cwd) : pi.SessionManager.continueRecent(params.cwd, params.sessionDir)
543
- })
544
- if (loaded.length && host) {
545
- // Without this an extension never hears that its session started and has nobody to ask.
546
- await session.bindExtensions({
547
- uiContext: extensionUi(host),
548
- mode: 'rpc',
549
- onError: (error) => host.notice({ kind: 'error', text: `${error.event}: ${error.error}`.slice(0, 1000), extension: error.extensionPath })
550
- })
551
- }
552
- const piSession = session as unknown as PiSessionLike & { agent: { streamFunction: typeof runtime.streamSimple } }
553
- piSession.extensionCommands = loaded.flatMap((extension) => extension.commands)
554
- supportsImageInput = piSession.model?.input.includes('image') ?? false
555
- const streamAgent = piSession.agent
556
- const originalStream = streamAgent.streamFunction
557
- streamAgent.streamFunction = (streamModel, context, options) => {
558
- if (!streamModel.reasoning || !REASONING_SUMMARY_APIS.has(streamModel.api)) return originalStream(streamModel, context, options)
559
- return originalStream(streamModel, context, {
560
- ...options,
561
- onPayload: async (payload, requestModel) => {
562
- const overridden = await options?.onPayload?.(payload, requestModel)
563
- const requested = requestConciseReasoningSummary(overridden ?? payload)
564
- return requested.requested || overridden !== undefined ? requested.payload : undefined
565
- }
566
- })
567
- }
568
- return piSession
569
- }
@@ -1,61 +0,0 @@
1
- import { mkdtempSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { join } from 'node:path'
4
- import { afterEach, expect, it } from 'vitest'
5
-
6
- import { memorySecretStore } from '../accounts/secrets'
7
- import { createHarness, type Harness } from '../harness'
8
- import { methods } from '../server/methods'
9
- import { writeFile } from '../../tests/helpers'
10
- import { fauxModel } from '../../tests/faux'
11
- import type { Inventory, Plugin } from '../plugins/types'
12
- import { piSessionFactory } from './runner'
13
-
14
- const open: Harness[] = []
15
- afterEach(async () => { for (const harness of open.splice(0)) await harness.close() })
16
-
17
- it('attributes discovered resources and tools, respects caller switches, and discards stale observations', async () => {
18
- const base = mkdtempSync(join(tmpdir(), 'runtime-resources-'))
19
- const harness = createHarness({ dataRoot: join(base, 'data'), stateDir: join(base, 'state'), secrets: memorySecretStore() })
20
- open.push(harness)
21
- harness.accounts.create('Main', 'apiKey')
22
- const account = harness.accounts.context(harness.accounts.resolve(null, null))
23
- await fauxModel(harness)
24
- const skill = join(base, 'resources/audit/SKILL.md')
25
- const prompt = join(base, 'resources/review.md')
26
- writeFile(skill, '---\nname: runtime-audit\ndescription: Audit at runtime.\n---\nAudit instructions.\n')
27
- writeFile(prompt, '---\nname: runtime-review\ndescription: Review at runtime.\n---\nReview instructions.\n')
28
- const extension = join(account.configDir, 'extensions/kit.ts')
29
- writeFile(extension, `import { Type } from 'typebox'
30
- export default function(pi) {
31
- pi.registerTool({ name: 'kit_scan', label: 'Scan', description: 'Scan', parameters: Type.Object({}), async execute() { return { content: [], details: {} } } })
32
- pi.on('resources_discover', () => ({ skillPaths: [${JSON.stringify(skill)}], promptPaths: [${JSON.stringify(prompt)}] }))
33
- }`)
34
- const table = methods(harness)
35
- const load = async (agentId: string) => piSessionFactory({ params: { runId: 'r', cwd: base, sessionDir: join(base, agentId), historyFile: null, model: null, text: '', account, system: '', update: null,
36
- plugins: { loading: () => harness.plugins.loading({ cwd: base, agentDir: account.configDir, caller: { agentId } }), loaded: (records) => harness.plugins.loaded(records) } },
37
- allow: ['read'], tools: [], gate: { check: async () => null }, runtime: () => harness.accounts.runtime(account), extensions: { ask: async () => ({ selected: [] }), notice: () => {} } })
38
- const first = await load('a1')
39
- expect(first.systemPrompt).toContain('runtime-audit')
40
- first.dispose()
41
- const list = await table['plugins.list']({ cwd: base }) as Plugin[]
42
- expect(list.find((plugin) => plugin.id === 'shared')?.contributions).toEqual(expect.arrayContaining([
43
- expect.objectContaining({ kind: 'tool', name: 'kit_scan', state: 'on' }),
44
- expect.objectContaining({ kind: 'skill', name: 'runtime-audit', path: skill, state: 'on' }),
45
- expect.objectContaining({ kind: 'command', name: 'runtime-review', path: prompt })
46
- ]))
47
- await table['plugins.detach']({ cwd: base, id: 'shared/skill/runtime-audit', scope: { agentId: 'a1' } })
48
- const off = await load('a1')
49
- expect(off.systemPrompt).not.toContain('runtime-audit')
50
- off.dispose()
51
- const on = await load('a2')
52
- expect(on.systemPrompt).toContain('runtime-audit')
53
- on.dispose()
54
- const inventory = await table['plugins.inventory']({ cwd: base, context: { agentId: 'a2' }, tools: ['read', 'kit_scan'] }) as Inventory
55
- expect(inventory.items).toEqual(expect.arrayContaining([expect.objectContaining({ pluginId: 'shared', kind: 'tool', name: 'kit_scan' }), expect.objectContaining({ pluginId: 'shared', kind: 'skill', name: 'runtime-audit', chars: expect.any(Number) })]))
56
- expect(inventory.unattributed).toEqual([])
57
- expect(inventory.items.filter((entry) => entry.kind === 'tool' && entry.name === 'kit_scan')).toHaveLength(1)
58
- writeFile(extension, 'export default function() {}\n')
59
- const changed = await table['plugins.list']({ cwd: base }) as Plugin[]
60
- expect(changed.find((plugin) => plugin.id === 'shared')?.contributions.some((item) => item.name === 'runtime-audit' || item.name === 'kit_scan')).toBe(false)
61
- })