@phnx-labs/agents-cli 1.22.34 → 1.22.37

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 (493) hide show
  1. package/CHANGELOG.md +672 -2
  2. package/README.md +82 -35
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.d.ts +15 -0
  5. package/dist/bootstrap.js +1211 -0
  6. package/dist/commands/accounts.d.ts +4 -11
  7. package/dist/commands/accounts.js +159 -27
  8. package/dist/commands/attach.js +17 -4
  9. package/dist/commands/audit.d.ts +8 -8
  10. package/dist/commands/audit.js +57 -47
  11. package/dist/commands/browser.js +15 -11
  12. package/dist/commands/cloud.js +1 -1
  13. package/dist/commands/commands.js +0 -11
  14. package/dist/commands/computer-actions.js +33 -0
  15. package/dist/commands/computer-sessions-picker.d.ts +21 -0
  16. package/dist/commands/computer-sessions-picker.js +141 -0
  17. package/dist/commands/computer.d.ts +16 -0
  18. package/dist/commands/computer.js +37 -0
  19. package/dist/commands/config.d.ts +17 -0
  20. package/dist/commands/config.js +401 -0
  21. package/dist/commands/cp.d.ts +84 -0
  22. package/dist/commands/cp.js +231 -0
  23. package/dist/commands/daemon.js +243 -14
  24. package/dist/commands/detach-core.d.ts +1 -1
  25. package/dist/commands/detach-core.js +12 -2
  26. package/dist/commands/detach.js +1 -1
  27. package/dist/commands/doctor.js +64 -5
  28. package/dist/commands/events.d.ts +24 -12
  29. package/dist/commands/events.js +144 -28
  30. package/dist/commands/exec.js +85 -41
  31. package/dist/commands/feed.d.ts +1 -1
  32. package/dist/commands/feed.js +16 -8
  33. package/dist/commands/focus.d.ts +33 -1
  34. package/dist/commands/focus.js +177 -17
  35. package/dist/commands/funnel.d.ts +1 -1
  36. package/dist/commands/go.js +9 -8
  37. package/dist/commands/harness-wizard.d.ts +1 -0
  38. package/dist/commands/harness-wizard.js +18 -20
  39. package/dist/commands/harness.d.ts +2 -0
  40. package/dist/commands/harness.js +59 -26
  41. package/dist/commands/hooks.js +0 -11
  42. package/dist/commands/inspect.d.ts +94 -1
  43. package/dist/commands/inspect.js +866 -40
  44. package/dist/commands/lease.d.ts +4 -4
  45. package/dist/commands/lease.js +6 -6
  46. package/dist/commands/login.js +0 -13
  47. package/dist/commands/logs.d.ts +2 -2
  48. package/dist/commands/logs.js +2 -2
  49. package/dist/commands/mcp.js +7 -2
  50. package/dist/commands/memory.js +7 -2
  51. package/dist/commands/message.d.ts +1 -1
  52. package/dist/commands/message.js +37 -6
  53. package/dist/commands/models.js +4 -0
  54. package/dist/commands/monitors.d.ts +0 -1
  55. package/dist/commands/monitors.js +199 -16
  56. package/dist/commands/open.d.ts +18 -0
  57. package/dist/commands/open.js +57 -0
  58. package/dist/commands/packages.js +2 -107
  59. package/dist/commands/plugins.js +6 -3
  60. package/dist/commands/profiles.d.ts +1 -0
  61. package/dist/commands/profiles.js +16 -160
  62. package/dist/commands/projects.d.ts +28 -0
  63. package/dist/commands/projects.js +125 -5
  64. package/dist/commands/reconnect.js +9 -3
  65. package/dist/commands/repo.js +42 -1
  66. package/dist/commands/resource-view.d.ts +17 -0
  67. package/dist/commands/resource-view.js +36 -14
  68. package/dist/commands/resume.js +9 -2
  69. package/dist/commands/routines.d.ts +0 -2
  70. package/dist/commands/routines.js +473 -289
  71. package/dist/commands/secrets.js +52 -9
  72. package/dist/commands/sessions-export.d.ts +47 -0
  73. package/dist/commands/sessions-export.js +116 -6
  74. package/dist/commands/sessions-import.d.ts +17 -0
  75. package/dist/commands/sessions-import.js +114 -6
  76. package/dist/commands/sessions-migrate.d.ts +27 -0
  77. package/dist/commands/sessions-migrate.js +50 -9
  78. package/dist/commands/sessions-picker.js +23 -4
  79. package/dist/commands/sessions-resume.d.ts +5 -3
  80. package/dist/commands/sessions-resume.js +30 -8
  81. package/dist/commands/sessions-watch.d.ts +2 -0
  82. package/dist/commands/sessions-watch.js +53 -0
  83. package/dist/commands/sessions.d.ts +66 -3
  84. package/dist/commands/sessions.js +298 -47
  85. package/dist/commands/set.d.ts +1 -1
  86. package/dist/commands/set.js +2 -2
  87. package/dist/commands/setup-browser.js +2 -2
  88. package/dist/commands/setup-mine.js +0 -1
  89. package/dist/commands/setup-preferences.js +1 -1
  90. package/dist/commands/setup-share.js +34 -4
  91. package/dist/commands/setup.d.ts +5 -0
  92. package/dist/commands/setup.js +26 -0
  93. package/dist/commands/share.d.ts +85 -0
  94. package/dist/commands/share.js +379 -8
  95. package/dist/commands/skills.js +0 -11
  96. package/dist/commands/snapshot.js +1 -1
  97. package/dist/commands/ssh.d.ts +18 -0
  98. package/dist/commands/ssh.js +549 -210
  99. package/dist/commands/sync.d.ts +5 -0
  100. package/dist/commands/sync.js +212 -32
  101. package/dist/commands/teams.d.ts +13 -0
  102. package/dist/commands/teams.js +187 -30
  103. package/dist/commands/tickets.d.ts +2 -0
  104. package/dist/commands/tickets.js +43 -0
  105. package/dist/commands/update.js +2 -4
  106. package/dist/commands/usage.js +5 -3
  107. package/dist/commands/versions.js +11 -5
  108. package/dist/commands/view.js +15 -7
  109. package/dist/commands/webhook.d.ts +2 -2
  110. package/dist/commands/webhook.js +7 -7
  111. package/dist/index.d.ts +18 -2
  112. package/dist/index.js +53 -1264
  113. package/dist/lib/account-catalog.d.ts +18 -0
  114. package/dist/lib/account-catalog.js +38 -0
  115. package/dist/lib/account-provider-registry.d.ts +18 -0
  116. package/dist/lib/account-provider-registry.js +59 -0
  117. package/dist/lib/account-registry.d.ts +40 -0
  118. package/dist/lib/account-registry.js +239 -0
  119. package/dist/lib/account-schema.d.ts +44 -0
  120. package/dist/lib/account-schema.js +91 -0
  121. package/dist/lib/account-state-service.d.ts +21 -0
  122. package/dist/lib/account-state-service.js +60 -0
  123. package/dist/lib/activity.d.ts +1 -1
  124. package/dist/lib/activity.js +8 -1
  125. package/dist/lib/add-dir.d.ts +80 -0
  126. package/dist/lib/add-dir.js +241 -0
  127. package/dist/lib/agent-cli-commands.d.ts +11 -0
  128. package/dist/lib/agent-cli-commands.js +30 -0
  129. package/dist/lib/agents.js +44 -36
  130. package/dist/lib/answer-router.js +1 -1
  131. package/dist/lib/audit/log.d.ts +10 -27
  132. package/dist/lib/audit/log.js +20 -33
  133. package/dist/lib/auth-health.d.ts +9 -2
  134. package/dist/lib/auth-health.js +42 -9
  135. package/dist/lib/auto-pull-worker.js +7 -3
  136. package/dist/lib/auto-pull.d.ts +44 -3
  137. package/dist/lib/auto-pull.js +88 -5
  138. package/dist/lib/binary-shadow.d.ts +28 -0
  139. package/dist/lib/binary-shadow.js +121 -0
  140. package/dist/lib/brand.js +9 -3
  141. package/dist/lib/browser/ipc.d.ts +30 -0
  142. package/dist/lib/browser/ipc.js +81 -4
  143. package/dist/lib/browser/profiles.d.ts +3 -2
  144. package/dist/lib/browser/profiles.js +65 -22
  145. package/dist/lib/browser/service.d.ts +4 -0
  146. package/dist/lib/browser/service.js +30 -3
  147. package/dist/lib/browser/sessions-list.d.ts +22 -2
  148. package/dist/lib/browser/sessions-list.js +54 -6
  149. package/dist/lib/browser/stream.d.ts +2 -0
  150. package/dist/lib/browser/stream.js +1 -0
  151. package/dist/lib/browser/types.d.ts +19 -0
  152. package/dist/lib/byok-usage.d.ts +9 -2
  153. package/dist/lib/byok-usage.js +133 -31
  154. package/dist/lib/cli-entry.d.ts +11 -0
  155. package/dist/lib/cli-entry.js +46 -0
  156. package/dist/lib/cloud/host.d.ts +1 -1
  157. package/dist/lib/cloud/host.js +2 -2
  158. package/dist/lib/cloud/registry.js +1 -1
  159. package/dist/lib/cloud/types.d.ts +1 -1
  160. package/dist/lib/codex-policy.d.ts +9 -1
  161. package/dist/lib/codex-policy.js +17 -2
  162. package/dist/lib/commands.d.ts +2 -0
  163. package/dist/lib/commands.js +2 -0
  164. package/dist/lib/computer/sessions-list.d.ts +150 -0
  165. package/dist/lib/computer/sessions-list.js +363 -0
  166. package/dist/lib/config-keys.d.ts +86 -0
  167. package/dist/lib/config-keys.js +193 -0
  168. package/dist/lib/config-machine-keys.d.ts +12 -0
  169. package/dist/lib/config-machine-keys.js +17 -0
  170. package/dist/lib/config-transfer.js +3 -4
  171. package/dist/lib/crabbox/cli.d.ts +2 -2
  172. package/dist/lib/crabbox/cli.js +3 -3
  173. package/dist/lib/daemon-health.d.ts +22 -0
  174. package/dist/lib/daemon-health.js +33 -3
  175. package/dist/lib/daemon-services.d.ts +50 -0
  176. package/dist/lib/daemon-services.js +147 -0
  177. package/dist/lib/daemon-ticks.d.ts +35 -66
  178. package/dist/lib/daemon-ticks.js +77 -159
  179. package/dist/lib/daemon.d.ts +72 -4
  180. package/dist/lib/daemon.js +792 -202
  181. package/dist/lib/deeplink/register.d.ts +49 -0
  182. package/dist/lib/deeplink/register.js +253 -0
  183. package/dist/lib/deeplink/url.d.ts +34 -0
  184. package/dist/lib/deeplink/url.js +78 -0
  185. package/dist/lib/device-config.d.ts +124 -29
  186. package/dist/lib/device-config.js +346 -141
  187. package/dist/lib/devices/config-migration.d.ts +42 -0
  188. package/dist/lib/devices/config-migration.js +203 -0
  189. package/dist/lib/devices/connect.js +14 -7
  190. package/dist/lib/devices/doctor-findings.d.ts +4 -1
  191. package/dist/lib/devices/doctor-findings.js +20 -1
  192. package/dist/lib/devices/harness-inventory.d.ts +11 -2
  193. package/dist/lib/devices/harness-inventory.js +0 -0
  194. package/dist/lib/devices/health.d.ts +1 -1
  195. package/dist/lib/devices/health.js +1 -1
  196. package/dist/lib/devices/pending.d.ts +22 -1
  197. package/dist/lib/devices/pending.js +67 -2
  198. package/dist/lib/devices/registry.d.ts +0 -25
  199. package/dist/lib/devices/registry.js +2 -83
  200. package/dist/lib/devices/resolve-profile.d.ts +20 -0
  201. package/dist/lib/devices/resolve-profile.js +44 -0
  202. package/dist/lib/devices/rollout-verify.d.ts +101 -0
  203. package/dist/lib/devices/rollout-verify.js +193 -0
  204. package/dist/lib/devices/ssh-config.js +10 -6
  205. package/dist/lib/event-families.d.ts +28 -0
  206. package/dist/lib/event-families.js +159 -0
  207. package/dist/lib/event-stream.d.ts +9 -1
  208. package/dist/lib/event-stream.js +26 -9
  209. package/dist/lib/events.d.ts +9 -1
  210. package/dist/lib/events.js +21 -6
  211. package/dist/lib/exec.d.ts +30 -0
  212. package/dist/lib/exec.js +220 -122
  213. package/dist/lib/feed-broadcast.d.ts +25 -0
  214. package/dist/lib/feed-broadcast.js +33 -0
  215. package/dist/lib/feed.d.ts +1 -1
  216. package/dist/lib/feed.js +12 -2
  217. package/dist/lib/fleet/capture.js +15 -0
  218. package/dist/lib/fleet/manifest.js +9 -0
  219. package/dist/lib/fleet/types.d.ts +9 -0
  220. package/dist/lib/fleet-status.js +10 -8
  221. package/dist/lib/git.d.ts +20 -6
  222. package/dist/lib/git.js +121 -17
  223. package/dist/lib/hosts/dispatch.d.ts +8 -3
  224. package/dist/lib/hosts/dispatch.js +29 -3
  225. package/dist/lib/hosts/logs.d.ts +2 -2
  226. package/dist/lib/hosts/logs.js +2 -2
  227. package/dist/lib/hosts/option.js +1 -1
  228. package/dist/lib/hosts/passthrough.d.ts +2 -3
  229. package/dist/lib/hosts/passthrough.js +10 -24
  230. package/dist/lib/hosts/progress.js +2 -2
  231. package/dist/lib/hosts/providers/devices.d.ts +3 -3
  232. package/dist/lib/hosts/providers/devices.js +18 -12
  233. package/dist/lib/hosts/ready.d.ts +5 -1
  234. package/dist/lib/hosts/ready.js +9 -3
  235. package/dist/lib/hosts/reconcile.d.ts +2 -2
  236. package/dist/lib/hosts/reconcile.js +2 -2
  237. package/dist/lib/hosts/registry.js +14 -9
  238. package/dist/lib/hosts/remote-cmd.js +1 -1
  239. package/dist/lib/hosts/remote-os.d.ts +9 -6
  240. package/dist/lib/hosts/remote-os.js +13 -6
  241. package/dist/lib/hosts/routing-flag.d.ts +23 -0
  242. package/dist/lib/hosts/routing-flag.js +41 -0
  243. package/dist/lib/hosts/run-target.js +1 -1
  244. package/dist/lib/hosts/session-index.js +1 -1
  245. package/dist/lib/hosts/tasks.d.ts +6 -6
  246. package/dist/lib/hosts/tasks.js +4 -4
  247. package/dist/lib/hosts/types.js +1 -2
  248. package/dist/lib/installations/resolve.js +2 -8
  249. package/dist/lib/isolation-boundary-report.js +0 -1
  250. package/dist/lib/linear-cache.d.ts +7 -0
  251. package/dist/lib/linear-cache.js +31 -4
  252. package/dist/lib/linear-project-counts.d.ts +1 -1
  253. package/dist/lib/linear-project-counts.js +2 -3
  254. package/dist/lib/linear-projects.js +1 -1
  255. package/dist/lib/loop.d.ts +2 -2
  256. package/dist/lib/loop.js +1 -1
  257. package/dist/lib/mailbox-target.d.ts +1 -1
  258. package/dist/lib/mailbox-target.js +1 -1
  259. package/dist/lib/manifest.js +7 -4
  260. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  261. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  262. package/dist/lib/menubar/snapshot.d.ts +3 -2
  263. package/dist/lib/menubar/snapshot.js +6 -2
  264. package/dist/lib/migrate-fold.d.ts +33 -0
  265. package/dist/lib/migrate-fold.js +130 -0
  266. package/dist/lib/migrate.d.ts +34 -34
  267. package/dist/lib/migrate.js +106 -128
  268. package/dist/lib/model-tier-overrides.d.ts +1 -1
  269. package/dist/lib/model-tier-overrides.js +15 -2
  270. package/dist/lib/monitors/config.d.ts +17 -3
  271. package/dist/lib/monitors/config.js +52 -18
  272. package/dist/lib/monitors/engine.d.ts +32 -1
  273. package/dist/lib/monitors/engine.js +94 -11
  274. package/dist/lib/monitors/fingerprint.d.ts +46 -0
  275. package/dist/lib/monitors/fingerprint.js +100 -0
  276. package/dist/lib/monitors/remote.d.ts +47 -0
  277. package/dist/lib/monitors/remote.js +81 -0
  278. package/dist/lib/monitors/state.d.ts +39 -0
  279. package/dist/lib/monitors/state.js +56 -0
  280. package/dist/lib/onepassword.d.ts +17 -0
  281. package/dist/lib/onepassword.js +52 -22
  282. package/dist/lib/open-url.js +1 -1
  283. package/dist/lib/picker.d.ts +14 -2
  284. package/dist/lib/picker.js +35 -13
  285. package/dist/lib/placement.d.ts +1 -1
  286. package/dist/lib/placement.js +1 -1
  287. package/dist/lib/pr-land-detach.d.ts +32 -0
  288. package/dist/lib/pr-land-detach.js +79 -0
  289. package/dist/lib/profiles-presets.js +13 -0
  290. package/dist/lib/profiles.d.ts +2 -0
  291. package/dist/lib/profiles.js +44 -1
  292. package/dist/lib/project-focus.d.ts +1 -1
  293. package/dist/lib/project-focus.js +1 -1
  294. package/dist/lib/project-key.d.ts +17 -0
  295. package/dist/lib/project-key.js +26 -0
  296. package/dist/lib/project-probe.d.ts +4 -1
  297. package/dist/lib/project-probe.js +5 -4
  298. package/dist/lib/project-resources.js +2 -18
  299. package/dist/lib/project-root.d.ts +16 -0
  300. package/dist/lib/project-root.js +20 -2
  301. package/dist/lib/projects.d.ts +20 -1
  302. package/dist/lib/projects.js +78 -1
  303. package/dist/lib/refresh-coordinator.d.ts +24 -0
  304. package/dist/lib/refresh-coordinator.js +52 -0
  305. package/dist/lib/registry.d.ts +2 -2
  306. package/dist/lib/registry.js +1 -1
  307. package/dist/lib/resource-aliases.d.ts +13 -0
  308. package/dist/lib/resource-aliases.js +26 -0
  309. package/dist/lib/resources/types.d.ts +1 -1
  310. package/dist/lib/resources.d.ts +16 -0
  311. package/dist/lib/resources.js +66 -10
  312. package/dist/lib/rotate.d.ts +3 -4
  313. package/dist/lib/rotate.js +4 -5
  314. package/dist/lib/routine-activation.d.ts +22 -2
  315. package/dist/lib/routine-activation.js +63 -16
  316. package/dist/lib/routine-context.d.ts +9 -2
  317. package/dist/lib/routine-context.js +21 -6
  318. package/dist/lib/routines-project.d.ts +58 -48
  319. package/dist/lib/routines-project.js +190 -159
  320. package/dist/lib/routines.d.ts +41 -6
  321. package/dist/lib/routines.js +92 -34
  322. package/dist/lib/run-defaults.d.ts +5 -0
  323. package/dist/lib/run-defaults.js +11 -1
  324. package/dist/lib/runner.d.ts +10 -8
  325. package/dist/lib/runner.js +122 -39
  326. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  327. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  328. package/dist/lib/secrets/agent.d.ts +10 -3
  329. package/dist/lib/secrets/agent.js +43 -8
  330. package/dist/lib/secrets/bundles.d.ts +1 -0
  331. package/dist/lib/secrets/bundles.js +92 -80
  332. package/dist/lib/secrets/index.js +32 -9
  333. package/dist/lib/secrets/install-helper.d.ts +4 -4
  334. package/dist/lib/secrets/install-helper.js +4 -4
  335. package/dist/lib/secrets/push.d.ts +40 -6
  336. package/dist/lib/secrets/push.js +58 -11
  337. package/dist/lib/secrets/read-backoff.d.ts +1 -1
  338. package/dist/lib/secrets/read-backoff.js +1 -1
  339. package/dist/lib/secrets/remote.d.ts +24 -0
  340. package/dist/lib/secrets/remote.js +54 -4
  341. package/dist/lib/self-update.d.ts +108 -0
  342. package/dist/lib/self-update.js +276 -1
  343. package/dist/lib/session/active.d.ts +89 -5
  344. package/dist/lib/session/active.js +165 -10
  345. package/dist/lib/session/actor-sidecar.d.ts +1 -1
  346. package/dist/lib/session/actor-sidecar.js +2 -1
  347. package/dist/lib/session/db.d.ts +176 -2
  348. package/dist/lib/session/db.js +484 -17
  349. package/dist/lib/session/discover.js +27 -4
  350. package/dist/lib/session/hook-sessions.js +2 -2
  351. package/dist/lib/session/host-link.d.ts +2 -2
  352. package/dist/lib/session/host-link.js +2 -2
  353. package/dist/lib/session/pid-registry.d.ts +21 -0
  354. package/dist/lib/session/pid-registry.js +57 -0
  355. package/dist/lib/session/remote-active.js +15 -1
  356. package/dist/lib/session/remote.js +2 -2
  357. package/dist/lib/session/session-cache.d.ts +14 -7
  358. package/dist/lib/session/session-cache.js +51 -9
  359. package/dist/lib/session/state.d.ts +2 -2
  360. package/dist/lib/session/state.js +1 -1
  361. package/dist/lib/session/sync/config.d.ts +10 -10
  362. package/dist/lib/session/sync/config.js +10 -10
  363. package/dist/lib/session/sync/r2.d.ts +34 -0
  364. package/dist/lib/session/sync/r2.js +123 -0
  365. package/dist/lib/session/throughput.d.ts +1 -1
  366. package/dist/lib/session/throughput.js +1 -1
  367. package/dist/lib/session/types.d.ts +23 -1
  368. package/dist/lib/session/types.js +15 -0
  369. package/dist/lib/session/viewing-in.d.ts +1 -1
  370. package/dist/lib/session/viewing-in.js +1 -1
  371. package/dist/lib/session/watch.d.ts +101 -0
  372. package/dist/lib/session/watch.js +242 -0
  373. package/dist/lib/share/config.d.ts +4 -0
  374. package/dist/lib/share/config.js +1 -0
  375. package/dist/lib/share/delete.d.ts +93 -0
  376. package/dist/lib/share/delete.js +127 -0
  377. package/dist/lib/share/provision.d.ts +38 -0
  378. package/dist/lib/share/provision.js +50 -0
  379. package/dist/lib/share/publish.d.ts +40 -1
  380. package/dist/lib/share/publish.js +116 -3
  381. package/dist/lib/share/worker-template.js +71 -6
  382. package/dist/lib/shims.d.ts +17 -3
  383. package/dist/lib/shims.js +136 -27
  384. package/dist/lib/signin-badge.js +3 -2
  385. package/dist/lib/skills.js +2 -0
  386. package/dist/lib/smart-launch.d.ts +8 -8
  387. package/dist/lib/smart-launch.js +80 -59
  388. package/dist/lib/ssh-exec.d.ts +1 -1
  389. package/dist/lib/ssh-exec.js +1 -1
  390. package/dist/lib/staleness/prune.d.ts +88 -0
  391. package/dist/lib/staleness/prune.js +69 -0
  392. package/dist/lib/staleness/registry.d.ts +1 -1
  393. package/dist/lib/staleness/writers/commands.js +34 -2
  394. package/dist/lib/staleness/writers/hooks.js +16 -0
  395. package/dist/lib/staleness/writers/kinds.d.ts +6 -0
  396. package/dist/lib/staleness/writers/skills.js +19 -0
  397. package/dist/lib/staleness/writers/subagents.d.ts +2 -3
  398. package/dist/lib/staleness/writers/subagents.js +0 -4
  399. package/dist/lib/staleness/writers/types.d.ts +32 -0
  400. package/dist/lib/startup/command-registry.d.ts +6 -12
  401. package/dist/lib/startup/command-registry.js +14 -31
  402. package/dist/lib/startup/dev-build.d.ts +10 -0
  403. package/dist/lib/startup/dev-build.js +13 -1
  404. package/dist/lib/startup/spellcheck.d.ts +18 -0
  405. package/dist/lib/startup/spellcheck.js +45 -0
  406. package/dist/lib/state.d.ts +36 -9
  407. package/dist/lib/state.js +96 -46
  408. package/dist/lib/subagents-registry.d.ts +0 -7
  409. package/dist/lib/subagents-registry.js +38 -65
  410. package/dist/lib/subagents.d.ts +0 -33
  411. package/dist/lib/subagents.js +0 -75
  412. package/dist/lib/sync-umbrella.js +1 -1
  413. package/dist/lib/teams/agents.d.ts +41 -1
  414. package/dist/lib/teams/agents.js +187 -9
  415. package/dist/lib/teams/api.d.ts +11 -1
  416. package/dist/lib/teams/api.js +11 -2
  417. package/dist/lib/teams/delivery.d.ts +41 -0
  418. package/dist/lib/teams/delivery.js +60 -0
  419. package/dist/lib/teams/registry.d.ts +14 -0
  420. package/dist/lib/teams/registry.js +51 -1
  421. package/dist/lib/teams/remoteWorktree.d.ts +19 -0
  422. package/dist/lib/teams/remoteWorktree.js +29 -0
  423. package/dist/lib/teams/scheduler.d.ts +1 -1
  424. package/dist/lib/teams/scheduler.js +1 -1
  425. package/dist/lib/teams/worktree.d.ts +24 -0
  426. package/dist/lib/teams/worktree.js +42 -0
  427. package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
  428. package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
  429. package/dist/lib/terminal/engine.d.ts +4 -0
  430. package/dist/lib/terminal/engine.js +8 -2
  431. package/dist/lib/terminal/types.d.ts +21 -2
  432. package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
  433. package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
  434. package/dist/lib/tickets/list.d.ts +53 -0
  435. package/dist/lib/tickets/list.js +153 -0
  436. package/dist/lib/tmux/orphan-reap.d.ts +320 -0
  437. package/dist/lib/tmux/orphan-reap.js +644 -0
  438. package/dist/lib/tmux/session.d.ts +68 -3
  439. package/dist/lib/tmux/session.js +95 -5
  440. package/dist/lib/triggers/handlers.d.ts +20 -0
  441. package/dist/lib/triggers/handlers.js +6 -1
  442. package/dist/lib/types.d.ts +46 -34
  443. package/dist/lib/usage-fleet.d.ts +32 -0
  444. package/dist/lib/usage-fleet.js +125 -0
  445. package/dist/lib/usage-refresh.d.ts +3 -3
  446. package/dist/lib/usage-refresh.js +19 -16
  447. package/dist/lib/usage.d.ts +51 -47
  448. package/dist/lib/usage.js +145 -153
  449. package/dist/lib/version-duplicates.js +2 -2
  450. package/dist/lib/versions.d.ts +56 -13
  451. package/dist/lib/versions.js +195 -45
  452. package/dist/lib/watchdog/log.d.ts +1 -1
  453. package/dist/lib/watchdog/log.js +3 -3
  454. package/dist/lib/watchdog/rotate.d.ts +6 -6
  455. package/dist/lib/watchdog/rotate.js +6 -6
  456. package/dist/lib/workflows.d.ts +1 -1
  457. package/dist/lib/yaml-io.d.ts +47 -0
  458. package/dist/lib/yaml-io.js +55 -0
  459. package/package.json +2 -1
  460. package/scripts/install-helper.js +2 -2
  461. package/scripts/postinstall.js +23 -20
  462. package/dist/commands/defaults.d.ts +0 -7
  463. package/dist/commands/defaults.js +0 -107
  464. package/dist/commands/export.d.ts +0 -11
  465. package/dist/commands/export.js +0 -215
  466. package/dist/commands/helper.d.ts +0 -12
  467. package/dist/commands/helper.js +0 -87
  468. package/dist/commands/hosts.d.ts +0 -11
  469. package/dist/commands/hosts.js +0 -330
  470. package/dist/commands/lock.d.ts +0 -12
  471. package/dist/commands/lock.js +0 -70
  472. package/dist/commands/pull.d.ts +0 -17
  473. package/dist/commands/pull.js +0 -39
  474. package/dist/commands/push.d.ts +0 -14
  475. package/dist/commands/push.js +0 -30
  476. package/dist/commands/wallet.d.ts +0 -20
  477. package/dist/commands/wallet.js +0 -216
  478. package/dist/commands/worktree.d.ts +0 -19
  479. package/dist/commands/worktree.js +0 -272
  480. package/dist/lib/account-labels.d.ts +0 -24
  481. package/dist/lib/account-labels.js +0 -72
  482. package/dist/lib/auto-dispatch-linear.d.ts +0 -18
  483. package/dist/lib/auto-dispatch-linear.js +0 -107
  484. package/dist/lib/auto-dispatch-provider.d.ts +0 -10
  485. package/dist/lib/auto-dispatch-provider.js +0 -30
  486. package/dist/lib/auto-dispatch.d.ts +0 -93
  487. package/dist/lib/auto-dispatch.js +0 -128
  488. package/dist/lib/export.d.ts +0 -72
  489. package/dist/lib/export.js +0 -269
  490. package/dist/lib/lock.d.ts +0 -93
  491. package/dist/lib/lock.js +0 -207
  492. package/dist/lib/wallet/index.d.ts +0 -78
  493. package/dist/lib/wallet/index.js +0 -253
@@ -18,6 +18,12 @@ export interface TeamMeta {
18
18
  * `origin` at create time. Used by `ensureRemoteRepo` to provision the repo.
19
19
  */
20
20
  repo?: string;
21
+ /**
22
+ * The project (`agents projects`) this team works on. Its primary directory
23
+ * is a local teammate's base cwd when neither `--cwd` nor a worktree gives
24
+ * one, and its other bound directories become `--add-dir` grants.
25
+ */
26
+ project?: string;
21
27
  }
22
28
  /** Map of team name to team metadata. */
23
29
  export type TeamRegistry = Record<string, TeamMeta>;
@@ -37,11 +43,19 @@ export interface CreateTeamOptions {
37
43
  devices?: string[];
38
44
  /** How each device gets the code (git URL to clone, or a path on the host). */
39
45
  repo?: string;
46
+ /** The `agents projects` project this team works on. */
47
+ project?: string;
40
48
  }
41
49
  /** Create a new team. Throws if a team with the same name already exists. */
42
50
  export declare function createTeam(name: string, options?: CreateTeamOptions): Promise<TeamMeta>;
43
51
  /** Return existing team metadata or create a new team if it does not exist. */
44
52
  export declare function ensureTeam(name: string): Promise<TeamMeta>;
53
+ /** Mark a team as disbanded so saveMeta will not resurrect its teammates. */
54
+ export declare function markTeamDisbanded(name: string): Promise<void>;
55
+ /** Clear a disband tombstone — called when the name is re-created. */
56
+ export declare function clearTeamDisbanded(name: string): Promise<void>;
57
+ /** True when the team was disbanded and has not been re-created since. */
58
+ export declare function isTeamDisbanded(name: string): Promise<boolean>;
45
59
  /** Remove a team from the registry. Returns false if the team did not exist. */
46
60
  export declare function removeTeam(name: string): Promise<boolean>;
47
61
  /** Check whether a team with the given name exists in the registry. */
@@ -111,11 +111,15 @@ export async function createTeam(name, options) {
111
111
  ...(options?.useWorktree ? { use_worktree: options.useWorktree } : {}),
112
112
  ...(options?.devices && options.devices.length ? { devices: options.devices } : {}),
113
113
  ...(options?.repo ? { repo: options.repo } : {}),
114
+ ...(options?.project ? { project: options.project } : {}),
114
115
  };
115
116
  reg[name] = m;
116
117
  await saveTeams(reg);
117
118
  return m;
118
119
  });
120
+ // A re-created name is a fresh team — drop any prior disband tombstone so
121
+ // saveMeta will persist new teammates again (RUSH-2450).
122
+ await clearTeamDisbanded(name);
119
123
  // Audit the lifecycle boundary, not the CLI shell — captures every creation
120
124
  // path (create + ensure) with team metadata the generic command log lacks.
121
125
  emit('teams.create', { module: 'teams', team: name, worktrees: Boolean(options?.enableWorktrees || options?.useWorktree) });
@@ -137,10 +141,52 @@ export async function ensureTeam(name) {
137
141
  });
138
142
  // `teams add` auto-creates the team on first teammate — audit that creation
139
143
  // too, but only when it actually happened (not the get-existing path).
140
- if (created)
144
+ if (created) {
145
+ await clearTeamDisbanded(name);
141
146
  emit('teams.create', { module: 'teams', team: name, worktrees: false });
147
+ }
142
148
  return meta;
143
149
  }
150
+ /**
151
+ * Tombstone dir for disbanded teams (RUSH-2450). Lives next to the registry so
152
+ * a long-lived supervisor can see that a team was deliberately removed and
153
+ * refuse to re-persist its in-memory AgentProcess objects via saveMeta.
154
+ * Cleared on create/ensure so a re-used name is a fresh team.
155
+ */
156
+ function disbandedDir() {
157
+ return path.join(path.dirname(getTeamsRegistryPath()), 'disbanded');
158
+ }
159
+ function disbandedPath(name) {
160
+ // Encode the name so a team called `../x` cannot escape the dir.
161
+ const safe = Buffer.from(name, 'utf8').toString('base64url');
162
+ return path.join(disbandedDir(), `${safe}.json`);
163
+ }
164
+ /** Mark a team as disbanded so saveMeta will not resurrect its teammates. */
165
+ export async function markTeamDisbanded(name) {
166
+ const dir = disbandedDir();
167
+ await fs.mkdir(dir, { recursive: true });
168
+ await fs.writeFile(disbandedPath(name), JSON.stringify({ team: name, disbanded_at: new Date().toISOString() }), 'utf-8');
169
+ }
170
+ /** Clear a disband tombstone — called when the name is re-created. */
171
+ export async function clearTeamDisbanded(name) {
172
+ try {
173
+ await fs.unlink(disbandedPath(name));
174
+ }
175
+ catch (err) {
176
+ if (err?.code !== 'ENOENT')
177
+ throw err;
178
+ }
179
+ }
180
+ /** True when the team was disbanded and has not been re-created since. */
181
+ export async function isTeamDisbanded(name) {
182
+ try {
183
+ await fs.access(disbandedPath(name));
184
+ return true;
185
+ }
186
+ catch {
187
+ return false;
188
+ }
189
+ }
144
190
  /** Remove a team from the registry. Returns false if the team did not exist. */
145
191
  export async function removeTeam(name) {
146
192
  const p = await registryPath();
@@ -152,6 +198,10 @@ export async function removeTeam(name) {
152
198
  await saveTeams(reg);
153
199
  return true;
154
200
  });
201
+ // Always stamp the tombstone when removeTeam is invoked from disband — even
202
+ // if the registry entry was already gone, so a concurrent supervisor still
203
+ // sees the disband. Idempotent.
204
+ await markTeamDisbanded(name);
155
205
  // "Disband" — only fires when a real team was removed, not a no-op.
156
206
  if (existed)
157
207
  emit('teams.disband', { module: 'teams', team: name });
@@ -34,6 +34,25 @@ export declare function remoteDefaultBranch(target: string, repoPath: string, op
34
34
  * teammate off old code.
35
35
  */
36
36
  export declare function createRemoteWorktree(target: string, repoPath: string, worktreeName: string, opts?: RemoteSshOptions): string;
37
+ /**
38
+ * How many commits the host checkout at `repoPath` is behind `origin/<default>` —
39
+ * the remote analog of the local {@link commitsBehindDefault} staleness probe, and
40
+ * the exact case from the incident this guard exists for (a distributed team
41
+ * pointed at a 71-commit-stale checkout on another box).
42
+ *
43
+ * `ensureRemoteRepo` already fetched `origin` when it provisioned/reused the
44
+ * checkout right before this runs, so the remote-tracking ref is usually fresh and
45
+ * this reads it WITHOUT a second fetch: resolve the default branch, then
46
+ * `rev-list --count HEAD..origin/<default>`. (That reuse fetch is best-effort —
47
+ * an offline host leaves the ref stale, so this under-reports rather than blocks;
48
+ * `createRemoteWorktree` re-fetches at launch so the teammate's base is still
49
+ * fresh regardless.) Returns null on any git/ssh error (unreachable host, non-repo
50
+ * path) — the caller treats null as "can't tell, don't block".
51
+ */
52
+ export declare function remoteCommitsBehindDefault(target: string, repoPath: string, opts?: RemoteSshOptions): {
53
+ behind: number;
54
+ base: string;
55
+ } | null;
37
56
  /**
38
57
  * Ensure the team's repo is present on the host and return its absolute git
39
58
  * root. The canonical location is `~/.agents/repos/<slug>` (slug = sanitized
@@ -102,6 +102,35 @@ export function createRemoteWorktree(target, repoPath, worktreeName, opts = {})
102
102
  remoteGit(target, gitRoot, ['worktree', 'add', '-b', branchName, worktreePath, `origin/${base}`], 120000, opts);
103
103
  return worktreePath;
104
104
  }
105
+ /**
106
+ * How many commits the host checkout at `repoPath` is behind `origin/<default>` —
107
+ * the remote analog of the local {@link commitsBehindDefault} staleness probe, and
108
+ * the exact case from the incident this guard exists for (a distributed team
109
+ * pointed at a 71-commit-stale checkout on another box).
110
+ *
111
+ * `ensureRemoteRepo` already fetched `origin` when it provisioned/reused the
112
+ * checkout right before this runs, so the remote-tracking ref is usually fresh and
113
+ * this reads it WITHOUT a second fetch: resolve the default branch, then
114
+ * `rev-list --count HEAD..origin/<default>`. (That reuse fetch is best-effort —
115
+ * an offline host leaves the ref stale, so this under-reports rather than blocks;
116
+ * `createRemoteWorktree` re-fetches at launch so the teammate's base is still
117
+ * fresh regardless.) Returns null on any git/ssh error (unreachable host, non-repo
118
+ * path) — the caller treats null as "can't tell, don't block".
119
+ */
120
+ export function remoteCommitsBehindDefault(target, repoPath, opts = {}) {
121
+ assertValidSshTarget(target);
122
+ try {
123
+ const base = remoteDefaultBranch(target, repoPath, opts);
124
+ const raw = remoteGit(target, repoPath, ['rev-list', '--count', `HEAD..origin/${base}`], 30000, opts);
125
+ const behind = parseInt(raw, 10);
126
+ if (!Number.isFinite(behind))
127
+ return null;
128
+ return { behind, base };
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
105
134
  // Team-name → repos-dir slug: same allowlist a worktree name uses, so it lands
106
135
  // safely in a path (`~/.agents/repos/<slug>`) with no shell metacharacters.
107
136
  const SLUG_RE = /[^A-Za-z0-9_-]/g;
@@ -30,7 +30,7 @@ export interface PlacementTeam {
30
30
  * device name to its `agents.max-concurrent` cap (from the device doc — read
31
31
  * locally via `readMaxConcurrentCaps`, never probed over SSH). Teams counts
32
32
  * the team's OWN roster against the cap (device-global counting would need an
33
- * SSH probe per candidate — out of the hot path; Factory auto-launch is the
33
+ * SSH probe per candidate — out of the hot path; AGI EXT auto-launch is the
34
34
  * device-wide counter). Only the least-loaded AUTO-PICK (cascade step 3)
35
35
  * honors caps: an explicit pin or a pool of one is the user's own choice and
36
36
  * is never second-guessed.
@@ -132,7 +132,7 @@ export function pickLeastLoaded(devices, roster, maxConcurrent) {
132
132
  .map((d) => `${d} (${load.get(d) ?? 0}/${maxConcurrent[d]})`)
133
133
  .join(', ');
134
134
  throw new Error(`Every device in the pool is at its agents.max-concurrent cap: ${detail}. ` +
135
- `Raise a cap with 'agents devices configure <name> --max-agents N' or add a device to the pool.`);
135
+ `Raise a cap with 'agents devices config <name> agents.max-concurrent N' or add a device to the pool.`);
136
136
  }
137
137
  // Iterate the pool in declared order so the first device wins ties.
138
138
  let best = eligible[0];
@@ -27,6 +27,30 @@ export declare function gitDiff(worktreePath: string, maxBytes?: number): Promis
27
27
  * Falls back to `main` when origin/HEAD isn't set.
28
28
  */
29
29
  export declare function localDefaultBranch(gitRoot: string): Promise<string>;
30
+ /**
31
+ * How many commits the checkout at `repoDir` is behind freshly-fetched
32
+ * `origin/<default>` — the staleness the `teams add` guard checks before pointing
33
+ * a team at a repo.
34
+ *
35
+ * Fetches `origin` FIRST, on purpose: the exact failure this guards (a team
36
+ * pointed at a repo "without fetching first" — a 71-commit-stale s1 checkout in
37
+ * the real incident) leaves the remote-tracking ref itself stale, so a naive
38
+ * `HEAD..origin/<default>` reads 0 and hides the drift. After the fetch the count
39
+ * is against the true remote.
40
+ *
41
+ * Measures the passed checkout's OWN root ({@link getGitRoot} / `--show-toplevel`,
42
+ * worktree-correct) — NOT {@link getMainRepoRoot}: for a `--use-worktree` shared
43
+ * worktree (or a caller standing inside a linked worktree), the teammate runs in
44
+ * THAT worktree, whose HEAD differs from the main checkout's, so folding to the
45
+ * main root would report the wrong tree's staleness. `origin/<default>` resolves
46
+ * from the shared object store regardless of which worktree we stand in. Returns
47
+ * null when `repoDir` isn't a git repo, origin is unreachable, or git errors — the
48
+ * caller treats null as "can't tell, don't block".
49
+ */
50
+ export declare function commitsBehindDefault(repoDir: string): Promise<{
51
+ behind: number;
52
+ base: string;
53
+ } | null>;
30
54
  /**
31
55
  * Create a new git worktree for a teammate, branched off the freshly-fetched
32
56
  * default branch. Fetches `origin` first and bases the branch on
@@ -100,6 +100,48 @@ export async function localDefaultBranch(gitRoot) {
100
100
  }
101
101
  return 'main';
102
102
  }
103
+ /**
104
+ * How many commits the checkout at `repoDir` is behind freshly-fetched
105
+ * `origin/<default>` — the staleness the `teams add` guard checks before pointing
106
+ * a team at a repo.
107
+ *
108
+ * Fetches `origin` FIRST, on purpose: the exact failure this guards (a team
109
+ * pointed at a repo "without fetching first" — a 71-commit-stale s1 checkout in
110
+ * the real incident) leaves the remote-tracking ref itself stale, so a naive
111
+ * `HEAD..origin/<default>` reads 0 and hides the drift. After the fetch the count
112
+ * is against the true remote.
113
+ *
114
+ * Measures the passed checkout's OWN root ({@link getGitRoot} / `--show-toplevel`,
115
+ * worktree-correct) — NOT {@link getMainRepoRoot}: for a `--use-worktree` shared
116
+ * worktree (or a caller standing inside a linked worktree), the teammate runs in
117
+ * THAT worktree, whose HEAD differs from the main checkout's, so folding to the
118
+ * main root would report the wrong tree's staleness. `origin/<default>` resolves
119
+ * from the shared object store regardless of which worktree we stand in. Returns
120
+ * null when `repoDir` isn't a git repo, origin is unreachable, or git errors — the
121
+ * caller treats null as "can't tell, don't block".
122
+ */
123
+ export async function commitsBehindDefault(repoDir) {
124
+ const gitRoot = await getGitRoot(repoDir).catch(() => null);
125
+ if (!gitRoot)
126
+ return null;
127
+ try {
128
+ await execFileAsync('git', ['fetch', 'origin'], { cwd: gitRoot });
129
+ }
130
+ catch {
131
+ return null; // offline / no origin — can't assess staleness, don't block a team.
132
+ }
133
+ const base = await localDefaultBranch(gitRoot);
134
+ try {
135
+ const { stdout } = await execFileAsync('git', ['rev-list', '--count', `HEAD..origin/${base}`], { cwd: gitRoot });
136
+ const behind = parseInt(stdout.trim(), 10);
137
+ if (!Number.isFinite(behind))
138
+ return null;
139
+ return { behind, base };
140
+ }
141
+ catch {
142
+ return null; // no origin/<default> tracking ref, detached probe, etc.
143
+ }
144
+ }
103
145
  /**
104
146
  * Create a new git worktree for a teammate, branched off the freshly-fetched
105
147
  * default branch. Fetches `origin` first and bases the branch on
@@ -23,8 +23,17 @@ export declare const EDITOR_VARIANTS: EditorVariant[];
23
23
  * it, so a `command`/`cwd` containing `&` (or `=`) would be mis-split by a naive
24
24
  * multi-param query. base64url is `[A-Za-z0-9_-]` only (no `&`, `=`, `%`, `+`,
25
25
  * `/`), so it survives that decode untouched and round-trips exactly.
26
+ *
27
+ * Optional `meta.agent` / `meta.sessionId` / `meta.title` let the extension set
28
+ * the tab chip and status bar without sniffing the local process tree — required
29
+ * when `command` is a remote attach (`ssh … tmux attach`) with no agent binary
30
+ * on this box (#2478).
26
31
  */
27
- export declare function spawnUri(scheme: string, cwd: string, command: string[], direction?: SplitDirection): string;
32
+ export declare function spawnUri(scheme: string, cwd: string, command: string[], direction?: SplitDirection, meta?: {
33
+ agent?: string;
34
+ sessionId?: string;
35
+ title?: string;
36
+ }): string;
28
37
  /** Build a backend bound to one editor variant. */
29
38
  export declare function makeVscodiumAgentBackend(variant: EditorVariant): TerminalBackend;
30
39
  /** Default backend: VSCodium (`codium` CLI, `vscodium://` scheme). */
@@ -41,14 +41,25 @@ function appExists(p) {
41
41
  * it, so a `command`/`cwd` containing `&` (or `=`) would be mis-split by a naive
42
42
  * multi-param query. base64url is `[A-Za-z0-9_-]` only (no `&`, `=`, `%`, `+`,
43
43
  * `/`), so it survives that decode untouched and round-trips exactly.
44
+ *
45
+ * Optional `meta.agent` / `meta.sessionId` / `meta.title` let the extension set
46
+ * the tab chip and status bar without sniffing the local process tree — required
47
+ * when `command` is a remote attach (`ssh … tmux attach`) with no agent binary
48
+ * on this box (#2478).
44
49
  */
45
- export function spawnUri(scheme, cwd, command, direction) {
50
+ export function spawnUri(scheme, cwd, command, direction, meta) {
46
51
  const payload = {
47
52
  command: command.join(' '),
48
53
  cwd,
49
54
  };
50
55
  if (direction)
51
56
  payload.split = direction;
57
+ if (meta?.agent)
58
+ payload.agent = meta.agent;
59
+ if (meta?.sessionId)
60
+ payload.sessionId = meta.sessionId;
61
+ if (meta?.title)
62
+ payload.title = meta.title;
52
63
  const p = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');
53
64
  return `${scheme}://${EXTENSION_AUTHORITY}/spawn?p=${p}`;
54
65
  }
@@ -60,11 +71,11 @@ export function makeVscodiumAgentBackend(variant) {
60
71
  isAvailable(ctx) {
61
72
  return ctx.platform === 'darwin' && appExists(variant.app);
62
73
  },
63
- buildTab(cwd, command) {
64
- return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command)] };
74
+ buildTab(cwd, command, meta) {
75
+ return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, undefined, meta)] };
65
76
  },
66
- buildSplit(cwd, command, direction) {
67
- return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, direction)] };
77
+ buildSplit(cwd, command, direction, meta) {
78
+ return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, direction, meta)] };
68
79
  },
69
80
  };
70
81
  }
@@ -21,6 +21,10 @@ export declare function openSurface(req: LaunchRequest, opts?: OpenOptions): Pro
21
21
  export interface SurfaceItem {
22
22
  cwd: string;
23
23
  command: string[];
24
+ /** Optional harness identity for editor-backed backends (vscodium-agent). */
25
+ agent?: string;
26
+ sessionId?: string;
27
+ title?: string;
24
28
  }
25
29
  export interface BuildRequestsOptions {
26
30
  backend: Backend;
@@ -8,9 +8,12 @@ export function specForRequest(req) {
8
8
  const backend = BACKENDS[req.backend];
9
9
  if (!backend)
10
10
  throw new Error(`unknown backend: ${req.backend}`);
11
+ const meta = req.agent || req.sessionId || req.title
12
+ ? { agent: req.agent, sessionId: req.sessionId, title: req.title }
13
+ : undefined;
11
14
  if (req.layout === 'tab')
12
- return backend.buildTab(req.cwd, req.command);
13
- return backend.buildSplit(req.cwd, req.command, req.layout === 'split-down' ? 'down' : 'right');
15
+ return backend.buildTab(req.cwd, req.command, meta);
16
+ return backend.buildSplit(req.cwd, req.command, req.layout === 'split-down' ? 'down' : 'right', meta);
14
17
  }
15
18
  /** Open a single surface for one request. Never throws — failures come back in the result. */
16
19
  export async function openSurface(req, opts = {}) {
@@ -35,6 +38,9 @@ export function buildRequests(items, opts) {
35
38
  cwd: item.cwd,
36
39
  command: item.command,
37
40
  host: opts.host,
41
+ agent: item.agent,
42
+ sessionId: item.sessionId,
43
+ title: item.title,
38
44
  }));
39
45
  }
40
46
  /**
@@ -25,6 +25,21 @@ export interface LaunchSpec {
25
25
  /** argv to run (e.g. `['osascript','-e',script]` or `['tmux','split-window',…]`). */
26
26
  argv: string[];
27
27
  }
28
+ /**
29
+ * Optional identity the caller already knows about the surface. The
30
+ * vscodium-agent backend forwards these into the swarm-ext `/spawn` URI so the
31
+ * extension can set the tab chip/name/session without sniffing the local
32
+ * process tree (required for remote `ssh … tmux attach` resumes — #2478).
33
+ * Other backends ignore them.
34
+ */
35
+ export interface SurfaceMeta {
36
+ /** Harness id: claude, codex, grok, … */
37
+ agent?: string;
38
+ /** Canonical session id. */
39
+ sessionId?: string;
40
+ /** Optional pre-baked tab title. */
41
+ title?: string;
42
+ }
28
43
  /** A single "open this command as this surface" instruction. */
29
44
  export interface LaunchRequest {
30
45
  backend: Backend;
@@ -35,6 +50,10 @@ export interface LaunchRequest {
35
50
  command: string[];
36
51
  /** undefined / 'local' = this machine; otherwise a resolvable host alias. */
37
52
  host?: string;
53
+ /** Optional agent identity for editor-backed backends. */
54
+ agent?: string;
55
+ sessionId?: string;
56
+ title?: string;
38
57
  }
39
58
  /** Outcome of opening one surface. Never throws for launch failures — reports them. */
40
59
  export interface LaunchResult {
@@ -53,7 +72,7 @@ export interface TerminalBackend {
53
72
  /** Can this backend be driven here? (platform + app installed / inside tmux). */
54
73
  isAvailable(ctx: EngineContext): boolean;
55
74
  /** Command that opens a new tab running `command` in `cwd`. */
56
- buildTab(cwd: string, command: string[]): LaunchSpec;
75
+ buildTab(cwd: string, command: string[], meta?: SurfaceMeta): LaunchSpec;
57
76
  /** Command that splits the current surface, running `command` in `cwd`. */
58
- buildSplit(cwd: string, command: string[], direction: SplitDirection): LaunchSpec;
77
+ buildSplit(cwd: string, command: string[], direction: SplitDirection, meta?: SurfaceMeta): LaunchSpec;
59
78
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ import * as fs from 'node:fs';
2
+ import { setRefreshLockRootForTest, withRefreshLease } from '../refresh-coordinator.js';
3
+ const [lockRoot, resultPath, countPath, key] = process.argv.slice(2);
4
+ setRefreshLockRootForTest(lockRoot);
5
+ await withRefreshLease({
6
+ scope: 'cross-process-test',
7
+ key,
8
+ readCompleted: () => {
9
+ try {
10
+ return Number(fs.readFileSync(resultPath, 'utf-8'));
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ },
16
+ isCompleted: (value) => value === 1,
17
+ refresh: async () => {
18
+ fs.appendFileSync(countPath, 'refresh\n');
19
+ await new Promise((resolve) => setTimeout(resolve, 100));
20
+ fs.writeFileSync(resultPath, '1');
21
+ return 1;
22
+ },
23
+ });
@@ -0,0 +1,53 @@
1
+ export type TicketSource = 'linear' | 'github';
2
+ export interface TicketComment {
3
+ body: string;
4
+ createdAt?: string;
5
+ author?: string;
6
+ }
7
+ export interface TicketRow {
8
+ id: string;
9
+ source: TicketSource;
10
+ title: string;
11
+ description?: string;
12
+ status: 'todo' | 'in_progress' | 'done';
13
+ priority?: 'urgent' | 'high' | 'medium' | 'low';
14
+ metadata: {
15
+ identifier?: string;
16
+ url?: string;
17
+ labels?: string[];
18
+ assignee?: string;
19
+ assigneeKind?: 'user' | 'agent';
20
+ state?: string;
21
+ createdAt?: string;
22
+ dueDate?: string;
23
+ project?: string;
24
+ repo?: string;
25
+ comments?: TicketComment[];
26
+ images?: string[];
27
+ };
28
+ }
29
+ export interface TicketListResult {
30
+ tickets: TicketRow[];
31
+ cycleInfo: {
32
+ name: string;
33
+ startsAt: string;
34
+ endsAt: string;
35
+ } | null;
36
+ sources: {
37
+ linear: {
38
+ available: boolean;
39
+ error?: string;
40
+ };
41
+ github: {
42
+ available: boolean;
43
+ error?: string;
44
+ };
45
+ };
46
+ }
47
+ export interface TicketListOptions {
48
+ cwd: string;
49
+ linear: boolean;
50
+ github: boolean;
51
+ githubAssignedOnly: boolean;
52
+ }
53
+ export declare function listTickets(options: TicketListOptions): Promise<TicketListResult>;
@@ -0,0 +1,153 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const run = promisify(execFile);
4
+ const AGENT_ASSIGNEE = /^(claude|codex|gemini|cursor|opencode|antigravity|grok|kimi|droid)$/i;
5
+ function assigneeKind(name) {
6
+ if (!name)
7
+ return undefined;
8
+ return AGENT_ASSIGNEE.test(name.trim()) ? 'agent' : 'user';
9
+ }
10
+ function imageUrls(...bodies) {
11
+ const urls = new Set();
12
+ const pattern = /!\[[^\]]*\]\(\s*(https?:\/\/[^)\s]+)|<img\b[^>]*?\bsrc\s*=\s*["'](https?:\/\/[^"']+)/gi;
13
+ for (const body of bodies) {
14
+ if (typeof body !== 'string')
15
+ continue;
16
+ let match;
17
+ while ((match = pattern.exec(body)))
18
+ urls.add(match[1] || match[2]);
19
+ }
20
+ return urls.size > 0 ? [...urls] : undefined;
21
+ }
22
+ function errorMessage(error) {
23
+ if (error instanceof Error)
24
+ return error.message;
25
+ return String(error);
26
+ }
27
+ async function readLinear(cwd) {
28
+ const { stdout } = await run('linear', ['tasks', '--json'], {
29
+ cwd,
30
+ timeout: 15_000,
31
+ maxBuffer: 16 * 1024 * 1024,
32
+ });
33
+ const data = JSON.parse(stdout);
34
+ const cycle = data?.cycle;
35
+ const cycleInfo = cycle?.startsAt && cycle?.endsAt
36
+ ? { name: String(cycle.name ?? ''), startsAt: String(cycle.startsAt), endsAt: String(cycle.endsAt) }
37
+ : null;
38
+ const priority = {
39
+ 1: 'urgent',
40
+ 2: 'high',
41
+ 3: 'medium',
42
+ 4: 'low',
43
+ };
44
+ const tickets = (Array.isArray(data?.issues) ? data.issues : []).map((issue) => {
45
+ const labels = (issue.labels?.nodes ?? []).map((label) => String(label.name));
46
+ const comments = (issue.comments?.nodes ?? []).map((comment) => ({
47
+ body: String(comment.body ?? ''),
48
+ createdAt: comment.createdAt ? String(comment.createdAt) : undefined,
49
+ author: comment.user?.name ? String(comment.user.name) : undefined,
50
+ }));
51
+ const stateType = String(issue.state?.type ?? '');
52
+ const status = stateType === 'started'
53
+ ? 'in_progress'
54
+ : stateType === 'completed' || stateType === 'canceled'
55
+ ? 'done'
56
+ : 'todo';
57
+ const identifier = String(issue.identifier ?? issue.id ?? '');
58
+ return {
59
+ id: `linear:${identifier}`,
60
+ source: 'linear',
61
+ title: String(issue.title ?? ''),
62
+ description: issue.description ? String(issue.description) : undefined,
63
+ status,
64
+ priority: priority[Number(issue.priority)],
65
+ metadata: {
66
+ identifier,
67
+ url: issue.url ? String(issue.url) : undefined,
68
+ labels,
69
+ assignee: issue.assignee?.name ? String(issue.assignee.name) : undefined,
70
+ assigneeKind: assigneeKind(issue.assignee?.name),
71
+ state: issue.state?.name ? String(issue.state.name) : undefined,
72
+ createdAt: issue.createdAt ? String(issue.createdAt) : undefined,
73
+ dueDate: issue.dueDate ? String(issue.dueDate) : undefined,
74
+ project: issue.project?.name ? String(issue.project.name) : undefined,
75
+ comments,
76
+ images: imageUrls(issue.description, ...comments.map(comment => comment.body)),
77
+ },
78
+ };
79
+ });
80
+ return { tickets, cycleInfo };
81
+ }
82
+ async function readGithub(cwd, assignedOnly) {
83
+ const repo = (await run('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner'], {
84
+ cwd,
85
+ timeout: 5_000,
86
+ })).stdout.trim();
87
+ if (!repo)
88
+ throw new Error('No GitHub repository resolved for this workspace.');
89
+ const args = [
90
+ 'issue', 'list', '--repo', repo, '--state', 'open', '--limit', '50',
91
+ '--json', 'number,title,state,labels,assignees,url,body,createdAt',
92
+ ];
93
+ if (assignedOnly)
94
+ args.push('--assignee', '@me');
95
+ const { stdout } = await run('gh', args, { cwd, timeout: 15_000, maxBuffer: 16 * 1024 * 1024 });
96
+ const issues = JSON.parse(stdout);
97
+ return issues.map((issue) => {
98
+ const assignee = issue.assignees?.[0]?.login ? String(issue.assignees[0].login) : undefined;
99
+ const number = Number(issue.number);
100
+ return {
101
+ id: `github:${number}`,
102
+ source: 'github',
103
+ title: String(issue.title ?? ''),
104
+ description: issue.body ? String(issue.body) : undefined,
105
+ status: String(issue.state ?? '').toLowerCase() === 'closed' ? 'done' : 'todo',
106
+ metadata: {
107
+ identifier: `#${number}`,
108
+ url: issue.url ? String(issue.url) : undefined,
109
+ labels: (issue.labels ?? []).map((label) => String(label.name)),
110
+ assignee,
111
+ assigneeKind: assigneeKind(assignee),
112
+ state: String(issue.state ?? '').toLowerCase(),
113
+ createdAt: issue.createdAt ? String(issue.createdAt) : undefined,
114
+ repo,
115
+ images: imageUrls(issue.body),
116
+ },
117
+ };
118
+ });
119
+ }
120
+ export async function listTickets(options) {
121
+ const result = {
122
+ tickets: [],
123
+ cycleInfo: null,
124
+ sources: {
125
+ linear: { available: false },
126
+ github: { available: false },
127
+ },
128
+ };
129
+ const [linear, github] = await Promise.all([
130
+ options.linear
131
+ ? readLinear(options.cwd).then(value => ({ ok: true, value })).catch(error => ({ ok: false, error }))
132
+ : Promise.resolve(null),
133
+ options.github
134
+ ? readGithub(options.cwd, options.githubAssignedOnly).then(value => ({ ok: true, value })).catch(error => ({ ok: false, error }))
135
+ : Promise.resolve(null),
136
+ ]);
137
+ if (linear?.ok) {
138
+ result.sources.linear.available = true;
139
+ result.tickets.push(...linear.value.tickets);
140
+ result.cycleInfo = linear.value.cycleInfo;
141
+ }
142
+ else if (linear) {
143
+ result.sources.linear.error = errorMessage(linear.error);
144
+ }
145
+ if (github?.ok) {
146
+ result.sources.github.available = true;
147
+ result.tickets.push(...github.value);
148
+ }
149
+ else if (github) {
150
+ result.sources.github.error = errorMessage(github.error);
151
+ }
152
+ return result;
153
+ }