@xingular/harness 0.1.7 → 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 (683) hide show
  1. package/CHANGELOG.md +97 -1
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +22 -0
  4. package/README.md +187 -85
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +13701 -13498
  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 +808 -151
  373. package/docs/README.md +22 -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-0002-native-subagent-lifecycle.md +49 -0
  403. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  404. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  405. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  406. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  407. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  408. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  409. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  410. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  411. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  412. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  413. package/docs/decisions/ADR-0013-doctor.md +27 -0
  414. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  415. package/docs/doctor.md +74 -0
  416. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  418. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  420. package/docs/features/README.md +20 -0
  421. package/docs/features/automations/README.md +41 -0
  422. package/docs/features/cores/README.md +39 -0
  423. package/docs/features/google-harness2/README.md +52 -0
  424. package/docs/features/integrations/README.md +40 -0
  425. package/docs/features/interfaces/README.md +29 -0
  426. package/docs/features/memory/README.md +28 -0
  427. package/docs/releases/1.0.0.md +40 -0
  428. package/docs/releases/README.md +36 -0
  429. package/docs/study/00-index.md +78 -0
  430. package/docs/study/arms/00-matrix.md +20 -0
  431. package/docs/study/arms/01-system-prompt.md +211 -0
  432. package/docs/study/arms/02-tools.md +79 -0
  433. package/docs/study/arms/03-subagents.md +90 -0
  434. package/docs/study/arms/04-skills.md +75 -0
  435. package/docs/study/arms/05-context-management.md +90 -0
  436. package/docs/study/arms/06-memory.md +90 -0
  437. package/docs/study/arms/07-governance.md +71 -0
  438. package/docs/study/arms/08-execution.md +69 -0
  439. package/docs/study/arms/09-observability.md +60 -0
  440. package/docs/study/arms/10-refinement.md +110 -0
  441. package/docs/study/btw-comparison.md +37 -0
  442. package/docs/study/feature-gap-review.md +42 -0
  443. package/docs/study/insights.md +123 -0
  444. package/docs/study/roadmap.md +72 -0
  445. package/docs/study/sources/claude-code.md +44 -0
  446. package/docs/study/sources/deepseek-harness.md +102 -0
  447. package/docs/study/sources/harness2.md +50 -0
  448. package/docs/study/sources/kimi-cli.md +42 -0
  449. package/docs/study/sources/omp.md +93 -0
  450. package/docs/study/sources/opencode.md +43 -0
  451. package/docs/study/sources/openhands.md +46 -0
  452. package/docs/study/sources/smolagents.md +40 -0
  453. package/docs/study/sources/swe-agent.md +34 -0
  454. package/docs/system-prompt-design.md +196 -0
  455. package/docs/terminal-tui.md +473 -56
  456. package/package.json +43 -13
  457. package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
  458. package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
  459. package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
  460. package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
  461. package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
  462. package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
  463. package/docs/evidence/terminal-2026-10-17/verification.json +0 -130
  464. package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
  465. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
  466. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
  467. package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
  468. package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
  469. package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
  470. package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
  471. package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
  472. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
  473. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
  474. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
  475. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
  476. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +0 -95
  477. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
  478. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
  479. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
  480. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
  481. package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +0 -27
  482. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
  483. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +0 -18
  484. package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +0 -95
  485. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
  486. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
  487. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +0 -60
  488. package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +0 -24
  489. package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
  490. package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +0 -57
  491. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
  492. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
  493. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +0 -58
  494. package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
  495. package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +0 -320
  496. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +0 -30
  497. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +0 -133
  498. package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +0 -20
  499. package/docs/evidence/terminal-2026-10-17-followup/verification.json +0 -207
  500. package/src/accounts/accounts.test.ts +0 -333
  501. package/src/accounts/accounts.ts +0 -658
  502. package/src/accounts/env.test.ts +0 -95
  503. package/src/accounts/env.ts +0 -338
  504. package/src/accounts/secrets.ts +0 -50
  505. package/src/accounts/store.ts +0 -338
  506. package/src/capabilities/api.ts +0 -75
  507. package/src/capabilities/runSnapshot.ts +0 -59
  508. package/src/capabilities/types.ts +0 -34
  509. package/src/cli.ts +0 -118
  510. package/src/core/bus.ts +0 -34
  511. package/src/core/changes.ts +0 -33
  512. package/src/core/env.ts +0 -27
  513. package/src/core/errors.ts +0 -32
  514. package/src/core/frontmatter.ts +0 -47
  515. package/src/core/fs.test.ts +0 -38
  516. package/src/core/fs.ts +0 -92
  517. package/src/core/index.ts +0 -193
  518. package/src/core/path.test.ts +0 -14
  519. package/src/core/path.ts +0 -79
  520. package/src/core/projects.ts +0 -90
  521. package/src/core/text.ts +0 -39
  522. package/src/harness.ts +0 -312
  523. package/src/hub/catalog.json +0 -123
  524. package/src/hub/cli.ts +0 -59
  525. package/src/hub/hub.test.ts +0 -205
  526. package/src/hub/hub.ts +0 -256
  527. package/src/hub/schema.ts +0 -81
  528. package/src/index.ts +0 -75
  529. package/src/mcp/connections.ts +0 -614
  530. package/src/mcp/manager.ts +0 -130
  531. package/src/mcp/oauth.ts +0 -195
  532. package/src/mcp/scopeMigration.test.ts +0 -79
  533. package/src/mcp/scopeMigration.ts +0 -204
  534. package/src/mcp/service.test.ts +0 -376
  535. package/src/mcp/service.ts +0 -549
  536. package/src/mcp/types.ts +0 -108
  537. package/src/memory/api.test.ts +0 -82
  538. package/src/memory/api.ts +0 -303
  539. package/src/memory/blocks.test.ts +0 -78
  540. package/src/memory/blocks.ts +0 -408
  541. package/src/memory/caller.ts +0 -69
  542. package/src/memory/curation.test.ts +0 -163
  543. package/src/memory/curation.ts +0 -64
  544. package/src/memory/dispatch.ts +0 -59
  545. package/src/memory/facts.test.ts +0 -41
  546. package/src/memory/facts.ts +0 -248
  547. package/src/memory/graph.ts +0 -103
  548. package/src/memory/health.test.ts +0 -130
  549. package/src/memory/health.ts +0 -74
  550. package/src/memory/maintainer.ts +0 -272
  551. package/src/memory/maintenance.test.ts +0 -176
  552. package/src/memory/maintenance.ts +0 -518
  553. package/src/memory/migrate.ts +0 -79
  554. package/src/memory/operations.ts +0 -150
  555. package/src/memory/proposals.test.ts +0 -168
  556. package/src/memory/proposals.ts +0 -584
  557. package/src/memory/recall.test.ts +0 -115
  558. package/src/memory/recall.ts +0 -278
  559. package/src/memory/references.ts +0 -77
  560. package/src/memory/runContext.ts +0 -93
  561. package/src/memory/secrets.ts +0 -6
  562. package/src/memory/store.test.ts +0 -66
  563. package/src/memory/store.ts +0 -385
  564. package/src/memory/wiki.test.ts +0 -47
  565. package/src/memory/wiki.ts +0 -422
  566. package/src/memory/wikiIndex.test.ts +0 -88
  567. package/src/memory/wikiIndex.ts +0 -116
  568. package/src/plugins/api.ts +0 -181
  569. package/src/plugins/attachments.test.ts +0 -84
  570. package/src/plugins/attachments.ts +0 -141
  571. package/src/plugins/builtin.ts +0 -82
  572. package/src/plugins/catalogue.test.ts +0 -254
  573. package/src/plugins/catalogue.ts +0 -251
  574. package/src/plugins/cli.ts +0 -184
  575. package/src/plugins/discover.ts +0 -151
  576. package/src/plugins/firstParty.test.ts +0 -143
  577. package/src/plugins/firstParty.ts +0 -129
  578. package/src/plugins/hooks.test.ts +0 -250
  579. package/src/plugins/hooks.ts +0 -239
  580. package/src/plugins/identity.ts +0 -37
  581. package/src/plugins/install.test.ts +0 -107
  582. package/src/plugins/install.ts +0 -106
  583. package/src/plugins/inventory.ts +0 -123
  584. package/src/plugins/manifest.ts +0 -76
  585. package/src/plugins/plugins.test.ts +0 -205
  586. package/src/plugins/plugins.ts +0 -189
  587. package/src/plugins/proposal.ts +0 -121
  588. package/src/plugins/runtime.test.ts +0 -40
  589. package/src/plugins/runtime.ts +0 -82
  590. package/src/plugins/trust.ts +0 -142
  591. package/src/plugins/types.ts +0 -149
  592. package/src/prompt/compile.test.ts +0 -261
  593. package/src/prompt/compile.ts +0 -732
  594. package/src/server/methods.ts +0 -349
  595. package/src/server/remote.ts +0 -77
  596. package/src/server/rpc.ts +0 -116
  597. package/src/server/serve.ts +0 -28
  598. package/src/server/server.test.ts +0 -174
  599. package/src/sessions/approvals.ts +0 -118
  600. package/src/sessions/contracts.ts +0 -336
  601. package/src/sessions/conversation.test.ts +0 -177
  602. package/src/sessions/extensionSession.test.ts +0 -74
  603. package/src/sessions/extensionUi.test.ts +0 -65
  604. package/src/sessions/extensionUi.ts +0 -102
  605. package/src/sessions/history.ts +0 -51
  606. package/src/sessions/lineageJoin.ts +0 -75
  607. package/src/sessions/policy.ts +0 -36
  608. package/src/sessions/pricing.ts +0 -60
  609. package/src/sessions/questionBatches.test.ts +0 -110
  610. package/src/sessions/reasoningSummaries.ts +0 -59
  611. package/src/sessions/registry.ts +0 -381
  612. package/src/sessions/runIndex.ts +0 -99
  613. package/src/sessions/runStore.test.ts +0 -152
  614. package/src/sessions/runStore.ts +0 -332
  615. package/src/sessions/runner.ts +0 -604
  616. package/src/sessions/runtimeResources.test.ts +0 -61
  617. package/src/sessions/sessions.test.ts +0 -549
  618. package/src/sessions/sessions.ts +0 -339
  619. package/src/skills/registry.test.ts +0 -104
  620. package/src/skills/registry.ts +0 -413
  621. package/src/terminal/accountsMenu.test.ts +0 -225
  622. package/src/terminal/accountsMenu.ts +0 -382
  623. package/src/terminal/cli.ts +0 -149
  624. package/src/terminal/client.ts +0 -74
  625. package/src/terminal/control.test.ts +0 -23
  626. package/src/terminal/control.ts +0 -23
  627. package/src/terminal/controller.ts +0 -291
  628. package/src/terminal/hubMenu.ts +0 -24
  629. package/src/terminal/launch.test.ts +0 -25
  630. package/src/terminal/launch.ts +0 -48
  631. package/src/terminal/piExtension.lifecycle.test.ts +0 -55
  632. package/src/terminal/piExtension.ts +0 -259
  633. package/src/terminal/pluginControl.test.ts +0 -146
  634. package/src/terminal/pluginMenu.ts +0 -112
  635. package/src/terminal/socket.test.ts +0 -71
  636. package/src/terminal/socket.ts +0 -232
  637. package/src/terminal/standalone.test.ts +0 -167
  638. package/src/terminal/standalone.ts +0 -153
  639. package/src/terminal/terminal.test.ts +0 -399
  640. package/src/terminal/terminals.ts +0 -553
  641. package/src/terminal/tui/application.test.ts +0 -114
  642. package/src/terminal/tui/application.ts +0 -491
  643. package/src/terminal/tui/commands.test.ts +0 -218
  644. package/src/terminal/tui/commands.ts +0 -361
  645. package/src/terminal/tui/dialogs.ts +0 -301
  646. package/src/terminal/tui/editor.test.ts +0 -84
  647. package/src/terminal/tui/editor.ts +0 -79
  648. package/src/terminal/tui/keybindings.test.ts +0 -22
  649. package/src/terminal/tui/keybindings.ts +0 -50
  650. package/src/terminal/tui/piAdapter.ts +0 -62
  651. package/src/terminal/tui/presentation.test.ts +0 -79
  652. package/src/terminal/tui/questions.test.ts +0 -41
  653. package/src/terminal/tui/questions.ts +0 -47
  654. package/src/terminal/tui/runtime.socket.test.ts +0 -104
  655. package/src/terminal/tui/runtime.test.ts +0 -215
  656. package/src/terminal/tui/runtime.ts +0 -388
  657. package/src/terminal/tui/sessionUi.ts +0 -24
  658. package/src/terminal/tui/settings.test.ts +0 -150
  659. package/src/terminal/tui/settings.ts +0 -188
  660. package/src/terminal/tui/status.test.ts +0 -70
  661. package/src/terminal/tui/status.ts +0 -109
  662. package/src/terminal/tui/theme.ts +0 -174
  663. package/src/terminal/tui/tools.test.ts +0 -145
  664. package/src/terminal/tui/tools.ts +0 -142
  665. package/src/terminal/tui/transcript.test.ts +0 -25
  666. package/src/terminal/tui/transcript.ts +0 -124
  667. package/src/terminal/tui/ui.test.ts +0 -313
  668. package/src/terminal/tui/ui.ts +0 -166
  669. package/src/terminal/tui/welcome.ts +0 -102
  670. package/src/tools/askUser.test.ts +0 -69
  671. package/src/tools/askUser.ts +0 -59
  672. package/src/tools/definitions.ts +0 -187
  673. package/src/tools/maintenance.ts +0 -24
  674. package/src/tools/memoryTools.ts +0 -22
  675. package/src/tools/pluginPropose.ts +0 -41
  676. package/src/tools/registryWrite.test.ts +0 -101
  677. package/src/tools/registryWrite.ts +0 -182
  678. package/src/tools/spawnSubagent.ts +0 -92
  679. package/src/tools/types.ts +0 -39
  680. package/src/web/safeRequest.ts +0 -171
  681. package/src/web/text.ts +0 -53
  682. package/src/web/tools.ts +0 -134
  683. package/src/web/web.test.ts +0 -141
@@ -1,177 +0,0 @@
1
- // Whole replies, through everything the harness does for one: the compiled prompt, the plugins
2
- // it chose to load, the gate, the run's events. Pi is real and so are the extensions; only the
3
- // model is scripted, so no request leaves the machine.
4
- import { existsSync, mkdtempSync } from 'node:fs'
5
- import { tmpdir } from 'node:os'
6
- import { join } from 'node:path'
7
- import { afterEach, describe, expect, it } from 'vitest'
8
-
9
- import { memorySecretStore } from '../accounts/secrets'
10
- import { createHarness, type Harness } from '../harness'
11
- import { listInbox } from '../memory/operations'
12
- import { wikiDir } from '../memory/store'
13
- import type { Plugin } from '../plugins/types'
14
- import { methods } from '../server/methods'
15
- import { fauxModel } from '../../tests/faux'
16
- import { rootWithProject, writeFile } from '../../tests/helpers'
17
- import type { RunEvent } from './contracts'
18
-
19
- const open: Harness[] = []
20
- afterEach(async () => {
21
- for (const harness of open.splice(0)) await harness.close()
22
- })
23
-
24
- const EXTENSION = `import { Type } from 'typebox'
25
- export default function (pi) {
26
- pi.registerTool({ name: 'kit_scan', label: 'Scan', description: 'Scan a folder.', parameters: Type.Object({ path: Type.String() }), async execute(id, input, signal, onUpdate, ctx) {
27
- ctx.ui.notify('Scanning ' + input.path, 'info')
28
- return { content: [{ type: 'text', text: 'scanned ' + input.path }], details: undefined }
29
- } })
30
- }
31
- `
32
-
33
- async function setup() {
34
- const root = rootWithProject()
35
- const base = mkdtempSync(join(tmpdir(), 'conversation-'))
36
- const harness = createHarness({ dataRoot: root, stateDir: join(base, 'state'), secrets: memorySecretStore(), maintainerFactory: async () => ({ prompt: async () => undefined, dispose: () => undefined, error: () => null }) })
37
- open.push(harness)
38
- harness.accounts.create('Main', 'apiKey')
39
- const model = await fauxModel(harness)
40
- const events: RunEvent[] = []
41
- harness.runs.listen((event) => void events.push(event))
42
- const table = methods(harness)
43
- const call = <T>(method: string, params: Record<string, unknown> = {}) => table[method](params) as Promise<T>
44
- const settled = (id: string) => events.some((event) => event.runId === id && (event.type === 'completed' || event.type === 'failed'))
45
- const until = async (done: () => boolean) => {
46
- for (let waited = 0; waited < 400 && !done(); waited += 1) await new Promise((resolve) => setTimeout(resolve, 25))
47
- }
48
- let count = 0
49
- const start = async (extra: Record<string, unknown> = {}) => {
50
- const id = `run-${(count += 1)}`
51
- await harness.sessions.run({ run: { id, sessionId: 'a1' }, cwd: base, sessionDir: join(root, 'sessions', 'a1'), text: 'Go.', model: model.model, caller: { agentId: 'a1', agentName: 'Helper', actor: 'Chat' }, tools: { allow: ['read'] }, ...extra })
52
- return id
53
- }
54
- const of = (id: string) => events.filter((event) => event.runId === id)
55
- return { harness, root, base, model, call, start, until, settled, of }
56
- }
57
-
58
- describe('a whole reply, with a scripted model', () => {
59
- it('dispatches a registered command with notes without making a provider request', async () => {
60
- const { harness, model, start, until, settled, of } = await setup()
61
- const account = harness.accounts.context(harness.accounts.resolve(null, null))
62
- writeFile(join(account.configDir, 'extensions/command.ts'), `export default function(pi) { pi.registerCommand('hello', { description: 'Hello', handler: async (args, ctx) => ctx.ui.notify('hello ' + args) }) }`)
63
- const id = await start({ text: '/hello original arguments', preamble: '[A note for the next request]' })
64
- await until(() => settled(id))
65
- expect(of(id).at(-1)?.type).toBe('completed')
66
- expect(of(id).find((event) => event.type === 'extension.notice')?.payload).toMatchObject({ text: 'hello original arguments' })
67
- expect(model.requests()).toBe(0)
68
- })
69
-
70
- it('asks before an extension tool that uses the name of an allowed native read', async () => {
71
- const { harness, model, start, until, settled, of } = await setup()
72
- const account = harness.accounts.context(harness.accounts.resolve(null, null))
73
- writeFile(join(account.configDir, 'extensions/override.ts'), EXTENSION.replaceAll('kit_scan', 'read'))
74
- model.script([model.calls(['read', { path: 'src' }]), model.says('Done.')])
75
- const id = await start()
76
- await until(() => of(id).some((event) => event.type === 'approval.requested') || settled(id))
77
- const approval = of(id).find((event) => event.type === 'approval.requested')?.payload as { approvalId: string; target: string }
78
- expect(approval?.target).toBe('read')
79
- expect(of(id).some((event) => event.type === 'extension.notice')).toBe(false)
80
- harness.runs.resolveApproval(id, approval.approvalId, 'denied')
81
- await until(() => settled(id))
82
- expect(model.lastToolResults().at(-1)).toContain('denied')
83
- expect(of(id).some((event) => event.type === 'extension.notice')).toBe(false)
84
- })
85
-
86
- it("offers an installed plugin's tool only once the plugin is switched on and trusted, and asks before the tool runs", async () => {
87
- const { harness, base, model, call, start, until, settled, of } = await setup()
88
- writeFile(join(base, 'kit/package.json'), JSON.stringify({ name: 'review-kit', version: '1.0.0', description: 'Review helpers.' }))
89
- writeFile(join(base, 'kit/extensions/scan.ts'), EXTENSION)
90
- const plugin = (await call<Plugin[]>('plugins.install', { source: join(base, 'kit') })).find((candidate) => candidate.id === 'package:review-kit')!
91
- const scan = () => model.script([model.calls(['kit_scan', { path: 'src' }]), model.says('Scanned.')])
92
-
93
- // Installed, switched off, untrusted: the model names a tool the session does not have.
94
- scan()
95
- const first = await start()
96
- await until(() => settled(first))
97
- expect(of(first).some((event) => event.type === 'approval.requested')).toBe(false)
98
- expect(model.lastToolResults().at(-1)).toMatch(/kit_scan/)
99
- expect(model.lastToolResults().at(-1)).not.toContain('scanned src')
100
-
101
- await call('plugins.attach', { id: plugin.id })
102
- await call('plugins.trust', { hash: plugin.code!.hash })
103
- scan()
104
- const second = await start()
105
- await until(() => of(second).some((event) => event.type === 'approval.requested') || settled(second))
106
- const approval = of(second).find((event) => event.type === 'approval.requested')!.payload as { approvalId: string; target: string }
107
- expect(approval.target).toBe('kit_scan')
108
- // Nothing ran while the person was deciding.
109
- expect(of(second).some((event) => event.type === 'extension.notice')).toBe(false)
110
- harness.runs.resolveApproval(second, approval.approvalId, 'approved')
111
- await until(() => settled(second))
112
- expect(model.lastToolResults().at(-1)).toBe('scanned src')
113
- // What the extension told the person arrived as a run event.
114
- expect(of(second).find((event) => event.type === 'extension.notice')?.payload).toEqual({ kind: 'notify', level: 'info', text: 'Scanning src' })
115
- expect(of(second).at(-1)?.type).toBe('completed')
116
- // Having loaded once, the plugin's details say what its extension adds.
117
- expect((await call<Plugin[]>('plugins.list')).find((candidate) => candidate.id === plugin.id)!.contributions[0].description).toBe('Adds tools kit_scan.')
118
-
119
- // Denied, the tool does not run and the model is told.
120
- scan()
121
- const third = await start()
122
- await until(() => of(third).some((event) => event.type === 'approval.requested') || settled(third))
123
- harness.runs.resolveApproval(third, (of(third).find((event) => event.type === 'approval.requested')!.payload as { approvalId: string }).approvalId, 'denied')
124
- await until(() => settled(third))
125
- expect(model.lastToolResults().at(-1)).toMatch(/denied/)
126
- })
127
-
128
- it('lets the agent propose a plugin, which reaches the Inbox and nothing else', async () => {
129
- const { root, model, start, until, settled, of } = await setup()
130
- model.script([
131
- model.calls(['plugin_propose', { name: 'Memory to Docs', description: 'Copies each saved memory to the team document.', extends: ['memory'] as never, files: [{ path: 'hooks.mjs', content: "export default function (harness) { harness.on('memory.saved', async () => {}) }\n" }] as never }]),
132
- model.says('I proposed it; it is in your Inbox.')
133
- ])
134
- const id = await start()
135
- await until(() => settled(id))
136
- expect(model.lastToolResults().at(-1)).toContain('The plugin "memory-to-docs" is waiting in the Inbox')
137
- expect(listInbox(wikiDir(root)).map((item) => item.title)).toEqual(['Proposed plugin "Memory to Docs"'])
138
- expect(existsSync(join(root, 'plugins'))).toBe(false)
139
- // Proposing is not something a person is asked to approve: it changes nothing until they accept.
140
- expect(of(id).some((event) => event.type === 'approval.requested')).toBe(false)
141
- })
142
-
143
- it('has no plugin proposal tool in unattended work', async () => {
144
- const { model, start, until, settled } = await setup()
145
- model.script([model.calls(['plugin_propose', { name: 'x', description: 'y', files: [] as never }]), model.says('Done.')])
146
- const id = await start({ automatic: true })
147
- await until(() => settled(id))
148
- expect(model.lastToolResults().at(-1)).not.toContain('waiting in the Inbox')
149
- })
150
-
151
- it('delivers a message sent during a tool call after that call, before the next request', async () => {
152
- const { harness, model, call, start, until, settled, of } = await setup()
153
- model.script([model.calls(['bash', { command: 'ls' }]), model.says('Noted.')])
154
- const id = await start({ tools: { allow: ['read', 'bash'], gated: ['bash'] } })
155
- await until(() => of(id).some((event) => event.type === 'approval.requested'))
156
- const approval = of(id).find((event) => event.type === 'approval.requested')!.payload as { approvalId: string }
157
- await call('runs.steer', { runId: id, text: 'Also check the logs.' })
158
- harness.runs.resolveApproval(id, approval.approvalId, 'denied')
159
- await until(() => settled(id))
160
- const types = of(id).map((event) => event.type)
161
- expect(of(id).find((event) => event.type === 'message.steered')?.payload).toEqual({ text: 'Also check the logs.' })
162
- expect(types.indexOf('message.steered')).toBeGreaterThan(types.indexOf('approval.resolved'))
163
- expect(model.requests()).toBe(2)
164
- // The context update reaches the model as a user-role message too; the prompt and the steer come last.
165
- expect(model.lastUserTexts().slice(-2)).toEqual(['Go.', 'Also check the logs.'])
166
- expect(of(id).at(-1)?.type).toBe('completed')
167
- })
168
-
169
- it('refuses a message once the reply has ended, so the app sends it as a new reply', async () => {
170
- const { call, model, start, until, settled, of } = await setup()
171
- model.script([model.says('Done.')])
172
- const id = await start()
173
- await until(() => settled(id))
174
- await expect(call('runs.steer', { runId: id, text: 'Too late.' })).rejects.toMatchObject({ code: 'run_not_active' })
175
- expect(of(id).some((event) => event.type === 'message.steered')).toBe(false)
176
- })
177
- })
@@ -1,74 +0,0 @@
1
- // A real Pi session with a real extension, and no provider: nothing here makes a model request.
2
- import { mkdtempSync } from 'node:fs'
3
- import { tmpdir } from 'node:os'
4
- import { join } from 'node:path'
5
- import { afterEach, expect, it } from 'vitest'
6
-
7
- import { memorySecretStore } from '../accounts/secrets'
8
- import { createHarness, type Harness } from '../harness'
9
- import { writeFile } from '../../tests/helpers'
10
- import type { ExtensionNotice } from './extensionUi'
11
- import type { QuestionInput } from './registry'
12
- import { piSessionFactory, type TurnParams } from './runner'
13
-
14
- const open: Harness[] = []
15
- afterEach(async () => {
16
- for (const harness of open.splice(0)) await harness.close()
17
- })
18
-
19
- const EXTENSION = `import { Type } from 'typebox'
20
- export default function (pi) {
21
- pi.registerTool({ name: 'kit_scan', label: 'Scan', description: 'Scan a folder.', parameters: Type.Object({ path: Type.String() }), async execute() { return { content: [{ type: 'text', text: 'scanned' }], details: undefined } } })
22
- pi.registerCommand('hello', { description: 'Says hello', handler: async (args, ctx) => {
23
- const sure = await ctx.ui.confirm('Say hello?', args)
24
- ctx.ui.notify(sure ? 'hello ' + args : 'kept quiet', 'info')
25
- } })
26
- pi.on('session_start', async (_event, ctx) => { ctx.ui.setStatus('kit', 'ready in ' + ctx.mode) })
27
- }
28
- `
29
-
30
- it('binds an extension in a session without a terminal: its start hook runs, its tool is offered and asks, its command can ask and tell', async () => {
31
- const base = mkdtempSync(join(tmpdir(), 'ext-session-'))
32
- const harness = createHarness({ dataRoot: join(base, 'data'), stateDir: join(base, 'state'), secrets: memorySecretStore() })
33
- open.push(harness)
34
- harness.accounts.create('Main', 'apiKey')
35
- const account = harness.accounts.context(harness.accounts.resolve(null, null))
36
- writeFile(join(account.configDir, 'extensions/kit.ts'), EXTENSION)
37
-
38
- const notices: ExtensionNotice[] = []
39
- const asked: QuestionInput[] = []
40
- const gated: string[] = []
41
- const params: TurnParams = {
42
- runId: 'r1',
43
- cwd: base,
44
- sessionDir: join(base, 'sessions'),
45
- historyFile: null,
46
- model: null,
47
- text: '',
48
- account,
49
- system: '',
50
- update: null,
51
- plugins: { loading: () => harness.plugins.loading({ cwd: base, agentDir: account.configDir }), loaded: (extensions) => harness.plugins.loaded(extensions) }
52
- }
53
- const session = await piSessionFactory({
54
- params,
55
- allow: ['read'],
56
- gate: { check: async () => null, ask: (names) => void gated.push(...names) },
57
- tools: [],
58
- runtime: () => harness.accounts.runtime(account),
59
- extensions: { ask: async (input) => (asked.push(input), { selected: ['Yes'] }), notice: (notice) => void notices.push(notice) }
60
- })
61
- try {
62
- expect(notices).toEqual([{ kind: 'status', key: 'kit', text: 'ready in rpc' }])
63
- expect(gated).toEqual(['kit_scan'])
64
- expect(session.getActiveToolNames?.()).toEqual(expect.arrayContaining(['read', 'kit_scan']))
65
- expect(session.getActiveToolNames?.()).not.toContain('bash')
66
-
67
- await session.prompt('/hello there')
68
- expect(asked).toEqual([{ question: 'Say hello?\n\nthere', options: [{ label: 'Yes' }, { label: 'No' }], multiSelect: false, allowText: false }])
69
- expect(notices.at(-1)).toEqual({ kind: 'notify', level: 'info', text: 'hello there' })
70
- expect(Object.values(harness.plugins.registered())[0]).toMatchObject({ tools: ['kit_scan'], commands: ['hello'], hooks: ['session_start'] })
71
- } finally {
72
- session.dispose()
73
- }
74
- })
@@ -1,65 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
-
3
- import { extensionUi, type ExtensionNotice } from './extensionUi'
4
- import type { QuestionAnswer, QuestionInput } from './registry'
5
-
6
- function host(answer: QuestionAnswer | Promise<QuestionAnswer>) {
7
- const asked: QuestionInput[] = []
8
- const notices: ExtensionNotice[] = []
9
- const ui = extensionUi({ ask: async (input) => (asked.push(input), answer), notice: (notice) => void notices.push(notice) })
10
- return { ui, asked, notices }
11
- }
12
-
13
- describe('what an extension can ask and show without a terminal', () => {
14
- it('turns a choice, a yes or no, and typed text into questions', async () => {
15
- const choice = host({ selected: ['Block'] })
16
- expect(await choice.ui.select('Allow this command?', ['Allow', 'Block'])).toBe('Block')
17
- expect(choice.asked[0]).toEqual({ question: 'Allow this command?', options: [{ label: 'Allow' }, { label: 'Block' }], multiSelect: false, allowText: false })
18
-
19
- const yes = host({ selected: ['Yes'] })
20
- expect(await yes.ui.confirm('Clear the session?', 'All messages will be lost.')).toBe(true)
21
- expect(yes.asked[0]).toMatchObject({ question: 'Clear the session?\n\nAll messages will be lost.', options: [{ label: 'Yes' }, { label: 'No' }] })
22
- expect(await host({ selected: ['No'] }).ui.confirm('Sure?', '')).toBe(false)
23
- // No answer is a no, never a yes.
24
- expect(await host({ selected: [] }).ui.confirm('Sure?', '')).toBe(false)
25
-
26
- const typed = host({ selected: [], text: 'main' })
27
- expect(await typed.ui.input('Branch', 'a name')).toBe('main')
28
- expect(typed.asked[0]).toMatchObject({ question: 'Branch (a name)', options: [], allowText: true })
29
- expect(await host({ selected: [] }).ui.input('Branch')).toBeUndefined()
30
- expect(await host({ selected: [], text: 'edited' }).ui.editor('Edit', 'before')).toBe('edited')
31
- })
32
-
33
- it('gives up a dialog when the extension dismisses it or its time runs out', async () => {
34
- const never = new Promise<QuestionAnswer>(() => undefined)
35
- expect(await host(never).ui.confirm('Sure?', '', { timeout: 10 })).toBe(false)
36
- const controller = new AbortController()
37
- const pending = host(never).ui.select('Pick', ['a'], { signal: controller.signal })
38
- controller.abort()
39
- expect(await pending).toBeUndefined()
40
- })
41
-
42
- it('relays notifications, status lines and text widgets, and ignores what needs a terminal', async () => {
43
- const { ui, notices } = host({ selected: [] })
44
- ui.notify('Blocked', 'warning')
45
- ui.setStatus('budget', '3 of 10 requests')
46
- ui.setStatus('budget', undefined)
47
- ui.setWidget('plan', ['One', 'Two'])
48
- ui.setWidget('plan', (() => ({})) as never)
49
- ui.setTitle('Review')
50
- ui.setFooter(undefined)
51
- ui.setWorkingMessage('thinking')
52
- expect(notices).toEqual([
53
- { kind: 'notify', level: 'warning', text: 'Blocked' },
54
- { kind: 'status', key: 'budget', text: '3 of 10 requests' },
55
- { kind: 'status', key: 'budget', text: '' },
56
- { kind: 'widget', key: 'plan', text: 'One\nTwo' },
57
- { kind: 'title', text: 'Review' }
58
- ])
59
- expect(await ui.custom((() => ({})) as never)).toBeUndefined()
60
- expect(ui.getEditorText()).toBe('')
61
- // Styling returns the text unchanged: there is nothing to colour.
62
- expect((ui.theme as unknown as { fg(color: string, text: string): string }).fg('accent', 'plain')).toBe('plain')
63
- expect(ui.setTheme('dark')).toMatchObject({ success: false })
64
- })
65
- })
@@ -1,102 +0,0 @@
1
- // What a Pi extension can show and ask in a session that has no terminal. Pi's own terminal
2
- // draws an extension's dialogs and status lines; here they become the run's question events and
3
- // notices, the same subset Pi's RPC mode supports. Anything that needs a real terminal (custom
4
- // components, key handlers, themes) does nothing, as it does there.
5
- import type { ExtensionUIContext } from '@earendil-works/pi-coding-agent'
6
-
7
- import type { QuestionAnswer, QuestionInput } from './registry'
8
-
9
- /** A status line, a notification, or an error from an extension. */
10
- export interface ExtensionNotice {
11
- kind: 'notify' | 'status' | 'widget' | 'title' | 'error'
12
- /** `notify` only. */
13
- level?: 'info' | 'warning' | 'error'
14
- /** The extension's own name for a status entry or a widget, so a later one replaces it. */
15
- key?: string
16
- /** The text. Empty clears a status entry or a widget. */
17
- text: string
18
- /** The file of the extension, for an error. */
19
- extension?: string
20
- }
21
-
22
- export interface ExtensionHost {
23
- ask(input: QuestionInput): Promise<QuestionAnswer>
24
- notice(notice: ExtensionNotice): void
25
- }
26
-
27
- const MAX_TEXT = 4_000
28
- const clip = (text: string): string => (text.length > MAX_TEXT ? `${text.slice(0, MAX_TEXT)}…` : text)
29
-
30
- /** A dialog that Pi can dismiss on its own: by a signal, or after a time. */
31
- function dismissable<T>(answer: Promise<T>, fallback: T, options?: { signal?: AbortSignal; timeout?: number }): Promise<T> {
32
- if (!options?.signal && !options?.timeout) return answer
33
- return new Promise<T>((resolve) => {
34
- let timer: ReturnType<typeof setTimeout> | undefined
35
- const done = (value: T): void => {
36
- if (timer) clearTimeout(timer)
37
- resolve(value)
38
- }
39
- if (options.signal?.aborted) return done(fallback)
40
- options.signal?.addEventListener('abort', () => done(fallback), { once: true })
41
- if (options.timeout) timer = setTimeout(() => done(fallback), options.timeout)
42
- void answer.then(done, () => done(fallback))
43
- })
44
- }
45
-
46
- // Text styling has no meaning without a terminal: every style returns the text it was given.
47
- const plainTheme = new Proxy({}, { get: () => (...args: unknown[]) => String(args[args.length - 1] ?? '') })
48
-
49
- export function extensionUi(host: ExtensionHost): ExtensionUIContext {
50
- const context = {
51
- select: (title: string, options: string[], opts?: { signal?: AbortSignal; timeout?: number }) =>
52
- dismissable(
53
- host.ask({ question: clip(title), options: options.map((label) => ({ label })), multiSelect: false, allowText: false }).then((answer) => answer.selected[0]),
54
- undefined,
55
- opts
56
- ),
57
- confirm: (title: string, message: string, opts?: { signal?: AbortSignal; timeout?: number }) =>
58
- dismissable(
59
- host.ask({ question: clip(message ? `${title}\n\n${message}` : title), options: [{ label: 'Yes' }, { label: 'No' }], multiSelect: false, allowText: false }).then((answer) => answer.selected[0] === 'Yes'),
60
- false,
61
- opts
62
- ),
63
- input: (title: string, placeholder?: string, opts?: { signal?: AbortSignal; timeout?: number }) =>
64
- dismissable(
65
- host.ask({ question: clip(placeholder ? `${title} (${placeholder})` : title), options: [], multiSelect: false, allowText: true }).then((answer) => answer.text || undefined),
66
- undefined,
67
- opts
68
- ),
69
- editor: (title: string, prefill?: string) =>
70
- host.ask({ question: clip(prefill ? `${title}\n\n${prefill}` : title), options: [], multiSelect: false, allowText: true }).then((answer) => answer.text || undefined),
71
- notify: (message: string, level?: 'info' | 'warning' | 'error') => host.notice({ kind: 'notify', level: level ?? 'info', text: clip(message) }),
72
- setStatus: (key: string, text: string | undefined) => host.notice({ kind: 'status', key, text: clip(text ?? '') }),
73
- setWidget: (key: string, content: unknown) => {
74
- // Only lines of text can be shown; a component needs a terminal.
75
- if (content === undefined || Array.isArray(content)) host.notice({ kind: 'widget', key, text: clip(((content as string[] | undefined) ?? []).join('\n')) })
76
- },
77
- setTitle: (title: string) => host.notice({ kind: 'title', text: clip(title) }),
78
- onTerminalInput: () => () => {},
79
- setWorkingMessage: () => {},
80
- setWorkingVisible: () => {},
81
- setWorkingIndicator: () => {},
82
- setHiddenThinkingLabel: () => {},
83
- setFooter: () => {},
84
- setHeader: () => {},
85
- custom: async () => undefined,
86
- pasteToEditor: () => {},
87
- setEditorText: () => {},
88
- getEditorText: () => '',
89
- addAutocompleteProvider: () => {},
90
- setEditorComponent: () => {},
91
- getEditorComponent: () => undefined,
92
- get theme() {
93
- return plainTheme
94
- },
95
- getAllThemes: () => [],
96
- getTheme: () => undefined,
97
- setTheme: () => ({ success: false, error: 'There is no terminal to theme in this session.' }),
98
- getToolsExpanded: () => false,
99
- setToolsExpanded: () => {}
100
- }
101
- return context as unknown as ExtensionUIContext
102
- }
@@ -1,51 +0,0 @@
1
- // Which native history a session opens. The prompt compiler compares against this file and Pi
2
- // opens it, so both always see the same conversation, including after a restart.
3
- import { readFileSync, realpathSync } from 'node:fs'
4
- import { isAbsolute, relative } from 'node:path'
5
-
6
- import { HarnessError } from '../core/errors'
7
- import { sessionFile } from '../prompt/compile'
8
-
9
- export interface HistorySelection {
10
- sessionDir: string
11
- /** A recorded history to continue, with the native session id it must still carry. */
12
- resume?: { sessionFile?: string | null; nativeSessionId?: string | null } | null
13
- }
14
-
15
- const unavailable = (): HarnessError => new HarnessError('native_resume_unavailable', 'The saved conversation is unavailable; this reply cannot be continued.')
16
-
17
- /** The session file's own id, when the file is a native history inside `sessionDir`. */
18
- function nativeId(sessionDir: string, path: string): string {
19
- const file = realpathSync(path)
20
- const within = relative(realpathSync(sessionDir), file)
21
- if (within.startsWith('..') || isAbsolute(within) || !file.endsWith('.jsonl')) throw new Error('Outside history')
22
- const header = JSON.parse(readFileSync(file, 'utf8').split('\n', 1)[0]) as { type?: string; id?: string }
23
- if (header.type !== 'session' || !header.id) throw new Error('Missing session identity')
24
- return header.id
25
- }
26
-
27
- /**
28
- * The history to open: the recorded one for an explicit continuation, else the newest in the
29
- * session's folder, else none (a fresh history). An explicit continuation never falls back to
30
- * another session or a fresh history.
31
- */
32
- export function selectHistory(selection: HistorySelection): string | null {
33
- const resume = selection.resume
34
- if (resume?.sessionFile || resume?.nativeSessionId) {
35
- try {
36
- if (!resume.sessionFile || !resume.nativeSessionId) throw new Error('Missing history')
37
- if (nativeId(selection.sessionDir, resume.sessionFile) !== resume.nativeSessionId) throw new Error('Different history')
38
- return realpathSync(resume.sessionFile)
39
- } catch {
40
- throw unavailable()
41
- }
42
- }
43
- const newest = sessionFile(selection.sessionDir)
44
- if (!newest) return null
45
- try {
46
- nativeId(selection.sessionDir, newest)
47
- return realpathSync(newest)
48
- } catch {
49
- throw unavailable()
50
- }
51
- }
@@ -1,75 +0,0 @@
1
- import type { AgentBeforeSettleEvent, BoundaryResult, ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent'
2
-
3
- import { takeChars } from '../core/text'
4
- import { isActiveStatus } from './contracts'
5
- import { readEvents, runFamily } from './runStore'
6
- import type { InlineExtension } from '../plugins/firstParty'
7
-
8
- interface RunSummary {
9
- id: string
10
- status: string
11
- goal: string | null
12
- terminalReason: string | null
13
- }
14
-
15
- function directChildren(root: string, runId: string): RunSummary[] {
16
- try {
17
- return runFamily(root, runId).runs
18
- .map(({ run }) => run)
19
- .filter((run) => run.parentRunId === runId)
20
- .map((run) => ({ id: run.id, status: run.status, goal: run.goal, terminalReason: run.terminalReason }))
21
- } catch {
22
- return []
23
- }
24
- }
25
-
26
- function settled(root: string, runId: string): boolean {
27
- return directChildren(root, runId).every((child) => !isActiveStatus(child.status))
28
- }
29
-
30
- function alreadyIncluded(event: AgentBeforeSettleEvent, runId: string): boolean {
31
- return JSON.stringify(event.context.contextMessages).includes(runId)
32
- }
33
-
34
- function childReport(root: string, child: RunSummary): string {
35
- const reply = readEvents(root, child.id)
36
- .filter((event) => event.type === 'message.completed' && (event.payload as { role?: unknown }).role === 'assistant')
37
- .at(-1)
38
- const payload = reply?.payload as { text?: unknown } | undefined
39
- const text = payload && typeof payload.text === 'string' ? takeChars(payload.text, 8000) : ''
40
- const lines = [`Run ${child.id} · ${child.status}`, `Goal: ${child.goal?.trim() || '(not recorded)'}`]
41
- if (text) lines.push(`Result:\n${text}`)
42
- if (child.status !== 'completed' && child.terminalReason) lines.push(`Stopped because: ${child.terminalReason}`)
43
- return lines.join('\n')
44
- }
45
-
46
- async function waitForChildren(root: string, runId: string, signal?: AbortSignal): Promise<boolean> {
47
- while (!signal?.aborted) {
48
- if (settled(root, runId)) return true
49
- await new Promise<void>((resolve) => setTimeout(resolve, 250))
50
- }
51
- return false
52
- }
53
-
54
- function install(pi: ExtensionAPI, root: string, runId: string): void {
55
- pi.on('agent_before_settle', async (event, context: ExtensionContext): Promise<BoundaryResult | undefined> => {
56
- if (event.outcome !== 'completed' || settled(root, runId)) return undefined
57
- const completed = await waitForChildren(root, runId, context.signal)
58
- if (!completed || context.signal?.aborted) return undefined
59
-
60
- const unreported = directChildren(root, runId).filter((child) => !alreadyIncluded(event, child.id))
61
- if (!unreported.length) return undefined
62
- const summary = takeChars(
63
- `Independent run results. Include each result or failure in the reply; the user may open each run for its full history.\n\n${unreported.map((child) => childReport(root, child)).join('\n\n')}`,
64
- 32_000
65
- )
66
- return {
67
- entries: [...event.entries, { type: 'custom_message', customType: 'run-lineage-results', content: summary, display: false }],
68
- continue: true
69
- }
70
- })
71
- }
72
-
73
- export function runLineageJoin(root: string, runId: string): InlineExtension {
74
- return { name: 'run-lineage-join', factory: (pi: ExtensionAPI) => install(pi, root, runId) }
75
- }
@@ -1,36 +0,0 @@
1
- // What the embedding application decides about a session's tool calls. The harness asks; it
2
- // never assumes: with no policy, every enabled tool may run and gated tools ask the user.
3
- import type { CallerContext } from '../memory/caller'
4
- import type { ApprovalFacts } from './approvals'
5
- import type { RunRecord } from './contracts'
6
-
7
- export interface ToolCall {
8
- run: RunRecord
9
- caller: CallerContext
10
- tool: string
11
- args: unknown
12
- }
13
-
14
- export interface ScopeDecision {
15
- /** The run is unattended: nothing may ask a person, so what is not allowed is refused. */
16
- automatic?: boolean
17
- allowed: boolean
18
- /** Not allowed as it stands, but a person may approve this one call. */
19
- requiresApproval?: boolean
20
- /** Per-tool remembered approvals never answer this call. */
21
- humanOnly?: boolean
22
- /** Whether the global always-approve switch may answer a human-only call. Defaults to false. */
23
- allowGlobalApproval?: boolean
24
- reason?: string | null
25
- }
26
-
27
- export interface ToolPolicy {
28
- /** Whether the call is inside what this run may do. Asked before every tool call. */
29
- scope?(call: ToolCall): Promise<ScopeDecision>
30
- /** Whether the tool is still switched on. Asked before a call and again after an approval; throws to block. */
31
- authorize?(call: ToolCall): Promise<void>
32
- /** Facts about a pending approval that only the application knows. */
33
- approval?(input: { run: RunRecord; target: string; operation?: { tool: string; args: unknown } }): Promise<ApprovalFacts>
34
- /** The connected apps this session may reach, out of those its scope already allows. */
35
- connections?(input: { sessionId: string; runId: string | null; caller: CallerContext; connectionIds: string[] }): Promise<string[]>
36
- }
@@ -1,60 +0,0 @@
1
- // List-price cost of token usage, for when a provider reports tokens but no cost.
2
- import type { ModelRuntime } from '@earendil-works/pi-coding-agent'
3
-
4
- /** Dollars per million tokens. */
5
- export interface PriceRates {
6
- input: number
7
- output: number
8
- cacheRead: number
9
- cacheWrite: number
10
- /** The highest tier whose threshold the request's whole input exceeds replaces the base rates. */
11
- tiers?: Array<{ input: number; output: number; cacheRead: number; cacheWrite: number; inputTokensAbove: number }>
12
- }
13
-
14
- export interface PricedTokens {
15
- inputTokens?: number
16
- outputTokens?: number
17
- cacheReadTokens?: number
18
- cacheWriteTokens?: number
19
- }
20
-
21
- /** The cost of one request at `rates`. Same arithmetic as Pi's own `calculateCost`. */
22
- export function costAt(rates: PriceRates, usage: PricedTokens): number {
23
- const input = usage.inputTokens ?? 0
24
- const cacheRead = usage.cacheReadTokens ?? 0
25
- const cacheWrite = usage.cacheWriteTokens ?? 0
26
- const whole = input + cacheRead + cacheWrite
27
- let applied: Omit<PriceRates, 'tiers'> = rates
28
- let threshold = -1
29
- for (const tier of rates.tiers ?? []) {
30
- if (whole > tier.inputTokensAbove && tier.inputTokensAbove > threshold) {
31
- applied = tier
32
- threshold = tier.inputTokensAbove
33
- }
34
- }
35
- return (applied.input * input + applied.output * (usage.outputTokens ?? 0) + applied.cacheRead * cacheRead + applied.cacheWrite * cacheWrite) / 1_000_000
36
- }
37
-
38
- type Catalogue = { getModel(provider: string, model: string): { cost?: PriceRates } | undefined }
39
- let catalogue: Promise<Catalogue> | null = null
40
-
41
- async function loadCatalogue(): Promise<Catalogue> {
42
- const { ModelRuntime } = await import('@earendil-works/pi-coding-agent')
43
- const none = { read: async () => undefined, list: async () => [], modify: async () => undefined, delete: async () => undefined }
44
- return (await ModelRuntime.create({ credentials: none, modelsPath: null, refreshOnCreate: false })) as ModelRuntime as unknown as Catalogue
45
- }
46
-
47
- /**
48
- * The list rates Pi's catalogue has for a model, or null when it has none. A dated model id
49
- * (`…-20250929`) also matches its undated entry. Rates of zero are "unknown", not "free".
50
- */
51
- export async function modelRates(provider: string | undefined, model: string | undefined, lookup: Promise<Catalogue> = (catalogue ??= loadCatalogue())): Promise<PriceRates | null> {
52
- if (!provider || !model) return null
53
- const models = await lookup.catch(() => null)
54
- if (!models) return null
55
- for (const id of new Set([model, model.replace(/-\d{8}$/, '')])) {
56
- const cost = models.getModel(provider, id)?.cost
57
- if (cost && (cost.input > 0 || cost.output > 0)) return cost
58
- }
59
- return null
60
- }