@co0ontty/wand 4.106.0 → 4.106.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 (279) hide show
  1. package/README.md +2 -2
  2. package/dist/ai-text-runner.js +24 -14
  3. package/dist/build-info.d.ts +2 -0
  4. package/dist/build-info.js +18 -0
  5. package/dist/build-info.json +3 -3
  6. package/dist/cli.js +8 -2
  7. package/dist/daemon-maintenance-state.js +1 -1
  8. package/dist/daemon-maintenance-targets.d.ts +1 -0
  9. package/dist/daemon-maintenance-targets.js +25 -9
  10. package/dist/daemon-maintenance.d.ts +3 -0
  11. package/dist/daemon-maintenance.js +60 -13
  12. package/dist/employee-im-types.d.ts +1 -1
  13. package/dist/employee-input-scheduling.d.ts +4 -0
  14. package/dist/employee-knowledge-cli.js +5 -5
  15. package/dist/employee-knowledge.d.ts +3 -1
  16. package/dist/employee-knowledge.js +24 -8
  17. package/dist/git-quick-commit.d.ts +2 -0
  18. package/dist/git-quick-commit.js +15 -2
  19. package/dist/git-worktree-batch.d.ts +26 -0
  20. package/dist/git-worktree-batch.js +139 -0
  21. package/dist/global-knowledge.d.ts +12 -0
  22. package/dist/global-knowledge.js +124 -0
  23. package/dist/iteration-log.d.ts +13 -5
  24. package/dist/iteration-log.js +120 -59
  25. package/dist/knowledge-types.d.ts +12 -1
  26. package/dist/knowledge-types.js +4 -0
  27. package/dist/middleware/api-scope.js +1 -0
  28. package/dist/model-groups.js +6 -3
  29. package/dist/models/parsers/opencode.js +31 -1
  30. package/dist/models.js +15 -14
  31. package/dist/npm-update-utils.d.ts +5 -2
  32. package/dist/npm-update-utils.js +34 -4
  33. package/dist/opencode-cli.d.ts +6 -0
  34. package/dist/opencode-cli.js +51 -0
  35. package/dist/opencode-system-fallback.d.ts +1 -0
  36. package/dist/opencode-system-fallback.js +16 -4
  37. package/dist/pi-native-event-bridge.js +55 -3
  38. package/dist/pi-native-input.d.ts +22 -0
  39. package/dist/pi-native-input.js +77 -0
  40. package/dist/pi-tmux-host.d.ts +14 -5
  41. package/dist/pi-tmux-host.js +68 -17
  42. package/dist/process-manager.js +17 -3
  43. package/dist/pty-tmux-backend.d.ts +27 -2
  44. package/dist/pty-tmux-backend.js +471 -70
  45. package/dist/pty-tmux-log.d.ts +1 -1
  46. package/dist/pty-tmux-log.js +23 -2
  47. package/dist/retention-protection.d.ts +1 -1
  48. package/dist/retention-protection.js +3 -2
  49. package/dist/retention.d.ts +5 -0
  50. package/dist/retention.js +11 -0
  51. package/dist/server-knowledge-routes.js +2 -2
  52. package/dist/server-session-input-routes.js +38 -19
  53. package/dist/server-session-lifecycle-routes.js +14 -1
  54. package/dist/server-session-worktree-routes.js +105 -12
  55. package/dist/server-task-routes.js +41 -12
  56. package/dist/server-workspace-routes.js +77 -9
  57. package/dist/server.js +67 -35
  58. package/dist/session-registry.d.ts +17 -3
  59. package/dist/session-registry.js +66 -13
  60. package/dist/session-service.js +1 -1
  61. package/dist/storage/internal.d.ts +4 -3
  62. package/dist/storage/internal.js +3 -3
  63. package/dist/storage/knowledge-repository.d.ts +5 -0
  64. package/dist/storage/knowledge-repository.js +75 -16
  65. package/dist/storage/mappers.d.ts +1 -0
  66. package/dist/storage/mappers.js +6 -1
  67. package/dist/storage/migrations.js +60 -0
  68. package/dist/storage/session-input-repository.d.ts +19 -0
  69. package/dist/storage/session-input-repository.js +35 -0
  70. package/dist/storage/task-workflow-repository.d.ts +29 -0
  71. package/dist/storage/task-workflow-repository.js +110 -0
  72. package/dist/storage/tasks-repository.d.ts +6 -1
  73. package/dist/storage/tasks-repository.js +94 -34
  74. package/dist/storage/workspaces-repository.d.ts +7 -0
  75. package/dist/storage/workspaces-repository.js +28 -2
  76. package/dist/storage-cleanup.d.ts +7 -2
  77. package/dist/storage-cleanup.js +16 -0
  78. package/dist/storage-schema.js +2 -0
  79. package/dist/storage.d.ts +5 -1
  80. package/dist/storage.js +12 -0
  81. package/dist/structured-exec-host.d.ts +4 -0
  82. package/dist/structured-exec-pump.d.ts +1 -0
  83. package/dist/structured-exec-pump.js +18 -11
  84. package/dist/structured-opencode-adapter.d.ts +2 -1
  85. package/dist/structured-opencode-adapter.js +32 -8
  86. package/dist/structured-pi-adapter.js +13 -2
  87. package/dist/structured-runner.d.ts +6 -0
  88. package/dist/structured-session-manager-replay.d.ts +2 -0
  89. package/dist/structured-session-manager-replay.js +27 -0
  90. package/dist/structured-session-manager.d.ts +32 -21
  91. package/dist/structured-session-manager.js +395 -118
  92. package/dist/structured-tmux-host.d.ts +23 -2
  93. package/dist/structured-tmux-host.js +143 -20
  94. package/dist/task-actions.js +5 -3
  95. package/dist/task-archive-policy.js +2 -1
  96. package/dist/task-comment-dispatch.d.ts +2 -1
  97. package/dist/task-comment-dispatch.js +19 -6
  98. package/dist/task-execution-queue.d.ts +2 -0
  99. package/dist/task-execution-queue.js +10 -10
  100. package/dist/task-hierarchy.js +1 -1
  101. package/dist/task-read-model.d.ts +1 -1
  102. package/dist/task-read-model.js +2 -1
  103. package/dist/task-types.d.ts +34 -3
  104. package/dist/task-types.js +21 -5
  105. package/dist/task-workflow-cli.d.ts +2 -0
  106. package/dist/task-workflow-cli.js +29 -0
  107. package/dist/task-workflow-runner.d.ts +4 -0
  108. package/dist/task-workflow-runner.js +36 -0
  109. package/dist/task-workflow.d.ts +13 -0
  110. package/dist/task-workflow.js +48 -0
  111. package/dist/terminal-daemon-server.js +12 -4
  112. package/dist/tmux-policy.d.ts +9 -0
  113. package/dist/tmux-policy.js +46 -0
  114. package/dist/tmux-terminal-host.js +5 -2
  115. package/dist/tui/commands.js +2 -1
  116. package/dist/types.d.ts +5 -0
  117. package/dist/wand-task-sync.js +5 -0
  118. package/dist/web-ui/content/ai-teams.js +9 -9
  119. package/dist/web-ui/content/module-manifest.json +1 -1
  120. package/dist/web-ui/content/modules/{52574891ef08e29b → 014fa5c6f973badf}/host.js +3 -3
  121. package/dist/web-ui/content/modules/0818b1d31a11d006/employee-profile.js +1 -0
  122. package/dist/web-ui/content/modules/{31157ceb6d23b809 → 0a58d9ec273078e4}/chunk.js +3 -3
  123. package/dist/web-ui/content/modules/{bf3ee58e0da44822 → 0a979dcd165cd0cc}/chunk.js +1 -1
  124. package/dist/web-ui/content/modules/{5f298a8f43dd0589 → 0c143928e8f96abc}/chunk.js +1 -1
  125. package/dist/web-ui/content/modules/0e9e42a319f6b8fc/workspace-window.js +1 -0
  126. package/dist/web-ui/content/modules/{b713cad51ca4c512 → 0f0d1769b732c0bd}/chunk.js +1 -1
  127. package/dist/web-ui/content/modules/{4970319a83432ec7 → 1447886e6a1e74a4}/chunk.js +1 -1
  128. package/dist/web-ui/content/modules/151c734cbca31da5/host.js +1 -0
  129. package/dist/web-ui/content/modules/{e5174201f9d918fb → 16e4ab9c5263fcfd}/chunk.js +1 -1
  130. package/dist/web-ui/content/modules/17e752fb53952753/host.js +1 -0
  131. package/dist/web-ui/content/modules/{913187c92a98a1ac → 20ed1454fc09fa6f}/chunk.js +1 -1
  132. package/dist/web-ui/content/modules/255a3baf59d2b734/home.js +6 -0
  133. package/dist/web-ui/content/modules/{2f801e53dda62770 → 296dd81886c42b45}/chunk.js +1 -1
  134. package/dist/web-ui/content/modules/{8891ca8165435ca1 → 2a01f4e525c0725e}/chunk.js +1 -1
  135. package/dist/web-ui/content/modules/2ab4409c82b44fba/markdown.js +1 -0
  136. package/dist/web-ui/content/modules/2c955eced11610c2/chunk.js +1 -0
  137. package/dist/web-ui/content/modules/2d7ee4f9e2c0aca4/panel.js +1 -0
  138. package/dist/web-ui/content/modules/{3f8830f8ad28decc → 33ae550e4a295c85}/chunk.js +1 -1
  139. package/dist/web-ui/content/modules/35f4aa4443696bd0/chunk.js +1 -0
  140. package/dist/web-ui/content/modules/388b37ffcce9d4ff/host.js +1 -0
  141. package/dist/web-ui/content/modules/39279604dcdac7c7/runtime.js +338 -0
  142. package/dist/web-ui/content/modules/{57c357d321db5df9 → 3a3cdff2a662b7d3}/chunk.js +1 -1
  143. package/dist/web-ui/content/modules/{d49f106c4d106057 → 3ab646be55514243}/chunk.js +1 -1
  144. package/dist/web-ui/content/modules/{16dab1297efd71a7 → 3ae88a5c5e1949d2}/chunk.js +1 -1
  145. package/dist/web-ui/content/modules/3e3b0e71d6ce80d8/chunk.js +1 -0
  146. package/dist/web-ui/content/modules/{ec33e17c00c1eb24 → 434aaaaf9604dc34}/chunk.js +1 -1
  147. package/dist/web-ui/content/modules/4385cd48771e1d4f/host.js +1 -0
  148. package/dist/web-ui/content/modules/{face3dbf117d63e3 → 4638129d60f549a0}/chunk.js +1 -1
  149. package/dist/web-ui/content/modules/47407209931b7011/host.js +13 -0
  150. package/dist/web-ui/content/modules/4829dd712d8b366b/chunk.js +1 -0
  151. package/dist/web-ui/content/modules/488d5b747bf374c8/chunk.js +1 -0
  152. package/dist/web-ui/content/modules/{ed7405f064944215 → 4ab085c195f7d76a}/sha256.js +1 -1
  153. package/dist/web-ui/content/modules/{f27a5d3c6c02a71c → 4c485bd44740fec7}/chunk.js +1 -1
  154. package/dist/web-ui/content/modules/{771439a41e737ee2 → 4ca0494308ab2bb3}/chunk.js +1 -1
  155. package/dist/web-ui/content/modules/4ec571218779ba3e/composer-surface-adapter.js +1 -0
  156. package/dist/web-ui/content/modules/{5933ce8965aa4004 → 5023bf0294c2e7cb}/chunk.js +1 -1
  157. package/dist/web-ui/content/modules/{e63582a3bce48f7d → 5456e3417600bf15}/chunk.js +1 -1
  158. package/dist/web-ui/content/modules/55c588b0f5b41a52/host-bridge.js +1 -0
  159. package/dist/web-ui/content/modules/{9d941d6ff39861b8 → 5c3c8237ba7d8460}/chunk.js +1 -1
  160. package/dist/web-ui/content/modules/624b858da9834757/host.js +1 -0
  161. package/dist/web-ui/content/modules/6290be936320d4b1/host.js +1 -0
  162. package/dist/web-ui/content/modules/66be408793048cc3/progress.js +1 -0
  163. package/dist/web-ui/content/modules/67a11176a563317b/chunk.js +1 -0
  164. package/dist/web-ui/content/modules/{e060508ecd50fa7e → 68ef6ec7d26d78cd}/chunk.js +1 -1
  165. package/dist/web-ui/content/modules/{41445c6589dba325 → 6ec3e41df31927d9}/host.js +2 -2
  166. package/dist/web-ui/content/modules/{97d7f267959fd385 → 6f10f369445bbcbe}/chunk.js +1 -1
  167. package/dist/web-ui/content/modules/{d47d75a78ae598e3 → 7295d9ff92d5e1e7}/chunk.js +1 -1
  168. package/dist/web-ui/content/modules/{f383d892fef73483 → 72cd613de1a5f69b}/chunk.js +1 -1
  169. package/dist/web-ui/content/modules/73aae1daafeea7e7/workspaces-panel.js +4 -0
  170. package/dist/web-ui/content/modules/{c2f09c8a472f5d83 → 73d2689f13b9a3e9}/dialog-modal.js +1 -1
  171. package/dist/web-ui/content/modules/{2f97ddba3842adaa → 75cf0c048e9b92ab}/chunk.js +1 -1
  172. package/dist/web-ui/content/modules/{4ba1e8c74bed7ef2 → 75dabda3b141296e}/chunk.js +1 -1
  173. package/dist/web-ui/content/modules/{f3cff7792ba39df8 → 76c10b58d5f92d02}/login-visual.js +1 -1
  174. package/dist/web-ui/content/modules/{b63e075f222a1266 → 783583a12f5010f8}/library-bridge.js +1 -1
  175. package/dist/web-ui/content/modules/7e13a8a4a981f2f1/group-editor.js +1 -0
  176. package/dist/web-ui/content/modules/{0d76e582a7a71b2f → 7e3034fea34c6dae}/chunk.js +1 -1
  177. package/dist/web-ui/content/modules/80bf3291f2577a68/host.js +1 -0
  178. package/dist/web-ui/content/modules/{cba6f13c0b2aec1c → 82c3e08f34a6b828}/chunk.js +1 -1
  179. package/dist/web-ui/content/modules/{dedd4a19bb70e327 → 83d1f4cf82c65f19}/page.js +3 -3
  180. package/dist/web-ui/content/modules/844f97958f25240c/shell-file-panel-drawer.js +1 -0
  181. package/dist/web-ui/content/modules/{62e0023451f428cf → 899cdc467044d418}/chunk.js +1 -1
  182. package/dist/web-ui/content/modules/{5083a5dbb5b155b7 → 8c7ca1fe72741c07}/chunk.js +1 -1
  183. package/dist/web-ui/content/modules/8dae4ca2261525e4/task-board-host.js +27 -0
  184. package/dist/web-ui/content/modules/92195c14c74929da/list-filter-panel.js +1 -0
  185. package/dist/web-ui/content/modules/{a61393bfa976d8d5 → 93793696af76bcbf}/chunk.js +1 -1
  186. package/dist/web-ui/content/modules/{db521a246e14e5e4 → 97cd6af3da5622b8}/chunk.js +4 -4
  187. package/dist/web-ui/content/modules/{8de8368570ab089d → 9d3179258249ec77}/chunk.js +1 -1
  188. package/dist/web-ui/content/modules/{579d486763d47c0d → a234c484078c0568}/chunk.js +1 -1
  189. package/dist/web-ui/content/modules/a4d215448a089a7d/host.js +1 -0
  190. package/dist/web-ui/content/modules/{c0a446100d969f3e → ae003f89901c5687}/chunk.js +1 -1
  191. package/dist/web-ui/content/modules/ae712bdd45b9917e/employee-card.js +1 -0
  192. package/dist/web-ui/content/modules/{a2caed0139df4b21 → b2a15293f7965d09}/chunk.js +1 -1
  193. package/dist/web-ui/content/modules/b4ee65e9998f0088/host.js +61 -0
  194. package/dist/web-ui/content/modules/{bd3daf04a8bf4422 → b666137d17f83be9}/chunk.js +1 -1
  195. package/dist/web-ui/content/modules/{831b6c7b43e800be → b66beb6c0185256b}/host.js +1 -1
  196. package/dist/web-ui/content/modules/{816eb9b3a000fb2c → bb03b17e877657de}/chunk.js +1 -1
  197. package/dist/web-ui/content/modules/{1eab7410d5586038 → bc343afc991db1a1}/chunk.js +1 -1
  198. package/dist/web-ui/content/modules/bca45976ff8fe2ac/host.js +69 -0
  199. package/dist/web-ui/content/modules/{d434edbb2f4672e5 → c2715dbfc9eaf510}/chunk.js +1 -1
  200. package/dist/web-ui/content/modules/{d6fffe2c2a3a738d → c30c220281f35d74}/toast-region.js +1 -1
  201. package/dist/web-ui/content/modules/c4cc46fa9b4adddc/dropdown-surface.js +1 -0
  202. package/dist/web-ui/content/modules/c6dd19ee3d3ffd59/brand-identity.js +1 -0
  203. package/dist/web-ui/content/modules/c7ea6a114e6ff8ae/host.js +1 -0
  204. package/dist/web-ui/content/modules/{a59734be368daa7e → c916d82c8acef9c8}/chunk.js +1 -1
  205. package/dist/web-ui/content/modules/{182929e188c1ab3a → cceaedda619a737a}/host.js +1 -1
  206. package/dist/web-ui/content/modules/cf67f52b076b9d2d/panel-host.js +1 -0
  207. package/dist/web-ui/content/modules/{9e163d54ff8fd1aa → d26c86558d422313}/chunk.js +1 -1
  208. package/dist/web-ui/content/modules/d2b8c6c6f3706032/queue-view-adapter.js +1 -0
  209. package/dist/web-ui/content/modules/d52ebe2ef12a9fa8/chunk.js +3 -0
  210. package/dist/web-ui/content/modules/{3fe11a75284ad8ae → d552b3bff2151eb6}/host.js +2 -2
  211. package/dist/web-ui/content/modules/d5d6b4511ac76a6e/chunk.js +3 -0
  212. package/dist/web-ui/content/modules/{bd7dc4bb46731ee7 → df42e151d625463b}/chunk.js +1 -1
  213. package/dist/web-ui/content/modules/{2a791cd2e14aa1e0 → e0a04f5ae56c68aa}/notice-view.js +1 -1
  214. package/dist/web-ui/content/modules/{438807b8bf112cd0 → e28e607c95d6f63a}/chunk.js +1 -1
  215. package/dist/web-ui/content/modules/{50da446c1377c220 → e3880df97ea62d0c}/chunk.js +1 -1
  216. package/dist/web-ui/content/modules/{87c7f50d9455d55e → e66196f1ece3e3ad}/chunk.js +1 -1
  217. package/dist/web-ui/content/modules/{9b12c2301f3a18f3 → eb76307444ac9d71}/chunk.js +1 -1
  218. package/dist/web-ui/content/modules/{c33935155289c22d → ebff7ca22cee1468}/chunk.js +1 -1
  219. package/dist/web-ui/content/modules/{4861eca9a8a87ad0 → ed1c712c569960d6}/chunk.js +1 -1
  220. package/dist/web-ui/content/modules/ee8b9c2d4bec63d4/chunk.js +1 -0
  221. package/dist/web-ui/content/modules/f458a194ce4208e2/chunk.js +1 -0
  222. package/dist/web-ui/content/modules/{11af5d14b30e57b6 → f938e826420cfe1b}/chunk.js +1 -1
  223. package/dist/web-ui/content/modules/fa7b9bf6cc84bfc1/chat-render.js +81 -0
  224. package/dist/web-ui/content/modules/{ea8fe4b9999fd2aa → fd1fb1834f5f06df}/chunk.js +1 -1
  225. package/dist/web-ui/content/modules/fd3084e562a3dbd6/host.js +1 -0
  226. package/dist/web-ui/content/styles.css +1 -1
  227. package/dist/web-ui/embedded-assets.d.ts +416 -413
  228. package/dist/web-ui/embedded-assets.js +5 -5
  229. package/dist/web-ui/page-route.js +2 -2
  230. package/dist/web-ui/react/workspaces/types.d.ts +3 -0
  231. package/dist/web-ui/thinking-efforts.d.ts +2 -0
  232. package/dist/web-ui/thinking-efforts.js +8 -0
  233. package/package.json +1 -2
  234. package/scripts/stage-render-binaries.js +0 -1
  235. package/skills/wand-knowledge/SKILL.md +5 -3
  236. package/dist/structured-bounded-keys.d.ts +0 -19
  237. package/dist/structured-bounded-keys.js +0 -47
  238. package/dist/web-ui/content/modules/00b168a19664439e/dropdown-surface.js +0 -1
  239. package/dist/web-ui/content/modules/059c5fb7f128d340/task-board-host.js +0 -27
  240. package/dist/web-ui/content/modules/07494f5a623e4471/chat-render.js +0 -76
  241. package/dist/web-ui/content/modules/0a743ad3b4db6874/chunk.js +0 -3
  242. package/dist/web-ui/content/modules/1858670c0f84fec5/employee-profile.js +0 -1
  243. package/dist/web-ui/content/modules/20c47dc0442f5a04/host.js +0 -1
  244. package/dist/web-ui/content/modules/226241b999d12008/host.js +0 -1
  245. package/dist/web-ui/content/modules/23c4b8d223ec64c5/host.js +0 -61
  246. package/dist/web-ui/content/modules/2882c97388ff4f7b/employee-card.js +0 -1
  247. package/dist/web-ui/content/modules/2c90c3be260e6cce/progress.js +0 -1
  248. package/dist/web-ui/content/modules/2d7be9935394f397/workspace-window.js +0 -1
  249. package/dist/web-ui/content/modules/389a5112332ec23a/host.js +0 -1
  250. package/dist/web-ui/content/modules/3ea13e8b3c2deaa4/panel-host.js +0 -1
  251. package/dist/web-ui/content/modules/42e5c34002fcffb7/chunk.js +0 -1
  252. package/dist/web-ui/content/modules/4a5d669c90f545cb/host.js +0 -1
  253. package/dist/web-ui/content/modules/5705d25468274534/host.js +0 -1
  254. package/dist/web-ui/content/modules/5961ab2947c86ca1/shell-file-panel-drawer.js +0 -1
  255. package/dist/web-ui/content/modules/5b6e1369df7dea69/chunk.js +0 -1
  256. package/dist/web-ui/content/modules/6787bdcf56f743a5/host.js +0 -1
  257. package/dist/web-ui/content/modules/67c39b0398186a9f/host.js +0 -1
  258. package/dist/web-ui/content/modules/6b16f35c0627bafb/chunk.js +0 -1
  259. package/dist/web-ui/content/modules/6dd4f3e2f619f7a0/chunk.js +0 -1
  260. package/dist/web-ui/content/modules/70a2e13e0ccc8549/panel.js +0 -1
  261. package/dist/web-ui/content/modules/710db590e9707f73/runtime.js +0 -338
  262. package/dist/web-ui/content/modules/7249950f8771dbeb/workspaces-panel.js +0 -4
  263. package/dist/web-ui/content/modules/87dcd516ffd9f688/composer-surface-adapter.js +0 -1
  264. package/dist/web-ui/content/modules/8b7cd7bffdfd69e7/brand-identity.js +0 -1
  265. package/dist/web-ui/content/modules/8bf9917f6c3429f6/host.js +0 -1
  266. package/dist/web-ui/content/modules/8e612d4881fa4118/home.js +0 -6
  267. package/dist/web-ui/content/modules/8e6178262ea63dec/markdown.js +0 -1
  268. package/dist/web-ui/content/modules/96f2ae970f8c576b/host.js +0 -1
  269. package/dist/web-ui/content/modules/ba89cd97627e6682/queue-view-adapter.js +0 -1
  270. package/dist/web-ui/content/modules/c351eb11e0bdec2c/sidebar-peek.js +0 -1
  271. package/dist/web-ui/content/modules/ca7ca5902a35d26e/chunk.js +0 -1
  272. package/dist/web-ui/content/modules/d5d28ec375826ef2/chunk.js +0 -3
  273. package/dist/web-ui/content/modules/d6b16dedb9011c33/chunk.js +0 -1
  274. package/dist/web-ui/content/modules/d8a7011760f61719/group-editor.js +0 -1
  275. package/dist/web-ui/content/modules/d9e2b65e9679ad39/host.js +0 -75
  276. package/dist/web-ui/content/modules/eac72f69716dba05/chunk.js +0 -1
  277. package/dist/web-ui/content/modules/ebc53dedc3945514/host.js +0 -1
  278. package/dist/web-ui/content/modules/f43da7050badf54c/host.js +0 -1
  279. package/dist/web-ui/content/modules/fb2356eced24c4cc/host-bridge.js +0 -1
package/dist/models.js CHANGED
@@ -12,6 +12,7 @@ import { AUTO_ASSIGN_LABEL, AUTO_ASSIGN_SELECTOR, FREE_MODEL_GROUP_ID, isAutoAss
12
12
  import { MODEL_ID_PATTERN, QODER_MODEL_ID_PATTERN, CLAUDE_BUILTIN_MODELS, CODEX_FALLBACK_MODELS, OPENCODE_FALLBACK_MODELS, GROK_FALLBACK_MODELS, QODER_FALLBACK_MODELS, PI_FALLBACK_MODELS, cloneModels, isRecord } from "./models/shared.js";
13
13
  import { EFFORT_ID_PATTERN, FALLBACK_PROVIDER_THINKING, cloneThinkingEfforts, effortLevelsFromIds, unionModelEfforts, parseCliEffortList } from "./models/thinking.js";
14
14
  import { parseOpenCodeModelCatalog } from "./models/parsers/opencode.js";
15
+ import { openCodeCatalogArgs } from "./opencode-cli.js";
15
16
  import { parseGrokModels } from "./models/parsers/grok.js";
16
17
  import { parseQoderModels } from "./models/parsers/qoder.js";
17
18
  import { parsePiRpcModels, parsePiModels } from "./models/parsers/pi.js";
@@ -288,20 +289,20 @@ async function probeCodexModels(runner, env) {
288
289
  }
289
290
  }
290
291
  async function probeOpenCode(runner, env) {
291
- const [modelsResult, versionResult] = await Promise.allSettled([
292
- runner("opencode", ["models", "--verbose"], { env, timeout: 8000 }),
293
- runner("opencode", ["--version"], { env, timeout: 5000 }),
294
- ]);
295
- const models = modelsResult.status === "fulfilled"
296
- ? { ok: true, value: parseOpenCodeModelCatalog(modelsResult.value.stdout) }
297
- : { ok: false };
298
- const version = versionResult.status === "fulfilled"
299
- ? {
300
- ok: true,
301
- value: extractSemver(versionResult.value.stdout) ?? (versionResult.value.stdout.trim().slice(0, 64) || null),
302
- }
303
- : { ok: false };
304
- return { models, version };
292
+ let version = { ok: false };
293
+ try {
294
+ const result = await runner("opencode", ["--version"], { env, timeout: 5000 });
295
+ version = { ok: true, value: extractSemver(result.stdout) ?? (result.stdout.trim().slice(0, 64) || null) };
296
+ }
297
+ catch { /* Directory failure preserves the last known catalog. */ }
298
+ try {
299
+ const major = version.ok ? Number(version.value?.split(".")[0]) : 1;
300
+ const result = await runner("opencode", openCodeCatalogArgs(major), { env, timeout: 8000 });
301
+ return { models: { ok: true, value: parseOpenCodeModelCatalog(result.stdout) }, version };
302
+ }
303
+ catch {
304
+ return { models: { ok: false }, version };
305
+ }
305
306
  }
306
307
  async function probeGrokModels(runner, env) {
307
308
  try {
@@ -11,6 +11,7 @@
11
11
  * 我们的策略:安装前备份当前全局包,补齐 npm 子进程 PATH,清掉
12
12
  * `@co0ontty/.wand-*` 残留目录;失败时恢复备份,避免运行中的服务被半成品安装拆掉。
13
13
  */
14
+ import type { WandBuildInfo } from "./build-info.js";
14
15
  export declare const PACKAGE_NAME = "@co0ontty/wand";
15
16
  export type UpdateChannel = "stable" | "beta";
16
17
  export interface PackageUpdateInfo {
@@ -28,8 +29,9 @@ export declare function normalizeUpdateChannel(value: unknown): UpdateChannel;
28
29
  export declare function getInstallSpecForChannel(channel: UpdateChannel): string;
29
30
  export declare function buildPackageUpdateInfo(currentVersion: string, channel: UpdateChannel, latestVersion: string | null): PackageUpdateInfo;
30
31
  export declare function selectPackageUpdateInfo(currentVersion: string, channel: UpdateChannel, stableVersion: string | null, betaVersion?: string | null): PackageUpdateInfo;
31
- export declare function checkPackageUpdateAsync(currentVersion: string, channel: UpdateChannel, timeoutMs?: number): Promise<PackageUpdateInfo>;
32
- export declare function checkPackageUpdateSync(currentVersion: string, channel: UpdateChannel, timeoutMs?: number): PackageUpdateInfo;
32
+ type UpdateBuildIdentity = Pick<WandBuildInfo, "version" | "commit">;
33
+ export declare function checkPackageUpdateAsync(currentVersion: string, channel: UpdateChannel, timeoutMs?: number, build?: UpdateBuildIdentity): Promise<PackageUpdateInfo>;
34
+ export declare function checkPackageUpdateSync(currentVersion: string, channel: UpdateChannel, timeoutMs?: number, build?: UpdateBuildIdentity): PackageUpdateInfo;
33
35
  export declare function resolveInstalledNpmPrefix(moduleUrl?: string, platform?: NodeJS.Platform): {
34
36
  root: string;
35
37
  prefix: string;
@@ -88,3 +90,4 @@ export declare function resolveGlobalWandCli(): string | null;
88
90
  * dist/cli.js;更新回滚期间 shim 会临时指向同盘安全备份,始终保持可启动。
89
91
  */
90
92
  export declare function resolveGlobalWandBin(): string | null;
93
+ export {};
@@ -103,17 +103,47 @@ export function selectPackageUpdateInfo(currentVersion, channel, stableVersion,
103
103
  const info = buildPackageUpdateInfo(currentVersion, useBeta ? "beta" : "stable", useBeta ? beta : stable);
104
104
  return { ...info, channel, stableVersion: stable, betaVersion: beta };
105
105
  }
106
- export async function checkPackageUpdateAsync(currentVersion, channel, timeoutMs = NPM_VIEW_TIMEOUT_MS) {
106
+ function localDebugCommit(info, build) {
107
+ if (!info.updateAvailable || !/^\d+\.\d+\.\d+-debug\./.test(info.current)
108
+ || !build?.commit || build.version === null || cleanVersion(build.version) !== info.current
109
+ || !/^[a-f0-9]{40}$/i.test(build.commit))
110
+ return null;
111
+ return build.commit.toLowerCase();
112
+ }
113
+ function applySourceCommit(info, currentCommit, candidateCommit) {
114
+ // start.sh uses X.Y.Z-debug while CI uses X.Y.(Z+1)-beta, even for the same
115
+ // commit. A published copy must not replace local changes on that commit.
116
+ return candidateCommit.trim().toLowerCase() === currentCommit ? { ...info, updateAvailable: false } : info;
117
+ }
118
+ export async function checkPackageUpdateAsync(currentVersion, channel, timeoutMs = NPM_VIEW_TIMEOUT_MS, build) {
107
119
  const [stable, beta] = await Promise.all([
108
120
  viewPackageVersionAsync("stable", timeoutMs),
109
121
  channel === "beta" ? viewPackageVersionAsync("beta", timeoutMs) : null,
110
122
  ]);
111
- return selectPackageUpdateInfo(currentVersion, channel, stable, beta);
123
+ const info = selectPackageUpdateInfo(currentVersion, channel, stable, beta);
124
+ const commit = localDebugCommit(info, build);
125
+ if (!commit)
126
+ return info;
127
+ try {
128
+ const { stdout } = await execFileAsync(npmBin(), ["view", info.installSpec, "gitHead"], {
129
+ timeout: timeoutMs, env: getChildEnv(), maxBuffer: INSTALL_MAX_BUFFER,
130
+ });
131
+ return applySourceCommit(info, commit, stdout);
132
+ }
133
+ catch {
134
+ // Missing provenance does not prove equal source; retain version ordering.
135
+ return info;
136
+ }
112
137
  }
113
- export function checkPackageUpdateSync(currentVersion, channel, timeoutMs = NPM_VIEW_TIMEOUT_MS) {
138
+ export function checkPackageUpdateSync(currentVersion, channel, timeoutMs = NPM_VIEW_TIMEOUT_MS, build) {
114
139
  const stable = viewPackageVersionSync("stable", timeoutMs);
115
140
  const beta = channel === "beta" ? viewPackageVersionSync("beta", timeoutMs) : null;
116
- return selectPackageUpdateInfo(currentVersion, channel, stable, beta);
141
+ const info = selectPackageUpdateInfo(currentVersion, channel, stable, beta);
142
+ const commit = localDebugCommit(info, build);
143
+ if (!commit)
144
+ return info;
145
+ const result = runNpmSync(["view", info.installSpec, "gitHead"], timeoutMs);
146
+ return result.status === 0 ? applySourceCommit(info, commit, result.stdout ?? "") : info;
117
147
  }
118
148
  export function resolveInstalledNpmPrefix(moduleUrl = import.meta.url, platform = process.platform) {
119
149
  try {
@@ -0,0 +1,6 @@
1
+ /** Resolve the actual executable; an upgrade invalidates the cached CLI dialect. */
2
+ export declare function openCodeMajorVersion(env: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<number>;
3
+ /** v2 returns priced native records through its read-only API, v1 through verbose models. */
4
+ export declare function openCodeCatalogArgs(major: number, nativeFree?: boolean): string[];
5
+ /** v2 folds the reasoning variant into the model reference. */
6
+ export declare function openCodeModelArgs(model: string | null | undefined, variant: string | null, major: number): string[];
@@ -0,0 +1,51 @@
1
+ import { execFile } from "node:child_process";
2
+ import { statSync } from "node:fs";
3
+ import { promisify } from "node:util";
4
+ import { whichSync } from "./path-repair.js";
5
+ import { extractSemver } from "./version-utils.js";
6
+ const execFileAsync = promisify(execFile);
7
+ let cachedVersion;
8
+ /** Resolve the actual executable; an upgrade invalidates the cached CLI dialect. */
9
+ export async function openCodeMajorVersion(env, signal) {
10
+ signal?.throwIfAborted();
11
+ const executable = whichSync("opencode", { env });
12
+ if (!executable)
13
+ throw new Error("未找到 OpenCode CLI。");
14
+ const stat = statSync(executable);
15
+ const identity = `${executable}:${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}`;
16
+ if (cachedVersion?.identity !== identity) {
17
+ const version = execFileAsync(executable, ["--version"], { env, timeout: 5_000, maxBuffer: 64 * 1024, encoding: "utf8" })
18
+ .then(({ stdout }) => {
19
+ const parsed = extractSemver(stdout);
20
+ if (!parsed)
21
+ throw new Error("无法识别 OpenCode CLI 版本。");
22
+ return Number(parsed.split(".")[0]);
23
+ });
24
+ cachedVersion = { identity, version };
25
+ void version.catch(() => { if (cachedVersion?.version === version)
26
+ cachedVersion = undefined; });
27
+ }
28
+ const major = await cachedVersion.version;
29
+ signal?.throwIfAborted();
30
+ return major;
31
+ }
32
+ /** v2 returns priced native records through its read-only API, v1 through verbose models. */
33
+ export function openCodeCatalogArgs(major, nativeFree = false) {
34
+ return major >= 2
35
+ ? ["api", "--standalone", "model.list"]
36
+ : nativeFree ? ["models", "opencode", "--verbose", "--refresh", "--pure"] : ["models", "--verbose"];
37
+ }
38
+ /** v2 folds the reasoning variant into the model reference. */
39
+ export function openCodeModelArgs(model, variant, major) {
40
+ const value = model?.trim();
41
+ const args = [];
42
+ if (value && value !== "default") {
43
+ args.push("--model", major >= 2 && variant ? `${value.split("#")[0]}#${variant}` : value);
44
+ }
45
+ else if (major >= 2 && variant) {
46
+ throw new Error("OpenCode 2 的思考深度需要具体模型,请先选择模型。");
47
+ }
48
+ if (major < 2 && variant)
49
+ args.push("--variant", variant);
50
+ return args;
51
+ }
@@ -29,6 +29,7 @@ export declare class OpenCodeFreeModelsService implements OpenCodeFreePool {
29
29
  private readonly options;
30
30
  private controller;
31
31
  private setup;
32
+ private cliMajor;
32
33
  private pending;
33
34
  private retryAfter;
34
35
  private disposed;
@@ -11,6 +11,7 @@ import { AI_TEAM_MAX_CANDIDATES } from "./ai-team-types.js";
11
11
  import { systemEmployeeDefaultAgents } from "./system-employee.js";
12
12
  import { whichSync } from "./path-repair.js";
13
13
  import { parseProviderCliVersion } from "./provider-cli-updater.js";
14
+ import { openCodeCatalogArgs } from "./opencode-cli.js";
14
15
  import { asRecord } from "./structured-content.js";
15
16
  import { redactSystemAiText } from "./system-ai-redaction.js";
16
17
  const pools = new WeakMap();
@@ -56,10 +57,19 @@ export function parseOpenCodeFreeModels(stdout) {
56
57
  return !!row && Object.keys(row).length > 0 && Object.values(row).every(allZero);
57
58
  };
58
59
  return [...new Set(parseOpenCodeModelRecords(stdout).flatMap(({ id, record }) => {
59
- const api = asRecord(record.api), cost = asRecord(record.cost), capabilities = asRecord(record.capabilities);
60
+ const api = asRecord(record.api), capabilities = asRecord(record.capabilities);
61
+ // v2 supplies a price per context tier. Every tier and every price must be zero.
62
+ const costs = Array.isArray(record.cost) ? record.cost : [record.cost];
63
+ const free = costs.length > 0 && costs.every((value) => {
64
+ const cost = asRecord(value);
65
+ if (!cost || !zero(cost.input) || !zero(cost.output))
66
+ return false;
67
+ const { tier: _tier, ...prices } = cost;
68
+ return allZero(prices);
69
+ });
60
70
  if (!isOpenCodeNativeModelId(id) || record.providerID !== "opencode" || record.status !== "active"
61
71
  || api?.id !== id.slice("opencode/".length) || typeof api.url !== "string" || !NATIVE_API_URLS.has(api.url)
62
- || typeof api.npm !== "string" || !NATIVE_SDKS.has(api.npm) || !cost || !zero(cost.input) || !zero(cost.output) || !allZero(cost)
72
+ || typeof api.npm !== "string" || !NATIVE_SDKS.has(api.npm) || !free
63
73
  || asRecord(capabilities?.input)?.text !== true || asRecord(capabilities?.output)?.text !== true
64
74
  || capabilities?.toolcall !== true)
65
75
  return [];
@@ -122,6 +132,7 @@ export class OpenCodeFreeModelsService {
122
132
  options;
123
133
  controller = new AbortController();
124
134
  setup;
135
+ cliMajor = 1;
125
136
  pending;
126
137
  retryAfter = 0;
127
138
  disposed = false;
@@ -160,7 +171,7 @@ export class OpenCodeFreeModelsService {
160
171
  return this.options.find ? this.options.find(command, this.env()) : whichSync(command, { env: this.env() });
161
172
  }
162
173
  async run(file, args, timeout, signal = this.controller.signal) {
163
- const nativeModels = args[0] === "models";
174
+ const nativeModels = args[0] === "models" || args[0] === "api";
164
175
  const result = await (this.options.run ?? runCommand)(file, args, { env: nativeModels ? this.execution.env(this.env()) : this.env(), timeout,
165
176
  ...(nativeModels ? { cwd: this.execution.cwd } : {}), signal: AbortSignal.any([signal, this.controller.signal]) });
166
177
  this.controller.signal.throwIfAborted();
@@ -200,6 +211,7 @@ export class OpenCodeFreeModelsService {
200
211
  const version = parseProviderCliVersion(await this.run(executable, ["--version"], 8_000));
201
212
  if (!version || /^0\.0\./.test(version))
202
213
  throw new Error("现有 OpenCode 版本不可用;未覆盖用户安装。");
214
+ this.cliMajor = Number(version.split(".")[0]);
203
215
  return executable;
204
216
  }
205
217
  ensure() {
@@ -222,7 +234,7 @@ export class OpenCodeFreeModelsService {
222
234
  const sequence = ++this.catalogSequence;
223
235
  const executable = await this.ensure();
224
236
  signal?.throwIfAborted();
225
- return { sequence, models: parseOpenCodeFreeModels(await this.run(executable, ["models", "opencode", "--verbose", "--refresh", "--pure"], 15_000, signal)) };
237
+ return { sequence, models: parseOpenCodeFreeModels(await this.run(executable, openCodeCatalogArgs(this.cliMajor, true), 15_000, signal)) };
226
238
  }
227
239
  async probe(model) {
228
240
  try {
@@ -2,6 +2,7 @@
2
2
  // Do not import a Wand SDK runtime: the native CLI owns its extensions and TUI.
3
3
  import { appendFileSync, readFileSync, writeFileSync } from "node:fs";
4
4
  import { projectPiProtocolEvent } from "./pi-event-projection.js";
5
+ import { claimNativeInput, nativeInputFile, openNativeInputBoundary, writeNativeInput } from "./pi-native-input.js";
5
6
  export default function wandNativeEvents(pi) {
6
7
  const file = process.env.WAND_PI_NATIVE_PATHS;
7
8
  if (!file)
@@ -28,7 +29,10 @@ export default function wandNativeEvents(pi) {
28
29
  if (ctx.mode !== "tui")
29
30
  throw new Error("Pi 原生 tmux 会话必须使用 TUI 模式。");
30
31
  append({ type: "session", id: ctx.sessionManager.getSessionId() });
31
- writeFileSync(paths.ready, JSON.stringify({ mode: ctx.mode, hasUI: ctx.hasUI, pid: process.pid }) + "\n", { mode: 0o600 });
32
+ if (paths.input)
33
+ append({ type: "wand_input_ready", id: paths.initialMessageId });
34
+ writeFileSync(paths.ready, JSON.stringify({ mode: ctx.mode, hasUI: ctx.hasUI, pid: process.pid,
35
+ sessionFile: ctx.sessionManager.getSessionFile() }) + "\n", { mode: 0o600 });
32
36
  });
33
37
  const capture = (event) => {
34
38
  if (event.type === "message_update") {
@@ -42,8 +46,55 @@ export default function wandNativeEvents(pi) {
42
46
  else
43
47
  append(event);
44
48
  };
49
+ let pending = null;
50
+ const confirmInput = (ctx) => {
51
+ if (!pending || !paths.input)
52
+ return;
53
+ const offer = pending;
54
+ const found = ctx.sessionManager.getBranch().some((entry) => entry.type === "custom_message"
55
+ && entry.customType === "wand-user-input"
56
+ && entry.details?.inputId === offer.id);
57
+ if (!found)
58
+ return;
59
+ writeNativeInput(nativeInputFile(paths.input, offer.boundaryId, "committed"), offer);
60
+ append({ type: "wand_input_committed", id: offer.boundaryId, message: offer });
61
+ pending = null;
62
+ };
63
+ pi.on("turn_end", async (event, ctx) => {
64
+ if (!paths.input || !Array.isArray(event.entries) || !event.context
65
+ || event.outcome === "error" || event.outcome === "aborted" || ctx.signal?.aborted
66
+ || event.message.stopReason === "error"
67
+ || event.message.stopReason === "aborted")
68
+ return;
69
+ confirmInput(ctx);
70
+ // A prior unconfirmed handoff must never be followed by another injection.
71
+ if (pending || ctx.hasPendingMessages())
72
+ return;
73
+ const boundaryId = openNativeInputBoundary(paths.input);
74
+ append({ type: "wand_input_boundary", id: boundaryId });
75
+ try {
76
+ const deadline = Date.now() + 2000;
77
+ while (!ctx.signal?.aborted && Date.now() < deadline) {
78
+ const offer = claimNativeInput(paths.input, boundaryId);
79
+ if (offer !== undefined) {
80
+ if (!offer)
81
+ return;
82
+ pending = offer;
83
+ // Official awaited boundary entries commit to the native session before
84
+ // continuing. Unlike sendUserMessage(), no discarded async enqueue runs.
85
+ return { entries: [...event.entries, { type: "custom_message",
86
+ customType: "wand-user-input", content: offer.text, display: true,
87
+ details: { inputId: offer.id, boundaryId } }], continue: true };
88
+ }
89
+ await new Promise((resolve) => setTimeout(resolve, 20));
90
+ }
91
+ }
92
+ finally {
93
+ writeNativeInput(nativeInputFile(paths.input, boundaryId, "closed"), { id: boundaryId });
94
+ }
95
+ });
45
96
  pi.on("agent_start", capture);
46
- pi.on("turn_start", capture);
97
+ pi.on("turn_start", (event, ctx) => { confirmInput(ctx); capture(event); });
47
98
  pi.on("message_start", capture);
48
99
  pi.on("message_update", capture);
49
100
  pi.on("message_end", capture);
@@ -51,8 +102,9 @@ export default function wandNativeEvents(pi) {
51
102
  pi.on("tool_execution_start", capture);
52
103
  pi.on("tool_execution_update", capture);
53
104
  pi.on("tool_execution_end", capture);
54
- pi.on("agent_end", capture);
105
+ pi.on("agent_end", (event, ctx) => { confirmInput(ctx); capture(event); });
55
106
  pi.on("agent_settled", (event, ctx) => {
107
+ confirmInput(ctx);
56
108
  append(event);
57
109
  // Match the existing per-submit CLI lifetime. This boundary is later than
58
110
  // agent_end: queued/background work, retry and compaction have drained.
@@ -0,0 +1,22 @@
1
+ /** Private per-execution mailbox; never a client request path or an SDK runtime. */
2
+ export interface PiInputHandoff {
3
+ id: string;
4
+ boundaryId: string;
5
+ incarnationId: string;
6
+ }
7
+ export interface PiInputOffer extends PiInputHandoff {
8
+ text: string;
9
+ }
10
+ export interface PiInputResolution {
11
+ state: "committed" | "unclaimed" | "unknown";
12
+ offer?: PiInputOffer;
13
+ }
14
+ export declare function nativeInputFile(directory: string, boundaryId: string, name: string): string;
15
+ export declare function writeNativeInput(file: string, value: unknown): void;
16
+ export declare function readNativeInput<T>(file: string): T | null;
17
+ export declare function openNativeInputBoundary(directory: string): string;
18
+ /** Queue reservation is synchronous and durable before publishing the response. */
19
+ export declare function offerNativeInput(directory: string, boundaryId: string, incarnationId: string, take: (identity: PiInputHandoff) => string | null): boolean;
20
+ /** Claim precedes any native transcript mutation; an absent claim is safe to release after close/exit. */
21
+ export declare function claimNativeInput(directory: string, boundaryId: string): PiInputOffer | null | undefined;
22
+ export declare function resolveNativeInput(directory: string, handoff: PiInputHandoff, exited: boolean): PiInputResolution;
@@ -0,0 +1,77 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { constants, closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ const UUID = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
5
+ const MAX_MAILBOX_BYTES = 8 * 1024 * 1024;
6
+ export function nativeInputFile(directory, boundaryId, name) {
7
+ if (!UUID.test(boundaryId))
8
+ throw new Error("Pi 输入边界标识无效。");
9
+ return path.join(directory, boundaryId, name + ".json");
10
+ }
11
+ export function writeNativeInput(file, value) {
12
+ const temporary = file + "." + randomUUID() + ".tmp";
13
+ writeFileSync(temporary, JSON.stringify(value) + "\n", { mode: 0o600, flag: "wx" });
14
+ renameSync(temporary, file);
15
+ }
16
+ export function readNativeInput(file) {
17
+ let fd;
18
+ try {
19
+ fd = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
20
+ }
21
+ catch (error) {
22
+ if (error.code === "ENOENT")
23
+ return null;
24
+ throw error;
25
+ }
26
+ try {
27
+ const stat = fstatSync(fd);
28
+ if (!stat.isFile() || stat.size > MAX_MAILBOX_BYTES)
29
+ throw new Error("Pi 输入邮箱无效或超过容量。");
30
+ return JSON.parse(readFileSync(fd, "utf8"));
31
+ }
32
+ finally {
33
+ closeSync(fd);
34
+ }
35
+ }
36
+ export function openNativeInputBoundary(directory) {
37
+ const id = randomUUID();
38
+ mkdirSync(path.join(directory, id), { recursive: true, mode: 0o700 });
39
+ writeNativeInput(nativeInputFile(directory, id, "request"), { id });
40
+ return id;
41
+ }
42
+ /** Queue reservation is synchronous and durable before publishing the response. */
43
+ export function offerNativeInput(directory, boundaryId, incarnationId, take) {
44
+ const file = (name) => nativeInputFile(directory, boundaryId, name);
45
+ if (readNativeInput(file("request"))?.id !== boundaryId
46
+ || existsSync(file("closed")) || existsSync(file("response")) || existsSync(file("claimed")))
47
+ return false;
48
+ const identity = { id: randomUUID(), boundaryId, incarnationId };
49
+ const text = take(identity);
50
+ writeNativeInput(file("response"), text === null ? null : { ...identity, text });
51
+ return true;
52
+ }
53
+ /** Claim precedes any native transcript mutation; an absent claim is safe to release after close/exit. */
54
+ export function claimNativeInput(directory, boundaryId) {
55
+ const response = nativeInputFile(directory, boundaryId, "response");
56
+ if (!existsSync(response))
57
+ return undefined;
58
+ const claimed = nativeInputFile(directory, boundaryId, "claimed");
59
+ renameSync(response, claimed);
60
+ const offer = readNativeInput(claimed);
61
+ if (offer === null)
62
+ return null;
63
+ if (!UUID.test(offer.id) || offer.boundaryId !== boundaryId || !UUID.test(offer.incarnationId)
64
+ || typeof offer.text !== "string" || !offer.text.trim())
65
+ throw new Error("Pi 输入交接内容无效。");
66
+ return offer;
67
+ }
68
+ export function resolveNativeInput(directory, handoff, exited) {
69
+ const file = (name) => nativeInputFile(directory, handoff.boundaryId, name);
70
+ const committed = readNativeInput(file("committed"));
71
+ if (committed?.id === handoff.id && committed.incarnationId === handoff.incarnationId) {
72
+ return { state: "committed", offer: committed };
73
+ }
74
+ if (!existsSync(file("claimed")) && (exited || existsSync(file("closed"))))
75
+ return { state: "unclaimed" };
76
+ return { state: "unknown" };
77
+ }
@@ -1,14 +1,17 @@
1
+ import { type PiInputHandoff, type PiInputResolution } from "./pi-native-input.js";
1
2
  import { type StructuredExecHost, type StructuredExecProcess, type StructuredSpawnRequest, type StructuredRunState } from "./structured-exec-host.js";
2
3
  interface NativeJob {
3
4
  runId: string;
4
5
  requestId: string;
5
6
  incarnationId: string;
6
7
  tmux: string;
8
+ pane?: string;
7
9
  events: string;
8
10
  stderr: string;
9
11
  state: string;
10
12
  ready: string;
11
13
  ack: string;
14
+ input?: string;
12
15
  }
13
16
  interface WorkerState {
14
17
  status: "starting" | "running" | "exited";
@@ -36,6 +39,8 @@ export declare class PiTmuxHost implements StructuredExecHost {
36
39
  state(job: NativeJob): WorkerState;
37
40
  private snapshot;
38
41
  spawnStructured(request: StructuredSpawnRequest): Promise<StructuredExecProcess>;
42
+ offerPiInput(runId: string, boundaryId: string, take: (identity: PiInputHandoff) => string | null): boolean;
43
+ resolvePiInput(runId: string, handoff: PiInputHandoff): PiInputResolution;
39
44
  attachRun(runId: string, checkpoint?: import("./pi-cli-checkpoint.js").PiCliCheckpoint): Promise<StructuredRunState | null>;
40
45
  adoptRun(runId: string): Promise<StructuredExecProcess | null>;
41
46
  listRuns(): Promise<StructuredRunState[]>;
@@ -47,21 +52,25 @@ export declare class PiTmuxHost implements StructuredExecHost {
47
52
  * 而 forgetRun 只写 ack 标记、从不删目录,所以会按回合数无限堆积。
48
53
  *
49
54
  * 只回收三类确定无主的东西:
50
- * - slot 已 ack 且 runId 不再属于任何存活会话:整个 slot 无主;
55
+ * - slot 已 ack 且 runId 不在 activeSessionIds 里:整个 slot 无主;
51
56
  * - slot 无主的,整槽删除;
52
57
  * - slot 仍有主的,只删非 current.json 引用、已 ack 且进程已退出、超保留期的 turn。
53
58
  *
54
- * 保留 current.json 指向的 turn:`listRuns` / `adoptRun` 仍靠它的 events.jsonl
55
- * 重放恢复;未 ack 的 slot 可能是尚未收尾的回合,一律不动。
59
+ * activeSessionIds 只含未归档会话。归档后不再续接这些 turn,已 ack 且进程退出
60
+ * 就可以整槽删除,不再额外等保留期;取消归档从会话自己的消息快照恢复。
61
+ * 保留未归档会话 current.json 指向的 turn:`listRuns` / `adoptRun` 仍靠它的
62
+ * events.jsonl 重放恢复;未 ack 的 slot 可能是尚未收尾的回合,一律不动。
56
63
  */
57
64
  collectGarbage(options: {
58
- /** 仍在数据库里的会话 id;不在其中的 slot 视为无主。 */
65
+ /** 未归档会话 id;不在其中的 slot(已删除或已归档)视为无主。 */
59
66
  liveSessionIds: ReadonlySet<string>;
67
+ /** 与 liveSessionIds 同义。传入时优先于旧字段,避免把归档会话算成仍在使用。 */
68
+ activeSessionIds?: ReadonlySet<string>;
60
69
  retentionMs: number;
61
70
  now?: number;
62
71
  }): PiNativeGcReport;
63
72
  private readJob;
64
- /** 无主 slot 是否已整体静默:所有 turn 都不再是运行中,且最新写入超过保留期。 */
73
+ /** 无主 slot 是否已整体静默:所有 turn 都不再是运行中。retentionMs 为 0 时不等待。 */
65
74
  private slotIsIdle;
66
75
  }
67
76
  /** pi-native 回收结果:删了几个 slot / 几个旧 turn / 释放多少字节。 */