@xingular/harness 1.0.0 → 1.2.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 (397) hide show
  1. package/CHANGELOG.md +46 -5
  2. package/README.md +75 -21
  3. package/dist/cli.js +17421 -8711
  4. package/dist/sdk/accounts/accounts.d.ts +27 -3
  5. package/dist/sdk/accounts/accounts.js +78 -24
  6. package/dist/sdk/accounts/secrets.d.ts +12 -0
  7. package/dist/sdk/accounts/secrets.js +114 -7
  8. package/dist/sdk/accounts/store.d.ts +26 -1
  9. package/dist/sdk/accounts/store.js +1 -1
  10. package/dist/sdk/agents/builtin.d.ts +2 -0
  11. package/dist/sdk/agents/builtin.js +48 -0
  12. package/dist/sdk/agents/narrow.d.ts +13 -0
  13. package/dist/sdk/agents/narrow.js +29 -0
  14. package/dist/sdk/agents/planResearch.d.ts +5 -0
  15. package/dist/sdk/agents/planResearch.js +19 -0
  16. package/dist/sdk/agents/profiles.d.ts +81 -0
  17. package/dist/sdk/agents/profiles.js +226 -0
  18. package/dist/sdk/annotations/bridge.d.ts +42 -0
  19. package/dist/sdk/annotations/bridge.js +264 -0
  20. package/dist/sdk/annotations/capture.d.ts +116 -0
  21. package/dist/sdk/annotations/capture.js +308 -0
  22. package/dist/sdk/annotations/delivery.d.ts +72 -0
  23. package/dist/sdk/annotations/delivery.js +130 -0
  24. package/dist/sdk/annotations/inspect.d.ts +10 -0
  25. package/dist/sdk/annotations/inspect.js +33 -0
  26. package/dist/sdk/annotations/isolated.d.ts +6 -0
  27. package/dist/sdk/annotations/isolated.js +51 -0
  28. package/dist/sdk/annotations/pageScript.d.ts +28 -0
  29. package/dist/sdk/annotations/pageScript.js +871 -0
  30. package/dist/sdk/annotations/part.d.ts +10 -0
  31. package/dist/sdk/annotations/part.js +155 -0
  32. package/dist/sdk/annotations/queue.d.ts +4 -0
  33. package/dist/sdk/annotations/queue.js +40 -0
  34. package/dist/sdk/annotations/serverMethods.d.ts +3 -0
  35. package/dist/sdk/annotations/serverMethods.js +62 -0
  36. package/dist/sdk/annotations/store.d.ts +167 -0
  37. package/dist/sdk/annotations/store.js +394 -0
  38. package/dist/sdk/browser/backend.d.ts +16 -0
  39. package/dist/sdk/browser/backend.js +17 -0
  40. package/dist/sdk/browser/contracts.d.ts +19 -0
  41. package/dist/sdk/browser/contracts.js +116 -0
  42. package/dist/sdk/browser/index.d.ts +14 -3
  43. package/dist/sdk/browser/index.js +11 -4
  44. package/dist/sdk/browser/serverMethods.d.ts +3 -0
  45. package/dist/sdk/browser/serverMethods.js +7 -0
  46. package/dist/sdk/browser/session.d.ts +1 -0
  47. package/dist/sdk/browser/session.js +45 -9
  48. package/dist/sdk/browser/tools.d.ts +1 -4
  49. package/dist/sdk/browser/tools.js +14 -91
  50. package/dist/sdk/cli.js +24 -15
  51. package/dist/sdk/commands/list.d.ts +3 -0
  52. package/dist/sdk/commands/list.js +75 -0
  53. package/dist/sdk/commands/registry.d.ts +250 -0
  54. package/dist/sdk/commands/registry.js +47 -0
  55. package/dist/sdk/commands/routes.d.ts +16 -0
  56. package/dist/sdk/commands/routes.js +33 -0
  57. package/dist/sdk/core/bus.js +1 -1
  58. package/dist/sdk/core/commandBudget.d.ts +23 -0
  59. package/dist/sdk/core/commandBudget.js +57 -0
  60. package/dist/sdk/core/env.d.ts +1 -1
  61. package/dist/sdk/core/env.js +1 -1
  62. package/dist/sdk/core/index.js +17 -1
  63. package/dist/sdk/core/interactiveProfile.d.ts +46 -0
  64. package/dist/sdk/core/interactiveProfile.js +143 -0
  65. package/dist/sdk/core/workspace.d.ts +13 -0
  66. package/dist/sdk/core/workspace.js +88 -0
  67. package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
  68. package/dist/sdk/core/workspaceBashTool.js +36 -0
  69. package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
  70. package/dist/sdk/core/workspaceSandbox.js +320 -0
  71. package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
  72. package/dist/sdk/core/workspaceWriteOperations.js +206 -0
  73. package/dist/sdk/doctor/serverMethods.d.ts +3 -0
  74. package/dist/sdk/doctor/serverMethods.js +8 -0
  75. package/dist/sdk/doctor/types.d.ts +2 -2
  76. package/dist/sdk/harness.d.ts +22 -0
  77. package/dist/sdk/harness.js +84 -5
  78. package/dist/sdk/history/recall.js +8 -8
  79. package/dist/sdk/history/serverMethods.d.ts +3 -0
  80. package/dist/sdk/history/serverMethods.js +8 -0
  81. package/dist/sdk/hub/cli.d.ts +1 -1
  82. package/dist/sdk/hub/cli.js +1 -1
  83. package/dist/sdk/hub/schema.d.ts +1 -1
  84. package/dist/sdk/hub/serverMethods.d.ts +3 -0
  85. package/dist/sdk/hub/serverMethods.js +11 -0
  86. package/dist/sdk/index.d.ts +16 -1
  87. package/dist/sdk/index.js +10 -0
  88. package/dist/sdk/mcp/connections.js +14 -7
  89. package/dist/sdk/mcp/serverMethods.d.ts +3 -0
  90. package/dist/sdk/mcp/serverMethods.js +22 -0
  91. package/dist/sdk/pi/runtime.d.ts +2 -1
  92. package/dist/sdk/pi/runtime.js +2 -2
  93. package/dist/sdk/plugins/builtin.d.ts +1 -0
  94. package/dist/sdk/plugins/builtin.js +145 -33
  95. package/dist/sdk/plugins/builtinRegistry.d.ts +60 -0
  96. package/dist/sdk/plugins/builtinRegistry.js +71 -0
  97. package/dist/sdk/plugins/catalogue.js +2 -1
  98. package/dist/sdk/plugins/cli.d.ts +1 -1
  99. package/dist/sdk/plugins/cli.js +4 -3
  100. package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
  101. package/dist/sdk/plugins/commandPrefix.js +21 -0
  102. package/dist/sdk/plugins/firstParty.d.ts +1 -1
  103. package/dist/sdk/plugins/firstParty.js +8 -2
  104. package/dist/sdk/plugins/inventory.js +4 -3
  105. package/dist/sdk/plugins/manifest.d.ts +2 -0
  106. package/dist/sdk/plugins/manifest.js +2 -1
  107. package/dist/sdk/plugins/surfaces.d.ts +5 -0
  108. package/dist/sdk/plugins/surfaces.js +11 -0
  109. package/dist/sdk/plugins/types.d.ts +15 -0
  110. package/dist/sdk/prompt/compile.d.ts +19 -2
  111. package/dist/sdk/prompt/compile.js +79 -26
  112. package/dist/sdk/prompt/standard.d.ts +17 -0
  113. package/dist/sdk/prompt/standard.js +21 -0
  114. package/dist/sdk/refine/cli.d.ts +1 -1
  115. package/dist/sdk/refine/cli.js +2 -2
  116. package/dist/sdk/refine/serverMethods.d.ts +3 -0
  117. package/dist/sdk/refine/serverMethods.js +20 -0
  118. package/dist/sdk/server/methods.js +27 -86
  119. package/dist/sdk/server/params.d.ts +4 -0
  120. package/dist/sdk/server/params.js +11 -0
  121. package/dist/sdk/server/remote.js +36 -11
  122. package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
  123. package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
  124. package/dist/sdk/sessions/continuation.d.ts +3 -0
  125. package/dist/sdk/sessions/continuation.js +5 -1
  126. package/dist/sdk/sessions/contracts.d.ts +185 -0
  127. package/dist/sdk/sessions/contracts.js +101 -4
  128. package/dist/sdk/sessions/control.d.ts +72 -0
  129. package/dist/sdk/sessions/control.js +158 -0
  130. package/dist/sdk/sessions/initialBash.d.ts +7 -0
  131. package/dist/sdk/sessions/initialBash.js +7 -0
  132. package/dist/sdk/sessions/planMode.d.ts +18 -4
  133. package/dist/sdk/sessions/planMode.js +82 -16
  134. package/dist/sdk/sessions/reasoningSummaries.d.ts +2 -2
  135. package/dist/sdk/sessions/reasoningSummaries.js +3 -3
  136. package/dist/sdk/sessions/registry.d.ts +2 -1
  137. package/dist/sdk/sessions/registry.js +6 -3
  138. package/dist/sdk/sessions/runIndex.js +7 -7
  139. package/dist/sdk/sessions/runStore.d.ts +14 -0
  140. package/dist/sdk/sessions/runStore.js +38 -1
  141. package/dist/sdk/sessions/runner.d.ts +40 -2
  142. package/dist/sdk/sessions/runner.js +163 -15
  143. package/dist/sdk/sessions/sessions.d.ts +40 -8
  144. package/dist/sdk/sessions/sessions.js +279 -27
  145. package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
  146. package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
  147. package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
  148. package/dist/sdk/sessions/sideQuestions.js +290 -0
  149. package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
  150. package/dist/sdk/sessions/subagentServerMethods.js +41 -0
  151. package/dist/sdk/sessions/subagentService.d.ts +22 -2
  152. package/dist/sdk/sessions/subagentService.js +93 -16
  153. package/dist/sdk/sessions/subagents.d.ts +9 -1
  154. package/dist/sdk/sessions/subagents.js +19 -0
  155. package/dist/sdk/sessions/workSlice.d.ts +103 -0
  156. package/dist/sdk/sessions/workSlice.js +297 -0
  157. package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
  158. package/dist/sdk/sessions/workspaceBoundary.js +46 -0
  159. package/dist/sdk/terminal/browser.d.ts +62 -0
  160. package/dist/sdk/terminal/browser.js +41 -0
  161. package/dist/sdk/terminal/browserControl.d.ts +29 -0
  162. package/dist/sdk/terminal/browserControl.js +187 -0
  163. package/dist/sdk/terminal/commandHelp.d.ts +17 -0
  164. package/dist/sdk/terminal/commandHelp.js +20 -0
  165. package/dist/sdk/terminal/controller.d.ts +15 -1
  166. package/dist/sdk/terminal/controller.js +67 -8
  167. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
  168. package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
  169. package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
  170. package/dist/sdk/terminal/opentui/theme.js +87 -0
  171. package/dist/sdk/terminal/piExtension.d.ts +6 -1
  172. package/dist/sdk/terminal/piExtension.js +169 -84
  173. package/dist/sdk/terminal/socket.d.ts +6 -3
  174. package/dist/sdk/terminal/socket.js +40 -9
  175. package/dist/sdk/terminal/standalone.d.ts +9 -0
  176. package/dist/sdk/terminal/standalone.js +118 -19
  177. package/dist/sdk/terminal/subagentMonitor.d.ts +47 -0
  178. package/dist/sdk/terminal/subagentMonitor.js +152 -0
  179. package/dist/sdk/terminal/terminals.d.ts +60 -7
  180. package/dist/sdk/terminal/terminals.js +598 -47
  181. package/dist/sdk/terminal/trajectory.js +2 -2
  182. package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
  183. package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
  184. package/dist/sdk/terminal/tui/commandPages.d.ts +7 -1
  185. package/dist/sdk/terminal/tui/commandPages.js +57 -6
  186. package/dist/sdk/terminal/tui/commands.d.ts +10 -4
  187. package/dist/sdk/terminal/tui/commands.js +269 -65
  188. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +2 -2
  189. package/dist/sdk/terminal/tui/dialogGeometry.js +4 -2
  190. package/dist/sdk/terminal/tui/dialogs.d.ts +6 -1
  191. package/dist/sdk/terminal/tui/dialogs.js +9 -2
  192. package/dist/sdk/terminal/tui/list.d.ts +14 -1
  193. package/dist/sdk/terminal/tui/list.js +96 -14
  194. package/dist/sdk/terminal/tui/modelPicker.js +1 -6
  195. package/dist/sdk/terminal/tui/page.d.ts +3 -0
  196. package/dist/sdk/terminal/tui/pageOverlay.js +27 -7
  197. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +26 -4
  198. package/dist/sdk/terminal/tui/pages/accountsPage.js +264 -36
  199. package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
  200. package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
  201. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
  202. package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
  203. package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
  204. package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
  205. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +2 -0
  206. package/dist/sdk/terminal/tui/pages/doctorPage.js +103 -15
  207. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
  208. package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
  209. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
  210. package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
  211. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +8 -0
  212. package/dist/sdk/terminal/tui/pages/settingsPage.js +16 -1
  213. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +24 -0
  214. package/dist/sdk/terminal/tui/pages/subagentsPage.js +152 -0
  215. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +12 -5
  216. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +156 -83
  217. package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
  218. package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
  219. package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
  220. package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
  221. package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
  222. package/dist/sdk/terminal/tui/piAdapter.js +3 -5
  223. package/dist/sdk/terminal/tui/planMode.d.ts +1 -1
  224. package/dist/sdk/terminal/tui/planMode.js +1 -1
  225. package/dist/sdk/terminal/tui/pluginCommands.d.ts +16 -0
  226. package/dist/sdk/terminal/tui/pluginCommands.js +31 -0
  227. package/dist/sdk/terminal/tui/questions.d.ts +2 -0
  228. package/dist/sdk/terminal/tui/runtime.js +27 -5
  229. package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
  230. package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
  231. package/dist/sdk/terminal/tui/settingsModel.d.ts +2 -0
  232. package/dist/sdk/terminal/tui/settingsModel.js +32 -2
  233. package/dist/sdk/terminal/tui/sideQuestion.d.ts +26 -26
  234. package/dist/sdk/terminal/tui/sideQuestion.js +131 -98
  235. package/dist/sdk/terminal/tui/ui.d.ts +2 -0
  236. package/dist/sdk/terminal/tui/ui.js +1 -0
  237. package/dist/sdk/tools/askUser.js +26 -8
  238. package/dist/sdk/tools/checklist.js +3 -2
  239. package/dist/sdk/tools/checkpoint.d.ts +27 -0
  240. package/dist/sdk/tools/checkpoint.js +154 -0
  241. package/dist/sdk/tools/getCapabilities.d.ts +31 -0
  242. package/dist/sdk/tools/getCapabilities.js +34 -0
  243. package/dist/sdk/tools/harnessTools.d.ts +2 -0
  244. package/dist/sdk/tools/harnessTools.js +1 -1
  245. package/dist/sdk/tools/spawnSubagent.js +14 -4
  246. package/dist/sdk/usage/analytics.d.ts +20 -0
  247. package/dist/sdk/usage/analytics.js +151 -0
  248. package/dist/sdk/usage/ledger.d.ts +38 -0
  249. package/dist/sdk/usage/ledger.js +142 -0
  250. package/dist/sdk/usage/limits/adapters.d.ts +11 -0
  251. package/dist/sdk/usage/limits/adapters.js +349 -0
  252. package/dist/sdk/usage/limits/capture.d.ts +8 -0
  253. package/dist/sdk/usage/limits/capture.js +47 -0
  254. package/dist/sdk/usage/limits/http.d.ts +12 -0
  255. package/dist/sdk/usage/limits/http.js +51 -0
  256. package/dist/sdk/usage/limits/normalize.d.ts +15 -0
  257. package/dist/sdk/usage/limits/normalize.js +211 -0
  258. package/dist/sdk/usage/limits/service.d.ts +30 -0
  259. package/dist/sdk/usage/limits/service.js +176 -0
  260. package/dist/sdk/usage/limits/types.d.ts +65 -0
  261. package/dist/sdk/usage/limits/types.js +1 -0
  262. package/dist/sdk/usage/serverMethods.d.ts +3 -0
  263. package/dist/sdk/usage/serverMethods.js +22 -0
  264. package/dist/sdk/usage/service.d.ts +32 -0
  265. package/dist/sdk/usage/service.js +66 -0
  266. package/dist/sdk/usage/settings.d.ts +7 -0
  267. package/dist/sdk/usage/settings.js +28 -0
  268. package/dist/sdk/usage/types.d.ts +60 -0
  269. package/dist/sdk/usage/types.js +4 -0
  270. package/dist/sdk/web/part.d.ts +10 -0
  271. package/dist/sdk/web/part.js +6 -0
  272. package/dist/sdk/web/serverMethods.d.ts +3 -0
  273. package/dist/sdk/web/serverMethods.js +7 -0
  274. package/dist/sdk/wiki/serverMethods.d.ts +3 -0
  275. package/dist/sdk/wiki/serverMethods.js +26 -0
  276. package/dist/sdk/worktrees/cli.d.ts +11 -0
  277. package/dist/sdk/worktrees/cli.js +146 -0
  278. package/dist/sdk/worktrees/copy.d.ts +9 -0
  279. package/dist/sdk/worktrees/copy.js +111 -0
  280. package/dist/sdk/worktrees/git.d.ts +16 -0
  281. package/dist/sdk/worktrees/git.js +81 -0
  282. package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
  283. package/dist/sdk/worktrees/serverMethods.js +30 -0
  284. package/dist/sdk/worktrees/service.d.ts +73 -0
  285. package/dist/sdk/worktrees/service.js +483 -0
  286. package/dist/sdk/worktrees/setup.d.ts +23 -0
  287. package/dist/sdk/worktrees/setup.js +65 -0
  288. package/dist/sdk/worktrees/types.d.ts +91 -0
  289. package/dist/sdk/worktrees/types.js +1 -0
  290. package/dist/sdk/world/cli.d.ts +2 -2
  291. package/dist/sdk/world/cli.js +6 -6
  292. package/dist/sdk/world/world.d.ts +3 -1
  293. package/dist/sdk/world/world.js +8 -9
  294. package/dist/terminal-opentui.js +16456 -5966
  295. package/dist/terminal-pi.js +1579 -573
  296. package/docs/README.md +22 -2
  297. package/docs/architecture/00-overview.md +28 -16
  298. package/docs/architecture/02-sessions-and-runs.md +184 -25
  299. package/docs/architecture/03-variants.md +10 -2
  300. package/docs/architecture/04-prompt.md +65 -7
  301. package/docs/architecture/06-plugins-and-capabilities.md +57 -4
  302. package/docs/architecture/07-tools-and-gate.md +112 -17
  303. package/docs/architecture/08-memory-and-history.md +4 -2
  304. package/docs/architecture/09-accounts-and-connectors.md +39 -1
  305. package/docs/architecture/10-server-protocol.md +168 -4
  306. package/docs/architecture/11-terminal.md +251 -8
  307. package/docs/architecture/12-storage.md +45 -3
  308. package/docs/architecture/13-world-tools.md +49 -6
  309. package/docs/architecture/14-surfaces-and-parity.md +136 -0
  310. package/docs/architecture/README.md +17 -4
  311. package/docs/architecture/proposals/PROP-0006-run-checklist.md +4 -2
  312. package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
  313. package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
  314. package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
  315. package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
  316. package/docs/architecture/proposals/PROP-0017-page-annotations.md +131 -0
  317. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
  318. package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
  319. package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
  320. package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
  321. package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
  322. package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
  323. package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
  324. package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
  325. package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
  326. package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
  327. package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
  328. package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
  329. package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
  330. package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
  331. package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
  332. package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
  333. package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
  334. package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
  335. package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
  336. package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
  337. package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
  338. package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
  339. package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
  340. package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
  341. package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
  342. package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
  343. package/docs/architecture/proposals/README.md +39 -0
  344. package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
  345. package/docs/decisions/ADR-0009-xharness-command.md +6 -5
  346. package/docs/decisions/ADR-0014-public-release-baseline.md +3 -2
  347. package/docs/decisions/ADR-0015-resource-browser.md +28 -0
  348. package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
  349. package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
  350. package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
  351. package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
  352. package/docs/decisions/ADR-0020-page-annotations.md +37 -0
  353. package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
  354. package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
  355. package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
  356. package/docs/decisions/ADR-0024-xagent-command.md +40 -0
  357. package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
  358. package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
  359. package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
  360. package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
  361. package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
  362. package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
  363. package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
  364. package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
  365. package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
  366. package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
  367. package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
  368. package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
  369. package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
  370. package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
  371. package/docs/doctor.md +10 -4
  372. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
  373. package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
  374. package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
  375. package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
  376. package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
  377. package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
  378. package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
  379. package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
  380. package/docs/features/README.md +26 -0
  381. package/docs/features/interfaces/README.md +1 -1
  382. package/docs/future-work.md +48 -0
  383. package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
  384. package/docs/parity.md +134 -0
  385. package/docs/releases/1.0.0.md +2 -2
  386. package/docs/releases/1.1.1.md +28 -0
  387. package/docs/releases/1.2.0.md +49 -0
  388. package/docs/releases/4.0.0.md +47 -0
  389. package/docs/releases/README.md +37 -27
  390. package/docs/study/00-index.md +8 -0
  391. package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
  392. package/docs/study/autonomous-engineering-sources.md +277 -0
  393. package/docs/study/autonomy-sources.md +147 -0
  394. package/docs/study/proactive-autonomy.md +408 -0
  395. package/docs/study/tui-resource-browser.md +78 -0
  396. package/docs/terminal-tui.md +386 -113
  397. package/package.json +6 -5
@@ -7,13 +7,13 @@ import { HarnessError, invalid } from "../core/errors.js";
7
7
  import * as capabilities from "../capabilities/api.js";
8
8
  import { loadRun as loadCapabilitySnapshot } from "../capabilities/runSnapshot.js";
9
9
  import { capabilitySet } from "../capabilities/runSnapshot.js";
10
- import { validateScopeIds } from "../mcp/connections.js";
11
- import * as recall from "../history/recall.js";
12
10
  import * as plugins from "../plugins/api.js";
11
+ import { BUILTIN_PLUGIN_REGISTRY } from "../plugins/builtin.js";
13
12
  import * as install from "../plugins/install.js";
14
13
  import { compile, load, render } from "../prompt/compile.js";
15
- import { readSummary } from "../refine/runner.js";
16
14
  import { continuationOf } from "../sessions/continuation.js";
15
+ import * as control from "../sessions/control.js";
16
+ import { listCommands } from "../commands/list.js";
17
17
  import { selectHistory } from "../sessions/history.js";
18
18
  import { runsSince } from "../sessions/runIndex.js";
19
19
  import { findRun, listRuns, loadRun, pendingDecisions, readEvents, runFamily, snapshot } from "../sessions/runStore.js";
@@ -25,14 +25,7 @@ import { seedVariant } from "../variant/seed.js";
25
25
  import * as variants from "../variant/store.js";
26
26
  import { PI_SURFACE } from "../variant/surface.js";
27
27
  import { applyEdit, autotrigger, VariantError, validate } from "../variant/variant.js";
28
- import * as notes from "../wiki/notes.js";
29
- const text = (params, name) => {
30
- const value = params[name];
31
- if (typeof value !== 'string' || !value)
32
- throw invalid(`${name} is required.`);
33
- return value;
34
- };
35
- const optional = (params, name) => (typeof params[name] === 'string' && params[name] ? params[name] : null);
28
+ import { optional, text } from "./params.js";
36
29
  const questionAnswer = (value) => {
37
30
  const answer = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
38
31
  return {
@@ -43,6 +36,7 @@ const questionAnswer = (value) => {
43
36
  : {})
44
37
  };
45
38
  };
39
+ const sessionRef = (params) => ({ sessionDir: text(params, 'sessionDir'), sessionFile: optional(params, 'sessionFile'), cwd: optional(params, 'cwd') });
46
40
  const pluginScope = (params) => ({ cwd: optional(params, 'cwd'), accountId: optional(params, 'accountId'), agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId') });
47
41
  const variantOf = (value) => {
48
42
  if (!value || typeof value !== 'object' || Array.isArray(value))
@@ -64,32 +58,16 @@ function check(variant) {
64
58
  return { ok: false, problems: error instanceof VariantError ? error.problems : [error instanceof Error ? error.message : String(error)] };
65
59
  }
66
60
  }
67
- /** Only the named fields of a parameter object. */
68
- function pick(params, keys) {
69
- return Object.fromEntries(keys.filter((key) => key in params).map((key) => [key, params[key]]));
70
- }
71
61
  export function methods(harness) {
72
- const { accounts, approvals, apps, runs, sessions, terminals, env } = harness;
62
+ const { accounts, approvals, runs, sessions, terminals, env } = harness;
73
63
  const root = () => env.root;
74
64
  const variantsChanged = (scope) => harness.bus.emit({ type: 'variants.changed', scope });
75
- return {
65
+ const builtins = BUILTIN_PLUGIN_REGISTRY.serverMethods(harness);
66
+ const foundation = {
76
67
  // ---- The harness itself --------------------------------------------------------------------
77
- 'web.status': () => harness.world.searchStatus(),
78
- 'web.setKey': (params) => harness.world.setSearchKey(text(params, 'provider'), typeof params.key === 'string' ? params.key : null),
79
- 'browser.config': () => harness.world.browserConfig(),
80
- 'browser.configure': (params) => harness.world.configureBrowser(pick(params, ['headed', 'cdpUrl', 'executablePath', 'allowPrivate', 'allowedDomains'])),
81
68
  'harness.status': () => ({ dataRoot: harness.dataRoot, productName: env.productName, recovery: harness.recovery, activeRuns: runs.activeRunIds() }),
82
- 'doctor.start': (params) => harness.doctor.start(params),
83
- 'doctor.read': (params) => harness.doctor.read(text(params, 'id')),
84
- 'doctor.cancel': (params) => harness.doctor.cancel(text(params, 'id')),
85
69
  'harness.open': (params) => harness.open(text(params, 'dataRoot'), Array.isArray(params.agentIds) ? params.agentIds : []),
86
70
  'harness.rebuildIndex': () => harness.rebuildIndex(),
87
- 'hub.list': (params) => harness.hub.list(params.refresh === true),
88
- 'hub.get': (params) => harness.hub.get(text(params, 'id'), text(params, 'version'), params.preview === true),
89
- 'hub.install': (params) => harness.hub.install(text(params, 'id'), text(params, 'version')),
90
- 'hub.preview': (params) => harness.hub.preview(text(params, 'id'), text(params, 'version'), typeof params.offset === 'number' ? params.offset : 0),
91
- 'hub.uninstall': (params) => harness.hub.uninstall(text(params, 'id'), text(params, 'version')),
92
- 'hub.readDocument': (params) => harness.hub.readDocument(text(params, 'id'), text(params, 'version')),
93
71
  // ---- Accounts --------------------------------------------------------------------------------
94
72
  'accounts.list': () => accounts.overview(),
95
73
  'accounts.find': (params) => accounts.find(text(params, 'accountId')),
@@ -129,22 +107,6 @@ export function methods(harness) {
129
107
  'approvals.remember': (params) => approvals.remember(text(params, 'sessionId'), text(params, 'target')),
130
108
  'approvals.forget': (params) => approvals.forget(text(params, 'sessionId'), text(params, 'target')),
131
109
  'approvals.forgetSession': (params) => approvals.forgetSession(text(params, 'sessionId')),
132
- // ---- Connected apps --------------------------------------------------------------------------
133
- 'connections.list': () => apps.connections.list(),
134
- 'connections.forScope': (params) => apps.connections.forScope({ agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId') }),
135
- 'connections.save': (params) => apps.save(params.input),
136
- 'connections.allowTool': (params) => apps.connections.allowTool(text(params, 'connectionId'), text(params, 'tool')),
137
- 'connections.remove': (params) => apps.remove(text(params, 'connectionId')),
138
- 'connections.test': (params) => apps.test(text(params, 'connectionId')),
139
- 'connections.signIn': (params) => apps.signIn(text(params, 'connectionId')),
140
- 'connections.signOut': (params) => apps.signOut(text(params, 'connectionId')),
141
- 'connections.runContext': (params) => apps.runContext(text(params, 'runId')),
142
- 'connections.refreshSource': (params) => apps.refreshSource(text(params, 'runId'), text(params, 'traceId'), text(params, 'sourceUri')),
143
- 'connections.setAgentScope': (params) => apps.setAgentScope(params.creator ?? {}, text(params, 'agentId'), Array.isArray(params.ids) ? params.ids : []),
144
- 'connections.removeAgentScope': (params) => apps.removeAgentScope(text(params, 'agentId')),
145
- 'connections.revision': () => apps.connections.revision(),
146
- 'connections.appClients': () => apps.appClients(),
147
- 'connections.validateScope': (params) => validateScopeIds(apps.connections.list(), { agentId: optional(params, 'agentId'), projectId: optional(params, 'projectId') }, Array.isArray(params.ids) ? params.ids : []),
148
110
  // ---- Variants: the eight components that shape an agent ---------------------------------
149
111
  'variants.surface': () => PI_SURFACE,
150
112
  'variants.list': () => variants.scopes(root()).map((scope) => {
@@ -227,45 +189,8 @@ export function methods(harness) {
227
189
  const built = materialise(root(), params.variant, { trust: harness.trust });
228
190
  return { ...built, files: undefined };
229
191
  },
230
- // ---- Refinement: improving a harness from evidence -------------------------------------------
231
- 'refine.start': (params) => harness.refine.start({ task: params.task, k: typeof params.k === 'number' ? params.k : 1, mode: params.mode === 'sequential' ? 'sequential' : 'parallel', improver: params.improver ?? {}, executor: params.executor ?? undefined, baseVersion: optional(params, 'baseVersion'), retainWorkspaces: params.retainWorkspaces === true, id: optional(params, 'id') ?? undefined }),
232
- 'refine.get': (params) => harness.refine.get(text(params, 'id')),
233
- 'refine.list': (params) => harness.refine.list({ scope: optional(params, 'scope'), limit: typeof params.limit === 'number' ? params.limit : undefined }),
234
- 'refine.running': () => harness.refine.running(),
235
- 'refine.cancel': async (params) => {
236
- await harness.refine.cancel(text(params, 'id'));
237
- return readSummary(root(), text(params, 'id'));
238
- },
239
- 'refine.candidates': (params) => harness.refine.candidates(text(params, 'id')),
240
- 'refine.adopt': (params) => harness.refine.adopt(text(params, 'id'), { label: optional(params, 'label') }),
241
- 'library.list': (params) => harness.refine.library(text(params, 'scope')),
242
- 'library.read': (params) => harness.refine.libraryEntry(text(params, 'scope'), text(params, 'area'), text(params, 'task')),
243
- 'library.forget': (params) => harness.refine.forget(text(params, 'scope'), text(params, 'area'), Array.isArray(params.tasks) ? params.tasks : []),
244
- // ---- The Wiki: project notes ------------------------------------------------------------------
245
- 'wiki.list': (params) => notes.list(root(), params.project === undefined ? {} : { project: optional(params, 'project') }),
246
- 'wiki.read': (params) => notes.read(root(), text(params, 'path')),
247
- 'wiki.write': (params) => {
248
- const note = notes.write(root(), text(params, 'path'), typeof params.text === 'string' ? params.text : '', { expectedUpdatedAt: optional(params, 'expectedUpdatedAt') });
249
- harness.bus.emit({ type: 'wiki.changed' });
250
- return note;
251
- },
252
- 'wiki.remove': (params) => {
253
- notes.remove(root(), text(params, 'path'));
254
- harness.bus.emit({ type: 'wiki.changed' });
255
- },
256
- 'wiki.search': (params) => notes.search(root(), typeof params.query === 'string' ? params.query : '', { project: optional(params, 'project'), limit: typeof params.limit === 'number' ? params.limit : undefined }),
257
- 'wiki.graph': () => notes.graph(root()),
258
- 'wiki.versions': (params) => notes.versions(root(), text(params, 'path')),
259
- 'wiki.version': (params) => notes.version(root(), text(params, 'path'), text(params, 'id')),
260
- 'wiki.ensureProject': () => {
261
- notes.ensureLayout(root(), env.productName);
262
- harness.bus.emit({ type: 'wiki.changed' });
263
- },
264
192
  // ---- What a session calls, on behalf of a caller the host names -------------------------------
265
193
  'harness.call': (params) => dispatch(env, (params.context ?? {}), text(params, 'call'), params.params ?? {}, { variantDir: optional(params, 'variantDir') }),
266
- // ---- Recall ------------------------------------------------------------------------------------
267
- 'recall.search': (params) => recall.searchAll(env, typeof params.query === 'string' ? params.query : '', params.filter ?? {}),
268
- 'recall.read': (params) => recall.read(root(), text(params, 'runId')),
269
194
  // ---- The compiled prompt -----------------------------------------------------------------------
270
195
  'context.compile': (params) => {
271
196
  const variant = params.variant ? materialise(root(), params.variant, { trust: harness.trust }) : null;
@@ -354,12 +279,24 @@ export function methods(harness) {
354
279
  runs.answerQuestions(text(params, 'runId'), text(params, 'batchId'), params.answers.map((item) => ({ questionId: text(item, 'questionId'), answer: questionAnswer(item.answer) })));
355
280
  },
356
281
  // ---- Sessions ----------------------------------------------------------------------------------
357
- 'subagents.spawn': (params) => harness.subagents.spawn(params),
358
- 'subagents.wait': (params) => harness.subagents.wait(params),
359
- 'subagents.results': (params) => harness.subagents.results(params),
360
282
  'sessions.spawnSubagent': (params) => sessions.spawnSubagent(params),
361
283
  'sessions.run': (params) => sessions.run(params),
362
284
  'sessions.history': (params) => ({ sessionFile: selectHistory({ sessionDir: text(params, 'sessionDir'), resume: params.resume ?? null }) }),
285
+ // The commands that need no model act on the saved history; see sessions/control.ts.
286
+ 'sessions.tree': (params) => control.tree(sessionRef(params)),
287
+ 'sessions.navigate': (params) => control.navigate({ ...sessionRef(params), entryId: text(params, 'entryId') }),
288
+ 'sessions.fork': (params) => control.fork({ ...sessionRef(params), entryId: text(params, 'entryId'), targetDir: text(params, 'targetDir') }),
289
+ 'sessions.clone': (params) => control.clone({ ...sessionRef(params), targetDir: text(params, 'targetDir') }),
290
+ 'sessions.rename': (params) => control.rename({ ...sessionRef(params), name: text(params, 'name') }),
291
+ 'sessions.lastReply': (params) => control.lastReply(sessionRef(params)),
292
+ 'sessions.export': (params) => control.exportJsonl({ ...sessionRef(params), path: text(params, 'path') }),
293
+ // Each structured turn loads its resources fresh; this reloads what lives between turns.
294
+ 'sessions.reload': async () => {
295
+ await harness.hooks.reload();
296
+ return { reloaded: true };
297
+ },
298
+ // ---- Commands ----------------------------------------------------------------------------------
299
+ 'commands.list': async (params) => listCommands(await plugins.list(harness, pluginScope(params))),
363
300
  // ---- Terminal sessions -------------------------------------------------------------------------
364
301
  'terminal.prepare': (params) => terminals.prepare(params),
365
302
  'terminal.send': (params) => terminals.send({ sessionId: text(params, 'sessionId'), runId: optional(params, 'runId'), text: text(params, 'text') }),
@@ -367,4 +304,8 @@ export function methods(harness) {
367
304
  'terminal.state': (params) => terminals.state(text(params, 'sessionId')),
368
305
  'terminal.dispose': (params) => terminals.dispose(text(params, 'sessionId'))
369
306
  };
307
+ const overlap = Object.keys(foundation).find(name => name in builtins);
308
+ if (overlap)
309
+ throw new Error(`Server method ${overlap} is owned by both Foundation and a built-in plugin.`);
310
+ return { ...builtins, ...foundation };
370
311
  }
@@ -0,0 +1,4 @@
1
+ export type Params = Record<string, any>;
2
+ export declare const text: (params: Params, name: string) => string;
3
+ export declare const optional: (params: Params, name: string) => string | null;
4
+ export declare function pick<T extends string>(params: Params, keys: readonly T[]): Record<T, unknown>;
@@ -0,0 +1,11 @@
1
+ import { invalid } from "../core/errors.js";
2
+ export const text = (params, name) => {
3
+ const value = params[name];
4
+ if (typeof value !== 'string' || !value)
5
+ throw invalid(`${name} is required.`);
6
+ return value;
7
+ };
8
+ export const optional = (params, name) => (typeof params[name] === 'string' && params[name] ? params[name] : null);
9
+ export function pick(params, keys) {
10
+ return Object.fromEntries(keys.filter(key => key in params).map(key => [key, params[key]]));
11
+ }
@@ -3,6 +3,8 @@
3
3
  // host; the harness works without any of them.
4
4
  import { z } from 'zod';
5
5
  import { findingSchema } from "../doctor/types.js";
6
+ import { browserBackendTools } from "../browser/backend.js";
7
+ import { BROWSER_TOOLS } from "../browser/contracts.js";
6
8
  /** `secrets.get`, `secrets.set`, `secrets.delete` on the host. */
7
9
  export function remoteSecrets(peer) {
8
10
  return {
@@ -52,18 +54,41 @@ export function remoteTools(peer) {
52
54
  registered = Array.isArray(params.tools) ? params.tools : [];
53
55
  return { registered: registered.map((tool) => tool.name) };
54
56
  });
55
- const provider = (session) => registered
56
- .filter((tool) => session.allow.includes(tool.name))
57
- .map((tool) => ({
58
- name: tool.name,
59
- label: tool.label ?? tool.name,
60
- description: tool.description,
61
- parameters: (Type) => Type.Unsafe(tool.parameters),
62
- execute: async (input) => {
63
- const result = await peer.callHost('tools.call', { name: tool.name, input, runId: session.run.runId, sessionId: session.run.sessionId, caller: session.caller, depth: session.depth, cwd: session.cwd }, 1_230_000);
64
- return typeof result === 'string' ? result : JSON.stringify(result);
57
+ const provider = (session) => {
58
+ const unique = [];
59
+ const names = new Set();
60
+ for (const tool of registered) {
61
+ if (!session.allow.includes(tool.name) || names.has(tool.name))
62
+ continue;
63
+ names.add(tool.name);
64
+ unique.push(tool);
65
65
  }
66
- }));
66
+ const browserNames = unique.filter(tool => BROWSER_TOOLS.some(definition => definition.name === tool.name)).map(tool => tool.name);
67
+ const browser = new Map(browserBackendTools({
68
+ id: 'remote host',
69
+ // Registering a canonical browser tool means the host implements it; the backend contract
70
+ // documents the freshness, tab isolation and approval rules that implementation must keep.
71
+ unsupported: () => null,
72
+ execute: async (name, input) => {
73
+ const result = await peer.callHost('tools.call', { name, input, runId: session.run.runId, sessionId: session.run.sessionId, caller: session.caller, depth: session.depth, cwd: session.cwd }, 1_230_000);
74
+ if (typeof result === 'string')
75
+ return result;
76
+ if (result && typeof result === 'object' && !Array.isArray(result) && typeof result.text === 'string')
77
+ return result;
78
+ return JSON.stringify(result) ?? String(result);
79
+ }
80
+ }, browserNames).map(tool => [tool.name, tool]));
81
+ return unique.map((tool) => browser.get(tool.name) ?? ({
82
+ name: tool.name,
83
+ label: tool.label ?? tool.name,
84
+ description: tool.description,
85
+ parameters: (Type) => Type.Unsafe(tool.parameters),
86
+ execute: async (input) => {
87
+ const result = await peer.callHost('tools.call', { name: tool.name, input, runId: session.run.runId, sessionId: session.run.sessionId, caller: session.caller, depth: session.depth, cwd: session.cwd }, 1_230_000);
88
+ return typeof result === 'string' ? result : JSON.stringify(result);
89
+ }
90
+ }));
91
+ };
67
92
  provider.diagnostics = context => diagnostics.map(check => ({
68
93
  id: `host.${check.id}`, category: check.category, title: check.title, tools: check.tools,
69
94
  local: async (signal) => {
@@ -0,0 +1,11 @@
1
+ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
2
+ import { type ChecklistItem } from "./contracts.js";
3
+ export declare const COMPACTION_CHECKPOINT_EXTENSION = "compaction-checkpoint";
4
+ export interface CompactionCheckpointOptions {
5
+ /** A stopped run's persisted checklist, when the active run is a continuation. */
6
+ initialChecklist?: readonly ChecklistItem[];
7
+ /** The current dynamic plan instructions, if this request is in plan mode. */
8
+ planInstructions?: () => string | null;
9
+ }
10
+ /** Adds only the active run's explicit state to requests made after a compaction. */
11
+ export declare function compactionCheckpoint(options?: CompactionCheckpointOptions): (pi: ExtensionAPI) => void;
@@ -0,0 +1,79 @@
1
+ import { renderCompactionCheckpoint } from "../prompt/compile.js";
2
+ import { CHECKLIST_WRITE } from "../tools/checklist.js";
3
+ import { checklistItemSchema, MAX_CHECKLIST_ITEMS } from "./contracts.js";
4
+ export const COMPACTION_CHECKPOINT_EXTENSION = 'compaction-checkpoint';
5
+ function validatedChecklist(value) {
6
+ if (!Array.isArray(value) || value.length > MAX_CHECKLIST_ITEMS)
7
+ return null;
8
+ const items = [];
9
+ for (const valueItem of value) {
10
+ const item = valueItem;
11
+ const parsed = checklistItemSchema.safeParse({
12
+ text: typeof item?.text === 'string' ? item.text.trim() : item?.text,
13
+ status: item?.status
14
+ });
15
+ if (!parsed.success)
16
+ return null;
17
+ items.push(parsed.data);
18
+ }
19
+ return items;
20
+ }
21
+ /** Adds only the active run's explicit state to requests made after a compaction. */
22
+ export function compactionCheckpoint(options = {}) {
23
+ return (pi) => {
24
+ let goal = '';
25
+ let checklist = validatedChecklist(options.initialChecklist ?? []) ?? [];
26
+ let lastCompactionKey = null;
27
+ let compacted = false;
28
+ const reset = () => {
29
+ goal = '';
30
+ checklist = validatedChecklist(options.initialChecklist ?? []) ?? [];
31
+ lastCompactionKey = null;
32
+ compacted = false;
33
+ };
34
+ pi.on('before_agent_start', (event) => {
35
+ if (event.messageType !== 'user')
36
+ return;
37
+ goal = event.prompt;
38
+ checklist = validatedChecklist(options.initialChecklist ?? []) ?? [];
39
+ lastCompactionKey = null;
40
+ compacted = false;
41
+ });
42
+ pi.on('tool_result', (event) => {
43
+ if (event.toolName !== CHECKLIST_WRITE || event.isError)
44
+ return;
45
+ const items = validatedChecklist(event.input.items);
46
+ if (items)
47
+ checklist = items;
48
+ });
49
+ pi.on('context', (event) => {
50
+ const summary = event.messages.findLast((message) => message.role === 'compactionSummary');
51
+ const compactionKey = summary ? `${summary.timestamp}:${summary.tokensBefore}` : null;
52
+ const planInstructions = options.planInstructions?.() ?? null;
53
+ if (compactionKey && compactionKey !== lastCompactionKey) {
54
+ lastCompactionKey = compactionKey;
55
+ compacted = true;
56
+ }
57
+ else if (!compactionKey) {
58
+ lastCompactionKey = null;
59
+ compacted = false;
60
+ }
61
+ if (!compacted)
62
+ return;
63
+ const content = renderCompactionCheckpoint({ goal, checklist, planInstructions });
64
+ if (!content)
65
+ return;
66
+ return {
67
+ messages: [...event.messages, {
68
+ role: 'custom',
69
+ customType: COMPACTION_CHECKPOINT_EXTENSION,
70
+ content,
71
+ display: false,
72
+ timestamp: Date.now()
73
+ }]
74
+ };
75
+ });
76
+ pi.on('agent_settled', reset);
77
+ pi.on('session_tree', reset);
78
+ };
79
+ }
@@ -1,5 +1,6 @@
1
1
  import type { CapabilitySet } from "../capabilities/types.js";
2
2
  import type { HostSection } from "../prompt/compile.js";
3
+ import type { Checkpoint } from "./contracts.js";
3
4
  import { type ChecklistItem } from "./contracts.js";
4
5
  import { type PendingDecision } from "./runStore.js";
5
6
  export declare const CONTINUATION_SECTION_ID = "continuation";
@@ -28,6 +29,8 @@ export interface Continuation {
28
29
  stoppedAt: string | null;
29
30
  terminalReason: string | null;
30
31
  checklist: ChecklistItem[];
32
+ /** The last work-slice handoff, when the run wrote one (PROP-0041). */
33
+ checkpoint: Checkpoint | null;
31
34
  pending: PendingDecision[];
32
35
  /** The last tool the run started, and whether it finished. */
33
36
  lastTool: {
@@ -3,6 +3,7 @@
3
3
  // run with `continueFrom`, tells the model where the earlier one stopped.
4
4
  import { loadRun as loadCapabilities } from "../capabilities/runSnapshot.js";
5
5
  import { checklistOf, describeChecklist } from "../tools/checklist.js";
6
+ import { checkpointOf, describeCheckpoint } from "../tools/checkpoint.js";
6
7
  import { isActiveStatus } from "./contracts.js";
7
8
  import { findHistory } from "./history.js";
8
9
  import { findRun, pendingDecisions, readEvents, recordedSubagents } from "./runStore.js";
@@ -17,7 +18,7 @@ const CONTINUATION_BUDGET = 2000;
17
18
  export function continuationOf(root, runId, sessionDir) {
18
19
  const record = findRun(root, runId);
19
20
  if (!record) {
20
- return { runId, sessionId: '', status: 'missing', resumable: false, reason: 'not_found', resume: null, accountId: null, variant: null, capabilities: null, stoppedAt: null, terminalReason: null, checklist: [], pending: [], lastTool: null, unfinishedSubagents: [] };
21
+ return { runId, sessionId: '', status: 'missing', resumable: false, reason: 'not_found', resume: null, accountId: null, variant: null, capabilities: null, stoppedAt: null, terminalReason: null, checklist: [], checkpoint: null, pending: [], lastTool: null, unfinishedSubagents: [] };
21
22
  }
22
23
  const events = readEvents(root, runId);
23
24
  const started = events.filter((event) => event.type === 'tool.started').at(-1);
@@ -46,6 +47,7 @@ export function continuationOf(root, runId, sessionDir) {
46
47
  stoppedAt: record.endedAt,
47
48
  terminalReason: record.terminalReason,
48
49
  checklist: checklistOf(events),
50
+ checkpoint: checkpointOf(events),
49
51
  pending: pendingDecisions(events),
50
52
  lastTool,
51
53
  unfinishedSubagents: recordedSubagents(root, runId).filter((id) => {
@@ -69,6 +71,8 @@ export function continuationBody(continuation) {
69
71
  ];
70
72
  if (continuation.lastTool)
71
73
  lines.push(continuation.lastTool.finished ? `Its last tool call, ${continuation.lastTool.name}, finished.` : `Its last tool call, ${continuation.lastTool.name}, did not finish; its effect is unknown.`);
74
+ if (continuation.checkpoint)
75
+ lines.push('', 'The handoff it wrote when it stopped:', describeCheckpoint(continuation.checkpoint));
72
76
  if (continuation.checklist.length)
73
77
  lines.push('', 'Its checklist when it stopped:', describeChecklist(continuation.checklist));
74
78
  if (continuation.pending.length)