@phnx-labs/agents-cli 1.22.112 → 1.22.114

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 (706) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +10 -11
  3. package/dist/cli/command-registry.d.ts +0 -60
  4. package/dist/cli/command-registry.js +59 -61
  5. package/dist/commands/apply.d.ts +0 -4
  6. package/dist/commands/apply.js +3 -3
  7. package/dist/commands/browser-picker.d.ts +3 -6
  8. package/dist/commands/browser-picker.js +2 -2
  9. package/dist/commands/browser-sessions-picker.d.ts +2 -1
  10. package/dist/commands/computer-sessions-picker.d.ts +2 -1
  11. package/dist/commands/computer.d.ts +14 -19
  12. package/dist/commands/computer.js +65 -10
  13. package/dist/commands/config.js +46 -2
  14. package/dist/commands/daemon.d.ts +0 -23
  15. package/dist/commands/daemon.js +1 -1
  16. package/dist/commands/detach-core.d.ts +2 -1
  17. package/dist/commands/detach.d.ts +0 -3
  18. package/dist/commands/detach.js +3 -3
  19. package/dist/commands/feed.d.ts +3 -3
  20. package/dist/commands/feed.js +1 -1
  21. package/dist/commands/focus.d.ts +4 -4
  22. package/dist/commands/harness-hooks.d.ts +0 -7
  23. package/dist/commands/harness-hooks.js +1 -1
  24. package/dist/commands/harness-wizard.d.ts +2 -2
  25. package/dist/commands/harness.d.ts +3 -8
  26. package/dist/commands/harness.js +1 -1
  27. package/dist/commands/inspect.d.ts +2 -3
  28. package/dist/commands/inspect.js +1 -1
  29. package/dist/commands/message.d.ts +1 -1
  30. package/dist/commands/message.js +3 -3
  31. package/dist/commands/projects.d.ts +2 -18
  32. package/dist/commands/projects.js +89 -3
  33. package/dist/commands/resource-view.d.ts +3 -2
  34. package/dist/commands/resume.d.ts +0 -1
  35. package/dist/commands/resume.js +1 -1
  36. package/dist/commands/routines.d.ts +1 -3
  37. package/dist/commands/routines.js +1 -1
  38. package/dist/commands/run-account-picker.d.ts +2 -1
  39. package/dist/commands/run-broadcast.d.ts +2 -1
  40. package/dist/commands/run-device-picker.d.ts +2 -1
  41. package/dist/commands/secrets-passthrough.d.ts +14 -0
  42. package/dist/commands/secrets-passthrough.js +21 -2
  43. package/dist/commands/sessions-backfill.d.ts +2 -35
  44. package/dist/commands/sessions-backfill.js +1 -1
  45. package/dist/commands/sessions-bookmark.d.ts +0 -10
  46. package/dist/commands/sessions-bookmark.js +1 -1
  47. package/dist/commands/sessions-inject.d.ts +2 -3
  48. package/dist/commands/sessions-inject.js +8 -17
  49. package/dist/commands/sessions-picker-factory.d.ts +4 -14
  50. package/dist/commands/sessions-picker-factory.js +2 -2
  51. package/dist/commands/sessions-picker.d.ts +3 -9
  52. package/dist/commands/sessions-picker.js +2 -2
  53. package/dist/commands/sessions-resume.d.ts +2 -4
  54. package/dist/commands/sessions-resume.js +0 -5
  55. package/dist/commands/sessions-stats.d.ts +2 -1
  56. package/dist/commands/sessions-stop.d.ts +0 -3
  57. package/dist/commands/sessions-stop.js +1 -1
  58. package/dist/commands/sessions-tail.d.ts +2 -1
  59. package/dist/commands/sessions-trace.d.ts +4 -6
  60. package/dist/commands/sessions-trace.js +1 -1
  61. package/dist/commands/sessions.d.ts +14 -104
  62. package/dist/commands/sessions.js +22 -10
  63. package/dist/commands/setup-mine.d.ts +0 -6
  64. package/dist/commands/setup-mine.js +1 -1
  65. package/dist/commands/setup.d.ts +3 -4
  66. package/dist/commands/setup.js +1 -1
  67. package/dist/commands/share.d.ts +8 -8
  68. package/dist/commands/teams-picker.d.ts +2 -5
  69. package/dist/commands/teams-picker.js +2 -2
  70. package/dist/commands/teams.d.ts +1 -7
  71. package/dist/commands/teams.js +1 -1
  72. package/dist/commands/tmux.d.ts +1 -1
  73. package/dist/commands/tmux.js +1 -1
  74. package/dist/commands/upgrade.d.ts +2 -1
  75. package/dist/commands/utils.d.ts +1 -1
  76. package/dist/commands/utils.js +1 -1
  77. package/dist/lib/account-capabilities.d.ts +2 -1
  78. package/dist/lib/account-catalog.d.ts +4 -13
  79. package/dist/lib/account-catalog.js +1 -1
  80. package/dist/lib/account-registry.d.ts +3 -4
  81. package/dist/lib/account-registry.js +1 -1
  82. package/dist/lib/accounting/account-launch.d.ts +4 -3
  83. package/dist/lib/accounting/account-pool.d.ts +2 -1
  84. package/dist/lib/accounting/rotate.d.ts +3 -9
  85. package/dist/lib/accounting/rotate.js +2 -14
  86. package/dist/lib/accounting/usage-sync.d.ts +5 -4
  87. package/dist/lib/accounting/usage.d.ts +7 -31
  88. package/dist/lib/accounting/usage.js +4 -4
  89. package/dist/lib/accounts/migrate.d.ts +8 -8
  90. package/dist/lib/accounts/migrate.js +1 -1
  91. package/dist/lib/acp/client.d.ts +3 -2
  92. package/dist/lib/acp/harnesses.d.ts +2 -2
  93. package/dist/lib/acp/harnesses.js +1 -1
  94. package/dist/lib/acp/run.d.ts +2 -1
  95. package/dist/lib/actor.d.ts +3 -2
  96. package/dist/lib/add-dir.d.ts +2 -17
  97. package/dist/lib/add-dir.js +2 -6
  98. package/dist/lib/address.d.ts +56 -0
  99. package/dist/lib/address.js +143 -0
  100. package/dist/lib/agent-spec/agents.d.ts +12 -28
  101. package/dist/lib/agent-spec/agents.js +2 -6
  102. package/dist/lib/agent-spec/primitives.d.ts +0 -7
  103. package/dist/lib/agent-spec/primitives.js +0 -6
  104. package/dist/lib/agent-spec/types.d.ts +2 -1
  105. package/dist/lib/analytics/dashboard.d.ts +1 -5
  106. package/dist/lib/analytics/dashboard.js +0 -2
  107. package/dist/lib/analytics/mix-commands.d.ts +0 -7
  108. package/dist/lib/analytics/mix-commands.js +3 -3
  109. package/dist/lib/analytics/recipes.d.ts +0 -12
  110. package/dist/lib/analytics/recipes.js +7 -31
  111. package/dist/lib/analytics/usage-db.d.ts +5 -32
  112. package/dist/lib/analytics/usage-db.js +1 -70
  113. package/dist/lib/answer-router.d.ts +7 -6
  114. package/dist/lib/answer-router.js +5 -11
  115. package/dist/lib/artifact-actions.d.ts +0 -4
  116. package/dist/lib/ask-classifier.d.ts +3 -4
  117. package/dist/lib/ask-classifier.js +0 -7
  118. package/dist/lib/auth-health.d.ts +3 -46
  119. package/dist/lib/auth-health.js +3 -3
  120. package/dist/lib/auth-mint.d.ts +6 -6
  121. package/dist/lib/auth-mint.js +5 -5
  122. package/dist/lib/bench/runner.d.ts +2 -2
  123. package/dist/lib/bench/runner.js +1 -1
  124. package/dist/lib/bench/storage.d.ts +0 -1
  125. package/dist/lib/bench/storage.js +1 -1
  126. package/dist/lib/boot-profile.d.ts +0 -2
  127. package/dist/lib/boot-profile.js +0 -4
  128. package/dist/lib/brand.d.ts +0 -6
  129. package/dist/lib/brand.js +1 -1
  130. package/dist/lib/browser/arc-discovery.d.ts +4 -12
  131. package/dist/lib/browser/arc-discovery.js +1 -1
  132. package/dist/lib/browser/cdp.d.ts +1 -1
  133. package/dist/lib/browser/chrome.d.ts +2 -2
  134. package/dist/lib/browser/chrome.js +0 -4
  135. package/dist/lib/browser/chromium-discovery.d.ts +3 -2
  136. package/dist/lib/browser/drivers/arc.d.ts +3 -20
  137. package/dist/lib/browser/drivers/arc.js +2 -7
  138. package/dist/lib/browser/drivers/firefox.d.ts +2 -6
  139. package/dist/lib/browser/drivers/firefox.js +1 -1
  140. package/dist/lib/browser/drivers/local.d.ts +2 -1
  141. package/dist/lib/browser/drivers/ssh.d.ts +2 -3
  142. package/dist/lib/browser/drivers/ssh.js +0 -7
  143. package/dist/lib/browser/firefox-discovery.d.ts +4 -3
  144. package/dist/lib/browser/har.d.ts +8 -7
  145. package/dist/lib/browser/hygiene.d.ts +2 -3
  146. package/dist/lib/browser/hygiene.js +1 -1
  147. package/dist/lib/browser/ipc.d.ts +4 -3
  148. package/dist/lib/browser/ipc.js +1 -1
  149. package/dist/lib/browser/login-detection.d.ts +1 -8
  150. package/dist/lib/browser/registry.d.ts +2 -1
  151. package/dist/lib/browser/remote-control.d.ts +0 -7
  152. package/dist/lib/browser/remote-control.js +2 -2
  153. package/dist/lib/browser/resolve-target.d.ts +2 -6
  154. package/dist/lib/browser/resolve-target.js +3 -3
  155. package/dist/lib/browser/runtime-state.d.ts +4 -4
  156. package/dist/lib/browser/service.d.ts +4 -4
  157. package/dist/lib/browser/sessions-list.d.ts +0 -10
  158. package/dist/lib/browser/sessions-list.js +3 -3
  159. package/dist/lib/browser/stream.d.ts +2 -1
  160. package/dist/lib/browser/task-index.d.ts +4 -4
  161. package/dist/lib/browser/task-index.js +1 -1
  162. package/dist/lib/browser/types.d.ts +0 -20
  163. package/dist/lib/browser/types.js +1 -34
  164. package/dist/lib/browser/upload.d.ts +0 -27
  165. package/dist/lib/budget/ledger.d.ts +0 -2
  166. package/dist/lib/budget/ledger.js +1 -1
  167. package/dist/lib/budget/live-cloud.d.ts +2 -1
  168. package/dist/lib/budget/preflight.d.ts +3 -5
  169. package/dist/lib/budget/preflight.js +1 -1
  170. package/dist/lib/catchup.d.ts +2 -1
  171. package/dist/lib/channels/owner-forward.d.ts +5 -4
  172. package/dist/lib/channels/owner-sink.js +2 -2
  173. package/dist/lib/channels/providers/desktop.js +1 -1
  174. package/dist/lib/channels/providers/rush.d.ts +2 -1
  175. package/dist/lib/channels/registry.d.ts +1 -1
  176. package/dist/lib/channels/registry.js +1 -1
  177. package/dist/lib/channels/resolve.d.ts +3 -2
  178. package/dist/lib/channels/send.d.ts +5 -4
  179. package/dist/lib/cli-resources.d.ts +3 -9
  180. package/dist/lib/cli-resources.js +1 -1
  181. package/dist/lib/cloud/cursor.d.ts +1 -2
  182. package/dist/lib/cloud/cursor.js +1 -1
  183. package/dist/lib/cloud/dispatch.d.ts +2 -1
  184. package/dist/lib/cloud/factory.d.ts +0 -2
  185. package/dist/lib/cloud/factory.js +1 -1
  186. package/dist/lib/cloud/rush.d.ts +3 -11
  187. package/dist/lib/cloud/rush.js +1 -1
  188. package/dist/lib/cloud/session-index.d.ts +2 -1
  189. package/dist/lib/cloud/types.d.ts +2 -1
  190. package/dist/lib/codex-policy.d.ts +2 -1
  191. package/dist/lib/commands.d.ts +7 -7
  192. package/dist/lib/commands.js +1 -1
  193. package/dist/lib/comms-render.d.ts +1 -1
  194. package/dist/lib/computer/context.d.ts +11 -3
  195. package/dist/lib/computer/context.js +2 -2
  196. package/dist/lib/computer/policy.d.ts +0 -12
  197. package/dist/lib/computer/policy.js +1 -1
  198. package/dist/lib/computer-client.d.ts +3 -3
  199. package/dist/lib/computer-client.js +0 -1
  200. package/dist/lib/concurrency.d.ts +2 -1
  201. package/dist/lib/config-keys.d.ts +16 -3
  202. package/dist/lib/config-keys.js +47 -2
  203. package/dist/lib/convert.d.ts +0 -12
  204. package/dist/lib/convert.js +1 -12
  205. package/dist/lib/crabbox/cli.d.ts +6 -24
  206. package/dist/lib/crabbox/cli.js +2 -28
  207. package/dist/lib/crabbox/lease.d.ts +5 -6
  208. package/dist/lib/crabbox/lease.js +1 -1
  209. package/dist/lib/crabbox/progress.d.ts +2 -1
  210. package/dist/lib/crabbox/setup-copy.d.ts +2 -3
  211. package/dist/lib/crabbox/setup-copy.js +1 -1
  212. package/dist/lib/daemon/account-state-daemon-service.d.ts +1 -1
  213. package/dist/lib/daemon/attention-notify-service.d.ts +2 -1
  214. package/dist/lib/daemon/catchup-service.d.ts +2 -1
  215. package/dist/lib/daemon/daemon.d.ts +4 -12
  216. package/dist/lib/daemon/daemon.js +42 -23
  217. package/dist/lib/daemon/harness-update-service.d.ts +2 -19
  218. package/dist/lib/daemon/harness-update-service.js +3 -3
  219. package/dist/lib/daemon/runner.d.ts +3 -3
  220. package/dist/lib/daemon/self-update-service.d.ts +1 -16
  221. package/dist/lib/daemon/self-update-service.js +6 -6
  222. package/dist/lib/daemon/state-dir-check-service.d.ts +2 -1
  223. package/dist/lib/daemon/supervisor.d.ts +3 -2
  224. package/dist/lib/daemon/testdata/process-view-daemon.d.ts +1 -0
  225. package/dist/lib/daemon/testdata/process-view-daemon.js +14 -0
  226. package/dist/lib/daemon/testdata/process-view-start.d.ts +1 -0
  227. package/dist/lib/daemon/testdata/process-view-start.js +43 -0
  228. package/dist/lib/daemon-services.d.ts +2 -1
  229. package/dist/lib/daemon-webhooks.d.ts +1 -1
  230. package/dist/lib/deeplink/register.d.ts +3 -13
  231. package/dist/lib/deeplink/register.js +3 -3
  232. package/dist/lib/deeplink/url.d.ts +3 -2
  233. package/dist/lib/device-config.d.ts +4 -15
  234. package/dist/lib/device-config.js +164 -8
  235. package/dist/lib/devices/connect.d.ts +2 -1
  236. package/dist/lib/devices/discovery-policy.d.ts +3 -2
  237. package/dist/lib/devices/doctor-findings.js +1 -1
  238. package/dist/lib/devices/doctor-overview-cache.d.ts +3 -2
  239. package/dist/lib/devices/fleet-divergence.d.ts +2 -1
  240. package/dist/lib/devices/fleet.d.ts +3 -4
  241. package/dist/lib/devices/fleet.js +1 -1
  242. package/dist/lib/devices/harness-inventory.d.ts +3 -2
  243. package/dist/lib/devices/health-report.d.ts +3 -2
  244. package/dist/lib/devices/health.d.ts +1 -8
  245. package/dist/lib/devices/health.js +1 -1
  246. package/dist/lib/devices/interactive-host.d.ts +0 -2
  247. package/dist/lib/devices/interactive-host.js +1 -1
  248. package/dist/lib/devices/known-hosts.d.ts +2 -20
  249. package/dist/lib/devices/known-hosts.js +2 -2
  250. package/dist/lib/devices/pool.d.ts +2 -1
  251. package/dist/lib/devices/resolve-target.d.ts +2 -2
  252. package/dist/lib/devices/rollout-verify.d.ts +3 -2
  253. package/dist/lib/devices/stats-cache.d.ts +3 -2
  254. package/dist/lib/devices/sync.d.ts +6 -5
  255. package/dist/lib/devices/worker-pick.d.ts +3 -12
  256. package/dist/lib/devices/worker-pick.js +1 -1
  257. package/dist/lib/diff-text.d.ts +2 -1
  258. package/dist/lib/doctor-diff.d.ts +2 -1
  259. package/dist/lib/drift-sync.d.ts +3 -2
  260. package/dist/lib/drift.d.ts +3 -3
  261. package/dist/lib/drift.js +1 -1
  262. package/dist/lib/event-families.d.ts +0 -6
  263. package/dist/lib/event-families.js +3 -3
  264. package/dist/lib/event-provenance.d.ts +4 -1
  265. package/dist/lib/event-provenance.js +4 -0
  266. package/dist/lib/events-ingest.d.ts +4 -3
  267. package/dist/lib/exec-account-home.d.ts +2 -4
  268. package/dist/lib/exec-account-home.js +1 -1
  269. package/dist/lib/exec-bounded.d.ts +3 -4
  270. package/dist/lib/exec-bounded.js +1 -1
  271. package/dist/lib/exec.d.ts +6 -18
  272. package/dist/lib/exec.js +28 -8
  273. package/dist/lib/factory/snapshot.d.ts +2 -2
  274. package/dist/lib/factory/snapshot.js +1 -1
  275. package/dist/lib/feed/activity-stream.d.ts +2 -5
  276. package/dist/lib/feed/activity-stream.js +11 -2
  277. package/dist/lib/feed/activity.d.ts +16 -33
  278. package/dist/lib/feed/activity.js +69 -26
  279. package/dist/lib/feed/answer.d.ts +3 -2
  280. package/dist/lib/feed/attention.js +5 -1
  281. package/dist/lib/feed/events.d.ts +2 -47
  282. package/dist/lib/feed/events.js +1 -141
  283. package/dist/lib/feed/feed.d.ts +9 -42
  284. package/dist/lib/feed/feed.js +1 -60
  285. package/dist/lib/feed/pr-status.d.ts +0 -2
  286. package/dist/lib/feed/pr-status.js +1 -5
  287. package/dist/lib/feed/watch.d.ts +10 -2
  288. package/dist/lib/feed/watch.js +91 -4
  289. package/dist/lib/feed-broadcast.d.ts +5 -47
  290. package/dist/lib/feed-broadcast.js +9 -9
  291. package/dist/lib/feed-outcome.d.ts +3 -6
  292. package/dist/lib/feed-outcome.js +2 -2
  293. package/dist/lib/feed-policy.d.ts +5 -6
  294. package/dist/lib/feed-policy.js +2 -2
  295. package/dist/lib/feed-post.d.ts +3 -4
  296. package/dist/lib/feed-post.js +2 -2
  297. package/dist/lib/feed-ranking.d.ts +2 -2
  298. package/dist/lib/feed-ranking.js +1 -1
  299. package/dist/lib/fleet/apply.d.ts +5 -6
  300. package/dist/lib/fleet/apply.js +4 -4
  301. package/dist/lib/fleet/manifest.d.ts +2 -1
  302. package/dist/lib/fleet/remote-login.d.ts +18 -36
  303. package/dist/lib/fleet/remote-login.js +20 -19
  304. package/dist/lib/fleet/types.d.ts +0 -8
  305. package/dist/lib/fleet-cache.d.ts +1 -18
  306. package/dist/lib/fleet-cache.js +0 -5
  307. package/dist/lib/fleet-shared-repo-sync.d.ts +3 -3
  308. package/dist/lib/fleet-shared-repo-sync.js +1 -1
  309. package/dist/lib/fleet-shared-state.d.ts +3 -2
  310. package/dist/lib/format.d.ts +2 -1
  311. package/dist/lib/friction-heuristics.d.ts +2 -1
  312. package/dist/lib/fs-walk.d.ts +2 -1
  313. package/dist/lib/fuzzy.d.ts +2 -1
  314. package/dist/lib/gemini-settings.d.ts +0 -1
  315. package/dist/lib/gemini-settings.js +1 -1
  316. package/dist/lib/git.d.ts +7 -65
  317. package/dist/lib/git.js +3 -142
  318. package/dist/lib/github/gh-overload.d.ts +0 -4
  319. package/dist/lib/github/gh-overload.js +2 -2
  320. package/dist/lib/github/project-prs.d.ts +118 -0
  321. package/dist/lib/github/project-prs.js +173 -0
  322. package/dist/lib/github/rest.d.ts +2 -1
  323. package/dist/lib/harness/exec-config-version.d.ts +2 -1
  324. package/dist/lib/harness-auth-capabilities.d.ts +5 -4
  325. package/dist/lib/harness-connection-test.d.ts +2 -1
  326. package/dist/lib/heal.d.ts +3 -20
  327. package/dist/lib/heal.js +2 -39
  328. package/dist/lib/help.d.ts +3 -2
  329. package/dist/lib/helper-download.d.ts +0 -12
  330. package/dist/lib/helper-download.js +2 -2
  331. package/dist/lib/helper-versions.d.ts +2 -1
  332. package/dist/lib/helper-versions.js +1 -1
  333. package/dist/lib/hooks/install.d.ts +8 -49
  334. package/dist/lib/hooks/install.js +2 -96
  335. package/dist/lib/hooks/match.d.ts +2 -1
  336. package/dist/lib/hosts/credential-transport.d.ts +0 -2
  337. package/dist/lib/hosts/credential-transport.js +1 -1
  338. package/dist/lib/hosts/dispatch.d.ts +2 -34
  339. package/dist/lib/hosts/dispatch.js +4 -21
  340. package/dist/lib/hosts/logs.d.ts +2 -1
  341. package/dist/lib/hosts/passthrough.d.ts +1 -1
  342. package/dist/lib/hosts/passthrough.js +0 -1
  343. package/dist/lib/hosts/progress.d.ts +0 -5
  344. package/dist/lib/hosts/progress.js +1 -1
  345. package/dist/lib/hosts/ready.d.ts +3 -4
  346. package/dist/lib/hosts/ready.js +0 -8
  347. package/dist/lib/hosts/reconcile.d.ts +2 -8
  348. package/dist/lib/hosts/reconcile.js +1 -1
  349. package/dist/lib/hosts/reconnect.d.ts +4 -11
  350. package/dist/lib/hosts/reconnect.js +2 -2
  351. package/dist/lib/hosts/registry.d.ts +1 -1
  352. package/dist/lib/hosts/remote-cmd.d.ts +4 -3
  353. package/dist/lib/hosts/remote-session-id.d.ts +5 -27
  354. package/dist/lib/hosts/remote-session-id.js +18 -61
  355. package/dist/lib/hosts/session-index.d.ts +3 -2
  356. package/dist/lib/hosts/ssh-config.d.ts +2 -3
  357. package/dist/lib/hosts/ssh-config.js +0 -10
  358. package/dist/lib/humans.d.ts +0 -2
  359. package/dist/lib/humans.js +2 -2
  360. package/dist/lib/import.d.ts +4 -3
  361. package/dist/lib/installations/installation-lock.d.ts +0 -2
  362. package/dist/lib/installations/installation-lock.js +2 -2
  363. package/dist/lib/installations/launch-gate.d.ts +0 -9
  364. package/dist/lib/installations/launch-gate.js +1 -1
  365. package/dist/lib/installations/migrate.d.ts +0 -11
  366. package/dist/lib/installations/migrate.js +1 -1
  367. package/dist/lib/installations/shims.d.ts +1 -1
  368. package/dist/lib/installations/shims.js +2 -2
  369. package/dist/lib/installations/update-runtime.js +1 -1
  370. package/dist/lib/launch-identity.d.ts +10 -0
  371. package/dist/lib/launch-identity.js +31 -0
  372. package/dist/lib/linear-cache.d.ts +2 -1
  373. package/dist/lib/linux-userns.d.ts +2 -3
  374. package/dist/lib/linux-userns.js +0 -4
  375. package/dist/lib/loop.d.ts +2 -1
  376. package/dist/lib/mailbox-gc.d.ts +2 -1
  377. package/dist/lib/mailbox-target.d.ts +2 -1
  378. package/dist/lib/mailbox.d.ts +0 -6
  379. package/dist/lib/mailbox.js +1 -1
  380. package/dist/lib/manifest.d.ts +0 -14
  381. package/dist/lib/manifest.js +2 -2
  382. package/dist/lib/mcp-registry.d.ts +2 -1
  383. package/dist/lib/memory.d.ts +2 -13
  384. package/dist/lib/memory.js +4 -4
  385. package/dist/lib/menubar/download-menubar.d.ts +0 -2
  386. package/dist/lib/menubar/download-menubar.js +1 -5
  387. package/dist/lib/menubar/install-menubar.d.ts +3 -14
  388. package/dist/lib/menubar/install-menubar.js +3 -3
  389. package/dist/lib/menubar/migrate-prefs.d.ts +53 -0
  390. package/dist/lib/menubar/migrate-prefs.js +168 -0
  391. package/dist/lib/menubar/resolve-version.d.ts +1 -9
  392. package/dist/lib/menubar/resolve-version.js +4 -4
  393. package/dist/lib/menubar/snapshot.d.ts +24 -2
  394. package/dist/lib/menubar/snapshot.js +26 -0
  395. package/dist/lib/model-tier-overrides.d.ts +3 -2
  396. package/dist/lib/monitors/config.d.ts +0 -2
  397. package/dist/lib/monitors/config.js +0 -4
  398. package/dist/lib/monitors/engine.d.ts +1 -1
  399. package/dist/lib/monitors/remote.d.ts +3 -2
  400. package/dist/lib/monitors/sources/webhook.d.ts +2 -15
  401. package/dist/lib/monitors/sources/webhook.js +1 -38
  402. package/dist/lib/monitors/state.d.ts +4 -7
  403. package/dist/lib/monitors/state.js +2 -2
  404. package/dist/lib/notify.d.ts +1 -1
  405. package/dist/lib/notify.js +1 -1
  406. package/dist/lib/onepassword.d.ts +5 -14
  407. package/dist/lib/onepassword.js +0 -64
  408. package/dist/lib/open-url.d.ts +3 -2
  409. package/dist/lib/openclaw-keychain.d.ts +4 -17
  410. package/dist/lib/openclaw-keychain.js +3 -33
  411. package/dist/lib/operator.d.ts +2 -2
  412. package/dist/lib/operator.js +1 -1
  413. package/dist/lib/output/git-output.d.ts +4 -14
  414. package/dist/lib/output/git-output.js +1 -1
  415. package/dist/lib/owner-message.d.ts +3 -29
  416. package/dist/lib/owner-message.js +3 -3
  417. package/dist/lib/packages/output-home.d.ts +2 -4
  418. package/dist/lib/packages/output-home.js +2 -2
  419. package/dist/lib/perf/db.d.ts +0 -2
  420. package/dist/lib/perf/db.js +2 -7
  421. package/dist/lib/permissions-registry.d.ts +2 -3
  422. package/dist/lib/permissions-registry.js +0 -4
  423. package/dist/lib/permissions.d.ts +6 -16
  424. package/dist/lib/permissions.js +2 -15
  425. package/dist/lib/picker.d.ts +6 -5
  426. package/dist/lib/placement.d.ts +3 -6
  427. package/dist/lib/placement.js +0 -17
  428. package/dist/lib/platform/posixpath.d.ts +2 -1
  429. package/dist/lib/platform/winpath.d.ts +2 -1
  430. package/dist/lib/plugins/plugin-marketplace.d.ts +2 -2
  431. package/dist/lib/plugins/plugin-marketplace.js +1 -1
  432. package/dist/lib/pr-land-detach.d.ts +2 -1
  433. package/dist/lib/profiles-presets.d.ts +2 -1
  434. package/dist/lib/profiles.d.ts +3 -9
  435. package/dist/lib/profiles.js +1 -9
  436. package/dist/lib/project-doctor.d.ts +2 -1
  437. package/dist/lib/project-launch.d.ts +2 -2
  438. package/dist/lib/project-probe.d.ts +4 -3
  439. package/dist/lib/project-pull.d.ts +2 -1
  440. package/dist/lib/project-resources.d.ts +2 -2
  441. package/dist/lib/project-resources.js +1 -1
  442. package/dist/lib/project-root.d.ts +2 -6
  443. package/dist/lib/project-root.js +1 -1
  444. package/dist/lib/project-schedule.d.ts +2 -1
  445. package/dist/lib/project-status.d.ts +2 -16
  446. package/dist/lib/project-status.js +3 -3
  447. package/dist/lib/reconcile-and-repair.d.ts +5 -4
  448. package/dist/lib/redact.d.ts +7 -1
  449. package/dist/lib/redact.js +94 -3
  450. package/dist/lib/refresh-coordinator.d.ts +2 -1
  451. package/dist/lib/refresh.d.ts +3 -2
  452. package/dist/lib/remote-agents-json.d.ts +3 -2
  453. package/dist/lib/reserved-stores.d.ts +0 -2
  454. package/dist/lib/reserved-stores.js +3 -5
  455. package/dist/lib/resource-content-diff.d.ts +0 -2
  456. package/dist/lib/resource-content-diff.js +1 -1
  457. package/dist/lib/resource-patterns.d.ts +2 -1
  458. package/dist/lib/resource-profiles.d.ts +2 -8
  459. package/dist/lib/resource-profiles.js +3 -27
  460. package/dist/lib/resources/workflows.d.ts +1 -1
  461. package/dist/lib/resources.d.ts +4 -9
  462. package/dist/lib/resources.js +1 -1
  463. package/dist/lib/routine-context.d.ts +2 -5
  464. package/dist/lib/routine-context.js +2 -2
  465. package/dist/lib/routine-notify-owner.d.ts +8 -7
  466. package/dist/lib/routine-notify-owner.js +5 -5
  467. package/dist/lib/routine-process-cleanup.d.ts +2 -1
  468. package/dist/lib/routine-readiness.d.ts +0 -2
  469. package/dist/lib/routine-readiness.js +0 -7
  470. package/dist/lib/routines-project.d.ts +3 -4
  471. package/dist/lib/routines-project.js +1 -1
  472. package/dist/lib/rules/compile.d.ts +3 -25
  473. package/dist/lib/rules/compile.js +1 -1
  474. package/dist/lib/rules/compose.d.ts +3 -9
  475. package/dist/lib/rules/rules.d.ts +4 -15
  476. package/dist/lib/rules/rules.js +1 -64
  477. package/dist/lib/run-defaults.d.ts +1 -1
  478. package/dist/lib/run-notify.d.ts +2 -1
  479. package/dist/lib/run-trace-sync.d.ts +1 -1
  480. package/dist/lib/run-trace-sync.js +1 -1
  481. package/dist/lib/scheduler.d.ts +2 -1
  482. package/dist/lib/scheduling/routines.d.ts +9 -21
  483. package/dist/lib/scheduling/routines.js +3 -46
  484. package/dist/lib/secrets-client.d.ts +0 -17
  485. package/dist/lib/secrets-client.js +4 -26
  486. package/dist/lib/secrets-policy.d.ts +12 -17
  487. package/dist/lib/secrets-policy.js +5 -5
  488. package/dist/lib/secrets-types.d.ts +3 -2
  489. package/dist/lib/secrets-types.js +2 -1
  490. package/dist/lib/self-heal/checks/install-staging.js +1 -1
  491. package/dist/lib/self-heal/registry.d.ts +3 -2
  492. package/dist/lib/self-heal/types.d.ts +1 -1
  493. package/dist/lib/self-heal/types.js +1 -1
  494. package/dist/lib/self-update.d.ts +5 -5
  495. package/dist/lib/self-update.js +4 -4
  496. package/dist/lib/session/active.js +9 -3
  497. package/dist/lib/session/actor-sidecar.d.ts +3 -2
  498. package/dist/lib/session/artifacts.d.ts +0 -2
  499. package/dist/lib/session/artifacts.js +1 -1
  500. package/dist/lib/session/bash-command.d.ts +2 -7
  501. package/dist/lib/session/bundle.d.ts +4 -6
  502. package/dist/lib/session/bundle.js +1 -5
  503. package/dist/lib/session/cloud.d.ts +0 -4
  504. package/dist/lib/session/cloud.js +2 -15
  505. package/dist/lib/session/db.d.ts +2 -1
  506. package/dist/lib/session/db.js +39 -4
  507. package/dist/lib/session/detached.d.ts +2 -1
  508. package/dist/lib/session/detached.js +2 -2
  509. package/dist/lib/session/digest.d.ts +2 -2
  510. package/dist/lib/session/digest.js +1 -1
  511. package/dist/lib/session/discover.js +7 -2
  512. package/dist/lib/session/fork.d.ts +3 -2
  513. package/dist/lib/session/highlights.d.ts +6 -5
  514. package/dist/lib/session/hook-sessions.d.ts +12 -1
  515. package/dist/lib/session/hook-sessions.js +139 -6
  516. package/dist/lib/session/host-link.d.ts +2 -1
  517. package/dist/lib/session/inject.d.ts +1 -1
  518. package/dist/lib/session/inject.js +1 -1
  519. package/dist/lib/session/insights.d.ts +3 -15
  520. package/dist/lib/session/insights.js +2 -2
  521. package/dist/lib/session/local-tmux-attach.d.ts +2 -18
  522. package/dist/lib/session/local-tmux-attach.js +1 -1
  523. package/dist/lib/session/migrations.d.ts +0 -1
  524. package/dist/lib/session/migrations.js +1 -1
  525. package/dist/lib/session/mirror.d.ts +5 -8
  526. package/dist/lib/session/mirror.js +2 -2
  527. package/dist/lib/session/parse.d.ts +1 -32
  528. package/dist/lib/session/parse.js +4 -4
  529. package/dist/lib/session/pid-registry.d.ts +18 -5
  530. package/dist/lib/session/pid-registry.js +164 -17
  531. package/dist/lib/session/presence.d.ts +2 -1
  532. package/dist/lib/session/process-view.d.ts +25 -0
  533. package/dist/lib/session/process-view.js +176 -0
  534. package/dist/lib/session/projection.d.ts +13 -0
  535. package/dist/lib/session/projection.js +101 -0
  536. package/dist/lib/session/prompt.d.ts +3 -2
  537. package/dist/lib/session/prompt.js +38 -1
  538. package/dist/lib/session/recovery.d.ts +3 -2
  539. package/dist/lib/session/remote/peer-stream.d.ts +2 -5
  540. package/dist/lib/session/remote/peer-stream.js +2 -2
  541. package/dist/lib/session/remote/remote-bundle.d.ts +2 -1
  542. package/dist/lib/session/remote/remote-list.d.ts +5 -5
  543. package/dist/lib/session/remote/remote.d.ts +4 -3
  544. package/dist/lib/session/remote/watch.d.ts +10 -7
  545. package/dist/lib/session/remote/watch.js +10 -6
  546. package/dist/lib/session/remote-active.d.ts +2 -1
  547. package/dist/lib/session/render.d.ts +2 -2
  548. package/dist/lib/session/render.js +1 -1
  549. package/dist/lib/session/resume-owner.d.ts +1 -1
  550. package/dist/lib/session/resume-owner.js +1 -1
  551. package/dist/lib/session/run-names.d.ts +2 -1
  552. package/dist/lib/session/session-cache.d.ts +7 -26
  553. package/dist/lib/session/session-cache.js +17 -8
  554. package/dist/lib/session/share-html.d.ts +1 -21
  555. package/dist/lib/session/share-html.js +1 -1
  556. package/dist/lib/session/shell-programs.d.ts +2 -1
  557. package/dist/lib/session/state.d.ts +41 -8
  558. package/dist/lib/session/state.js +112 -11
  559. package/dist/lib/session/stream-render.d.ts +2 -1
  560. package/dist/lib/session/sync/agents.d.ts +0 -4
  561. package/dist/lib/session/sync/agents.js +0 -0
  562. package/dist/lib/session/sync/backend.d.ts +5 -5
  563. package/dist/lib/session/sync/managed-config.d.ts +0 -8
  564. package/dist/lib/session/sync/managed-key.d.ts +0 -2
  565. package/dist/lib/session/sync/managed-key.js +1 -1
  566. package/dist/lib/session/sync/r2.d.ts +4 -1
  567. package/dist/lib/session/sync/r2.js +4 -7
  568. package/dist/lib/session/sync/transcript-crypto.d.ts +2 -1
  569. package/dist/lib/session/tail.d.ts +2 -1
  570. package/dist/lib/session/team-filter.d.ts +1 -1
  571. package/dist/lib/session/testdata/pid-registry-namespace.d.ts +1 -0
  572. package/dist/lib/session/testdata/pid-registry-namespace.js +27 -0
  573. package/dist/lib/session/testdata/process-view-namespace.d.ts +1 -0
  574. package/dist/lib/session/testdata/process-view-namespace.js +56 -0
  575. package/dist/lib/session/testdata/process-view-private.d.ts +1 -0
  576. package/dist/lib/session/testdata/process-view-private.js +12 -0
  577. package/dist/lib/session/throughput.d.ts +2 -3
  578. package/dist/lib/session/throughput.js +1 -1
  579. package/dist/lib/session/timeline-pass.d.ts +3 -42
  580. package/dist/lib/session/timeline-pass.js +4 -4
  581. package/dist/lib/session/timeline.d.ts +3 -13
  582. package/dist/lib/session/timeline.js +3 -3
  583. package/dist/lib/session/tool-calls.d.ts +2 -2
  584. package/dist/lib/session/tool-calls.js +1 -1
  585. package/dist/lib/session/tool-index.d.ts +0 -8
  586. package/dist/lib/session/tool-index.js +2 -2
  587. package/dist/lib/session/tool-store.d.ts +2 -1
  588. package/dist/lib/session/trajectory-compare.d.ts +2 -1
  589. package/dist/lib/session/trajectory-lineage.d.ts +2 -1
  590. package/dist/lib/session/trajectory-text.d.ts +3 -2
  591. package/dist/lib/session/trajectory.d.ts +2 -1
  592. package/dist/lib/session/viewing-in.d.ts +2 -1
  593. package/dist/lib/settings-manifest.d.ts +2 -1
  594. package/dist/lib/share/delete.d.ts +5 -4
  595. package/dist/lib/share/html.d.ts +0 -2
  596. package/dist/lib/share/html.js +9 -9
  597. package/dist/lib/share/http-error.d.ts +3 -2
  598. package/dist/lib/share/og.d.ts +2 -1
  599. package/dist/lib/share/provision.d.ts +2 -2
  600. package/dist/lib/share/publish.d.ts +4 -13
  601. package/dist/lib/share/publish.js +2 -2
  602. package/dist/lib/shim-heal.d.ts +1 -5
  603. package/dist/lib/shim-heal.js +0 -6
  604. package/dist/lib/smart-launch.d.ts +4 -5
  605. package/dist/lib/smart-launch.js +1 -1
  606. package/dist/lib/snapshot.d.ts +3 -2
  607. package/dist/lib/ssh-exec.d.ts +5 -4
  608. package/dist/lib/ssh-tunnel.d.ts +3 -2
  609. package/dist/lib/staleness/checkers/permissions.d.ts +0 -2
  610. package/dist/lib/staleness/checkers/permissions.js +1 -1
  611. package/dist/lib/staleness/fingerprint.d.ts +0 -7
  612. package/dist/lib/staleness/fingerprint.js +1 -1
  613. package/dist/lib/staleness/prune.d.ts +3 -2
  614. package/dist/lib/staleness/registry.d.ts +1 -1
  615. package/dist/lib/staleness/writers/sources.d.ts +0 -8
  616. package/dist/lib/staleness/writers/sources.js +1 -1
  617. package/dist/lib/startup/command-registry.js +1 -1
  618. package/dist/lib/state.d.ts +1 -3
  619. package/dist/lib/state.js +1 -4
  620. package/dist/lib/subagents-registry.d.ts +4 -3
  621. package/dist/lib/subagents.d.ts +2 -1
  622. package/dist/lib/subagents.js +3 -2
  623. package/dist/lib/summarizer/pass.d.ts +3 -6
  624. package/dist/lib/summarizer/pass.js +2 -2
  625. package/dist/lib/summarizer/summarize.d.ts +4 -3
  626. package/dist/lib/sync-passphrase.d.ts +3 -2
  627. package/dist/lib/sync-status.d.ts +3 -16
  628. package/dist/lib/sync-status.js +2 -2
  629. package/dist/lib/sync-umbrella.d.ts +4 -3
  630. package/dist/lib/system-run-sync.d.ts +2 -1
  631. package/dist/lib/teams/agents.d.ts +2 -4
  632. package/dist/lib/teams/agents.js +1 -1
  633. package/dist/lib/teams/forEach.d.ts +3 -2
  634. package/dist/lib/teams/pr-watch.d.ts +4 -11
  635. package/dist/lib/teams/pr-watch.js +4 -4
  636. package/dist/lib/teams/registry.d.ts +2 -3
  637. package/dist/lib/teams/registry.js +1 -1
  638. package/dist/lib/teams/remoteWorktree.d.ts +0 -16
  639. package/dist/lib/teams/remoteWorktree.js +3 -3
  640. package/dist/lib/teams/scheduler.d.ts +6 -5
  641. package/dist/lib/teams/scheduler.js +1 -1
  642. package/dist/lib/teams/supervisor.d.ts +4 -3
  643. package/dist/lib/teams/worktree.d.ts +0 -9
  644. package/dist/lib/teams/worktree.js +0 -32
  645. package/dist/lib/term-client.d.ts +44 -0
  646. package/dist/lib/term-client.js +117 -0
  647. package/dist/lib/terminal/inject.d.ts +3 -16
  648. package/dist/lib/terminal/inject.js +1 -29
  649. package/dist/lib/terminal/resolve.d.ts +3 -9
  650. package/dist/lib/terminal/resolve.js +3 -7
  651. package/dist/lib/tmux/binary.d.ts +2 -1
  652. package/dist/lib/tmux/orphan-reap.d.ts +6 -7
  653. package/dist/lib/tmux/orphan-reap.js +1 -1
  654. package/dist/lib/tmux/session.d.ts +4 -3
  655. package/dist/lib/traces/classify.d.ts +3 -2
  656. package/dist/lib/traces/config.d.ts +0 -8
  657. package/dist/lib/traces/insights.d.ts +2 -1
  658. package/dist/lib/traces/phenotype.d.ts +3 -3
  659. package/dist/lib/traces/provision.d.ts +1 -3
  660. package/dist/lib/traces/provision.js +1 -1
  661. package/dist/lib/traces/schema2-build.d.ts +1 -1
  662. package/dist/lib/traces/schema2-danger.d.ts +2 -1
  663. package/dist/lib/traces/schema2.d.ts +5 -4
  664. package/dist/lib/traces/segments.d.ts +4 -20
  665. package/dist/lib/traces/segments.js +3 -3
  666. package/dist/lib/traces/sync.d.ts +2 -3
  667. package/dist/lib/traces/sync.js +1 -1
  668. package/dist/lib/triggers/handlers.d.ts +4 -13
  669. package/dist/lib/triggers/handlers.js +1 -1
  670. package/dist/lib/triggers/webhook.d.ts +5 -27
  671. package/dist/lib/triggers/webhook.js +4 -4
  672. package/dist/lib/types.d.ts +3 -3
  673. package/dist/lib/usage-refresh.d.ts +4 -10
  674. package/dist/lib/usage-refresh.js +3 -8
  675. package/dist/lib/verbs.d.ts +2 -1
  676. package/dist/lib/version-duplicates.d.ts +2 -3
  677. package/dist/lib/version-duplicates.js +3 -33
  678. package/dist/lib/version.d.ts +2 -1
  679. package/dist/lib/warn-unpushed.d.ts +2 -1
  680. package/dist/lib/watchdog/history.d.ts +3 -2
  681. package/dist/lib/watchdog/log.d.ts +0 -6
  682. package/dist/lib/watchdog/log.js +1 -1
  683. package/dist/lib/watchdog/rotate.d.ts +2 -26
  684. package/dist/lib/watchdog/rotate.js +4 -12
  685. package/dist/lib/watchdog/runner.d.ts +0 -7
  686. package/dist/lib/watchdog/runner.js +4 -4
  687. package/dist/lib/watchdog/service.d.ts +2 -2
  688. package/dist/lib/watchdog/service.js +1 -1
  689. package/dist/lib/watchdog/watchdog-agent.d.ts +2 -1
  690. package/dist/lib/watchdog/watchdog.d.ts +2 -1
  691. package/dist/lib/watchdog/watchdogTail.d.ts +2 -1
  692. package/dist/lib/workflows-registry.d.ts +3 -2
  693. package/dist/lib/workflows.d.ts +4 -7
  694. package/dist/lib/workflows.js +1 -1
  695. package/dist/lib/worktree/held.d.ts +4 -28
  696. package/dist/lib/worktree/held.js +3 -3
  697. package/package.json +2 -3
  698. package/scripts/postinstall.js +5 -4
  699. package/dist/commands/pty.d.ts +0 -20
  700. package/dist/commands/pty.js +0 -404
  701. package/dist/lib/config-machine-keys.d.ts +0 -14
  702. package/dist/lib/config-machine-keys.js +0 -21
  703. package/dist/lib/pty-client.d.ts +0 -49
  704. package/dist/lib/pty-client.js +0 -315
  705. package/dist/lib/pty-server.d.ts +0 -59
  706. package/dist/lib/pty-server.js +0 -653
@@ -7,6 +7,12 @@ export interface BlockQuestion {
7
7
  header?: string;
8
8
  options?: BlockOption[];
9
9
  multiSelect?: boolean;
10
+ /**
11
+ * Preceding report/explanation for a prose question — the context that came
12
+ * BEFORE the trailing ask, Markdown + newlines preserved (PHNX-3999). The
13
+ * operator UI renders it under the question; absent for a structured question.
14
+ */
15
+ context?: string;
10
16
  }
11
17
  export interface MessageReceipt {
12
18
  /** The message id this receipt describes. */
@@ -230,8 +236,6 @@ export declare function deriveBlockState(block: OpenBlock): AttentionState;
230
236
  export declare function recordResolution(resolution: AttentionResolution, root?: string): void;
231
237
  /** Read the latest resolution tombstone for a block, if one exists. */
232
238
  export declare function readResolution(blockId: string, root?: string): AttentionResolution | undefined;
233
- /** Read every resolution tombstone. Returns them sorted by stable block filename. */
234
- export declare function listResolutions(root?: string): AttentionResolution[];
235
239
  /**
236
240
  * Stable block id for a session. One block per session -- a new question
237
241
  * replaces the previous one (the agent can only ask one question at a time).
@@ -239,7 +243,7 @@ export declare function listResolutions(root?: string): AttentionResolution[];
239
243
  export declare function blockIdForSession(sessionId: string): string;
240
244
  /** Read one block record. Returns undefined when missing or corrupt. */
241
245
  export declare function readBlock(blockId: string, root?: string): OpenBlock | undefined;
242
- export type RecordAnswerResult = {
246
+ type RecordAnswerResult = {
243
247
  ok: true;
244
248
  } | {
245
249
  ok: false;
@@ -292,10 +296,6 @@ export declare function recordParked(blockId: string, root?: string): void;
292
296
  export declare function recordDefaulted(blockId: string, root?: string): void;
293
297
  /** Mark that an urgent block was paged to the phone. */
294
298
  export declare function recordNotified(blockId: string, root?: string): void;
295
- /** Convenience: record that a terminal answer closed the block. */
296
- export declare function recordTerminalAnswer(blockId: string, root?: string): void;
297
- /** Remove answered marker and receipts for a block (used by block removal/GC). */
298
- export declare function clearBlockLifecycle(blockId: string, root?: string): void;
299
299
  /** Identity of the agent declaring a block — the subset of `PostIdentity` it needs. */
300
300
  export interface DeclaringAgent {
301
301
  sessionId: string;
@@ -304,7 +304,7 @@ export interface DeclaringAgent {
304
304
  runtime: string;
305
305
  cwd?: string;
306
306
  }
307
- export interface DeclareBlockInput {
307
+ interface DeclareBlockInput {
308
308
  /** What the agent needs from the user, front-loaded. */
309
309
  text: string;
310
310
  /** Answerable choices, if the ask is a pick-one. */
@@ -347,40 +347,6 @@ export declare function removeBlock(blockId: string, root?: string): boolean;
347
347
  * CLI-writable user hooks dir without a separate file in the npm tarball.
348
348
  */
349
349
  export declare const FEED_PUBLISH_HOOK_SCRIPT = "#!/usr/bin/env python3\n\"\"\"Publish and clear open-block records for `agents feed`.\n\nThe manifest invokes this script for top-level AskUserQuestion calls, waiting\nnotifications, question answers, and session lifecycle events. One atomic file\nper session means a new block replaces the previous block. Answer/resume/stop\nevents remove it so `agents feed` only lists decisions that are still open.\n\nSub-agent gate: when the PreToolUse payload carries `agent_type`, this is a\nTask/Agent subagent -- skip. Only the top-level agent publishes. Verified on\nClaude Code 2.1.170 (2026-07).\n\nFail-open: ANY error is swallowed so a feed hiccup never blocks a tool call.\n\"\"\"\nimport os\nimport sys\nimport json\nimport re\nimport socket\nimport tempfile\nfrom datetime import datetime, timezone\n\n# Notification subtypes that mean something is PENDING. Claude's idle_prompt is\n# deliberately absent: it fires a minute after the turn ended with the operator\n# idle, which is a finished turn, not a request -- publishing it put an\n# Approve/Deny banner on a session that had already answered \"pong\" (PHNX-3999).\nWAITING_NOTIFICATION_TYPES = {\n \"permission_prompt\",\n \"elicitation_dialog\",\n}\nCLEAR_EVENTS = {\n \"PostToolUse\",\n \"Stop\",\n \"SessionEnd\",\n}\n# Codex emits a PermissionRequest event (not Claude's Notification) when it\n# blocks on an approval prompt. Claude never fires PermissionRequest, so the\n# same script handles both: PermissionRequest maps to an approval-class block\n# with a high cost-of-delay so 'agents feed --dispatch' pages it as urgent.\n\n\ndef read_json(path):\n try:\n with open(path) as f:\n return json.load(f)\n except Exception:\n return None\n\n\ndef write_json(path, value):\n dir_name = os.path.dirname(path)\n os.makedirs(dir_name, exist_ok=True)\n fd, tmp = tempfile.mkstemp(dir=dir_name, suffix=\".tmp\")\n try:\n with os.fdopen(fd, \"w\") as f:\n json.dump(value, f, indent=2)\n os.replace(tmp, path)\n except Exception:\n try:\n os.unlink(tmp)\n except Exception:\n pass\n\n\ndef project_from_cwd(cwd):\n \"\"\"Basename of cwd, with worktree paths resolved to their repo name.\"\"\"\n if not cwd:\n return None\n norm = cwd.replace(\"\\\\\", \"/\").rstrip(\"/\")\n if not norm:\n return None\n marker = \"/.agents/worktrees/\"\n idx = norm.find(marker)\n if idx > 0:\n repo_path = norm[:idx]\n base = repo_path[repo_path.rfind(\"/\") + 1:]\n if base:\n return base\n base = norm[norm.rfind(\"/\") + 1:]\n return base or None\n\n\ndef main():\n raw = sys.stdin.read()\n try:\n payload = json.loads(raw) if raw.strip() else {}\n except Exception:\n return\n\n # Sub-agent gate.\n if payload.get(\"agent_type\"):\n return\n\n session_id = payload.get(\"session_id\", \"\")\n if not session_id:\n return\n\n safe_session_id = re.sub(r\"[^A-Za-z0-9._-]\", \"-\", session_id)\n block_id = f\"block-{safe_session_id}\"\n home = os.environ.get(\"HOME\") or os.path.expanduser(\"~\")\n feed_dir = os.path.join(home, \".agents\", \".history\", \"feed\")\n answered_dir = os.path.join(feed_dir, \"answered\")\n asks_dir = os.path.join(feed_dir, \"asks\")\n target = os.path.join(feed_dir, f\"{block_id}.json\")\n hook_event = payload.get(\"hook_event_name\", \"PreToolUse\")\n\n if hook_event in CLEAR_EVENTS:\n # A declared block (`agents feed post --blocked`) is the agent explicitly\n # saying it is stuck. Unlike a question/notification/approval block -- which\n # tracks an in-flight harness prompt that a lifecycle event resolves -- a\n # declared block stays open until it is actually ANSWERED. So while it is\n # still UNANSWERED, Stop/SessionEnd/PostToolUse must never silently drop it:\n # otherwise the needs-you record vanishes the moment the agent parks the block\n # and its turn ends -- exactly when the owner still needs to see and answer it.\n # Once it IS answered (an answered marker exists), it clears like any other\n # block by falling through below -- which frees that marker too, so a later\n # `--blocked` in the same session is not falsely locked as already-answered\n # (recordAnswer creates the marker with O_EXCL).\n try:\n with open(target) as existing_file:\n existing = json.load(existing_file)\n answered = os.path.exists(os.path.join(answered_dir, f\"{block_id}.json\"))\n if existing.get(\"kind\") == \"declared\" and not answered:\n return\n except Exception:\n pass\n # A matcher-less PostToolUse clear (registered for Codex so an approved\n # tool clears its approval card) must NOT wipe an open AskUserQuestion\n # while an unrelated tool runs mid-question -- those are cleared only by\n # the AskUserQuestion-matched PostToolUse. So on PostToolUse, keep a\n # 'question' block; approval/notification blocks clear once the tool runs.\n if hook_event == \"PostToolUse\":\n try:\n with open(target) as existing_file:\n existing = json.load(existing_file)\n if existing.get(\"kind\") == \"question\" and payload.get(\"tool_name\") != \"AskUserQuestion\":\n return\n except Exception:\n pass\n try:\n os.unlink(target)\n except FileNotFoundError:\n pass\n except Exception:\n pass\n # Also clear the answered marker so a future question for this session\n # is not permanently locked.\n try:\n os.unlink(os.path.join(answered_dir, f\"{block_id}.json\"))\n except FileNotFoundError:\n pass\n except Exception:\n pass\n return\n\n # Terminal answers (human typed in the TUI) record an answered marker and\n # remove the block file so the feed stops showing it within one poll cycle.\n # The marker stays behind so a concurrent surface cannot double-answer.\n # A resolution tombstone is written BEFORE unlink (matching TS recordAnswer)\n # so a stale lifecycle re-read cannot resurrect this generation.\n if hook_event == \"UserPromptSubmit\":\n os.makedirs(answered_dir, exist_ok=True)\n marker = os.path.join(answered_dir, f\"{block_id}.json\")\n now_iso = datetime.now(timezone.utc).isoformat()\n try:\n fd = os.open(marker, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)\n record = {\n \"answeredAt\": now_iso,\n \"answeredFrom\": \"terminal\",\n }\n with os.fdopen(fd, \"w\") as f:\n json.dump(record, f, indent=2)\n except FileExistsError:\n pass\n except Exception:\n pass\n # Tombstone first, then drop the open-block view. A missing/corrupt\n # block means there is nothing to resolve; fail open.\n existing = read_json(target)\n if isinstance(existing, dict):\n generation = existing.get(\"generation\") or existing.get(\"ts\")\n if generation:\n tombstone = {\n \"blockId\": block_id,\n \"generation\": generation,\n \"resolvedAt\": now_iso,\n \"reason\": \"answered\",\n }\n source_cursor = existing.get(\"sourceCursor\")\n if source_cursor:\n tombstone[\"sourceCursor\"] = source_cursor\n write_json(\n os.path.join(feed_dir, \"resolutions\", f\"{block_id}.json\"),\n tombstone,\n )\n # Remove the visible block so the feed drops the answered question.\n try:\n os.unlink(target)\n except FileNotFoundError:\n pass\n except Exception:\n pass\n return\n\n notification_type = None\n codex_approval = False\n if hook_event == \"Notification\":\n notification_type = payload.get(\"notification_type\", \"\")\n if notification_type not in WAITING_NOTIFICATION_TYPES:\n return\n # Claude emits a generic permission notification after presenting an\n # AskUserQuestion. Keep the structured questions and options already\n # published for this session instead of replacing them with that less\n # useful notification text.\n try:\n with open(target) as existing_file:\n existing = json.load(existing_file)\n if existing.get(\"kind\") == \"question\":\n return\n except Exception:\n pass\n message = payload.get(\"message\", \"\")\n if not message:\n return\n normalized_questions = [{\n \"text\": message,\n \"header\": payload.get(\"title\") or notification_type.replace(\"_\", \" \").title(),\n \"multiSelect\": False,\n }]\n kind = \"notification\"\n elif hook_event == \"PermissionRequest\":\n # Codex approval prompt. The payload mirrors PreToolUse (tool_name,\n # tool_input) but carries no questions -- Codex is asking to run a tool,\n # not asking the operator a multiple-choice question. Publish it as a\n # notification-kind approval block naming the tool so the feed and the\n # phone notifier can surface it, and so AGI EXT can bridge\n # it to a VS Code notification.\n tool_name = payload.get(\"tool_name\") or \"a tool\"\n tool_input = payload.get(\"tool_input\", {})\n command = \"\"\n if isinstance(tool_input, dict):\n command = (\n tool_input.get(\"command\")\n or tool_input.get(\"cmd\")\n or tool_input.get(\"path\")\n or \"\"\n )\n if isinstance(command, list):\n command = \" \".join(str(c) for c in command)\n detail = f\": {command}\" if command else \"\"\n normalized_questions = [{\n \"text\": f\"Codex needs approval to run {tool_name}{detail}\",\n \"header\": \"Approval needed\",\n \"multiSelect\": False,\n }]\n kind = \"notification\"\n notification_type = \"permission_prompt\"\n codex_approval = True\n else:\n tool_input = payload.get(\"tool_input\", {})\n questions = tool_input.get(\"questions\", [])\n if not questions:\n return\n normalized_questions = []\n for q in questions:\n if not isinstance(q, dict):\n continue\n question = {\n \"text\": q.get(\"question\", q.get(\"header\", \"\")),\n \"header\": q.get(\"header\"),\n \"multiSelect\": q.get(\"multiSelect\", False),\n }\n raw_opts = q.get(\"options\", [])\n if raw_opts:\n question[\"options\"] = [\n {\"label\": o.get(\"label\", \"\"), \"description\": o.get(\"description\")}\n for o in raw_opts\n if isinstance(o, dict)\n ]\n normalized_questions.append(question)\n if not normalized_questions:\n return\n kind = \"question\"\n\n # Identity from env (set by agents-cli at spawn).\n mailbox_id = os.path.basename(\n os.environ.get(\"AGENTS_MAILBOX_DIR\", \"\").rstrip(\"/\")\n ) or session_id\n\n now = datetime.now(timezone.utc)\n now_iso = now.isoformat()\n now_ms = int(now.timestamp() * 1000)\n stats_path = os.path.join(asks_dir, f\"{safe_session_id}.json\")\n stats = read_json(stats_path) or {}\n recent = stats.get(\"recentAskTimestamps\") if isinstance(stats, dict) else []\n if not isinstance(recent, list):\n recent = []\n recent.append(now_iso)\n # Keep enough history for rolling one-hour needy detection without unbounded\n # per-session files. The TypeScript reader applies the exact time window.\n recent = recent[-200:]\n write_json(stats_path, {\n \"sessionId\": session_id,\n \"mailboxId\": mailbox_id,\n \"firstAskAt\": stats.get(\"firstAskAt\") or now_iso,\n \"lastAskAt\": now_iso,\n \"totalAskCount\": int(stats.get(\"totalAskCount\") or 0) + 1,\n \"recentAskTimestamps\": recent,\n })\n\n hostname = os.environ.get(\"AGENTS_SYNC_MACHINE_ID\") or socket.gethostname()\n host = hostname.split(\".\")[0].strip().lower()\n host = re.sub(r\"[^a-z0-9_-]\", \"-\", host) or \"unknown\"\n\n runtime = os.environ.get(\"AGENTS_RUNTIME\", \"headless\")\n cwd = payload.get(\"cwd\") or os.environ.get(\"AGENTS_CWD\")\n project = project_from_cwd(cwd)\n\n block = {\n \"blockId\": block_id,\n \"sessionId\": session_id,\n \"mailboxId\": mailbox_id,\n \"host\": host,\n \"runtime\": runtime,\n \"ts\": now_iso,\n # Write-time cursor so a new generation is not suppressed when\n # session.lastActivityMs is unresolvable (cloud / remote / index-lag).\n \"sourceCursor\": {\"lastActivityMs\": now_ms},\n \"questions\": normalized_questions,\n \"kind\": kind,\n }\n if project:\n block[\"project\"] = project\n if notification_type:\n block[\"notificationType\"] = notification_type\n\n # A Codex PermissionRequest is a real approval gate: mark it approval-class\n # with a high cost-of-delay so 'agents feed --dispatch' classifies it urgent\n # (isPhoneUrgent gates on costOfDelay >= phoneNotifyThreshold, default\n # 'medium') and pages the phone. A plain 'deny' is the safe default.\n if codex_approval:\n block[\"blockClass\"] = \"approval\"\n block[\"costOfDelay\"] = \"high\"\n block[\"safeDefault\"] = \"deny\"\n\n # Optional multi-operator control metadata passed by the agent in the\n # AskUserQuestion tool_input. Defaults keep the existing behavior. A Codex\n # PermissionRequest carries tool ARGS in tool_input (command/path), not\n # operator controls, so it is excluded here -- its class/cost is stamped\n # above from codex_approval.\n controls = payload.get(\"tool_input\", {}) if hook_event not in (\"Notification\", \"PermissionRequest\") else {}\n block_class = controls.get(\"blockClass\") if isinstance(controls, dict) else None\n if block_class in (\"approval\", \"decision\"):\n block[\"blockClass\"] = block_class\n consequence = controls.get(\"consequence\") if isinstance(controls, dict) else None\n if consequence:\n block[\"consequence\"] = consequence\n allowed = controls.get(\"allowedOperators\") if isinstance(controls, dict) else None\n if isinstance(allowed, list):\n block[\"allowedOperators\"] = [str(a) for a in allowed]\n timeout = controls.get(\"timeoutMinutes\") if isinstance(controls, dict) else None\n if isinstance(timeout, (int, float)) and timeout > 0:\n block[\"timeoutMinutes\"] = int(timeout)\n safe_default = controls.get(\"safeDefault\") if isinstance(controls, dict) else None\n if isinstance(safe_default, str):\n block[\"safeDefault\"] = safe_default\n cost = controls.get(\"costOfDelay\") if isinstance(controls, dict) else None\n if cost in (\"low\", \"medium\", \"high\"):\n block[\"costOfDelay\"] = cost\n\n # Publishing a new question clears any stale answered marker from the\n # previous question in this session.\n try:\n os.unlink(os.path.join(answered_dir, f\"{block_id}.json\"))\n except FileNotFoundError:\n pass\n except Exception:\n pass\n\n # Python's expanduser() ignores HOME on Windows, while agents-cli honors a\n # HOME override on every platform. Use the same anchor so hooks and the CLI\n # always read/write one feed store (including temp-home and sandbox runs).\n os.makedirs(feed_dir, exist_ok=True)\n\n fd, tmp = tempfile.mkstemp(dir=feed_dir, suffix=\".tmp\")\n try:\n with os.fdopen(fd, \"w\") as f:\n json.dump(block, f, indent=2)\n os.replace(tmp, target)\n except Exception:\n try:\n os.unlink(tmp)\n except Exception:\n pass\n\n\nif __name__ == \"__main__\":\n try:\n main()\n except Exception:\n pass # fail open\n";
350
- /** Manifest entry for the feed-publish hook, matching the ManifestHook shape. */
351
- export declare const FEED_PUBLISH_HOOK_MANIFEST: {
352
- name: string;
353
- events: string[];
354
- matcher: string;
355
- script: string;
356
- timeout: number;
357
- };
358
- export declare const FEED_NOTIFICATION_HOOK_MANIFEST: {
359
- name: string;
360
- events: string[];
361
- matcher: string;
362
- script: string;
363
- timeout: number;
364
- };
365
- export declare const FEED_PERMISSION_HOOK_MANIFEST: {
366
- name: string;
367
- events: string[];
368
- script: string;
369
- timeout: number;
370
- };
371
- export declare const FEED_ANSWERED_HOOK_MANIFEST: {
372
- name: string;
373
- events: string[];
374
- matcher: string;
375
- script: string;
376
- timeout: number;
377
- };
378
- export declare const FEED_LIFECYCLE_HOOK_MANIFEST: {
379
- name: string;
380
- events: string[];
381
- script: string;
382
- timeout: number;
383
- };
384
350
  /**
385
351
  * Install the feed-publish hook script into the user hooks dir and add its
386
352
  * manifest entry to the user agents.yaml. The system repo is an auto-pulled,
@@ -391,3 +357,4 @@ export declare function ensureFeedPublishHook(userAgentsDir?: string): {
391
357
  installed: boolean;
392
358
  error?: string;
393
359
  };
360
+ export {};
@@ -85,24 +85,6 @@ export function recordResolution(resolution, root) {
85
85
  export function readResolution(blockId, root) {
86
86
  return safeReadJson(path.join(resolutionDir(root ?? getFeedDir()), `${blockId}.json`));
87
87
  }
88
- /** Read every resolution tombstone. Returns them sorted by stable block filename. */
89
- export function listResolutions(root) {
90
- const dir = resolutionDir(root ?? getFeedDir());
91
- let names;
92
- try {
93
- names = fs.readdirSync(dir);
94
- }
95
- catch {
96
- return [];
97
- }
98
- const out = [];
99
- for (const name of names.filter(n => n.endsWith('.json')).sort()) {
100
- const parsed = safeReadJson(path.join(dir, name));
101
- if (parsed?.blockId && parsed.generation && parsed.reason)
102
- out.push(parsed);
103
- }
104
- return out;
105
- }
106
88
  /**
107
89
  * Stable block id for a session. One block per session -- a new question
108
90
  * replaces the previous one (the agent can only ask one question at a time).
@@ -345,12 +327,8 @@ export function recordNotified(blockId, root) {
345
327
  block.notifiedAt = new Date().toISOString();
346
328
  publishBlock(block, dir);
347
329
  }
348
- /** Convenience: record that a terminal answer closed the block. */
349
- export function recordTerminalAnswer(blockId, root) {
350
- recordAnswer(blockId, { answeredFrom: 'terminal' }, root);
351
- }
352
330
  /** Remove answered marker and receipts for a block (used by block removal/GC). */
353
- export function clearBlockLifecycle(blockId, root) {
331
+ function clearBlockLifecycle(blockId, root) {
354
332
  const dir = root ?? getFeedDir();
355
333
  for (const sub of [answeredDir(dir), receiptDir(dir)]) {
356
334
  try {
@@ -913,43 +891,6 @@ if __name__ == "__main__":
913
891
  except Exception:
914
892
  pass # fail open
915
893
  `;
916
- /** Manifest entry for the feed-publish hook, matching the ManifestHook shape. */
917
- export const FEED_PUBLISH_HOOK_MANIFEST = {
918
- name: 'feed-publish',
919
- events: ['PreToolUse'],
920
- matcher: 'AskUserQuestion',
921
- script: '10-feed-publish.py',
922
- timeout: 5,
923
- };
924
- export const FEED_NOTIFICATION_HOOK_MANIFEST = {
925
- name: 'feed-publish-notification',
926
- events: ['Notification'],
927
- matcher: 'permission_prompt|elicitation_dialog',
928
- script: '10-feed-publish.py',
929
- timeout: 5,
930
- };
931
- // Codex fires PermissionRequest (not Claude's Notification) when it blocks on an
932
- // approval prompt. The same script handles it, publishing a high-cost approval
933
- // block so the feed dispatch pages the phone. PermissionRequest has no matcher.
934
- export const FEED_PERMISSION_HOOK_MANIFEST = {
935
- name: 'feed-publish-permission',
936
- events: ['PermissionRequest'],
937
- script: '10-feed-publish.py',
938
- timeout: 5,
939
- };
940
- export const FEED_ANSWERED_HOOK_MANIFEST = {
941
- name: 'feed-clear-answered',
942
- events: ['PostToolUse'],
943
- matcher: 'AskUserQuestion',
944
- script: '10-feed-publish.py',
945
- timeout: 5,
946
- };
947
- export const FEED_LIFECYCLE_HOOK_MANIFEST = {
948
- name: 'feed-clear-lifecycle',
949
- events: ['Stop', 'UserPromptSubmit', 'SessionEnd'],
950
- script: '10-feed-publish.py',
951
- timeout: 5,
952
- };
953
894
  /**
954
895
  * Install the feed-publish hook script into the user hooks dir and add its
955
896
  * manifest entry to the user agents.yaml. The system repo is an auto-pulled,
@@ -3,7 +3,6 @@ import type { DetectedPr } from '../session/state.js';
3
3
  import type { GhExec } from '../github/pr-mergeable.js';
4
4
  import type { PullRequestAttentionSignal } from './attention.js';
5
5
  export declare const PR_STATUS_TTL_MS = 45000;
6
- export declare const PR_STATUS_FIELDS = "number,title,state,isDraft,reviewDecision,mergeable,statusCheckRollup";
7
6
  export interface PullRequestStatus extends PullRequestAttentionSignal {
8
7
  statusCheckRollup?: unknown[];
9
8
  }
@@ -13,7 +12,6 @@ export declare function readPullRequestStatus(session: ActiveSession, options?:
13
12
  ttlMs?: number;
14
13
  gh?: GhExec;
15
14
  }): Promise<PullRequestStatus | undefined>;
16
- export declare function projectPullRequestBoard(sessions: ActiveSession[]): Promise<PullRequestStatus[]>;
17
15
  export declare function resetPullRequestStatusCache(): void;
18
16
  /**
19
17
  * The check rollup folded to one verdict; undefined when the PR has no checks.
@@ -2,7 +2,7 @@ import { execFile } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
3
  const execFileAsync = promisify(execFile);
4
4
  export const PR_STATUS_TTL_MS = 45_000;
5
- export const PR_STATUS_FIELDS = 'number,title,state,isDraft,reviewDecision,mergeable,statusCheckRollup';
5
+ const PR_STATUS_FIELDS = 'number,title,state,isDraft,reviewDecision,mergeable,statusCheckRollup';
6
6
  const cache = new Map();
7
7
  function needsHuman(value) {
8
8
  if (value.state !== 'OPEN' || value.isDraft)
@@ -38,10 +38,6 @@ export async function readPullRequestStatus(session, options = {}) {
38
38
  return undefined;
39
39
  }
40
40
  }
41
- export async function projectPullRequestBoard(sessions) {
42
- const rows = await Promise.all(sessions.map((session) => readPullRequestStatus(session)));
43
- return rows.filter((row) => row !== undefined);
44
- }
45
41
  export function resetPullRequestStatusCache() { cache.clear(); }
46
42
  /**
47
43
  * The check rollup folded to one verdict; undefined when the PR has no checks.
@@ -2,7 +2,6 @@ import { type SessionWatchEnvelope, type SessionWatchRow, type SessionWatchScope
2
2
  import { type AttentionItem } from './attention.js';
3
3
  import { type ActivityEvent } from './activity.js';
4
4
  import type { GhExec } from '../github/pr-mergeable.js';
5
- export declare const FEED_WATCH_VERSION: 1;
6
5
  type Base = {
7
6
  v: 1;
8
7
  type: string;
@@ -48,8 +47,17 @@ export declare class FeedWatchState {
48
47
  constructor(streamId?: `${string}-${string}-${string}-${string}-${string}`);
49
48
  emit(event: FeedWatchPayload): FeedWatchEnvelope;
50
49
  }
50
+ /** Reuse session ownership reconciliation for the combined operator stream. */
51
+ export declare class FeedSessionProjection {
52
+ private readonly state;
53
+ private readonly sessions;
54
+ private readonly observations;
55
+ private projectedAttention;
56
+ constructor(state?: FeedWatchState);
57
+ apply(event: FeedWatchEnvelope): FeedWatchEnvelope[];
58
+ }
51
59
  export declare function projectSessionEnvelope(event: SessionWatchEnvelope, state: FeedWatchState, gh?: GhExec): Promise<FeedWatchEnvelope[]>;
52
- export interface WatchLocalFeedOptions {
60
+ interface WatchLocalFeedOptions {
53
61
  scope: string;
54
62
  signal: AbortSignal;
55
63
  emit: (event: FeedWatchEnvelope) => void;
@@ -1,3 +1,4 @@
1
+ import { SessionProjection } from '../session/projection.js';
1
2
  import { randomUUID } from 'node:crypto';
2
3
  import * as fs from 'node:fs';
3
4
  import * as path from 'node:path';
@@ -12,7 +13,6 @@ import { readBlock, readResolution, blockIdForSession } from './feed.js';
12
13
  import { reconcileAttention } from './attention.js';
13
14
  import { ActivityStream } from './activity-stream.js';
14
15
  import { PR_STATUS_TTL_MS, readPullRequestStatus, withPullRequestStatus } from './pr-status.js';
15
- export const FEED_WATCH_VERSION = 1;
16
16
  export class FeedWatchState {
17
17
  streamId;
18
18
  sequence = 0;
@@ -21,6 +21,86 @@ export class FeedWatchState {
21
21
  return { v: 1, streamId: this.streamId, sequence: ++this.sequence, ...event };
22
22
  }
23
23
  }
24
+ /** Reuse session ownership reconciliation for the combined operator stream. */
25
+ export class FeedSessionProjection {
26
+ state;
27
+ sessions = new SessionProjection();
28
+ observations = new Map();
29
+ projectedAttention = new Map();
30
+ constructor(state = new FeedWatchState()) {
31
+ this.state = state;
32
+ }
33
+ apply(event) {
34
+ const scope = normalizeHost(event.scope);
35
+ const base = { version: 1, streamId: event.streamId, sequence: event.sequence, capturedAt: 'capturedAt' in event ? event.capturedAt : Date.now(), scope };
36
+ let sessionEvent;
37
+ if (event.type === 'reset') {
38
+ sessionEvent = { ...base, type: 'reset', rows: event.agents };
39
+ const attention = new Map();
40
+ for (const row of event.agents) {
41
+ const item = event.attention.find(item => item.sessionId === row.sessionId);
42
+ if (item && !row.previous)
43
+ attention.set(row.rowKey, item);
44
+ }
45
+ this.observations.set(scope, attention);
46
+ }
47
+ else if (event.type === 'agent.upsert') {
48
+ sessionEvent = { ...base, type: 'upsert', rowKey: event.rowKey, row: event.agent };
49
+ }
50
+ else if (event.type === 'agent.remove') {
51
+ sessionEvent = { ...base, type: 'remove', rowKey: event.rowKey };
52
+ this.observations.get(scope)?.delete(event.rowKey);
53
+ }
54
+ else if (event.type === 'attention.upsert') {
55
+ if (!this.observations.has(scope))
56
+ this.observations.set(scope, new Map());
57
+ this.observations.get(scope).set(event.rowKey, event.attention);
58
+ }
59
+ else if (event.type === 'attention.remove') {
60
+ this.observations.get(scope)?.delete(event.rowKey);
61
+ }
62
+ else {
63
+ const { v: _v, streamId: _streamId, sequence: _sequence, ...payload } = event;
64
+ return [this.state.emit(payload)];
65
+ }
66
+ const projected = sessionEvent ? this.sessions.apply(sessionEvent) : [];
67
+ const next = new Map();
68
+ for (const [observer, items] of this.observations)
69
+ for (const [rowKey, item] of items) {
70
+ const row = this.sessions.rowForObservation(observer, rowKey);
71
+ if (row && !row.previous && row.sourceDevice === observer)
72
+ next.set(item.key, { scope: observer, item });
73
+ }
74
+ const result = [];
75
+ const resetScopes = new Set();
76
+ for (const rowEvent of projected) {
77
+ if (rowEvent.type === 'reset') {
78
+ resetScopes.add(rowEvent.scope);
79
+ result.push(this.state.emit({ type: 'reset', scope: rowEvent.scope, capturedAt: rowEvent.capturedAt, agents: rowEvent.rows,
80
+ attention: [...next.values()].filter(value => value.scope === rowEvent.scope).map(value => value.item) }));
81
+ }
82
+ else if (rowEvent.type === 'upsert') {
83
+ result.push(this.state.emit({ type: 'agent.upsert', scope: rowEvent.scope, rowKey: rowEvent.rowKey, agent: rowEvent.row }));
84
+ }
85
+ else if (rowEvent.type === 'remove') {
86
+ result.push(this.state.emit({ type: 'agent.remove', scope: rowEvent.scope, rowKey: rowEvent.rowKey }));
87
+ }
88
+ }
89
+ // Attention has its own stable generation key, also used by feed answer.
90
+ // Never substitute the projected agent row key: reset consumers key by item.key.
91
+ for (const [key, previous] of this.projectedAttention) {
92
+ if (!next.has(key) && !resetScopes.has(previous.scope))
93
+ result.push(this.state.emit({ type: 'attention.remove', scope: previous.scope, rowKey: key }));
94
+ }
95
+ for (const [key, value] of next) {
96
+ if (!resetScopes.has(value.scope) && JSON.stringify(this.projectedAttention.get(key)) !== JSON.stringify(value)) {
97
+ result.push(this.state.emit({ type: 'attention.upsert', scope: value.scope, rowKey: key, attention: value.item }));
98
+ }
99
+ }
100
+ this.projectedAttention = next;
101
+ return result;
102
+ }
103
+ }
24
104
  /**
25
105
  * Live rows only: durable Previous rows share the operator stream for Sessions
26
106
  * history, but they are not live work and must never synthesize Needs-you
@@ -92,13 +172,19 @@ function watchAttentionStores(onChange) {
92
172
  const watchers = [];
93
173
  for (const dir of [feedDir, path.join(feedDir, 'resolutions')]) {
94
174
  try {
175
+ // `resolutions` is created lazily by the first `recordResolution` call, so
176
+ // a fresh feed dir has no directory to watch yet. Create it up front —
177
+ // otherwise fs.watch throws ENOENT here, is swallowed, and never retried,
178
+ // silently downgrading every resolution to the 45 s PR-status fallback
179
+ // instead of the event-driven reconcile this function exists to provide.
180
+ fs.mkdirSync(dir, { recursive: true });
95
181
  const watcher = fs.watch(dir, () => onChange());
96
182
  // A directory that disappears must not take the watcher process down; the
97
183
  // PR-status cadence below still reconciles on its own timer.
98
184
  watcher.on('error', () => watcher.close());
99
185
  watchers.push(watcher);
100
186
  }
101
- catch { /* the dir appears with the first block; the timed pass covers it */ }
187
+ catch { /* best-effort: the timed pass still reconciles on its own cadence */ }
102
188
  }
103
189
  return () => { for (const watcher of watchers)
104
190
  watcher.close(); };
@@ -217,9 +303,10 @@ function remoteFeedWatchCommand(os) {
217
303
  }
218
304
  export async function watchFleetFeed(options) {
219
305
  const coordinator = new FeedWatchState();
306
+ const projection = new FeedSessionProjection(coordinator);
220
307
  const forward = (event) => {
221
- const { v: _v, streamId: peerStreamId, sequence: peerSequence, ...payload } = event;
222
- options.emit(coordinator.emit({ ...payload, peerStreamId, peerSequence }));
308
+ for (const projected of projection.apply(event))
309
+ options.emit(projected);
223
310
  };
224
311
  const local = watchLocalFeed({ scope: machineId(), signal: options.signal, emit: forward });
225
312
  let devices;
@@ -14,9 +14,9 @@ export interface FeedSinkConfig {
14
14
  command?: string[];
15
15
  /**
16
16
  * In-process delivery through the same channel-provider registry `agents
17
- * send`/`agents notify` use — the composed `{message}` body, no argv, no
17
+ * send`/`agents send --to owner` use — the composed `{message}` body, no argv, no
18
18
  * spawn. `'owner'` is the address alias (expands to `notify.owner.{channel,to}`
19
- * in agents.yaml, same as `agents notify`); any other value is a registered
19
+ * in agents.yaml, same as `agents send --to owner`); any other value is a registered
20
20
  * channel name (or a `notify.transports` mapping) and requires `to`.
21
21
  */
22
22
  channel?: string;
@@ -113,7 +113,7 @@ export declare function blockBroadcastContext(block: {
113
113
  * not mask a delivered desktop notification.
114
114
  */
115
115
  export declare function blockDeliveryFailure(blocked: boolean, outcomes: SinkOutcome[]): string | undefined;
116
- export interface PlannedSink {
116
+ interface PlannedSink {
117
117
  name: string;
118
118
  /** Command sink: argv to spawn (mutually exclusive with `channel`). */
119
119
  argv?: string[];
@@ -141,49 +141,6 @@ export interface SinkOutcome {
141
141
  /** stderr tail when the sink failed, for the warning line. */
142
142
  error?: string;
143
143
  }
144
- /**
145
- * Short host label for a phone line — strip user@ and domain so
146
- * `muqsit@mac-mini.tailnet.ts.net` reads as `mac-mini`.
147
- */
148
- export declare function shortHost(host: string | undefined): string | undefined;
149
- /** First 8 hex chars of a session id for the footer (readable, not a full uuid). */
150
- export declare function shortSessionChunk(session: string | undefined): string | undefined;
151
- /**
152
- * Tap-to-view link for the session behind a post: the addressable console page
153
- * ({@link https://prix.dev/console/sessions/<id>}, prix/web). The footer already
154
- * carries a short session crumb for disambiguation; this rides the link trail so
155
- * the owner can open the full transcript straight from an iMessage broadcast
156
- * instead of hunting for it in the console.
157
- *
158
- * Accepts any real, path-safe session id — a Claude/Codex UUID *and* a native
159
- * `ses_…` id from OpenCode or another harness. The console shard uploader
160
- * (`traces/sync.ts`) syncs sessions with no harness filter, so all of them are
161
- * addressable; a UUID-only gate would silently drop the link for every non-Claude
162
- * harness (the whole point of the link). Reject only an id that could not resolve:
163
- * one with a path separator (URL-unsafe, via {@link isValidMailboxId}) or the bare
164
- * 8-char footer crumb (a truncated id that would 404).
165
- */
166
- export declare function sessionConsoleUrl(session: string | undefined): string | undefined;
167
- /**
168
- * Scrub em/en dashes from outbound phone copy (house rule + iMessage readability).
169
- * Collapses whitespace; does not invent meaning.
170
- */
171
- export declare function scrubOutboundDashes(text: string): string;
172
- /**
173
- * Footer like "Sent from my iPhone" — who posted, a session crumb, which box.
174
- *
175
- * Sent from grok/a02da0e2 on mac-mini
176
- *
177
- * Agent name first; session chunk for disambiguation when many groks run;
178
- * host last. Skip the uninformative default label `agent`.
179
- *
180
- * In `mrkdwn` the crumb (`agent/short`) becomes a Slack labeled link to the
181
- * session's console page, so the human sentence reads identically while the
182
- * crumb turns blue and taps through (PHNX-3698). `plain` keeps the bare sentence
183
- * — it can't render a labeled link and must not dump the URL.
184
- */
185
- export declare function composeBroadcastFooter(ctx: FeedBroadcastContext, format?: SinkMessageFormat): string | undefined;
186
- export declare function truncateBroadcastBody(body: string): string;
187
144
  export declare function composeBroadcastMessage(ctx: FeedBroadcastContext, format?: SinkMessageFormat): string;
188
145
  /**
189
146
  * Substitute `{placeholder}` tokens in an argv template. Returns undefined when
@@ -221,7 +178,7 @@ export declare function planFeedBroadcast(config: FeedBroadcastConfig | undefine
221
178
  * moment `feed.broadcast` was empty, even when `notify.owner` was fully
222
179
  * configured — so the common case (an operator who set up owner notifications
223
180
  * but never wrote a `feed.broadcast` block) produced a `--blocked` post that
224
- * looked recorded and reached nobody. `agents notify` already treats
181
+ * looked recorded and reached nobody. `agents send --to owner` already treats
225
182
  * `notify.owner` as the default human destination; this makes an important
226
183
  * feed post/block use that same default instead of requiring a second,
227
184
  * redundant config block that says the same thing.
@@ -265,3 +222,4 @@ export declare function withDesktopNotify(config: FeedBroadcastConfig | undefine
265
222
  * reached.
266
223
  */
267
224
  export declare function runFeedBroadcast(planned: PlannedSink[], meta: Meta, timeoutMs?: number): Promise<SinkOutcome[]>;
225
+ export {};
@@ -27,7 +27,7 @@
27
27
  * A second sink shape (RUSH-2123) delivers **in-process** through the same
28
28
  * channel-provider registry `agents send` uses (`channel:` instead of
29
29
  * `command:`) — no spawn, no argv templating. `channel: owner` is the address
30
- * alias that expands to `notify.owner.{channel,to}`, matching `agents notify`.
30
+ * alias that expands to `notify.owner.{channel,to}`, matching `agents send --to owner`.
31
31
  * When the operator has never written a `feed.broadcast` block at all, an
32
32
  * important-level post falls back to that owner address implicitly
33
33
  * ({@link effectiveBroadcastConfig}) rather than reaching nobody — see that
@@ -127,7 +127,7 @@ const PLACEHOLDER = /\{([a-z_]+)\}/g;
127
127
  * Short host label for a phone line — strip user@ and domain so
128
128
  * `muqsit@mac-mini.tailnet.ts.net` reads as `mac-mini`.
129
129
  */
130
- export function shortHost(host) {
130
+ function shortHost(host) {
131
131
  if (!host?.trim())
132
132
  return undefined;
133
133
  let h = host.trim();
@@ -140,7 +140,7 @@ export function shortHost(host) {
140
140
  return h || undefined;
141
141
  }
142
142
  /** First 8 hex chars of a session id for the footer (readable, not a full uuid). */
143
- export function shortSessionChunk(session) {
143
+ function shortSessionChunk(session) {
144
144
  if (!session?.trim())
145
145
  return undefined;
146
146
  const hex = session.replace(/-/g, '').toLowerCase();
@@ -162,7 +162,7 @@ export function shortSessionChunk(session) {
162
162
  * one with a path separator (URL-unsafe, via {@link isValidMailboxId}) or the bare
163
163
  * 8-char footer crumb (a truncated id that would 404).
164
164
  */
165
- export function sessionConsoleUrl(session) {
165
+ function sessionConsoleUrl(session) {
166
166
  const id = session?.trim();
167
167
  if (!id || !isValidMailboxId(id) || /^[0-9a-f]{8}$/i.test(id))
168
168
  return undefined;
@@ -172,7 +172,7 @@ export function sessionConsoleUrl(session) {
172
172
  * Scrub em/en dashes from outbound phone copy (house rule + iMessage readability).
173
173
  * Collapses whitespace; does not invent meaning.
174
174
  */
175
- export function scrubOutboundDashes(text) {
175
+ function scrubOutboundDashes(text) {
176
176
  return text
177
177
  .replace(/\u2014/g, ' - ')
178
178
  .replace(/\u2013/g, ' - ')
@@ -227,7 +227,7 @@ function linkifyKeys(text, format) {
227
227
  * crumb turns blue and taps through (PHNX-3698). `plain` keeps the bare sentence
228
228
  * — it can't render a labeled link and must not dump the URL.
229
229
  */
230
- export function composeBroadcastFooter(ctx, format = 'plain') {
230
+ function composeBroadcastFooter(ctx, format = 'plain') {
231
231
  const agent = ctx.agent?.trim();
232
232
  const agentLabel = agent && agent !== 'agent' ? agent : undefined;
233
233
  const session = shortSessionChunk(ctx.session);
@@ -283,7 +283,7 @@ export function composeBroadcastFooter(ctx, format = 'plain') {
283
283
  */
284
284
  const PHONE_BODY_MAX_CHARS = 500;
285
285
  const PHONE_BODY_MAX_LINES = 8;
286
- export function truncateBroadcastBody(body) {
286
+ function truncateBroadcastBody(body) {
287
287
  if (!body)
288
288
  return body;
289
289
  let out = body;
@@ -508,7 +508,7 @@ export function planFeedBroadcast(config, ctx, meta) {
508
508
  * moment `feed.broadcast` was empty, even when `notify.owner` was fully
509
509
  * configured — so the common case (an operator who set up owner notifications
510
510
  * but never wrote a `feed.broadcast` block) produced a `--blocked` post that
511
- * looked recorded and reached nobody. `agents notify` already treats
511
+ * looked recorded and reached nobody. `agents send --to owner` already treats
512
512
  * `notify.owner` as the default human destination; this makes an important
513
513
  * feed post/block use that same default instead of requiring a second,
514
514
  * redundant config block that says the same thing.
@@ -577,7 +577,7 @@ function runCommandSink(name, argv, timeoutMs) {
577
577
  }
578
578
  /**
579
579
  * Deliver one `channel:` sink through the real provider registry —
580
- * `resolveSendEnvelope` reuses `agents notify`'s owner-alias expansion, and
580
+ * `resolveSendEnvelope` reuses `agents send --to owner`'s owner-alias expansion, and
581
581
  * `deliverEnvelope` is the same seam `agents send` calls. A bad channel name
582
582
  * is checked with `lookupTransport` (the non-throwing lookup) BEFORE handing
583
583
  * off to `deliverEnvelope`: that function's own resolution `die()`s on an
@@ -1,5 +1,5 @@
1
1
  import type { OpenBlock } from './feed/feed.js';
2
- export type OutcomeKind = 'ticket' | 'pr' | 'worktree' | 'unassigned';
2
+ type OutcomeKind = 'ticket' | 'pr' | 'worktree' | 'unassigned';
3
3
  /** Stable attribution of a block (or agent) to one deliverable. */
4
4
  export interface OutcomeRef {
5
5
  /** Map/JSON key, e.g. `ticket:RUSH-1125`, `pr:#534`, `worktree:headless-secrets`, `unassigned`. */
@@ -12,7 +12,7 @@ export interface OutcomeRef {
12
12
  * Signals used to derive an outcome. All optional — callers pass whatever they
13
13
  * already know (block fields, session meta, free-text questions).
14
14
  */
15
- export interface OutcomeSignals {
15
+ interface OutcomeSignals {
16
16
  ticket?: string | null;
17
17
  pr?: string | null;
18
18
  worktreeSlug?: string | null;
@@ -29,8 +29,6 @@ export interface OutcomeSignals {
29
29
  * - Bare `#123` / `PR#123` → `#123` (no repo known)
30
30
  */
31
31
  export declare function normalizePrRef(raw: string | null | undefined): string | undefined;
32
- /** `https://github.com/owner/repo/pull/N` → `owner/repo`. */
33
- export declare function repoFromPrUrl(url: string | null | undefined): string | undefined;
34
32
  /** Canonical ticket id (uppercase team key). */
35
33
  export declare function normalizeTicketRef(raw: string | null | undefined): string | undefined;
36
34
  /**
@@ -38,8 +36,6 @@ export declare function normalizeTicketRef(raw: string | null | undefined): stri
38
36
  * Exactly one outcome per call — never ambiguous, never empty.
39
37
  */
40
38
  export declare function deriveOutcome(signals: OutcomeSignals): OutcomeRef;
41
- /** Join question headers + bodies into one scan target for ticket/PR detection. */
42
- export declare function blockScanText(block: Pick<OpenBlock, 'questions'>): string;
43
39
  /** Outcome for a stored open block (uses stamped fields + question text). */
44
40
  export declare function outcomeForBlock(block: OpenBlock): OutcomeRef;
45
41
  /** Per-outcome rollup used by the default `agents feed` view. */
@@ -103,3 +99,4 @@ export declare function enrichBlockFromSession(block: OpenBlock, hint: SessionOu
103
99
  * Matching order: mailboxId, then sessionId, then agentId.
104
100
  */
105
101
  export declare function enrichBlocksFromSessions(blocks: OpenBlock[], sessions: SessionOutcomeHint[]): OpenBlock[];
102
+ export {};
@@ -44,7 +44,7 @@ export function normalizePrRef(raw) {
44
44
  return undefined;
45
45
  }
46
46
  /** `https://github.com/owner/repo/pull/N` → `owner/repo`. */
47
- export function repoFromPrUrl(url) {
47
+ function repoFromPrUrl(url) {
48
48
  if (!url)
49
49
  return undefined;
50
50
  const m = /github\.com\/([^/\s]+)\/([^/\s]+)\/pull\/\d+/i.exec(url);
@@ -116,7 +116,7 @@ export function deriveOutcome(signals) {
116
116
  return UNASSIGNED;
117
117
  }
118
118
  /** Join question headers + bodies into one scan target for ticket/PR detection. */
119
- export function blockScanText(block) {
119
+ function blockScanText(block) {
120
120
  return block.questions
121
121
  .map((q) => [q.header, q.text].filter(Boolean).join(' '))
122
122
  .filter(Boolean)