@xingular/harness 0.1.7 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (683) hide show
  1. package/CHANGELOG.md +97 -1
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +22 -0
  4. package/README.md +187 -85
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +13701 -13498
  7. package/dist/sdk/accounts/accounts.d.ts +165 -0
  8. package/dist/sdk/accounts/accounts.js +730 -0
  9. package/dist/sdk/accounts/choices.d.ts +23 -0
  10. package/dist/sdk/accounts/choices.js +62 -0
  11. package/dist/sdk/accounts/env.d.ts +78 -0
  12. package/dist/sdk/accounts/env.js +294 -0
  13. package/dist/sdk/accounts/secrets.d.ts +16 -0
  14. package/dist/sdk/accounts/secrets.js +40 -0
  15. package/dist/sdk/accounts/store.d.ts +114 -0
  16. package/dist/sdk/accounts/store.js +255 -0
  17. package/dist/sdk/browser/config.d.ts +16 -0
  18. package/dist/sdk/browser/config.js +22 -0
  19. package/dist/sdk/browser/diagnostics.d.ts +4 -0
  20. package/dist/sdk/browser/diagnostics.js +38 -0
  21. package/dist/sdk/browser/index.d.ts +17 -0
  22. package/dist/sdk/browser/index.js +65 -0
  23. package/dist/sdk/browser/network.d.ts +10 -0
  24. package/dist/sdk/browser/network.js +59 -0
  25. package/dist/sdk/browser/session.d.ts +84 -0
  26. package/dist/sdk/browser/session.js +192 -0
  27. package/dist/sdk/browser/tools.d.ts +8 -0
  28. package/dist/sdk/browser/tools.js +329 -0
  29. package/dist/sdk/capabilities/api.d.ts +22 -0
  30. package/dist/sdk/capabilities/api.js +54 -0
  31. package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
  32. package/dist/sdk/capabilities/runSnapshot.js +47 -0
  33. package/dist/sdk/capabilities/types.d.ts +29 -0
  34. package/dist/sdk/capabilities/types.js +1 -0
  35. package/dist/sdk/cli.d.ts +2 -0
  36. package/dist/sdk/cli.js +142 -0
  37. package/dist/sdk/core/bus.d.ts +23 -0
  38. package/dist/sdk/core/bus.js +76 -0
  39. package/dist/sdk/core/caller.d.ts +22 -0
  40. package/dist/sdk/core/caller.js +16 -0
  41. package/dist/sdk/core/changes.d.ts +15 -0
  42. package/dist/sdk/core/changes.js +15 -0
  43. package/dist/sdk/core/effort.d.ts +2 -0
  44. package/dist/sdk/core/effort.js +1 -0
  45. package/dist/sdk/core/env.d.ts +18 -0
  46. package/dist/sdk/core/env.js +8 -0
  47. package/dist/sdk/core/errors.d.ts +15 -0
  48. package/dist/sdk/core/errors.js +24 -0
  49. package/dist/sdk/core/frontmatter.d.ts +12 -0
  50. package/dist/sdk/core/frontmatter.js +50 -0
  51. package/dist/sdk/core/fs.d.ts +18 -0
  52. package/dist/sdk/core/fs.js +106 -0
  53. package/dist/sdk/core/index.d.ts +24 -0
  54. package/dist/sdk/core/index.js +187 -0
  55. package/dist/sdk/core/path.d.ts +7 -0
  56. package/dist/sdk/core/path.js +79 -0
  57. package/dist/sdk/core/projects.d.ts +18 -0
  58. package/dist/sdk/core/projects.js +67 -0
  59. package/dist/sdk/core/secrets.d.ts +2 -0
  60. package/dist/sdk/core/secrets.js +5 -0
  61. package/dist/sdk/core/text.d.ts +7 -0
  62. package/dist/sdk/core/text.js +40 -0
  63. package/dist/sdk/doctor/checks.d.ts +5 -0
  64. package/dist/sdk/doctor/checks.js +208 -0
  65. package/dist/sdk/doctor/probe.d.ts +4 -0
  66. package/dist/sdk/doctor/probe.js +92 -0
  67. package/dist/sdk/doctor/service.d.ts +23 -0
  68. package/dist/sdk/doctor/service.js +144 -0
  69. package/dist/sdk/doctor/types.d.ts +141 -0
  70. package/dist/sdk/doctor/types.js +29 -0
  71. package/dist/sdk/harness.d.ts +133 -0
  72. package/dist/sdk/harness.js +299 -0
  73. package/dist/sdk/history/lessonPrompt.d.ts +2 -0
  74. package/dist/sdk/history/lessonPrompt.js +15 -0
  75. package/dist/sdk/history/lessons.d.ts +52 -0
  76. package/dist/sdk/history/lessons.js +173 -0
  77. package/dist/sdk/history/recall.d.ts +68 -0
  78. package/dist/sdk/history/recall.js +199 -0
  79. package/dist/sdk/history/trajectory.d.ts +7 -0
  80. package/dist/sdk/history/trajectory.js +216 -0
  81. package/dist/sdk/hub/catalog.json +123 -0
  82. package/dist/sdk/hub/cli.d.ts +7 -0
  83. package/dist/sdk/hub/cli.js +81 -0
  84. package/dist/sdk/hub/hub.d.ts +74 -0
  85. package/dist/sdk/hub/hub.js +474 -0
  86. package/dist/sdk/hub/schema.d.ts +280 -0
  87. package/dist/sdk/hub/schema.js +78 -0
  88. package/dist/sdk/index.d.ts +63 -0
  89. package/dist/sdk/index.js +48 -0
  90. package/dist/sdk/mcp/connections.d.ts +83 -0
  91. package/dist/sdk/mcp/connections.js +669 -0
  92. package/dist/sdk/mcp/manager.d.ts +26 -0
  93. package/dist/sdk/mcp/manager.js +124 -0
  94. package/dist/sdk/mcp/oauth.d.ts +35 -0
  95. package/dist/sdk/mcp/oauth.js +171 -0
  96. package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
  97. package/dist/sdk/mcp/scopeMigration.js +198 -0
  98. package/dist/sdk/mcp/service.d.ts +160 -0
  99. package/dist/sdk/mcp/service.js +510 -0
  100. package/dist/sdk/mcp/types.d.ts +131 -0
  101. package/dist/sdk/mcp/types.js +49 -0
  102. package/dist/sdk/pi/runtime.d.ts +13 -0
  103. package/dist/sdk/pi/runtime.js +31 -0
  104. package/dist/sdk/plugins/api.d.ts +66 -0
  105. package/dist/sdk/plugins/api.js +155 -0
  106. package/dist/sdk/plugins/attachments.d.ts +46 -0
  107. package/dist/sdk/plugins/attachments.js +111 -0
  108. package/dist/sdk/plugins/builtin.d.ts +6 -0
  109. package/dist/sdk/plugins/builtin.js +68 -0
  110. package/dist/sdk/plugins/catalogue.d.ts +29 -0
  111. package/dist/sdk/plugins/catalogue.js +196 -0
  112. package/dist/sdk/plugins/cli.d.ts +13 -0
  113. package/dist/sdk/plugins/cli.js +187 -0
  114. package/dist/sdk/plugins/discover.d.ts +42 -0
  115. package/dist/sdk/plugins/discover.js +115 -0
  116. package/dist/sdk/plugins/firstParty.d.ts +50 -0
  117. package/dist/sdk/plugins/firstParty.js +113 -0
  118. package/dist/sdk/plugins/hooks.d.ts +94 -0
  119. package/dist/sdk/plugins/hooks.js +162 -0
  120. package/dist/sdk/plugins/identity.d.ts +19 -0
  121. package/dist/sdk/plugins/identity.js +48 -0
  122. package/dist/sdk/plugins/install.d.ts +20 -0
  123. package/dist/sdk/plugins/install.js +110 -0
  124. package/dist/sdk/plugins/inventory.d.ts +22 -0
  125. package/dist/sdk/plugins/inventory.js +110 -0
  126. package/dist/sdk/plugins/manifest.d.ts +13 -0
  127. package/dist/sdk/plugins/manifest.js +56 -0
  128. package/dist/sdk/plugins/plugins.d.ts +104 -0
  129. package/dist/sdk/plugins/plugins.js +164 -0
  130. package/dist/sdk/plugins/runtime.d.ts +9 -0
  131. package/dist/sdk/plugins/runtime.js +95 -0
  132. package/dist/sdk/plugins/trust.d.ts +44 -0
  133. package/dist/sdk/plugins/trust.js +120 -0
  134. package/dist/sdk/plugins/types.d.ts +159 -0
  135. package/dist/sdk/plugins/types.js +7 -0
  136. package/dist/sdk/prompt/compile.d.ts +174 -0
  137. package/dist/sdk/prompt/compile.js +396 -0
  138. package/dist/sdk/refine/cli.d.ts +4 -0
  139. package/dist/sdk/refine/cli.js +186 -0
  140. package/dist/sdk/refine/demo.d.ts +21 -0
  141. package/dist/sdk/refine/demo.js +114 -0
  142. package/dist/sdk/refine/evidence.d.ts +55 -0
  143. package/dist/sdk/refine/evidence.js +330 -0
  144. package/dist/sdk/refine/host.d.ts +51 -0
  145. package/dist/sdk/refine/host.js +76 -0
  146. package/dist/sdk/refine/ledger.d.ts +48 -0
  147. package/dist/sdk/refine/ledger.js +76 -0
  148. package/dist/sdk/refine/library.d.ts +55 -0
  149. package/dist/sdk/refine/library.js +177 -0
  150. package/dist/sdk/refine/pi.d.ts +72 -0
  151. package/dist/sdk/refine/pi.js +248 -0
  152. package/dist/sdk/refine/prompts.d.ts +45 -0
  153. package/dist/sdk/refine/prompts.js +390 -0
  154. package/dist/sdk/refine/recursion.d.ts +113 -0
  155. package/dist/sdk/refine/recursion.js +258 -0
  156. package/dist/sdk/refine/runner.d.ts +81 -0
  157. package/dist/sdk/refine/runner.js +150 -0
  158. package/dist/sdk/refine/selection.d.ts +57 -0
  159. package/dist/sdk/refine/selection.js +251 -0
  160. package/dist/sdk/refine/service.d.ts +84 -0
  161. package/dist/sdk/refine/service.js +165 -0
  162. package/dist/sdk/refine/suite.d.ts +67 -0
  163. package/dist/sdk/refine/suite.js +174 -0
  164. package/dist/sdk/refine/trajectory.d.ts +9 -0
  165. package/dist/sdk/refine/trajectory.js +68 -0
  166. package/dist/sdk/refine/types.d.ts +77 -0
  167. package/dist/sdk/refine/types.js +10 -0
  168. package/dist/sdk/server/methods.d.ts +3 -0
  169. package/dist/sdk/server/methods.js +370 -0
  170. package/dist/sdk/server/remote.d.ts +19 -0
  171. package/dist/sdk/server/remote.js +84 -0
  172. package/dist/sdk/server/rpc.d.ts +20 -0
  173. package/dist/sdk/server/rpc.js +102 -0
  174. package/dist/sdk/server/serve.d.ts +10 -0
  175. package/dist/sdk/server/serve.js +18 -0
  176. package/dist/sdk/sessions/approvals.d.ts +47 -0
  177. package/dist/sdk/sessions/approvals.js +119 -0
  178. package/dist/sdk/sessions/continuation.d.ts +48 -0
  179. package/dist/sdk/sessions/continuation.js +85 -0
  180. package/dist/sdk/sessions/contracts.d.ts +534 -0
  181. package/dist/sdk/sessions/contracts.js +299 -0
  182. package/dist/sdk/sessions/extensionUi.d.ts +19 -0
  183. package/dist/sdk/sessions/extensionUi.js +64 -0
  184. package/dist/sdk/sessions/history.d.ts +16 -0
  185. package/dist/sdk/sessions/history.js +68 -0
  186. package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
  187. package/dist/sdk/sessions/lineageJoin.js +61 -0
  188. package/dist/sdk/sessions/planMode.d.ts +36 -0
  189. package/dist/sdk/sessions/planMode.js +84 -0
  190. package/dist/sdk/sessions/policy.d.ts +43 -0
  191. package/dist/sdk/sessions/policy.js +1 -0
  192. package/dist/sdk/sessions/pricing.d.ts +34 -0
  193. package/dist/sdk/sessions/pricing.js +40 -0
  194. package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
  195. package/dist/sdk/sessions/reasoningSummaries.js +61 -0
  196. package/dist/sdk/sessions/registry.d.ts +102 -0
  197. package/dist/sdk/sessions/registry.js +383 -0
  198. package/dist/sdk/sessions/runIndex.d.ts +21 -0
  199. package/dist/sdk/sessions/runIndex.js +65 -0
  200. package/dist/sdk/sessions/runStore.d.ts +66 -0
  201. package/dist/sdk/sessions/runStore.js +335 -0
  202. package/dist/sdk/sessions/runner.d.ts +213 -0
  203. package/dist/sdk/sessions/runner.js +589 -0
  204. package/dist/sdk/sessions/sessions.d.ts +140 -0
  205. package/dist/sdk/sessions/sessions.js +394 -0
  206. package/dist/sdk/sessions/subagentService.d.ts +41 -0
  207. package/dist/sdk/sessions/subagentService.js +247 -0
  208. package/dist/sdk/sessions/subagents.d.ts +50 -0
  209. package/dist/sdk/sessions/subagents.js +68 -0
  210. package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
  211. package/dist/sdk/terminal/accountsMenu.js +392 -0
  212. package/dist/sdk/terminal/cli.d.ts +20 -0
  213. package/dist/sdk/terminal/cli.js +121 -0
  214. package/dist/sdk/terminal/client.d.ts +15 -0
  215. package/dist/sdk/terminal/client.js +126 -0
  216. package/dist/sdk/terminal/control.d.ts +4 -0
  217. package/dist/sdk/terminal/control.js +25 -0
  218. package/dist/sdk/terminal/controller.d.ts +72 -0
  219. package/dist/sdk/terminal/controller.js +351 -0
  220. package/dist/sdk/terminal/hubMenu.d.ts +10 -0
  221. package/dist/sdk/terminal/hubMenu.js +34 -0
  222. package/dist/sdk/terminal/launch.d.ts +5 -0
  223. package/dist/sdk/terminal/launch.js +27 -0
  224. package/dist/sdk/terminal/logs.d.ts +14 -0
  225. package/dist/sdk/terminal/logs.js +59 -0
  226. package/dist/sdk/terminal/piExtension.d.ts +6 -0
  227. package/dist/sdk/terminal/piExtension.js +392 -0
  228. package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
  229. package/dist/sdk/terminal/pluginMenu.js +101 -0
  230. package/dist/sdk/terminal/socket.d.ts +70 -0
  231. package/dist/sdk/terminal/socket.js +256 -0
  232. package/dist/sdk/terminal/standalone.d.ts +18 -0
  233. package/dist/sdk/terminal/standalone.js +146 -0
  234. package/dist/sdk/terminal/terminals.d.ts +176 -0
  235. package/dist/sdk/terminal/terminals.js +767 -0
  236. package/dist/sdk/terminal/trajectory.d.ts +10 -0
  237. package/dist/sdk/terminal/trajectory.js +30 -0
  238. package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
  239. package/dist/sdk/terminal/tui/chrome.js +169 -0
  240. package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
  241. package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
  242. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -0
  243. package/dist/sdk/terminal/tui/commandPages.js +63 -0
  244. package/dist/sdk/terminal/tui/commands.d.ts +42 -0
  245. package/dist/sdk/terminal/tui/commands.js +276 -0
  246. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
  247. package/dist/sdk/terminal/tui/dialogGeometry.js +50 -0
  248. package/dist/sdk/terminal/tui/dialogs.d.ts +75 -0
  249. package/dist/sdk/terminal/tui/dialogs.js +363 -0
  250. package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
  251. package/dist/sdk/terminal/tui/keybindings.js +49 -0
  252. package/dist/sdk/terminal/tui/list.d.ts +73 -0
  253. package/dist/sdk/terminal/tui/list.js +196 -0
  254. package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
  255. package/dist/sdk/terminal/tui/modeChoices.js +70 -0
  256. package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
  257. package/dist/sdk/terminal/tui/modelPicker.js +155 -0
  258. package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
  259. package/dist/sdk/terminal/tui/mouse.js +3 -0
  260. package/dist/sdk/terminal/tui/page.d.ts +14 -0
  261. package/dist/sdk/terminal/tui/page.js +1 -0
  262. package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
  263. package/dist/sdk/terminal/tui/pageOverlay.js +145 -0
  264. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +54 -0
  265. package/dist/sdk/terminal/tui/pages/accountsPage.js +181 -0
  266. package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
  267. package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
  268. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +37 -0
  269. package/dist/sdk/terminal/tui/pages/doctorPage.js +145 -0
  270. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
  271. package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
  272. package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
  273. package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
  274. package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
  275. package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
  276. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
  277. package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
  278. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +55 -0
  279. package/dist/sdk/terminal/tui/pages/settingsPage.js +88 -0
  280. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +58 -0
  281. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +377 -0
  282. package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
  283. package/dist/sdk/terminal/tui/piAdapter.js +48 -0
  284. package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
  285. package/dist/sdk/terminal/tui/planMode.js +2 -0
  286. package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
  287. package/dist/sdk/terminal/tui/questionPicker.js +150 -0
  288. package/dist/sdk/terminal/tui/questions.d.ts +19 -0
  289. package/dist/sdk/terminal/tui/questions.js +42 -0
  290. package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
  291. package/dist/sdk/terminal/tui/runtime.js +441 -0
  292. package/dist/sdk/terminal/tui/search.d.ts +22 -0
  293. package/dist/sdk/terminal/tui/search.js +60 -0
  294. package/dist/sdk/terminal/tui/selection.d.ts +16 -0
  295. package/dist/sdk/terminal/tui/selection.js +16 -0
  296. package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
  297. package/dist/sdk/terminal/tui/sessionUi.js +30 -0
  298. package/dist/sdk/terminal/tui/settingsModel.d.ts +12 -0
  299. package/dist/sdk/terminal/tui/settingsModel.js +84 -0
  300. package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
  301. package/dist/sdk/terminal/tui/sideQuestion.js +197 -0
  302. package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
  303. package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
  304. package/dist/sdk/terminal/tui/status.d.ts +18 -0
  305. package/dist/sdk/terminal/tui/status.js +67 -0
  306. package/dist/sdk/terminal/tui/theme.d.ts +45 -0
  307. package/dist/sdk/terminal/tui/theme.js +176 -0
  308. package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
  309. package/dist/sdk/terminal/tui/treeModel.js +483 -0
  310. package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
  311. package/dist/sdk/terminal/tui/treePicker.js +251 -0
  312. package/dist/sdk/terminal/tui/ui.d.ts +47 -0
  313. package/dist/sdk/terminal/tui/ui.js +148 -0
  314. package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
  315. package/dist/sdk/terminal/tui/workingStatus.js +229 -0
  316. package/dist/sdk/tools/askUser.d.ts +6 -0
  317. package/dist/sdk/tools/askUser.js +74 -0
  318. package/dist/sdk/tools/checklist.d.ts +9 -0
  319. package/dist/sdk/tools/checklist.js +54 -0
  320. package/dist/sdk/tools/definitions.d.ts +30 -0
  321. package/dist/sdk/tools/definitions.js +117 -0
  322. package/dist/sdk/tools/dispatch.d.ts +16 -0
  323. package/dist/sdk/tools/dispatch.js +67 -0
  324. package/dist/sdk/tools/harnessTools.d.ts +6 -0
  325. package/dist/sdk/tools/harnessTools.js +20 -0
  326. package/dist/sdk/tools/sessionName.d.ts +7 -0
  327. package/dist/sdk/tools/sessionName.js +31 -0
  328. package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
  329. package/dist/sdk/tools/spawnSubagent.js +49 -0
  330. package/dist/sdk/tools/types.d.ts +48 -0
  331. package/dist/sdk/tools/types.js +1 -0
  332. package/dist/sdk/variant/components.d.ts +34 -0
  333. package/dist/sdk/variant/components.js +230 -0
  334. package/dist/sdk/variant/materialise.d.ts +66 -0
  335. package/dist/sdk/variant/materialise.js +81 -0
  336. package/dist/sdk/variant/migrate.d.ts +4 -0
  337. package/dist/sdk/variant/migrate.js +41 -0
  338. package/dist/sdk/variant/seed.d.ts +20 -0
  339. package/dist/sdk/variant/seed.js +116 -0
  340. package/dist/sdk/variant/store.d.ts +82 -0
  341. package/dist/sdk/variant/store.js +151 -0
  342. package/dist/sdk/variant/surface.d.ts +56 -0
  343. package/dist/sdk/variant/surface.js +81 -0
  344. package/dist/sdk/variant/trust.d.ts +27 -0
  345. package/dist/sdk/variant/trust.js +64 -0
  346. package/dist/sdk/variant/variant.d.ts +71 -0
  347. package/dist/sdk/variant/variant.js +331 -0
  348. package/dist/sdk/web/markdown.d.ts +10 -0
  349. package/dist/sdk/web/markdown.js +66 -0
  350. package/dist/sdk/web/safeRequest.d.ts +34 -0
  351. package/dist/sdk/web/safeRequest.js +175 -0
  352. package/dist/sdk/web/search.d.ts +53 -0
  353. package/dist/sdk/web/search.js +168 -0
  354. package/dist/sdk/web/text.d.ts +2 -0
  355. package/dist/sdk/web/text.js +7 -0
  356. package/dist/sdk/web/tools.d.ts +22 -0
  357. package/dist/sdk/web/tools.js +195 -0
  358. package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
  359. package/dist/sdk/wiki/notes.d.ts +68 -0
  360. package/dist/sdk/wiki/notes.js +297 -0
  361. package/dist/sdk/world/actions.d.ts +23 -0
  362. package/dist/sdk/world/actions.js +31 -0
  363. package/dist/sdk/world/cli.d.ts +12 -0
  364. package/dist/sdk/world/cli.js +166 -0
  365. package/dist/sdk/world/images.d.ts +20 -0
  366. package/dist/sdk/world/images.js +48 -0
  367. package/dist/sdk/world/untrusted.d.ts +12 -0
  368. package/dist/sdk/world/untrusted.js +20 -0
  369. package/dist/sdk/world/world.d.ts +65 -0
  370. package/dist/sdk/world/world.js +80 -0
  371. package/dist/terminal-opentui.js +13612 -0
  372. package/dist/terminal-pi.js +808 -151
  373. package/docs/README.md +22 -0
  374. package/docs/architecture/00-overview.md +159 -0
  375. package/docs/architecture/01-extension-points.md +78 -0
  376. package/docs/architecture/02-sessions-and-runs.md +146 -0
  377. package/docs/architecture/03-variants.md +95 -0
  378. package/docs/architecture/04-prompt.md +102 -0
  379. package/docs/architecture/05-refinement.md +107 -0
  380. package/docs/architecture/06-plugins-and-capabilities.md +93 -0
  381. package/docs/architecture/07-tools-and-gate.md +88 -0
  382. package/docs/architecture/08-memory-and-history.md +94 -0
  383. package/docs/architecture/09-accounts-and-connectors.md +90 -0
  384. package/docs/architecture/10-server-protocol.md +84 -0
  385. package/docs/architecture/11-terminal.md +81 -0
  386. package/docs/architecture/12-storage.md +61 -0
  387. package/docs/architecture/13-world-tools.md +23 -0
  388. package/docs/architecture/README.md +114 -0
  389. package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
  390. package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
  391. package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
  392. package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
  393. package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
  394. package/docs/architecture/proposals/PROP-0006-run-checklist.md +68 -0
  395. package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
  396. package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
  397. package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
  398. package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
  399. package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
  400. package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
  401. package/docs/architecture/proposals/README.md +76 -0
  402. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  403. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  404. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  405. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  406. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  407. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  408. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  409. package/docs/decisions/ADR-0009-xharness-command.md +38 -0
  410. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  411. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  412. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  413. package/docs/decisions/ADR-0013-doctor.md +27 -0
  414. package/docs/decisions/ADR-0014-public-release-baseline.md +21 -0
  415. package/docs/doctor.md +74 -0
  416. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  417. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  418. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  419. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  420. package/docs/features/README.md +20 -0
  421. package/docs/features/automations/README.md +41 -0
  422. package/docs/features/cores/README.md +39 -0
  423. package/docs/features/google-harness2/README.md +52 -0
  424. package/docs/features/integrations/README.md +40 -0
  425. package/docs/features/interfaces/README.md +29 -0
  426. package/docs/features/memory/README.md +28 -0
  427. package/docs/releases/1.0.0.md +40 -0
  428. package/docs/releases/README.md +36 -0
  429. package/docs/study/00-index.md +78 -0
  430. package/docs/study/arms/00-matrix.md +20 -0
  431. package/docs/study/arms/01-system-prompt.md +211 -0
  432. package/docs/study/arms/02-tools.md +79 -0
  433. package/docs/study/arms/03-subagents.md +90 -0
  434. package/docs/study/arms/04-skills.md +75 -0
  435. package/docs/study/arms/05-context-management.md +90 -0
  436. package/docs/study/arms/06-memory.md +90 -0
  437. package/docs/study/arms/07-governance.md +71 -0
  438. package/docs/study/arms/08-execution.md +69 -0
  439. package/docs/study/arms/09-observability.md +60 -0
  440. package/docs/study/arms/10-refinement.md +110 -0
  441. package/docs/study/btw-comparison.md +37 -0
  442. package/docs/study/feature-gap-review.md +42 -0
  443. package/docs/study/insights.md +123 -0
  444. package/docs/study/roadmap.md +72 -0
  445. package/docs/study/sources/claude-code.md +44 -0
  446. package/docs/study/sources/deepseek-harness.md +102 -0
  447. package/docs/study/sources/harness2.md +50 -0
  448. package/docs/study/sources/kimi-cli.md +42 -0
  449. package/docs/study/sources/omp.md +93 -0
  450. package/docs/study/sources/opencode.md +43 -0
  451. package/docs/study/sources/openhands.md +46 -0
  452. package/docs/study/sources/smolagents.md +40 -0
  453. package/docs/study/sources/swe-agent.md +34 -0
  454. package/docs/system-prompt-design.md +196 -0
  455. package/docs/terminal-tui.md +473 -56
  456. package/package.json +43 -13
  457. package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
  458. package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
  459. package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
  460. package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
  461. package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
  462. package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
  463. package/docs/evidence/terminal-2026-10-17/verification.json +0 -130
  464. package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
  465. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
  466. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
  467. package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
  468. package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
  469. package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
  470. package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
  471. package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
  472. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
  473. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
  474. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
  475. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
  476. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +0 -95
  477. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
  478. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
  479. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
  480. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
  481. package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +0 -27
  482. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
  483. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +0 -18
  484. package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +0 -95
  485. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
  486. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
  487. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +0 -60
  488. package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +0 -24
  489. package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
  490. package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +0 -57
  491. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
  492. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
  493. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +0 -58
  494. package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
  495. package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +0 -320
  496. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +0 -30
  497. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +0 -133
  498. package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +0 -20
  499. package/docs/evidence/terminal-2026-10-17-followup/verification.json +0 -207
  500. package/src/accounts/accounts.test.ts +0 -333
  501. package/src/accounts/accounts.ts +0 -658
  502. package/src/accounts/env.test.ts +0 -95
  503. package/src/accounts/env.ts +0 -338
  504. package/src/accounts/secrets.ts +0 -50
  505. package/src/accounts/store.ts +0 -338
  506. package/src/capabilities/api.ts +0 -75
  507. package/src/capabilities/runSnapshot.ts +0 -59
  508. package/src/capabilities/types.ts +0 -34
  509. package/src/cli.ts +0 -118
  510. package/src/core/bus.ts +0 -34
  511. package/src/core/changes.ts +0 -33
  512. package/src/core/env.ts +0 -27
  513. package/src/core/errors.ts +0 -32
  514. package/src/core/frontmatter.ts +0 -47
  515. package/src/core/fs.test.ts +0 -38
  516. package/src/core/fs.ts +0 -92
  517. package/src/core/index.ts +0 -193
  518. package/src/core/path.test.ts +0 -14
  519. package/src/core/path.ts +0 -79
  520. package/src/core/projects.ts +0 -90
  521. package/src/core/text.ts +0 -39
  522. package/src/harness.ts +0 -312
  523. package/src/hub/catalog.json +0 -123
  524. package/src/hub/cli.ts +0 -59
  525. package/src/hub/hub.test.ts +0 -205
  526. package/src/hub/hub.ts +0 -256
  527. package/src/hub/schema.ts +0 -81
  528. package/src/index.ts +0 -75
  529. package/src/mcp/connections.ts +0 -614
  530. package/src/mcp/manager.ts +0 -130
  531. package/src/mcp/oauth.ts +0 -195
  532. package/src/mcp/scopeMigration.test.ts +0 -79
  533. package/src/mcp/scopeMigration.ts +0 -204
  534. package/src/mcp/service.test.ts +0 -376
  535. package/src/mcp/service.ts +0 -549
  536. package/src/mcp/types.ts +0 -108
  537. package/src/memory/api.test.ts +0 -82
  538. package/src/memory/api.ts +0 -303
  539. package/src/memory/blocks.test.ts +0 -78
  540. package/src/memory/blocks.ts +0 -408
  541. package/src/memory/caller.ts +0 -69
  542. package/src/memory/curation.test.ts +0 -163
  543. package/src/memory/curation.ts +0 -64
  544. package/src/memory/dispatch.ts +0 -59
  545. package/src/memory/facts.test.ts +0 -41
  546. package/src/memory/facts.ts +0 -248
  547. package/src/memory/graph.ts +0 -103
  548. package/src/memory/health.test.ts +0 -130
  549. package/src/memory/health.ts +0 -74
  550. package/src/memory/maintainer.ts +0 -272
  551. package/src/memory/maintenance.test.ts +0 -176
  552. package/src/memory/maintenance.ts +0 -518
  553. package/src/memory/migrate.ts +0 -79
  554. package/src/memory/operations.ts +0 -150
  555. package/src/memory/proposals.test.ts +0 -168
  556. package/src/memory/proposals.ts +0 -584
  557. package/src/memory/recall.test.ts +0 -115
  558. package/src/memory/recall.ts +0 -278
  559. package/src/memory/references.ts +0 -77
  560. package/src/memory/runContext.ts +0 -93
  561. package/src/memory/secrets.ts +0 -6
  562. package/src/memory/store.test.ts +0 -66
  563. package/src/memory/store.ts +0 -385
  564. package/src/memory/wiki.test.ts +0 -47
  565. package/src/memory/wiki.ts +0 -422
  566. package/src/memory/wikiIndex.test.ts +0 -88
  567. package/src/memory/wikiIndex.ts +0 -116
  568. package/src/plugins/api.ts +0 -181
  569. package/src/plugins/attachments.test.ts +0 -84
  570. package/src/plugins/attachments.ts +0 -141
  571. package/src/plugins/builtin.ts +0 -82
  572. package/src/plugins/catalogue.test.ts +0 -254
  573. package/src/plugins/catalogue.ts +0 -251
  574. package/src/plugins/cli.ts +0 -184
  575. package/src/plugins/discover.ts +0 -151
  576. package/src/plugins/firstParty.test.ts +0 -143
  577. package/src/plugins/firstParty.ts +0 -129
  578. package/src/plugins/hooks.test.ts +0 -250
  579. package/src/plugins/hooks.ts +0 -239
  580. package/src/plugins/identity.ts +0 -37
  581. package/src/plugins/install.test.ts +0 -107
  582. package/src/plugins/install.ts +0 -106
  583. package/src/plugins/inventory.ts +0 -123
  584. package/src/plugins/manifest.ts +0 -76
  585. package/src/plugins/plugins.test.ts +0 -205
  586. package/src/plugins/plugins.ts +0 -189
  587. package/src/plugins/proposal.ts +0 -121
  588. package/src/plugins/runtime.test.ts +0 -40
  589. package/src/plugins/runtime.ts +0 -82
  590. package/src/plugins/trust.ts +0 -142
  591. package/src/plugins/types.ts +0 -149
  592. package/src/prompt/compile.test.ts +0 -261
  593. package/src/prompt/compile.ts +0 -732
  594. package/src/server/methods.ts +0 -349
  595. package/src/server/remote.ts +0 -77
  596. package/src/server/rpc.ts +0 -116
  597. package/src/server/serve.ts +0 -28
  598. package/src/server/server.test.ts +0 -174
  599. package/src/sessions/approvals.ts +0 -118
  600. package/src/sessions/contracts.ts +0 -336
  601. package/src/sessions/conversation.test.ts +0 -177
  602. package/src/sessions/extensionSession.test.ts +0 -74
  603. package/src/sessions/extensionUi.test.ts +0 -65
  604. package/src/sessions/extensionUi.ts +0 -102
  605. package/src/sessions/history.ts +0 -51
  606. package/src/sessions/lineageJoin.ts +0 -75
  607. package/src/sessions/policy.ts +0 -36
  608. package/src/sessions/pricing.ts +0 -60
  609. package/src/sessions/questionBatches.test.ts +0 -110
  610. package/src/sessions/reasoningSummaries.ts +0 -59
  611. package/src/sessions/registry.ts +0 -381
  612. package/src/sessions/runIndex.ts +0 -99
  613. package/src/sessions/runStore.test.ts +0 -152
  614. package/src/sessions/runStore.ts +0 -332
  615. package/src/sessions/runner.ts +0 -604
  616. package/src/sessions/runtimeResources.test.ts +0 -61
  617. package/src/sessions/sessions.test.ts +0 -549
  618. package/src/sessions/sessions.ts +0 -339
  619. package/src/skills/registry.test.ts +0 -104
  620. package/src/skills/registry.ts +0 -413
  621. package/src/terminal/accountsMenu.test.ts +0 -225
  622. package/src/terminal/accountsMenu.ts +0 -382
  623. package/src/terminal/cli.ts +0 -149
  624. package/src/terminal/client.ts +0 -74
  625. package/src/terminal/control.test.ts +0 -23
  626. package/src/terminal/control.ts +0 -23
  627. package/src/terminal/controller.ts +0 -291
  628. package/src/terminal/hubMenu.ts +0 -24
  629. package/src/terminal/launch.test.ts +0 -25
  630. package/src/terminal/launch.ts +0 -48
  631. package/src/terminal/piExtension.lifecycle.test.ts +0 -55
  632. package/src/terminal/piExtension.ts +0 -259
  633. package/src/terminal/pluginControl.test.ts +0 -146
  634. package/src/terminal/pluginMenu.ts +0 -112
  635. package/src/terminal/socket.test.ts +0 -71
  636. package/src/terminal/socket.ts +0 -232
  637. package/src/terminal/standalone.test.ts +0 -167
  638. package/src/terminal/standalone.ts +0 -153
  639. package/src/terminal/terminal.test.ts +0 -399
  640. package/src/terminal/terminals.ts +0 -553
  641. package/src/terminal/tui/application.test.ts +0 -114
  642. package/src/terminal/tui/application.ts +0 -491
  643. package/src/terminal/tui/commands.test.ts +0 -218
  644. package/src/terminal/tui/commands.ts +0 -361
  645. package/src/terminal/tui/dialogs.ts +0 -301
  646. package/src/terminal/tui/editor.test.ts +0 -84
  647. package/src/terminal/tui/editor.ts +0 -79
  648. package/src/terminal/tui/keybindings.test.ts +0 -22
  649. package/src/terminal/tui/keybindings.ts +0 -50
  650. package/src/terminal/tui/piAdapter.ts +0 -62
  651. package/src/terminal/tui/presentation.test.ts +0 -79
  652. package/src/terminal/tui/questions.test.ts +0 -41
  653. package/src/terminal/tui/questions.ts +0 -47
  654. package/src/terminal/tui/runtime.socket.test.ts +0 -104
  655. package/src/terminal/tui/runtime.test.ts +0 -215
  656. package/src/terminal/tui/runtime.ts +0 -388
  657. package/src/terminal/tui/sessionUi.ts +0 -24
  658. package/src/terminal/tui/settings.test.ts +0 -150
  659. package/src/terminal/tui/settings.ts +0 -188
  660. package/src/terminal/tui/status.test.ts +0 -70
  661. package/src/terminal/tui/status.ts +0 -109
  662. package/src/terminal/tui/theme.ts +0 -174
  663. package/src/terminal/tui/tools.test.ts +0 -145
  664. package/src/terminal/tui/tools.ts +0 -142
  665. package/src/terminal/tui/transcript.test.ts +0 -25
  666. package/src/terminal/tui/transcript.ts +0 -124
  667. package/src/terminal/tui/ui.test.ts +0 -313
  668. package/src/terminal/tui/ui.ts +0 -166
  669. package/src/terminal/tui/welcome.ts +0 -102
  670. package/src/tools/askUser.test.ts +0 -69
  671. package/src/tools/askUser.ts +0 -59
  672. package/src/tools/definitions.ts +0 -187
  673. package/src/tools/maintenance.ts +0 -24
  674. package/src/tools/memoryTools.ts +0 -22
  675. package/src/tools/pluginPropose.ts +0 -41
  676. package/src/tools/registryWrite.test.ts +0 -101
  677. package/src/tools/registryWrite.ts +0 -182
  678. package/src/tools/spawnSubagent.ts +0 -92
  679. package/src/tools/types.ts +0 -39
  680. package/src/web/safeRequest.ts +0 -171
  681. package/src/web/text.ts +0 -53
  682. package/src/web/tools.ts +0 -134
  683. package/src/web/web.test.ts +0 -141
@@ -1,408 +0,0 @@
1
- // Core memory: blocks. A block is a short Markdown file that is always in the context of what
2
- // it is attached to, and that the model edits itself. Blocks live under `wiki/blocks/`:
3
- // `shared/<label>.md` (the `user` block and custom shared blocks), `agents/<agent-id>/` (an
4
- // agent's `persona` and `notes`), and `projects/<slug>/brief.md`. A block's id and scope come
5
- // from where its file lives. Every edit is a revision and an undoable operation.
6
- import { existsSync, readFileSync } from 'node:fs'
7
- import { join, relative } from 'node:path'
8
-
9
- import { noteChange } from '../core/changes'
10
- import { HarnessError, invalid, notFound } from '../core/errors'
11
- import * as frontmatter from '../core/frontmatter'
12
- import { atomicWrite, newId, now, safeId, writeJson } from '../core/fs'
13
- import { listProjects, projectsOrNone } from '../core/projects'
14
- import { charCount, comparePaths, compareText } from '../core/text'
15
- import { listOperations, undo, type Operation } from './operations'
16
- import { looksSecret } from './secrets'
17
- import * as store from './store'
18
-
19
- export const DEFAULT_LIMIT = 2000
20
- export const PROJECT_LIMIT = 3000
21
- export const MAX_LIMIT = 20_000
22
- /** An agent's prompt carries at most this many project briefs; the rest are listed by name. */
23
- export const AGENT_PROJECT_BRIEFS = 2
24
- const AGENT_LABELS = ['persona', 'notes']
25
-
26
- export interface BlockFront {
27
- label: string
28
- /** Tells the model what belongs in the block. */
29
- description: string
30
- limit: number
31
- /** Only the user may edit it. */
32
- readOnly: boolean
33
- /** Custom shared blocks: the agents it is attached to; empty means every agent. */
34
- agents: string[]
35
- updatedAt: string
36
- }
37
-
38
- export type BlockScope = 'shared' | 'agent' | 'project'
39
-
40
- export interface Block {
41
- /** `blocks/shared/user`, `blocks/agents/<agent-id>/persona`, `blocks/projects/<slug>/brief`. */
42
- id: string
43
- scope: BlockScope
44
- /** The agent id or project slug the block belongs to. */
45
- owner: string | null
46
- front: BlockFront
47
- body: string
48
- path: string
49
- }
50
-
51
- /** Who is reading or editing blocks. */
52
- export type Caller =
53
- | { kind: 'user' }
54
- /** An agent with blocks of its own, and the name recorded on its revisions. */
55
- | { kind: 'agent'; id: string; name: string; vaultAccess?: 'self' | 'propose' | 'curator' }
56
- /** A session without blocks of its own, and its project, if any. */
57
- | { kind: 'session'; projectSlug: string | null }
58
-
59
- function actorOf(caller: Caller): string {
60
- return caller.kind === 'user' ? 'user' : caller.kind === 'agent' ? caller.name : 'Harness session'
61
- }
62
-
63
- export function blocksDir(wiki: string): string {
64
- return join(wiki, 'blocks')
65
- }
66
-
67
- function locate(wiki: string, path: string): { id: string; scope: BlockScope; owner: string | null } | null {
68
- const inside = relative(blocksDir(wiki), path)
69
- if (inside.startsWith('..')) return null
70
- const parts = inside.replace(/(?<=[^/])\.[^./]*$/, '').split('/')
71
- const id = `blocks/${parts.join('/')}`
72
- if (parts.length === 2 && parts[0] === 'shared') return { id, scope: 'shared', owner: null }
73
- if (parts.length === 3 && parts[0] === 'agents') return { id, scope: 'agent', owner: parts[1] }
74
- if (parts.length === 3 && parts[0] === 'projects' && parts[2] === 'brief') return { id, scope: 'project', owner: parts[1] }
75
- return null
76
- }
77
-
78
- export function parseFront(front: Record<string, unknown>): BlockFront | null {
79
- const { label, description, limit, readOnly, updatedAt } = front
80
- if (typeof label !== 'string') return null
81
- if (description !== undefined && typeof description !== 'string') return null
82
- if (limit !== undefined && !(typeof limit === 'number' && Number.isInteger(limit) && limit >= 0)) return null
83
- if (readOnly !== undefined && typeof readOnly !== 'boolean') return null
84
- if (updatedAt !== undefined && typeof updatedAt !== 'string') return null
85
- const agents = store.stringList(front.agents)
86
- if (!agents) return null
87
- return { label, description: description ?? '', limit: limit ?? DEFAULT_LIMIT, readOnly: readOnly ?? false, agents, updatedAt: updatedAt ?? '' }
88
- }
89
-
90
- export function serializeBlock(front: BlockFront, body: string): string {
91
- return frontmatter.serialize(
92
- { label: front.label, description: front.description, limit: front.limit, readOnly: front.readOnly, ...(front.agents.length ? { agents: front.agents } : {}), updatedAt: front.updatedAt },
93
- body
94
- )
95
- }
96
-
97
- function parse(wiki: string, path: string): Block | null {
98
- const located = locate(wiki, path)
99
- if (!located) return null
100
- let text: string
101
- try {
102
- text = readFileSync(path, 'utf8')
103
- } catch {
104
- return null
105
- }
106
- const parsed = frontmatter.parse(text)
107
- const front = parsed && parseFront(parsed.front)
108
- if (!parsed || !front) return null
109
- return { ...located, front, body: parsed.body.trimEnd(), path }
110
- }
111
-
112
- export function loadAll(wiki: string): Block[] {
113
- const files: string[] = []
114
- store.markdownFiles(blocksDir(wiki), files)
115
- return files.sort(comparePaths).flatMap((path) => parse(wiki, path) ?? [])
116
- }
117
-
118
- /** A block by its id (`blocks/shared/user`). Every segment must be a safe identifier. */
119
- export function find(wiki: string, id: string): Block {
120
- if (!id.startsWith('blocks/')) throw notFound('Memory block')
121
- const segments = id.slice('blocks/'.length).split('/')
122
- try {
123
- segments.forEach(safeId)
124
- } catch {
125
- throw notFound('Memory block')
126
- }
127
- const block = parse(wiki, `${join(blocksDir(wiki), ...segments)}.md`)
128
- if (!block) throw notFound('Memory block')
129
- return block
130
- }
131
-
132
- function create(wiki: string, path: string, label: string, description: string, limit: number): Block {
133
- const file = join(blocksDir(wiki), `${path}.md`)
134
- if (!existsSync(file)) atomicWrite(file, serializeBlock({ label, description, limit, readOnly: false, agents: [], updatedAt: now() }, ''))
135
- const block = parse(wiki, file)
136
- if (!block) throw new HarnessError('invalid_data', `The ${label} memory block could not be read.`)
137
- return block
138
- }
139
-
140
- export function ensureUser(wiki: string): Block {
141
- return create(wiki, 'shared/user', 'user', 'What you know about the user: name, role, preferences, and how they like to work. Shared with every agent and session.', DEFAULT_LIMIT)
142
- }
143
-
144
- export function ensureAgent(wiki: string, agentId: string): Block[] {
145
- const agent = safeId(agentId)
146
- return [
147
- create(wiki, `agents/${agent}/persona`, 'persona', 'How you work: your role for this user, your habits, and what you have learned about doing this job well.', DEFAULT_LIMIT),
148
- create(wiki, `agents/${agent}/notes`, 'notes', 'Working notes to keep across turns: what you are in the middle of and what to follow up. Prune what is done.', DEFAULT_LIMIT)
149
- ]
150
- }
151
-
152
- export function ensureProject(wiki: string, slug: string, name: string): Block {
153
- const safe = safeId(slug)
154
- return create(
155
- wiki,
156
- `projects/${safe}/brief`,
157
- `project/${safe}`,
158
- `What ${name.replaceAll('\n', ' ')} is, its stack and conventions, and its current state. Shared by everyone working in this project.`,
159
- PROJECT_LIMIT
160
- )
161
- }
162
-
163
- /**
164
- * The blocks in a caller's context, in the order they are shown. Missing default blocks are
165
- * created. `projectSlugs` are the projects whose briefs an agent carries (most recent first).
166
- */
167
- export function attached(root: string, caller: Caller, projectSlugs: readonly string[]): Block[] {
168
- const wiki = store.wikiDir(root)
169
- const projectName = (slug: string): string | null => projectsOrNone(root).find((project) => project.slug === slug)?.name ?? null
170
- if (caller.kind === 'user') return loadAll(wiki)
171
- const blocks: Block[] = []
172
- if (caller.kind === 'agent') {
173
- blocks.push(...ensureAgent(wiki, caller.id))
174
- blocks.push(ensureUser(wiki))
175
- blocks.push(...loadAll(wiki).filter((block) => block.scope === 'shared' && block.front.label !== 'user' && (!block.front.agents.length || block.front.agents.includes(caller.id))))
176
- // The most recently active projects are chosen, then listed in a fixed order: later activity
177
- // must not reshuffle the context a prompt cache was built on.
178
- for (const slug of projectSlugs.slice(0, AGENT_PROJECT_BRIEFS).sort(compareText)) {
179
- const name = projectName(slug)
180
- if (name !== null) blocks.push(ensureProject(wiki, slug, name))
181
- }
182
- } else {
183
- blocks.push(ensureUser(wiki))
184
- const name = caller.projectSlug ? projectName(caller.projectSlug) : null
185
- if (caller.projectSlug && name !== null) blocks.push(ensureProject(wiki, caller.projectSlug, name))
186
- }
187
- return blocks
188
- }
189
-
190
- /** Why `caller` may not change `block`, or `null` when it may; the text is what the model sees. */
191
- export function editRefusal(caller: Caller, block: Block): string | null {
192
- const label = block.front.label
193
- if (caller.kind === 'user') return null
194
- if (block.front.readOnly) return `The ${label} block is read-only; only the user can change it.`
195
- if (caller.kind === 'agent' && caller.vaultAccess === 'propose') return 'Memory changes are proposals in this session. Submit the block change with wiki_propose; the next memory merge applies it.'
196
- if (caller.kind === 'agent' && caller.vaultAccess === 'self' && (block.scope !== 'agent' || block.owner !== caller.id || !['persona', 'notes'].includes(label))) return 'This field is outside your writable memory. Submit a block change with wiki_propose for the curator to review.'
197
- if (caller.kind === 'agent') {
198
- if (block.scope === 'agent') return block.owner === caller.id ? null : 'That block belongs to another agent.'
199
- if (block.scope === 'shared') return !block.front.agents.length || block.front.agents.includes(caller.id) ? null : `The ${label} block is not attached to you.`
200
- return null
201
- }
202
- if (block.scope === 'project') return block.owner === caller.projectSlug ? null : "A session may edit only its own project's brief."
203
- return `A Harness session can read the ${label} block but cannot edit it. Report what you learned in your result instead.`
204
- }
205
-
206
- /**
207
- * Finds the block a caller means by `label`: `user`, `persona`, `notes`, `project/<slug>`
208
- * (or `project` for a session's own), a custom shared label, or a full block id.
209
- */
210
- export function resolve(root: string, caller: Caller, rawLabel: string): Block {
211
- const wiki = store.wikiDir(root)
212
- const label = rawLabel.trim().replace(/^\/+/, '')
213
- const unknown = () => invalid(`There is no memory block called ${label}. Use one of the labels shown in your memory blocks.`)
214
- const orUnknown = (id: string): Block => {
215
- try {
216
- return find(wiki, id)
217
- } catch {
218
- throw unknown()
219
- }
220
- }
221
- if (label.startsWith('blocks/')) return orUnknown(label)
222
- if (AGENT_LABELS.includes(label)) {
223
- if (caller.kind !== 'agent') throw invalid(`The ${label} block belongs to an agent, not to a session.`)
224
- return ensureAgent(wiki, caller.id).find((block) => block.front.label === label)!
225
- }
226
- if (label === 'project' || label.startsWith('project/')) {
227
- const slug = label.startsWith('project/') ? label.slice('project/'.length) : caller.kind === 'session' ? caller.projectSlug : null
228
- if (slug === null) throw invalid('Name the project: project/<slug>.')
229
- const project = listProjects(root).find((entry) => entry.slug === slug)
230
- if (!project) throw unknown()
231
- return ensureProject(wiki, project.slug, project.name)
232
- }
233
- if (label === 'user') return ensureUser(wiki)
234
- return orUnknown(`blocks/shared/${label}`)
235
- }
236
-
237
- export type Edit = { kind: 'append'; text: string } | { kind: 'replace'; old: string; new: string } | { kind: 'rethink'; text: string }
238
-
239
- /** The body after an edit. Pure, so the rules are testable. Throws the reason an edit is refused. */
240
- export function applyEdit(body: string, edit: Edit): string {
241
- if (edit.kind === 'append') {
242
- const text = edit.text.trim()
243
- if (!text) throw invalid('Nothing to append.')
244
- return body.trim() ? `${body.trimEnd()}\n${text}` : text
245
- }
246
- if (edit.kind === 'replace') {
247
- if (!edit.old) throw invalid('Give the exact passage to replace.')
248
- const count = body.split(edit.old).length - 1
249
- if (count === 0) throw invalid('That passage is not in the block. Copy it exactly as it appears.')
250
- if (count > 1) throw invalid(`That passage appears ${count} times. Include more of the surrounding text so it is unique.`)
251
- return body.replace(edit.old, () => edit.new).trim()
252
- }
253
- return edit.text.trim()
254
- }
255
-
256
- /** Why `body` cannot be stored in the block, or `null`. */
257
- export function check(front: BlockFront, body: string): string | null {
258
- const length = charCount(body)
259
- if (length > front.limit) {
260
- return `The ${front.label} block would be ${length} of ${front.limit} characters. Condense it with memory_rethink, or move detail to the Wiki with wiki_propose.`
261
- }
262
- if (looksSecret(body) || looksSecret(front.description)) return 'That text looks like it contains a credential, so it was not stored.'
263
- return null
264
- }
265
-
266
- /** Writes a block's new content with a revision before and after and an undo operation. */
267
- function write(wiki: string, block: Block, front: BlockFront, body: string, actor: string, reason: string): Block {
268
- let current = ''
269
- try {
270
- current = readFileSync(block.path, 'utf8')
271
- } catch {
272
- current = ''
273
- }
274
- const next = serializeBlock(front, body)
275
- if (next === current) return block
276
- // The undo target: the latest revision when it already holds the current text, else a new one.
277
- const latest = store.currentRevision(wiki, block.id)
278
- let before: string | null = null
279
- if (latest) {
280
- try {
281
- if (store.revisionText(wiki, block.id, latest) === current) before = latest
282
- } catch {
283
- before = null
284
- }
285
- }
286
- before ??= store.snapshot(wiki, block.id, current, actor, 'Before edit').id
287
- atomicWrite(block.path, next)
288
- const after = store.snapshot(wiki, block.id, next, actor, reason)
289
- noteChange({ wiki, id: block.id, path: block.path, text: next, actor, reason })
290
- const operation: Operation = {
291
- id: newId(),
292
- createdAt: now(),
293
- trigger: `${actor}: ${reason} (${front.label})`,
294
- pages: [{ pageId: block.id, path: block.path, beforeRevisionId: before, afterRevisionId: after.id }],
295
- undone: false
296
- }
297
- writeJson(join(wiki, 'operations', `${operation.id}.json`), operation)
298
- store.log(wiki, `- ${now()} · ${actor} · block · \`${block.id}\` ${reason} · revision \`${after.id}\``)
299
- return find(wiki, block.id)
300
- }
301
-
302
- /** A model's edit through `memory_append`, `memory_replace`, or `memory_rethink`. */
303
- export function edit(root: string, caller: Caller, label: string, change: Edit): Block {
304
- const wiki = store.wikiDir(root)
305
- const block = resolve(root, caller, label)
306
- const refusal = editRefusal(caller, block)
307
- if (refusal) throw invalid(refusal)
308
- const body = applyEdit(block.body, change)
309
- const problem = check(block.front, body)
310
- if (problem) throw invalid(problem)
311
- const reason = change.kind === 'append' ? 'appended' : change.kind === 'replace' ? 'replaced a passage' : 'rewrote'
312
- return write(wiki, block, { ...block.front, updatedAt: now() }, body, actorOf(caller), reason)
313
- }
314
-
315
- export interface BlockInput {
316
- /** An existing block id, or none to create a shared block from `label`. */
317
- id?: string | null
318
- label?: string | null
319
- body: string
320
- description: string
321
- limit: number
322
- readOnly?: boolean
323
- agents?: string[]
324
- }
325
-
326
- /** The user's edit in the Wiki, or a new custom shared block. */
327
- export function saveAsUser(wiki: string, input: BlockInput): Block {
328
- if (!Number.isInteger(input.limit) || input.limit <= 0 || input.limit > MAX_LIMIT) throw invalid(`A block's limit is between 1 and ${MAX_LIMIT} characters.`)
329
- let block: Block
330
- if (input.id) {
331
- block = find(wiki, input.id)
332
- } else {
333
- const label = store.slug(input.label ?? '')
334
- if (!(input.label ?? '').trim() || AGENT_LABELS.includes(label) || label === 'user' || label.startsWith('project')) {
335
- throw invalid('Give the block a label that is not user, persona, notes, or project.')
336
- }
337
- let exists = true
338
- try {
339
- find(wiki, `blocks/shared/${label}`)
340
- } catch {
341
- exists = false
342
- }
343
- if (exists) throw invalid(`A shared block called ${label} already exists.`)
344
- block = create(wiki, `shared/${label}`, label, input.description.trim(), input.limit)
345
- }
346
- const front: BlockFront = { ...block.front, description: input.description.trim(), limit: input.limit, readOnly: input.readOnly ?? false, updatedAt: now() }
347
- if (block.scope === 'shared' && front.label !== 'user') front.agents = input.agents ?? []
348
- const body = input.body.trim()
349
- const problem = check(front, body)
350
- if (problem) throw invalid(problem)
351
- return write(wiki, block, front, body, 'user', input.id ? 'edited' : 'created')
352
- }
353
-
354
- /** The most recent edit of a block that has not been undone yet. */
355
- function lastEdit(wiki: string, blockId: string): Operation | null {
356
- return (
357
- listOperations(wiki)
358
- .filter((operation) => !operation.undone && operation.pages.length === 1 && operation.pages[0].pageId === blockId)
359
- .sort((left, right) => compareText(left.createdAt, right.createdAt))
360
- .at(-1) ?? null
361
- )
362
- }
363
-
364
- export function undoLast(wiki: string, blockId: string): Block {
365
- const latest = lastEdit(wiki, blockId)
366
- if (!latest) throw invalid('There is no edit to undo.')
367
- undo(wiki, latest.id)
368
- return find(wiki, blockId)
369
- }
370
-
371
- /**
372
- * The memory-blocks section of a compiled prompt. `cli` names the `xagent-wiki` commands in
373
- * place of the tools, for sessions that have the command and not the tools.
374
- */
375
- export function render(blocks: readonly Block[], caller: Caller, cli: boolean): string {
376
- if (!blocks.length) return ''
377
- const how = cli
378
- ? '`xagent-wiki block append <label> <text>`, `block replace <label> --old <text> --new <text>`, or `block rethink <label> <text>`'
379
- : 'memory_append, memory_replace, or memory_rethink'
380
- return `## Memory blocks\n\nThese blocks are your memory that is always in view, and they persist across conversations. When you learn something worth keeping, edit a block you may change with ${how}. Keep each block within its limit.\n${renderItems(blocks, caller)}`
381
- }
382
-
383
- /** The blocks alone, each framed with its label, how full it is, and what belongs in it. */
384
- export function renderItems(blocks: readonly Block[], caller: Caller): string {
385
- let text = ''
386
- for (const block of blocks) {
387
- const editable = editRefusal(caller, block) === null
388
- text += `\n<block label="${block.front.label}" chars="${charCount(block.body)}/${block.front.limit}"${editable ? '' : ' read-only="true"'}>\n${block.front.description}\n---\n${block.body.trim() || '(empty)'}\n</block>\n`
389
- }
390
- return text
391
- }
392
-
393
- export type MemoryBlock = Omit<BlockFront, 'agents'> & { agents?: string[]; id: string; scope: BlockScope; owner: string | null; body: string; path: string; revisionId: string | null; canUndo: boolean }
394
-
395
- export function response(wiki: string, block: Block): MemoryBlock {
396
- const { agents, ...front } = block.front
397
- return {
398
- id: block.id,
399
- scope: block.scope,
400
- owner: block.owner,
401
- ...front,
402
- ...(agents.length ? { agents } : {}),
403
- body: block.body,
404
- path: block.path,
405
- revisionId: store.currentRevision(wiki, block.id),
406
- canUndo: lastEdit(wiki, block.id) !== null
407
- }
408
- }
@@ -1,69 +0,0 @@
1
- // Who is calling the memory and Wiki API. The embedding application supplies this when a
2
- // session starts; the harness never looks an agent up by itself.
3
- import { findProject, projectsOrNone, type Project } from '../core/projects'
4
- import { invalid } from '../core/errors'
5
- import type { HarnessEnv } from '../core/env'
6
- import * as blocks from './blocks'
7
-
8
- /**
9
- * The current project only orders results and picks a default namespace for proposals; it
10
- * never limits what can be read.
11
- */
12
- export interface CallerContext {
13
- /** Opaque, host-owned policy data frozen when this session starts. The harness only forwards it to the embedding app's tool policy. */
14
- policyContext?: unknown
15
- /**
16
- * Trusted, frozen vault mutation capability supplied by an embedding host. `self` writes its own
17
- * persona and notes directly and proposes the rest; `propose` writes nothing directly; `curator`
18
- * applies proposals.
19
- */
20
- vaultAccess?: 'self' | 'propose' | 'curator'
21
- maintenanceJobId?: string | null
22
- maintenanceJobIds?: string[]
23
- runId?: string | null
24
- sessionId?: string | null
25
- projectId?: string | null
26
- /** The agent calling; it decides which memory blocks are attached and editable. */
27
- agentId?: string | null
28
- /** Agents whose conversations this caller may not recall (opaque ids from the embedding host). */
29
- recallExcludeAgents?: string[] | null
30
- /** The agent's name, recorded on the revisions it makes. */
31
- agentName?: string | null
32
- /** Projects whose briefs the agent carries, most recently active first. */
33
- briefProjectIds?: string[] | null
34
- /** `Chat` for an agent's own conversation, `Code` for a session in a project. */
35
- actor?: string | null
36
- /** `cli` when the caller reaches the Wiki through the `xagent-wiki` command. */
37
- surface?: string | null
38
- }
39
-
40
- export const isSession = (context: CallerContext): boolean => context.actor === 'Code'
41
- export const actorOf = (context: CallerContext): string => (isSession(context) ? 'Code' : 'Chat')
42
- export const usesCli = (context: CallerContext): boolean => context.surface === 'cli'
43
-
44
- export function projectOf(root: string, context: CallerContext): Project | null {
45
- if (!context.projectId) return null
46
- try {
47
- return findProject(root, context.projectId)
48
- } catch {
49
- return null
50
- }
51
- }
52
-
53
- /** Who is asking, for block attachment and permissions: an agent, or a session. */
54
- export function blockCaller(env: HarnessEnv, context: CallerContext): blocks.Caller {
55
- if (isSession(context)) return { kind: 'session', projectSlug: projectOf(env.root, context)?.slug ?? null }
56
- if (!context.agentId) throw invalid('Memory blocks need an agent or a Harness session.')
57
- return { kind: 'agent', id: context.agentId, name: context.agentName ?? env.directory.agentName(context.agentId) ?? context.agentId, vaultAccess: context.vaultAccess === 'propose' ? 'propose' : context.vaultAccess ? 'self' : undefined }
58
- }
59
-
60
- /** The blocks in the caller's context: an agent also carries the briefs of its active projects. */
61
- export function callerBlocks(env: HarnessEnv, context: CallerContext): { caller: blocks.Caller; attached: blocks.Block[] } {
62
- const caller = blockCaller(env, context)
63
- let slugs: string[] = []
64
- if (caller.kind === 'agent' && context.briefProjectIds?.length) {
65
- const projects = projectsOrNone(env.root)
66
- slugs = context.briefProjectIds.flatMap((id) => projects.find((project) => project.id === id)?.slug ?? [])
67
- }
68
- return { caller, attached: blocks.attached(env.root, caller, slugs) }
69
- }
@@ -1,163 +0,0 @@
1
- import { existsSync, mkdtempSync } from 'node:fs'
2
- import { join } from 'node:path'
3
- import { tmpdir } from 'node:os'
4
- import { afterEach, expect, test } from 'vitest'
5
-
6
- import { createHarness, type Harness } from '../harness'
7
- import { memorySecretStore } from '../accounts/secrets'
8
- import type { PiSessionLike } from '../sessions/runner'
9
- import { registryTools } from '../tools/registryWrite'
10
- import type { ToolSession } from '../tools/types'
11
- import * as blocks from './blocks'
12
- import { memoryEdit, propose } from './api'
13
- import { enqueueCuration } from './curation'
14
- import { findMemory } from './facts'
15
- import * as registry from '../skills/registry'
16
- import * as attachments from '../plugins/attachments'
17
- import { wikiDir } from './store'
18
-
19
- const opened: Harness[] = []
20
- afterEach(async () => { for (const harness of opened.splice(0)) await harness.close() })
21
- const self = { agentId: 'nora', agentName: 'Nora', actor: 'Chat', vaultAccess: 'self' as const, runId: 'origin' }
22
- const curator = { agentId: 'curator', agentName: 'Curator', actor: 'Chat', vaultAccess: 'curator' as const, runId: 'review' }
23
-
24
- function setup(): Harness {
25
- let emit: (event: unknown) => void = () => undefined
26
- const session: PiSessionLike = { sessionId: 'test-session', subscribe: listener => { emit = listener as never; return () => undefined }, prompt: async () => { emit({ type: 'message_end', message: { role: 'assistant', content: [{ type: 'text', text: 'Prefer pnpm for all builds.' }] } }) }, sendCustomMessage: async () => undefined, abort: async () => undefined, dispose: () => undefined }
27
- const harness = createHarness({ dataRoot: mkdtempSync(join(tmpdir(), 'curation-data-')), stateDir: mkdtempSync(join(tmpdir(), 'curation-state-')), externalMaintenance: true, secrets: memorySecretStore(), sessionFactory: async () => session, maintainerFactory: async () => { throw new Error('Hidden maintenance must not run') } })
28
- opened.push(harness)
29
- harness.accounts.create('Main', 'apiKey')
30
- blocks.ensureAgent(wikiDir(harness.env.root), 'nora')
31
- return harness
32
- }
33
- async function origin(harness: Harness): Promise<void> {
34
- await harness.sessions.run({ run: { id: 'origin', sessionId: 'nora' }, cwd: harness.env.root, sessionDir: join(harness.env.root, 'history'), text: 'Prefer pnpm for all builds.', caller: self, tools: { allow: [] } })
35
- await new Promise(resolve => setTimeout(resolve, 30))
36
- }
37
-
38
- test('normal callers directly write only their own persona and notes; standalone callers retain their prior scope', () => {
39
- const h = setup()
40
- expect(memoryEdit(h.env, self, 'memory.append', { block: 'notes', text: 'Working on release notes.' })).toContain('Updated')
41
- expect(() => memoryEdit(h.env, self, 'memory.append', { block: 'user', text: 'A shared preference.' })).toThrow('outside your writable memory')
42
- blocks.ensureAgent(wikiDir(h.env.root), 'other')
43
- expect(() => memoryEdit(h.env, self, 'memory.append', { block: 'blocks/agents/other/notes', text: 'Not mine.' })).toThrow()
44
- expect(memoryEdit(h.env, { ...self, vaultAccess: undefined }, 'memory.append', { block: 'user', text: 'Standalone scope.' })).toContain('Updated')
45
- })
46
-
47
- test('a shared fact is proposed without writing, then validated against its original run and applied once', async () => {
48
- const h = setup(); await origin(h)
49
- const submitted = propose(h.env, self, { kind: 'fact', title: 'Build tool', body: 'Use pnpm for builds.', confidence: 'high', sourceRefs: [{ kind: 'run', ref: 'current', excerpt: 'Prefer pnpm for all builds.' }] })
50
- const job = h.maintenance.jobs().find(job => job.input.kind === 'proposal')!
51
- expect(submitted).toContain(job.id)
52
- expect(() => findMemory(wikiDir(h.env.root), 'build-tool')).toThrow()
53
- expect(() => h.maintenance.readJob(self, job.id)).toThrow('curator capability')
54
- const receipt = h.maintenance.applyJob(curator, job.id, undefined, 'Preserve the stated build preference.')
55
- expect(receipt.status).toBe('completed')
56
- expect(findMemory(wikiDir(h.env.root), 'build-tool').front.sourceIds).toContain('run:origin')
57
- expect(h.maintenance.applyJob(curator, job.id, undefined, 'Retry receipt').receipt).toEqual(receipt.receipt)
58
- })
59
-
60
- test('invented evidence is parked and a read-only memory block is not rewritten', async () => {
61
- const h = setup(); await origin(h)
62
- propose(h.env, self, { kind: 'fact', title: 'Invented', body: 'Use another tool.', confidence: 'high', sourceRefs: [{ kind: 'run', ref: 'current', excerpt: 'This was never said anywhere.' }] })
63
- const job = h.maintenance.jobs().find(job => job.input.kind === 'proposal')!
64
- expect(h.maintenance.applyJob(curator, job.id, undefined, 'Review the claimed evidence').status).toBe('needs_user')
65
- expect(() => findMemory(wikiDir(h.env.root), 'invented')).toThrow()
66
- const block = blocks.find(wikiDir(h.env.root), 'blocks/agents/nora/notes')
67
- blocks.saveAsUser(wikiDir(h.env.root), { id: block.id, body: '', description: block.front.description, limit: 2000, readOnly: true })
68
- expect(() => propose(h.env, self, { kind: 'block', id: block.id, title: 'Notes', body: 'Changed.' })).toThrow('user-only')
69
- })
70
-
71
- test('text resources remain inactive until curated; undo restores attachments and preserves subsequent user edits', async () => {
72
- const h = setup()
73
- const tool = (await registryTools({ harness: h })({ caller: self } as ToolSession)).find(tool => tool.name === 'registry_write')!
74
- await tool.execute({ kind: 'skill', name: 'release-notes', description: 'Write release notes', body: 'Summarize verified changes.', reason: 'Repeated release work.' })
75
- const job = h.maintenance.jobs().find(job => job.input.kind === 'registry')!
76
- expect(registry.list(h.env.root).some(item => item.id === 'skills/release-notes')).toBe(false)
77
- const receipt = h.maintenance.applyJob(curator, job.id, undefined, 'Reuse the repeated release procedure.')
78
- expect(attachments.attached(attachments.load(h.env.root), ['skills/release-notes'], { agentId: 'nora' }, false)).toBe(true)
79
- h.maintenance.undoOperation(receipt.receipt!.operationId!)
80
- expect(registry.list(h.env.root).some(item => item.id === 'skills/release-notes')).toBe(false)
81
- const next = enqueueCuration(h.env.root, { kind: 'registry', caller: self, proposal: { kind: 'skill', name: 'other-notes', description: 'Notes', body: 'Write verified notes.', reason: 'Workflow improvement.' } })
82
- const applied = h.maintenance.applyJob(curator, next.id, undefined, 'Apply text-only improvement.')
83
- registry.writeItem(h.env.root, 'skill', 'other-notes', 'Notes', 'The user changed this.', 'User edit')
84
- expect(() => h.maintenance.undoOperation(applied.receipt!.operationId!)).toThrow('changed after')
85
- })
86
-
87
- test('changed target versions are escalated instead of overwritten', () => {
88
- const h = setup()
89
- registry.writeItem(h.env.root, 'skill', 'notes', 'Notes', 'Original notes.', 'Initial')
90
- const job = enqueueCuration(h.env.root, { kind: 'registry', caller: self, proposal: { kind: 'skill', name: 'notes', description: 'Notes', body: 'Proposed notes.', reason: 'Improve' } })
91
- registry.writeItem(h.env.root, 'skill', 'notes', 'Notes', 'User edits win.', 'User edit')
92
- expect(h.maintenance.applyJob(curator, job.id, undefined, 'Review update').status).toBe('needs_user')
93
- expect(registry.list(h.env.root).find(item => item.id === 'skills/notes')).toBeDefined()
94
- })
95
-
96
- test('executable plugins are submitted without saving, activation or trust', async () => {
97
- const h = setup()
98
- const tool = (await registryTools({ harness: h })({ caller: self } as ToolSession)).find(tool => tool.name === 'plugin_write')!
99
- await tool.execute({ name: 'code-change', description: 'A code plugin', files: [{ path: 'extensions/index.ts', content: 'export default () => {}' }] })
100
- const job = h.maintenance.jobs().find(job => job.input.kind === 'plugin')!
101
- expect(h.maintenance.applyJob(curator, job.id, undefined, 'Code needs trust').status).toBe('needs_user')
102
- expect(existsSync(join(h.env.root, 'plugins/code-change'))).toBe(false)
103
- })
104
-
105
- test('external jobs persist and repeated schedule occurrences are distinct; no hidden provider runs', async () => {
106
- const h = setup()
107
- const source = h.maintenance.ingest('source.txt', Buffer.from('Prefer pnpm for all builds.'))
108
- expect(h.maintenance.jobs().some(job => job.input.kind === 'ingest' && job.input.sourceId === source.id)).toBe(true)
109
- h.maintenance.enqueue({ kind: 'review', requestId: 'day-one' })
110
- h.maintenance.enqueue({ kind: 'review', requestId: 'day-one' })
111
- h.maintenance.enqueue({ kind: 'review', requestId: 'day-two' })
112
- expect(h.maintenance.jobs().filter(job => job.input.kind === 'review')).toHaveLength(2)
113
- await h.maintenance.settled()
114
- })
115
-
116
- test('a curator run never enqueues another completed-run maintenance job', async () => {
117
- const h = setup()
118
- await h.sessions.run({ run: { id: 'curator-run', sessionId: 'curator' }, cwd: h.env.root, sessionDir: join(h.env.root, 'curator-history'), text: 'Review maintenance.', caller: curator, tools: { allow: [] } })
119
- await new Promise(resolve => setTimeout(resolve, 30))
120
- expect(h.maintenance.jobs().some(job => job.input.kind === 'run' && job.input.runId === 'curator-run')).toBe(false)
121
- })
122
-
123
- test('curator prose cannot become its own evidence; original source runs can support a review', async () => {
124
- const h = setup(); await origin(h)
125
- await h.sessions.run({ run: { id: 'review', sessionId: 'curator' }, cwd: h.env.root, sessionDir: join(h.env.root, 'curator-history'), text: 'Prefer pnpm for all builds.', caller: curator, tools: { allow: [] } })
126
- await new Promise(resolve => setTimeout(resolve, 30))
127
- propose(h.env, curator, { kind: 'fact', title: 'Curator claim', body: 'A claim from the review.', confidence: 'high', sourceRefs: [{ kind: 'run', ref: 'current', excerpt: 'Prefer pnpm for all builds.' }] })
128
- const own = h.maintenance.jobs().find(job => job.input.kind === 'proposal')!
129
- expect(h.maintenance.applyJob(curator, own.id, undefined, 'Check the original evidence.').status).toBe('needs_user')
130
- expect(() => findMemory(wikiDir(h.env.root), 'curator-claim')).toThrow()
131
- const review = enqueueCuration(h.env.root, { kind: 'review', requestId: 'grounded-review' })
132
- const applied = h.maintenance.applyJob(curator, review.id, { memories: [{ title: 'Original preference', kind: 'preference', body: 'Prefer pnpm.', confidence: 'high', sourceRefs: [{ kind: 'run', ref: 'origin', excerpt: 'Prefer pnpm for all builds.' }] }] }, 'Retain the original recorded preference.')
133
- expect(applied.status).toBe('completed')
134
- expect(findMemory(wikiDir(h.env.root), 'original-preference').front.sourceIds).toContain('run:origin')
135
- })
136
-
137
-
138
- test('a failed evidence preparation remains attributed and can be rejected without rereading invalid input', () => {
139
- const h = setup()
140
- const job = enqueueCuration(h.env.root, { kind: 'consolidate', blockIds: ['missing-block'] })
141
- expect(() => h.maintenance.readJob(curator, job.id)).toThrow('No writable blocks')
142
- expect(h.maintenance.jobs().find(item => item.id === job.id)).toMatchObject({ status: 'failed', runId: 'review' })
143
- expect(h.maintenance.decide(curator, job.id, 'reject', 'The target no longer exists.').status).toBe('rejected')
144
- })
145
-
146
- test('a propose-only caller writes no memory directly, not even its own persona and notes', () => {
147
- const h = setup()
148
- const proposer = { ...self, vaultAccess: 'propose' as const }
149
- expect(() => memoryEdit(h.env, proposer, 'memory.append', { block: 'notes', text: 'Working on release notes.' })).toThrow('Memory changes are proposals')
150
- expect(() => memoryEdit(h.env, proposer, 'memory.append', { block: 'persona', text: 'I am terse.' })).toThrow('Memory changes are proposals')
151
- expect(propose(h.env, proposer, { kind: 'block', id: 'blocks/agents/nora/notes', title: 'Notes', body: 'Working on release notes.' })).toContain('Submitted proposal')
152
- })
153
-
154
- test('with the run trigger off, a settled run queues no consolidation of its own', async () => {
155
- let emit: (event: unknown) => void = () => undefined
156
- const session: PiSessionLike = { sessionId: 'quiet', subscribe: listener => { emit = listener as never; return () => undefined }, prompt: async () => { emit({ type: 'message_end', message: { role: 'assistant', content: [{ type: 'text', text: 'Prefer pnpm for all builds.' }] } }) }, sendCustomMessage: async () => undefined, abort: async () => undefined, dispose: () => undefined }
157
- const h = createHarness({ dataRoot: mkdtempSync(join(tmpdir(), 'curation-data-')), stateDir: mkdtempSync(join(tmpdir(), 'curation-state-')), externalMaintenance: true, maintenanceRunTrigger: false, secrets: memorySecretStore(), sessionFactory: async () => session })
158
- opened.push(h)
159
- h.accounts.create('Main', 'apiKey')
160
- await h.sessions.run({ run: { id: 'quiet-run', sessionId: 'nora' }, cwd: h.env.root, sessionDir: join(h.env.root, 'history'), text: 'Prefer pnpm.', caller: self, tools: { allow: [] } })
161
- await new Promise(resolve => setTimeout(resolve, 30))
162
- expect(h.maintenance.jobs().filter(job => job.input.kind === 'run')).toEqual([])
163
- })