@xingular/harness 0.1.7 → 1.1.1

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 (819) hide show
  1. package/CHANGELOG.md +125 -1
  2. package/LICENSE +202 -0
  3. package/NOTICE.md +22 -0
  4. package/README.md +239 -86
  5. package/THIRD_PARTY_LICENSES.md +942 -0
  6. package/dist/cli.js +17853 -13114
  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/agents/builtin.d.ts +2 -0
  18. package/dist/sdk/agents/builtin.js +34 -0
  19. package/dist/sdk/agents/narrow.d.ts +13 -0
  20. package/dist/sdk/agents/narrow.js +29 -0
  21. package/dist/sdk/agents/profiles.d.ts +80 -0
  22. package/dist/sdk/agents/profiles.js +221 -0
  23. package/dist/sdk/annotations/bridge.d.ts +42 -0
  24. package/dist/sdk/annotations/bridge.js +264 -0
  25. package/dist/sdk/annotations/capture.d.ts +116 -0
  26. package/dist/sdk/annotations/capture.js +308 -0
  27. package/dist/sdk/annotations/delivery.d.ts +72 -0
  28. package/dist/sdk/annotations/delivery.js +130 -0
  29. package/dist/sdk/annotations/inspect.d.ts +10 -0
  30. package/dist/sdk/annotations/inspect.js +33 -0
  31. package/dist/sdk/annotations/isolated.d.ts +6 -0
  32. package/dist/sdk/annotations/isolated.js +51 -0
  33. package/dist/sdk/annotations/pageScript.d.ts +28 -0
  34. package/dist/sdk/annotations/pageScript.js +570 -0
  35. package/dist/sdk/annotations/part.d.ts +10 -0
  36. package/dist/sdk/annotations/part.js +144 -0
  37. package/dist/sdk/annotations/queue.d.ts +4 -0
  38. package/dist/sdk/annotations/queue.js +40 -0
  39. package/dist/sdk/annotations/serverMethods.d.ts +3 -0
  40. package/dist/sdk/annotations/serverMethods.js +62 -0
  41. package/dist/sdk/annotations/store.d.ts +160 -0
  42. package/dist/sdk/annotations/store.js +386 -0
  43. package/dist/sdk/browser/config.d.ts +16 -0
  44. package/dist/sdk/browser/config.js +22 -0
  45. package/dist/sdk/browser/diagnostics.d.ts +4 -0
  46. package/dist/sdk/browser/diagnostics.js +38 -0
  47. package/dist/sdk/browser/index.d.ts +28 -0
  48. package/dist/sdk/browser/index.js +72 -0
  49. package/dist/sdk/browser/network.d.ts +10 -0
  50. package/dist/sdk/browser/network.js +59 -0
  51. package/dist/sdk/browser/serverMethods.d.ts +3 -0
  52. package/dist/sdk/browser/serverMethods.js +7 -0
  53. package/dist/sdk/browser/session.d.ts +85 -0
  54. package/dist/sdk/browser/session.js +228 -0
  55. package/dist/sdk/browser/tools.d.ts +8 -0
  56. package/dist/sdk/browser/tools.js +329 -0
  57. package/dist/sdk/capabilities/api.d.ts +22 -0
  58. package/dist/sdk/capabilities/api.js +54 -0
  59. package/dist/sdk/capabilities/runSnapshot.d.ts +18 -0
  60. package/dist/sdk/capabilities/runSnapshot.js +47 -0
  61. package/dist/sdk/capabilities/types.d.ts +29 -0
  62. package/dist/sdk/capabilities/types.js +1 -0
  63. package/dist/sdk/cli.d.ts +2 -0
  64. package/dist/sdk/cli.js +150 -0
  65. package/dist/sdk/core/bus.d.ts +23 -0
  66. package/dist/sdk/core/bus.js +76 -0
  67. package/dist/sdk/core/caller.d.ts +22 -0
  68. package/dist/sdk/core/caller.js +16 -0
  69. package/dist/sdk/core/changes.d.ts +15 -0
  70. package/dist/sdk/core/changes.js +15 -0
  71. package/dist/sdk/core/effort.d.ts +2 -0
  72. package/dist/sdk/core/effort.js +1 -0
  73. package/dist/sdk/core/env.d.ts +18 -0
  74. package/dist/sdk/core/env.js +8 -0
  75. package/dist/sdk/core/errors.d.ts +15 -0
  76. package/dist/sdk/core/errors.js +24 -0
  77. package/dist/sdk/core/frontmatter.d.ts +12 -0
  78. package/dist/sdk/core/frontmatter.js +50 -0
  79. package/dist/sdk/core/fs.d.ts +18 -0
  80. package/dist/sdk/core/fs.js +106 -0
  81. package/dist/sdk/core/index.d.ts +24 -0
  82. package/dist/sdk/core/index.js +187 -0
  83. package/dist/sdk/core/path.d.ts +7 -0
  84. package/dist/sdk/core/path.js +79 -0
  85. package/dist/sdk/core/projects.d.ts +18 -0
  86. package/dist/sdk/core/projects.js +67 -0
  87. package/dist/sdk/core/secrets.d.ts +2 -0
  88. package/dist/sdk/core/secrets.js +5 -0
  89. package/dist/sdk/core/text.d.ts +7 -0
  90. package/dist/sdk/core/text.js +40 -0
  91. package/dist/sdk/doctor/checks.d.ts +5 -0
  92. package/dist/sdk/doctor/checks.js +208 -0
  93. package/dist/sdk/doctor/probe.d.ts +4 -0
  94. package/dist/sdk/doctor/probe.js +92 -0
  95. package/dist/sdk/doctor/serverMethods.d.ts +3 -0
  96. package/dist/sdk/doctor/serverMethods.js +8 -0
  97. package/dist/sdk/doctor/service.d.ts +23 -0
  98. package/dist/sdk/doctor/service.js +144 -0
  99. package/dist/sdk/doctor/types.d.ts +141 -0
  100. package/dist/sdk/doctor/types.js +29 -0
  101. package/dist/sdk/harness.d.ts +148 -0
  102. package/dist/sdk/harness.js +338 -0
  103. package/dist/sdk/history/lessonPrompt.d.ts +2 -0
  104. package/dist/sdk/history/lessonPrompt.js +15 -0
  105. package/dist/sdk/history/lessons.d.ts +52 -0
  106. package/dist/sdk/history/lessons.js +173 -0
  107. package/dist/sdk/history/recall.d.ts +68 -0
  108. package/dist/sdk/history/recall.js +199 -0
  109. package/dist/sdk/history/serverMethods.d.ts +3 -0
  110. package/dist/sdk/history/serverMethods.js +8 -0
  111. package/dist/sdk/history/trajectory.d.ts +7 -0
  112. package/dist/sdk/history/trajectory.js +216 -0
  113. package/dist/sdk/hub/catalog.json +123 -0
  114. package/dist/sdk/hub/cli.d.ts +7 -0
  115. package/dist/sdk/hub/cli.js +81 -0
  116. package/dist/sdk/hub/hub.d.ts +74 -0
  117. package/dist/sdk/hub/hub.js +474 -0
  118. package/dist/sdk/hub/schema.d.ts +280 -0
  119. package/dist/sdk/hub/schema.js +78 -0
  120. package/dist/sdk/hub/serverMethods.d.ts +3 -0
  121. package/dist/sdk/hub/serverMethods.js +11 -0
  122. package/dist/sdk/index.d.ts +73 -0
  123. package/dist/sdk/index.js +55 -0
  124. package/dist/sdk/mcp/connections.d.ts +83 -0
  125. package/dist/sdk/mcp/connections.js +676 -0
  126. package/dist/sdk/mcp/manager.d.ts +26 -0
  127. package/dist/sdk/mcp/manager.js +124 -0
  128. package/dist/sdk/mcp/oauth.d.ts +35 -0
  129. package/dist/sdk/mcp/oauth.js +171 -0
  130. package/dist/sdk/mcp/scopeMigration.d.ts +19 -0
  131. package/dist/sdk/mcp/scopeMigration.js +198 -0
  132. package/dist/sdk/mcp/serverMethods.d.ts +3 -0
  133. package/dist/sdk/mcp/serverMethods.js +22 -0
  134. package/dist/sdk/mcp/service.d.ts +160 -0
  135. package/dist/sdk/mcp/service.js +510 -0
  136. package/dist/sdk/mcp/types.d.ts +131 -0
  137. package/dist/sdk/mcp/types.js +49 -0
  138. package/dist/sdk/pi/runtime.d.ts +13 -0
  139. package/dist/sdk/pi/runtime.js +31 -0
  140. package/dist/sdk/plugins/api.d.ts +66 -0
  141. package/dist/sdk/plugins/api.js +155 -0
  142. package/dist/sdk/plugins/attachments.d.ts +46 -0
  143. package/dist/sdk/plugins/attachments.js +111 -0
  144. package/dist/sdk/plugins/builtin.d.ts +7 -0
  145. package/dist/sdk/plugins/builtin.js +163 -0
  146. package/dist/sdk/plugins/builtinRegistry.d.ts +53 -0
  147. package/dist/sdk/plugins/builtinRegistry.js +49 -0
  148. package/dist/sdk/plugins/catalogue.d.ts +29 -0
  149. package/dist/sdk/plugins/catalogue.js +196 -0
  150. package/dist/sdk/plugins/cli.d.ts +13 -0
  151. package/dist/sdk/plugins/cli.js +188 -0
  152. package/dist/sdk/plugins/discover.d.ts +42 -0
  153. package/dist/sdk/plugins/discover.js +115 -0
  154. package/dist/sdk/plugins/firstParty.d.ts +50 -0
  155. package/dist/sdk/plugins/firstParty.js +113 -0
  156. package/dist/sdk/plugins/hooks.d.ts +94 -0
  157. package/dist/sdk/plugins/hooks.js +162 -0
  158. package/dist/sdk/plugins/identity.d.ts +19 -0
  159. package/dist/sdk/plugins/identity.js +48 -0
  160. package/dist/sdk/plugins/install.d.ts +20 -0
  161. package/dist/sdk/plugins/install.js +110 -0
  162. package/dist/sdk/plugins/inventory.d.ts +22 -0
  163. package/dist/sdk/plugins/inventory.js +110 -0
  164. package/dist/sdk/plugins/manifest.d.ts +13 -0
  165. package/dist/sdk/plugins/manifest.js +56 -0
  166. package/dist/sdk/plugins/plugins.d.ts +104 -0
  167. package/dist/sdk/plugins/plugins.js +164 -0
  168. package/dist/sdk/plugins/runtime.d.ts +9 -0
  169. package/dist/sdk/plugins/runtime.js +95 -0
  170. package/dist/sdk/plugins/trust.d.ts +44 -0
  171. package/dist/sdk/plugins/trust.js +120 -0
  172. package/dist/sdk/plugins/types.d.ts +159 -0
  173. package/dist/sdk/plugins/types.js +7 -0
  174. package/dist/sdk/prompt/compile.d.ts +177 -0
  175. package/dist/sdk/prompt/compile.js +413 -0
  176. package/dist/sdk/refine/cli.d.ts +4 -0
  177. package/dist/sdk/refine/cli.js +186 -0
  178. package/dist/sdk/refine/demo.d.ts +21 -0
  179. package/dist/sdk/refine/demo.js +114 -0
  180. package/dist/sdk/refine/evidence.d.ts +55 -0
  181. package/dist/sdk/refine/evidence.js +330 -0
  182. package/dist/sdk/refine/host.d.ts +51 -0
  183. package/dist/sdk/refine/host.js +76 -0
  184. package/dist/sdk/refine/ledger.d.ts +48 -0
  185. package/dist/sdk/refine/ledger.js +76 -0
  186. package/dist/sdk/refine/library.d.ts +55 -0
  187. package/dist/sdk/refine/library.js +177 -0
  188. package/dist/sdk/refine/pi.d.ts +72 -0
  189. package/dist/sdk/refine/pi.js +248 -0
  190. package/dist/sdk/refine/prompts.d.ts +45 -0
  191. package/dist/sdk/refine/prompts.js +390 -0
  192. package/dist/sdk/refine/recursion.d.ts +113 -0
  193. package/dist/sdk/refine/recursion.js +258 -0
  194. package/dist/sdk/refine/runner.d.ts +81 -0
  195. package/dist/sdk/refine/runner.js +150 -0
  196. package/dist/sdk/refine/selection.d.ts +57 -0
  197. package/dist/sdk/refine/selection.js +251 -0
  198. package/dist/sdk/refine/serverMethods.d.ts +3 -0
  199. package/dist/sdk/refine/serverMethods.js +20 -0
  200. package/dist/sdk/refine/service.d.ts +84 -0
  201. package/dist/sdk/refine/service.js +165 -0
  202. package/dist/sdk/refine/suite.d.ts +67 -0
  203. package/dist/sdk/refine/suite.js +174 -0
  204. package/dist/sdk/refine/trajectory.d.ts +9 -0
  205. package/dist/sdk/refine/trajectory.js +68 -0
  206. package/dist/sdk/refine/types.d.ts +77 -0
  207. package/dist/sdk/refine/types.js +10 -0
  208. package/dist/sdk/server/methods.d.ts +3 -0
  209. package/dist/sdk/server/methods.js +293 -0
  210. package/dist/sdk/server/params.d.ts +4 -0
  211. package/dist/sdk/server/params.js +11 -0
  212. package/dist/sdk/server/remote.d.ts +19 -0
  213. package/dist/sdk/server/remote.js +84 -0
  214. package/dist/sdk/server/rpc.d.ts +20 -0
  215. package/dist/sdk/server/rpc.js +102 -0
  216. package/dist/sdk/server/serve.d.ts +10 -0
  217. package/dist/sdk/server/serve.js +18 -0
  218. package/dist/sdk/sessions/approvals.d.ts +47 -0
  219. package/dist/sdk/sessions/approvals.js +119 -0
  220. package/dist/sdk/sessions/continuation.d.ts +48 -0
  221. package/dist/sdk/sessions/continuation.js +85 -0
  222. package/dist/sdk/sessions/contracts.d.ts +551 -0
  223. package/dist/sdk/sessions/contracts.js +338 -0
  224. package/dist/sdk/sessions/extensionUi.d.ts +19 -0
  225. package/dist/sdk/sessions/extensionUi.js +64 -0
  226. package/dist/sdk/sessions/history.d.ts +16 -0
  227. package/dist/sdk/sessions/history.js +68 -0
  228. package/dist/sdk/sessions/lineageJoin.d.ts +2 -0
  229. package/dist/sdk/sessions/lineageJoin.js +61 -0
  230. package/dist/sdk/sessions/planMode.d.ts +39 -0
  231. package/dist/sdk/sessions/planMode.js +93 -0
  232. package/dist/sdk/sessions/policy.d.ts +43 -0
  233. package/dist/sdk/sessions/policy.js +1 -0
  234. package/dist/sdk/sessions/pricing.d.ts +34 -0
  235. package/dist/sdk/sessions/pricing.js +40 -0
  236. package/dist/sdk/sessions/reasoningSummaries.d.ts +11 -0
  237. package/dist/sdk/sessions/reasoningSummaries.js +61 -0
  238. package/dist/sdk/sessions/registry.d.ts +103 -0
  239. package/dist/sdk/sessions/registry.js +386 -0
  240. package/dist/sdk/sessions/runIndex.d.ts +21 -0
  241. package/dist/sdk/sessions/runIndex.js +65 -0
  242. package/dist/sdk/sessions/runStore.d.ts +66 -0
  243. package/dist/sdk/sessions/runStore.js +337 -0
  244. package/dist/sdk/sessions/runner.d.ts +213 -0
  245. package/dist/sdk/sessions/runner.js +589 -0
  246. package/dist/sdk/sessions/sessions.d.ts +152 -0
  247. package/dist/sdk/sessions/sessions.js +461 -0
  248. package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
  249. package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
  250. package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
  251. package/dist/sdk/sessions/sideQuestions.js +290 -0
  252. package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
  253. package/dist/sdk/sessions/subagentServerMethods.js +41 -0
  254. package/dist/sdk/sessions/subagentService.d.ts +52 -0
  255. package/dist/sdk/sessions/subagentService.js +265 -0
  256. package/dist/sdk/sessions/subagents.d.ts +58 -0
  257. package/dist/sdk/sessions/subagents.js +87 -0
  258. package/dist/sdk/terminal/accountsMenu.d.ts +46 -0
  259. package/dist/sdk/terminal/accountsMenu.js +392 -0
  260. package/dist/sdk/terminal/browser.d.ts +62 -0
  261. package/dist/sdk/terminal/browser.js +41 -0
  262. package/dist/sdk/terminal/browserControl.d.ts +29 -0
  263. package/dist/sdk/terminal/browserControl.js +186 -0
  264. package/dist/sdk/terminal/cli.d.ts +20 -0
  265. package/dist/sdk/terminal/cli.js +121 -0
  266. package/dist/sdk/terminal/client.d.ts +15 -0
  267. package/dist/sdk/terminal/client.js +126 -0
  268. package/dist/sdk/terminal/commandHelp.d.ts +17 -0
  269. package/dist/sdk/terminal/commandHelp.js +20 -0
  270. package/dist/sdk/terminal/control.d.ts +4 -0
  271. package/dist/sdk/terminal/control.js +25 -0
  272. package/dist/sdk/terminal/controller.d.ts +78 -0
  273. package/dist/sdk/terminal/controller.js +383 -0
  274. package/dist/sdk/terminal/hubMenu.d.ts +10 -0
  275. package/dist/sdk/terminal/hubMenu.js +34 -0
  276. package/dist/sdk/terminal/launch.d.ts +5 -0
  277. package/dist/sdk/terminal/launch.js +27 -0
  278. package/dist/sdk/terminal/logs.d.ts +14 -0
  279. package/dist/sdk/terminal/logs.js +59 -0
  280. package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
  281. package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
  282. package/dist/sdk/terminal/piExtension.d.ts +6 -0
  283. package/dist/sdk/terminal/piExtension.js +377 -0
  284. package/dist/sdk/terminal/pluginMenu.d.ts +34 -0
  285. package/dist/sdk/terminal/pluginMenu.js +101 -0
  286. package/dist/sdk/terminal/socket.d.ts +73 -0
  287. package/dist/sdk/terminal/socket.js +287 -0
  288. package/dist/sdk/terminal/standalone.d.ts +20 -0
  289. package/dist/sdk/terminal/standalone.js +186 -0
  290. package/dist/sdk/terminal/subagentMonitor.d.ts +38 -0
  291. package/dist/sdk/terminal/subagentMonitor.js +121 -0
  292. package/dist/sdk/terminal/terminals.d.ts +212 -0
  293. package/dist/sdk/terminal/terminals.js +1108 -0
  294. package/dist/sdk/terminal/trajectory.d.ts +10 -0
  295. package/dist/sdk/terminal/trajectory.js +30 -0
  296. package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
  297. package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
  298. package/dist/sdk/terminal/tui/chrome.d.ts +64 -0
  299. package/dist/sdk/terminal/tui/chrome.js +169 -0
  300. package/dist/sdk/terminal/tui/clipboardFiles.d.ts +11 -0
  301. package/dist/sdk/terminal/tui/clipboardFiles.js +74 -0
  302. package/dist/sdk/terminal/tui/commandPages.d.ts +11 -0
  303. package/dist/sdk/terminal/tui/commandPages.js +111 -0
  304. package/dist/sdk/terminal/tui/commands.d.ts +46 -0
  305. package/dist/sdk/terminal/tui/commands.js +399 -0
  306. package/dist/sdk/terminal/tui/dialogGeometry.d.ts +27 -0
  307. package/dist/sdk/terminal/tui/dialogGeometry.js +52 -0
  308. package/dist/sdk/terminal/tui/dialogs.d.ts +80 -0
  309. package/dist/sdk/terminal/tui/dialogs.js +370 -0
  310. package/dist/sdk/terminal/tui/keybindings.d.ts +11 -0
  311. package/dist/sdk/terminal/tui/keybindings.js +49 -0
  312. package/dist/sdk/terminal/tui/list.d.ts +73 -0
  313. package/dist/sdk/terminal/tui/list.js +196 -0
  314. package/dist/sdk/terminal/tui/modeChoices.d.ts +42 -0
  315. package/dist/sdk/terminal/tui/modeChoices.js +70 -0
  316. package/dist/sdk/terminal/tui/modelPicker.d.ts +55 -0
  317. package/dist/sdk/terminal/tui/modelPicker.js +150 -0
  318. package/dist/sdk/terminal/tui/mouse.d.ts +3 -0
  319. package/dist/sdk/terminal/tui/mouse.js +3 -0
  320. package/dist/sdk/terminal/tui/page.d.ts +17 -0
  321. package/dist/sdk/terminal/tui/page.js +1 -0
  322. package/dist/sdk/terminal/tui/pageOverlay.d.ts +27 -0
  323. package/dist/sdk/terminal/tui/pageOverlay.js +156 -0
  324. package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +76 -0
  325. package/dist/sdk/terminal/tui/pages/accountsPage.js +409 -0
  326. package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
  327. package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
  328. package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
  329. package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
  330. package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
  331. package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
  332. package/dist/sdk/terminal/tui/pages/componentsPage.d.ts +47 -0
  333. package/dist/sdk/terminal/tui/pages/componentsPage.js +119 -0
  334. package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +39 -0
  335. package/dist/sdk/terminal/tui/pages/doctorPage.js +233 -0
  336. package/dist/sdk/terminal/tui/pages/hubPage.d.ts +39 -0
  337. package/dist/sdk/terminal/tui/pages/hubPage.js +128 -0
  338. package/dist/sdk/terminal/tui/pages/logPage.d.ts +38 -0
  339. package/dist/sdk/terminal/tui/pages/logPage.js +189 -0
  340. package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
  341. package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
  342. package/dist/sdk/terminal/tui/pages/permissionsPage.d.ts +44 -0
  343. package/dist/sdk/terminal/tui/pages/permissionsPage.js +124 -0
  344. package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +57 -0
  345. package/dist/sdk/terminal/tui/pages/pluginsPage.js +243 -0
  346. package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +63 -0
  347. package/dist/sdk/terminal/tui/pages/settingsPage.js +103 -0
  348. package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +23 -0
  349. package/dist/sdk/terminal/tui/pages/subagentsPage.js +70 -0
  350. package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +65 -0
  351. package/dist/sdk/terminal/tui/pages/trajectoryPage.js +450 -0
  352. package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
  353. package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
  354. package/dist/sdk/terminal/tui/piAdapter.d.ts +18 -0
  355. package/dist/sdk/terminal/tui/piAdapter.js +48 -0
  356. package/dist/sdk/terminal/tui/planMode.d.ts +2 -0
  357. package/dist/sdk/terminal/tui/planMode.js +2 -0
  358. package/dist/sdk/terminal/tui/pluginCommands.d.ts +14 -0
  359. package/dist/sdk/terminal/tui/pluginCommands.js +27 -0
  360. package/dist/sdk/terminal/tui/questionPicker.d.ts +20 -0
  361. package/dist/sdk/terminal/tui/questionPicker.js +150 -0
  362. package/dist/sdk/terminal/tui/questions.d.ts +21 -0
  363. package/dist/sdk/terminal/tui/questions.js +42 -0
  364. package/dist/sdk/terminal/tui/runtime.d.ts +114 -0
  365. package/dist/sdk/terminal/tui/runtime.js +443 -0
  366. package/dist/sdk/terminal/tui/search.d.ts +22 -0
  367. package/dist/sdk/terminal/tui/search.js +60 -0
  368. package/dist/sdk/terminal/tui/selection.d.ts +16 -0
  369. package/dist/sdk/terminal/tui/selection.js +16 -0
  370. package/dist/sdk/terminal/tui/sessionUi.d.ts +3 -0
  371. package/dist/sdk/terminal/tui/sessionUi.js +30 -0
  372. package/dist/sdk/terminal/tui/settingsModel.d.ts +14 -0
  373. package/dist/sdk/terminal/tui/settingsModel.js +114 -0
  374. package/dist/sdk/terminal/tui/sideQuestion.d.ts +53 -0
  375. package/dist/sdk/terminal/tui/sideQuestion.js +230 -0
  376. package/dist/sdk/terminal/tui/skillInvocation.d.ts +9 -0
  377. package/dist/sdk/terminal/tui/skillInvocation.js +43 -0
  378. package/dist/sdk/terminal/tui/status.d.ts +18 -0
  379. package/dist/sdk/terminal/tui/status.js +67 -0
  380. package/dist/sdk/terminal/tui/theme.d.ts +45 -0
  381. package/dist/sdk/terminal/tui/theme.js +176 -0
  382. package/dist/sdk/terminal/tui/treeModel.d.ts +79 -0
  383. package/dist/sdk/terminal/tui/treeModel.js +483 -0
  384. package/dist/sdk/terminal/tui/treePicker.d.ts +49 -0
  385. package/dist/sdk/terminal/tui/treePicker.js +251 -0
  386. package/dist/sdk/terminal/tui/ui.d.ts +49 -0
  387. package/dist/sdk/terminal/tui/ui.js +149 -0
  388. package/dist/sdk/terminal/tui/workingStatus.d.ts +9 -0
  389. package/dist/sdk/terminal/tui/workingStatus.js +229 -0
  390. package/dist/sdk/tools/askUser.d.ts +6 -0
  391. package/dist/sdk/tools/askUser.js +92 -0
  392. package/dist/sdk/tools/checklist.d.ts +9 -0
  393. package/dist/sdk/tools/checklist.js +54 -0
  394. package/dist/sdk/tools/definitions.d.ts +30 -0
  395. package/dist/sdk/tools/definitions.js +117 -0
  396. package/dist/sdk/tools/dispatch.d.ts +16 -0
  397. package/dist/sdk/tools/dispatch.js +67 -0
  398. package/dist/sdk/tools/harnessTools.d.ts +8 -0
  399. package/dist/sdk/tools/harnessTools.js +20 -0
  400. package/dist/sdk/tools/sessionName.d.ts +7 -0
  401. package/dist/sdk/tools/sessionName.js +31 -0
  402. package/dist/sdk/tools/spawnSubagent.d.ts +4 -0
  403. package/dist/sdk/tools/spawnSubagent.js +58 -0
  404. package/dist/sdk/tools/types.d.ts +48 -0
  405. package/dist/sdk/tools/types.js +1 -0
  406. package/dist/sdk/variant/components.d.ts +34 -0
  407. package/dist/sdk/variant/components.js +230 -0
  408. package/dist/sdk/variant/materialise.d.ts +66 -0
  409. package/dist/sdk/variant/materialise.js +81 -0
  410. package/dist/sdk/variant/migrate.d.ts +4 -0
  411. package/dist/sdk/variant/migrate.js +41 -0
  412. package/dist/sdk/variant/seed.d.ts +20 -0
  413. package/dist/sdk/variant/seed.js +116 -0
  414. package/dist/sdk/variant/store.d.ts +82 -0
  415. package/dist/sdk/variant/store.js +151 -0
  416. package/dist/sdk/variant/surface.d.ts +56 -0
  417. package/dist/sdk/variant/surface.js +81 -0
  418. package/dist/sdk/variant/trust.d.ts +27 -0
  419. package/dist/sdk/variant/trust.js +64 -0
  420. package/dist/sdk/variant/variant.d.ts +71 -0
  421. package/dist/sdk/variant/variant.js +331 -0
  422. package/dist/sdk/web/markdown.d.ts +10 -0
  423. package/dist/sdk/web/markdown.js +66 -0
  424. package/dist/sdk/web/part.d.ts +10 -0
  425. package/dist/sdk/web/part.js +6 -0
  426. package/dist/sdk/web/safeRequest.d.ts +34 -0
  427. package/dist/sdk/web/safeRequest.js +175 -0
  428. package/dist/sdk/web/search.d.ts +53 -0
  429. package/dist/sdk/web/search.js +168 -0
  430. package/dist/sdk/web/serverMethods.d.ts +3 -0
  431. package/dist/sdk/web/serverMethods.js +7 -0
  432. package/dist/sdk/web/text.d.ts +2 -0
  433. package/dist/sdk/web/text.js +7 -0
  434. package/dist/sdk/web/tools.d.ts +22 -0
  435. package/dist/sdk/web/tools.js +195 -0
  436. package/dist/sdk/web/turndown-plugin-gfm.d.ts +4 -0
  437. package/dist/sdk/wiki/notes.d.ts +68 -0
  438. package/dist/sdk/wiki/notes.js +297 -0
  439. package/dist/sdk/wiki/serverMethods.d.ts +3 -0
  440. package/dist/sdk/wiki/serverMethods.js +26 -0
  441. package/dist/sdk/worktrees/cli.d.ts +11 -0
  442. package/dist/sdk/worktrees/cli.js +146 -0
  443. package/dist/sdk/worktrees/copy.d.ts +9 -0
  444. package/dist/sdk/worktrees/copy.js +111 -0
  445. package/dist/sdk/worktrees/git.d.ts +16 -0
  446. package/dist/sdk/worktrees/git.js +81 -0
  447. package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
  448. package/dist/sdk/worktrees/serverMethods.js +30 -0
  449. package/dist/sdk/worktrees/service.d.ts +73 -0
  450. package/dist/sdk/worktrees/service.js +483 -0
  451. package/dist/sdk/worktrees/setup.d.ts +23 -0
  452. package/dist/sdk/worktrees/setup.js +65 -0
  453. package/dist/sdk/worktrees/types.d.ts +91 -0
  454. package/dist/sdk/worktrees/types.js +1 -0
  455. package/dist/sdk/world/actions.d.ts +23 -0
  456. package/dist/sdk/world/actions.js +31 -0
  457. package/dist/sdk/world/cli.d.ts +12 -0
  458. package/dist/sdk/world/cli.js +166 -0
  459. package/dist/sdk/world/images.d.ts +20 -0
  460. package/dist/sdk/world/images.js +48 -0
  461. package/dist/sdk/world/untrusted.d.ts +12 -0
  462. package/dist/sdk/world/untrusted.js +20 -0
  463. package/dist/sdk/world/world.d.ts +67 -0
  464. package/dist/sdk/world/world.js +79 -0
  465. package/dist/terminal-opentui.js +20778 -0
  466. package/dist/terminal-pi.js +794 -518
  467. package/docs/README.md +42 -0
  468. package/docs/architecture/00-overview.md +171 -0
  469. package/docs/architecture/01-extension-points.md +78 -0
  470. package/docs/architecture/02-sessions-and-runs.md +203 -0
  471. package/docs/architecture/03-variants.md +103 -0
  472. package/docs/architecture/04-prompt.md +122 -0
  473. package/docs/architecture/05-refinement.md +107 -0
  474. package/docs/architecture/06-plugins-and-capabilities.md +129 -0
  475. package/docs/architecture/07-tools-and-gate.md +103 -0
  476. package/docs/architecture/08-memory-and-history.md +94 -0
  477. package/docs/architecture/09-accounts-and-connectors.md +98 -0
  478. package/docs/architecture/10-server-protocol.md +193 -0
  479. package/docs/architecture/11-terminal.md +261 -0
  480. package/docs/architecture/12-storage.md +75 -0
  481. package/docs/architecture/13-world-tools.md +45 -0
  482. package/docs/architecture/14-surfaces-and-parity.md +89 -0
  483. package/docs/architecture/README.md +125 -0
  484. package/docs/architecture/proposals/PROP-0001-reporting-section.md +106 -0
  485. package/docs/architecture/proposals/PROP-0002-retain-rollout-workspaces.md +104 -0
  486. package/docs/architecture/proposals/PROP-0003-executor-settings.md +81 -0
  487. package/docs/architecture/proposals/PROP-0004-flexible-reporting-guidance.md +71 -0
  488. package/docs/architecture/proposals/PROP-0005-xharness-cli-name.md +78 -0
  489. package/docs/architecture/proposals/PROP-0006-run-checklist.md +70 -0
  490. package/docs/architecture/proposals/PROP-0007-run-continuation.md +80 -0
  491. package/docs/architecture/proposals/PROP-0008-lessons-from-runs.md +80 -0
  492. package/docs/architecture/proposals/PROP-0009-foundation-and-variants.md +78 -0
  493. package/docs/architecture/proposals/PROP-0010-session-names.md +73 -0
  494. package/docs/architecture/proposals/PROP-0011-doctor.md +63 -0
  495. package/docs/architecture/proposals/PROP-0012-release-baseline.md +56 -0
  496. package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
  497. package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
  498. package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
  499. package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
  500. package/docs/architecture/proposals/PROP-0017-page-annotations.md +127 -0
  501. package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
  502. package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
  503. package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
  504. package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
  505. package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
  506. package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
  507. package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
  508. package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
  509. package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
  510. package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
  511. package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
  512. package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
  513. package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
  514. package/docs/architecture/proposals/README.md +101 -0
  515. package/docs/decisions/ADR-0002-native-subagent-lifecycle.md +49 -0
  516. package/docs/decisions/ADR-0003-shared-asynchronous-subagents.md +70 -0
  517. package/docs/decisions/ADR-0004-fullscreen-terminal-layout.md +50 -0
  518. package/docs/decisions/ADR-0005-app-provided-oauth-clients.md +54 -0
  519. package/docs/decisions/ADR-0006-opentui-only-terminal.md +47 -0
  520. package/docs/decisions/ADR-0007-reporting-section.md +33 -0
  521. package/docs/decisions/ADR-0008-flexible-reporting-guidance.md +38 -0
  522. package/docs/decisions/ADR-0009-xharness-command.md +39 -0
  523. package/docs/decisions/ADR-0010-lessons-in-the-wiki.md +31 -0
  524. package/docs/decisions/ADR-0011-foundation-and-variants.md +28 -0
  525. package/docs/decisions/ADR-0012-native-session-names.md +34 -0
  526. package/docs/decisions/ADR-0013-doctor.md +27 -0
  527. package/docs/decisions/ADR-0014-public-release-baseline.md +22 -0
  528. package/docs/decisions/ADR-0015-resource-browser.md +28 -0
  529. package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
  530. package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
  531. package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
  532. package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
  533. package/docs/decisions/ADR-0020-page-annotations.md +37 -0
  534. package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
  535. package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
  536. package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
  537. package/docs/decisions/ADR-0024-xagent-command.md +40 -0
  538. package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
  539. package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
  540. package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
  541. package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
  542. package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
  543. package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
  544. package/docs/doctor.md +80 -0
  545. package/docs/experiments/EXP-0001-terminal-input-latency/plan.md +81 -0
  546. package/docs/experiments/EXP-0001-terminal-input-latency/results.md +46 -0
  547. package/docs/experiments/EXP-0002-opentui-typing-latency/plan.md +70 -0
  548. package/docs/experiments/EXP-0002-opentui-typing-latency/results.md +92 -0
  549. package/docs/features/README.md +46 -0
  550. package/docs/features/automations/README.md +41 -0
  551. package/docs/features/cores/README.md +39 -0
  552. package/docs/features/google-harness2/README.md +52 -0
  553. package/docs/features/integrations/README.md +40 -0
  554. package/docs/features/interfaces/README.md +29 -0
  555. package/docs/features/memory/README.md +28 -0
  556. package/docs/future-work.md +48 -0
  557. package/docs/parity.md +78 -0
  558. package/docs/releases/1.0.0.md +40 -0
  559. package/docs/releases/4.0.0.md +46 -0
  560. package/docs/releases/README.md +41 -0
  561. package/docs/study/00-index.md +83 -0
  562. package/docs/study/arms/00-matrix.md +20 -0
  563. package/docs/study/arms/01-system-prompt.md +211 -0
  564. package/docs/study/arms/02-tools.md +79 -0
  565. package/docs/study/arms/03-subagents.md +90 -0
  566. package/docs/study/arms/04-skills.md +75 -0
  567. package/docs/study/arms/05-context-management.md +90 -0
  568. package/docs/study/arms/06-memory.md +90 -0
  569. package/docs/study/arms/07-governance.md +71 -0
  570. package/docs/study/arms/08-execution.md +69 -0
  571. package/docs/study/arms/09-observability.md +60 -0
  572. package/docs/study/arms/10-refinement.md +110 -0
  573. package/docs/study/autonomous-engineering-sources.md +277 -0
  574. package/docs/study/autonomy-sources.md +147 -0
  575. package/docs/study/btw-comparison.md +37 -0
  576. package/docs/study/feature-gap-review.md +42 -0
  577. package/docs/study/insights.md +123 -0
  578. package/docs/study/proactive-autonomy.md +408 -0
  579. package/docs/study/roadmap.md +72 -0
  580. package/docs/study/sources/claude-code.md +44 -0
  581. package/docs/study/sources/deepseek-harness.md +102 -0
  582. package/docs/study/sources/harness2.md +50 -0
  583. package/docs/study/sources/kimi-cli.md +42 -0
  584. package/docs/study/sources/omp.md +93 -0
  585. package/docs/study/sources/opencode.md +43 -0
  586. package/docs/study/sources/openhands.md +46 -0
  587. package/docs/study/sources/smolagents.md +40 -0
  588. package/docs/study/sources/swe-agent.md +34 -0
  589. package/docs/study/tui-resource-browser.md +78 -0
  590. package/docs/system-prompt-design.md +196 -0
  591. package/docs/terminal-tui.md +707 -58
  592. package/package.json +43 -13
  593. package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
  594. package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
  595. package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
  596. package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
  597. package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
  598. package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
  599. package/docs/evidence/terminal-2026-10-17/verification.json +0 -130
  600. package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
  601. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
  602. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
  603. package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
  604. package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
  605. package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
  606. package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
  607. package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
  608. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
  609. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
  610. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
  611. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
  612. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +0 -95
  613. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
  614. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
  615. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
  616. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
  617. package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +0 -27
  618. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
  619. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +0 -18
  620. package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +0 -95
  621. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
  622. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
  623. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +0 -60
  624. package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +0 -24
  625. package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
  626. package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +0 -57
  627. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
  628. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
  629. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +0 -58
  630. package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
  631. package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +0 -320
  632. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +0 -30
  633. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +0 -133
  634. package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +0 -20
  635. package/docs/evidence/terminal-2026-10-17-followup/verification.json +0 -207
  636. package/src/accounts/accounts.test.ts +0 -333
  637. package/src/accounts/accounts.ts +0 -658
  638. package/src/accounts/env.test.ts +0 -95
  639. package/src/accounts/env.ts +0 -338
  640. package/src/accounts/secrets.ts +0 -50
  641. package/src/accounts/store.ts +0 -338
  642. package/src/capabilities/api.ts +0 -75
  643. package/src/capabilities/runSnapshot.ts +0 -59
  644. package/src/capabilities/types.ts +0 -34
  645. package/src/cli.ts +0 -118
  646. package/src/core/bus.ts +0 -34
  647. package/src/core/changes.ts +0 -33
  648. package/src/core/env.ts +0 -27
  649. package/src/core/errors.ts +0 -32
  650. package/src/core/frontmatter.ts +0 -47
  651. package/src/core/fs.test.ts +0 -38
  652. package/src/core/fs.ts +0 -92
  653. package/src/core/index.ts +0 -193
  654. package/src/core/path.test.ts +0 -14
  655. package/src/core/path.ts +0 -79
  656. package/src/core/projects.ts +0 -90
  657. package/src/core/text.ts +0 -39
  658. package/src/harness.ts +0 -312
  659. package/src/hub/catalog.json +0 -123
  660. package/src/hub/cli.ts +0 -59
  661. package/src/hub/hub.test.ts +0 -205
  662. package/src/hub/hub.ts +0 -256
  663. package/src/hub/schema.ts +0 -81
  664. package/src/index.ts +0 -75
  665. package/src/mcp/connections.ts +0 -614
  666. package/src/mcp/manager.ts +0 -130
  667. package/src/mcp/oauth.ts +0 -195
  668. package/src/mcp/scopeMigration.test.ts +0 -79
  669. package/src/mcp/scopeMigration.ts +0 -204
  670. package/src/mcp/service.test.ts +0 -376
  671. package/src/mcp/service.ts +0 -549
  672. package/src/mcp/types.ts +0 -108
  673. package/src/memory/api.test.ts +0 -82
  674. package/src/memory/api.ts +0 -303
  675. package/src/memory/blocks.test.ts +0 -78
  676. package/src/memory/blocks.ts +0 -408
  677. package/src/memory/caller.ts +0 -69
  678. package/src/memory/curation.test.ts +0 -163
  679. package/src/memory/curation.ts +0 -64
  680. package/src/memory/dispatch.ts +0 -59
  681. package/src/memory/facts.test.ts +0 -41
  682. package/src/memory/facts.ts +0 -248
  683. package/src/memory/graph.ts +0 -103
  684. package/src/memory/health.test.ts +0 -130
  685. package/src/memory/health.ts +0 -74
  686. package/src/memory/maintainer.ts +0 -272
  687. package/src/memory/maintenance.test.ts +0 -176
  688. package/src/memory/maintenance.ts +0 -518
  689. package/src/memory/migrate.ts +0 -79
  690. package/src/memory/operations.ts +0 -150
  691. package/src/memory/proposals.test.ts +0 -168
  692. package/src/memory/proposals.ts +0 -584
  693. package/src/memory/recall.test.ts +0 -115
  694. package/src/memory/recall.ts +0 -278
  695. package/src/memory/references.ts +0 -77
  696. package/src/memory/runContext.ts +0 -93
  697. package/src/memory/secrets.ts +0 -6
  698. package/src/memory/store.test.ts +0 -66
  699. package/src/memory/store.ts +0 -385
  700. package/src/memory/wiki.test.ts +0 -47
  701. package/src/memory/wiki.ts +0 -422
  702. package/src/memory/wikiIndex.test.ts +0 -88
  703. package/src/memory/wikiIndex.ts +0 -116
  704. package/src/plugins/api.ts +0 -181
  705. package/src/plugins/attachments.test.ts +0 -84
  706. package/src/plugins/attachments.ts +0 -141
  707. package/src/plugins/builtin.ts +0 -82
  708. package/src/plugins/catalogue.test.ts +0 -254
  709. package/src/plugins/catalogue.ts +0 -251
  710. package/src/plugins/cli.ts +0 -184
  711. package/src/plugins/discover.ts +0 -151
  712. package/src/plugins/firstParty.test.ts +0 -143
  713. package/src/plugins/firstParty.ts +0 -129
  714. package/src/plugins/hooks.test.ts +0 -250
  715. package/src/plugins/hooks.ts +0 -239
  716. package/src/plugins/identity.ts +0 -37
  717. package/src/plugins/install.test.ts +0 -107
  718. package/src/plugins/install.ts +0 -106
  719. package/src/plugins/inventory.ts +0 -123
  720. package/src/plugins/manifest.ts +0 -76
  721. package/src/plugins/plugins.test.ts +0 -205
  722. package/src/plugins/plugins.ts +0 -189
  723. package/src/plugins/proposal.ts +0 -121
  724. package/src/plugins/runtime.test.ts +0 -40
  725. package/src/plugins/runtime.ts +0 -82
  726. package/src/plugins/trust.ts +0 -142
  727. package/src/plugins/types.ts +0 -149
  728. package/src/prompt/compile.test.ts +0 -261
  729. package/src/prompt/compile.ts +0 -732
  730. package/src/server/methods.ts +0 -349
  731. package/src/server/remote.ts +0 -77
  732. package/src/server/rpc.ts +0 -116
  733. package/src/server/serve.ts +0 -28
  734. package/src/server/server.test.ts +0 -174
  735. package/src/sessions/approvals.ts +0 -118
  736. package/src/sessions/contracts.ts +0 -336
  737. package/src/sessions/conversation.test.ts +0 -177
  738. package/src/sessions/extensionSession.test.ts +0 -74
  739. package/src/sessions/extensionUi.test.ts +0 -65
  740. package/src/sessions/extensionUi.ts +0 -102
  741. package/src/sessions/history.ts +0 -51
  742. package/src/sessions/lineageJoin.ts +0 -75
  743. package/src/sessions/policy.ts +0 -36
  744. package/src/sessions/pricing.ts +0 -60
  745. package/src/sessions/questionBatches.test.ts +0 -110
  746. package/src/sessions/reasoningSummaries.ts +0 -59
  747. package/src/sessions/registry.ts +0 -381
  748. package/src/sessions/runIndex.ts +0 -99
  749. package/src/sessions/runStore.test.ts +0 -152
  750. package/src/sessions/runStore.ts +0 -332
  751. package/src/sessions/runner.ts +0 -604
  752. package/src/sessions/runtimeResources.test.ts +0 -61
  753. package/src/sessions/sessions.test.ts +0 -549
  754. package/src/sessions/sessions.ts +0 -339
  755. package/src/skills/registry.test.ts +0 -104
  756. package/src/skills/registry.ts +0 -413
  757. package/src/terminal/accountsMenu.test.ts +0 -225
  758. package/src/terminal/accountsMenu.ts +0 -382
  759. package/src/terminal/cli.ts +0 -149
  760. package/src/terminal/client.ts +0 -74
  761. package/src/terminal/control.test.ts +0 -23
  762. package/src/terminal/control.ts +0 -23
  763. package/src/terminal/controller.ts +0 -291
  764. package/src/terminal/hubMenu.ts +0 -24
  765. package/src/terminal/launch.test.ts +0 -25
  766. package/src/terminal/launch.ts +0 -48
  767. package/src/terminal/piExtension.lifecycle.test.ts +0 -55
  768. package/src/terminal/piExtension.ts +0 -259
  769. package/src/terminal/pluginControl.test.ts +0 -146
  770. package/src/terminal/pluginMenu.ts +0 -112
  771. package/src/terminal/socket.test.ts +0 -71
  772. package/src/terminal/socket.ts +0 -232
  773. package/src/terminal/standalone.test.ts +0 -167
  774. package/src/terminal/standalone.ts +0 -153
  775. package/src/terminal/terminal.test.ts +0 -399
  776. package/src/terminal/terminals.ts +0 -553
  777. package/src/terminal/tui/application.test.ts +0 -114
  778. package/src/terminal/tui/application.ts +0 -491
  779. package/src/terminal/tui/commands.test.ts +0 -218
  780. package/src/terminal/tui/commands.ts +0 -361
  781. package/src/terminal/tui/dialogs.ts +0 -301
  782. package/src/terminal/tui/editor.test.ts +0 -84
  783. package/src/terminal/tui/editor.ts +0 -79
  784. package/src/terminal/tui/keybindings.test.ts +0 -22
  785. package/src/terminal/tui/keybindings.ts +0 -50
  786. package/src/terminal/tui/piAdapter.ts +0 -62
  787. package/src/terminal/tui/presentation.test.ts +0 -79
  788. package/src/terminal/tui/questions.test.ts +0 -41
  789. package/src/terminal/tui/questions.ts +0 -47
  790. package/src/terminal/tui/runtime.socket.test.ts +0 -104
  791. package/src/terminal/tui/runtime.test.ts +0 -215
  792. package/src/terminal/tui/runtime.ts +0 -388
  793. package/src/terminal/tui/sessionUi.ts +0 -24
  794. package/src/terminal/tui/settings.test.ts +0 -150
  795. package/src/terminal/tui/settings.ts +0 -188
  796. package/src/terminal/tui/status.test.ts +0 -70
  797. package/src/terminal/tui/status.ts +0 -109
  798. package/src/terminal/tui/theme.ts +0 -174
  799. package/src/terminal/tui/tools.test.ts +0 -145
  800. package/src/terminal/tui/tools.ts +0 -142
  801. package/src/terminal/tui/transcript.test.ts +0 -25
  802. package/src/terminal/tui/transcript.ts +0 -124
  803. package/src/terminal/tui/ui.test.ts +0 -313
  804. package/src/terminal/tui/ui.ts +0 -166
  805. package/src/terminal/tui/welcome.ts +0 -102
  806. package/src/tools/askUser.test.ts +0 -69
  807. package/src/tools/askUser.ts +0 -59
  808. package/src/tools/definitions.ts +0 -187
  809. package/src/tools/maintenance.ts +0 -24
  810. package/src/tools/memoryTools.ts +0 -22
  811. package/src/tools/pluginPropose.ts +0 -41
  812. package/src/tools/registryWrite.test.ts +0 -101
  813. package/src/tools/registryWrite.ts +0 -182
  814. package/src/tools/spawnSubagent.ts +0 -92
  815. package/src/tools/types.ts +0 -39
  816. package/src/web/safeRequest.ts +0 -171
  817. package/src/web/text.ts +0 -53
  818. package/src/web/tools.ts +0 -134
  819. package/src/web/web.test.ts +0 -141
@@ -0,0 +1,483 @@
1
+ // Managed git worktrees (PROP-0016). A session can work in its own checkout of a repository so its
2
+ // edits never touch the person's main checkout: managed worktrees are disposable and pruned to the
3
+ // most recent few, permanent ones stay until a person removes them, and nothing with work in it is
4
+ // removed without a snapshot it can be restored from.
5
+ import { createHash, randomBytes } from 'node:crypto';
6
+ import { existsSync, mkdirSync, realpathSync, rmSync } from 'node:fs';
7
+ import { tmpdir } from 'node:os';
8
+ import { basename, dirname, isAbsolute, join, resolve } from 'node:path';
9
+ import { HarnessError, invalid, notFound } from "../core/errors.js";
10
+ import { newId, now, readJsonOr, writeJson } from "../core/fs.js";
11
+ import { copyFiles, ignoredFiles, includedFiles, untrackedFiles } from "./copy.js";
12
+ import { git, gitText, nulList } from "./git.js";
13
+ import { runSetup, SetupTrust } from "./setup.js";
14
+ const NAME = /^[a-z0-9][a-z0-9-]{0,62}$/;
15
+ const SNAPSHOT_REF = 'refs/xharness/snapshots';
16
+ const IDENTITY = { GIT_AUTHOR_NAME: 'Xingular Harness', GIT_AUTHOR_EMAIL: 'harness@localhost', GIT_COMMITTER_NAME: 'Xingular Harness', GIT_COMMITTER_EMAIL: 'harness@localhost' };
17
+ function alive(pid) {
18
+ try {
19
+ process.kill(pid, 0);
20
+ return true;
21
+ }
22
+ catch (error) {
23
+ return error.code === 'EPERM';
24
+ }
25
+ }
26
+ function real(path) {
27
+ try {
28
+ return realpathSync(path);
29
+ }
30
+ catch {
31
+ return resolve(path);
32
+ }
33
+ }
34
+ function slug(text) {
35
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40) || 'repo';
36
+ }
37
+ /** Paths in `git status --porcelain=v1 -z` output; a rename's original path is not counted. */
38
+ function statusPaths(output) {
39
+ const items = nulList(output);
40
+ const paths = [];
41
+ for (let index = 0; index < items.length; index += 1) {
42
+ const entry = items[index];
43
+ paths.push(entry.slice(3));
44
+ if (entry[0] === 'R' || entry[0] === 'C')
45
+ index += 1;
46
+ }
47
+ return paths;
48
+ }
49
+ export class Worktrees {
50
+ root;
51
+ branchPrefix;
52
+ keep;
53
+ registryFile;
54
+ trust;
55
+ leaseCounts = new Map();
56
+ chain = Promise.resolve();
57
+ constructor(stateDir, options = {}) {
58
+ this.root = options.root ?? join(stateDir, 'worktrees');
59
+ this.branchPrefix = options.branchPrefix ?? 'wt/';
60
+ this.keep = options.keep ?? 15;
61
+ this.registryFile = join(stateDir, 'worktrees.json');
62
+ this.trust = new SetupTrust(join(stateDir, 'worktree-setup-trust.json'));
63
+ this.recover(true);
64
+ }
65
+ // ---- Registry -------------------------------------------------------------------------------
66
+ read() {
67
+ const registry = readJsonOr(this.registryFile, { version: 1, worktrees: [] });
68
+ return Array.isArray(registry.worktrees) ? registry : { version: 1, worktrees: [] };
69
+ }
70
+ write(registry) {
71
+ writeJson(this.registryFile, registry);
72
+ }
73
+ update(id, change) {
74
+ const registry = this.read();
75
+ const record = registry.worktrees.find((entry) => entry.id === id);
76
+ if (!record)
77
+ throw notFound(`Worktree ${id}`);
78
+ change(record);
79
+ this.write(registry);
80
+ return record;
81
+ }
82
+ /** Runs changes one at a time, so two requests never race on the registry or on git. */
83
+ serial(work) {
84
+ const next = this.chain.then(work, work);
85
+ this.chain = next.catch(() => undefined);
86
+ return next;
87
+ }
88
+ /** Releases leases whose process is gone. At start-up, this process's own leases are stale too. */
89
+ recover(startup = false) {
90
+ const registry = this.read();
91
+ const released = [];
92
+ for (const record of registry.worktrees) {
93
+ if (!record.lease)
94
+ continue;
95
+ if (alive(record.lease.pid) && !(startup && record.lease.pid === process.pid))
96
+ continue;
97
+ record.lease = null;
98
+ this.leaseCounts.delete(record.id);
99
+ released.push(record.id);
100
+ if (existsSync(record.path))
101
+ void git(record.path, ['worktree', 'unlock', record.path], { allowFail: true }).catch(() => undefined);
102
+ }
103
+ if (released.length)
104
+ this.write(registry);
105
+ return released;
106
+ }
107
+ get(id) {
108
+ const record = this.read().worktrees.find((entry) => entry.id === id);
109
+ if (!record)
110
+ throw notFound(`Worktree ${id}`);
111
+ return record;
112
+ }
113
+ active(id) {
114
+ const record = this.get(id);
115
+ if (record.removed)
116
+ throw new HarnessError('worktree_removed', `Worktree ${record.name} was removed.`, 'Restore it first.');
117
+ return record;
118
+ }
119
+ /** The folder for a registered worktree; unknown ids remain opaque to the caller. */
120
+ pathOf(id) {
121
+ const record = this.read().worktrees.find((entry) => entry.id === id);
122
+ if (!record)
123
+ return null;
124
+ if (record.removed)
125
+ throw new HarnessError('worktree_removed', `Worktree ${record.name} was removed.`, 'Restore it first.');
126
+ if (!existsSync(record.path))
127
+ throw new HarnessError('worktree_missing', `The folder of worktree ${record.name} is gone.`, 'Remove it, or restore it.');
128
+ return record.path;
129
+ }
130
+ /** The top folder of the repository a folder belongs to (the main checkout, for a linked worktree). */
131
+ async repositoryOf(folder) {
132
+ const known = this.read().worktrees.find((entry) => !entry.removed && real(entry.path) === real(folder));
133
+ if (known)
134
+ return known.repoRoot;
135
+ const top = await git(folder, ['rev-parse', '--show-toplevel'], { allowFail: true });
136
+ if (top.code !== 0)
137
+ throw new HarnessError('not_a_repository', `${folder} is not inside a git repository.`, 'Worktrees need a git repository with at least one commit.');
138
+ const gitDir = await gitText(folder, ['rev-parse', '--absolute-git-dir']);
139
+ const common = resolve(top.stdout.trim(), await gitText(folder, ['rev-parse', '--git-common-dir']));
140
+ if (real(gitDir) === real(common))
141
+ return real(top.stdout.trim());
142
+ const main = (await gitText(folder, ['worktree', 'list', '--porcelain'])).split('\n').find((line) => line.startsWith('worktree '));
143
+ return real(main ? main.slice('worktree '.length) : top.stdout.trim());
144
+ }
145
+ async list(repo) {
146
+ const root = repo ? await this.repositoryOf(repo) : null;
147
+ return this.read().worktrees.filter((record) => !record.removed && (!root || record.repoRoot === root));
148
+ }
149
+ /** Worktrees removed with a snapshot, which `restore` can bring back. */
150
+ removed(repo) {
151
+ return this.read().worktrees.filter((record) => record.removed && (!repo || record.repoRoot === real(repo)));
152
+ }
153
+ async status(id) {
154
+ const record = this.get(id);
155
+ if (record.removed || !existsSync(record.path))
156
+ return { record, exists: false, head: null, changes: 0, ahead: 0 };
157
+ const head = (await git(record.path, ['rev-parse', 'HEAD'], { allowFail: true })).stdout.trim() || null;
158
+ const changes = statusPaths((await git(record.path, ['status', '--porcelain=v1', '-z', '--untracked-files=all'])).stdout).length;
159
+ const ahead = head ? Number((await git(record.path, ['rev-list', '--count', `${record.baseCommit}..HEAD`], { allowFail: true })).stdout.trim() || 0) : 0;
160
+ return { record, exists: true, head, changes, ahead };
161
+ }
162
+ // ---- Create and adopt -----------------------------------------------------------------------
163
+ repoKey(repoRoot) {
164
+ return `${slug(basename(repoRoot))}-${createHash('sha256').update(repoRoot).digest('hex').slice(0, 8)}`;
165
+ }
166
+ uniqueName(repoRoot, wanted) {
167
+ const taken = new Set(this.read().worktrees.filter((record) => record.repoRoot === repoRoot && !record.removed).map((record) => record.name));
168
+ const folder = join(this.root, this.repoKey(repoRoot));
169
+ if (wanted !== undefined) {
170
+ if (!NAME.test(wanted))
171
+ throw invalid('A worktree name uses lowercase letters, digits and dashes (at most 63).');
172
+ if (taken.has(wanted) || existsSync(join(folder, wanted)))
173
+ throw new HarnessError('worktree_exists', `A worktree named ${wanted} already exists.`);
174
+ return wanted;
175
+ }
176
+ for (;;) {
177
+ const name = `wt-${randomBytes(3).toString('hex')}`;
178
+ if (!taken.has(name) && !existsSync(join(folder, name)))
179
+ return name;
180
+ }
181
+ }
182
+ async branchName(repoRoot, name) {
183
+ const full = `${this.branchPrefix}${name}`;
184
+ const check = await git(repoRoot, ['check-ref-format', '--branch', full], { allowFail: true });
185
+ if (check.code !== 0)
186
+ throw invalid(`${full} is not a valid branch name.`);
187
+ if ((await git(repoRoot, ['rev-parse', '--verify', '-q', `refs/heads/${full}`], { allowFail: true })).code === 0)
188
+ throw new HarnessError('branch_exists', `Branch ${full} already exists.`);
189
+ return full;
190
+ }
191
+ create(input) {
192
+ return this.serial(async () => {
193
+ if (!input?.repo)
194
+ throw invalid('A repository folder is required.');
195
+ const repoRoot = await this.repositoryOf(input.repo);
196
+ if ((await git(repoRoot, ['rev-parse', '--verify', '-q', 'HEAD^{commit}'], { allowFail: true })).code !== 0) {
197
+ throw new HarnessError('repository_empty', 'This repository has no commit yet, so a worktree cannot be made from it.');
198
+ }
199
+ const name = this.uniqueName(repoRoot, input.name);
200
+ const baseRef = input.baseRef || 'HEAD';
201
+ const baseCommit = (await git(repoRoot, ['rev-parse', '--verify', '-q', `${baseRef}^{commit}`], { allowFail: true })).stdout.trim();
202
+ if (!baseCommit)
203
+ throw invalid(`${baseRef} does not name a commit.`);
204
+ const branch = input.branch ? await this.branchName(repoRoot, input.branch) : null;
205
+ const path = join(this.root, this.repoKey(repoRoot), name);
206
+ mkdirSync(dirname(path), { recursive: true });
207
+ await git(repoRoot, ['worktree', 'add', ...(branch ? ['-b', branch] : ['--detach']), path, baseCommit]);
208
+ const at = now();
209
+ const record = {
210
+ id: newId(), repoRoot, path, name, branch, baseRef, baseCommit, kind: input.kind ?? 'managed', origin: 'created',
211
+ createdAt: at, lastUsedAt: at, lease: null, removed: null
212
+ };
213
+ const registry = this.read();
214
+ registry.worktrees.push(record);
215
+ this.write(registry);
216
+ let patched = false;
217
+ let carried = { copied: [], skipped: [] };
218
+ if (input.carryChanges ?? baseRef === 'HEAD') {
219
+ const patch = (await git(repoRoot, ['diff', '--binary', 'HEAD'])).stdout;
220
+ if (patch.trim())
221
+ patched = (await git(path, ['apply', '--binary', '--whitespace=nowarn'], { input: patch, allowFail: true })).code === 0;
222
+ carried = copyFiles(repoRoot, path, await untrackedFiles(repoRoot));
223
+ }
224
+ const included = copyFiles(repoRoot, path, await includedFiles(repoRoot));
225
+ const setup = input.setup === false
226
+ ? { state: 'none', hash: null, log: null }
227
+ : await runSetup({ checkout: path, source: repoRoot, name, repoRoot, logFile: join(this.root, 'logs', `${record.id}.setup.log`), trust: this.trust });
228
+ return { worktree: record, carried: { ...carried, patched }, included, setup };
229
+ });
230
+ }
231
+ adopt(path) {
232
+ return this.serial(async () => {
233
+ if (!path || !isAbsolute(path))
234
+ throw invalid('An absolute worktree folder is required.');
235
+ const folder = real(path);
236
+ const known = this.read().worktrees.find((record) => !record.removed && real(record.path) === folder);
237
+ if (known)
238
+ return known;
239
+ const top = await git(folder, ['rev-parse', '--show-toplevel'], { allowFail: true });
240
+ if (top.code !== 0 || real(top.stdout.trim()) !== folder)
241
+ throw new HarnessError('not_a_worktree', `${path} is not the top folder of a git worktree.`);
242
+ const repoRoot = await this.repositoryOf(folder);
243
+ if (repoRoot === folder)
244
+ throw new HarnessError('not_a_worktree', `${path} is a repository's main checkout, not a linked worktree.`);
245
+ const branch = (await git(folder, ['symbolic-ref', '-q', '--short', 'HEAD'], { allowFail: true })).stdout.trim() || null;
246
+ const head = await gitText(folder, ['rev-parse', 'HEAD']);
247
+ const taken = new Set(this.read().worktrees.filter((record) => record.repoRoot === repoRoot && !record.removed).map((record) => record.name));
248
+ let name = slug(basename(folder)).slice(0, 56) || 'adopted';
249
+ if (!/^[a-z0-9]/.test(name))
250
+ name = `w-${name}`;
251
+ for (let suffix = 2; taken.has(name); suffix += 1)
252
+ name = `${name.replace(/-\d+$/, '')}-${suffix}`;
253
+ const at = now();
254
+ const record = {
255
+ id: newId(), repoRoot, path: folder, name, branch, baseRef: 'HEAD', baseCommit: head, kind: 'permanent', origin: 'adopted',
256
+ createdAt: at, lastUsedAt: at, lease: null, removed: null
257
+ };
258
+ const registry = this.read();
259
+ registry.worktrees.push(record);
260
+ this.write(registry);
261
+ return record;
262
+ });
263
+ }
264
+ // ---- Use ------------------------------------------------------------------------------------
265
+ /** A session starts using a worktree. Another live session's lease refuses it. */
266
+ acquire(id, holder) {
267
+ return this.serial(async () => {
268
+ const record = this.active(id);
269
+ if (!existsSync(record.path))
270
+ throw new HarnessError('worktree_missing', `The folder of worktree ${record.name} is gone.`, 'Remove it, or restore it.');
271
+ if (record.lease && record.lease.holder !== holder && alive(record.lease.pid)) {
272
+ throw new HarnessError('worktree_in_use', `Worktree ${record.name} is in use by another session.`);
273
+ }
274
+ const sameLiveLease = record.lease?.holder === holder && alive(record.lease.pid);
275
+ const previousCount = sameLiveLease ? this.leaseCounts.get(id) ?? 1 : 0;
276
+ const updated = this.update(id, (entry) => {
277
+ entry.lease = { holder, pid: process.pid, at: now() };
278
+ entry.lastUsedAt = now();
279
+ });
280
+ this.leaseCounts.set(id, previousCount + 1);
281
+ try {
282
+ await git(record.path, ['worktree', 'lock', '--reason', 'in use by a Xingular Harness session', record.path], { allowFail: true });
283
+ }
284
+ catch (error) {
285
+ if (previousCount)
286
+ this.leaseCounts.set(id, previousCount);
287
+ else {
288
+ this.leaseCounts.delete(id);
289
+ this.update(id, (entry) => { entry.lease = null; });
290
+ }
291
+ throw error;
292
+ }
293
+ return updated;
294
+ });
295
+ }
296
+ release(id, holder) {
297
+ return this.serial(async () => {
298
+ const record = this.read().worktrees.find((entry) => entry.id === id);
299
+ if (!record?.lease || record.lease.holder !== holder)
300
+ return;
301
+ const count = this.leaseCounts.get(id) ?? 1;
302
+ if (count > 1) {
303
+ this.leaseCounts.set(id, count - 1);
304
+ return;
305
+ }
306
+ this.leaseCounts.delete(id);
307
+ this.update(id, (entry) => { entry.lease = null; });
308
+ if (existsSync(record.path))
309
+ await git(record.path, ['worktree', 'unlock', record.path], { allowFail: true });
310
+ });
311
+ }
312
+ branch(id, name) {
313
+ return this.serial(async () => {
314
+ const record = this.active(id);
315
+ if (record.branch)
316
+ throw new HarnessError('branch_exists', `Worktree ${record.name} is already on branch ${record.branch}.`);
317
+ const full = await this.branchName(record.repoRoot, name);
318
+ await git(record.path, ['switch', '-c', full]);
319
+ return this.update(id, (entry) => { entry.branch = full; });
320
+ });
321
+ }
322
+ // ---- Remove, restore, prune -----------------------------------------------------------------
323
+ async reachable(checkout, commit) {
324
+ const refs = await git(checkout, ['for-each-ref', '--count=1', `--contains=${commit}`, 'refs/heads', 'refs/tags', 'refs/remotes'], { allowFail: true });
325
+ return refs.code === 0 && refs.stdout.trim().length > 0;
326
+ }
327
+ /** Records the worktree's commits and working changes under a snapshot ref. */
328
+ async snapshot(record, ignored) {
329
+ const index = join(tmpdir(), `xharness-index-${record.id}-${randomBytes(4).toString('hex')}`);
330
+ const env = { ...IDENTITY, GIT_INDEX_FILE: index };
331
+ try {
332
+ await git(record.path, ['read-tree', 'HEAD'], { env });
333
+ await git(record.path, ['add', '-A'], { env });
334
+ if (ignored.length) {
335
+ const pathspecs = Buffer.from(ignored.map((path) => `:(literal)${path}\0`).join(''));
336
+ await git(record.path, ['add', '--force', '--pathspec-from-file=-', '--pathspec-file-nul'], { env, input: pathspecs });
337
+ }
338
+ const tree = await gitText(record.path, ['write-tree'], { env });
339
+ const commit = await gitText(record.path, ['commit-tree', tree, '-p', 'HEAD', '-m', `Xingular Harness snapshot of worktree ${record.name}`], { env });
340
+ const ref = `${SNAPSHOT_REF}/${record.id}`;
341
+ await git(record.path, ['update-ref', ref, commit]);
342
+ return ref;
343
+ }
344
+ finally {
345
+ rmSync(index, { force: true });
346
+ }
347
+ }
348
+ remove(id, options = {}) {
349
+ return this.serial(() => this.removeNow(id, options.force === true));
350
+ }
351
+ async removeNow(id, force) {
352
+ const record = this.active(id);
353
+ // Several sessions share one process in an embedding host, so a lease of a live process always counts.
354
+ if (record.lease && alive(record.lease.pid)) {
355
+ throw new HarnessError('worktree_in_use', `Worktree ${record.name} is in use by a session.`, 'End that session first.');
356
+ }
357
+ let head = record.baseCommit;
358
+ let snapshot = null;
359
+ if (existsSync(record.path)) {
360
+ const ignored = await ignoredFiles(record.path);
361
+ const status = await this.status(id);
362
+ head = status.head ?? head;
363
+ const work = status.changes > 0 || ignored.length > 0 || !(await this.reachable(record.path, head));
364
+ if (work && !force) {
365
+ throw new HarnessError('worktree_has_work', `Worktree ${record.name} has ${status.changes} changed path(s), ${ignored.length} ignored file(s), or commits on no branch.`, 'Remove it with force to keep a snapshot you can restore.');
366
+ }
367
+ if (work)
368
+ snapshot = await this.snapshot(record, ignored);
369
+ await git(record.repoRoot, ['worktree', 'unlock', record.path], { allowFail: true });
370
+ const removed = await git(record.repoRoot, ['worktree', 'remove', '--force', record.path], { allowFail: true });
371
+ if (removed.code !== 0 && existsSync(record.path) && record.path.startsWith(this.root + '/'))
372
+ rmSync(record.path, { recursive: true, force: true });
373
+ }
374
+ await git(record.repoRoot, ['worktree', 'prune'], { allowFail: true });
375
+ const worktree = this.update(id, (entry) => {
376
+ entry.lease = null;
377
+ entry.removed = { at: now(), head, snapshot };
378
+ });
379
+ this.leaseCounts.delete(id);
380
+ return { worktree, snapshot };
381
+ }
382
+ restore(id) {
383
+ return this.serial(async () => {
384
+ const record = this.get(id);
385
+ if (!record.removed)
386
+ throw new HarnessError('worktree_active', `Worktree ${record.name} was not removed.`);
387
+ if (existsSync(record.path))
388
+ throw new HarnessError('worktree_exists', `${record.path} already exists.`);
389
+ const { snapshot, head } = record.removed;
390
+ const start = snapshot ? await gitText(record.repoRoot, ['rev-parse', `${snapshot}^`]) : head;
391
+ const onBranch = record.branch && (await git(record.repoRoot, ['rev-parse', '--verify', '-q', `refs/heads/${record.branch}`], { allowFail: true })).stdout.trim() === start;
392
+ mkdirSync(dirname(record.path), { recursive: true });
393
+ await git(record.repoRoot, ['worktree', 'add', ...(onBranch ? [record.path, record.branch] : ['--detach', record.path, start])]);
394
+ if (snapshot) {
395
+ await git(record.path, ['read-tree', '-u', '--reset', snapshot]);
396
+ await git(record.path, ['reset', '-q']);
397
+ }
398
+ return this.update(id, (entry) => {
399
+ entry.removed = null;
400
+ entry.branch = onBranch ? entry.branch : null;
401
+ entry.lastUsedAt = now();
402
+ });
403
+ });
404
+ }
405
+ /** Keeps the most recently used managed worktrees of each repository and removes the rest, with snapshots. */
406
+ prune(options = {}) {
407
+ return this.serial(async () => {
408
+ const keep = Math.max(0, options.keep ?? this.keep);
409
+ const root = options.repo ? await this.repositoryOf(options.repo) : null;
410
+ const groups = new Map();
411
+ for (const record of this.read().worktrees) {
412
+ if (record.removed || record.kind !== 'managed' || (root && record.repoRoot !== root))
413
+ continue;
414
+ groups.set(record.repoRoot, [...(groups.get(record.repoRoot) ?? []), record]);
415
+ }
416
+ const removed = [];
417
+ const failed = [];
418
+ for (const records of groups.values()) {
419
+ const older = records.sort((left, right) => right.lastUsedAt.localeCompare(left.lastUsedAt)).slice(keep);
420
+ for (const record of older) {
421
+ if (record.lease && alive(record.lease.pid))
422
+ continue;
423
+ try {
424
+ removed.push(await this.removeNow(record.id, true));
425
+ }
426
+ catch (error) {
427
+ failed.push({ id: record.id, error: error instanceof Error ? error.message : String(error) });
428
+ }
429
+ }
430
+ }
431
+ return { removed, failed };
432
+ });
433
+ }
434
+ // ---- Handoff --------------------------------------------------------------------------------
435
+ /**
436
+ * Moves work between the worktree and the main checkout. `toSource` brings the worktree's changes
437
+ * since it started (commits and working changes) to the main checkout; `toWorktree` brings the
438
+ * main checkout's uncommitted changes to the worktree. The target must have no tracked changes,
439
+ * and nothing changes when the patch does not apply. With `move` (the default), what was handed
440
+ * off is stashed away from the origin, where `git stash` can bring it back.
441
+ */
442
+ handoff(id, direction, options = {}) {
443
+ return this.serial(async () => {
444
+ if (direction !== 'toSource' && direction !== 'toWorktree')
445
+ throw invalid('direction is toSource or toWorktree.');
446
+ const record = this.active(id);
447
+ if (!existsSync(record.path))
448
+ throw new HarnessError('worktree_missing', `The folder of worktree ${record.name} is gone.`);
449
+ const origin = direction === 'toSource' ? record.path : record.repoRoot;
450
+ const target = direction === 'toSource' ? record.repoRoot : record.path;
451
+ const dirty = (await gitText(target, ['status', '--porcelain', '--untracked-files=no'])).length > 0;
452
+ if (dirty)
453
+ throw new HarnessError('handoff_target_dirty', `The ${direction === 'toSource' ? 'main checkout' : 'worktree'} has uncommitted changes.`, 'Commit or stash them, then hand off again.');
454
+ const patch = (await git(origin, ['diff', '--binary', direction === 'toSource' ? record.baseCommit : 'HEAD'])).stdout;
455
+ const untracked = await untrackedFiles(origin);
456
+ const collisions = untracked.filter((path) => existsSync(join(target, path)));
457
+ if (collisions.length)
458
+ throw new HarnessError('handoff_conflict', `${collisions.length} untracked file(s) already exist in the target, for example ${collisions[0]}.`);
459
+ if (patch.trim()) {
460
+ const check = await git(target, ['apply', '--check', '--binary', '--whitespace=nowarn'], { input: patch, allowFail: true });
461
+ if (check.code !== 0)
462
+ throw new HarnessError('handoff_conflict', `The changes do not apply cleanly: ${check.stderr.trim()}`, 'Bring the two checkouts to the same commit, or commit and merge instead.');
463
+ await git(target, ['apply', '--binary', '--whitespace=nowarn'], { input: patch });
464
+ }
465
+ const copied = copyFiles(origin, target, untracked).copied;
466
+ let stash = null;
467
+ if (options.move !== false && (patch.trim() || untracked.length)) {
468
+ const before = (await git(origin, ['rev-parse', '-q', '--verify', 'refs/stash'], { allowFail: true })).stdout.trim();
469
+ await git(origin, ['stash', 'push', '--include-untracked', '-m', `Xingular Harness handoff of worktree ${record.name}`], { env: IDENTITY, allowFail: true });
470
+ const after = (await git(origin, ['rev-parse', '-q', '--verify', 'refs/stash'], { allowFail: true })).stdout.trim();
471
+ stash = after && after !== before ? after : null;
472
+ }
473
+ this.update(id, (entry) => { entry.lastUsedAt = now(); });
474
+ return { direction, patched: patch.trim().length > 0, copied, stash };
475
+ });
476
+ }
477
+ // ---- Setup trust ----------------------------------------------------------------------------
478
+ async trustSetup(repo, hash) {
479
+ if (!/^[0-9a-f]{64}$/.test(hash))
480
+ throw invalid('A setup script hash is 64 hexadecimal characters.');
481
+ this.trust.trust(await this.repositoryOf(repo), hash);
482
+ }
483
+ }
@@ -0,0 +1,23 @@
1
+ import type { SetupReport } from "./types.js";
2
+ export declare const SETUP_SCRIPT = ".xharness/worktree-setup";
3
+ export declare function scriptHash(text: string | Buffer): string;
4
+ export declare class SetupTrust {
5
+ private readonly file;
6
+ constructor(file: string);
7
+ private read;
8
+ trusted(repoRoot: string, hash: string): boolean;
9
+ trust(repoRoot: string, hash: string): void;
10
+ }
11
+ /** The setup script a checkout carries, with its hash, or null. */
12
+ export declare function setupScript(checkout: string): {
13
+ path: string;
14
+ hash: string;
15
+ } | null;
16
+ export declare function runSetup(input: {
17
+ checkout: string;
18
+ source: string;
19
+ name: string;
20
+ repoRoot: string;
21
+ logFile: string;
22
+ trust: SetupTrust;
23
+ }): Promise<SetupReport>;
@@ -0,0 +1,65 @@
1
+ // A repository's setup script runs in each new worktree (installing dependencies, say), but only
2
+ // once a person trusted its exact text. The hash is the trust; a changed script asks again.
3
+ import { spawn } from 'node:child_process';
4
+ import { createHash } from 'node:crypto';
5
+ import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, statSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ import { readJsonOr, writeJson } from "../core/fs.js";
8
+ export const SETUP_SCRIPT = '.xharness/worktree-setup';
9
+ const TIMEOUT_MS = 10 * 60 * 1000;
10
+ export function scriptHash(text) {
11
+ return createHash('sha256').update(text).digest('hex');
12
+ }
13
+ export class SetupTrust {
14
+ file;
15
+ constructor(file) {
16
+ this.file = file;
17
+ }
18
+ read() {
19
+ return readJsonOr(this.file, {});
20
+ }
21
+ trusted(repoRoot, hash) {
22
+ return this.read()[repoRoot]?.includes(hash) ?? false;
23
+ }
24
+ trust(repoRoot, hash) {
25
+ const all = this.read();
26
+ all[repoRoot] = [...new Set([...(all[repoRoot] ?? []), hash])];
27
+ writeJson(this.file, all);
28
+ chmodSync(this.file, 0o600);
29
+ }
30
+ }
31
+ /** The setup script a checkout carries, with its hash, or null. */
32
+ export function setupScript(checkout) {
33
+ const path = join(checkout, SETUP_SCRIPT);
34
+ if (!existsSync(path) || !statSync(path).isFile())
35
+ return null;
36
+ return { path, hash: scriptHash(readFileSync(path)) };
37
+ }
38
+ export function runSetup(input) {
39
+ const script = setupScript(input.checkout);
40
+ if (!script)
41
+ return Promise.resolve({ state: 'none', hash: null, log: null });
42
+ if (!input.trust.trusted(input.repoRoot, script.hash))
43
+ return Promise.resolve({ state: 'untrusted', hash: script.hash, log: null });
44
+ mkdirSync(dirname(input.logFile), { recursive: true });
45
+ const log = openSync(input.logFile, 'w');
46
+ return new Promise((resolve) => {
47
+ const child = spawn('/bin/sh', [script.path], {
48
+ cwd: input.checkout,
49
+ env: { ...process.env, HARNESS_WORKTREE_PATH: input.checkout, HARNESS_WORKTREE_SOURCE: input.source, HARNESS_WORKTREE_NAME: input.name },
50
+ stdio: ['ignore', log, log]
51
+ });
52
+ const timer = setTimeout(() => child.kill('SIGTERM'), TIMEOUT_MS);
53
+ let settled = false;
54
+ const finish = (exitCode) => {
55
+ if (settled)
56
+ return;
57
+ settled = true;
58
+ clearTimeout(timer);
59
+ closeSync(log);
60
+ resolve({ state: exitCode === 0 ? 'ran' : 'failed', hash: script.hash, log: input.logFile, exitCode });
61
+ };
62
+ child.once('error', () => finish(null));
63
+ child.once('close', (code) => finish(code));
64
+ });
65
+ }
@@ -0,0 +1,91 @@
1
+ /** A managed worktree is disposable and pruned; a permanent one is kept until a person removes it. */
2
+ export type WorktreeKind = 'managed' | 'permanent';
3
+ export interface WorktreeLease {
4
+ /** Who uses the worktree: a session id. */
5
+ holder: string;
6
+ /** The process that holds the lease; a lease whose process is gone is released on recovery. */
7
+ pid: number;
8
+ at: string;
9
+ }
10
+ export interface WorktreeRecord {
11
+ id: string;
12
+ /** The source checkout's top folder. */
13
+ repoRoot: string;
14
+ path: string;
15
+ name: string;
16
+ /** Null while the worktree is on a detached HEAD. */
17
+ branch: string | null;
18
+ baseRef: string;
19
+ baseCommit: string;
20
+ kind: WorktreeKind;
21
+ origin: 'created' | 'adopted';
22
+ createdAt: string;
23
+ lastUsedAt: string;
24
+ lease: WorktreeLease | null;
25
+ /** Set once the checkout is removed; the record stays so the worktree can be restored. */
26
+ removed: {
27
+ at: string;
28
+ head: string;
29
+ snapshot: string | null;
30
+ } | null;
31
+ }
32
+ export interface WorktreeStatus {
33
+ record: WorktreeRecord;
34
+ exists: boolean;
35
+ head: string | null;
36
+ /** Changed, added or untracked paths in the working tree. */
37
+ changes: number;
38
+ /** Commits made since the worktree started. */
39
+ ahead: number;
40
+ }
41
+ export interface CopyReport {
42
+ copied: string[];
43
+ skipped: {
44
+ path: string;
45
+ reason: 'exists' | 'symlink' | 'too_large' | 'over_total' | 'not_file';
46
+ }[];
47
+ }
48
+ export interface SetupReport {
49
+ state: 'none' | 'untrusted' | 'ran' | 'failed';
50
+ /** The script's content hash, to trust it with `setup.trust`. */
51
+ hash: string | null;
52
+ log: string | null;
53
+ exitCode?: number | null;
54
+ }
55
+ export interface CreateWorktreeInput {
56
+ /** Any folder inside the source repository. */
57
+ repo: string;
58
+ name?: string;
59
+ /** What the worktree starts from. Defaults to the source checkout's HEAD. */
60
+ baseRef?: string;
61
+ kind?: WorktreeKind;
62
+ /** A branch to create instead of a detached HEAD. The configured prefix is added. */
63
+ branch?: string;
64
+ /** Bring the source checkout's uncommitted changes along (default when starting from HEAD). */
65
+ carryChanges?: boolean;
66
+ /** Run the repository's trusted setup script (default yes). */
67
+ setup?: boolean;
68
+ }
69
+ export interface CreateWorktreeResult {
70
+ worktree: WorktreeRecord;
71
+ carried: CopyReport & {
72
+ patched: boolean;
73
+ };
74
+ included: CopyReport;
75
+ setup: SetupReport;
76
+ }
77
+ export interface HandoffResult {
78
+ direction: 'toSource' | 'toWorktree';
79
+ patched: boolean;
80
+ copied: string[];
81
+ /** The stash that holds what was moved away from the origin, when `move` was asked. */
82
+ stash: string | null;
83
+ }
84
+ export interface WorktreesOptions {
85
+ /** Where checkouts are made. Defaults to `<state dir>/worktrees`. */
86
+ root?: string;
87
+ /** Prefix of branches the harness creates. Defaults to `wt/`. */
88
+ branchPrefix?: string;
89
+ /** Managed worktrees kept per repository by `prune`. Defaults to 15. */
90
+ keep?: number;
91
+ }
@@ -0,0 +1 @@
1
+ export {};