@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
@@ -0,0 +1,208 @@
1
+ import { accessSync, constants, existsSync, readFileSync, statSync } from 'node:fs';
2
+ import { delimiter, isAbsolute, join } from 'node:path';
3
+ import { defaultAssets } from "../terminal/terminals.js";
4
+ import { loadPi, PINNED_PI_VERSION } from "../pi/runtime.js";
5
+ import { list as listPlugins } from "../plugins/api.js";
6
+ import { compile } from "../prompt/compile.js";
7
+ import { materialise } from "../variant/materialise.js";
8
+ import { validate } from "../variant/variant.js";
9
+ import { PI_SURFACE } from "../variant/surface.js";
10
+ import { allowed } from "../mcp/connections.js";
11
+ import { BRAVE, TAVILY, EXA } from "../web/search.js";
12
+ import { KEYLESS_SEARCH, WEB_PLUGIN } from "../web/tools.js";
13
+ const pass = (evidence) => ({ status: 'pass', evidence });
14
+ const fail = (evidence, remedy) => ({ status: 'fail', evidence, remedy });
15
+ function executable(name) {
16
+ const paths = isAbsolute(name) ? [name] : (process.env.PATH ?? '').split(delimiter).filter(Boolean).map(dir => join(dir, name));
17
+ return paths.some(path => {
18
+ try {
19
+ accessSync(path, constants.X_OK);
20
+ return statSync(path).isFile();
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ });
26
+ }
27
+ export async function builtinChecks(harness, context, secrets, assets = defaultAssets()) {
28
+ const check = (id, category, title, local) => ({ id, category, title, local });
29
+ const account = () => context.accountId ? harness.accounts.find(context.accountId) : null;
30
+ const checks = [
31
+ check('account', 'account', 'Selected account', async (signal) => {
32
+ const selected = account();
33
+ if (!selected)
34
+ return fail('No account is selected.', 'Choose an account with /accounts.');
35
+ const saved = harness.accounts.overview().accounts.find(item => item.id === selected.id);
36
+ const inspected = await harness.accounts.inspect(selected.id, signal);
37
+ if (!inspected.credentials)
38
+ return fail('The pinned account has no saved provider credentials.', 'Sign in or add a key in /accounts.');
39
+ return { status: saved.state.health === 'ok' || saved.state.health === 'unknown' ? 'pass' : 'warning', evidence: `Credentials are configured. Saved health: ${saved.state.health}; checked ${saved.state.lastCheckedAt ?? 'never'}. ${saved.state.limits.map(limit => `${limit.label || limit.id}: ${limit.usedPercent}% used; resets ${limit.resetsAt ?? 'unknown'}`).join('; ')} ${saved.state.lastError ? `Saved issue: ${saved.state.lastError.category}.` : ''} This does not verify authentication with the provider.`, remedy: saved.state.health === 'ok' ? undefined : 'Use the model live probe to verify current provider access.' };
40
+ }),
41
+ check('accounts.inventory', 'account', 'Other saved accounts', async () => {
42
+ const others = harness.accounts.overview().accounts.filter(item => item.id !== context.accountId);
43
+ return pass(others.length ? others.map(item => `${item.label}: ${item.state.health}; checked ${item.state.lastCheckedAt ?? 'never'}`).join('\n') : 'No other saved accounts.');
44
+ }),
45
+ {
46
+ ...check('model', 'account', 'Selected model', async (signal) => {
47
+ if (!context.accountId || !context.model)
48
+ return fail('No account/model is selected.', 'Choose an account and /model.');
49
+ const model = (await harness.accounts.inspect(context.accountId, signal)).models.find(item => item.id === context.model);
50
+ return model ? pass(`${model.id} is available locally; images: ${model.supportsImages}; reasoning: ${model.reasoning}. Provider access is unverified.`) : fail('The selected model is absent from the account model catalogue.', 'Choose an available model with /model.');
51
+ }),
52
+ live: {
53
+ notice: 'One provider request on the selected account/model, up to 64 output tokens; charges may apply. Only synthetic diagnostic content is sent.',
54
+ run: async ({ signal, run }) => {
55
+ const selected = account();
56
+ if (!selected || !context.model)
57
+ return fail('No account/model is selected.', 'Choose an account and /model.');
58
+ const runtime = await harness.accounts.runtime(selected);
59
+ const model = (await runtime.getAvailable()).find(item => `${item.provider}/${item.id}` === context.model);
60
+ if (!model)
61
+ return fail('The selected model is unavailable.', 'Choose an available model with /model.');
62
+ signal.throwIfAborted();
63
+ const result = await runtime.completeSimple(model, { messages: [{ role: 'user', content: 'Reply with OK.', timestamp: Date.now() }] }, { maxTokens: 64, signal });
64
+ const usage = result.usage;
65
+ run.emit('usage.updated', {
66
+ inputTokens: usage.input, outputTokens: usage.output, cacheReadTokens: usage.cacheRead, cacheWriteTokens: usage.cacheWrite,
67
+ costUsd: usage.cost.total, costSource: 'harness', requests: 1, model: result.model, provider: result.provider,
68
+ request: { index: 1, model: result.model, provider: result.provider, stopReason: result.stopReason }
69
+ });
70
+ return result.stopReason === 'error' || result.stopReason === 'aborted'
71
+ ? fail(`The provider request ended with ${result.stopReason}.`, 'Review account authentication, limits, and model configuration.')
72
+ : pass('The selected provider/model completed a real request. Usage is recorded on the diagnostic run.');
73
+ }
74
+ }
75
+ },
76
+ check('runtime.pi', 'runtime', 'Pi runtime', async () => { await loadPi(); return pass(`Pi ${PINNED_PI_VERSION} loaded with its required dispatcher.`); }),
77
+ check('runtime.launcher', 'runtime', 'Terminal launcher', async () => {
78
+ if (!executable(assets.node))
79
+ return fail('The configured Node executable cannot be accessed.', 'Check the host launch configuration.');
80
+ return executable(process.env.XINGULAR_HARNESS_BUN || 'bun')
81
+ ? pass('Node and Bun executables are accessible. No process was launched for this check.')
82
+ : { status: 'warning', evidence: 'Bun was not found on the inherited PATH or at XINGULAR_HARNESS_BUN. The terminal launcher may resolve an additional login-shell path.', remedy: 'Verify the terminal Bun launch path.' };
83
+ }),
84
+ {
85
+ ...check('native.files', 'tools', 'Native file tools', async () => {
86
+ accessSync(context.cwd, constants.R_OK);
87
+ if (context.tools.some(name => name === 'write' || name === 'edit')) {
88
+ try {
89
+ accessSync(context.cwd, constants.W_OK);
90
+ }
91
+ catch {
92
+ return { status: 'blocked', evidence: 'The working directory is readable but not writable.', remedy: 'Choose a writable working directory for edits.' };
93
+ }
94
+ }
95
+ return pass('The working directory is accessible for enabled native file tools. Per-call policy and actual file operations are unverified.');
96
+ }), tools: ['read', 'grep', 'find', 'ls', 'write', 'edit']
97
+ },
98
+ {
99
+ ...check('native.bash', 'tools', 'Native shell tool', async () => process.platform === 'win32'
100
+ ? { status: 'unverified', evidence: 'Windows shell resolution is delegated to Pi; no shell was launched.' }
101
+ : executable('bash') ? pass('Bash is executable on the inherited PATH. No shell command was run.') : fail('Bash was not found on the inherited PATH.', 'Verify the shell executable used by Pi.')),
102
+ tools: ['bash']
103
+ },
104
+ check('runtime.storage', 'runtime', 'State and data storage', async () => {
105
+ accessSync(harness.stateDir, constants.R_OK | constants.W_OK);
106
+ if (!harness.dataRoot)
107
+ return fail('No data root is open.', 'Open a data location before starting runs.');
108
+ accessSync(harness.dataRoot, constants.R_OK | constants.W_OK);
109
+ accessSync(context.cwd, constants.R_OK);
110
+ return pass('State/data directories are accessible and the working directory is readable. Write access is checked without writing files.');
111
+ }),
112
+ check('runtime.assets', 'runtime', 'Terminal assets', async () => {
113
+ const files = [assets.cli, assets.openTui, assets.piExtension];
114
+ const missing = files.filter(file => !existsSync(file));
115
+ return missing.length ? { status: 'warning', evidence: `Configured terminal assets are missing: ${missing.join(', ')}.`, remedy: 'Build the Harness or verify the host-supplied assets.' } : pass('Configured terminal assets are present.');
116
+ }),
117
+ check('runtime.recovery', 'runtime', 'Startup recovery', async () => harness.recovery.migrationError
118
+ ? fail('Startup recorded a storage migration error.', 'Review the recovery diagnostics before starting work.')
119
+ : { status: harness.recovery.interruptedRuns ? 'warning' : 'pass', evidence: `${harness.recovery.interruptedRuns} interrupted runs recovered; no recorded migration error.` }),
120
+ check('variant', 'variant', 'Pinned variant and prompt', async () => {
121
+ if (!harness.dataRoot)
122
+ return { status: 'blocked', evidence: 'Variant and prompt inspection needs an open data root.', remedy: 'Open a data location.' };
123
+ if (!context.variant) {
124
+ compile(harness.env, context.caller, {});
125
+ return pass('No variant is selected; the foundation prompt compiles.');
126
+ }
127
+ const variant = materialise(harness.env.root, context.variant, { trust: harness.trust });
128
+ validate(PI_SURFACE, variant.files);
129
+ compile(harness.env, context.caller, { tools: [...context.tools] }, variant);
130
+ return { status: variant.untrustedPlugins.length ? 'warning' : 'pass', evidence: `Variant ${variant.fingerprint} validates and its prompt compiles; ${variant.untrustedPlugins.length} code resources withheld for trust.` };
131
+ }),
132
+ check('plugins', 'plugins', 'Plugins, skills and resources', async () => {
133
+ if (!harness.dataRoot)
134
+ return { status: 'blocked', evidence: 'Plugin inspection needs an open data root.', remedy: 'Open a data location.' };
135
+ const plugins = await listPlugins(harness, { ...context.caller, cwd: context.cwd, accountId: context.accountId });
136
+ const contributions = plugins.flatMap(plugin => plugin.contributions);
137
+ const problems = [];
138
+ for (const item of contributions.filter(item => item.state === 'on')) {
139
+ if (item.problem)
140
+ problems.push(`${item.name}: recorded resource error`);
141
+ if (item.path) {
142
+ try {
143
+ accessSync(item.path, constants.R_OK);
144
+ if (item.kind === 'skill')
145
+ readFileSync(item.path, 'utf8');
146
+ }
147
+ catch {
148
+ problems.push(`${item.name}: resource cannot be read`);
149
+ }
150
+ }
151
+ }
152
+ const names = contributions.filter(item => item.kind === 'tool' && item.state === 'on').map(item => item.name);
153
+ const duplicates = [...new Set(names.filter((name, index) => names.indexOf(name) !== index))];
154
+ if (duplicates.length)
155
+ problems.push(`Overlapping tool contributions: ${duplicates.join(', ')}`);
156
+ const withheld = contributions.filter(item => item.state === 'untrusted').length;
157
+ return problems.length ? fail(problems.join('\n'), 'Review /plugins and the resource configuration.') : { status: withheld ? 'warning' : 'pass', evidence: `${plugins.length} plugins inspected; ${withheld} untrusted resources withheld. No plugin code was executed for diagnostics. Transitive dependencies are unverified until loaded normally.` };
158
+ })
159
+ ];
160
+ const providers = [BRAVE, TAVILY, EXA];
161
+ checks.push({
162
+ ...check('web.search', 'web', 'Web search', async () => {
163
+ const configured = (await Promise.all(providers.map(async (provider) => await secrets.get(provider.key) ? provider.title : null))).filter(Boolean);
164
+ const keyless = harness.dataRoot !== null && harness.world.setting(WEB_PLUGIN.id, KEYLESS_SEARCH) === 1;
165
+ return configured.length || keyless ? pass(`Configured: ${[...configured, ...(keyless ? ['DuckDuckGo (keyless)'] : [])].join(', ')}. Keys have not been authenticated.`) : fail('No search provider key is saved and keyless search is disabled.', 'Configure Web in /plugins.');
166
+ }), tools: ['web_search'],
167
+ live: { notice: 'Search the public web for “example domain” through configured Brave, Tavily, Exa, or DuckDuckGo endpoints; search API charges may apply.', run: async (probe) => {
168
+ const result = await probe.call('web_search', { queries: ['example domain'] });
169
+ const details = typeof result === 'string' ? undefined : result.details;
170
+ return details?.provider && Array.isArray(details.sources) && details.sources.length ? pass(`Search completed through ${String(details.provider)}.`) : fail('Search did not return verified results.', 'Review configured search providers and limits.');
171
+ } }
172
+ });
173
+ checks.push({
174
+ ...check('web.fetch', 'web', 'Public web fetch', async () => pass('Checked public HTTP reader is installed; network access is unverified.')),
175
+ tools: ['web_fetch'], live: { notice: 'Fetch https://example.com/ through the enabled web_fetch tool.', run: async (probe) => {
176
+ const result = await probe.call('web_fetch', { url: 'https://example.com/' });
177
+ return typeof result !== 'string' && result.details?.status === 200 ? pass('The public page returned HTTP 200 and readable text.') : fail('The public page could not be read.', 'Check network access and retry.');
178
+ } }
179
+ });
180
+ for (const connection of harness.dataRoot ? harness.apps.connections.list() : []) {
181
+ const inScope = allowed(connection, context.caller) && (!context.capabilities || context.capabilities.connectors.includes(connection.id));
182
+ checks.push({
183
+ ...check(`mcp.${connection.id}`, 'mcp', `MCP: ${connection.name}`, async () => {
184
+ if (!connection.enabled)
185
+ return { status: 'disabled', evidence: 'The connection is disabled.' };
186
+ if (!inScope)
187
+ return { status: 'blocked', evidence: 'The connection is outside this diagnostic scope.' };
188
+ if (connection.auth === 'oauth' && connection.authState !== 'signed_in')
189
+ return { status: 'warning', evidence: `Saved authentication state: ${connection.authState ?? 'unknown'}.`, remedy: 'Check connector authentication in the host.' };
190
+ return { status: connection.error ? 'warning' : 'pass', evidence: `Configured; last checked ${connection.checkedAt ?? 'never'}; ${connection.tools.length} cached tools. Live connectivity is unverified.` };
191
+ }),
192
+ tools: ['mcp_list_tools'],
193
+ live: { notice: `Connect to configured MCP server “${connection.name}” and list its tools. A configured local server process may start. No connector tools are invoked.`, run: async (probe) => {
194
+ if (!connection.enabled || !inScope)
195
+ return { status: 'blocked', evidence: 'This connection is disabled or outside the selected scope.' };
196
+ const result = await probe.call('mcp_list_tools', { connectionId: connection.id });
197
+ const details = typeof result === 'string' ? undefined : result.details;
198
+ return details?.doctorOk === true ? pass(`${String(details.toolCount)} tools listed.`) : fail('The MCP server could not list tools.', 'Review its transport, authentication, and scope.');
199
+ } }
200
+ });
201
+ }
202
+ // A tool without diagnostics is present in the report without claiming its backend works.
203
+ const supplied = await harness.sessions.diagnostics(context);
204
+ const covered = new Set([...checks, ...supplied].flatMap(item => item.tools ?? []));
205
+ for (const tool of context.tools.filter(tool => !covered.has(tool)))
206
+ checks.push(check(`tool.${tool}`, 'tools', tool, async () => ({ status: 'unverified', evidence: 'Enabled in this session; this provider has no readiness check.', remedy: 'Use the tool normally or add provider diagnostics.' })));
207
+ return [...checks, ...supplied];
208
+ }
@@ -0,0 +1,4 @@
1
+ import type { Harness } from "../harness.js";
2
+ import type { DoctorContext, DoctorProbeContext } from "./types.js";
3
+ /** A real, tool-only diagnostic run. Model requests, if selected, use Pi's account runtime. */
4
+ export declare function diagnosticProbe<T>(harness: Harness, context: DoctorContext, inputSignal: AbortSignal, action: (probe: DoctorProbeContext) => Promise<T>): Promise<T>;
@@ -0,0 +1,92 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { resolve } from "../capabilities/api.js";
3
+ import { freezeRun } from "../capabilities/runSnapshot.js";
4
+ import { runRecordSchema } from "../sessions/contracts.js";
5
+ import { saveRun } from "../sessions/runStore.js";
6
+ import { HarnessError } from "../core/errors.js";
7
+ import { materialise } from "../variant/materialise.js";
8
+ /** A real, tool-only diagnostic run. Model requests, if selected, use Pi's account runtime. */
9
+ export async function diagnosticProbe(harness, context, inputSignal, action) {
10
+ const interrupt = new AbortController();
11
+ const signal = AbortSignal.any([inputSignal, interrupt.signal]);
12
+ signal.throwIfAborted();
13
+ const root = harness.env.root;
14
+ const id = randomUUID();
15
+ const caller = { ...context.caller, runId: id, sessionId: id, surface: 'doctor' };
16
+ const available = await resolve(harness, { ...context.caller, cwd: context.cwd, tools: context.tools });
17
+ const capabilities = {
18
+ version: 1,
19
+ tools: available.tools.filter(tool => context.tools.includes(tool) && (!context.capabilities || context.capabilities.tools.includes(tool))),
20
+ connectors: available.connectors.filter(connector => !context.capabilities || context.capabilities.connectors.includes(connector)),
21
+ contributions: available.contributions.filter(item => !context.capabilities || context.capabilities.contributions.includes(item))
22
+ };
23
+ signal.throwIfAborted();
24
+ if (context.accountId)
25
+ harness.accounts.find(context.accountId);
26
+ const variant = context.variant ? materialise(root, context.variant, { trust: harness.trust }) : null;
27
+ saveRun(root, runRecordSchema.parse({
28
+ id, sessionId: id, mode: 'doctor', harness: 'pi', sessionType: 'structured', workingDirectory: context.cwd,
29
+ startedAt: new Date().toISOString(), status: 'running', goal: 'User-approved diagnostic probe',
30
+ accountId: context.accountId, agentId: caller.agentId ?? null, projectId: caller.projectId ?? null, trigger: 'doctor',
31
+ variantScope: variant?.scope ?? null, variantVersion: variant?.fingerprint ?? null
32
+ }));
33
+ freezeRun(root, id, caller, capabilities);
34
+ const run = harness.runs.start(id, id);
35
+ run.onInterrupt(() => interrupt.abort());
36
+ const abort = () => { run.finish('interrupted'); void harness.world.release(id); };
37
+ signal.addEventListener('abort', abort, { once: true });
38
+ const gate = harness.sessions.diagnosticGate(run, caller);
39
+ try {
40
+ signal.throwIfAborted();
41
+ const result = await action({
42
+ signal, context, run,
43
+ call: async (name, input) => {
44
+ signal.throwIfAborted();
45
+ if (run.finished || !capabilities.tools.includes(name))
46
+ throw new HarnessError('doctor_blocked', 'This tool is outside the diagnostic capability set.');
47
+ const refusal = await gate.check(name, input);
48
+ if (refusal)
49
+ throw new HarnessError('doctor_blocked', 'The tool policy refused this diagnostic call.');
50
+ signal.throwIfAborted();
51
+ const callId = randomUUID();
52
+ run.emit('tool.started', { toolCallId: callId, name, summary: 'Synthetic diagnostic input' });
53
+ try {
54
+ let result;
55
+ if (name === 'mcp_list_tools') {
56
+ if (typeof input.connectionId !== 'string')
57
+ throw new HarnessError('doctor_blocked', 'A connection must be selected.');
58
+ const broker = harness.apps.grant({ sessionId: id, runId: id, caller, readOnly: true, depth: 0, capabilities: { ...capabilities, connectors: capabilities.connectors.filter(connector => connector === input.connectionId) } });
59
+ const count = await harness.apps.diagnosticList(broker, input.connectionId, signal);
60
+ result = { text: `${count} tools listed.`, details: { doctorOk: true, toolCount: count } };
61
+ }
62
+ else {
63
+ const tools = await harness.sessions.diagnosticTools({ run, caller, allow: capabilities.tools, depth: 0, cwd: context.cwd, capabilities });
64
+ const tool = tools.find(tool => tool.name === name);
65
+ if (!tool)
66
+ throw new HarnessError('doctor_blocked', 'No provider supplies this diagnostic tool.');
67
+ signal.throwIfAborted();
68
+ result = await tool.execute(input);
69
+ }
70
+ signal.throwIfAborted();
71
+ run.emit('tool.completed', { toolCallId: callId, name, ok: true });
72
+ return result;
73
+ }
74
+ catch (error) {
75
+ run.emit('tool.completed', { toolCallId: callId, name, ok: false });
76
+ throw error;
77
+ }
78
+ }
79
+ });
80
+ return result;
81
+ }
82
+ catch (error) {
83
+ run.finish(signal.aborted ? 'interrupted' : 'failed', { code: 'doctor_failed', message: 'The diagnostic probe failed.' });
84
+ throw error;
85
+ }
86
+ finally {
87
+ signal.removeEventListener('abort', abort);
88
+ run.finish(signal.aborted ? 'interrupted' : 'completed');
89
+ harness.apps.revokeRun(id, id);
90
+ await harness.world.release(id);
91
+ }
92
+ }
@@ -0,0 +1,23 @@
1
+ import { type DoctorCheck, type DoctorContext, type DoctorInput, type DoctorProbeContext, type DoctorReport } from "./types.js";
2
+ export interface DoctorOptions {
3
+ checks(context: DoctorContext): Promise<DoctorCheck[]>;
4
+ probe<T>(context: DoctorContext, signal: AbortSignal, action: (probe: DoctorProbeContext) => Promise<T>): Promise<T>;
5
+ timeout?: {
6
+ local: number;
7
+ live: number;
8
+ model: number;
9
+ };
10
+ }
11
+ export declare class Doctor {
12
+ private readonly options;
13
+ private readonly jobs;
14
+ private closed;
15
+ constructor(options: DoctorOptions);
16
+ start(input: DoctorInput): DoctorReport;
17
+ read(id: string): DoctorReport;
18
+ cancel(id: string): DoctorReport;
19
+ close(): Promise<void>;
20
+ private job;
21
+ private run;
22
+ private bounded;
23
+ }
@@ -0,0 +1,144 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { redactLogText } from "../core/bus.js";
3
+ import { invalid, notFound } from "../core/errors.js";
4
+ import { doctorInputSchema, findingSchema } from "./types.js";
5
+ const safe = (text) => redactLogText(text).replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, '').replace(/[\x00-\x08\x0b-\x1f\x7f-\x9f]/g, ' ').slice(0, 4000);
6
+ export class Doctor {
7
+ options;
8
+ jobs = new Map();
9
+ closed = false;
10
+ constructor(options) {
11
+ this.options = options;
12
+ }
13
+ start(input) {
14
+ if (this.closed)
15
+ throw invalid('Diagnostics are closed.');
16
+ const parsed = doctorInputSchema.parse(input);
17
+ if (parsed.mode === 'live' && (!parsed.confirmed || !parsed.checks.length))
18
+ throw invalid('Select live checks and confirm their costs and isolated resources first.');
19
+ const context = structuredClone(parsed.context);
20
+ const report = {
21
+ id: randomUUID(), state: 'running', startedAt: new Date().toISOString(), endedAt: null,
22
+ mode: parsed.mode, context: { accountId: context.accountId, model: context.model },
23
+ completed: 0, total: 0, findings: [], liveChecks: []
24
+ };
25
+ const job = { report, abort: new AbortController(), settled: Promise.resolve() };
26
+ this.jobs.set(report.id, job);
27
+ job.settled = this.run(job, context, parsed.checks);
28
+ return this.read(report.id);
29
+ }
30
+ read(id) { return structuredClone(this.job(id).report); }
31
+ cancel(id) {
32
+ const job = this.job(id);
33
+ if (job.report.state === 'running') {
34
+ job.report.state = 'cancelled';
35
+ job.report.endedAt = new Date().toISOString();
36
+ job.abort.abort();
37
+ }
38
+ return this.read(id);
39
+ }
40
+ async close() {
41
+ this.closed = true;
42
+ for (const id of this.jobs.keys())
43
+ this.cancel(id);
44
+ await Promise.all([...this.jobs.values()].map(job => job.settled));
45
+ this.jobs.clear();
46
+ }
47
+ job(id) {
48
+ const job = this.jobs.get(id);
49
+ if (!job)
50
+ throw notFound('Diagnostic job');
51
+ return job;
52
+ }
53
+ async run(job, context, selected) {
54
+ const { report, abort } = job;
55
+ try {
56
+ const checks = await this.bounded(abort.signal, 10_000, () => this.options.checks(context));
57
+ const ids = new Set();
58
+ for (const check of checks) {
59
+ if (ids.has(check.id))
60
+ throw invalid(`Duplicate diagnostic check: ${check.id}`);
61
+ ids.add(check.id);
62
+ }
63
+ const enabled = (check) => !check.tools?.length || check.tools.some(tool => context.tools.includes(tool));
64
+ report.liveChecks = checks.filter(check => check.live && enabled(check)).map(check => ({ id: check.id, title: safe(check.title), notice: safe(check.live.notice) }));
65
+ if (selected.some(id => !ids.has(id)))
66
+ throw invalid('An unknown diagnostic check was selected.');
67
+ const wanted = selected.length ? checks.filter(check => selected.includes(check.id)) : checks;
68
+ report.total = wanted.length;
69
+ const execute = async (check) => {
70
+ if (abort.signal.aborted)
71
+ return;
72
+ const mode = report.mode;
73
+ const limits = this.options.timeout ?? { local: 10_000, live: 30_000, model: 60_000 };
74
+ let result;
75
+ try {
76
+ result = !enabled(check)
77
+ ? { status: 'disabled', evidence: 'This capability is disabled in the selected session.' }
78
+ : await this.bounded(abort.signal, mode === 'local' ? limits.local : check.id === 'model' ? limits.model : limits.live, signal => {
79
+ if (mode === 'local')
80
+ return check.local(signal);
81
+ if (!check.live)
82
+ return Promise.resolve({ status: 'unverified', evidence: 'This check has no live probe.' });
83
+ return this.options.probe(context, signal, probe => check.live.run(probe));
84
+ });
85
+ }
86
+ catch (error) {
87
+ const blocked = error && typeof error === 'object' && 'code' in error && error.code === 'doctor_blocked';
88
+ result = { status: blocked ? 'blocked' : 'fail', evidence: blocked ? 'The capability or tool policy refused this diagnostic call.' : 'The check failed or exceeded its time limit.', remedy: blocked ? 'Review the selected scope and tool permissions.' : 'Review the backend configuration and retry this check.' };
89
+ }
90
+ if (abort.signal.aborted)
91
+ return;
92
+ const parsed = findingSchema.safeParse({ ...result, id: check.id, category: safe(check.category), title: safe(check.title), verification: mode, checkedAt: new Date().toISOString() });
93
+ const finding = parsed.success ? parsed.data : {
94
+ id: check.id, category: safe(check.category), title: safe(check.title), verification: mode,
95
+ checkedAt: new Date().toISOString(), status: 'fail',
96
+ evidence: 'The diagnostic provider returned an invalid finding.', remedy: 'Review the provider implementation.'
97
+ };
98
+ finding.evidence = safe(finding.evidence);
99
+ if (finding.remedy)
100
+ finding.remedy = safe(finding.remedy);
101
+ report.findings.push(finding);
102
+ report.completed++;
103
+ };
104
+ // Interaction probes are serial, so only one isolated surface can own input at a time.
105
+ if (report.mode === 'live') {
106
+ for (const check of wanted)
107
+ await execute(check);
108
+ }
109
+ else {
110
+ let index = 0;
111
+ await Promise.all(Array.from({ length: Math.min(4, wanted.length) }, async () => {
112
+ while (!abort.signal.aborted && index < wanted.length)
113
+ await execute(wanted[index++]);
114
+ }));
115
+ }
116
+ }
117
+ catch {
118
+ if (!abort.signal.aborted)
119
+ report.findings.push({ id: 'doctor', title: 'Diagnostic setup', category: 'runtime', status: 'fail', verification: 'local', evidence: 'Diagnostic checks could not be prepared.', remedy: 'Check the selected scope, account, and data location.', checkedAt: new Date().toISOString() });
120
+ }
121
+ finally {
122
+ if (report.state === 'running')
123
+ report.state = 'completed';
124
+ report.endedAt ??= new Date().toISOString();
125
+ }
126
+ }
127
+ async bounded(parent, ms, action) {
128
+ parent.throwIfAborted();
129
+ const controller = new AbortController();
130
+ const abort = () => controller.abort();
131
+ parent.addEventListener('abort', abort, { once: true });
132
+ const timer = setTimeout(abort, ms);
133
+ try {
134
+ return await Promise.race([
135
+ Promise.resolve().then(() => { controller.signal.throwIfAborted(); return action(controller.signal); }),
136
+ new Promise((_, reject) => controller.signal.addEventListener('abort', () => reject(new Error('Diagnostic cancelled or timed out.')), { once: true }))
137
+ ]);
138
+ }
139
+ finally {
140
+ clearTimeout(timer);
141
+ parent.removeEventListener('abort', abort);
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,141 @@
1
+ import { z } from 'zod';
2
+ import type { CallerContext } from "../core/caller.js";
3
+ import type { CapabilitySet } from "../capabilities/types.js";
4
+ import type { VariantChoice } from "../variant/materialise.js";
5
+ import type { ToolResult } from "../tools/types.js";
6
+ import type { ActiveRun } from "../sessions/registry.js";
7
+ export declare const findingSchema: z.ZodObject<{
8
+ id: z.ZodString;
9
+ category: z.ZodString;
10
+ title: z.ZodString;
11
+ status: z.ZodEnum<{
12
+ disabled: "disabled";
13
+ warning: "warning";
14
+ pass: "pass";
15
+ fail: "fail";
16
+ blocked: "blocked";
17
+ unverified: "unverified";
18
+ }>;
19
+ verification: z.ZodEnum<{
20
+ local: "local";
21
+ live: "live";
22
+ }>;
23
+ evidence: z.ZodString;
24
+ remedy: z.ZodOptional<z.ZodString>;
25
+ checkedAt: z.ZodString;
26
+ }, z.core.$strip>;
27
+ export type DoctorFinding = z.infer<typeof findingSchema>;
28
+ export type CheckResult = Pick<DoctorFinding, 'status' | 'evidence' | 'remedy'>;
29
+ export interface DoctorContext {
30
+ caller: CallerContext;
31
+ cwd: string;
32
+ accountId: string | null;
33
+ model: string | null;
34
+ tools: readonly string[];
35
+ capabilities?: CapabilitySet;
36
+ variant?: VariantChoice | null;
37
+ }
38
+ export interface DoctorCheck {
39
+ id: string;
40
+ category: string;
41
+ title: string;
42
+ tools?: readonly string[];
43
+ /** Readiness inspection only: no network, authentication or world actions. */
44
+ local(signal: AbortSignal): Promise<CheckResult>;
45
+ live?: {
46
+ /** Shown to the person before confirmation. Include destinations, costs and isolation. */
47
+ notice: string;
48
+ run(context: DoctorProbeContext): Promise<CheckResult>;
49
+ };
50
+ }
51
+ export interface DoctorProbeContext {
52
+ run: ActiveRun;
53
+ signal: AbortSignal;
54
+ context: DoctorContext;
55
+ /** Executes an enabled tool through the existing per-call gate. */
56
+ call(tool: string, input: Record<string, unknown>): Promise<string | ToolResult>;
57
+ }
58
+ /** Optional metadata on a callable tool provider; no new Harness extension point. */
59
+ export interface ProviderDiagnostics {
60
+ diagnostics?(context: DoctorContext): DoctorCheck[] | Promise<DoctorCheck[]>;
61
+ }
62
+ export declare const doctorInputSchema: z.ZodObject<{
63
+ context: z.ZodObject<{
64
+ caller: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
65
+ cwd: z.ZodString;
66
+ accountId: z.ZodNullable<z.ZodString>;
67
+ model: z.ZodNullable<z.ZodString>;
68
+ tools: z.ZodArray<z.ZodString>;
69
+ variant: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
70
+ scope: z.ZodString;
71
+ version: z.ZodOptional<z.ZodNullable<z.ZodString>>;
72
+ }, z.core.$strip>, z.ZodObject<{
73
+ dir: z.ZodString;
74
+ scope: z.ZodOptional<z.ZodNullable<z.ZodString>>;
75
+ }, z.core.$strip>]>>>;
76
+ capabilities: z.ZodOptional<z.ZodObject<{
77
+ version: z.ZodLiteral<1>;
78
+ tools: z.ZodArray<z.ZodString>;
79
+ connectors: z.ZodArray<z.ZodString>;
80
+ contributions: z.ZodArray<z.ZodString>;
81
+ }, z.core.$strip>>;
82
+ }, z.core.$strip>;
83
+ mode: z.ZodDefault<z.ZodEnum<{
84
+ local: "local";
85
+ live: "live";
86
+ }>>;
87
+ checks: z.ZodDefault<z.ZodArray<z.ZodString>>;
88
+ confirmed: z.ZodDefault<z.ZodBoolean>;
89
+ }, z.core.$strip>;
90
+ export interface DoctorInput {
91
+ context: DoctorContext;
92
+ mode?: 'local' | 'live';
93
+ checks?: string[];
94
+ confirmed?: boolean;
95
+ }
96
+ export declare const doctorReportSchema: z.ZodObject<{
97
+ id: z.ZodString;
98
+ state: z.ZodEnum<{
99
+ running: "running";
100
+ completed: "completed";
101
+ cancelled: "cancelled";
102
+ }>;
103
+ startedAt: z.ZodString;
104
+ endedAt: z.ZodNullable<z.ZodString>;
105
+ mode: z.ZodEnum<{
106
+ local: "local";
107
+ live: "live";
108
+ }>;
109
+ context: z.ZodObject<{
110
+ accountId: z.ZodNullable<z.ZodString>;
111
+ model: z.ZodNullable<z.ZodString>;
112
+ }, z.core.$strip>;
113
+ completed: z.ZodNumber;
114
+ total: z.ZodNumber;
115
+ findings: z.ZodArray<z.ZodObject<{
116
+ id: z.ZodString;
117
+ category: z.ZodString;
118
+ title: z.ZodString;
119
+ status: z.ZodEnum<{
120
+ disabled: "disabled";
121
+ warning: "warning";
122
+ pass: "pass";
123
+ fail: "fail";
124
+ blocked: "blocked";
125
+ unverified: "unverified";
126
+ }>;
127
+ verification: z.ZodEnum<{
128
+ local: "local";
129
+ live: "live";
130
+ }>;
131
+ evidence: z.ZodString;
132
+ remedy: z.ZodOptional<z.ZodString>;
133
+ checkedAt: z.ZodString;
134
+ }, z.core.$strip>>;
135
+ liveChecks: z.ZodArray<z.ZodObject<{
136
+ id: z.ZodString;
137
+ title: z.ZodString;
138
+ notice: z.ZodString;
139
+ }, z.core.$strip>>;
140
+ }, z.core.$strip>;
141
+ export type DoctorReport = z.infer<typeof doctorReportSchema>;
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ export const findingSchema = z.object({
3
+ id: z.string(), category: z.string(), title: z.string(),
4
+ status: z.enum(['pass', 'warning', 'fail', 'disabled', 'blocked', 'unverified']),
5
+ verification: z.enum(['local', 'live']), evidence: z.string(), remedy: z.string().optional(),
6
+ checkedAt: z.string()
7
+ });
8
+ export const doctorInputSchema = z.object({
9
+ context: z.object({
10
+ caller: z.record(z.string(), z.unknown()).default({}), cwd: z.string().min(1),
11
+ accountId: z.string().nullable(), model: z.string().nullable(), tools: z.array(z.string()),
12
+ variant: z.union([
13
+ z.object({ scope: z.string(), version: z.string().nullable().optional() }),
14
+ z.object({ dir: z.string(), scope: z.string().nullable().optional() })
15
+ ]).nullable().optional(),
16
+ capabilities: z.object({ version: z.literal(1), tools: z.array(z.string()), connectors: z.array(z.string()), contributions: z.array(z.string()) }).optional()
17
+ }),
18
+ mode: z.enum(['local', 'live']).default('local'),
19
+ checks: z.array(z.string()).default([]),
20
+ /** A trusted host attests that the person approved these exact checks. */
21
+ confirmed: z.boolean().default(false)
22
+ });
23
+ export const doctorReportSchema = z.object({
24
+ id: z.string(), state: z.enum(['running', 'completed', 'cancelled']),
25
+ startedAt: z.string(), endedAt: z.string().nullable(), mode: z.enum(['local', 'live']),
26
+ context: z.object({ accountId: z.string().nullable(), model: z.string().nullable() }),
27
+ completed: z.number(), total: z.number(), findings: z.array(findingSchema),
28
+ liveChecks: z.array(z.object({ id: z.string(), title: z.string(), notice: z.string() }))
29
+ });