@songsid/agend 2.3.0-beta.8 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (736) hide show
  1. package/README.md +16 -8
  2. package/README.zh-TW.md +16 -8
  3. package/dist/adapter-world.js.map +1 -1
  4. package/dist/agend-home.d.ts +5 -0
  5. package/dist/agend-home.js +7 -0
  6. package/dist/agend-home.js.map +1 -0
  7. package/dist/agent-cli-instructions.md +9 -2
  8. package/dist/agent-cli.js +44 -0
  9. package/dist/agent-cli.js.map +1 -1
  10. package/dist/agent-endpoint.d.ts +9 -0
  11. package/dist/agent-endpoint.js +23 -0
  12. package/dist/agent-endpoint.js.map +1 -1
  13. package/dist/agent-file-read.js +1 -1
  14. package/dist/agent-file-read.js.map +1 -1
  15. package/dist/agent-whats-new.d.ts +16 -0
  16. package/dist/agent-whats-new.js +54 -11
  17. package/dist/agent-whats-new.js.map +1 -1
  18. package/dist/apply-job.js.map +1 -1
  19. package/dist/atomic-write.js.map +1 -1
  20. package/dist/auth-api.d.ts +12 -0
  21. package/dist/auth-api.js +77 -22
  22. package/dist/auth-api.js.map +1 -1
  23. package/dist/authority/authority-state.d.ts +4 -0
  24. package/dist/authority/authority-state.js +17 -8
  25. package/dist/authority/authority-state.js.map +1 -1
  26. package/dist/authority/session-authorizations.js.map +1 -1
  27. package/dist/authority/web-authority.d.ts +16 -8
  28. package/dist/authority/web-authority.js +19 -5
  29. package/dist/authority/web-authority.js.map +1 -1
  30. package/dist/backend/antigravity.d.ts +2 -2
  31. package/dist/backend/antigravity.js +2 -1
  32. package/dist/backend/antigravity.js.map +1 -1
  33. package/dist/backend/claude-code.js +13 -4
  34. package/dist/backend/claude-code.js.map +1 -1
  35. package/dist/backend/codex-metadata.d.ts +8 -0
  36. package/dist/backend/codex-metadata.js +74 -17
  37. package/dist/backend/codex-metadata.js.map +1 -1
  38. package/dist/backend/codex-package.d.ts +30 -0
  39. package/dist/backend/codex-package.js +133 -0
  40. package/dist/backend/codex-package.js.map +1 -0
  41. package/dist/backend/codex-session-lookup.js.map +1 -1
  42. package/dist/backend/codex.d.ts +2 -0
  43. package/dist/backend/codex.js +25 -5
  44. package/dist/backend/codex.js.map +1 -1
  45. package/dist/backend/credential-profile.d.ts +2 -0
  46. package/dist/backend/credential-profile.js +2 -0
  47. package/dist/backend/credential-profile.js.map +1 -1
  48. package/dist/backend/effort-metadata.js.map +1 -1
  49. package/dist/backend/grok.js +58 -3
  50. package/dist/backend/grok.js.map +1 -1
  51. package/dist/backend/kiro-engine-ledger.js.map +1 -1
  52. package/dist/backend/kiro-kas-store.js.map +1 -1
  53. package/dist/backend/kiro-v2-store.js.map +1 -1
  54. package/dist/backend/kiro-v3-identity.js.map +1 -1
  55. package/dist/backend/kiro.d.ts +9 -1
  56. package/dist/backend/kiro.js +102 -1
  57. package/dist/backend/kiro.js.map +1 -1
  58. package/dist/backend/launch-effort.js.map +1 -1
  59. package/dist/backend/mock.js.map +1 -1
  60. package/dist/backend/muse.js.map +1 -1
  61. package/dist/backend/opencode-permission.js +1 -1
  62. package/dist/backend/opencode-permission.js.map +1 -1
  63. package/dist/backend/opencode.js +2 -1
  64. package/dist/backend/opencode.js.map +1 -1
  65. package/dist/backend/session-signals.js.map +1 -1
  66. package/dist/backend-availability.js.map +1 -1
  67. package/dist/backend-command.d.ts +2 -0
  68. package/dist/backend-command.js +3 -1
  69. package/dist/backend-command.js.map +1 -1
  70. package/dist/backend-outage.js.map +1 -1
  71. package/dist/binary-probe.js +1 -1
  72. package/dist/binary-probe.js.map +1 -1
  73. package/dist/bug-report-cli.d.ts +30 -0
  74. package/dist/bug-report-cli.js +139 -0
  75. package/dist/bug-report-cli.js.map +1 -0
  76. package/dist/bug-report.d.ts +47 -0
  77. package/dist/bug-report.js +137 -0
  78. package/dist/bug-report.js.map +1 -0
  79. package/dist/bundled-skills.d.ts +18 -0
  80. package/dist/bundled-skills.js +38 -0
  81. package/dist/bundled-skills.js.map +1 -0
  82. package/dist/cache-service.js +1 -1
  83. package/dist/cache-service.js.map +1 -1
  84. package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
  85. package/dist/channel/adapters/discord-client-retirement.js +57 -0
  86. package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
  87. package/dist/channel/adapters/discord.d.ts +4 -0
  88. package/dist/channel/adapters/discord.js +57 -12
  89. package/dist/channel/adapters/discord.js.map +1 -1
  90. package/dist/channel/adapters/telegram.d.ts +6 -0
  91. package/dist/channel/adapters/telegram.js +54 -14
  92. package/dist/channel/adapters/telegram.js.map +1 -1
  93. package/dist/channel/mcp-server.js +21 -4
  94. package/dist/channel/mcp-server.js.map +1 -1
  95. package/dist/channel/mcp-tools.d.ts +3 -1
  96. package/dist/channel/mcp-tools.js +43 -6
  97. package/dist/channel/mcp-tools.js.map +1 -1
  98. package/dist/channel/message-queue.js.map +1 -1
  99. package/dist/channel/sticker-download.js.map +1 -1
  100. package/dist/channel/tool-router.js.map +1 -1
  101. package/dist/child-process.d.ts +21 -0
  102. package/dist/child-process.js +54 -0
  103. package/dist/child-process.js.map +1 -0
  104. package/dist/classic-channel-manager.js +3 -2
  105. package/dist/classic-channel-manager.js.map +1 -1
  106. package/dist/cli-entry.js.map +1 -1
  107. package/dist/cli-flags.js.map +1 -1
  108. package/dist/cli.d.ts +1 -0
  109. package/dist/cli.js +443 -311
  110. package/dist/cli.js.map +1 -1
  111. package/dist/command-table.d.ts +1 -1
  112. package/dist/command-table.js +1 -1
  113. package/dist/command-table.js.map +1 -1
  114. package/dist/compact-watch.js.map +1 -1
  115. package/dist/completion-install.js.map +1 -1
  116. package/dist/completion.js.map +1 -1
  117. package/dist/config-validator.d.ts +6 -0
  118. package/dist/config-validator.js +81 -8
  119. package/dist/config-validator.js.map +1 -1
  120. package/dist/config.d.ts +15 -3
  121. package/dist/config.js +41 -10
  122. package/dist/config.js.map +1 -1
  123. package/dist/connection-secrets.js.map +1 -1
  124. package/dist/context-guardian.js.map +1 -1
  125. package/dist/coredump-filter.js.map +1 -1
  126. package/dist/cpu-profile.js.map +1 -1
  127. package/dist/cross-instance-envelope.js.map +1 -1
  128. package/dist/cross-instance-notice.d.ts +7 -0
  129. package/dist/cross-instance-notice.js +10 -0
  130. package/dist/cross-instance-notice.js.map +1 -1
  131. package/dist/daemon.d.ts +39 -1
  132. package/dist/daemon.js +234 -15
  133. package/dist/daemon.js.map +1 -1
  134. package/dist/daily-summary.js.map +1 -1
  135. package/dist/darwin-memory.js +1 -1
  136. package/dist/darwin-memory.js.map +1 -1
  137. package/dist/dashboard-live.d.ts +8 -0
  138. package/dist/dashboard-live.js +35 -0
  139. package/dist/dashboard-live.js.map +1 -0
  140. package/dist/dashboard-permissions.d.ts +69 -0
  141. package/dist/dashboard-permissions.js +138 -0
  142. package/dist/dashboard-permissions.js.map +1 -0
  143. package/dist/decision-list.d.ts +25 -0
  144. package/dist/decision-list.js +30 -0
  145. package/dist/decision-list.js.map +1 -0
  146. package/dist/delivery-consumed-watch.js.map +1 -1
  147. package/dist/delivery-outbox.js +5 -0
  148. package/dist/delivery-outbox.js.map +1 -1
  149. package/dist/delivery-outbox.test.js.map +1 -1
  150. package/dist/delivery-reconciliation.test.js.map +1 -1
  151. package/dist/diagnostic-redaction.d.ts +10 -0
  152. package/dist/diagnostic-redaction.js +167 -0
  153. package/dist/diagnostic-redaction.js.map +1 -0
  154. package/dist/doctor.d.ts +8 -0
  155. package/dist/doctor.js +52 -0
  156. package/dist/doctor.js.map +1 -1
  157. package/dist/e2e-isolation.js.map +1 -1
  158. package/dist/event-log.js.map +1 -1
  159. package/dist/export-import.js +7 -5
  160. package/dist/export-import.js.map +1 -1
  161. package/dist/fleet-control-audit.js.map +1 -1
  162. package/dist/fleet-label.js.map +1 -1
  163. package/dist/fleet-level-config.d.ts +1 -1
  164. package/dist/fleet-level-config.js +2 -0
  165. package/dist/fleet-level-config.js.map +1 -1
  166. package/dist/fleet-lock.js +3 -2
  167. package/dist/fleet-lock.js.map +1 -1
  168. package/dist/fleet-manager.d.ts +258 -15
  169. package/dist/fleet-manager.js +1605 -304
  170. package/dist/fleet-manager.js.map +1 -1
  171. package/dist/fleet-process-handlers.d.ts +18 -0
  172. package/dist/fleet-process-handlers.js +70 -0
  173. package/dist/fleet-process-handlers.js.map +1 -0
  174. package/dist/fleet-startup.d.ts +14 -0
  175. package/dist/fleet-startup.js +30 -0
  176. package/dist/fleet-startup.js.map +1 -0
  177. package/dist/fleet-traffic.d.ts +36 -0
  178. package/dist/fleet-traffic.js +100 -0
  179. package/dist/fleet-traffic.js.map +1 -1
  180. package/dist/forged-envelope-scan.d.ts +0 -20
  181. package/dist/forged-envelope-scan.js +3 -2
  182. package/dist/forged-envelope-scan.js.map +1 -1
  183. package/dist/full-restart.d.ts +5 -5
  184. package/dist/full-restart.js +5 -5
  185. package/dist/full-restart.js.map +1 -1
  186. package/dist/general-knowledge/skills/bug-report/SKILL.md +31 -0
  187. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +52 -11
  188. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +5 -1
  189. package/dist/general-knowledge/skills/fleet-config/SKILL.md +3 -1
  190. package/dist/general-knowledge/skills/fleet-restart/SKILL.md +8 -9
  191. package/dist/general-knowledge/skills/multi-channel/SKILL.md +1 -1
  192. package/dist/general-knowledge/skills/persona-emoji/SKILL.md +1 -1
  193. package/dist/general-knowledge/skills/scheduling/SKILL.md +4 -0
  194. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +321 -0
  195. package/dist/general-knowledge/skills/web-appearance/SKILL.md +28 -4
  196. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +553 -0
  197. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +170 -35
  198. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  199. package/dist/general-knowledge/steering/core-rules.md +1 -1
  200. package/dist/host-memory.js.map +1 -1
  201. package/dist/idle-gate-log.d.ts +19 -0
  202. package/dist/idle-gate-log.js +15 -0
  203. package/dist/idle-gate-log.js.map +1 -0
  204. package/dist/instance-config-impact.js +25 -4
  205. package/dist/instance-config-impact.js.map +1 -1
  206. package/dist/instance-lifecycle.d.ts +10 -1
  207. package/dist/instance-lifecycle.js +86 -25
  208. package/dist/instance-lifecycle.js.map +1 -1
  209. package/dist/instructions.d.ts +12 -6
  210. package/dist/instructions.js +19 -10
  211. package/dist/instructions.js.map +1 -1
  212. package/dist/kiro-compact-pane.js.map +1 -1
  213. package/dist/kiro-db-reader.js.map +1 -1
  214. package/dist/kiro-engine-status.js.map +1 -1
  215. package/dist/kiro-log-gate.js.map +1 -1
  216. package/dist/kiro-transcript-lane.js.map +1 -1
  217. package/dist/locale.js +428 -20
  218. package/dist/locale.js.map +1 -1
  219. package/dist/log-service.js.map +1 -1
  220. package/dist/log-steps.d.ts +1 -0
  221. package/dist/log-steps.js +15 -0
  222. package/dist/log-steps.js.map +1 -1
  223. package/dist/logger.js +3 -2
  224. package/dist/logger.js.map +1 -1
  225. package/dist/login-controller.d.ts +45 -0
  226. package/dist/login-controller.js +101 -5
  227. package/dist/login-controller.js.map +1 -1
  228. package/dist/login-flows.js +1 -1
  229. package/dist/login-manager.js.map +1 -1
  230. package/dist/login-shell.js +3 -1
  231. package/dist/login-shell.js.map +1 -1
  232. package/dist/ls-attach-resolve.d.ts +96 -0
  233. package/dist/ls-attach-resolve.js +180 -0
  234. package/dist/ls-attach-resolve.js.map +1 -0
  235. package/dist/ls-rows.d.ts +12 -0
  236. package/dist/ls-rows.js +83 -4
  237. package/dist/ls-rows.js.map +1 -1
  238. package/dist/memory-pressure.js.map +1 -1
  239. package/dist/muse-usage-relay.js.map +1 -1
  240. package/dist/needs-you-hub.d.ts +98 -1
  241. package/dist/needs-you-hub.js +313 -44
  242. package/dist/needs-you-hub.js.map +1 -1
  243. package/dist/needs-you-live.d.ts +5 -2
  244. package/dist/needs-you-live.js +6 -3
  245. package/dist/needs-you-live.js.map +1 -1
  246. package/dist/needs-you.d.ts +68 -3
  247. package/dist/needs-you.js +38 -4
  248. package/dist/needs-you.js.map +1 -1
  249. package/dist/network-family.js.map +1 -1
  250. package/dist/operator-control-paths.js +3 -4
  251. package/dist/operator-control-paths.js.map +1 -1
  252. package/dist/outbound-handlers.d.ts +3 -0
  253. package/dist/outbound-handlers.js +76 -19
  254. package/dist/outbound-handlers.js.map +1 -1
  255. package/dist/outbound-schemas.d.ts +112 -64
  256. package/dist/outbound-schemas.js +39 -12
  257. package/dist/outbound-schemas.js.map +1 -1
  258. package/dist/outbox-open-error.js.map +1 -1
  259. package/dist/pane-context-cache.js.map +1 -1
  260. package/dist/paths.js.map +1 -1
  261. package/dist/private-dir.js.map +1 -1
  262. package/dist/probe-worker-pool.js.map +1 -1
  263. package/dist/profile-control.js.map +1 -1
  264. package/dist/prompt-file-ref.js.map +1 -1
  265. package/dist/provider-probe.js.map +1 -1
  266. package/dist/provider-secret-registry.d.ts +5 -3
  267. package/dist/provider-secret-registry.js +8 -2
  268. package/dist/provider-secret-registry.js.map +1 -1
  269. package/dist/public-link-auto-open.d.ts +32 -0
  270. package/dist/public-link-auto-open.js +86 -0
  271. package/dist/public-link-auto-open.js.map +1 -0
  272. package/dist/public-link-owner.d.ts +10 -0
  273. package/dist/public-link-owner.js +36 -0
  274. package/dist/public-link-owner.js.map +1 -0
  275. package/dist/public-link-progress.d.ts +12 -1
  276. package/dist/public-link-progress.js +5 -10
  277. package/dist/public-link-progress.js.map +1 -1
  278. package/dist/public-preview.js.map +1 -1
  279. package/dist/public-tunnel-config.d.ts +11 -0
  280. package/dist/public-tunnel-config.js +68 -0
  281. package/dist/public-tunnel-config.js.map +1 -0
  282. package/dist/public-web-gateway.d.ts +2 -0
  283. package/dist/public-web-gateway.js +19 -6
  284. package/dist/public-web-gateway.js.map +1 -1
  285. package/dist/public-web-link.d.ts +48 -3
  286. package/dist/public-web-link.js +177 -51
  287. package/dist/public-web-link.js.map +1 -1
  288. package/dist/quickstart-api.d.ts +9 -0
  289. package/dist/quickstart-api.js +82 -0
  290. package/dist/quickstart-api.js.map +1 -1
  291. package/dist/quickstart.d.ts +5 -0
  292. package/dist/quickstart.js +40 -25
  293. package/dist/quickstart.js.map +1 -1
  294. package/dist/reply-buttons-controller.js.map +1 -1
  295. package/dist/reply-dedup.js.map +1 -1
  296. package/dist/resource-report.js +1 -1
  297. package/dist/resource-report.js.map +1 -1
  298. package/dist/restart-guard.js.map +1 -1
  299. package/dist/restart-progress.d.ts +80 -1
  300. package/dist/restart-progress.js +306 -21
  301. package/dist/restart-progress.js.map +1 -1
  302. package/dist/rollout-index.js.map +1 -1
  303. package/dist/runtime-cpu-profile.js.map +1 -1
  304. package/dist/scheduler/db.d.ts +40 -13
  305. package/dist/scheduler/db.js +123 -89
  306. package/dist/scheduler/db.js.map +1 -1
  307. package/dist/scheduler/scheduler.js.map +1 -1
  308. package/dist/scheduler/task-board-text.d.ts +26 -0
  309. package/dist/scheduler/task-board-text.js +140 -0
  310. package/dist/scheduler/task-board-text.js.map +1 -0
  311. package/dist/scheduler/task-board.d.ts +730 -0
  312. package/dist/scheduler/task-board.js +2179 -0
  313. package/dist/scheduler/task-board.js.map +1 -0
  314. package/dist/scheduler/types.d.ts +6 -1
  315. package/dist/sd-notify.js +2 -1
  316. package/dist/sd-notify.js.map +1 -1
  317. package/dist/search/search-docs.d.ts +58 -0
  318. package/dist/search/search-docs.js +63 -0
  319. package/dist/search/search-docs.js.map +1 -0
  320. package/dist/search/search-index.d.ts +141 -0
  321. package/dist/search/search-index.js +440 -0
  322. package/dist/search/search-index.js.map +1 -0
  323. package/dist/search/search-store.d.ts +122 -0
  324. package/dist/search/search-store.js +236 -0
  325. package/dist/search/search-store.js.map +1 -0
  326. package/dist/search/search-worker.d.ts +1 -0
  327. package/dist/search/search-worker.js +163 -0
  328. package/dist/search/search-worker.js.map +1 -0
  329. package/dist/secret-file.js.map +1 -1
  330. package/dist/secret-store.d.ts +2 -0
  331. package/dist/secret-store.js +21 -0
  332. package/dist/secret-store.js.map +1 -1
  333. package/dist/service-installer.d.ts +75 -0
  334. package/dist/service-installer.js +206 -0
  335. package/dist/service-installer.js.map +1 -1
  336. package/dist/service-owner.d.ts +44 -0
  337. package/dist/service-owner.js +48 -0
  338. package/dist/service-owner.js.map +1 -0
  339. package/dist/service-plan.d.ts +39 -2
  340. package/dist/service-plan.js +188 -6
  341. package/dist/service-plan.js.map +1 -1
  342. package/dist/session-oom.d.ts +21 -0
  343. package/dist/session-oom.js +139 -0
  344. package/dist/session-oom.js.map +1 -0
  345. package/dist/settings-api.d.ts +13 -0
  346. package/dist/settings-api.js +73 -12
  347. package/dist/settings-api.js.map +1 -1
  348. package/dist/settings-baseline.js.map +1 -1
  349. package/dist/settings-change.d.ts +5 -0
  350. package/dist/settings-change.js +167 -6
  351. package/dist/settings-change.js.map +1 -1
  352. package/dist/settings-confirmation.d.ts +9 -1
  353. package/dist/settings-confirmation.js +18 -8
  354. package/dist/settings-confirmation.js.map +1 -1
  355. package/dist/settings-control.js +2 -1
  356. package/dist/settings-control.js.map +1 -1
  357. package/dist/settings-effect.js +29 -4
  358. package/dist/settings-effect.js.map +1 -1
  359. package/dist/settings-http-confirmation.d.ts +13 -0
  360. package/dist/settings-http-confirmation.js +15 -3
  361. package/dist/settings-http-confirmation.js.map +1 -1
  362. package/dist/settings-instance-patch.js +13 -1
  363. package/dist/settings-instance-patch.js.map +1 -1
  364. package/dist/settings-request-capability.d.ts +4 -1
  365. package/dist/settings-request-capability.js +11 -3
  366. package/dist/settings-request-capability.js.map +1 -1
  367. package/dist/settings-transaction.js.map +1 -1
  368. package/dist/setup-auth.d.ts +1 -0
  369. package/dist/setup-auth.js +2 -1
  370. package/dist/setup-auth.js.map +1 -1
  371. package/dist/setup-form.d.ts +1 -1
  372. package/dist/setup-form.js +23 -7
  373. package/dist/setup-form.js.map +1 -1
  374. package/dist/setup-host.d.ts +6 -1
  375. package/dist/setup-host.js +15 -4
  376. package/dist/setup-host.js.map +1 -1
  377. package/dist/setup-wizard.js +6 -3
  378. package/dist/setup-wizard.js.map +1 -1
  379. package/dist/spawn-gate.d.ts +5 -0
  380. package/dist/spawn-gate.js +28 -8
  381. package/dist/spawn-gate.js.map +1 -1
  382. package/dist/start-attempt.d.ts +1 -0
  383. package/dist/start-attempt.js +18 -0
  384. package/dist/start-attempt.js.map +1 -0
  385. package/dist/start-failure-notice.d.ts +4 -0
  386. package/dist/start-failure-notice.js +20 -0
  387. package/dist/start-failure-notice.js.map +1 -0
  388. package/dist/start-failure.d.ts +147 -0
  389. package/dist/start-failure.js +281 -0
  390. package/dist/start-failure.js.map +1 -0
  391. package/dist/startup-memory-deadline.d.ts +23 -0
  392. package/dist/startup-memory-deadline.js +55 -0
  393. package/dist/startup-memory-deadline.js.map +1 -0
  394. package/dist/statusline-watcher.js.map +1 -1
  395. package/dist/storm-window.js.map +1 -1
  396. package/dist/systemd-peer-bus.js.map +1 -1
  397. package/dist/target-queue-worker.js.map +1 -1
  398. package/dist/task-board-summary.d.ts +101 -0
  399. package/dist/task-board-summary.js +177 -0
  400. package/dist/task-board-summary.js.map +1 -0
  401. package/dist/task-board-tool.d.ts +25 -0
  402. package/dist/task-board-tool.js +155 -0
  403. package/dist/task-board-tool.js.map +1 -0
  404. package/dist/task-board-waker.d.ts +51 -0
  405. package/dist/task-board-waker.js +141 -0
  406. package/dist/task-board-waker.js.map +1 -0
  407. package/dist/tips.js.map +1 -1
  408. package/dist/tmux-control.js +1 -1
  409. package/dist/tmux-control.js.map +1 -1
  410. package/dist/tmux-exec-helper.d.ts +104 -0
  411. package/dist/tmux-exec-helper.js +412 -0
  412. package/dist/tmux-exec-helper.js.map +1 -0
  413. package/dist/tmux-manager.d.ts +1 -0
  414. package/dist/tmux-manager.js +29 -13
  415. package/dist/tmux-manager.js.map +1 -1
  416. package/dist/tmux-read.js +2 -2
  417. package/dist/tmux-read.js.map +1 -1
  418. package/dist/tool-permissions.js +9 -42
  419. package/dist/tool-permissions.js.map +1 -1
  420. package/dist/tool-progress.js.map +1 -1
  421. package/dist/topic-archiver.js.map +1 -1
  422. package/dist/topic-commands.d.ts +13 -0
  423. package/dist/topic-commands.js +56 -33
  424. package/dist/topic-commands.js.map +1 -1
  425. package/dist/topic-link.js.map +1 -1
  426. package/dist/transcript-delta-reader.js.map +1 -1
  427. package/dist/transcript-jsonl.js.map +1 -1
  428. package/dist/transcript-monitor.js +5 -0
  429. package/dist/transcript-monitor.js.map +1 -1
  430. package/dist/transcript-sources.d.ts +2 -0
  431. package/dist/transcript-sources.js +4 -0
  432. package/dist/transcript-sources.js.map +1 -1
  433. package/dist/tunnel/cloudflared-install.js +3 -1
  434. package/dist/tunnel/cloudflared-install.js.map +1 -1
  435. package/dist/tunnel/cloudflared.d.ts +7 -16
  436. package/dist/tunnel/cloudflared.js +100 -13
  437. package/dist/tunnel/cloudflared.js.map +1 -1
  438. package/dist/tunnel/lease.js +3 -2
  439. package/dist/tunnel/lease.js.map +1 -1
  440. package/dist/tunnel/manager.js.map +1 -1
  441. package/dist/tunnel/named-diagnostics.d.ts +13 -0
  442. package/dist/tunnel/named-diagnostics.js +52 -0
  443. package/dist/tunnel/named-diagnostics.js.map +1 -0
  444. package/dist/tunnel/public-fetch.js.map +1 -1
  445. package/dist/tunnel/purpose-lane.js.map +1 -1
  446. package/dist/tunnel/types.d.ts +4 -1
  447. package/dist/tunnel/types.js.map +1 -1
  448. package/dist/types.d.ts +55 -2
  449. package/dist/ui/app-effects.js +27 -5
  450. package/dist/ui/app.html +2 -0
  451. package/dist/ui/backend-signin.js +297 -0
  452. package/dist/ui/chat-effects.js +15 -7
  453. package/dist/ui/chat-msg-actions.js +176 -0
  454. package/dist/ui/chat-render.js +67 -20
  455. package/dist/ui/chat-store.js +218 -48
  456. package/dist/ui/chat-strings.js +42 -10
  457. package/dist/ui/chat-thread.js +249 -23
  458. package/dist/ui/effect-trial-controller.js +13 -8
  459. package/dist/ui/effect-trial-offer.js +2 -31
  460. package/dist/ui/effects-waker.js +2 -0
  461. package/dist/ui/fleet-canvas-layout.js +13 -4
  462. package/dist/ui/fleet-canvas.js +120 -43
  463. package/dist/ui/fleet-office-editor.js +149 -0
  464. package/dist/ui/fleet-office-model.js +358 -0
  465. package/dist/ui/fleet-office-pack.js +199 -0
  466. package/dist/ui/fleet-office-skin.js +474 -0
  467. package/dist/ui/fleet-office-store.js +49 -0
  468. package/dist/ui/fleet-office-zones.js +177 -0
  469. package/dist/ui/fleet-office.js +434 -0
  470. package/dist/ui/fleet-org.js +21 -8
  471. package/dist/ui/fleet-route-scene.js +272 -0
  472. package/dist/ui/fleet-route-worker.js +21 -0
  473. package/dist/ui/fleet-route.js +88 -0
  474. package/dist/ui/fleet-task-card.js +436 -0
  475. package/dist/ui/fleet-task-common.js +482 -0
  476. package/dist/ui/fleet-task-work.js +107 -0
  477. package/dist/ui/fleet-tasks.js +569 -0
  478. package/dist/ui/fleet-traffic.js +227 -45
  479. package/dist/ui/fleet-usage.js +36 -2
  480. package/dist/ui/guest-refused.html +41 -0
  481. package/dist/ui/icons/icon-192.png +0 -0
  482. package/dist/ui/icons/icon-512.png +0 -0
  483. package/dist/ui/image-lightbox.js +45 -1
  484. package/dist/ui/image-zoom.js +242 -0
  485. package/dist/ui/panel-chat.js +282 -89
  486. package/dist/ui/panel-details.js +2 -0
  487. package/dist/ui/panel-fleet.js +32 -71
  488. package/dist/ui/panel-needs.js +23 -6
  489. package/dist/ui/panel-settings.js +158 -32
  490. package/dist/ui/preview-panel.js +2 -1
  491. package/dist/ui/search-dialog.js +350 -0
  492. package/dist/ui/settings-appearance.js +170 -10
  493. package/dist/ui/settings-apply.js +3 -3
  494. package/dist/ui/settings-confirm.js +7 -2
  495. package/dist/ui/settings-dialogs.js +46 -21
  496. package/dist/ui/settings-discord.js +6 -2
  497. package/dist/ui/settings-guests.js +2 -1
  498. package/dist/ui/settings-learn.js +1 -0
  499. package/dist/ui/settings-model.js +51 -18
  500. package/dist/ui/settings-mods.js +8 -3
  501. package/dist/ui/settings-owner-effects.js +6 -4
  502. package/dist/ui/settings-strings.js +180 -6
  503. package/dist/ui/settings-token.js +3 -1
  504. package/dist/ui/settings-web-authority.js +13 -5
  505. package/dist/ui/settings-wizard.js +13 -7
  506. package/dist/ui/shared/agend-auth.js +3 -1
  507. package/dist/ui/shared/app-i18n.js +12 -5
  508. package/dist/ui/shared/app-needs.js +2 -2
  509. package/dist/ui/shared/app-prefs.js +15 -0
  510. package/dist/ui/shared/app-route.js +18 -0
  511. package/dist/ui/shared/app-shell.js +172 -28
  512. package/dist/ui/shared/app-store.js +3 -2
  513. package/dist/ui/shared/app-stream.js +7 -2
  514. package/dist/ui/shared/app-themes.js +116 -1
  515. package/dist/ui/shared/app.css +681 -54
  516. package/dist/ui/shared/app.js +9 -1
  517. package/dist/ui/shared/card-strings.js +4 -0
  518. package/dist/ui/shared/effect-app-runtime.js +7 -5
  519. package/dist/ui/shared/effect-chat-runtime.js +2 -7
  520. package/dist/ui/shared/effect-cursor.js +3 -2
  521. package/dist/ui/shared/effect-display-metadata.js +39 -0
  522. package/dist/ui/shared/effect-owner-source.js +8 -1
  523. package/dist/ui/shared/effect-policy.js +2 -2
  524. package/dist/ui/shared/effect-registry.js +30 -11
  525. package/dist/ui/shared/effect-runtime-loader.js +3 -1
  526. package/dist/ui/shared/effect-stock-snapshot.js +9 -0
  527. package/dist/ui/shared/effect-stock-trust.js +40 -9
  528. package/dist/ui/shared/effect-trial-source.js +1 -1
  529. package/dist/ui/shared/effect-trial-stage.js +27 -21
  530. package/dist/ui/shared/effect-trial.css +1 -1
  531. package/dist/ui/shared/feature-flags.js +127 -0
  532. package/dist/ui/shared/guest-refused.js +35 -0
  533. package/dist/ui/shared/header-tools.js +2 -2
  534. package/dist/ui/shared/identity-card.js +26 -8
  535. package/dist/ui/shared/identity-color.js +17 -10
  536. package/dist/ui/shared/instance-nav.js +183 -28
  537. package/dist/ui/shared/owner-css.js +30 -1
  538. package/dist/ui/shared/panel-view.js +14 -29
  539. package/dist/ui/shared/text-undo.js +210 -0
  540. package/dist/ui/shared/tokens.css +13 -3
  541. package/dist/ui/shared/ui-dialog.js +5 -4
  542. package/dist/ui/shared/ui-icons.js +4 -0
  543. package/dist/ui/shared/ui-menu.js +20 -7
  544. package/dist/ui/shared/ui-toast.js +16 -3
  545. package/dist/ui/shared/usage-dialog.js +206 -16
  546. package/dist/ui/shared/view-strings.js +68 -4
  547. package/dist/ui/shared/web-authorize.js +50 -1
  548. package/dist/ui/signin.html +2 -0
  549. package/dist/ui/web-terminal/terminal.css +4 -4
  550. package/dist/ui/web-terminal/terminal.html +10 -10
  551. package/dist/ui/web-terminal/terminal.js +58 -12
  552. package/dist/update-check.js.map +1 -1
  553. package/dist/update-dispatch.js +1 -1
  554. package/dist/update-dispatch.js.map +1 -1
  555. package/dist/update-install.js.map +1 -1
  556. package/dist/update-launch.d.ts +10 -1
  557. package/dist/update-launch.js +39 -14
  558. package/dist/update-launch.js.map +1 -1
  559. package/dist/update-marker.js.map +1 -1
  560. package/dist/update-preflight.js +1 -1
  561. package/dist/update-preflight.js.map +1 -1
  562. package/dist/update-progress.d.ts +3 -1
  563. package/dist/update-progress.js +3 -1
  564. package/dist/update-progress.js.map +1 -1
  565. package/dist/usage/format-rich.js +6 -3
  566. package/dist/usage/format-rich.js.map +1 -1
  567. package/dist/usage/i18n-keys.d.ts +1 -1
  568. package/dist/usage/i18n-keys.js +2 -1
  569. package/dist/usage/i18n-keys.js.map +1 -1
  570. package/dist/usage/i18n.d.ts +13 -1
  571. package/dist/usage/i18n.js +29 -0
  572. package/dist/usage/i18n.js.map +1 -1
  573. package/dist/usage/providers.d.ts +89 -2
  574. package/dist/usage/providers.js +247 -41
  575. package/dist/usage/providers.js.map +1 -1
  576. package/dist/usage/statusline-usage.js.map +1 -1
  577. package/dist/usage/usage-api.d.ts +5 -1
  578. package/dist/usage/usage-api.js +185 -58
  579. package/dist/usage/usage-api.js.map +1 -1
  580. package/dist/usage-report.js.map +1 -1
  581. package/dist/usage-rollup.js +1 -1
  582. package/dist/usage-rollup.js.map +1 -1
  583. package/dist/user-systemd.d.ts +24 -0
  584. package/dist/user-systemd.js +75 -0
  585. package/dist/user-systemd.js.map +1 -0
  586. package/dist/view-api.d.ts +7 -0
  587. package/dist/view-api.js +16 -4
  588. package/dist/view-api.js.map +1 -1
  589. package/dist/wake-coordinator.js.map +1 -1
  590. package/dist/web-ambient.js +9 -2
  591. package/dist/web-ambient.js.map +1 -1
  592. package/dist/web-api.d.ts +58 -10
  593. package/dist/web-api.js +1104 -71
  594. package/dist/web-api.js.map +1 -1
  595. package/dist/web-app-icon-worker.d.ts +1 -0
  596. package/dist/web-app-icon-worker.js +16 -0
  597. package/dist/web-app-icon-worker.js.map +1 -0
  598. package/dist/web-app-icon.d.ts +109 -0
  599. package/dist/web-app-icon.js +257 -0
  600. package/dist/web-app-icon.js.map +1 -0
  601. package/dist/web-appearance-policy.js.map +1 -1
  602. package/dist/web-appearance-tools.d.ts +1 -0
  603. package/dist/web-appearance-tools.js +7 -3
  604. package/dist/web-appearance-tools.js.map +1 -1
  605. package/dist/web-appearance-view.js.map +1 -1
  606. package/dist/web-appearance.d.ts +4 -10
  607. package/dist/web-appearance.js +7 -4
  608. package/dist/web-appearance.js.map +1 -1
  609. package/dist/web-auth.d.ts +8 -4
  610. package/dist/web-auth.js +33 -21
  611. package/dist/web-auth.js.map +1 -1
  612. package/dist/web-backend-login.d.ts +130 -0
  613. package/dist/web-backend-login.js +225 -0
  614. package/dist/web-backend-login.js.map +1 -0
  615. package/dist/web-card.js.map +1 -1
  616. package/dist/web-channel-echo.js.map +1 -1
  617. package/dist/web-chat-history.d.ts +118 -8
  618. package/dist/web-chat-history.js +220 -25
  619. package/dist/web-chat-history.js.map +1 -1
  620. package/dist/web-commands.d.ts +5 -1
  621. package/dist/web-commands.js +1 -1
  622. package/dist/web-commands.js.map +1 -1
  623. package/dist/web-cookie-names.d.ts +5 -0
  624. package/dist/web-cookie-names.js +12 -0
  625. package/dist/web-cookie-names.js.map +1 -0
  626. package/dist/web-effect-bundle.d.ts +2 -2
  627. package/dist/web-effect-library.js.map +1 -1
  628. package/dist/web-effect-playback.js.map +1 -1
  629. package/dist/web-effect-profiles.d.ts +16 -16
  630. package/dist/web-effect-profiles.js +3 -2
  631. package/dist/web-effect-profiles.js.map +1 -1
  632. package/dist/web-effect-service.js.map +1 -1
  633. package/dist/web-effect-tools.js.map +1 -1
  634. package/dist/web-effect-trials.js.map +1 -1
  635. package/dist/web-effect-upload.js.map +1 -1
  636. package/dist/web-effect.d.ts +6 -6
  637. package/dist/web-effect.js.map +1 -1
  638. package/dist/web-experimental-http.d.ts +2 -0
  639. package/dist/web-experimental-http.js +12 -0
  640. package/dist/web-experimental-http.js.map +1 -0
  641. package/dist/web-experimental.d.ts +11 -0
  642. package/dist/web-experimental.js +49 -0
  643. package/dist/web-experimental.js.map +1 -0
  644. package/dist/web-guest-access.d.ts +4 -2
  645. package/dist/web-guest-access.js +22 -10
  646. package/dist/web-guest-access.js.map +1 -1
  647. package/dist/web-guest-rooms.js.map +1 -1
  648. package/dist/web-host-guard.d.ts +11 -0
  649. package/dist/web-host-guard.js +11 -0
  650. package/dist/web-host-guard.js.map +1 -1
  651. package/dist/web-icons.d.ts +33 -1
  652. package/dist/web-icons.js +83 -11
  653. package/dist/web-icons.js.map +1 -1
  654. package/dist/web-identity-color.js.map +1 -1
  655. package/dist/web-image-meta.d.ts +13 -0
  656. package/dist/web-image-meta.js +62 -0
  657. package/dist/web-image-meta.js.map +1 -1
  658. package/dist/web-images.js.map +1 -1
  659. package/dist/web-libavoid.d.ts +14 -0
  660. package/dist/web-libavoid.js +46 -0
  661. package/dist/web-libavoid.js.map +1 -0
  662. package/dist/web-login.js.map +1 -1
  663. package/dist/web-mentions.js.map +1 -1
  664. package/dist/web-mod-agent.js.map +1 -1
  665. package/dist/web-mod-store.d.ts +2 -0
  666. package/dist/web-mod-store.js +10 -0
  667. package/dist/web-mod-store.js.map +1 -1
  668. package/dist/web-office-store.d.ts +104 -0
  669. package/dist/web-office-store.js +236 -0
  670. package/dist/web-office-store.js.map +1 -0
  671. package/dist/web-owner-css-store.d.ts +44 -1
  672. package/dist/web-owner-css-store.js +70 -9
  673. package/dist/web-owner-css-store.js.map +1 -1
  674. package/dist/web-owner-css.js.map +1 -1
  675. package/dist/web-png.d.ts +33 -0
  676. package/dist/web-png.js +329 -0
  677. package/dist/web-png.js.map +1 -0
  678. package/dist/web-prefs.d.ts +6 -0
  679. package/dist/web-prefs.js +29 -3
  680. package/dist/web-prefs.js.map +1 -1
  681. package/dist/web-preview.d.ts +2 -0
  682. package/dist/web-preview.js +2 -0
  683. package/dist/web-preview.js.map +1 -1
  684. package/dist/web-profile.js.map +1 -1
  685. package/dist/web-reactions.d.ts +35 -0
  686. package/dist/web-reactions.js +47 -0
  687. package/dist/web-reactions.js.map +1 -0
  688. package/dist/web-request-context.d.ts +5 -0
  689. package/dist/web-request-context.js.map +1 -1
  690. package/dist/web-returning-device.d.ts +4 -2
  691. package/dist/web-returning-device.js +13 -6
  692. package/dist/web-returning-device.js.map +1 -1
  693. package/dist/web-schedules.js.map +1 -1
  694. package/dist/web-send-dedupe.d.ts +36 -0
  695. package/dist/web-send-dedupe.js +69 -0
  696. package/dist/web-send-dedupe.js.map +1 -0
  697. package/dist/web-session-authorization.js.map +1 -1
  698. package/dist/web-session.js +1 -1
  699. package/dist/web-session.js.map +1 -1
  700. package/dist/web-settings-patch.d.ts +3 -1
  701. package/dist/web-settings-patch.js +11 -5
  702. package/dist/web-settings-patch.js.map +1 -1
  703. package/dist/web-settings-tools.d.ts +6 -0
  704. package/dist/web-settings-tools.js +52 -17
  705. package/dist/web-settings-tools.js.map +1 -1
  706. package/dist/web-terminal-http.js +15 -2
  707. package/dist/web-terminal-http.js.map +1 -1
  708. package/dist/web-terminal.js +1 -1
  709. package/dist/web-terminal.js.map +1 -1
  710. package/dist/web-theme-store.d.ts +2 -2
  711. package/dist/web-theme-store.js +6 -3
  712. package/dist/web-theme-store.js.map +1 -1
  713. package/dist/web-theme.d.ts +29 -0
  714. package/dist/web-theme.js +89 -1
  715. package/dist/web-theme.js.map +1 -1
  716. package/dist/web-upload.d.ts +18 -1
  717. package/dist/web-upload.js +45 -7
  718. package/dist/web-upload.js.map +1 -1
  719. package/dist/web-widget.js.map +1 -1
  720. package/dist/webhook-emitter.js.map +1 -1
  721. package/dist/windows-shortcuts.d.ts +78 -0
  722. package/dist/windows-shortcuts.js +203 -0
  723. package/dist/windows-shortcuts.js.map +1 -0
  724. package/dist/workflow-templates/default.md +4 -1
  725. package/dist/ws-server.js.map +1 -1
  726. package/dist/yaml-shared-nodes.d.ts +25 -0
  727. package/dist/yaml-shared-nodes.js +185 -0
  728. package/dist/yaml-shared-nodes.js.map +1 -0
  729. package/launcher/agend-install.cjs +828 -0
  730. package/launcher/install-admission.cjs +4 -39
  731. package/launcher/postinstall.cjs +14 -12
  732. package/launcher/private-home.cjs +43 -0
  733. package/package.json +16 -13
  734. package/scripts/preinstall-guard.cjs +2 -5
  735. package/templates/windows-shortcuts.ps1 +181 -0
  736. package/launcher/old-updater-note.cjs +0 -48
@@ -1,7 +1,11 @@
1
1
  import type { ChannelAdapter } from "./channel/types.js";
2
- import { type DeliveryInput, type InstanceInput, type NeedsYouItem, type PromptInput, type WorldPlace } from "./needs-you.js";
2
+ import { type DeliveryInput, type InstanceInput, type NeedsYouItem, type PromptInput, type TaskInput, type WorldPlace } from "./needs-you.js";
3
3
  import { type LiveTarget } from "./needs-you-live.js";
4
4
  export declare const NEEDS_ACK_PREFIX = "needs-ack:";
5
+ /** A Send back or Answer prompt waits this long for its reply (monotonic). */
6
+ export declare const TASK_REPLY_TTL_MS: number;
7
+ /** Send back / Answer prompts open at once, being sent or waiting for their reply, over every card and person (#2306 review). */
8
+ export declare const TASK_REPLY_MAX = 32;
5
9
  /** awaiting_input pings (DM, browser) only once it has lasted this long; the list itself is never delayed (§6.3). */
6
10
  export declare const AWAITING_PING_MIN_MS = 5000;
7
11
  /** An Acknowledge button's capability lapses this long after it was minted, whether or not a renewal replaced it. */
@@ -27,6 +31,15 @@ export interface NeedsYouHubContext {
27
31
  worlds(): NeedsYouWorld[];
28
32
  /** Where a world's fleet notices go (its General), or null. */
29
33
  noticeTarget(world: string): LiveTarget | null;
34
+ /** #2352: an instance's own channel (its topic in its world's group, or its ClassicBot room), or null. */
35
+ laneTarget?(instance: string): LiveTarget | null;
36
+ /**
37
+ * #2355 review: where a card's buttons belong NOW, read from the board (not from the last render): `{ lane }` (no lane:
38
+ * General), or null when the card no longer waits for the person (the board answers a move by its version).
39
+ */
40
+ taskRoute?(code: string): {
41
+ lane?: string;
42
+ } | null;
30
43
  /** An instance's own thread/topic id, for its link. */
31
44
  instanceTopic(instance: string): string | undefined;
32
45
  isFleetAdmin(userId: string, world: string): boolean;
@@ -34,6 +47,16 @@ export interface NeedsYouHubContext {
34
47
  emitSse(event: string, data: unknown): void;
35
48
  /** outbox.acknowledge: true when this call acknowledged it; throws on a write error. */
36
49
  acknowledge(deliveryId: string, by: string): boolean;
50
+ /** Task board cards waiting for the person (#2246 step 3); none when the board is not open. */
51
+ tasks?(): TaskInput[];
52
+ /**
53
+ * The person's move on a card from the chat: confirm it, send it back with `text` (the reason), or answer its blocked
54
+ * question with `text`. Checked against the version the button showed; the answer is said to the clicker.
55
+ */
56
+ taskAction?(action: TaskAction): {
57
+ ok: boolean;
58
+ message: string;
59
+ };
37
60
  settings(): {
38
61
  liveMessage: boolean;
39
62
  dm: boolean;
@@ -42,16 +65,44 @@ export interface NeedsYouHubContext {
42
65
  t(key: string, ...args: Array<string | number>): string;
43
66
  log(level: "info" | "warn" | "debug", message: string, extra?: Record<string, unknown>): void;
44
67
  }
68
+ export type TaskVerb = "confirm" | "back" | "answer";
69
+ export interface TaskAction {
70
+ verb: TaskVerb;
71
+ code: string;
72
+ version: number;
73
+ /** The reason (back) or the answer (answer). */
74
+ text?: string;
75
+ /** The person, as the platform names them. */
76
+ by: {
77
+ platform: string;
78
+ userId: string;
79
+ username?: string;
80
+ };
81
+ }
82
+ /** A reply to a message, as the inbound handler sees it (InboundMessage's fields). */
83
+ export interface ReplyMessage {
84
+ adapterId: string;
85
+ chatId: string;
86
+ threadId?: string;
87
+ replyTo?: string;
88
+ messageId: string;
89
+ userId: string;
90
+ username?: string;
91
+ text: string;
92
+ }
45
93
  export interface AckCallback {
46
94
  callbackData: string;
47
95
  chatId: string;
48
96
  threadId?: string;
49
97
  messageId: string;
50
98
  userId?: string;
99
+ username?: string;
51
100
  ack?(notice?: string): void;
52
101
  }
53
102
  /** What the web receives: the items without their chat coordinates. */
54
103
  export type WebNeedsItem = Omit<NeedsYouItem, "promptAt">;
104
+ /** #2352: a live message's key — its world (General, as before #2352) or `<world>#lane:<instance>` (a lane's channel). */
105
+ export declare function liveKey(world: string, lane: string | null): string;
55
106
  export declare class NeedsYouHub {
56
107
  private readonly ctx;
57
108
  private items;
@@ -62,6 +113,16 @@ export declare class NeedsYouHub {
62
113
  * moved place gets a new renderer, and the old one can no longer publish. */
63
114
  private readonly live;
64
115
  private readonly acks;
116
+ /** Send back / Answer prompts waiting for the clicker's reply, by `${world}|${chatId}|${messageId}`. */
117
+ /** Pending replies by where their prompt is (`<chatId>|<messageId>`), whichever bot receives the reply. */
118
+ private readonly replies;
119
+ /** Prompts on their way: reserved before the send, released when it is posted or fails (#2306 review). */
120
+ private readonly asking;
121
+ /**
122
+ * #2341 review r2: replies already taken, by `<chatId>|<messageId>`, until the prompt's TTL — so another bot's copy of
123
+ * the same message (a shared group) is dropped by the inbound handler, not handed to an agent as input.
124
+ */
125
+ private readonly taken;
65
126
  private readonly dmSeen;
66
127
  private readonly dmLastAt;
67
128
  /** Per world: the ids waiting to be DMed, and the one timer that will send them. */
@@ -84,7 +145,12 @@ export declare class NeedsYouHub {
84
145
  private pointerPath;
85
146
  private readPointers;
86
147
  private writePointer;
148
+ /** A line's words: why it waits — and for a card, which card and what it asks or lacks (the chat shows no detail). */
87
149
  private lineTitle;
150
+ /** #2352: a lane can carry a list here: its instance is this world's now, and has a channel of its own. */
151
+ private laneUsable;
152
+ /** Where a list (General, or a lane's) is posted now, or null. */
153
+ private listTarget;
88
154
  private makeLive;
89
155
  private mintAcks;
90
156
  private revokeAcks;
@@ -94,6 +160,37 @@ export declare class NeedsYouHub {
94
160
  * never edited from here — that would strip the current keyboard of the same message.
95
161
  */
96
162
  handleCallback(data: AckCallback, adapterId: string): boolean;
163
+ /**
164
+ * #2352: a card still routes to this lane (or, for no lane, to General) — asked of the board now (#2355 review: a
165
+ * project's lead can change with the card's version unchanged, and the last render may not have seen it yet). One
166
+ * that no longer waits for the person is left to the board, which answers by its version.
167
+ */
168
+ private stillInLane;
169
+ /** #2355 review: a list's place (its lane's channel, or General) is still where this button or prompt is. */
170
+ private placeStill;
171
+ /** A prompt for this reservation still waits for its reply. */
172
+ private pendingFor;
173
+ /** Prompts still waiting for their reply (lapsed ones go). */
174
+ private livePending;
175
+ /**
176
+ * The card's instance is still this world's, the world still the same connection in the same place, and its notice
177
+ * place still where the prompt is: else a reply there is not this world's to take (#2306 review — an instance that
178
+ * moved to another world, a replaced connection, a new notice room).
179
+ */
180
+ private stillHere;
181
+ /** Post the prompt for a Send back's reason or an answer, and wait for the clicker's reply to it. */
182
+ private askForReply;
183
+ /**
184
+ * An inbound message that replies to one of our Send back / Answer prompts, by the admin who clicked: its text is
185
+ * the reason or the answer, and the message goes no further (true). Anything else — another message, another
186
+ * person, a lapsed prompt — is not ours (false) and flows on as usual.
187
+ */
188
+ handleReply(msg: ReplyMessage): boolean;
189
+ /**
190
+ * #2341 review r2: this message (another bot's copy of it) was already taken as a prompt's answer. The inbound handler
191
+ * asks it first and drops the copy: it is neither a second answer nor an agent's input.
192
+ */
193
+ wasTakenReply(chatId: string, messageId: string | undefined): boolean;
97
194
  /** The web's Acknowledge: any item (the web is global, §5.0). `principal` is "web:<session handle>" or "cli". */
98
195
  webAcknowledge(itemId: string, principal: string): {
99
196
  status: 200 | 400 | 404 | 409 | 500;
@@ -2,7 +2,13 @@
2
2
  * #1386: the fleet side of "Needs you". One derivation (needs-you.ts), recomputed on change, rendered to:
3
3
  * - each world's live message in its General and, optionally, its admins' DMs — only that world's items (§5.0, §5);
4
4
  * - the web, globally: SSE `needs` and a `needs` field on /ui/poll (§6).
5
- * Plus Acknowledge for delivery items, from a world's live message (its admins, its items) or from the web (any).
5
+ * Plus Acknowledge for delivery items, from a world's live message (its admins, its items) or from the web (any); and
6
+ * for task board cards (#2246 step 3), Confirm, Send back and Answer from the live message — the two that need words
7
+ * ask for them as a reply to a prompt the bot posts, which only the admin who clicked may answer.
8
+ *
9
+ * #2352: a card with a lane (the instance that handed it out, else its project's lead) is listed in that instance's own
10
+ * channel instead — one live message per lane, the same renderer, its buttons and prompts bound to that message and
11
+ * place. A world's General keeps everything else.
6
12
  *
7
13
  * The Acknowledge capabilities live in this hub's own registry, not in the fleet's prompt map: the map's walkers
8
14
  * (per-instance clear, shutdown retire, prompt expiry) edit the message an entry points at, and the live message must
@@ -14,11 +20,15 @@ import { readFileSync } from "node:fs";
14
20
  import { join } from "node:path";
15
21
  import { writeFileAtomic } from "./backend/kiro-engine-ledger.js";
16
22
  import { isMessageEditLoss } from "./channel/message-edit-errors.js";
17
- import { deriveNeedsYou, itemsForWorld, renderLiveMessage, renderSignature, messageLink, instanceLink, } from "./needs-you.js";
23
+ import { deriveNeedsYou, itemsForWorld, itemsForLane, lanesOf, renderLiveMessage, renderSignature, messageLink, instanceLink, } from "./needs-you.js";
18
24
  import { GroupMembership, topicUrl } from "./topic-link.js";
19
- import { NeedsYouLiveMessage, canonicalTarget } from "./needs-you-live.js";
25
+ import { NeedsYouLiveMessage, canonicalTarget, samePlace } from "./needs-you-live.js";
20
26
  export const NEEDS_ACK_PREFIX = "needs-ack:";
21
- const ACK_RE = /^needs-ack:([0-9a-f]{32}):ack$/;
27
+ const ACK_RE = /^needs-ack:([0-9a-f]{32}):(ack|confirm|back|answer)$/;
28
+ /** A Send back or Answer prompt waits this long for its reply (monotonic). */
29
+ export const TASK_REPLY_TTL_MS = 10 * 60_000;
30
+ /** Send back / Answer prompts open at once, being sent or waiting for their reply, over every card and person (#2306 review). */
31
+ export const TASK_REPLY_MAX = 32;
22
32
  const BACKSTOP_MS = 10_000;
23
33
  const ATTENTION_WINDOW_MS = 24 * 60 * 60_000;
24
34
  /** awaiting_input pings (DM, browser) only once it has lasted this long; the list itself is never delayed (§6.3). */
@@ -30,6 +40,11 @@ export const ACK_TTL_MS = 15 * 60_000;
30
40
  function placeKey(place) {
31
41
  return `${place.type}|${place.groupId ?? ""}`;
32
42
  }
43
+ /** #2352: a live message's key — its world (General, as before #2352) or `<world>#lane:<instance>` (a lane's channel). */
44
+ export function liveKey(world, lane) {
45
+ return lane ? `${world}#lane:${lane}` : world;
46
+ }
47
+ const LANE_SEP = "#lane:";
33
48
  export class NeedsYouHub {
34
49
  ctx;
35
50
  items = [];
@@ -40,6 +55,16 @@ export class NeedsYouHub {
40
55
  * moved place gets a new renderer, and the old one can no longer publish. */
41
56
  live = new Map();
42
57
  acks = new Map();
58
+ /** Send back / Answer prompts waiting for the clicker's reply, by `${world}|${chatId}|${messageId}`. */
59
+ /** Pending replies by where their prompt is (`<chatId>|<messageId>`), whichever bot receives the reply. */
60
+ replies = new Map();
61
+ /** Prompts on their way: reserved before the send, released when it is posted or fails (#2306 review). */
62
+ asking = new Set();
63
+ /**
64
+ * #2341 review r2: replies already taken, by `<chatId>|<messageId>`, until the prompt's TTL — so another bot's copy of
65
+ * the same message (a shared group) is dropped by the inbound handler, not handed to an agent as input.
66
+ */
67
+ taken = new Map();
43
68
  dmSeen = new Map();
44
69
  dmLastAt = new Map();
45
70
  /** Per world: the ids waiting to be DMed, and the one timer that will send them. */
@@ -75,6 +100,9 @@ export class NeedsYouHub {
75
100
  if (this.stopped)
76
101
  return;
77
102
  const now = this.ctx.now();
103
+ for (const [key, r] of this.replies)
104
+ if (this.ctx.mono() >= r.deadline)
105
+ this.replies.delete(key);
78
106
  let deliveries = [];
79
107
  try {
80
108
  deliveries = this.ctx.deliveries(new Date(now - ATTENTION_WINDOW_MS).toISOString());
@@ -82,7 +110,14 @@ export class NeedsYouHub {
82
110
  catch (err) {
83
111
  this.ctx.log("warn", "Needs you: could not read the delivery outbox", { err: String(err?.message ?? err) });
84
112
  }
85
- this.items = deriveNeedsYou({ prompts: this.ctx.prompts(), instances: this.ctx.instances(), deliveries, ownerOf: i => this.ctx.ownerOf(i) });
113
+ let tasks = [];
114
+ try {
115
+ tasks = this.ctx.tasks?.() ?? [];
116
+ }
117
+ catch (err) {
118
+ this.ctx.log("warn", "Needs you: could not read the task board", { err: String(err?.message ?? err) });
119
+ }
120
+ this.items = deriveNeedsYou({ prompts: this.ctx.prompts(), instances: this.ctx.instances(), deliveries, tasks, ownerOf: i => this.ctx.ownerOf(i) });
86
121
  const webSig = renderSignature(this.items, now);
87
122
  if (webSig !== this.webSignature) {
88
123
  this.webSignature = webSig;
@@ -91,20 +126,30 @@ export class NeedsYouHub {
91
126
  const settings = this.ctx.settings();
92
127
  const worlds = this.ctx.worlds();
93
128
  const worldIds = new Set(worlds.map(w => w.id));
94
- for (const [id, pinned] of this.live) {
95
- const current = worlds.find(w => w.id === id);
129
+ for (const [key, pinned] of this.live) {
130
+ const current = worlds.find(w => w.id === pinned.world);
96
131
  if (!settings.liveMessage || !current) {
97
- this.live.delete(id);
98
- this.worldSignature.delete(id);
132
+ this.live.delete(key);
133
+ this.worldSignature.delete(key);
134
+ this.worldSeen.delete(key);
99
135
  void pinned.renderer.disable();
100
136
  }
101
137
  else if (current.adapter !== pinned.adapter || placeKey(current.place) !== pinned.placeKey) {
102
138
  // Another adapter (or place) under the same id: the old renderer stops without touching anything — its adapter
103
139
  // may be gone — and a new one picks up from the persisted pointer.
104
- this.live.delete(id);
105
- this.worldSignature.delete(id);
140
+ this.live.delete(key);
141
+ this.worldSignature.delete(key);
142
+ this.worldSeen.delete(key);
106
143
  pinned.renderer.abandon();
107
144
  }
145
+ else if (pinned.lane !== null && !this.laneUsable(pinned.lane, pinned.world)) {
146
+ // #2352: the lane is gone from this world (its instance removed or moved, its channel gone): its message says
147
+ // so, without buttons, and is forgotten. A lane that is merely empty stays, saying nothing waits.
148
+ this.live.delete(key);
149
+ this.worldSignature.delete(key);
150
+ this.worldSeen.delete(key);
151
+ void pinned.renderer.disable(this.ctx.t("needs.live_moved"));
152
+ }
108
153
  }
109
154
  if (!settings.dm)
110
155
  for (const id of [...this.dmPending.keys()])
@@ -114,25 +159,39 @@ export class NeedsYouHub {
114
159
  this.cancelDms(id);
115
160
  const seeding = !this.seeded;
116
161
  this.seeded = true;
162
+ const saved = settings.liveMessage ? Object.keys(this.readPointers()) : [];
117
163
  for (const world of worlds) {
118
164
  const mine = itemsForWorld(this.items, world.id);
119
- if (seeding) {
120
- this.worldSeen.set(world.id, new Set(mine.map(i => i.id)));
165
+ if (seeding)
121
166
  this.dmSeen.set(world.id, new Set(mine.map(i => i.id)));
122
- }
123
- const seen = this.worldSeen.get(world.id) ?? new Set();
124
- const fresh = mine.filter(i => !seen.has(i.id));
125
- this.worldSeen.set(world.id, new Set(mine.map(i => i.id)));
126
167
  if (settings.liveMessage) {
127
- let pinned = this.live.get(world.id);
128
- if (!pinned) {
129
- pinned = { renderer: this.makeLive(world), adapter: world.adapter, placeKey: placeKey(world.place) };
130
- this.live.set(world.id, pinned);
131
- }
132
- const sig = renderSignature(mine, now);
133
- if (sig !== this.worldSignature.get(world.id)) {
134
- this.worldSignature.set(world.id, sig);
135
- pinned.renderer.changed(fresh.length > 0);
168
+ // General, every lane with cards now, and every lane whose message is still out there (from before a restart,
169
+ // or emptied since): those render too, so a stale list never keeps its old lines.
170
+ const lanes = new Set(lanesOf(this.items, world.id));
171
+ for (const k of saved)
172
+ if (k.startsWith(world.id + LANE_SEP))
173
+ lanes.add(k.slice(world.id.length + LANE_SEP.length));
174
+ for (const [, pinned] of this.live)
175
+ if (pinned.world === world.id && pinned.lane !== null)
176
+ lanes.add(pinned.lane);
177
+ for (const lane of [null, ...[...lanes].filter(l => this.laneUsable(l, world.id))]) {
178
+ const key = liveKey(world.id, lane);
179
+ const listed = itemsForLane(this.items, world.id, lane);
180
+ if (seeding)
181
+ this.worldSeen.set(key, new Set(listed.map(i => i.id)));
182
+ const seen = this.worldSeen.get(key) ?? new Set();
183
+ const fresh = listed.filter(i => !seen.has(i.id));
184
+ this.worldSeen.set(key, new Set(listed.map(i => i.id)));
185
+ let pinned = this.live.get(key);
186
+ if (!pinned) {
187
+ pinned = { renderer: this.makeLive(world, lane), adapter: world.adapter, placeKey: placeKey(world.place), world: world.id, lane };
188
+ this.live.set(key, pinned);
189
+ }
190
+ const sig = renderSignature(listed, now);
191
+ if (sig !== this.worldSignature.get(key)) {
192
+ this.worldSignature.set(key, sig);
193
+ pinned.renderer.changed(fresh.length > 0);
194
+ }
136
195
  }
137
196
  }
138
197
  if (settings.dm)
@@ -172,27 +231,42 @@ export class NeedsYouHub {
172
231
  this.ctx.log("warn", "Needs you: could not save where the live message is", { world, err: String(err?.message ?? err) });
173
232
  }
174
233
  }
175
- lineTitle(item) { return this.ctx.t(`needs.reason.${item.reason}`); }
176
- makeLive(world) {
234
+ /** A line's words: why it waits — and for a card, which card and what it asks or lacks (the chat shows no detail). */
235
+ lineTitle(item) {
236
+ const reason = this.ctx.t(`needs.reason.${item.reason}`);
237
+ return item.type === "task" && item.detail ? `${reason}: ${item.detail}` : reason;
238
+ }
239
+ /** #2352: a lane can carry a list here: its instance is this world's now, and has a channel of its own. */
240
+ laneUsable(lane, world) {
241
+ return this.ctx.ownerOf(lane) === world && !!this.ctx.laneTarget?.(lane);
242
+ }
243
+ /** Where a list (General, or a lane's) is posted now, or null. */
244
+ listTarget(world, lane) {
245
+ if (!lane)
246
+ return this.ctx.noticeTarget(world);
247
+ return this.laneUsable(lane, world) ? this.ctx.laneTarget(lane) : null;
248
+ }
249
+ makeLive(world, lane) {
177
250
  const ctx = this.ctx;
178
- const owner = Symbol(world.id);
251
+ const key = liveKey(world.id, lane);
252
+ const owner = Symbol(key);
179
253
  return new NeedsYouLiveMessage({
180
- world: world.id,
254
+ world: key,
181
255
  now: () => ctx.mono(),
182
256
  setTimer: (fn, ms) => ctx.setTimer(fn, ms),
183
257
  clearTimer: h => ctx.clearTimer(h),
184
- target: () => { const t = ctx.noticeTarget(world.id); return t ? canonicalTarget(t) : null; },
258
+ target: () => { const t = this.listTarget(world.id, lane); return t ? canonicalTarget(t) : null; },
185
259
  enabled: () => ctx.settings().liveMessage,
186
260
  stopping: () => ctx.stopping() || this.stopped,
187
261
  // The same world means the same adapter object and place it was built for, not just the same id.
188
262
  worldExists: () => ctx.worlds().some(w => w.id === world.id && w.adapter === world.adapter && placeKey(w.place) === placeKey(world.place)),
189
263
  content: () => {
190
- const mine = itemsForWorld(this.items, world.id);
264
+ const mine = itemsForLane(this.items, world.id, lane);
191
265
  const lines = mine.map(item => ({
192
266
  item, title: this.lineTitle(item),
193
267
  link: item.promptAt ? messageLink(world.place, item.promptAt) : instanceLink(world.place, ctx.instanceTopic(item.instance)),
194
268
  }));
195
- const rendered = renderLiveMessage(lines, ctx.now(), (k, ...a) => ctx.t(k, ...a));
269
+ const rendered = renderLiveMessage(lines, ctx.now(), (k, ...a) => ctx.t(k, ...a), lane ? "needs.live_header_lane" : "needs.live_header");
196
270
  return { empty: mine.length === 0, ...rendered };
197
271
  },
198
272
  post: async (target, text, choices) => {
@@ -206,25 +280,36 @@ export class NeedsYouHub {
206
280
  },
207
281
  isEditLoss: isMessageEditLoss,
208
282
  remove: async (pointer) => { await world.adapter.deleteMessage?.(pointer.chatId, pointer.messageId, pointer.threadId); },
209
- loadPointer: () => this.readPointers()[world.id] ?? null,
210
- savePointer: pointer => this.writePointer(world.id, pointer),
211
- mintAcks: (generation, place, items) => this.mintAcks(world.id, owner, generation, place, items),
283
+ loadPointer: () => this.readPointers()[key] ?? null,
284
+ savePointer: pointer => this.writePointer(key, pointer),
285
+ mintAcks: (generation, place, items) => this.mintAcks(world.id, owner, generation, place, items, lane),
212
286
  revokeAcks: () => this.revokeAcks(owner),
213
287
  log: (message, extra) => ctx.log("info", `Needs you: ${message}`, extra),
214
288
  text: { stopped: ctx.t("needs.live_stopped"), off: ctx.t("needs.live_off") },
215
289
  });
216
290
  }
217
- mintAcks(world, owner, generation, place, items) {
291
+ mintAcks(world, owner, generation, place, items, lane = null) {
218
292
  const minted = [];
219
- const choices = items.filter(i => i.deliveryId).map(item => {
293
+ const mint = (item, verb, label) => {
220
294
  const nonce = randomBytes(16).toString("hex");
221
295
  const entry = {
222
296
  world, owner, generation, deadline: this.ctx.mono() + ACK_TTL_MS, chatId: place.chatId, ...(place.threadId !== undefined ? { threadId: place.threadId } : {}),
223
- ...(place.messageId ? { messageId: place.messageId } : {}), deliveryId: item.deliveryId, instance: item.instance,
297
+ ...(place.messageId ? { messageId: place.messageId } : {}), verb, instance: item.instance, ...(lane ? { lane } : {}),
298
+ ...(item.deliveryId ? { deliveryId: item.deliveryId } : {}), ...(item.card ? { card: { ...item.card } } : {}),
224
299
  };
225
300
  this.acks.set(nonce, entry);
226
301
  minted.push(entry);
227
- return { id: `${NEEDS_ACK_PREFIX}${nonce}:ack`, label: this.ctx.t("needs.ack_button", item.instance) };
302
+ return { id: `${NEEDS_ACK_PREFIX}${nonce}:${verb}`, label };
303
+ };
304
+ const choices = items.flatMap(item => {
305
+ if (item.deliveryId)
306
+ return [mint(item, "ack", this.ctx.t("needs.ack_button", item.instance))];
307
+ if (item.type !== "task" || !item.card)
308
+ return [];
309
+ const code = item.card.code;
310
+ return item.reason === "task_review"
311
+ ? [mint(item, "confirm", this.ctx.t("needs.task_confirm_button", code)), mint(item, "back", this.ctx.t("needs.task_back_button", code))]
312
+ : [mint(item, "answer", this.ctx.t("needs.task_answer_button", code))];
228
313
  });
229
314
  return { choices, bind: pointer => { for (const e of minted)
230
315
  e.messageId = pointer.messageId; } };
@@ -244,7 +329,8 @@ export class NeedsYouHub {
244
329
  if (!data.callbackData.startsWith(NEEDS_ACK_PREFIX))
245
330
  return false;
246
331
  const m = ACK_RE.exec(data.callbackData);
247
- const entry = m ? this.acks.get(m[1]) : undefined;
332
+ const found = m ? this.acks.get(m[1]) : undefined;
333
+ const entry = found && found.verb === m[2] ? found : undefined;
248
334
  if (entry && this.ctx.mono() >= entry.deadline)
249
335
  this.acks.delete(m[1]);
250
336
  // Unknown, revoked, lapsed — or not yet bound to the message its post returned: no authority yet.
@@ -263,13 +349,193 @@ export class NeedsYouHub {
263
349
  data.ack?.(this.ctx.t("buttons.admin_only"));
264
350
  return true;
265
351
  }
266
- // §5.0: the item must still belong to this world.
267
- if (this.ctx.ownerOf(entry.instance) !== adapterId) {
352
+ // §5.0: the item must still belong to this world — for a laned card, its lane's world (#2352).
353
+ if (this.ctx.ownerOf(entry.lane ?? entry.instance) !== adapterId) {
268
354
  data.ack?.(this.ctx.t("needs.ack_not_this_world"));
269
355
  return true;
270
356
  }
357
+ // #2352: and a card must still wait where this button showed it (its lead or dispatcher changed: elsewhere now).
358
+ // #2355 review: read now — the card's route (a lead changed) and the list's place (a lane's topic moved or went).
359
+ if (entry.card && (!this.stillInLane(entry.card.code, entry.lane) || !this.placeStill(adapterId, entry.lane, entry.chatId, entry.threadId))) {
360
+ data.ack?.(this.ctx.t("needs.task_moved"));
361
+ return true;
362
+ }
271
363
  const platform = this.ctx.worlds().find(w => w.id === adapterId)?.place.type ?? "chat";
272
- data.ack?.(this.ctx.t(`needs.ack_${this.acknowledge(entry.deliveryId, `${platform}:${data.userId}`)}`));
364
+ if (entry.verb === "ack") {
365
+ data.ack?.(this.ctx.t(`needs.ack_${this.acknowledge(entry.deliveryId, `${platform}:${data.userId}`)}`));
366
+ return true;
367
+ }
368
+ const card = entry.card;
369
+ const by = { platform, userId: data.userId, ...(data.username ? { username: data.username } : {}) };
370
+ if (entry.verb === "confirm") {
371
+ const outcome = this.ctx.taskAction?.({ verb: "confirm", code: card.code, version: card.version, by }) ?? { ok: false, message: this.ctx.t("needs.task_board_closed") };
372
+ data.ack?.(outcome.message);
373
+ this.poke();
374
+ return true;
375
+ }
376
+ // Send back and Answer take words: a prompt the clicker answers by replying to it (handleReply). One prompt per
377
+ // world, card, person and verb at a time, reserved before the send (#2306 review): a second press while one is on
378
+ // its way or still waits is told so, and the prompts open over everything are capped.
379
+ const askKey = `${adapterId}|${card.code}|${data.userId}|${entry.verb}`;
380
+ if (this.asking.has(askKey) || this.pendingFor(askKey)) {
381
+ data.ack?.(this.ctx.t("needs.task_reply_already", card.code));
382
+ return true;
383
+ }
384
+ if (this.asking.size + this.livePending() >= TASK_REPLY_MAX) {
385
+ data.ack?.(this.ctx.t("needs.task_reply_busy"));
386
+ return true;
387
+ }
388
+ this.asking.add(askKey);
389
+ data.ack?.(this.ctx.t("needs.task_reply_asked"));
390
+ void this.askForReply(entry, entry.verb, by, askKey);
391
+ return true;
392
+ }
393
+ /**
394
+ * #2352: a card still routes to this lane (or, for no lane, to General) — asked of the board now (#2355 review: a
395
+ * project's lead can change with the card's version unchanged, and the last render may not have seen it yet). One
396
+ * that no longer waits for the person is left to the board, which answers by its version.
397
+ */
398
+ stillInLane(code, lane) {
399
+ if (this.ctx.taskRoute) {
400
+ const route = this.ctx.taskRoute(code);
401
+ return route === null || (route.lane ?? undefined) === lane;
402
+ }
403
+ const now = this.items.find(i => i.type === "task" && i.card?.code === code);
404
+ return !now || (now.lane ?? undefined) === lane;
405
+ }
406
+ /** #2355 review: a list's place (its lane's channel, or General) is still where this button or prompt is. */
407
+ placeStill(world, lane, chatId, threadId) {
408
+ const target = this.listTarget(world, lane);
409
+ return !!target && samePlace(target, { chatId, ...(threadId !== undefined ? { threadId } : {}) });
410
+ }
411
+ /** A prompt for this reservation still waits for its reply. */
412
+ pendingFor(askKey) {
413
+ const now = this.ctx.mono();
414
+ for (const r of this.replies.values())
415
+ if (r.askKey === askKey && now < r.deadline)
416
+ return true;
417
+ return false;
418
+ }
419
+ /** Prompts still waiting for their reply (lapsed ones go). */
420
+ livePending() {
421
+ const now = this.ctx.mono();
422
+ for (const [key, r] of this.replies)
423
+ if (now >= r.deadline)
424
+ this.replies.delete(key);
425
+ return this.replies.size;
426
+ }
427
+ /**
428
+ * The card's instance is still this world's, the world still the same connection in the same place, and its notice
429
+ * place still where the prompt is: else a reply there is not this world's to take (#2306 review — an instance that
430
+ * moved to another world, a replaced connection, a new notice room).
431
+ */
432
+ stillHere(p) {
433
+ if (this.ctx.ownerOf(p.lane ?? p.instance) !== p.world)
434
+ return false;
435
+ const now = this.ctx.worlds().find(w => w.id === p.world);
436
+ if (!now || now.adapter !== p.adapter || placeKey(now.place) !== p.placeKey)
437
+ return false;
438
+ // #2352: the card still waits in this lane, and the lane's (or General's) place is still where the prompt is.
439
+ if (p.code !== undefined && !this.stillInLane(p.code, p.lane))
440
+ return false;
441
+ return this.placeStill(p.world, p.lane, p.chatId, p.threadId);
442
+ }
443
+ /** Post the prompt for a Send back's reason or an answer, and wait for the clicker's reply to it. */
444
+ async askForReply(entry, verb, by, askKey) {
445
+ const card = entry.card;
446
+ try {
447
+ const world = this.ctx.worlds().find(w => w.id === entry.world);
448
+ if (!world || this.stopped)
449
+ return;
450
+ const target = { world: entry.world, instance: entry.instance, ...(entry.lane ? { lane: entry.lane } : {}), code: card.code,
451
+ adapter: world.adapter, placeKey: placeKey(world.place), chatId: entry.chatId, ...(entry.threadId !== undefined ? { threadId: entry.threadId } : {}) };
452
+ // #2355 review: and again before the prompt goes out — the card's route and the place as they are now.
453
+ if (!this.stillHere(target))
454
+ return;
455
+ const who = by.username ? ` (@${by.username})` : "";
456
+ const text = this.ctx.t(verb === "back" ? "needs.task_back_prompt" : "needs.task_answer_prompt", card.code, who, Math.round(TASK_REPLY_TTL_MS / 60_000));
457
+ const sent = await world.adapter.sendText(entry.chatId, text, entry.threadId !== undefined ? { threadId: entry.threadId } : undefined);
458
+ // While it was on its way the fleet may have stopped, or the card's instance, the connection or the room moved.
459
+ if (this.stopped || !this.stillHere(target))
460
+ return;
461
+ const pending = {
462
+ ...target, askKey, messageId: sent.messageId,
463
+ userId: by.userId, ...(by.username ? { username: by.username } : {}), verb, code: card.code, version: card.version,
464
+ deadline: this.ctx.mono() + TASK_REPLY_TTL_MS,
465
+ };
466
+ this.replies.set(`${entry.chatId}|${sent.messageId}`, pending);
467
+ }
468
+ catch (err) {
469
+ this.ctx.log("warn", "Needs you: could not ask for a reply", { code: card.code, err: String(err?.message ?? err) });
470
+ }
471
+ finally {
472
+ this.asking.delete(askKey);
473
+ }
474
+ }
475
+ /**
476
+ * An inbound message that replies to one of our Send back / Answer prompts, by the admin who clicked: its text is
477
+ * the reason or the answer, and the message goes no further (true). Anything else — another message, another
478
+ * person, a lapsed prompt — is not ours (false) and flows on as usual.
479
+ */
480
+ handleReply(msg) {
481
+ if (!msg.replyTo)
482
+ return false;
483
+ // #2306 review: found by where the prompt is, whichever bot received the reply (in a shared Discord guild a
484
+ // sibling bot's copy may come first), and judged by the prompt's world — its admins, its instance, its connection
485
+ // and room as they are now — so the answer is taken once, and only with that world's authority.
486
+ const key = `${msg.chatId}|${msg.replyTo}`;
487
+ const pending = this.replies.get(key);
488
+ if (!pending)
489
+ return false;
490
+ if (this.ctx.mono() >= pending.deadline) {
491
+ this.replies.delete(key);
492
+ return false;
493
+ }
494
+ if (msg.userId !== pending.userId || (pending.threadId !== undefined && msg.threadId !== undefined && msg.threadId !== pending.threadId))
495
+ return false;
496
+ if (!this.ctx.isFleetAdmin(msg.userId, pending.world))
497
+ return false;
498
+ if (!this.stillHere(pending)) {
499
+ this.replies.delete(key);
500
+ return false;
501
+ }
502
+ this.replies.delete(key);
503
+ if (msg.messageId) {
504
+ this.taken.set(`${msg.chatId}|${msg.messageId}`, this.ctx.mono() + TASK_REPLY_TTL_MS);
505
+ for (const [k, until] of this.taken)
506
+ if (this.taken.size > 256 || this.ctx.mono() >= until)
507
+ this.taken.delete(k);
508
+ else
509
+ break;
510
+ }
511
+ const text = msg.text.trim();
512
+ const world = this.ctx.worlds().find(w => w.id === pending.world);
513
+ const platform = world?.place.type ?? "chat";
514
+ const outcome = text
515
+ ? this.ctx.taskAction?.({ verb: pending.verb, code: pending.code, version: pending.version, text,
516
+ by: { platform, userId: msg.userId, ...(msg.username ? { username: msg.username } : {}) } }) ?? { ok: false, message: this.ctx.t("needs.task_board_closed") }
517
+ : { ok: false, message: this.ctx.t("needs.task_reply_empty", pending.code) };
518
+ this.poke();
519
+ if (world) {
520
+ void world.adapter.sendText(msg.chatId, outcome.message, { ...(msg.threadId !== undefined ? { threadId: msg.threadId } : {}), replyTo: msg.messageId })
521
+ .catch(err => this.ctx.log("warn", "Needs you: could not answer a reply", { code: pending.code, err: String(err?.message ?? err) }));
522
+ }
523
+ return true;
524
+ }
525
+ /**
526
+ * #2341 review r2: this message (another bot's copy of it) was already taken as a prompt's answer. The inbound handler
527
+ * asks it first and drops the copy: it is neither a second answer nor an agent's input.
528
+ */
529
+ wasTakenReply(chatId, messageId) {
530
+ if (!messageId)
531
+ return false;
532
+ const until = this.taken.get(`${chatId}|${messageId}`);
533
+ if (until === undefined)
534
+ return false;
535
+ if (this.ctx.mono() >= until) {
536
+ this.taken.delete(`${chatId}|${messageId}`);
537
+ return false;
538
+ }
273
539
  return true;
274
540
  }
275
541
  /** The web's Acknowledge: any item (the web is global, §5.0). `principal` is "web:<session handle>" or "cli". */
@@ -392,6 +658,9 @@ export class NeedsYouHub {
392
658
  this.cancelDms(id);
393
659
  await Promise.all([...this.live.values()].map(p => p.renderer.retire()));
394
660
  this.acks.clear();
661
+ this.replies.clear();
662
+ this.asking.clear();
663
+ this.taken.clear();
395
664
  }
396
665
  }
397
666
  //# sourceMappingURL=needs-you-hub.js.map