@xingular/harness 0.1.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (683) hide show
  1. package/CHANGELOG.md +97 -1
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +22 -0
  4. package/README.md +187 -85
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +13701 -13498
  7. package/dist/sdk/accounts/accounts.d.ts +165 -0
  8. package/dist/sdk/accounts/accounts.js +730 -0
  9. package/dist/sdk/accounts/choices.d.ts +23 -0
  10. package/dist/sdk/accounts/choices.js +62 -0
  11. package/dist/sdk/accounts/env.d.ts +78 -0
  12. package/dist/sdk/accounts/env.js +294 -0
  13. package/dist/sdk/accounts/secrets.d.ts +16 -0
  14. package/dist/sdk/accounts/secrets.js +40 -0
  15. package/dist/sdk/accounts/store.d.ts +114 -0
  16. package/dist/sdk/accounts/store.js +255 -0
  17. package/dist/sdk/browser/config.d.ts +16 -0
  18. package/dist/sdk/browser/config.js +22 -0
  19. package/dist/sdk/browser/diagnostics.d.ts +4 -0
  20. package/dist/sdk/browser/diagnostics.js +38 -0
  21. package/dist/sdk/browser/index.d.ts +17 -0
  22. package/dist/sdk/browser/index.js +65 -0
  23. package/dist/sdk/browser/network.d.ts +10 -0
  24. package/dist/sdk/browser/network.js +59 -0
  25. package/dist/sdk/browser/session.d.ts +84 -0
  26. package/dist/sdk/browser/session.js +192 -0
  27. package/dist/sdk/browser/tools.d.ts +8 -0
  28. package/dist/sdk/browser/tools.js +329 -0
  29. package/dist/sdk/capabilities/api.d.ts +22 -0
  30. package/dist/sdk/capabilities/api.js +54 -0
  31. package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
  32. package/dist/sdk/capabilities/runSnapshot.js +47 -0
  33. package/dist/sdk/capabilities/types.d.ts +29 -0
  34. package/dist/sdk/capabilities/types.js +1 -0
  35. package/dist/sdk/cli.d.ts +2 -0
  36. package/dist/sdk/cli.js +142 -0
  37. package/dist/sdk/core/bus.d.ts +23 -0
  38. package/dist/sdk/core/bus.js +76 -0
  39. package/dist/sdk/core/caller.d.ts +22 -0
  40. package/dist/sdk/core/caller.js +16 -0
  41. package/dist/sdk/core/changes.d.ts +15 -0
  42. package/dist/sdk/core/changes.js +15 -0
  43. package/dist/sdk/core/effort.d.ts +2 -0
  44. package/dist/sdk/core/effort.js +1 -0
  45. package/dist/sdk/core/env.d.ts +18 -0
  46. package/dist/sdk/core/env.js +8 -0
  47. package/dist/sdk/core/errors.d.ts +15 -0
  48. package/dist/sdk/core/errors.js +24 -0
  49. package/dist/sdk/core/frontmatter.d.ts +12 -0
  50. package/dist/sdk/core/frontmatter.js +50 -0
  51. package/dist/sdk/core/fs.d.ts +18 -0
  52. package/dist/sdk/core/fs.js +106 -0
  53. package/dist/sdk/core/index.d.ts +24 -0
  54. package/dist/sdk/core/index.js +187 -0
  55. package/dist/sdk/core/path.d.ts +7 -0
  56. package/dist/sdk/core/path.js +79 -0
  57. package/dist/sdk/core/projects.d.ts +18 -0
  58. package/dist/sdk/core/projects.js +67 -0
  59. package/dist/sdk/core/secrets.d.ts +2 -0
  60. package/dist/sdk/core/secrets.js +5 -0
  61. package/dist/sdk/core/text.d.ts +7 -0
  62. package/dist/sdk/core/text.js +40 -0
  63. package/dist/sdk/doctor/checks.d.ts +5 -0
  64. package/dist/sdk/doctor/checks.js +208 -0
  65. package/dist/sdk/doctor/probe.d.ts +4 -0
  66. package/dist/sdk/doctor/probe.js +92 -0
  67. package/dist/sdk/doctor/service.d.ts +23 -0
  68. package/dist/sdk/doctor/service.js +144 -0
  69. package/dist/sdk/doctor/types.d.ts +141 -0
  70. package/dist/sdk/doctor/types.js +29 -0
  71. package/dist/sdk/harness.d.ts +133 -0
  72. package/dist/sdk/harness.js +299 -0
  73. package/dist/sdk/history/lessonPrompt.d.ts +2 -0
  74. package/dist/sdk/history/lessonPrompt.js +15 -0
  75. package/dist/sdk/history/lessons.d.ts +52 -0
  76. package/dist/sdk/history/lessons.js +173 -0
  77. package/dist/sdk/history/recall.d.ts +68 -0
  78. package/dist/sdk/history/recall.js +199 -0
  79. package/dist/sdk/history/trajectory.d.ts +7 -0
  80. package/dist/sdk/history/trajectory.js +216 -0
  81. package/dist/sdk/hub/catalog.json +123 -0
  82. package/dist/sdk/hub/cli.d.ts +7 -0
  83. package/dist/sdk/hub/cli.js +81 -0
  84. package/dist/sdk/hub/hub.d.ts +74 -0
  85. package/dist/sdk/hub/hub.js +474 -0
  86. package/dist/sdk/hub/schema.d.ts +280 -0
  87. package/dist/sdk/hub/schema.js +78 -0
  88. package/dist/sdk/index.d.ts +63 -0
  89. package/dist/sdk/index.js +48 -0
  90. package/dist/sdk/mcp/connections.d.ts +83 -0
  91. package/dist/sdk/mcp/connections.js +669 -0
  92. package/dist/sdk/mcp/manager.d.ts +26 -0
  93. package/dist/sdk/mcp/manager.js +124 -0
  94. package/dist/sdk/mcp/oauth.d.ts +35 -0
  95. package/dist/sdk/mcp/oauth.js +171 -0
  96. package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
  97. package/dist/sdk/mcp/scopeMigration.js +198 -0
  98. package/dist/sdk/mcp/service.d.ts +160 -0
  99. package/dist/sdk/mcp/service.js +510 -0
  100. package/dist/sdk/mcp/types.d.ts +131 -0
  101. package/dist/sdk/mcp/types.js +49 -0
  102. package/dist/sdk/pi/runtime.d.ts +13 -0
  103. package/dist/sdk/pi/runtime.js +31 -0
  104. package/dist/sdk/plugins/api.d.ts +66 -0
  105. package/dist/sdk/plugins/api.js +155 -0
  106. package/dist/sdk/plugins/attachments.d.ts +46 -0
  107. package/dist/sdk/plugins/attachments.js +111 -0
  108. package/dist/sdk/plugins/builtin.d.ts +6 -0
  109. package/dist/sdk/plugins/builtin.js +68 -0
  110. package/dist/sdk/plugins/catalogue.d.ts +29 -0
  111. package/dist/sdk/plugins/catalogue.js +196 -0
  112. package/dist/sdk/plugins/cli.d.ts +13 -0
  113. package/dist/sdk/plugins/cli.js +187 -0
  114. package/dist/sdk/plugins/discover.d.ts +42 -0
  115. package/dist/sdk/plugins/discover.js +115 -0
  116. package/dist/sdk/plugins/firstParty.d.ts +50 -0
  117. package/dist/sdk/plugins/firstParty.js +113 -0
  118. package/dist/sdk/plugins/hooks.d.ts +94 -0
  119. package/dist/sdk/plugins/hooks.js +162 -0
  120. package/dist/sdk/plugins/identity.d.ts +19 -0
  121. package/dist/sdk/plugins/identity.js +48 -0
  122. package/dist/sdk/plugins/install.d.ts +20 -0
  123. package/dist/sdk/plugins/install.js +110 -0
  124. package/dist/sdk/plugins/inventory.d.ts +22 -0
  125. package/dist/sdk/plugins/inventory.js +110 -0
  126. package/dist/sdk/plugins/manifest.d.ts +13 -0
  127. package/dist/sdk/plugins/manifest.js +56 -0
  128. package/dist/sdk/plugins/plugins.d.ts +104 -0
  129. package/dist/sdk/plugins/plugins.js +164 -0
  130. package/dist/sdk/plugins/runtime.d.ts +9 -0
  131. package/dist/sdk/plugins/runtime.js +95 -0
  132. package/dist/sdk/plugins/trust.d.ts +44 -0
  133. package/dist/sdk/plugins/trust.js +120 -0
  134. package/dist/sdk/plugins/types.d.ts +159 -0
  135. package/dist/sdk/plugins/types.js +7 -0
  136. package/dist/sdk/prompt/compile.d.ts +174 -0
  137. package/dist/sdk/prompt/compile.js +396 -0
  138. package/dist/sdk/refine/cli.d.ts +4 -0
  139. package/dist/sdk/refine/cli.js +186 -0
  140. package/dist/sdk/refine/demo.d.ts +21 -0
  141. package/dist/sdk/refine/demo.js +114 -0
  142. package/dist/sdk/refine/evidence.d.ts +55 -0
  143. package/dist/sdk/refine/evidence.js +330 -0
  144. package/dist/sdk/refine/host.d.ts +51 -0
  145. package/dist/sdk/refine/host.js +76 -0
  146. package/dist/sdk/refine/ledger.d.ts +48 -0
  147. package/dist/sdk/refine/ledger.js +76 -0
  148. package/dist/sdk/refine/library.d.ts +55 -0
  149. package/dist/sdk/refine/library.js +177 -0
  150. package/dist/sdk/refine/pi.d.ts +72 -0
  151. package/dist/sdk/refine/pi.js +248 -0
  152. package/dist/sdk/refine/prompts.d.ts +45 -0
  153. package/dist/sdk/refine/prompts.js +390 -0
  154. package/dist/sdk/refine/recursion.d.ts +113 -0
  155. package/dist/sdk/refine/recursion.js +258 -0
  156. package/dist/sdk/refine/runner.d.ts +81 -0
  157. package/dist/sdk/refine/runner.js +150 -0
  158. package/dist/sdk/refine/selection.d.ts +57 -0
  159. package/dist/sdk/refine/selection.js +251 -0
  160. package/dist/sdk/refine/service.d.ts +84 -0
  161. package/dist/sdk/refine/service.js +165 -0
  162. package/dist/sdk/refine/suite.d.ts +67 -0
  163. package/dist/sdk/refine/suite.js +174 -0
  164. package/dist/sdk/refine/trajectory.d.ts +9 -0
  165. package/dist/sdk/refine/trajectory.js +68 -0
  166. package/dist/sdk/refine/types.d.ts +77 -0
  167. package/dist/sdk/refine/types.js +10 -0
  168. package/dist/sdk/server/methods.d.ts +3 -0
  169. package/dist/sdk/server/methods.js +370 -0
  170. package/dist/sdk/server/remote.d.ts +19 -0
  171. package/dist/sdk/server/remote.js +84 -0
  172. package/dist/sdk/server/rpc.d.ts +20 -0
  173. package/dist/sdk/server/rpc.js +102 -0
  174. package/dist/sdk/server/serve.d.ts +10 -0
  175. package/dist/sdk/server/serve.js +18 -0
  176. package/dist/sdk/sessions/approvals.d.ts +47 -0
  177. package/dist/sdk/sessions/approvals.js +119 -0
  178. package/dist/sdk/sessions/continuation.d.ts +48 -0
  179. package/dist/sdk/sessions/continuation.js +85 -0
  180. package/dist/sdk/sessions/contracts.d.ts +534 -0
  181. package/dist/sdk/sessions/contracts.js +299 -0
  182. package/dist/sdk/sessions/extensionUi.d.ts +19 -0
  183. package/dist/sdk/sessions/extensionUi.js +64 -0
  184. package/dist/sdk/sessions/history.d.ts +16 -0
  185. package/dist/sdk/sessions/history.js +68 -0
  186. package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
  187. package/dist/sdk/sessions/lineageJoin.js +61 -0
  188. package/dist/sdk/sessions/planMode.d.ts +36 -0
  189. package/dist/sdk/sessions/planMode.js +84 -0
  190. package/dist/sdk/sessions/policy.d.ts +43 -0
  191. package/dist/sdk/sessions/policy.js +1 -0
  192. package/dist/sdk/sessions/pricing.d.ts +34 -0
  193. package/dist/sdk/sessions/pricing.js +40 -0
  194. package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
  195. package/dist/sdk/sessions/reasoningSummaries.js +61 -0
  196. package/dist/sdk/sessions/registry.d.ts +102 -0
  197. package/dist/sdk/sessions/registry.js +383 -0
  198. package/dist/sdk/sessions/runIndex.d.ts +21 -0
  199. package/dist/sdk/sessions/runIndex.js +65 -0
  200. package/dist/sdk/sessions/runStore.d.ts +66 -0
  201. package/dist/sdk/sessions/runStore.js +335 -0
  202. package/dist/sdk/sessions/runner.d.ts +213 -0
  203. package/dist/sdk/sessions/runner.js +589 -0
  204. package/dist/sdk/sessions/sessions.d.ts +140 -0
  205. package/dist/sdk/sessions/sessions.js +394 -0
  206. package/dist/sdk/sessions/subagentService.d.ts +41 -0
  207. package/dist/sdk/sessions/subagentService.js +247 -0
  208. package/dist/sdk/sessions/subagents.d.ts +50 -0
  209. package/dist/sdk/sessions/subagents.js +68 -0
  210. package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
  211. package/dist/sdk/terminal/accountsMenu.js +392 -0
  212. package/dist/sdk/terminal/cli.d.ts +20 -0
  213. package/dist/sdk/terminal/cli.js +121 -0
  214. package/dist/sdk/terminal/client.d.ts +15 -0
  215. package/dist/sdk/terminal/client.js +126 -0
  216. package/dist/sdk/terminal/control.d.ts +4 -0
  217. package/dist/sdk/terminal/control.js +25 -0
  218. package/dist/sdk/terminal/controller.d.ts +72 -0
  219. package/dist/sdk/terminal/controller.js +351 -0
  220. package/dist/sdk/terminal/hubMenu.d.ts +10 -0
  221. package/dist/sdk/terminal/hubMenu.js +34 -0
  222. package/dist/sdk/terminal/launch.d.ts +5 -0
  223. package/dist/sdk/terminal/launch.js +27 -0
  224. package/dist/sdk/terminal/logs.d.ts +14 -0
  225. package/dist/sdk/terminal/logs.js +59 -0
  226. package/dist/sdk/terminal/piExtension.d.ts +6 -0
  227. package/dist/sdk/terminal/piExtension.js +392 -0
  228. package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
  229. package/dist/sdk/terminal/pluginMenu.js +101 -0
  230. package/dist/sdk/terminal/socket.d.ts +70 -0
  231. package/dist/sdk/terminal/socket.js +256 -0
  232. package/dist/sdk/terminal/standalone.d.ts +18 -0
  233. package/dist/sdk/terminal/standalone.js +146 -0
  234. package/dist/sdk/terminal/terminals.d.ts +176 -0
  235. package/dist/sdk/terminal/terminals.js +767 -0
  236. package/dist/sdk/terminal/trajectory.d.ts +10 -0
  237. package/dist/sdk/terminal/trajectory.js +30 -0
  238. package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
  239. package/dist/sdk/terminal/tui/chrome.js +169 -0
  240. package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
  241. package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
  242. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -0
  243. package/dist/sdk/terminal/tui/commandPages.js +63 -0
  244. package/dist/sdk/terminal/tui/commands.d.ts +42 -0
  245. package/dist/sdk/terminal/tui/commands.js +276 -0
  246. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
  247. package/dist/sdk/terminal/tui/dialogGeometry.js +50 -0
  248. package/dist/sdk/terminal/tui/dialogs.d.ts +75 -0
  249. package/dist/sdk/terminal/tui/dialogs.js +363 -0
  250. package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
  251. package/dist/sdk/terminal/tui/keybindings.js +49 -0
  252. package/dist/sdk/terminal/tui/list.d.ts +73 -0
  253. package/dist/sdk/terminal/tui/list.js +196 -0
  254. package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
  255. package/dist/sdk/terminal/tui/modeChoices.js +70 -0
  256. package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
  257. package/dist/sdk/terminal/tui/modelPicker.js +155 -0
  258. package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
  259. package/dist/sdk/terminal/tui/mouse.js +3 -0
  260. package/dist/sdk/terminal/tui/page.d.ts +14 -0
  261. package/dist/sdk/terminal/tui/page.js +1 -0
  262. package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
  263. package/dist/sdk/terminal/tui/pageOverlay.js +145 -0
  264. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +54 -0
  265. package/dist/sdk/terminal/tui/pages/accountsPage.js +181 -0
  266. package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
  267. package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
  268. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +37 -0
  269. package/dist/sdk/terminal/tui/pages/doctorPage.js +145 -0
  270. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
  271. package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
  272. package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
  273. package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
  274. package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
  275. package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
  276. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
  277. package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
  278. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +55 -0
  279. package/dist/sdk/terminal/tui/pages/settingsPage.js +88 -0
  280. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +58 -0
  281. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +377 -0
  282. package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
  283. package/dist/sdk/terminal/tui/piAdapter.js +48 -0
  284. package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
  285. package/dist/sdk/terminal/tui/planMode.js +2 -0
  286. package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
  287. package/dist/sdk/terminal/tui/questionPicker.js +150 -0
  288. package/dist/sdk/terminal/tui/questions.d.ts +19 -0
  289. package/dist/sdk/terminal/tui/questions.js +42 -0
  290. package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
  291. package/dist/sdk/terminal/tui/runtime.js +441 -0
  292. package/dist/sdk/terminal/tui/search.d.ts +22 -0
  293. package/dist/sdk/terminal/tui/search.js +60 -0
  294. package/dist/sdk/terminal/tui/selection.d.ts +16 -0
  295. package/dist/sdk/terminal/tui/selection.js +16 -0
  296. package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
  297. package/dist/sdk/terminal/tui/sessionUi.js +30 -0
  298. package/dist/sdk/terminal/tui/settingsModel.d.ts +12 -0
  299. package/dist/sdk/terminal/tui/settingsModel.js +84 -0
  300. package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
  301. package/dist/sdk/terminal/tui/sideQuestion.js +197 -0
  302. package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
  303. package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
  304. package/dist/sdk/terminal/tui/status.d.ts +18 -0
  305. package/dist/sdk/terminal/tui/status.js +67 -0
  306. package/dist/sdk/terminal/tui/theme.d.ts +45 -0
  307. package/dist/sdk/terminal/tui/theme.js +176 -0
  308. package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
  309. package/dist/sdk/terminal/tui/treeModel.js +483 -0
  310. package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
  311. package/dist/sdk/terminal/tui/treePicker.js +251 -0
  312. package/dist/sdk/terminal/tui/ui.d.ts +47 -0
  313. package/dist/sdk/terminal/tui/ui.js +148 -0
  314. package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
  315. package/dist/sdk/terminal/tui/workingStatus.js +229 -0
  316. package/dist/sdk/tools/askUser.d.ts +6 -0
  317. package/dist/sdk/tools/askUser.js +74 -0
  318. package/dist/sdk/tools/checklist.d.ts +9 -0
  319. package/dist/sdk/tools/checklist.js +54 -0
  320. package/dist/sdk/tools/definitions.d.ts +30 -0
  321. package/dist/sdk/tools/definitions.js +117 -0
  322. package/dist/sdk/tools/dispatch.d.ts +16 -0
  323. package/dist/sdk/tools/dispatch.js +67 -0
  324. package/dist/sdk/tools/harnessTools.d.ts +6 -0
  325. package/dist/sdk/tools/harnessTools.js +20 -0
  326. package/dist/sdk/tools/sessionName.d.ts +7 -0
  327. package/dist/sdk/tools/sessionName.js +31 -0
  328. package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
  329. package/dist/sdk/tools/spawnSubagent.js +49 -0
  330. package/dist/sdk/tools/types.d.ts +48 -0
  331. package/dist/sdk/tools/types.js +1 -0
  332. package/dist/sdk/variant/components.d.ts +34 -0
  333. package/dist/sdk/variant/components.js +230 -0
  334. package/dist/sdk/variant/materialise.d.ts +66 -0
  335. package/dist/sdk/variant/materialise.js +81 -0
  336. package/dist/sdk/variant/migrate.d.ts +4 -0
  337. package/dist/sdk/variant/migrate.js +41 -0
  338. package/dist/sdk/variant/seed.d.ts +20 -0
  339. package/dist/sdk/variant/seed.js +116 -0
  340. package/dist/sdk/variant/store.d.ts +82 -0
  341. package/dist/sdk/variant/store.js +151 -0
  342. package/dist/sdk/variant/surface.d.ts +56 -0
  343. package/dist/sdk/variant/surface.js +81 -0
  344. package/dist/sdk/variant/trust.d.ts +27 -0
  345. package/dist/sdk/variant/trust.js +64 -0
  346. package/dist/sdk/variant/variant.d.ts +71 -0
  347. package/dist/sdk/variant/variant.js +331 -0
  348. package/dist/sdk/web/markdown.d.ts +10 -0
  349. package/dist/sdk/web/markdown.js +66 -0
  350. package/dist/sdk/web/safeRequest.d.ts +34 -0
  351. package/dist/sdk/web/safeRequest.js +175 -0
  352. package/dist/sdk/web/search.d.ts +53 -0
  353. package/dist/sdk/web/search.js +168 -0
  354. package/dist/sdk/web/text.d.ts +2 -0
  355. package/dist/sdk/web/text.js +7 -0
  356. package/dist/sdk/web/tools.d.ts +22 -0
  357. package/dist/sdk/web/tools.js +195 -0
  358. package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
  359. package/dist/sdk/wiki/notes.d.ts +68 -0
  360. package/dist/sdk/wiki/notes.js +297 -0
  361. package/dist/sdk/world/actions.d.ts +23 -0
  362. package/dist/sdk/world/actions.js +31 -0
  363. package/dist/sdk/world/cli.d.ts +12 -0
  364. package/dist/sdk/world/cli.js +166 -0
  365. package/dist/sdk/world/images.d.ts +20 -0
  366. package/dist/sdk/world/images.js +48 -0
  367. package/dist/sdk/world/untrusted.d.ts +12 -0
  368. package/dist/sdk/world/untrusted.js +20 -0
  369. package/dist/sdk/world/world.d.ts +65 -0
  370. package/dist/sdk/world/world.js +80 -0
  371. package/dist/terminal-opentui.js +13612 -0
  372. package/dist/terminal-pi.js +808 -151
  373. package/docs/README.md +22 -0
  374. package/docs/architecture/00-overview.md +159 -0
  375. package/docs/architecture/01-extension-points.md +78 -0
  376. package/docs/architecture/02-sessions-and-runs.md +146 -0
  377. package/docs/architecture/03-variants.md +95 -0
  378. package/docs/architecture/04-prompt.md +102 -0
  379. package/docs/architecture/05-refinement.md +107 -0
  380. package/docs/architecture/06-plugins-and-capabilities.md +93 -0
  381. package/docs/architecture/07-tools-and-gate.md +88 -0
  382. package/docs/architecture/08-memory-and-history.md +94 -0
  383. package/docs/architecture/09-accounts-and-connectors.md +90 -0
  384. package/docs/architecture/10-server-protocol.md +84 -0
  385. package/docs/architecture/11-terminal.md +81 -0
  386. package/docs/architecture/12-storage.md +61 -0
  387. package/docs/architecture/13-world-tools.md +23 -0
  388. package/docs/architecture/README.md +114 -0
  389. package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
  390. package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
  391. package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
  392. package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
  393. package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
  394. package/docs/architecture/proposals/PROP-0006-run-checklist.md +68 -0
  395. package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
  396. package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
  397. package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
  398. package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
  399. package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
  400. package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
  401. package/docs/architecture/proposals/README.md +76 -0
  402. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  403. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  404. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  405. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  406. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  407. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  408. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  409. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  410. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  411. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  412. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  413. package/docs/decisions/ADR-0013-doctor.md +27 -0
  414. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  415. package/docs/doctor.md +74 -0
  416. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  418. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  420. package/docs/features/README.md +20 -0
  421. package/docs/features/automations/README.md +41 -0
  422. package/docs/features/cores/README.md +39 -0
  423. package/docs/features/google-harness2/README.md +52 -0
  424. package/docs/features/integrations/README.md +40 -0
  425. package/docs/features/interfaces/README.md +29 -0
  426. package/docs/features/memory/README.md +28 -0
  427. package/docs/releases/1.0.0.md +40 -0
  428. package/docs/releases/README.md +36 -0
  429. package/docs/study/00-index.md +78 -0
  430. package/docs/study/arms/00-matrix.md +20 -0
  431. package/docs/study/arms/01-system-prompt.md +211 -0
  432. package/docs/study/arms/02-tools.md +79 -0
  433. package/docs/study/arms/03-subagents.md +90 -0
  434. package/docs/study/arms/04-skills.md +75 -0
  435. package/docs/study/arms/05-context-management.md +90 -0
  436. package/docs/study/arms/06-memory.md +90 -0
  437. package/docs/study/arms/07-governance.md +71 -0
  438. package/docs/study/arms/08-execution.md +69 -0
  439. package/docs/study/arms/09-observability.md +60 -0
  440. package/docs/study/arms/10-refinement.md +110 -0
  441. package/docs/study/btw-comparison.md +37 -0
  442. package/docs/study/feature-gap-review.md +42 -0
  443. package/docs/study/insights.md +123 -0
  444. package/docs/study/roadmap.md +72 -0
  445. package/docs/study/sources/claude-code.md +44 -0
  446. package/docs/study/sources/deepseek-harness.md +102 -0
  447. package/docs/study/sources/harness2.md +50 -0
  448. package/docs/study/sources/kimi-cli.md +42 -0
  449. package/docs/study/sources/omp.md +93 -0
  450. package/docs/study/sources/opencode.md +43 -0
  451. package/docs/study/sources/openhands.md +46 -0
  452. package/docs/study/sources/smolagents.md +40 -0
  453. package/docs/study/sources/swe-agent.md +34 -0
  454. package/docs/system-prompt-design.md +196 -0
  455. package/docs/terminal-tui.md +473 -56
  456. package/package.json +43 -13
  457. package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
  458. package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
  459. package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
  460. package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
  461. package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
  462. package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
  463. package/docs/evidence/terminal-2026-10-17/verification.json +0 -130
  464. package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
  465. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
  466. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
  467. package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
  468. package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
  469. package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
  470. package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
  471. package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
  472. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
  473. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
  474. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
  475. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
  476. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +0 -95
  477. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
  478. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
  479. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
  480. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
  481. package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +0 -27
  482. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
  483. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +0 -18
  484. package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +0 -95
  485. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
  486. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
  487. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +0 -60
  488. package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +0 -24
  489. package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
  490. package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +0 -57
  491. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
  492. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
  493. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +0 -58
  494. package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
  495. package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +0 -320
  496. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +0 -30
  497. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +0 -133
  498. package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +0 -20
  499. package/docs/evidence/terminal-2026-10-17-followup/verification.json +0 -207
  500. package/src/accounts/accounts.test.ts +0 -333
  501. package/src/accounts/accounts.ts +0 -658
  502. package/src/accounts/env.test.ts +0 -95
  503. package/src/accounts/env.ts +0 -338
  504. package/src/accounts/secrets.ts +0 -50
  505. package/src/accounts/store.ts +0 -338
  506. package/src/capabilities/api.ts +0 -75
  507. package/src/capabilities/runSnapshot.ts +0 -59
  508. package/src/capabilities/types.ts +0 -34
  509. package/src/cli.ts +0 -118
  510. package/src/core/bus.ts +0 -34
  511. package/src/core/changes.ts +0 -33
  512. package/src/core/env.ts +0 -27
  513. package/src/core/errors.ts +0 -32
  514. package/src/core/frontmatter.ts +0 -47
  515. package/src/core/fs.test.ts +0 -38
  516. package/src/core/fs.ts +0 -92
  517. package/src/core/index.ts +0 -193
  518. package/src/core/path.test.ts +0 -14
  519. package/src/core/path.ts +0 -79
  520. package/src/core/projects.ts +0 -90
  521. package/src/core/text.ts +0 -39
  522. package/src/harness.ts +0 -312
  523. package/src/hub/catalog.json +0 -123
  524. package/src/hub/cli.ts +0 -59
  525. package/src/hub/hub.test.ts +0 -205
  526. package/src/hub/hub.ts +0 -256
  527. package/src/hub/schema.ts +0 -81
  528. package/src/index.ts +0 -75
  529. package/src/mcp/connections.ts +0 -614
  530. package/src/mcp/manager.ts +0 -130
  531. package/src/mcp/oauth.ts +0 -195
  532. package/src/mcp/scopeMigration.test.ts +0 -79
  533. package/src/mcp/scopeMigration.ts +0 -204
  534. package/src/mcp/service.test.ts +0 -376
  535. package/src/mcp/service.ts +0 -549
  536. package/src/mcp/types.ts +0 -108
  537. package/src/memory/api.test.ts +0 -82
  538. package/src/memory/api.ts +0 -303
  539. package/src/memory/blocks.test.ts +0 -78
  540. package/src/memory/blocks.ts +0 -408
  541. package/src/memory/caller.ts +0 -69
  542. package/src/memory/curation.test.ts +0 -163
  543. package/src/memory/curation.ts +0 -64
  544. package/src/memory/dispatch.ts +0 -59
  545. package/src/memory/facts.test.ts +0 -41
  546. package/src/memory/facts.ts +0 -248
  547. package/src/memory/graph.ts +0 -103
  548. package/src/memory/health.test.ts +0 -130
  549. package/src/memory/health.ts +0 -74
  550. package/src/memory/maintainer.ts +0 -272
  551. package/src/memory/maintenance.test.ts +0 -176
  552. package/src/memory/maintenance.ts +0 -518
  553. package/src/memory/migrate.ts +0 -79
  554. package/src/memory/operations.ts +0 -150
  555. package/src/memory/proposals.test.ts +0 -168
  556. package/src/memory/proposals.ts +0 -584
  557. package/src/memory/recall.test.ts +0 -115
  558. package/src/memory/recall.ts +0 -278
  559. package/src/memory/references.ts +0 -77
  560. package/src/memory/runContext.ts +0 -93
  561. package/src/memory/secrets.ts +0 -6
  562. package/src/memory/store.test.ts +0 -66
  563. package/src/memory/store.ts +0 -385
  564. package/src/memory/wiki.test.ts +0 -47
  565. package/src/memory/wiki.ts +0 -422
  566. package/src/memory/wikiIndex.test.ts +0 -88
  567. package/src/memory/wikiIndex.ts +0 -116
  568. package/src/plugins/api.ts +0 -181
  569. package/src/plugins/attachments.test.ts +0 -84
  570. package/src/plugins/attachments.ts +0 -141
  571. package/src/plugins/builtin.ts +0 -82
  572. package/src/plugins/catalogue.test.ts +0 -254
  573. package/src/plugins/catalogue.ts +0 -251
  574. package/src/plugins/cli.ts +0 -184
  575. package/src/plugins/discover.ts +0 -151
  576. package/src/plugins/firstParty.test.ts +0 -143
  577. package/src/plugins/firstParty.ts +0 -129
  578. package/src/plugins/hooks.test.ts +0 -250
  579. package/src/plugins/hooks.ts +0 -239
  580. package/src/plugins/identity.ts +0 -37
  581. package/src/plugins/install.test.ts +0 -107
  582. package/src/plugins/install.ts +0 -106
  583. package/src/plugins/inventory.ts +0 -123
  584. package/src/plugins/manifest.ts +0 -76
  585. package/src/plugins/plugins.test.ts +0 -205
  586. package/src/plugins/plugins.ts +0 -189
  587. package/src/plugins/proposal.ts +0 -121
  588. package/src/plugins/runtime.test.ts +0 -40
  589. package/src/plugins/runtime.ts +0 -82
  590. package/src/plugins/trust.ts +0 -142
  591. package/src/plugins/types.ts +0 -149
  592. package/src/prompt/compile.test.ts +0 -261
  593. package/src/prompt/compile.ts +0 -732
  594. package/src/server/methods.ts +0 -349
  595. package/src/server/remote.ts +0 -77
  596. package/src/server/rpc.ts +0 -116
  597. package/src/server/serve.ts +0 -28
  598. package/src/server/server.test.ts +0 -174
  599. package/src/sessions/approvals.ts +0 -118
  600. package/src/sessions/contracts.ts +0 -336
  601. package/src/sessions/conversation.test.ts +0 -177
  602. package/src/sessions/extensionSession.test.ts +0 -74
  603. package/src/sessions/extensionUi.test.ts +0 -65
  604. package/src/sessions/extensionUi.ts +0 -102
  605. package/src/sessions/history.ts +0 -51
  606. package/src/sessions/lineageJoin.ts +0 -75
  607. package/src/sessions/policy.ts +0 -36
  608. package/src/sessions/pricing.ts +0 -60
  609. package/src/sessions/questionBatches.test.ts +0 -110
  610. package/src/sessions/reasoningSummaries.ts +0 -59
  611. package/src/sessions/registry.ts +0 -381
  612. package/src/sessions/runIndex.ts +0 -99
  613. package/src/sessions/runStore.test.ts +0 -152
  614. package/src/sessions/runStore.ts +0 -332
  615. package/src/sessions/runner.ts +0 -604
  616. package/src/sessions/runtimeResources.test.ts +0 -61
  617. package/src/sessions/sessions.test.ts +0 -549
  618. package/src/sessions/sessions.ts +0 -339
  619. package/src/skills/registry.test.ts +0 -104
  620. package/src/skills/registry.ts +0 -413
  621. package/src/terminal/accountsMenu.test.ts +0 -225
  622. package/src/terminal/accountsMenu.ts +0 -382
  623. package/src/terminal/cli.ts +0 -149
  624. package/src/terminal/client.ts +0 -74
  625. package/src/terminal/control.test.ts +0 -23
  626. package/src/terminal/control.ts +0 -23
  627. package/src/terminal/controller.ts +0 -291
  628. package/src/terminal/hubMenu.ts +0 -24
  629. package/src/terminal/launch.test.ts +0 -25
  630. package/src/terminal/launch.ts +0 -48
  631. package/src/terminal/piExtension.lifecycle.test.ts +0 -55
  632. package/src/terminal/piExtension.ts +0 -259
  633. package/src/terminal/pluginControl.test.ts +0 -146
  634. package/src/terminal/pluginMenu.ts +0 -112
  635. package/src/terminal/socket.test.ts +0 -71
  636. package/src/terminal/socket.ts +0 -232
  637. package/src/terminal/standalone.test.ts +0 -167
  638. package/src/terminal/standalone.ts +0 -153
  639. package/src/terminal/terminal.test.ts +0 -399
  640. package/src/terminal/terminals.ts +0 -553
  641. package/src/terminal/tui/application.test.ts +0 -114
  642. package/src/terminal/tui/application.ts +0 -491
  643. package/src/terminal/tui/commands.test.ts +0 -218
  644. package/src/terminal/tui/commands.ts +0 -361
  645. package/src/terminal/tui/dialogs.ts +0 -301
  646. package/src/terminal/tui/editor.test.ts +0 -84
  647. package/src/terminal/tui/editor.ts +0 -79
  648. package/src/terminal/tui/keybindings.test.ts +0 -22
  649. package/src/terminal/tui/keybindings.ts +0 -50
  650. package/src/terminal/tui/piAdapter.ts +0 -62
  651. package/src/terminal/tui/presentation.test.ts +0 -79
  652. package/src/terminal/tui/questions.test.ts +0 -41
  653. package/src/terminal/tui/questions.ts +0 -47
  654. package/src/terminal/tui/runtime.socket.test.ts +0 -104
  655. package/src/terminal/tui/runtime.test.ts +0 -215
  656. package/src/terminal/tui/runtime.ts +0 -388
  657. package/src/terminal/tui/sessionUi.ts +0 -24
  658. package/src/terminal/tui/settings.test.ts +0 -150
  659. package/src/terminal/tui/settings.ts +0 -188
  660. package/src/terminal/tui/status.test.ts +0 -70
  661. package/src/terminal/tui/status.ts +0 -109
  662. package/src/terminal/tui/theme.ts +0 -174
  663. package/src/terminal/tui/tools.test.ts +0 -145
  664. package/src/terminal/tui/tools.ts +0 -142
  665. package/src/terminal/tui/transcript.test.ts +0 -25
  666. package/src/terminal/tui/transcript.ts +0 -124
  667. package/src/terminal/tui/ui.test.ts +0 -313
  668. package/src/terminal/tui/ui.ts +0 -166
  669. package/src/terminal/tui/welcome.ts +0 -102
  670. package/src/tools/askUser.test.ts +0 -69
  671. package/src/tools/askUser.ts +0 -59
  672. package/src/tools/definitions.ts +0 -187
  673. package/src/tools/maintenance.ts +0 -24
  674. package/src/tools/memoryTools.ts +0 -22
  675. package/src/tools/pluginPropose.ts +0 -41
  676. package/src/tools/registryWrite.test.ts +0 -101
  677. package/src/tools/registryWrite.ts +0 -182
  678. package/src/tools/spawnSubagent.ts +0 -92
  679. package/src/tools/types.ts +0 -39
  680. package/src/web/safeRequest.ts +0 -171
  681. package/src/web/text.ts +0 -53
  682. package/src/web/tools.ts +0 -134
  683. package/src/web/web.test.ts +0 -141
@@ -0,0 +1,173 @@
1
+ // Lessons from finished runs. When the `lessons` plugin is on for a run's caller, a completed
2
+ // top-level run is reflected on in the background: a file-tools-only session reads its record and
3
+ // may keep one general lesson as a Wiki note under `library/lessons/`. The lesson shape and the
4
+ // answer-free guards are refinement's (harness²); the caps follow OMP's memory budget.
5
+ //
6
+ // Lessons are reference notes (INV-MEM-1). They never enter the stable prefix and never change a
7
+ // variant; something that should become an instruction goes through refinement and `adopt`.
8
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
9
+ import { tmpdir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ import { loadRun as loadCapabilities } from "../capabilities/runSnapshot.js";
12
+ import { log } from "../core/bus.js";
13
+ import * as frontmatter from "../core/frontmatter.js";
14
+ import { looksSecret } from "../core/secrets.js";
15
+ import * as attachments from "../plugins/attachments.js";
16
+ import { LESSONS, LESSONS_CODE, LESSONS_SETTINGS, settingValue } from "../plugins/firstParty.js";
17
+ import { assertNoGraderVerdicts, assertVariantHasNoGraderVerdicts } from "../refine/evidence.js";
18
+ import { hasExperience } from "../refine/library.js";
19
+ import { PiImprover } from "../refine/pi.js";
20
+ import { parseExperience } from "../refine/selection.js";
21
+ import { renderEvents } from "../refine/trajectory.js";
22
+ import { executionEvents, findRun, readEvents } from "../sessions/runStore.js";
23
+ import * as notes from "../wiki/notes.js";
24
+ import { lessonMission, REFLECTION_IDENTITY } from "./lessonPrompt.js";
25
+ export const REFLECTION_TRIGGER = 'reflection';
26
+ export const LESSONS_FOLDER = 'library/lessons';
27
+ /** Runs that are themselves part of improving the harness are never reflected on. */
28
+ const SKIPPED_TRIGGERS = new Set(['probe', 'improver', REFLECTION_TRIGGER]);
29
+ const REFLECTION_TOOLS = ['read', 'grep', 'find', 'ls'];
30
+ /** The same floor refinement keeps for a trajectory (INV-REF-8). */
31
+ const OBS_TRUNC = 10_000;
32
+ const slug = (text) => text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 60).replace(/-+$/, '') || 'lesson';
33
+ /** The lessons the Wiki keeps now. */
34
+ export function keptLessons(root) {
35
+ return notes.paths(root).filter((path) => path.startsWith(`${LESSONS_FOLDER}/`)).flatMap((path) => {
36
+ try {
37
+ const text = readFileSync(join(notes.wikiDir(root), `${path}.md`), 'utf8');
38
+ const parsed = frontmatter.parse(text);
39
+ const front = parsed?.front ?? {};
40
+ const sources = Array.isArray(front.sources) ? front.sources.filter((id) => typeof id === 'string') : [];
41
+ return [{ path, cue: typeof front.cue === 'string' ? front.cue : '', sources, front, body: parsed?.body ?? text }];
42
+ }
43
+ catch {
44
+ return [];
45
+ }
46
+ });
47
+ }
48
+ /** The model the run used, as Pi names it, from its last usage report. */
49
+ function modelOf(root, runId) {
50
+ const usage = readEvents(root, runId).filter((event) => event.type === 'usage.updated').at(-1)?.payload;
51
+ return typeof usage?.model === 'string' && typeof usage.provider === 'string' ? `${usage.provider}/${usage.model}` : null;
52
+ }
53
+ function lessonNote(experience, sources) {
54
+ const title = experience.cue.length > 80 ? `${experience.cue.slice(0, 77).trimEnd()}…` : experience.cue;
55
+ const body = [`# ${title}`, '', `**When:** ${experience.cue}`, '', `**Do:** ${experience.lesson}`, '', `**Evidence:** ${experience.evidence}`].join('\n');
56
+ return frontmatter.serialize({ title, cue: experience.cue, confidence: experience.confidence ?? null, sources }, body);
57
+ }
58
+ export class Lessons {
59
+ options;
60
+ queue = [];
61
+ abort = new AbortController();
62
+ draining = null;
63
+ closed = false;
64
+ constructor(options) {
65
+ this.options = options;
66
+ }
67
+ /** Called when a run completes. Cheap: the work happens later, one run at a time. */
68
+ consider(run) {
69
+ if (this.closed || !run || run.status !== 'completed' || run.parentRunId || run.relation)
70
+ return;
71
+ if (run.trigger && SKIPPED_TRIGGERS.has(run.trigger))
72
+ return;
73
+ if (this.queue.includes(run.id))
74
+ return;
75
+ this.queue.push(run.id);
76
+ this.draining ??= this.drain().finally(() => {
77
+ this.draining = null;
78
+ });
79
+ }
80
+ /** Resolves when everything queued so far was reflected on. */
81
+ async idle() {
82
+ while (this.draining)
83
+ await this.draining;
84
+ }
85
+ async close() {
86
+ this.closed = true;
87
+ this.queue.length = 0;
88
+ this.abort.abort();
89
+ await this.draining?.catch(() => undefined);
90
+ }
91
+ async drain() {
92
+ while (this.queue.length && !this.closed) {
93
+ const runId = this.queue.shift();
94
+ try {
95
+ const outcome = await this.reflect(runId);
96
+ if (outcome.kind !== 'skipped')
97
+ log(`lessons: run ${runId}: ${outcome.kind}${'path' in outcome ? ` ${outcome.path}` : ''}`);
98
+ }
99
+ catch (error) {
100
+ log(`lessons: run ${runId} was not reflected on`, error instanceof Error ? error.message : String(error));
101
+ }
102
+ }
103
+ }
104
+ /** The plugin's settings for this run's caller, or null when it is off for them. */
105
+ limits(root, runId) {
106
+ const contribution = `${LESSONS}/code/${LESSONS_CODE}`;
107
+ if (!loadCapabilities(root, runId)?.contributions.includes(contribution))
108
+ return null;
109
+ const saved = attachments.load(root).settings[LESSONS];
110
+ const value = (key) => settingValue(LESSONS_SETTINGS.find((setting) => setting.key === key), saved);
111
+ return { minToolCalls: value('minToolCalls'), maxLessons: value('maxLessons'), maxChars: value('maxChars') };
112
+ }
113
+ /** Reflects on one finished run. Exposed for tests and for a host that wants to ask directly. */
114
+ async reflect(runId) {
115
+ const root = this.options.root();
116
+ const run = findRun(root, runId);
117
+ if (!run || run.status !== 'completed')
118
+ return { kind: 'skipped', reason: 'not completed' };
119
+ const limits = this.limits(root, runId);
120
+ if (!limits)
121
+ return { kind: 'skipped', reason: 'plugin off' };
122
+ const events = executionEvents(readEvents(root, runId));
123
+ if (events.filter((event) => event.type === 'tool.started').length < limits.minToolCalls)
124
+ return { kind: 'skipped', reason: 'too few tool calls' };
125
+ const kept = keptLessons(root);
126
+ if (kept.some((lesson) => lesson.sources.includes(runId)))
127
+ return { kind: 'skipped', reason: 'already reflected' };
128
+ if (kept.length >= limits.maxLessons)
129
+ return { kind: 'skipped', reason: 'lesson limit reached' };
130
+ const context = mkdtempSync(join(tmpdir(), 'harness-lesson-'));
131
+ try {
132
+ const goal = run.goal ? `# Request\n\n${run.goal}\n\n# Record\n\n` : '# Record\n\n';
133
+ writeFileSync(join(context, 'run.md'), `${goal}${renderEvents(events, { obsTrunc: OBS_TRUNC })}\n`);
134
+ writeFileSync(join(context, 'lessons.md'), kept.length ? `${kept.map((lesson) => `${lesson.path} -- ${lesson.cue}`).join('\n')}\n` : '(no lessons kept yet)\n');
135
+ assertNoGraderVerdicts(context);
136
+ const reflector = this.options.reflector?.(run, modelOf(root, runId), this.abort.signal)
137
+ ?? new PiImprover(this.options.runtime, join(root, 'reflection'), { accountId: run.accountId, model: modelOf(root, runId), effort: 'medium' }, this.abort.signal, { trigger: REFLECTION_TRIGGER, identity: REFLECTION_IDENTITY, tools: REFLECTION_TOOLS });
138
+ const reply = await reflector.call({ mission: lessonMission(), contextDir: context, label: `lesson-${runId}`, signal: this.abort.signal });
139
+ return this.keep(root, runId, reply.text, kept, limits);
140
+ }
141
+ finally {
142
+ rmSync(context, { recursive: true, force: true });
143
+ }
144
+ }
145
+ keep(root, runId, text, kept, limits) {
146
+ if (/^\s*NO_ENTRY\s*$/m.test(text) && !text.includes('<experience>'))
147
+ return { kind: 'no_entry' };
148
+ const same = /^\s*SAME\s+(\S+)\s*$/m.exec(text)?.[1]?.replace(/\.md$/, '');
149
+ if (same) {
150
+ const lesson = kept.find((entry) => entry.path === same);
151
+ if (!lesson)
152
+ return { kind: 'skipped', reason: `named an unknown lesson ${same}` };
153
+ notes.write(root, lesson.path, frontmatter.serialize({ ...lesson.front, sources: [...lesson.sources, runId] }, lesson.body), { actor: REFLECTION_TRIGGER, reason: `Seen again in run ${runId}` });
154
+ return { kind: 'same', path: lesson.path };
155
+ }
156
+ const experience = parseExperience(text);
157
+ if (!hasExperience(experience))
158
+ return { kind: 'no_entry' };
159
+ const body = lessonNote(experience, [runId]);
160
+ if (`${experience.cue}${experience.lesson}${experience.evidence}`.length > limits.maxChars)
161
+ return { kind: 'skipped', reason: 'lesson too long' };
162
+ if (looksSecret(body))
163
+ return { kind: 'skipped', reason: 'lesson looked like it held a credential' };
164
+ assertVariantHasNoGraderVerdicts({ 'lesson.md': body });
165
+ const taken = new Set(notes.paths(root));
166
+ const base = `${LESSONS_FOLDER}/${slug(experience.cue)}`;
167
+ let path = base;
168
+ for (let n = 2; taken.has(path); n++)
169
+ path = `${base}-${n}`;
170
+ notes.write(root, path, body, { actor: REFLECTION_TRIGGER, reason: `Lesson from run ${runId}` });
171
+ return { kind: 'written', path };
172
+ }
173
+ }
@@ -0,0 +1,68 @@
1
+ import type { HarnessEnv } from "../core/env.js";
2
+ import type { RunEvent, RunRecord } from "../sessions/contracts.js";
3
+ import { type CallerContext } from "../core/caller.js";
4
+ export interface Passage {
5
+ /** `user`, `event` (a turn the application started, not the user), `assistant`, or `tool`. */
6
+ role: 'user' | 'event' | 'assistant' | 'tool';
7
+ at: string;
8
+ text: string;
9
+ }
10
+ /** A run as recall sees it: what was asked, what the assistant said, and which tools it used. */
11
+ export declare function passages(run: RunRecord, events: readonly RunEvent[]): Passage[];
12
+ /** Indexes one run from its record and events. Index failures never block a run. */
13
+ export declare function indexRun(root: string, runId: string): void;
14
+ /**
15
+ * Indexes every run that is missing or whose status changed since it was indexed. Returns how
16
+ * many were (re)indexed. Called at startup, so earlier conversations are searchable.
17
+ */
18
+ export declare function sync(root: string): number;
19
+ /**
20
+ * What a caller may recall. An agent searches its own conversations by default and everything
21
+ * when it asks; a session only sees session runs in its own project (or its own session when
22
+ * it has none), never an agent's conversation.
23
+ */
24
+ export interface Scope {
25
+ /** Only runs of this session. */
26
+ sessionId?: string | null;
27
+ /** Only runs of this mode (`code` for sessions). */
28
+ mode?: string | null;
29
+ projectId?: string | null;
30
+ /** ISO date or timestamp; only passages at or after it. */
31
+ since?: string | null;
32
+ }
33
+ export interface RecallHit {
34
+ runId: string;
35
+ seq: number;
36
+ role: string;
37
+ at: string;
38
+ mode: string;
39
+ sessionId: string;
40
+ projectId: string | null;
41
+ snippet: string;
42
+ }
43
+ export declare function search(root: string, query: string, scope: Scope, limit: number): RecallHit[];
44
+ export interface RecallMessage {
45
+ seq: number;
46
+ role: string;
47
+ at: string;
48
+ text: string;
49
+ }
50
+ export declare function read(root: string, runId: string): RecallMessage[];
51
+ type Params = Record<string, unknown> | null | undefined;
52
+ /** Who a run belonged to, for a person or a model reading a hit. */
53
+ export declare function sourceLabel(env: HarnessEnv, mode: string, sessionId: string, projectId: string | null): string;
54
+ /** `recall.search` as text for a model. */
55
+ export declare function searchTool(env: HarnessEnv, context: CallerContext, params: Params): string;
56
+ /** `recall.read` as text for a model. */
57
+ export declare function readTool(env: HarnessEnv, context: CallerContext, params: Params): string;
58
+ export interface RecallFilter {
59
+ sessionId?: string | null;
60
+ projectId?: string | null;
61
+ since?: string | null;
62
+ }
63
+ export type RecallResult = RecallHit & {
64
+ source: string;
65
+ };
66
+ /** A person's search: every conversation and run, narrowed only by the filter. */
67
+ export declare function searchAll(env: HarnessEnv, query: string, filter?: RecallFilter): RecallResult[];
68
+ export {};
@@ -0,0 +1,199 @@
1
+ import { logLine } from "../core/bus.js";
2
+ import { invalid, notFound } from "../core/errors.js";
3
+ import { all, run as execute, transaction, withIndex } from "../core/index.js";
4
+ import { findProject, listProjects } from "../core/projects.js";
5
+ import { charCount, takeChars } from "../core/text.js";
6
+ import { readAllRuns } from "../sessions/runIndex.js";
7
+ import { findRun, readEvents } from "../sessions/runStore.js";
8
+ import { isSession, projectOf } from "../core/caller.js";
9
+ const PASSAGE_LIMIT = 6000;
10
+ const READ_LIMIT = 12_000;
11
+ const SEARCH_DEFAULT = 8;
12
+ const SEARCH_MAX = 30;
13
+ /** A run as recall sees it: what was asked, what the assistant said, and which tools it used. */
14
+ export function passages(run, events) {
15
+ const found = [];
16
+ const goal = run.goal?.trim();
17
+ if (goal)
18
+ found.push({ role: goal.startsWith('[App coordination event') ? 'event' : 'user', at: run.startedAt, text: takeChars(goal, PASSAGE_LIMIT) });
19
+ for (const event of events) {
20
+ const payload = event.payload;
21
+ if (event.type === 'message.completed' && payload.role === 'assistant') {
22
+ const text = typeof payload.text === 'string' ? payload.text.trim() : '';
23
+ if (text)
24
+ found.push({ role: 'assistant', at: event.timestamp, text: takeChars(text, PASSAGE_LIMIT) });
25
+ }
26
+ else if (event.type === 'tool.started') {
27
+ const summary = typeof payload.summary === 'string' ? payload.summary.trim() : '';
28
+ if (summary)
29
+ found.push({ role: 'tool', at: event.timestamp, text: takeChars(`${typeof payload.name === 'string' ? payload.name : 'tool'}: ${summary}`, PASSAGE_LIMIT) });
30
+ }
31
+ }
32
+ return found;
33
+ }
34
+ function writeRun(database, run, found) {
35
+ execute(database, 'DELETE FROM recall_fts WHERE run_id = ?1', run.id);
36
+ found.forEach((passage, seq) => {
37
+ execute(database, 'INSERT INTO recall_fts (run_id, seq, role, at, mode, session_id, project_id, text) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)', run.id, seq, passage.role, passage.at, run.mode, run.sessionId, run.projectId, passage.text);
38
+ });
39
+ execute(database, 'INSERT OR REPLACE INTO recall_runs (run_id, passages, status) VALUES (?1, ?2, ?3)', run.id, found.length, run.status);
40
+ }
41
+ function eventsOf(root, runId) {
42
+ try {
43
+ return readEvents(root, runId);
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
49
+ /** Indexes one run from its record and events. Index failures never block a run. */
50
+ export function indexRun(root, runId) {
51
+ const run = findRun(root, runId);
52
+ if (!run)
53
+ return;
54
+ const found = passages(run, eventsOf(root, runId));
55
+ try {
56
+ withIndex(root, (database) => writeRun(database, run, found));
57
+ }
58
+ catch (error) {
59
+ logLine(`[recall] run ${runId} was not indexed: ${error instanceof Error ? error.message : String(error)}`);
60
+ }
61
+ }
62
+ /**
63
+ * Indexes every run that is missing or whose status changed since it was indexed. Returns how
64
+ * many were (re)indexed. Called at startup, so earlier conversations are searchable.
65
+ */
66
+ export function sync(root) {
67
+ const known = new Map();
68
+ withIndex(root, (database) => {
69
+ for (const row of all(database, 'SELECT run_id, status FROM recall_runs'))
70
+ known.set(row.run_id, row.status);
71
+ });
72
+ const pending = readAllRuns(root)
73
+ .filter((run) => known.get(run.id) !== run.status)
74
+ .map((run) => ({ run, found: passages(run, eventsOf(root, run.id)) }));
75
+ if (pending.length)
76
+ withIndex(root, (database) => transaction(database, () => pending.forEach(({ run, found }) => writeRun(database, run, found))));
77
+ return pending.length;
78
+ }
79
+ /** Any word may match; passages that match more of them, and rarer ones, rank first. */
80
+ function ftsAny(query) {
81
+ const terms = [];
82
+ for (const word of query.split(/[^\p{Alphabetic}\p{N}]+/u)) {
83
+ if (charCount(word) <= 1)
84
+ continue;
85
+ const term = `"${word.toLowerCase()}"*`;
86
+ if (!terms.includes(term) && terms.length < 24)
87
+ terms.push(term);
88
+ }
89
+ return terms.length ? terms.join(' OR ') : null;
90
+ }
91
+ export function search(root, query, scope, limit) {
92
+ const fts = ftsAny(query);
93
+ if (!fts)
94
+ return [];
95
+ return withIndex(root, (database) => all(database, `SELECT run_id, seq, role, at, mode, session_id, project_id, snippet(recall_fts, 7, '', '', '…', 40) AS snippet
96
+ FROM recall_fts WHERE recall_fts MATCH ?1
97
+ AND (?2 IS NULL OR session_id = ?2) AND (?3 IS NULL OR mode = ?3)
98
+ AND (?4 IS NULL OR project_id = ?4) AND (?5 IS NULL OR at >= ?5)
99
+ ORDER BY bm25(recall_fts), at DESC LIMIT ?6`, fts, scope.sessionId ?? null, scope.mode ?? null, scope.projectId ?? null, scope.since ?? null, Math.min(Math.max(limit, 1), SEARCH_MAX)).map((row) => ({ runId: row.run_id, seq: Number(row.seq), role: row.role, at: row.at ?? '', mode: row.mode ?? '', sessionId: row.session_id ?? '', projectId: row.project_id, snippet: row.snippet })));
100
+ }
101
+ export function read(root, runId) {
102
+ return withIndex(root, (database) => all(database, 'SELECT seq, role, at, text FROM recall_fts WHERE run_id = ?1 ORDER BY CAST(seq AS INTEGER)', runId).map((row) => ({ seq: Number(row.seq), role: row.role, at: row.at ?? '', text: row.text })));
103
+ }
104
+ function textParam(params, key) {
105
+ const value = params?.[key];
106
+ return typeof value === 'string' ? value.trim() : '';
107
+ }
108
+ /** The widest scope a caller may use, narrowed by what it asked for. */
109
+ function callerScope(root, context, params) {
110
+ const since = textParam(params, 'since') || null;
111
+ if (isSession(context)) {
112
+ // A session never reads an agent's conversations: only session runs of its project, or its own.
113
+ const projectId = projectOf(root, context)?.id ?? null;
114
+ if (!projectId && !context.sessionId)
115
+ throw invalid('Recall needs a session.');
116
+ return { sessionId: projectId ? null : context.sessionId, mode: 'code', projectId, since };
117
+ }
118
+ if (!context.agentId)
119
+ throw invalid('Recall needs an agent or a Harness session.');
120
+ const key = textParam(params, 'project');
121
+ let projectId = null;
122
+ if (key) {
123
+ const project = listProjects(root).find((entry) => entry.id === key || entry.slug === key || entry.name.toLowerCase() === key.toLowerCase());
124
+ if (!project)
125
+ throw invalid(`There is no project called ${key}.`);
126
+ projectId = project.id;
127
+ }
128
+ const everything = textParam(params, 'scope') === 'all' || projectId !== null;
129
+ return { sessionId: everything ? null : context.agentId, mode: null, projectId, since };
130
+ }
131
+ function mayRead(scope, run) {
132
+ if (!scope.mode)
133
+ return true;
134
+ return scope.mode === run.mode && (!scope.projectId || scope.projectId === run.projectId) && (!scope.sessionId || scope.sessionId === run.sessionId);
135
+ }
136
+ /** Who a run belonged to, for a person or a model reading a hit. */
137
+ export function sourceLabel(env, mode, sessionId, projectId) {
138
+ if (mode === 'chat') {
139
+ // One of an agent's extra conversations has its own id.
140
+ const owner = env.directory.sessionAgent(sessionId);
141
+ const name = env.directory.agentName(sessionId) ?? (owner ? env.directory.agentName(owner) : null);
142
+ return name ? `chat with ${name}` : 'group or earlier chat';
143
+ }
144
+ try {
145
+ return projectId ? `Harness session in ${findProject(env.root, projectId).name}` : 'Harness session';
146
+ }
147
+ catch {
148
+ return 'Harness session';
149
+ }
150
+ }
151
+ /** Whether a conversation belongs to an agent the caller may not recall. */
152
+ function excluded(env, context, sessionId) {
153
+ const hidden = context.recallExcludeAgents ?? [];
154
+ if (!hidden.length)
155
+ return false;
156
+ return hidden.includes(sessionId) || hidden.includes(env.directory.sessionAgent(sessionId) ?? '');
157
+ }
158
+ /** `recall.search` as text for a model. */
159
+ export function searchTool(env, context, params) {
160
+ const query = textParam(params, 'query');
161
+ if (!query)
162
+ throw invalid('Give a query.');
163
+ const scope = callerScope(env.root, context, params);
164
+ const requested = params?.limit;
165
+ const limit = typeof requested === 'number' && Number.isInteger(requested) && requested >= 0 ? requested : SEARCH_DEFAULT;
166
+ // The caller's current run is what it is in the middle of, not something to recall.
167
+ const hits = search(env.root, query, scope, limit + 4 + (context.recallExcludeAgents?.length ? SEARCH_MAX : 0)).filter((hit) => hit.runId !== context.runId && !excluded(env, context, hit.sessionId)).slice(0, Math.min(Math.max(limit, 1), SEARCH_MAX));
168
+ if (!hits.length) {
169
+ return scope.sessionId && !isSession(context) ? 'Nothing in your own conversations matches. Pass scope "all" to search every conversation and Harness run.' : 'Nothing in the recorded history matches.';
170
+ }
171
+ return `${hits.map((hit) => `- [run ${hit.runId} · ${hit.at.slice(0, 10)} · ${sourceLabel(env, hit.mode, hit.sessionId, hit.projectId)}] ${hit.role}: ${hit.snippet.replaceAll('\n', ' ')}`).join('\n')}\n\nRead a whole run with history_read and its run id.`;
172
+ }
173
+ /** `recall.read` as text for a model. */
174
+ export function readTool(env, context, params) {
175
+ const runId = textParam(params, 'run') || textParam(params, 'runId');
176
+ const run = findRun(env.root, runId);
177
+ if (!run)
178
+ throw notFound('Run');
179
+ // Reading is as wide as an "all" search for an agent, and as narrow as a search for a session.
180
+ if (!mayRead(callerScope(env.root, context, { scope: 'all' }), run) || excluded(env, context, run.sessionId))
181
+ throw notFound('Run');
182
+ const messages = read(env.root, run.id);
183
+ if (!messages.length)
184
+ return 'That run has no recorded messages.';
185
+ let text = `Run ${run.id} · ${run.startedAt.slice(0, 16)} · ${sourceLabel(env, run.mode, run.sessionId, run.projectId)} · ${run.status}\n`;
186
+ for (const message of messages) {
187
+ const line = `\n${message.role}: ${message.text}\n`;
188
+ if (charCount(text) + charCount(line) > READ_LIMIT) {
189
+ text += '\n(The rest of the run was left out.)\n';
190
+ break;
191
+ }
192
+ text += line;
193
+ }
194
+ return text;
195
+ }
196
+ /** A person's search: every conversation and run, narrowed only by the filter. */
197
+ export function searchAll(env, query, filter = {}) {
198
+ return search(env.root, query, { sessionId: filter.sessionId, mode: null, projectId: filter.projectId, since: filter.since || null }, SEARCH_MAX).map((hit) => ({ ...hit, source: sourceLabel(env, hit.mode, hit.sessionId, hit.projectId) }));
199
+ }
@@ -0,0 +1,7 @@
1
+ import type { HarnessEnv } from "../core/env.js";
2
+ import type { CallerContext } from "../core/caller.js";
3
+ export type Params = Record<string, unknown> | null | undefined;
4
+ /** `trajectory.search`: structured list/search over the current Harness data root. */
5
+ export declare function searchTool(env: HarnessEnv, context: CallerContext, params: Params): string;
6
+ /** `trajectory.read`: a bounded page of the events that affected a run. */
7
+ export declare function readTool(env: HarnessEnv, context: CallerContext, params: Params): string;
@@ -0,0 +1,216 @@
1
+ import { invalid, notFound } from "../core/errors.js";
2
+ import { listProjects } from "../core/projects.js";
3
+ import { compareText } from "../core/text.js";
4
+ import { scrub } from "../accounts/store.js";
5
+ import { scrubSensitive } from "../mcp/connections.js";
6
+ import { isActiveStatus, runStatusSchema } from "../sessions/contracts.js";
7
+ import { readAllRuns } from "../sessions/runIndex.js";
8
+ import { findRun, snapshot } from "../sessions/runStore.js";
9
+ const SEARCH_DEFAULT = 10;
10
+ const SEARCH_MAX = 30;
11
+ const READ_DEFAULT = 8;
12
+ const READ_MAX = 10;
13
+ const EVENT_MAX_CHARS = 18_000;
14
+ const PAGE_MAX_CHARS = 48_000;
15
+ function textParam(params, key) {
16
+ const value = params?.[key];
17
+ return typeof value === 'string' ? value.trim() : '';
18
+ }
19
+ function boundedInteger(params, key, fallback, minimum, maximum) {
20
+ const value = params?.[key];
21
+ if (value === undefined)
22
+ return fallback;
23
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < minimum || value > maximum) {
24
+ throw invalid(`${key} must be an integer from ${minimum} to ${maximum}.`);
25
+ }
26
+ return value;
27
+ }
28
+ function dateValue(params, key) {
29
+ const value = textParam(params, key);
30
+ if (!value)
31
+ return null;
32
+ if (!/^\d{4}-\d{2}-\d{2}(?:T.*)?$/.test(value))
33
+ throw invalid(`${key} must be a YYYY-MM-DD date or ISO timestamp.`);
34
+ const timestamp = Date.parse(/^\d{4}-\d{2}-\d{2}$/.test(value) ? `${value}${key === 'until' ? 'T23:59:59.999Z' : 'T00:00:00.000Z'}` : value);
35
+ if (!Number.isFinite(timestamp))
36
+ throw invalid(`${key} must be a valid date or ISO timestamp.`);
37
+ return { text: value, timestamp };
38
+ }
39
+ function decodeCursor(value) {
40
+ if (!value)
41
+ return null;
42
+ try {
43
+ const parsed = JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));
44
+ if (typeof parsed.startedAt !== 'string' || !parsed.startedAt || typeof parsed.id !== 'string' || !parsed.id)
45
+ throw new Error('invalid cursor');
46
+ return { startedAt: parsed.startedAt, id: parsed.id };
47
+ }
48
+ catch {
49
+ throw invalid('The trajectory cursor is invalid. Start a new search without it.');
50
+ }
51
+ }
52
+ function encodeCursor(run) {
53
+ return Buffer.from(JSON.stringify({ startedAt: run.startedAt, id: run.id })).toString('base64url');
54
+ }
55
+ function hidden(env, context, run) {
56
+ const excluded = context.recallExcludeAgents ?? [];
57
+ if (!excluded.length)
58
+ return false;
59
+ return excluded.includes(run.agentId ?? '') || excluded.includes(run.sessionId) || excluded.includes(env.directory.sessionAgent(run.sessionId) ?? '');
60
+ }
61
+ function afterCursor(run, cursor) {
62
+ return run.startedAt < cursor.startedAt || (run.startedAt === cursor.startedAt && run.id < cursor.id);
63
+ }
64
+ function summary(env, run, projects) {
65
+ const project = projects.find((entry) => entry.id === run.projectId);
66
+ const goal = run.goal?.trim() ?? '';
67
+ return {
68
+ id: run.id,
69
+ agentId: run.agentId,
70
+ agentName: run.agentId ? env.directory.agentName(run.agentId) : null,
71
+ project: project ? { id: project.id, name: project.name, slug: project.slug } : null,
72
+ mode: run.mode,
73
+ status: run.status,
74
+ goal: goal.length > 500 ? `${goal.slice(0, 497)}…` : goal || null,
75
+ startedAt: run.startedAt,
76
+ endedAt: run.endedAt,
77
+ parentRunId: run.parentRunId,
78
+ relation: run.relation
79
+ };
80
+ }
81
+ /** `trajectory.search`: structured list/search over the current Harness data root. */
82
+ export function searchTool(env, context, params) {
83
+ const agent = textParam(params, 'agent');
84
+ const projectKey = textParam(params, 'project');
85
+ const mode = textParam(params, 'mode');
86
+ const status = textParam(params, 'status');
87
+ const since = dateValue(params, 'since');
88
+ const until = dateValue(params, 'until');
89
+ const limit = boundedInteger(params, 'limit', SEARCH_DEFAULT, 1, SEARCH_MAX);
90
+ const cursor = decodeCursor(textParam(params, 'cursor'));
91
+ if (status && !runStatusSchema.safeParse(status).success)
92
+ throw invalid(`Unknown run status ${status}.`);
93
+ const projects = listProjects(env.root);
94
+ const project = projectKey ? projects.find((entry) => entry.id === projectKey || entry.slug === projectKey || entry.name.toLowerCase() === projectKey.toLowerCase()) : null;
95
+ if (projectKey && !project)
96
+ throw invalid(`There is no project called ${projectKey}.`);
97
+ const matching = readAllRuns(env.root)
98
+ .filter((run) => !hidden(env, context, run))
99
+ .filter((run) => !agent || run.agentId === agent || (run.agentId !== null && env.directory.agentName(run.agentId)?.toLowerCase() === agent.toLowerCase()))
100
+ .filter((run) => !projectKey || run.projectId === project?.id)
101
+ .filter((run) => !mode || run.mode === mode)
102
+ .filter((run) => !status || run.status === status)
103
+ .filter((run) => !since || Date.parse(run.startedAt) >= since.timestamp)
104
+ .filter((run) => !until || Date.parse(run.startedAt) <= until.timestamp)
105
+ .filter((run) => !cursor || afterCursor(run, cursor))
106
+ .sort((left, right) => compareText(right.startedAt, left.startedAt) || compareText(right.id, left.id));
107
+ const page = matching.slice(0, limit);
108
+ const hasMore = matching.length > page.length;
109
+ return JSON.stringify({
110
+ runs: page.map((run) => summary(env, run, projects)),
111
+ hasMore,
112
+ nextCursor: hasMore && page.length ? encodeCursor(page[page.length - 1]) : null
113
+ });
114
+ }
115
+ function boundedValue(value, path, truncated, stringLimit, arrayLimit, depth = 0) {
116
+ if (typeof value === 'string') {
117
+ const fieldLimit = path.endsWith('.systemPrompt') || path.endsWith('.contextUpdate') ? Math.min(12_000, stringLimit) :
118
+ path.endsWith('.input') || path.endsWith('.output') || path.endsWith('.summary') ? Math.min(10_000, stringLimit) : stringLimit;
119
+ if (value.length <= fieldLimit)
120
+ return value;
121
+ truncated.push(path);
122
+ return `${value.slice(0, Math.max(0, fieldLimit - 16))}… [truncated]`;
123
+ }
124
+ if (Array.isArray(value)) {
125
+ const kept = value.slice(0, arrayLimit).map((item, index) => boundedValue(item, `${path}[${index}]`, truncated, stringLimit, arrayLimit, depth + 1));
126
+ if (value.length > arrayLimit)
127
+ truncated.push(path);
128
+ return kept;
129
+ }
130
+ if (!value || typeof value !== 'object' || depth >= 8)
131
+ return value;
132
+ const entries = Object.entries(value);
133
+ const kept = entries.slice(0, 40).map(([key, item]) => [key, boundedValue(item, `${path}.${key}`, truncated, stringLimit, arrayLimit, depth + 1)]);
134
+ if (entries.length > 40)
135
+ truncated.push(path);
136
+ return Object.fromEntries(kept);
137
+ }
138
+ function publicEvent(event) {
139
+ let stringLimit = 12_000;
140
+ let arrayLimit = 20;
141
+ while (true) {
142
+ const truncated = [];
143
+ const omitted = [];
144
+ let payload = scrubSensitive(event.payload);
145
+ if (event.type === 'account.status' && payload && typeof payload === 'object' && !Array.isArray(payload)) {
146
+ const account = payload;
147
+ if (Object.hasOwn(account, 'accountId')) {
148
+ delete account.accountId;
149
+ omitted.push('payload.accountId');
150
+ }
151
+ if (typeof account.message === 'string')
152
+ account.message = scrub(account.message);
153
+ }
154
+ if (event.type === 'usage.updated' && payload && typeof payload === 'object' && !Array.isArray(payload)) {
155
+ const request = payload.request;
156
+ if (request && typeof request === 'object' && !Array.isArray(request) && Object.hasOwn(request, 'reasoningSummary')) {
157
+ delete request.reasoningSummary;
158
+ omitted.push('payload.request.reasoningSummary');
159
+ }
160
+ }
161
+ const value = {
162
+ id: event.id,
163
+ sequence: event.sequence,
164
+ timestamp: event.timestamp,
165
+ type: event.type,
166
+ payload: boundedValue(payload, 'payload', truncated, stringLimit, arrayLimit)
167
+ };
168
+ if (event.coalescedFrom !== undefined)
169
+ value.coalescedFrom = event.coalescedFrom;
170
+ if (truncated.length)
171
+ value.truncatedFields = truncated.slice(0, 40);
172
+ if (omitted.length)
173
+ value.omittedFields = omitted;
174
+ if (JSON.stringify(value).length <= EVENT_MAX_CHARS || (stringLimit <= 500 && arrayLimit <= 1))
175
+ return value;
176
+ stringLimit = Math.max(500, Math.floor(stringLimit / 2));
177
+ arrayLimit = Math.max(1, Math.floor(arrayLimit / 2));
178
+ }
179
+ }
180
+ /** `trajectory.read`: a bounded page of the events that affected a run. */
181
+ export function readTool(env, context, params) {
182
+ const requested = textParam(params, 'run');
183
+ if (!requested)
184
+ throw invalid('Give a run id or "current".');
185
+ const runId = requested === 'current' ? context.runId ?? '' : requested;
186
+ if (!runId)
187
+ throw invalid('This caller has no current run.');
188
+ const run = findRun(env.root, runId);
189
+ if (!run || hidden(env, context, run))
190
+ throw notFound('Run');
191
+ const afterSequence = boundedInteger(params, 'afterSequence', -1, -1, Number.MAX_SAFE_INTEGER);
192
+ const limit = boundedInteger(params, 'limit', READ_DEFAULT, 1, READ_MAX);
193
+ const captured = snapshot(env.root, run.id);
194
+ const candidates = captured.events.filter((event) => event.sequence > afterSequence);
195
+ const events = [];
196
+ let eventChars = 0;
197
+ for (const event of candidates.slice(0, limit)) {
198
+ const bounded = publicEvent(event);
199
+ const size = JSON.stringify(bounded).length;
200
+ if (events.length && eventChars + size > PAGE_MAX_CHARS)
201
+ break;
202
+ events.push(bounded);
203
+ eventChars += size;
204
+ }
205
+ const lastSequence = events.length ? Number(events[events.length - 1].sequence) : afterSequence;
206
+ const hasMore = candidates.some((event) => event.sequence > lastSequence);
207
+ const projects = listProjects(env.root);
208
+ const result = {
209
+ run: summary(env, captured.run, projects),
210
+ active: isActiveStatus(captured.run.status),
211
+ events,
212
+ hasMore,
213
+ nextAfterSequence: lastSequence
214
+ };
215
+ return JSON.stringify(result);
216
+ }