@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,150 +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
- })
@@ -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,32 +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
- reason?: string | null
21
- }
22
-
23
- export interface ToolPolicy {
24
- /** Whether the call is inside what this run may do. Asked before every tool call. */
25
- scope?(call: ToolCall): Promise<ScopeDecision>
26
- /** Whether the tool is still switched on. Asked before a call and again after an approval; throws to block. */
27
- authorize?(call: ToolCall): Promise<void>
28
- /** Facts about a pending approval that only the application knows. */
29
- approval?(input: { run: RunRecord; target: string; operation?: { tool: string; args: unknown } }): Promise<ApprovalFacts>
30
- /** The connected apps this session may reach, out of those its scope already allows. */
31
- connections?(input: { sessionId: string; runId: string | null; caller: CallerContext; connectionIds: string[] }): Promise<string[]>
32
- }
@@ -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
- }