@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
@@ -0,0 +1,297 @@
1
+ // #2233: signing a backend in from the dashboard — the dialog, the line every admin page shows while a sign-in runs,
2
+ // and the list Settings → Agents shows. Behind the session gate (/ui/js/); a guest's page never loads it.
3
+ //
4
+ // What the page is told comes from GET /ui/backend-login, as this session may see it (web-backend-login.ts): the
5
+ // session that started a sign-in gets its terminal link, access code and device code; every other admin page only that
6
+ // one runs, on which device, and may cancel it. The stream's `backend_login` event carries nothing — it only says to
7
+ // read again. Starting is two steps, as in chat: check (the server keeps what it found) and start (with its id).
8
+ import { html, useEffect, useState } from "/assets/app-html.js";
9
+ import { t, register } from "/assets/app-i18n.js";
10
+ import { appStore, createStore, useStore } from "/assets/app-store.js";
11
+ import { closeDialog, shellStore, showDialog } from "/assets/app-shell.js";
12
+ import { Dialog } from "/assets/ui-dialog.js";
13
+ import { toast } from "/assets/ui-toast.js";
14
+
15
+ register("signin", {
16
+ en: {
17
+ title: "Sign in to {0}",
18
+ checking: "Checking whether {0} is signed in…",
19
+ confirmDevice: "AgEnD runs {0}'s own sign-in on this machine. You get a link and a one-time code here, to finish in your browser.",
20
+ confirmTerminal: "AgEnD runs {0}'s own sign-in on this machine and opens it as a terminal in your browser (only that sign-in, no shell). You get the link and a one-time access code here.",
21
+ stillSignedIn: "It is still signed in: signing in again replaces that login.",
22
+ logoutFirst: "It signs out first ({0}), then in.",
23
+ publicNote: "Not at this machine? A temporary public link opens the terminal from anywhere, for this sign-in only.",
24
+ go: "Sign in",
25
+ goPublic: "Use a temporary public link",
26
+ cancel: "Cancel",
27
+ close: "Close",
28
+ starting: "Starting…",
29
+ deviceStep: "Open this page and enter the code:",
30
+ linkStep: "Open this page to sign in; if it gives you a code, paste it into the sign-in terminal:",
31
+ terminalStep: "Open the sign-in terminal and enter this access code there. It works once, for {0} minutes.",
32
+ openTerminal: "Open the sign-in terminal",
33
+ accessCode: "Access code",
34
+ code: "Code",
35
+ copy: "Copy",
36
+ copied: "Copied",
37
+ publicLink: "Public link: anyone with the link and the code could use it — keep both to yourself.",
38
+ loopback: "This terminal listens on the machine's own address only. Open it on that machine, or set web_terminal.bind for your network.",
39
+ waitingHint: "Waiting for the sign-in to show its link…",
40
+ signedIn: "{0} is signed in.",
41
+ ended: "The sign-in ended.",
42
+ cancelSignIn: "Cancel sign-in",
43
+ cancelled: "Sign-in cancelled.",
44
+ running: "Signing in to {0} (started on {1}).",
45
+ open: "Open",
46
+ expired: "That took too long — start again.",
47
+ notHere: "Signing in is not available over the public link. Open the dashboard on the machine running AgEnD, or use /login in your chat.",
48
+ notAdmin: "Only a fleet admin signed in on this machine or its network can sign a backend in.",
49
+ notOffered: "A public link is not offered for this sign-in.",
50
+ failed: "That did not work.",
51
+ listTitle: "Sign-ins",
52
+ listHint: "Each backend's login on this machine, and each credential profile an agent uses.",
53
+ stUsable: "signed in",
54
+ stNotSignedIn: "not signed in",
55
+ stNotInstalled: "not installed",
56
+ stTooOld: "too old",
57
+ stUnknown: "not checked",
58
+ signIn: "Sign in",
59
+ signInAgain: "Sign in again",
60
+ onHost: "Sign in on the machine: {0}",
61
+ install: "Install on the machine: {0}",
62
+ update: "Update on the machine: {0}",
63
+ profile: "{0} · profile {1}",
64
+ },
65
+ "zh-TW": {
66
+ title: "登入 {0}",
67
+ checking: "正在確認 {0} 是否已登入…",
68
+ confirmDevice: "AgEnD 會在這台機器上執行 {0} 自己的登入。這裡會給你一個連結和一次性代碼,在瀏覽器完成登入。",
69
+ confirmTerminal: "AgEnD 會在這台機器上執行 {0} 自己的登入,並在瀏覽器以終端機開啟(只有這個登入,沒有 shell)。這裡會給你連結和一次性存取碼。",
70
+ stillSignedIn: "它目前仍是登入狀態:重新登入會取代原本的登入。",
71
+ logoutFirst: "會先登出({0}),再登入。",
72
+ publicNote: "不在這台機器前?臨時公開連結可以從任何地方開啟終端機,只用於這次登入。",
73
+ go: "登入",
74
+ goPublic: "使用臨時公開連結",
75
+ cancel: "取消",
76
+ close: "關閉",
77
+ starting: "啟動中…",
78
+ deviceStep: "開啟這個頁面並輸入代碼:",
79
+ linkStep: "開啟這個頁面登入;如果它給你一組代碼,請貼到登入終端機:",
80
+ terminalStep: "開啟登入終端機,在那裡輸入這個存取碼。只能用一次,{0} 分鐘內有效。",
81
+ openTerminal: "開啟登入終端機",
82
+ accessCode: "存取碼",
83
+ code: "代碼",
84
+ copy: "複製",
85
+ copied: "已複製",
86
+ publicLink: "公開連結:拿到連結和代碼的人都能使用——兩者都只留給自己。",
87
+ loopback: "這個終端機只在本機位址上接聽。請在那台機器上開啟,或為你的網路設定 web_terminal.bind。",
88
+ waitingHint: "等待登入顯示連結…",
89
+ signedIn: "{0} 已登入。",
90
+ ended: "登入已結束。",
91
+ cancelSignIn: "取消登入",
92
+ cancelled: "已取消登入。",
93
+ running: "正在登入 {0}(從 {1} 啟動)。",
94
+ open: "開啟",
95
+ expired: "等太久了——請重新開始。",
96
+ notHere: "公開連結上不能登入。請在執行 AgEnD 的機器上開啟儀表板,或在聊天裡用 /login。",
97
+ notAdmin: "只有在這台機器或它的網路上登入的 fleet 管理員,才能讓後端登入。",
98
+ notOffered: "這次登入不提供公開連結。",
99
+ failed: "沒有成功。",
100
+ listTitle: "登入",
101
+ listHint: "這台機器上每個 backend 的登入,以及代理使用的每個憑證設定檔。",
102
+ stUsable: "已登入",
103
+ stNotSignedIn: "未登入",
104
+ stNotInstalled: "未安裝",
105
+ stTooOld: "版本太舊",
106
+ stUnknown: "未檢查",
107
+ signIn: "登入",
108
+ signInAgain: "重新登入",
109
+ onHost: "在機器上登入:{0}",
110
+ install: "在機器上安裝:{0}",
111
+ update: "在機器上更新:{0}",
112
+ profile: "{0} · 設定檔 {1}",
113
+ },
114
+ });
115
+ const tn = (k, ...v) => t(`signin.${k}`, ...v);
116
+ const shownOf = (backend, profile) => (profile ? tn("profile", backend, profile) : backend);
117
+
118
+ /** What this page knows: the current sign-in as this session may see it, and Settings' list. */
119
+ export const signInStore = createStore({ loaded: false, login: null, targets: [] });
120
+
121
+ let reading = null, again = false;
122
+ /**
123
+ * Read GET /ui/backend-login (one read at a time). Asked again while one is on its way (an event that came after it was
124
+ * sent): one more read follows it, so the last change is never missed (#2262 review).
125
+ */
126
+ export function refreshSignIn() {
127
+ if (reading) { again = true; return reading; }
128
+ reading = fetch("/ui/backend-login", { cache: "no-store" })
129
+ .then((r) => (r.ok ? r.json() : null))
130
+ .then((b) => { if (b) signInStore.set({ loaded: true, login: b.login || null, targets: Array.isArray(b.targets) ? b.targets : [] }); return b; })
131
+ .catch(() => null)
132
+ .finally(() => { reading = null; if (again) { again = false; void refreshSignIn(); } });
133
+ return reading;
134
+ }
135
+
136
+ let installed = false;
137
+ /** Once per admin page: listen for `backend_login`, read once, and show the line while a sign-in runs. */
138
+ export function installSignIn() {
139
+ if (installed || !signInOffered()) return;
140
+ installed = true;
141
+ const on = appStore.get().streamOn;
142
+ if (typeof on === "function") on("backend_login", () => { void refreshSignIn(); });
143
+ void refreshSignIn();
144
+ shellStore.set({ banner: SignInLine });
145
+ }
146
+
147
+ /** Open the dialog for one login (a backend's default one, or a credential profile). */
148
+ export function openSignIn({ backend, profile }) {
149
+ showDialog(SignInDialog, { backend, ...(profile ? { profile } : {}) });
150
+ }
151
+
152
+ /** Open the dialog on the running sign-in (its starter's view, or the cancel-only one). */
153
+ function openRunning(login) { showDialog(SignInDialog, { backend: login.backend, ...(login.profile ? { profile: login.profile } : {}), resume: true }); }
154
+
155
+ async function post(path, body) {
156
+ try {
157
+ const res = await fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) });
158
+ let json = null; try { json = await res.json(); } catch { /* none */ }
159
+ return { ok: res.ok, status: res.status, body: json };
160
+ } catch { return { ok: false, status: 0, body: null }; }
161
+ }
162
+
163
+ const errorText = (code) => (code === "confirm_expired" ? tn("expired") : code === "tunnel_not_offered" ? tn("notOffered")
164
+ : code === "sign_in_not_over_public_link" ? tn("notHere") : code === "sign_in_needs_a_local_admin" ? tn("notAdmin") : tn("failed"));
165
+ /** The public link's page (#2233: Sign in is refused there — never offered). */
166
+ export const signInOffered = () => !(typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1");
167
+ const loopbackHost = (h) => h === "localhost" || h === "::1" || h === "[::1]" || /^127\./.test(h);
168
+
169
+ function CopyField({ label, value }) {
170
+ const [copied, setCopied] = useState(false);
171
+ const copy = async () => { try { await navigator.clipboard.writeText(value); setCopied(true); } catch { toast(value); } };
172
+ return html`<div class="signin-field"><span class="signin-label">${label}</span><code class="signin-value">${value}</code>
173
+ <button type="button" class="btn btn-sm" onClick=${copy}>${copied ? tn("copied") : tn("copy")}</button></div>`;
174
+ }
175
+
176
+ /** The starter's view of a running sign-in: the device link and code, or the terminal and its access code. */
177
+ function Running({ login }) {
178
+ const { hint, terminal, accessCode } = login;
179
+ const away = terminal && terminal.loopback && typeof location !== "undefined" && !loopbackHost(location.hostname);
180
+ return html`<div class="signin-run">
181
+ ${hint ? html`<p>${hint.code ? tn("deviceStep") : tn("linkStep")}</p>
182
+ ${hint.linkable ? html`<p><a data-trust="navigation" class="btn btn-primary" href=${hint.url} target="_blank" rel="noopener noreferrer">${tn("open")}</a> <span class="signin-url">${hint.url}</span></p>`
183
+ : html`<${CopyField} label="URL" value=${hint.url} />`}
184
+ ${hint.code ? html`<${CopyField} label=${tn("code")} value=${hint.code} />` : null}` : null}
185
+ ${terminal ? html`<p>${tn("terminalStep", terminal.ttlMinutes)}</p>
186
+ <p><a data-trust="navigation" class="btn btn-primary" href=${terminal.url} target="_blank" rel="noopener noreferrer">${tn("openTerminal")}</a></p>
187
+ ${accessCode ? html`<${CopyField} label=${tn("accessCode")} value=${accessCode} />` : null}
188
+ ${terminal.public ? html`<p class="signin-note">${tn("publicLink")}</p>` : null}
189
+ ${away ? html`<p class="signin-note">${tn("loopback")}</p>` : null}` : null}
190
+ ${!hint && !terminal ? html`<p class="signin-note">${tn("waitingHint")}</p>` : null}
191
+ </div>`;
192
+ }
193
+
194
+ export function SignInDialog({ backend, profile, resume = false, onClose }) {
195
+ const s = useStore(signInStore);
196
+ const [step, setStep] = useState(resume ? { kind: "login" } : { kind: "checking" });
197
+ const [busy, setBusy] = useState(false);
198
+ const shown = shownOf(backend, profile);
199
+ const close = onClose || closeDialog;
200
+ useEffect(() => {
201
+ if (resume) return undefined;
202
+ let gone = false;
203
+ post("/ui/backend-login/check", { backend, ...(profile ? { profile } : {}) }).then((r) => {
204
+ if (gone) return;
205
+ if (r.body && r.body.confirm) setStep({ kind: "confirm", confirm: r.body.confirm });
206
+ else setStep({ kind: "message", text: (r.body && (r.body.message || (r.body.error && errorText(r.body.error)))) || tn("failed") });
207
+ });
208
+ return () => { gone = true; };
209
+ }, []);
210
+ const login = s.login;
211
+ const live = step.kind === "login" && login && login.phase === "running";
212
+ // While a running sign-in is on screen, read it every 2 s too (a page without the stream still sees it move).
213
+ useEffect(() => {
214
+ if (!live) return undefined;
215
+ const h = setInterval(() => { void refreshSignIn(); }, 2000);
216
+ return () => clearInterval(h);
217
+ }, [live]);
218
+ const start = async (tunnel) => {
219
+ setBusy(true); setStep({ kind: "starting" });
220
+ const r = await post("/ui/backend-login/start", { confirm: step.confirm.id, ...(tunnel ? { tunnel: true } : {}) });
221
+ setBusy(false);
222
+ if (r.body && r.body.login) { signInStore.set({ login: r.body.login }); setStep({ kind: "login" }); return; }
223
+ setStep({ kind: "message", text: (r.body && (r.body.message || (r.body.error && errorText(r.body.error)))) || tn("failed") });
224
+ };
225
+ const cancelRun = async () => {
226
+ setBusy(true);
227
+ const r = await post("/ui/backend-login/cancel", {});
228
+ setBusy(false);
229
+ toast((r.body && r.body.message) || tn("cancelled"));
230
+ void refreshSignIn();
231
+ };
232
+ let body, actions;
233
+ if (step.kind === "checking" || step.kind === "starting") {
234
+ body = html`<p role="status">${step.kind === "checking" ? tn("checking", shown) : tn("starting")}</p>`;
235
+ actions = html`<button type="button" class="btn" disabled=${busy} onClick=${close}>${tn("cancel")}</button>`;
236
+ } else if (step.kind === "confirm") {
237
+ const c = step.confirm;
238
+ body = html`<p>${c.deviceAuth ? tn("confirmDevice", shown) : tn("confirmTerminal", shown)}</p>
239
+ ${c.tokenPresent ? html`<p>${tn("stillSignedIn")}</p>` : null}
240
+ ${c.logoutFirst ? html`<p>${tn("logoutFirst", c.logoutFirst)}</p>` : null}
241
+ ${c.publicLink ? html`<p class="signin-note">${tn("publicNote")}</p>` : null}`;
242
+ actions = html`<button type="button" class="btn" onClick=${close}>${tn("cancel")}</button>
243
+ ${c.publicLink ? html`<button type="button" class="btn" onClick=${() => start(true)}>${tn("goPublic")}</button>` : null}
244
+ <button type="button" class="btn btn-primary" onClick=${() => start(false)}>${tn("go")}</button>`;
245
+ } else if (step.kind === "message") {
246
+ body = html`<p class="signin-message">${step.text}</p>`;
247
+ actions = html`<button type="button" class="btn btn-primary" onClick=${close}>${tn("close")}</button>`;
248
+ } else if (!login) {
249
+ body = html`<p class="signin-note">${tn("ended")}</p>`;
250
+ actions = html`<button type="button" class="btn btn-primary" onClick=${close}>${tn("close")}</button>`;
251
+ } else if (!login.mine) {
252
+ body = html`<p>${login.phase === "running" ? tn("running", shownOf(login.backend, login.profile), login.startedOn) : tn("ended")}</p>`;
253
+ actions = html`<button type="button" class="btn" onClick=${close}>${tn("close")}</button>
254
+ ${login.phase === "running" ? html`<button type="button" class="btn btn-danger" disabled=${busy} onClick=${cancelRun}>${tn("cancelSignIn")}</button>` : null}`;
255
+ } else {
256
+ const lines = Array.isArray(login.lines) ? login.lines : [];
257
+ body = html`${login.phase === "running" ? html`<${Running} login=${login} />`
258
+ : html`<p role="status" class=${login.ok ? "signin-ok" : "signin-message"}>${login.ok ? tn("signedIn", shownOf(login.backend, login.profile)) : tn("ended")}</p>`}
259
+ ${lines.length ? html`<ul class="signin-lines">${lines.map((l, i) => html`<li key=${i}>${l}</li>`)}</ul>` : null}`;
260
+ actions = html`<button type="button" class="btn" onClick=${close}>${tn("close")}</button>
261
+ ${login.phase === "running" ? html`<button type="button" class="btn btn-danger" disabled=${busy} onClick=${cancelRun}>${tn("cancelSignIn")}</button>` : null}`;
262
+ }
263
+ return html`<${Dialog} title=${tn("title", shown)} onClose=${close} busy=${busy} actions=${actions}>${body}</${Dialog}>`;
264
+ }
265
+
266
+ /** The line every admin page shows while a sign-in runs (the shell's banner slot). */
267
+ export function SignInLine() {
268
+ const { login } = useStore(signInStore);
269
+ if (!login || login.phase !== "running") return null;
270
+ return html`<div data-trust="status" class="conn op-line signin-line" role="status">
271
+ <span>${tn("running", shownOf(login.backend, login.profile), login.startedOn)}</span>
272
+ <button type="button" class="btn btn-sm" onClick=${() => openRunning(login)}>${tn("open")}</button></div>`;
273
+ }
274
+
275
+ const STATE_KEY = { usable: "stUsable", not_signed_in: "stNotSignedIn", not_installed: "stNotInstalled", too_old: "stTooOld", unknown: "stUnknown" };
276
+
277
+ /** Settings → Agents: each login on this machine, with Sign in where the dashboard can do it. */
278
+ export function SignInList() {
279
+ const { targets, loaded, login } = useStore(signInStore);
280
+ useEffect(() => { void refreshSignIn(); }, []);
281
+ if (!loaded || !targets.length) return null;
282
+ const running = login && login.phase === "running";
283
+ return html`<section class="s-group signin-list" aria-label=${tn("listTitle")}>
284
+ <div class="list-head"><span>${tn("listTitle")}</span></div>
285
+ <p class="sub">${tn("listHint")}</p>
286
+ ${targets.map((x) => html`<div key=${`${x.backend}:${x.profile || ""}`} class="s-row">
287
+ <span class="s-name">${shownOf(x.backend, x.profile)}</span>
288
+ <span class="tag">${tn(STATE_KEY[x.state] || "stUnknown")}</span>
289
+ <span class="s-br" aria-hidden="true"></span>
290
+ ${x.install ? html`<span class="s-meta"><code>${tn("install", x.install)}</code></span>` : null}
291
+ ${x.update ? html`<span class="s-meta"><code>${tn("update", x.update)}</code></span>` : null}
292
+ ${x.hostCommand ? html`<span class="s-meta"><code>${tn("onHost", x.hostCommand)}</code></span>` : null}
293
+ <span class="s-actions">${x.signIn ? html`<button type="button" class=${x.state === "not_signed_in" ? "btn btn-sm btn-primary" : "btn btn-sm"} disabled=${!!running}
294
+ onClick=${() => openSignIn(x)}>${x.state === "usable" ? tn("signInAgain") : tn("signIn")}</button>` : null}</span>
295
+ </div>`)}
296
+ </section>`;
297
+ }
@@ -9,10 +9,10 @@ import { navigate } from "/assets/app-nav.js";
9
9
  import { toast } from "/assets/ui-toast.js";
10
10
  import { setThemesShown, themesShown, themesStore } from "/assets/app-themes.js";
11
11
  import { setFollowsReducedMotion } from "/assets/fx-motion.js";
12
- import { getAppEffects } from "./app-effects.js";
12
+ import { getAppEffects, wakeEffects, effectsLoaded, onEffectsAwake } from "./effects-waker.js";
13
13
 
14
14
  register("chatFx", {
15
- en: { transport: "Off: the isolated effect frame could not start. Reload to try again.", enableHere: "Turn effects on here", playMotion: "Play effects anyway", leaveSafe: "Leave safe mode", viewerShow: "Show themes, effects and widgets here", clock: "Off: the page timing clock is unavailable. Reload to try again.", gatesUnknown: "Off: the playback conditions could not be verified.", resource: "Off: this effect could not be loaded or verified. Reload to try again.", frontQueue: "Waiting for a foreground slot.", consent: "This page has older playback information. Reload to use the isolated effect player.", previewMissing: "Off: the isolated effect frame is unavailable. Reload to try again.", unsupported: "Off: this browser lacks required Canvas Worker or layout support.", calibration: "Starting the effect.", baseline: "This page has older playback information. Reload to try again.", safetyUnknown: "Stopped: this device's safety history could not be verified. Reload to check it.", rawReason: "Playback blocked: {0}", missingRow: "Playback state is unavailable (runtime_unavailable).", region: "Off: this effect does not declare the chat region.", blocked: "Placed effects are blocked for this viewer:", deviceSetting: "Open device preferences", webSetting: "Open Web settings", reloadHint: "Reload page",
15
+ en: { stock: "Off: the page layout could not be verified ({0}). Reload and report this code if it persists.", transport: "Off: the isolated effect frame could not start. Reload to try again.", enableHere: "Turn effects on here", playMotion: "Play effects anyway", leaveSafe: "Leave safe mode", viewerShow: "Show themes, effects and widgets here", clock: "Off: the page timing clock is unavailable. Reload to try again.", gatesUnknown: "Off: the playback conditions could not be verified.", resource: "Off: this effect could not be loaded or verified. Reload to try again.", frontQueue: "Waiting for a foreground slot.", consent: "This page has older playback information. Reload to use the isolated effect player.", previewMissing: "Off: the isolated effect frame is unavailable. Reload to try again.", unsupported: "Off: this browser lacks required Canvas Worker or layout support.", calibration: "Starting the effect.", baseline: "This page has older playback information. Reload to try again.", safetyUnknown: "Stopped: this device's safety history could not be verified. Reload to check it.", rawReason: "Playback blocked: {0}", missingRow: "Playback state is unavailable (runtime_unavailable).", region: "Off: this effect does not declare the chat region.", blocked: "Placed effects are blocked for this viewer:", deviceSetting: "Open device preferences", webSetting: "Open Web settings", reloadHint: "Reload page",
16
16
  title: "Effects", loading: "Checking effects…", empty: "No effects in this chat.", failed: "Effects stopped because their resources could not be verified. Reload the page to try again.", reload: "Reload page", pause: "Pause", resume: "Resume", remove: "Remove from chat", removeFailed: "Could not remove this effect. Reload the page to check its state.", css: "Agent foreground effects are paused while your custom CSS is on or cannot be verified.", setting: "Open Web appearance settings", running: "Running", starting: "Starting", off: "Stopped", resumeFailed: "This effect cannot resume: the page or its safety history is not ready. Reload the page or choose another effect.", queued: "Waiting for a slot", unknown: "Playback is off or unavailable here.", budget: "Paused to protect page responsiveness. Resume keeps the three-pauses safety limit.", pauseHelp: "Resume keeps this device’s automatic-pause history and three-pause safety limit.", paused: "Paused", low: "Reduced quality",
17
17
  typing: "Waiting while you type — it plays when you leave the message box.", covered: "Waiting while a menu or panel covers the chat.",
18
18
  dialogOpen: "Paused while this dialog is open.", wasRunning: "Was running; paused while this dialog is open.", modal: "Waiting while a dialog is open.",
@@ -20,7 +20,7 @@ register("chatFx", {
20
20
  cssOff: "Off while your custom CSS is on.", reducedMotion: "Off: you chose to follow the system's reduced motion setting.", saveData: "This page has older playback information. Reload to try again.",
21
21
  hiddenTab: "Waiting until this tab is visible.", offscreen: "Waiting until the chat is on screen.",
22
22
  safeMode: "Off in safe mode.", publicLink: "Off on a public link.", disabled: "Effects are switched off." },
23
- "zh-TW": { transport: "已關閉:無法啟動隔離效果框架。請重新載入再試。", enableHere: "在這裡開啟效果", playMotion: "仍然播放效果", leaveSafe: "離開安全模式", viewerShow: "在這裡顯示主題、效果與小工具", clock: "已關閉:頁面計時無法使用。請重新載入再試。", gatesUnknown: "已關閉:無法確認播放條件。", resource: "已關閉:無法載入或驗證此效果。請重新載入再試。", frontQueue: "等待前景空位。", consent: "這個頁面的播放資訊已過期。請重新載入以使用隔離效果播放器。", previewMissing: "已關閉:隔離效果框架無法使用。請重新載入再試。", unsupported: "已關閉:這個瀏覽器缺少 Canvas Worker 或版面驗證支援。", calibration: "正在啟動效果。", baseline: "這個頁面的播放資訊已過期,請重新載入再試。", safetyUnknown: "已停止:無法確認這台裝置的安全紀錄。請重新載入確認。", rawReason: "播放受阻:{0}", missingRow: "無法取得播放狀態(runtime_unavailable)。", region: "已關閉:此效果未宣告聊天區域。", blocked: "放置的效果目前無法在這個畫面播放:", deviceSetting: "開啟裝置偏好設定", webSetting: "開啟網頁設定", reloadHint: "重新載入頁面",
23
+ "zh-TW": { stock: "已關閉:無法驗證頁面版面({0})。請重新載入;若持續發生,請回報此代碼。", transport: "已關閉:無法啟動隔離效果框架。請重新載入再試。", enableHere: "在這裡開啟效果", playMotion: "仍然播放效果", leaveSafe: "離開安全模式", viewerShow: "在這裡顯示主題、效果與小工具", clock: "已關閉:頁面計時無法使用。請重新載入再試。", gatesUnknown: "已關閉:無法確認播放條件。", resource: "已關閉:無法載入或驗證此效果。請重新載入再試。", frontQueue: "等待前景空位。", consent: "這個頁面的播放資訊已過期。請重新載入以使用隔離效果播放器。", previewMissing: "已關閉:隔離效果框架無法使用。請重新載入再試。", unsupported: "已關閉:這個瀏覽器缺少 Canvas Worker 或版面驗證支援。", calibration: "正在啟動效果。", baseline: "這個頁面的播放資訊已過期,請重新載入再試。", safetyUnknown: "已停止:無法確認這台裝置的安全紀錄。請重新載入確認。", rawReason: "播放受阻:{0}", missingRow: "無法取得播放狀態(runtime_unavailable)。", region: "已關閉:此效果未宣告聊天區域。", blocked: "放置的效果目前無法在這個畫面播放:", deviceSetting: "開啟裝置偏好設定", webSetting: "開啟網頁設定", reloadHint: "重新載入頁面",
24
24
  title: "效果", loading: "正在確認效果…", empty: "這個聊天沒有放置效果。", failed: "無法確認效果資源,已停止播放。重新載入頁面後再試。", reload: "重新載入頁面", pause: "暫停", resume: "恢復", remove: "從聊天移除", removeFailed: "無法移除效果。請重新載入頁面確認狀態。", css: "自訂 CSS 開啟或無法確認時,代理的前景效果會暫停。", setting: "開啟網頁外觀設定", running: "播放中", starting: "啟動中", off: "已停止", resumeFailed: "頁面或安全紀錄尚未就緒,無法恢復此效果。請重新載入頁面,或選擇其他效果。", queued: "等待空位", unknown: "這裡已關閉播放,或無法播放效果。", budget: "為維持頁面順暢,已暫停效果。恢復仍保留三次暫停的安全上限。", pauseHelp: "恢復仍保留這台裝置的自動暫停紀錄與三次暫停安全上限。", paused: "已暫停", low: "降低畫質",
25
25
  typing: "輸入時暫停,離開訊息輸入框就會播放。", covered: "選單或面板蓋住聊天時暫停。",
26
26
  dialogOpen: "開著這個對話框時暫停。", wasRunning: "原本在播放;開著這個對話框時暫停。", modal: "有對話框開著時暫停。",
@@ -43,12 +43,13 @@ const REASON_KEY = { __proto__: null, transport_unavailable: "chatFx.transport",
43
43
  /** `ownOpen`: this Effects dialog is open; `wasRunning`: the effect was running when it opened (shown as past, never as current). */
44
44
  export function effectRowText(row, { ownOpen = false, wasRunning = false, doc = typeof document === "undefined" ? null : document } = {}) {
45
45
  if (!row) return t("chatFx.missingRow");
46
+ if (typeof row.reason === "string" && row.reason !== "stock_overlay" && /^(stock_|trust_|geometry_)/.test(row.reason)) return t("chatFx.stock", row.reason.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 80));
46
47
  // The sticky history first (it is what Resume answers), then a pause, then what is playing or queued.
47
48
  if (row.reason === "safety_off" || row.reason === "interrupted") return t(REASON_KEY[row.reason]);
48
49
  if (row.reason === "paused" || row.reason === "host_budget") return t("chatFx.paused");
49
50
  if (REASON_KEY[row.reason]) return t(REASON_KEY[row.reason]);
50
51
  if (row.reason != null && !["stock_overlay", "modal", "frame_limit"].includes(row.reason))
51
- return t("chatFx.rawReason", typeof row.reason === "string" ? row.reason.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 80) : "unknown");
52
+ return t("chatFx.rawReason", typeof row.reason === "string" ? row.reason.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 80) : "invalid_reason_type");
52
53
  if (row.phase === "running") return t("chatFx.running");
53
54
  if (row.phase) return t("chatFx.starting");
54
55
  if (row.verdict === "queued") return t("chatFx.queued");
@@ -57,7 +58,7 @@ export function effectRowText(row, { ownOpen = false, wasRunning = false, doc =
57
58
  if (row.reason === "modal") return t("chatFx.modal");
58
59
  return t("chatFx.covered");
59
60
  }
60
- return t("chatFx.rawReason", typeof row.reason === "string" ? row.reason.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 80) : "unknown");
61
+ return t("chatFx.rawReason", typeof row.reason === "string" ? row.reason.replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 80) : "invalid_reason_type");
61
62
  }
62
63
 
63
64
  /** Fixed local actions: no server/Worker-provided destination or raw reason in a URL. */
@@ -77,8 +78,13 @@ function ReasonAction({ reason, onClose = () => {} }) {
77
78
  }
78
79
 
79
80
  const NO_PLAYBACK = () => {};
80
- export function ChatEffects({ name, lease, element, store, open, onClose, onPlayback = NO_PLAYBACK }) {
81
+ export function ChatEffects({ name, lease, element, store, open, onClose, onPlayback = NO_PLAYBACK, active = true }) {
81
82
  const cssLife = useStore(ownerCssLifecycle);
83
+ // #2193: `active` — this chat has placements (its status row says so). While the runtime sleeps, a chat with none
84
+ // attaches and reads nothing (the dialog says "No effects in this chat"); one with some wakes it and attaches once it
85
+ // runs. Once it runs (woken by anything — a Try card needs its chat attached), every chat attaches as before.
86
+ const [awake, setAwake] = useState(() => getAppEffects() !== null || effectsLoaded());
87
+ useEffect(() => (awake ? undefined : onEffectsAwake(() => setAwake(true))), [awake]);
82
88
  useStore(themesStore); // Viewer-local off/on is visible immediately, independent of runtime callbacks.
83
89
  // Which effects were running just before this dialog opened ("was running" is said in the past, never shown as
84
90
  // current). The ⋯ menu that opens it is a barrier too, so "just before" is within RECENT_MS of the observed stop.
@@ -99,6 +105,8 @@ export function ChatEffects({ name, lease, element, store, open, onClose, onPlay
99
105
  lease.hold(cleanup);
100
106
  try {
101
107
  setBusy(false); onClose(); setCanWrite(false); setState(null);
108
+ if (!active && !awake) { setState({ error: null, rows: [], effects: [], loading: false }); return cleanup; }
109
+ if (!awake) { void wakeEffects(); return cleanup; } // "Checking effects…" until it runs
102
110
  const host = window, owner = getAppEffects(host);
103
111
  const current = () => live && lease.current();
104
112
  if (!owner) { setState({ error: null, rows: [], effects: [], unavailable: true, reason: typeof host.OffscreenCanvas !== "function" || typeof host.Worker !== "function" ? "unsupported_host" : "runtime_unavailable" }); return cleanup; }
@@ -131,7 +139,7 @@ export function ChatEffects({ name, lease, element, store, open, onClose, onPlay
131
139
  if (lease.current()) setState({ error: "runtime_unavailable", rows: [], effects: [] });
132
140
  return cleanup;
133
141
  }
134
- }, [name, lease]);
142
+ }, [name, lease, active, awake]);
135
143
  const rows = state?.rows ?? [], effects = state?.effects ?? [];
136
144
  if (open && !wasOpen.current) {
137
145
  const now = performance.now();
@@ -0,0 +1,176 @@
1
+ // #2272: a chat message's own actions, beyond the hover strip — the message menu (right-click, long-press on a phone),
2
+ // swipe left to reply (as in Telegram), and R on a focused message. One install per thread element.
3
+ //
4
+ // - Right-click on a message opens Reply / Copy text / Copy link. Shift+right-click, a right-click with text selected,
5
+ // or one on a link, an image or a field keeps the browser's own menu.
6
+ // - A long press (500 ms without moving) opens the same menu; the click and the browser menu it would also cause are
7
+ // swallowed.
8
+ // - Swipe left on a message: it follows the finger (up to 64 px); let go past 56 px and it is a reply. A mostly
9
+ // vertical move is scrolling, never a reply. A swipe right is the phone drawer's (app-swipe.js), on a message too: the
10
+ // two never fight.
11
+ // - R (no modifier) on a focused message replies; ↑/↓ move to the message before or after (one message is in the Tab
12
+ // order); Escape closes the menu.
13
+
14
+ const LONG_PRESS_MS = 500, MOVE_TOLERANCE = 10, SWIPE_REPLY_PX = 56, SWIPE_MAX_PX = 64;
15
+
16
+ /** The message element an event is on (a person's or an agent's message of this thread), or null. */
17
+ function messageEl(list, target) {
18
+ const el = target && target.closest ? target.closest(".msg[data-key]") : null;
19
+ return el && list.contains(el) ? el : null;
20
+ }
21
+ /** The browser's own menu stays for: Shift, selected text, a link, an image, a field, code. */
22
+ function keepsNativeMenu(e, doc) {
23
+ if (e.shiftKey) return true;
24
+ const sel = doc.getSelection ? doc.getSelection() : null;
25
+ if (sel && !sel.isCollapsed && String(sel).trim()) return true;
26
+ return !!(e.target && e.target.closest && e.target.closest("a[href], img, video, input, textarea, select, pre, code, [contenteditable='true']"));
27
+ }
28
+
29
+ /**
30
+ * Install the gestures on `list` (the thread element). `deps`:
31
+ * messageOf(key) → the row; reply(row); copyText(text) → Promise<boolean>; linkOf(row) → string; notice(text);
32
+ * canReply() → boolean (false: no Reply — a page that cannot send); t(key).
33
+ * Returns a function that removes everything (and closes an open menu).
34
+ */
35
+ export function installMessageActions(list, deps) {
36
+ const doc = list.ownerDocument, win = doc.defaultView;
37
+ let menu = null, press = null, swipe = null, swallowClick = false;
38
+
39
+ function closeMenu() {
40
+ if (!menu) return;
41
+ menu.remove(); menu = null;
42
+ doc.removeEventListener("pointerdown", outside, true);
43
+ doc.removeEventListener("keydown", onMenuKey, true);
44
+ win?.removeEventListener("scroll", closeMenu, true);
45
+ win?.removeEventListener("blur", closeMenu);
46
+ }
47
+ function outside(e) { if (menu && !menu.contains(e.target)) closeMenu(); }
48
+ function onMenuKey(e) {
49
+ if (!menu) return;
50
+ if (e.key === "Escape") { e.preventDefault(); e.stopPropagation(); closeMenu(); return; }
51
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
52
+ e.preventDefault();
53
+ const items = [...menu.querySelectorAll("button")], i = items.indexOf(doc.activeElement);
54
+ items[(i + (e.key === "ArrowDown" ? 1 : items.length - 1)) % items.length]?.focus();
55
+ }
56
+ }
57
+ /** The message menu at (x, y), within the window; focus on its first item. */
58
+ function openMenu(row, x, y) {
59
+ closeMenu();
60
+ const items = [];
61
+ if (deps.canReply?.() !== false) items.push(["reply", deps.t("chat.reply"), () => deps.reply(row)]);
62
+ items.push(["copyText", deps.t("chat.copyText"), async () => { const ok = await deps.copyText(String(row.click?.label ?? row.text ?? "")); deps.notice(deps.t(ok ? "chat.copied" : "chat.copyFailed"), ok); }]);
63
+ items.push(["copyLink", deps.t("chat.copyLink"), async () => { const ok = await deps.copyText(deps.linkOf(row)); deps.notice(deps.t(ok ? "chat.copied" : "chat.copyFailed"), ok); }]);
64
+ menu = doc.createElement("div");
65
+ menu.className = "msg-menu";
66
+ menu.setAttribute("role", "menu");
67
+ menu.setAttribute("aria-label", deps.t("chat.msgMenu"));
68
+ menu.setAttribute("data-trust", "menu");
69
+ for (const [id, label, run] of items) {
70
+ const b = doc.createElement("button");
71
+ b.type = "button"; b.className = "menu-item"; b.setAttribute("role", "menuitem"); b.dataset.item = id; b.textContent = label;
72
+ b.addEventListener("click", () => { closeMenu(); void run(); });
73
+ menu.append(b);
74
+ }
75
+ doc.body.append(menu);
76
+ const w = win?.innerWidth ?? 1024, h = win?.innerHeight ?? 768, r = menu.getBoundingClientRect();
77
+ menu.style.left = `${Math.max(4, Math.min(x, w - r.width - 4))}px`;
78
+ menu.style.top = `${Math.max(4, Math.min(y, h - r.height - 4))}px`;
79
+ doc.addEventListener("pointerdown", outside, true);
80
+ doc.addEventListener("keydown", onMenuKey, true);
81
+ win?.addEventListener("scroll", closeMenu, true);
82
+ win?.addEventListener("blur", closeMenu);
83
+ menu.querySelector("button")?.focus();
84
+ }
85
+
86
+ function onContextMenu(e) {
87
+ if (swallowClick) { e.preventDefault(); return; } // the long press already opened ours
88
+ cancelPress(); // Android's long press fires this itself: one menu
89
+ const el = messageEl(list, e.target);
90
+ if (!el || keepsNativeMenu(e, doc)) return;
91
+ const row = deps.messageOf(el.dataset.key);
92
+ if (!row) return;
93
+ e.preventDefault();
94
+ openMenu(row, e.clientX, e.clientY);
95
+ }
96
+ function onKeyDown(e) {
97
+ // ↑/↓ on a focused message: the one before or after it (one message is in the Tab order: the thread's rove()).
98
+ if ((e.key === "ArrowUp" || e.key === "ArrowDown") && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey
99
+ && e.target && e.target.matches && e.target.matches(".msg[data-key]") && list.contains(e.target)) {
100
+ const all = [...list.querySelectorAll(".msg[data-key]")], i = all.indexOf(e.target);
101
+ const to = all[i + (e.key === "ArrowDown" ? 1 : -1)];
102
+ if (to) { e.preventDefault(); deps.rove?.(to.dataset.key); to.focus(); to.scrollIntoView?.({ block: "nearest" }); }
103
+ return;
104
+ }
105
+ if (e.key !== "r" && e.key !== "R") return;
106
+ if (e.ctrlKey || e.metaKey || e.altKey || deps.canReply?.() === false) return;
107
+ const el = e.target && e.target.matches && e.target.matches(".msg[data-key]") && list.contains(e.target) ? e.target : null;
108
+ const row = el ? deps.messageOf(el.dataset.key) : null;
109
+ if (!row) return;
110
+ e.preventDefault();
111
+ deps.reply(row);
112
+ }
113
+
114
+ function onTouchStart(e) {
115
+ if (e.touches.length !== 1) { cancelPress(); cancelSwipe(); return; }
116
+ const el = messageEl(list, e.target);
117
+ if (!el) return;
118
+ const t0 = e.touches[0];
119
+ const native = keepsNativeMenu({ target: e.target, shiftKey: false }, doc); // a link, an image, code: the browser's
120
+ press = native ? null : { el, x: t0.clientX, y: t0.clientY, timer: setTimeout(() => {
121
+ const row = deps.messageOf(el.dataset.key);
122
+ press = null; cancelSwipe();
123
+ if (!row) return;
124
+ swallowClick = true; setTimeout(() => { swallowClick = false; }, 700);
125
+ openMenu(row, t0.clientX, t0.clientY);
126
+ }, LONG_PRESS_MS) };
127
+ swipe = deps.canReply?.() === false || native ? null : { el, x: t0.clientX, y: t0.clientY, dx: 0, locked: null };
128
+ }
129
+ function onTouchMove(e) {
130
+ const p = e.touches[0];
131
+ if (press && (Math.abs(p.clientX - press.x) > MOVE_TOLERANCE || Math.abs(p.clientY - press.y) > MOVE_TOLERANCE)) cancelPress();
132
+ if (!swipe) return;
133
+ const dx = p.clientX - swipe.x, dy = p.clientY - swipe.y;
134
+ if (swipe.locked === null && (Math.abs(dx) > MOVE_TOLERANCE || Math.abs(dy) > MOVE_TOLERANCE)) swipe.locked = dx < 0 && Math.abs(dy) < -dx / 2 ? "x" : "no";
135
+ if (swipe.locked !== "x") return;
136
+ swipe.dx = Math.max(0, Math.min(-dx, SWIPE_MAX_PX)); // how far left, as a positive distance
137
+ swipe.el.style.transform = `translateX(${-swipe.dx}px)`;
138
+ swipe.el.classList.toggle("swipe-ready", swipe.dx >= SWIPE_REPLY_PX);
139
+ }
140
+ function onTouchEnd() {
141
+ cancelPress();
142
+ if (!swipe) return;
143
+ const { el, dx, locked } = swipe;
144
+ cancelSwipe();
145
+ if (locked === "x" && dx >= SWIPE_REPLY_PX) { const row = deps.messageOf(el.dataset.key); if (row) deps.reply(row); }
146
+ }
147
+ function cancelPress() { if (press) { clearTimeout(press.timer); press = null; } }
148
+ function cancelSwipe() {
149
+ if (!swipe) return;
150
+ swipe.el.style.transform = ""; swipe.el.classList.remove("swipe-ready");
151
+ swipe = null;
152
+ }
153
+ function onClickCapture(e) { if (swallowClick) { e.preventDefault(); e.stopPropagation(); } }
154
+
155
+ // A message focused by a click or a tap becomes the one Tab comes back to.
156
+ function onFocusIn(e) { const el = e.target && e.target.matches && e.target.matches(".msg[data-key]") ? e.target : null; if (el && list.contains(el)) deps.rove?.(el.dataset.key); }
157
+ list.addEventListener("focusin", onFocusIn);
158
+ list.addEventListener("contextmenu", onContextMenu);
159
+ list.addEventListener("keydown", onKeyDown);
160
+ list.addEventListener("touchstart", onTouchStart, { passive: true });
161
+ list.addEventListener("touchmove", onTouchMove, { passive: true });
162
+ list.addEventListener("touchend", onTouchEnd, { passive: true });
163
+ list.addEventListener("touchcancel", onTouchEnd, { passive: true });
164
+ list.addEventListener("click", onClickCapture, true);
165
+ return () => {
166
+ closeMenu(); cancelPress(); cancelSwipe();
167
+ list.removeEventListener("focusin", onFocusIn);
168
+ list.removeEventListener("contextmenu", onContextMenu);
169
+ list.removeEventListener("keydown", onKeyDown);
170
+ list.removeEventListener("touchstart", onTouchStart);
171
+ list.removeEventListener("touchmove", onTouchMove);
172
+ list.removeEventListener("touchend", onTouchEnd);
173
+ list.removeEventListener("touchcancel", onTouchEnd);
174
+ list.removeEventListener("click", onClickCapture, true);
175
+ };
176
+ }