@songsid/agend 2.3.1 → 2.3.2-beta.10

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 (338) hide show
  1. package/THIRD_PARTY_NOTICES.md +40 -0
  2. package/dist/agent-cli.js +21 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.js +5 -0
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/antigravity-usage-scan.d.ts +58 -0
  7. package/dist/antigravity-usage-scan.js +257 -0
  8. package/dist/antigravity-usage-scan.js.map +1 -0
  9. package/dist/antigravity-usage-worker.d.ts +1 -0
  10. package/dist/antigravity-usage-worker.js +10 -0
  11. package/dist/antigravity-usage-worker.js.map +1 -0
  12. package/dist/auth-api.js +4 -0
  13. package/dist/auth-api.js.map +1 -1
  14. package/dist/authority/authority-state.d.ts +4 -0
  15. package/dist/authority/authority-state.js +16 -10
  16. package/dist/authority/authority-state.js.map +1 -1
  17. package/dist/authority/session-authorizations.d.ts +7 -1
  18. package/dist/authority/session-authorizations.js +6 -4
  19. package/dist/authority/session-authorizations.js.map +1 -1
  20. package/dist/authority/web-authority.d.ts +19 -6
  21. package/dist/authority/web-authority.js +22 -8
  22. package/dist/authority/web-authority.js.map +1 -1
  23. package/dist/backend/kiro-identity.d.ts +64 -0
  24. package/dist/backend/kiro-identity.js +101 -0
  25. package/dist/backend/kiro-identity.js.map +1 -1
  26. package/dist/backend/kiro-retired-model.d.ts +62 -0
  27. package/dist/backend/kiro-retired-model.js +160 -0
  28. package/dist/backend/kiro-retired-model.js.map +1 -0
  29. package/dist/backend/kiro.d.ts +71 -2
  30. package/dist/backend/kiro.js +352 -11
  31. package/dist/backend/kiro.js.map +1 -1
  32. package/dist/backend/types.d.ts +59 -0
  33. package/dist/backend/types.js.map +1 -1
  34. package/dist/backend-signin-guide.d.ts +1 -0
  35. package/dist/backend-signin-guide.js +9 -0
  36. package/dist/backend-signin-guide.js.map +1 -0
  37. package/dist/backend-signin-pending.d.ts +10 -0
  38. package/dist/backend-signin-pending.js +44 -0
  39. package/dist/backend-signin-pending.js.map +1 -0
  40. package/dist/browser-backend-signins.d.ts +56 -0
  41. package/dist/browser-backend-signins.js +189 -0
  42. package/dist/browser-backend-signins.js.map +1 -0
  43. package/dist/cache-ledger.d.ts +38 -2
  44. package/dist/cache-ledger.js +133 -8
  45. package/dist/cache-ledger.js.map +1 -1
  46. package/dist/cache-prices.d.ts +2 -1
  47. package/dist/cache-prices.js +5 -2
  48. package/dist/cache-prices.js.map +1 -1
  49. package/dist/cache-service.d.ts +68 -0
  50. package/dist/cache-service.js +355 -13
  51. package/dist/cache-service.js.map +1 -1
  52. package/dist/channel/adapters/discord.d.ts +13 -0
  53. package/dist/channel/adapters/discord.js +103 -16
  54. package/dist/channel/adapters/discord.js.map +1 -1
  55. package/dist/channel/mcp-tools.js +34 -7
  56. package/dist/channel/mcp-tools.js.map +1 -1
  57. package/dist/channel/tool-router.js +2 -1
  58. package/dist/channel/tool-router.js.map +1 -1
  59. package/dist/channel/types.d.ts +11 -0
  60. package/dist/classic-channel-manager.d.ts +11 -0
  61. package/dist/classic-channel-manager.js +39 -1
  62. package/dist/classic-channel-manager.js.map +1 -1
  63. package/dist/cli.js +21 -2
  64. package/dist/cli.js.map +1 -1
  65. package/dist/config-validator.d.ts +7 -1
  66. package/dist/config-validator.js +92 -12
  67. package/dist/config-validator.js.map +1 -1
  68. package/dist/config.d.ts +19 -0
  69. package/dist/config.js +31 -1
  70. package/dist/config.js.map +1 -1
  71. package/dist/cpu-quota.d.ts +23 -0
  72. package/dist/cpu-quota.js +86 -0
  73. package/dist/cpu-quota.js.map +1 -0
  74. package/dist/daemon.d.ts +57 -3
  75. package/dist/daemon.js +330 -50
  76. package/dist/daemon.js.map +1 -1
  77. package/dist/dashboard-permissions.d.ts +20 -6
  78. package/dist/dashboard-permissions.js +58 -9
  79. package/dist/dashboard-permissions.js.map +1 -1
  80. package/dist/delivery-outbox.d.ts +12 -1
  81. package/dist/delivery-outbox.js +67 -15
  82. package/dist/delivery-outbox.js.map +1 -1
  83. package/dist/doctor.d.ts +3 -0
  84. package/dist/doctor.js +11 -1
  85. package/dist/doctor.js.map +1 -1
  86. package/dist/event-log.d.ts +5 -0
  87. package/dist/event-log.js +13 -0
  88. package/dist/event-log.js.map +1 -1
  89. package/dist/fleet-manager.d.ts +212 -0
  90. package/dist/fleet-manager.js +914 -111
  91. package/dist/fleet-manager.js.map +1 -1
  92. package/dist/fleet-process-handlers.d.ts +1 -0
  93. package/dist/fleet-process-handlers.js +9 -1
  94. package/dist/fleet-process-handlers.js.map +1 -1
  95. package/dist/forged-envelope-scan.d.ts +9 -0
  96. package/dist/forged-envelope-scan.js +30 -5
  97. package/dist/forged-envelope-scan.js.map +1 -1
  98. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
  99. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +14 -1
  100. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +28 -5
  101. package/dist/general-knowledge/skills/web-appearance/SKILL.md +31 -8
  102. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +138 -59
  103. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +145 -61
  104. package/dist/guest-seen-people.d.ts +38 -0
  105. package/dist/guest-seen-people.js +78 -0
  106. package/dist/guest-seen-people.js.map +1 -0
  107. package/dist/instance-config-impact.js +14 -6
  108. package/dist/instance-config-impact.js.map +1 -1
  109. package/dist/instance-lifecycle.d.ts +20 -0
  110. package/dist/instance-lifecycle.js +71 -13
  111. package/dist/instance-lifecycle.js.map +1 -1
  112. package/dist/kiro-db-reader.d.ts +5 -0
  113. package/dist/kiro-db-reader.js +18 -0
  114. package/dist/kiro-db-reader.js.map +1 -1
  115. package/dist/kiro-engine-status.d.ts +2 -0
  116. package/dist/kiro-engine-status.js +9 -0
  117. package/dist/kiro-engine-status.js.map +1 -1
  118. package/dist/kiro-migrate.d.ts +49 -0
  119. package/dist/kiro-migrate.js +105 -0
  120. package/dist/kiro-migrate.js.map +1 -0
  121. package/dist/kiro-transcript-lane.d.ts +2 -0
  122. package/dist/kiro-transcript-lane.js.map +1 -1
  123. package/dist/kiro-transcript-worker.js +1 -0
  124. package/dist/kiro-transcript-worker.js.map +1 -1
  125. package/dist/kiro-tui-forensic.d.ts +7 -0
  126. package/dist/kiro-tui-forensic.js +110 -0
  127. package/dist/kiro-tui-forensic.js.map +1 -0
  128. package/dist/kiro-usage-run.d.ts +7 -0
  129. package/dist/kiro-usage-run.js +39 -0
  130. package/dist/kiro-usage-run.js.map +1 -0
  131. package/dist/kiro-usage-scan.d.ts +49 -0
  132. package/dist/kiro-usage-scan.js +223 -0
  133. package/dist/kiro-usage-scan.js.map +1 -0
  134. package/dist/kiro-usage-worker.d.ts +1 -0
  135. package/dist/kiro-usage-worker.js +10 -0
  136. package/dist/kiro-usage-worker.js.map +1 -0
  137. package/dist/kiro-usage.d.ts +58 -0
  138. package/dist/kiro-usage.js +310 -0
  139. package/dist/kiro-usage.js.map +1 -0
  140. package/dist/locale.js +120 -12
  141. package/dist/locale.js.map +1 -1
  142. package/dist/log-service.js +1 -1
  143. package/dist/log-service.js.map +1 -1
  144. package/dist/login-url.d.ts +4 -0
  145. package/dist/login-url.js +22 -0
  146. package/dist/login-url.js.map +1 -0
  147. package/dist/mac-auto-restore.d.ts +117 -0
  148. package/dist/mac-auto-restore.js +294 -0
  149. package/dist/mac-auto-restore.js.map +1 -0
  150. package/dist/needs-you-hub.d.ts +2 -1
  151. package/dist/needs-you-hub.js +1 -1
  152. package/dist/needs-you-hub.js.map +1 -1
  153. package/dist/needs-you.d.ts +8 -2
  154. package/dist/needs-you.js +6 -0
  155. package/dist/needs-you.js.map +1 -1
  156. package/dist/notice-delivery.d.ts +16 -0
  157. package/dist/notice-delivery.js +35 -0
  158. package/dist/notice-delivery.js.map +1 -0
  159. package/dist/office-share-page.d.ts +16 -0
  160. package/dist/office-share-page.js +85 -0
  161. package/dist/office-share-page.js.map +1 -0
  162. package/dist/office-share-service.d.ts +91 -0
  163. package/dist/office-share-service.js +176 -0
  164. package/dist/office-share-service.js.map +1 -0
  165. package/dist/office-share.d.ts +258 -0
  166. package/dist/office-share.js +549 -0
  167. package/dist/office-share.js.map +1 -0
  168. package/dist/opencode-usage-scan.d.ts +28 -0
  169. package/dist/opencode-usage-scan.js +92 -0
  170. package/dist/opencode-usage-scan.js.map +1 -0
  171. package/dist/opencode-usage-worker.d.ts +1 -0
  172. package/dist/opencode-usage-worker.js +10 -0
  173. package/dist/opencode-usage-worker.js.map +1 -0
  174. package/dist/outbound-handlers.js +22 -2
  175. package/dist/outbound-handlers.js.map +1 -1
  176. package/dist/outbound-schemas.d.ts +28 -2
  177. package/dist/outbound-schemas.js +29 -2
  178. package/dist/outbound-schemas.js.map +1 -1
  179. package/dist/public-web-gateway.js +16 -2
  180. package/dist/public-web-gateway.js.map +1 -1
  181. package/dist/quickstart-api.js +13 -2
  182. package/dist/quickstart-api.js.map +1 -1
  183. package/dist/quickstart.js +2 -1
  184. package/dist/quickstart.js.map +1 -1
  185. package/dist/remote-card-answer.d.ts +83 -0
  186. package/dist/remote-card-answer.js +208 -0
  187. package/dist/remote-card-answer.js.map +1 -0
  188. package/dist/reply-triggers.d.ts +2 -0
  189. package/dist/reply-triggers.js +3 -0
  190. package/dist/reply-triggers.js.map +1 -0
  191. package/dist/settings-api.d.ts +28 -0
  192. package/dist/settings-api.js +148 -17
  193. package/dist/settings-api.js.map +1 -1
  194. package/dist/settings-change.js +54 -17
  195. package/dist/settings-change.js.map +1 -1
  196. package/dist/settings-effect.js +12 -3
  197. package/dist/settings-effect.js.map +1 -1
  198. package/dist/settings-instance-patch.js +4 -1
  199. package/dist/settings-instance-patch.js.map +1 -1
  200. package/dist/setup-form.d.ts +1 -1
  201. package/dist/setup-form.js +55 -6
  202. package/dist/setup-form.js.map +1 -1
  203. package/dist/setup-host.d.ts +9 -0
  204. package/dist/setup-host.js +127 -6
  205. package/dist/setup-host.js.map +1 -1
  206. package/dist/setup-signin-assets.d.ts +2 -0
  207. package/dist/setup-signin-assets.js +6 -0
  208. package/dist/setup-signin-assets.js.map +1 -0
  209. package/dist/setup-wizard.js +2 -0
  210. package/dist/setup-wizard.js.map +1 -1
  211. package/dist/start-attempt.d.ts +9 -5
  212. package/dist/start-attempt.js +27 -8
  213. package/dist/start-attempt.js.map +1 -1
  214. package/dist/start-failure-chat.d.ts +4 -0
  215. package/dist/start-failure-chat.js +23 -6
  216. package/dist/start-failure-chat.js.map +1 -1
  217. package/dist/start-failure-notice.d.ts +4 -0
  218. package/dist/start-failure-notice.js +8 -0
  219. package/dist/start-failure-notice.js.map +1 -1
  220. package/dist/start-failure.d.ts +25 -0
  221. package/dist/start-failure.js +75 -2
  222. package/dist/start-failure.js.map +1 -1
  223. package/dist/structured-signin-transport.d.ts +8 -0
  224. package/dist/structured-signin-transport.js +79 -0
  225. package/dist/structured-signin-transport.js.map +1 -0
  226. package/dist/structured-signin.d.ts +131 -0
  227. package/dist/structured-signin.js +388 -0
  228. package/dist/structured-signin.js.map +1 -0
  229. package/dist/tool-permissions.js +12 -0
  230. package/dist/tool-permissions.js.map +1 -1
  231. package/dist/topic-commands.js +6 -2
  232. package/dist/topic-commands.js.map +1 -1
  233. package/dist/transcript-sources.d.ts +26 -2
  234. package/dist/transcript-sources.js +103 -40
  235. package/dist/transcript-sources.js.map +1 -1
  236. package/dist/turn-reply-guard.d.ts +25 -0
  237. package/dist/turn-reply-guard.js +111 -12
  238. package/dist/turn-reply-guard.js.map +1 -1
  239. package/dist/types.d.ts +46 -9
  240. package/dist/ui/backend-signin.js +68 -12
  241. package/dist/ui/chat-ambient.js +1 -1
  242. package/dist/ui/chat-effects.js +4 -4
  243. package/dist/ui/chat-render.js +5 -2
  244. package/dist/ui/chat-strings.js +4 -4
  245. package/dist/ui/chat-thread.js +2 -2
  246. package/dist/ui/first-run.js +2 -2
  247. package/dist/ui/fleet-canvas-view.js +114 -0
  248. package/dist/ui/fleet-canvas.js +15 -77
  249. package/dist/ui/fleet-office-editor.js +94 -14
  250. package/dist/ui/fleet-office-layout.js +235 -0
  251. package/dist/ui/fleet-office-model.js +12 -6
  252. package/dist/ui/fleet-office-overview.js +167 -0
  253. package/dist/ui/fleet-office-pack.d.ts +44 -0
  254. package/dist/ui/fleet-office-pack.js +352 -37
  255. package/dist/ui/fleet-office-skin.js +220 -36
  256. package/dist/ui/fleet-office-store.js +112 -7
  257. package/dist/ui/fleet-office-view.js +155 -0
  258. package/dist/ui/fleet-office-zones.js +264 -42
  259. package/dist/ui/fleet-office.js +957 -160
  260. package/dist/ui/fleet-usage.js +26 -21
  261. package/dist/ui/office-share-dialog.js +145 -0
  262. package/dist/ui/office-share-page.js +164 -0
  263. package/dist/ui/panel-chat.js +9 -2
  264. package/dist/ui/panel-details.js +2 -2
  265. package/dist/ui/panel-fleet.js +11 -77
  266. package/dist/ui/panel-log.js +4 -4
  267. package/dist/ui/panel-needs.js +4 -4
  268. package/dist/ui/panel-settings.js +608 -167
  269. package/dist/ui/search-dialog.js +26 -7
  270. package/dist/ui/settings-appearance.js +82 -29
  271. package/dist/ui/settings-apply.js +42 -7
  272. package/dist/ui/settings-dialogs.js +76 -23
  273. package/dist/ui/settings-draft.js +51 -0
  274. package/dist/ui/settings-guests.js +255 -79
  275. package/dist/ui/settings-learn.js +2 -2
  276. package/dist/ui/settings-model.js +16 -6
  277. package/dist/ui/settings-registry.js +146 -0
  278. package/dist/ui/settings-strings.js +116 -44
  279. package/dist/ui/settings-web-authority.js +34 -23
  280. package/dist/ui/shared/app-i18n.js +18 -2
  281. package/dist/ui/shared/app-nav.js +10 -5
  282. package/dist/ui/shared/app-prefs.js +80 -2
  283. package/dist/ui/shared/app-route.js +39 -5
  284. package/dist/ui/shared/app-shell.js +73 -10
  285. package/dist/ui/shared/app-stream.js +3 -1
  286. package/dist/ui/shared/app.css +307 -17
  287. package/dist/ui/shared/app.js +3 -0
  288. package/dist/ui/shared/effect-stock-trust.js +1 -1
  289. package/dist/ui/shared/identity-color.js +4 -4
  290. package/dist/ui/shared/office/cozy.png +0 -0
  291. package/dist/ui/shared/side-panel.js +95 -0
  292. package/dist/ui/shared/signin.js +2 -2
  293. package/dist/ui/shared/ui-dialog.js +6 -1
  294. package/dist/ui/shared/ui-icons.js +2 -0
  295. package/dist/ui/shared/web-authorize.js +13 -12
  296. package/dist/ui/structured-signin.js +115 -0
  297. package/dist/usage-report.d.ts +20 -0
  298. package/dist/usage-report.js +54 -17
  299. package/dist/usage-report.js.map +1 -1
  300. package/dist/usage-rollup.d.ts +9 -1
  301. package/dist/usage-rollup.js +20 -4
  302. package/dist/usage-rollup.js.map +1 -1
  303. package/dist/web-api.d.ts +26 -2
  304. package/dist/web-api.js +361 -5
  305. package/dist/web-api.js.map +1 -1
  306. package/dist/web-auth.js +8 -2
  307. package/dist/web-auth.js.map +1 -1
  308. package/dist/web-backend-login.d.ts +1 -7
  309. package/dist/web-backend-login.js +2 -24
  310. package/dist/web-backend-login.js.map +1 -1
  311. package/dist/web-experimental.d.ts +1 -1
  312. package/dist/web-experimental.js +1 -1
  313. package/dist/web-experimental.js.map +1 -1
  314. package/dist/web-mod-agent.js +2 -2
  315. package/dist/web-mod-agent.js.map +1 -1
  316. package/dist/web-office-acts.d.ts +173 -0
  317. package/dist/web-office-acts.js +285 -0
  318. package/dist/web-office-acts.js.map +1 -0
  319. package/dist/web-office-skins.d.ts +109 -0
  320. package/dist/web-office-skins.js +299 -0
  321. package/dist/web-office-skins.js.map +1 -0
  322. package/dist/web-office-store.d.ts +8 -2
  323. package/dist/web-office-store.js +77 -14
  324. package/dist/web-office-store.js.map +1 -1
  325. package/dist/web-settings-patch.d.ts +8 -1
  326. package/dist/web-settings-patch.js +65 -5
  327. package/dist/web-settings-patch.js.map +1 -1
  328. package/dist/web-shell-routes.d.ts +4 -2
  329. package/dist/web-shell-routes.js +17 -7
  330. package/dist/web-shell-routes.js.map +1 -1
  331. package/dist/working-recovery.d.ts +104 -0
  332. package/dist/working-recovery.js +298 -0
  333. package/dist/working-recovery.js.map +1 -0
  334. package/dist/working-state-journal.d.ts +5 -1
  335. package/dist/working-state-journal.js +31 -3
  336. package/dist/working-state-journal.js.map +1 -1
  337. package/package.json +3 -2
  338. package/templates/windows-shortcuts.ps1 +155 -140
@@ -1,3 +1,34 @@
1
+ /**
2
+ * #2544: only a person waiting on a channel answer arms the reply-completion
3
+ * guard. Schedules (silent or not), cross-instance traffic, and AgEnD system
4
+ * notices must not expect a reply to a person.
5
+ */
6
+ export function turnExpectsPersonReply(meta) {
7
+ if (meta.from_instance)
8
+ return false;
9
+ const source = meta.source ?? "";
10
+ if (source === "agend-system" || source === "schedule")
11
+ return false;
12
+ if (meta.user === "scheduler")
13
+ return false;
14
+ if (!meta.chat_id && source !== "web")
15
+ return false;
16
+ return true;
17
+ }
18
+ /** Short, stable diagnostic summary for daemon.log and the web Log; never channel text. */
19
+ export function formatReplyDropDetection(turn, reason) {
20
+ const bits = [reason, turn.replyDelivered ? "reply-delivered" : "no-adapter-confirmed-reply"];
21
+ if (turn.replyAttempted)
22
+ bits.push("reply-attempted");
23
+ if (turn.completionDelivered)
24
+ bits.push("completion-delivered");
25
+ if (turn.target.chatId)
26
+ bits.push(`chat=${turn.target.chatId}`);
27
+ if (turn.target.threadId)
28
+ bits.push(`thread=${turn.target.threadId}`);
29
+ return bits.join(", ");
30
+ }
31
+ const PRE_ARM_GENERATION = 0;
1
32
  /**
2
33
  * Generation-scoped evidence for one human-facing turn (or a batch of messages
3
34
  * delivered into the same busy interval). A tool invocation is only an
@@ -15,6 +46,12 @@ export class TurnReplyGuard {
15
46
  * that delivery's ingress — anything older belongs to an earlier turn.
16
47
  */
17
48
  pendingActivityAt = 0;
49
+ /**
50
+ * #2544: a completion tool can begin/settle before paste proof arms the
51
+ * guard (codex: reply at 22:22:25, task_complete + idle confirm later).
52
+ * Bounded by the next arm's ingress, same as pendingActivityAt.
53
+ */
54
+ pendingTool = null;
18
55
  /**
19
56
  * Fired exactly when a turn actually completes (stale generations are
20
57
  * fenced out, like the boolean result). #1209 registers a marker-clear
@@ -26,17 +63,19 @@ export class TurnReplyGuard {
26
63
  if (!this.active || this.active.cancelledByUser) {
27
64
  const carried = this.pendingActivityAt >= ingressAt ? this.pendingActivityAt : 0;
28
65
  this.pendingActivityAt = 0;
66
+ const pending = this.pendingTool && this.pendingTool.at >= ingressAt ? this.pendingTool : null;
67
+ this.pendingTool = null;
29
68
  this.active = {
30
69
  generation: ++this.generation,
31
70
  phase: "awaiting",
32
71
  cancelledByUser: false,
33
72
  target,
34
73
  latestObligation: 1,
35
- replyAttemptedAt: 0,
36
- replyAttemptFailedAt: 0,
37
- replyDeliveredAt: 0,
38
- completionDeliveredAt: 0,
39
- outboundDeliveredAt: 0,
74
+ replyAttemptedAt: pending?.replyAttempted ? 1 : 0,
75
+ replyAttemptFailedAt: pending?.replyAttemptFailed ? 1 : 0,
76
+ replyDeliveredAt: pending?.replyDelivered ? 1 : 0,
77
+ completionDeliveredAt: pending?.completionDelivered ? 1 : 0,
78
+ outboundDeliveredAt: pending?.outboundDelivered ? 1 : 0,
40
79
  busyObservedAt: carried,
41
80
  };
42
81
  return this.active.generation;
@@ -45,6 +84,7 @@ export class TurnReplyGuard {
45
84
  this.active.busyObservedAt = Math.max(this.active.busyObservedAt, this.pendingActivityAt);
46
85
  }
47
86
  this.pendingActivityAt = 0;
87
+ this.pendingTool = null;
48
88
  this.active.latestObligation++;
49
89
  this.active.target = target;
50
90
  return this.active.generation;
@@ -76,8 +116,16 @@ export class TurnReplyGuard {
76
116
  }
77
117
  beginToolAttempt(reply, completionAction = reply) {
78
118
  const active = this.active;
79
- if (!active)
80
- return null;
119
+ if (!active) {
120
+ // #2544: Codex can call reply before paste proof arms this generation.
121
+ this.stashPendingBegin(reply);
122
+ return {
123
+ generation: PRE_ARM_GENERATION,
124
+ obligation: 0,
125
+ reply,
126
+ completionAction,
127
+ };
128
+ }
81
129
  if (reply)
82
130
  active.replyAttemptedAt = Math.max(active.replyAttemptedAt, active.latestObligation);
83
131
  return {
@@ -88,21 +136,71 @@ export class TurnReplyGuard {
88
136
  };
89
137
  }
90
138
  settleToolAttempt(token, delivered) {
139
+ if (!token)
140
+ return;
91
141
  const active = this.active;
92
- if (!token || !active || token.generation !== active.generation)
142
+ if (token.generation === PRE_ARM_GENERATION) {
143
+ if (active && !active.cancelledByUser) {
144
+ this.applySettle(active, token, delivered, active.latestObligation);
145
+ return;
146
+ }
147
+ if (active?.cancelledByUser)
148
+ return;
149
+ this.stashPendingSettle(token, delivered);
93
150
  return;
151
+ }
152
+ if (!active || token.generation !== active.generation)
153
+ return;
154
+ this.applySettle(active, token, delivered, token.obligation);
155
+ }
156
+ applySettle(active, token, delivered, obligation) {
94
157
  if (!delivered) {
95
158
  // #1377: a definitive failure (adapter returned an error) is recorded so
96
159
  // maybeProxyReplyOnTurnEnd can distinguish "in-flight" from "known-failed".
97
160
  if (token.reply)
98
- active.replyAttemptFailedAt = Math.max(active.replyAttemptFailedAt, token.obligation);
161
+ active.replyAttemptFailedAt = Math.max(active.replyAttemptFailedAt, obligation);
99
162
  return;
100
163
  }
101
- active.outboundDeliveredAt = Math.max(active.outboundDeliveredAt, token.obligation);
164
+ active.outboundDeliveredAt = Math.max(active.outboundDeliveredAt, obligation);
102
165
  if (token.reply)
103
- active.replyDeliveredAt = Math.max(active.replyDeliveredAt, token.obligation);
166
+ active.replyDeliveredAt = Math.max(active.replyDeliveredAt, obligation);
104
167
  if (token.completionAction)
105
- active.completionDeliveredAt = Math.max(active.completionDeliveredAt, token.obligation);
168
+ active.completionDeliveredAt = Math.max(active.completionDeliveredAt, obligation);
169
+ }
170
+ stashPendingBegin(reply) {
171
+ const prev = this.pendingTool;
172
+ this.pendingTool = {
173
+ at: Date.now(),
174
+ replyAttempted: (prev?.replyAttempted ?? false) || reply,
175
+ replyAttemptFailed: prev?.replyAttemptFailed ?? false,
176
+ replyDelivered: prev?.replyDelivered ?? false,
177
+ completionDelivered: prev?.completionDelivered ?? false,
178
+ outboundDelivered: prev?.outboundDelivered ?? false,
179
+ };
180
+ }
181
+ stashPendingSettle(token, delivered) {
182
+ const at = Date.now();
183
+ const prev = this.pendingTool ?? {
184
+ at,
185
+ replyAttempted: token.reply,
186
+ replyAttemptFailed: false,
187
+ replyDelivered: false,
188
+ completionDelivered: false,
189
+ outboundDelivered: false,
190
+ };
191
+ if (!delivered) {
192
+ if (token.reply)
193
+ prev.replyAttemptFailed = true;
194
+ }
195
+ else {
196
+ prev.outboundDelivered = true;
197
+ if (token.reply)
198
+ prev.replyDelivered = true;
199
+ if (token.completionAction)
200
+ prev.completionDelivered = true;
201
+ }
202
+ prev.at = at;
203
+ this.pendingTool = prev;
106
204
  }
107
205
  snapshot() {
108
206
  const active = this.active;
@@ -142,6 +240,7 @@ export class TurnReplyGuard {
142
240
  reset() {
143
241
  this.active = null;
144
242
  this.pendingActivityAt = 0;
243
+ this.pendingTool = null;
145
244
  }
146
245
  }
147
246
  //# sourceMappingURL=turn-reply-guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"turn-reply-guard.js","sourceRoot":"","sources":["../src/turn-reply-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"turn-reply-guard.js","sourceRoot":"","sources":["../src/turn-reply-guard.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -94,6 +94,8 @@ export declare function resolveDeliveryWorkerMode(config: {
94
94
  }>;
95
95
  } | null | undefined, name: string): DeliveryWorkerMode;
96
96
  export interface InstanceConfig {
97
+ /** Proactive interrupted-work continuation; defaults true, inherited from fleet defaults. */
98
+ resume_interrupted_work?: boolean;
97
99
  working_directory: string;
98
100
  /** Minutes an idle CLI may remain resident before auto-pause. 0 disables it. */
99
101
  auto_pause_after?: number;
@@ -153,8 +155,9 @@ export interface InstanceConfig {
153
155
  backend?: string;
154
156
  /**
155
157
  * Kiro CLI interface/engine profile. Only used when backend is "kiro-cli".
156
- * "legacy" preserves AgEnD's current --legacy-ui launch; "tui" uses Kiro's
157
- * default UI; "v3" opts into the experimental next-generation agent.
158
+ * "legacy" is kiro's classic UI/v1 engine (the value when unset); "tui" its
159
+ * TUI/v2 engine, which new instances are written with (#2598,
160
+ * newInstanceKiroUi); "v3" the next-generation agent (refused by validation).
158
161
  */
159
162
  kiro_ui?: "legacy" | "tui" | "v3";
160
163
  /**
@@ -183,12 +186,15 @@ export interface InstanceConfig {
183
186
  board_cards_at_once?: number;
184
187
  /**
185
188
  * Which dashboard features this instance may use, on top of its `tool_set` (dashboard-permissions.ts): `appearance`
186
- * (its own look: theme, pictures, widgets, ambient, effects, mod proposals), `task_board` (the `task` tool) and
187
- * `web_settings` (Settings → Web appearance for the person). `false` switches one off; unset allows. `defaults.dashboard`
189
+ * (its own look: theme, pictures, widgets, ambient, effects, mod proposals), `task_board` (the `task` tool),
190
+ * `web_settings` (Settings → Web appearance for the person). `false` switches one off; unset allows. Office uses
191
+ * the separate `office_access` switch (off unless true). `defaults.dashboard`
188
192
  * sets it for every instance and merges key by key with an instance's own. The fleet reads it at each tool call; the
189
193
  * daemon keeps it current, and an agent's tool menu follows from its next start.
190
194
  */
191
195
  dashboard?: import("./dashboard-permissions.js").DashboardAccess;
196
+ /** Office tools: off unless true; inherits defaults.office_access. Stored outside the legacy closed dashboard map. */
197
+ office_access?: boolean;
192
198
  /**
193
199
  * Detect a human-channel turn that ended without a delivered reply and ask
194
200
  * the agent to send one bounded recovery reply. Only capable backends use
@@ -196,6 +202,8 @@ export interface InstanceConfig {
196
202
  * Default: true.
197
203
  */
198
204
  reply_completion_guard?: boolean;
205
+ /** Fleet-wide default for native replies addressing ClassicBot collab rooms. */
206
+ reply_triggers?: boolean;
199
207
  /** Skip non-essential subsystems (transcript monitor, context guardian, approval server, prompt detector) */
200
208
  lightweight?: boolean;
201
209
  /** System prompt — supports comma-separated file: paths for modularization */
@@ -283,8 +291,8 @@ export interface FleetDefaults extends Partial<InstanceConfig> {
283
291
  cost_guard?: CostGuardConfig;
284
292
  hang_detector?: HangDetectorConfig;
285
293
  daily_summary?: DailySummaryConfig;
286
- /** Daily General-topic tips and update-completion tip. Default: true. */
287
- tips?: boolean;
294
+ /** Daily tips: true (posted in the General topic) or false. A legacy "dm" (#2581, withdrawn) reads as true. Update-completion tips stay with the result. Default: true. */
295
+ tips?: boolean | "dm";
288
296
  /** #2246 step 3: the task board's fleet-level settings. */
289
297
  task_board?: {
290
298
  /** The daily summary's time in the fleet's zone ("HH:MM", 24 h), or "off". Default "09:00". */
@@ -411,6 +419,15 @@ export interface WebConfig {
411
419
  retention_days?: number;
412
420
  public_link?: boolean;
413
421
  };
422
+ /**
423
+ * #2636: Office share links — the live Office view for people outside the fleet, read-only, on a quick tunnel of its
424
+ * own. `enabled` (default true): false offers no Share and ends every open share. `max_hours` (1–24, default 24): the
425
+ * longest a share may live.
426
+ */
427
+ office_share?: {
428
+ enabled?: boolean;
429
+ max_hours?: number;
430
+ };
414
431
  /** Expose provider API-key verify/apply endpoints (default false until dark-shipped). */
415
432
  provider_secrets?: boolean;
416
433
  /**
@@ -425,8 +442,13 @@ export interface WebConfig {
425
442
  * `session`: a signed-in web session or the CLI header token. Writes need a credential either way.
426
443
  */
427
444
  view_access?: "open" | "session";
428
- /** Tell the admin channel when someone signs in to the web panel (default true). */
429
- notify_login?: boolean;
445
+ /** Sign-in notices: true/topic (default) or false/operator notices off. A legacy "dm" (#2581, withdrawn) reads as true. */
446
+ notify_login?: boolean | "dm";
447
+ /** Legacy (#2591), ignored and dropped on startup: notices always post in the topic. */
448
+ notice_delivery?: {
449
+ login?: "dm";
450
+ tips?: "dm";
451
+ };
430
452
  /**
431
453
  * #1620: how long a web session lasts. Only the LOCAL surface (the dashboard reached directly — loopback, a LAN, a
432
454
  * tailnet) is configurable; a public-link session's limits stay fixed. Hours, 1 ≤ idle_hours ≤ absolute_hours ≤ 720;
@@ -494,9 +516,15 @@ export interface WebVerifiedAuthorityConfig {
494
516
  /**
495
517
  * #2453 (§0.2): sessions over the admin's own named tunnel (`web.public_link.hostname`) may be authorized too — off by
496
518
  * default. Turning it on is confirmed in a General or on the host (never by the asking session); off applies at once
497
- * and every receipt from a named-link session reads as none. A quick tunnel never qualifies.
519
+ * and every receipt from a named-link session reads as none. A quick tunnel is `quick_link`'s (§0.3).
498
520
  */
499
521
  named_link?: boolean;
522
+ /**
523
+ * #1939 §0.3: sessions over the temporary public link (the quick tunnel `/web` opens) may be authorized too — off by
524
+ * default (the user's decision, 2026-10-23). Turning it on is confirmed in a General or on the host (never by the
525
+ * asking session); off applies at once and every receipt from a quick-link session reads as none.
526
+ */
527
+ quick_link?: boolean;
500
528
  }
501
529
  /** #1920: fleet.yaml `web.guests`. */
502
530
  export interface WebGuestsConfig {
@@ -511,6 +539,15 @@ export interface WebGuestsConfig {
511
539
  open_instances?: Record<string, string[]>;
512
540
  /** An admin's narrowing, per `<connection id>:<user id>`: intersected with the derived scope, never widening it. */
513
541
  narrow?: Record<string, string[]>;
542
+ /**
543
+ * #2348: an admin's explicit grants, per `<connection id>:<user id>` — the agents that person may see as a guest. Once
544
+ * this key exists it is the only scope there is (default deny): the derived scope above (connection access, rooms,
545
+ * open_instances, narrow) no longer gives anything. `name` is display only (who it was when granted).
546
+ */
547
+ grants?: Record<string, {
548
+ name?: string;
549
+ instances: string[];
550
+ }>;
514
551
  /** A guest session's limits: absolute 1–24 h (default 12), idle 15–720 min (default 120). */
515
552
  session?: {
516
553
  absolute_hours?: number;
@@ -5,12 +5,13 @@
5
5
  // session that started a sign-in gets its terminal link, access code and device code; every other admin page only that
6
6
  // one runs, on which device, and may cancel it. The stream's `backend_login` event carries nothing — it only says to
7
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";
8
+ import { html, useEffect, useState, useRef } from "/assets/app-html.js";
9
9
  import { t, register } from "/assets/app-i18n.js";
10
10
  import { appStore, createStore, useStore } from "/assets/app-store.js";
11
11
  import { closeDialog, shellStore, showDialog } from "/assets/app-shell.js";
12
12
  import { Dialog } from "/assets/ui-dialog.js";
13
13
  import { toast } from "/assets/ui-toast.js";
14
+ import { mountStructuredSignIns } from "./structured-signin.js";
14
15
 
15
16
  register("signin", {
16
17
  en: {
@@ -49,6 +50,8 @@ register("signin", {
49
50
  notOffered: "A public link is not offered for this sign-in.",
50
51
  failed: "That did not work.",
51
52
  listTitle: "Sign-ins",
53
+ browserRunning: "Signing in to {0} on this machine",
54
+ consoleFallback: "Use console fallback",
52
55
  listHint: "Each backend's login on this machine, and each credential profile an agent uses.",
53
56
  stUsable: "signed in",
54
57
  stNotSignedIn: "not signed in",
@@ -98,6 +101,8 @@ register("signin", {
98
101
  notOffered: "這次登入不提供公開連結。",
99
102
  failed: "沒有成功。",
100
103
  listTitle: "登入",
104
+ browserRunning: "正在這台機器登入 {0}",
105
+ consoleFallback: "改用主控台備援",
101
106
  listHint: "這台機器上每個 backend 的登入,以及代理使用的每個憑證設定檔。",
102
107
  stUsable: "已登入",
103
108
  stNotSignedIn: "未登入",
@@ -116,7 +121,7 @@ const tn = (k, ...v) => t(`signin.${k}`, ...v);
116
121
  const shownOf = (backend, profile) => (profile ? tn("profile", backend, profile) : backend);
117
122
 
118
123
  /** 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: [] });
124
+ export const signInStore = createStore({ loaded: false, login: null, targets: [], structured: null });
120
125
 
121
126
  let reading = null, again = false;
122
127
  /**
@@ -125,9 +130,13 @@ let reading = null, again = false;
125
130
  */
126
131
  export function refreshSignIn() {
127
132
  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; })
133
+ reading = Promise.all([
134
+ fetch("/ui/backend-login", { cache: "no-store" }).then(r => r.ok ? r.json() : null).catch(() => null),
135
+ fetch("/ui/browser-backend-signins", { cache: "no-store" }).then(r => r.ok ? r.json() : null).catch(() => null),
136
+ ]).then(([b, structured]) => {
137
+ if (b) signInStore.set({ loaded: true, login: b.login || null, targets: Array.isArray(b.targets) ? b.targets : [] });
138
+ signInStore.set({ structured: structured && Array.isArray(structured.selected) && Array.isArray(structured.pending) ? structured : null }); return b;
139
+ })
131
140
  .catch(() => null)
132
141
  .finally(() => { reading = null; if (again) { again = false; void refreshSignIn(); } });
133
142
  return reading;
@@ -140,13 +149,25 @@ export function installSignIn() {
140
149
  installed = true;
141
150
  const on = appStore.get().streamOn;
142
151
  if (typeof on === "function") on("backend_login", () => { void refreshSignIn(); });
143
- void refreshSignIn();
152
+ void refreshSignIn().then(() => {
153
+ // A navigation hint from the installer, never authority to start a CLI or cancel another writer.
154
+ const backends = installerSignInBackends(typeof location === "undefined" ? "" : location.search);
155
+ if (backends && signInStore.get().structured) showDialog(BrowserSignInDialog, { backends });
156
+ });
144
157
  shellStore.set({ banner: SignInLine });
145
158
  }
146
159
 
160
+ export function installerSignInBackends(search) {
161
+ const csv = new URLSearchParams(search).get("backend_signins");
162
+ if (!csv || csv.length > 100) return null;
163
+ const ids = csv.split(",");
164
+ return ids.length <= 4 && ids.every(b => ["kiro-cli", "claude-code", "codex", "antigravity"].includes(b)) ? [...new Set(ids)] : null;
165
+ }
166
+
147
167
  /** Open the dialog for one login (a backend's default one, or a credential profile). */
148
168
  export function openSignIn({ backend, profile }) {
149
- showDialog(SignInDialog, { backend, ...(profile ? { profile } : {}) });
169
+ if (!profile && ["kiro-cli", "claude-code", "codex"].includes(backend)) showDialog(BrowserSignInDialog, { backend });
170
+ else showDialog(SignInDialog, { backend, ...(profile ? { profile } : {}) });
150
171
  }
151
172
 
152
173
  /** Open the dialog on the running sign-in (its starter's view, or the cancel-only one). */
@@ -191,6 +212,32 @@ function Running({ login }) {
191
212
  </div>`;
192
213
  }
193
214
 
215
+ /** The same closed controls as first setup. Profile-specific logins retain their existing flow. */
216
+ export function BrowserSignInDialog({ backend, backends, onClose }) {
217
+ const root = useRef(null), close = onClose || closeDialog;
218
+ useEffect(() => {
219
+ let cards, last = "";
220
+ cards = mountStructuredSignIns(root.current, { endpoint: "/ui/browser-backend-signins", changed: next => {
221
+ if (backends) { if (backends.some(b => !next.selected.includes(b))) void cards.addBackends(backends); }
222
+ else if (!next.selected.includes(backend)) void cards.addBackend(backend);
223
+ const signature = JSON.stringify([next.login, next.pending]);
224
+ if (signature !== last) { last = signature; void refreshSignIn(); }
225
+ } });
226
+ return () => cards.dispose();
227
+ }, [backend, backends]);
228
+ const fallback = async (chosen = backend) => {
229
+ const result = await post("/ui/browser-backend-signins", { operation: "cancel" });
230
+ if (!result.ok) { toast(tn("failed")); return; }
231
+ showDialog(SignInDialog, { backend: chosen });
232
+ };
233
+ return html`<${Dialog} title=${backends ? tn("listTitle") : tn("title", backend)} onClose=${close}>
234
+ <div ref=${root}></div>
235
+ ${backends ? backends.filter(b => b !== "antigravity").map(b => html`<button type="button" class="btn" onClick=${() => fallback(b)}>${b} · ${tn("consoleFallback")}</button>`) : null}
236
+ <div class="s-actions">${backend ? html`<button type="button" class="btn" onClick=${() => fallback(backend)}>${tn("consoleFallback")}</button>` : null}
237
+ <button type="button" class="btn" onClick=${close}>${tn("close")}</button></div>
238
+ </${Dialog}>`;
239
+ }
240
+
194
241
  export function SignInDialog({ backend, profile, resume = false, onClose }) {
195
242
  const s = useStore(signInStore);
196
243
  const [step, setStep] = useState(resume ? { kind: "login" } : { kind: "checking" });
@@ -265,7 +312,12 @@ export function SignInDialog({ backend, profile, resume = false, onClose }) {
265
312
 
266
313
  /** The line every admin page shows while a sign-in runs (the shell's banner slot). */
267
314
  export function SignInLine() {
268
- const { login } = useStore(signInStore);
315
+ const { login, structured } = useStore(signInStore);
316
+ const active = structured?.login;
317
+ if ((!login || login.phase !== "running") && active && active.phase !== "done" && !(active.phase === "failed" && active.reason)) {
318
+ return html`<div data-trust="status" class="conn op-line signin-line" role="status"><span>${tn("browserRunning", active.backend)}</span>
319
+ <button type="button" class="btn btn-sm" onClick=${() => openSignIn({ backend: active.backend })}>${tn("open")}</button></div>`;
320
+ }
269
321
  if (!login || login.phase !== "running") return null;
270
322
  return html`<div data-trust="status" class="conn op-line signin-line" role="status">
271
323
  <span>${tn("running", shownOf(login.backend, login.profile), login.startedOn)}</span>
@@ -276,10 +328,14 @@ const STATE_KEY = { usable: "stUsable", not_signed_in: "stNotSignedIn", not_inst
276
328
 
277
329
  /** Settings → Agents: each login on this machine, with Sign in where the dashboard can do it. */
278
330
  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";
331
+ const { targets, loaded, login, structured } = useStore(signInStore);
332
+ // Not over the temporary public link: only the dashboard reached directly signs a backend in, and the link does not
333
+ // serve this read (it was a 404 in the console there, found by smoke-1939-authorize-defaults).
334
+ const offered = signInOffered();
335
+ useEffect(() => { if (offered) void refreshSignIn(); }, []);
336
+ if (!offered || !loaded || !targets.length) return null;
337
+ const active = structured?.login;
338
+ const running = (login && login.phase === "running") || (active && active.phase !== "done" && !(active.phase === "failed" && active.reason));
283
339
  return html`<section class="s-group signin-list" aria-label=${tn("listTitle")}>
284
340
  <div class="list-head"><span>${tn("listTitle")}</span></div>
285
341
  <p class="sub">${tn("listHint")}</p>
@@ -278,7 +278,7 @@ export function AmbientMotionNote({ name, canvasPlaying = false }) {
278
278
  /**
279
279
  * The fix for a block, done right here: both switches are this viewer's own (the show switch is a local choice on the
280
280
  * public link; the reduced-motion one is per device), so it works on the public link too; safe mode is the URL. Both
281
- * stay in Settings → Web appearance as well.
281
+ * stay in Settings → Look as well.
282
282
  */
283
283
  const FIX = {
284
284
  hidden: () => setThemesShown(true),
@@ -13,7 +13,7 @@ import { getAppEffects, wakeEffects, effectsLoaded, onEffectsAwake } from "./eff
13
13
 
14
14
  register("chatFx", {
15
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
- 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",
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 Settings → Look", 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.",
19
19
  off3: "Turned off on this device after three automatic pauses. Resume cannot restart it here.", interrupted: "Stopped: the page closed while it was playing. Resume to play it again.",
@@ -21,7 +21,7 @@ register("chatFx", {
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
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
- title: "效果", loading: "正在確認效果…", empty: "這個聊天沒有放置效果。", failed: "無法確認效果資源,已停止播放。重新載入頁面後再試。", reload: "重新載入頁面", pause: "暫停", resume: "恢復", remove: "從聊天移除", removeFailed: "無法移除效果。請重新載入頁面確認狀態。", css: "自訂 CSS 開啟或無法確認時,代理的前景效果會暫停。", setting: "開啟網頁外觀設定", running: "播放中", starting: "啟動中", off: "已停止", resumeFailed: "頁面或安全紀錄尚未就緒,無法恢復此效果。請重新載入頁面,或選擇其他效果。", queued: "等待空位", unknown: "這裡已關閉播放,或無法播放效果。", budget: "為維持頁面順暢,已暫停效果。恢復仍保留三次暫停的安全上限。", pauseHelp: "恢復仍保留這台裝置的自動暫停紀錄與三次暫停安全上限。", paused: "已暫停", low: "降低畫質",
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: "有對話框開著時暫停。",
27
27
  off3: "已自動暫停三次,這台裝置已關閉此效果,無法在這裡恢復。", interrupted: "播放時頁面被關閉而停止。按「恢復」再播放一次。",
@@ -64,7 +64,7 @@ export function effectRowText(row, { ownOpen = false, wasRunning = false, doc =
64
64
  /** Fixed local actions: no server/Worker-provided destination or raw reason in a URL. */
65
65
  export function effectReasonAction(reason) {
66
66
  if (reason === "preview_not_consented" || reason === "preview_unavailable") return { reload: true, label: "chatFx.reloadHint" };
67
- if (["disabled", "owner_css"].includes(reason)) return { href: "/settings/appearance", label: "chatFx.setting" };
67
+ if (["disabled", "owner_css"].includes(reason)) return { href: "/settings/look", label: "chatFx.setting" };
68
68
  if (["transport_unavailable", "baseline_unsupported", "baseline_unavailable", "baseline_timeout", "runtime_unavailable", "resource_unavailable", "resource_timeout", "clock_unavailable", "safety_unknown"].includes(reason)) return { reload: true, label: "chatFx.reloadHint" };
69
69
  return null;
70
70
  }
@@ -155,7 +155,7 @@ export function ChatEffects({ name, lease, element, store, open, onClose, onPlay
155
155
  return html`${!open && localViewer() && effects.length ? html`<div class="chat-fx-notice"><label><input type="checkbox" checked=${themesShown()} onChange=${e => setThemesShown(e.currentTarget.checked)} /> ${t("chatFx.viewerShow")}</label></div>` : null}${!open && state?.error && !effects.length ? html`<div class="chat-fx-notice" role="status">${effectRowText({ reason: state.error })} <${ReasonAction} reason=${state.error} /></div>` : null}${!open && state?.reason ? html`<div class="chat-fx-notice" role="status">${effectRowText({ reason: state.reason })} <${ReasonAction} reason=${state.reason} /></div>` : null}${!open && blocked.length ? html`<div class="chat-fx-notice" role="status"><strong>${t("chatFx.blocked")}</strong>
156
156
  ${blocked.map(({ p, row }) => html`<span key=${p.id}>${p.manifest.title}: ${effectRowText(row)} ${["paused", "host_budget"].includes(row?.reason) ? html`<small>${t(row.reason === "host_budget" ? "chatFx.budget" : "chatFx.pauseHelp")}</small>` : null} <${ReasonAction} reason=${row?.reason} /></span>`)}</div>` : null}${open ? html`<${Dialog} title=${t("chatFx.title")} onClose=${onClose} busy=${busy}>
157
157
  ${state?.error ? html`<p>${t("chatFx.failed")}</p><button type="button" class="btn" onClick=${() => location.reload()}>${t("chatFx.reload")}</button>` : null}
158
- ${css ? html`<p>${t("chatFx.css")}</p><button type="button" class="btn" onClick=${() => { onClose(); navigate("/settings/appearance"); }}>${t("chatFx.setting")}</button>` : null}
158
+ ${css ? html`<p>${t("chatFx.css")}</p><button type="button" class="btn" onClick=${() => { onClose(); navigate("/settings/look"); }}>${t("chatFx.setting")}</button>` : null}
159
159
  ${!effects.length && !state?.error ? html`<p>${t(state?.unavailable ? "chatFx.unknown" : state?.loading || !state ? "chatFx.loading" : "chatFx.empty")}</p>` : null}
160
160
  ${effects.map(p => { const row = rows.find(r => r.id === p.id); return html`<section key=${p.id}><h3>${p.manifest.title}</h3><p>${effectRowText(row, { ownOpen: open, wasRunning: before.current?.get(p.id) === true })}${row?.quality === "low" ? ` · ${t("chatFx.low")}` : ""}</p>
161
161
  <${ReasonAction} reason=${row?.reason} onClose=${onClose} />
@@ -627,7 +627,9 @@
627
627
  if (!Array.isArray(attachments)) return "";
628
628
  var cards = !!(opts && opts.htmlCards);
629
629
  // #1589: { inlinePreviews: true } (not on the public link) plays media and offers text inline, after the file list.
630
- var inline = !!(opts && opts.inlinePreviews);
630
+ // #2547: { textPreviews: true } offers the text cards (Markdown, CSV/TSV, JSON, code, text) on the public link too:
631
+ // the same capped, same-origin read and the same rendering (nothing in the file ever runs); media stays local.
632
+ var inline = !!(opts && opts.inlinePreviews), texts = inline || !!(opts && opts.textPreviews);
631
633
  var out = [], after = [];
632
634
  attachments.forEach(function (a) {
633
635
  // #1565: a file from before the fleet restarted that could not be served again — its name, marked unavailable;
@@ -639,7 +641,8 @@
639
641
  if (!a || typeof a.id !== "string" || !/^[0-9a-f]{32}$/.test(a.id)) return;
640
642
  if (cards && isHtmlAttachment(a)) after.push('<div class="html-card" data-att="' + a.id + '"></div>');
641
643
  var url = "/ui/file/" + a.id;
642
- var kind = inline ? attachmentPreviewType(a) : null;
644
+ var kind = texts ? attachmentPreviewType(a) : null;
645
+ if ((kind === "video" || kind === "audio") && !inline) kind = null;
643
646
  if (kind === "video") after.push('<div data-trust="media" class="att-media"><video class="att-video" controls preload="metadata" src="' + url + '"></video></div>');
644
647
  else if (kind === "audio") after.push('<div data-trust="media" class="att-media"><audio class="att-audio" controls preload="metadata" src="' + url + '"></audio></div>');
645
648
  else if (kind) after.push('<div class="text-card" data-att="' + a.id + '" data-type="' + kind + '"></div>');
@@ -49,7 +49,7 @@ register("chat", {
49
49
  cmd_wake: "Wake a paused instance", cmd_save: "Save the conversation to a file",
50
50
  tourTitle: "Welcome to web chat", tourStep: "{0} of {1}", tourBack: "Back", tourNext: "Next", tourDone: "Got it", tourSkip: "Skip",
51
51
  tour1: "Pick an instance in the list to chat with it. On a phone, ☰ opens the list.",
52
- tour2: "This is the agent's conversation. If it also has a Telegram or Discord chat, web echo (Settings → Web) decides whether what you send here shows there too.",
52
+ tour2: "This is the agent's conversation. If it also has a Telegram or Discord chat, web echo (Settings → Chat & connections) decides whether what you send here shows there too.",
53
53
  tour3: "Attach files and images with 📎, or paste or drop them on the chat.",
54
54
  tour4: "While the agent works, Stop reply appears in the message box: it interrupts the current reply. The instance itself keeps running.",
55
55
  tour5: "A “needs you” badge means the agent is waiting on its terminal, for example a permission question. Answer it from the buttons in its chat.",
@@ -116,7 +116,7 @@ register("chat", {
116
116
  file_empty: "empty file", file_too_large: "over {0} MB", file_too_large_public: "over {0} MB — the most the public link carries in one upload", file_too_many: "at most {0} files per message", file_too_much: "the files together would be over {0} MB", removeFile: "Remove", putBack: "Put back",
117
117
  noMessages: "Type a task below.",
118
118
  pick: "Choose an agent to start chatting.", noAgents: "Create an agent to start chatting.", newAgent: "New agent", notFound: "No instance called “{0}”", notFoundHint: "It may have been deleted or renamed.", backToList: "Choose an agent",
119
- details: "Instance details", start: "Start instance", stopInstance: "Stop instance", restart: "Restart instance", delete: "Delete instance…",
119
+ details: "Instance details", fullWidth: "Full width", start: "Start instance", stopInstance: "Stop instance", restart: "Restart instance", delete: "Delete instance…",
120
120
  started: "{0} started", stoppedInst: "{0} stopped", restarted: "{0} restarted", instanceDeleted: "{0} was deleted",
121
121
  deleteTitle: "Delete {0}?", deleteHelp: "This removes the instance from the fleet and stops it. Its working directory is kept. Type “delete {0}” to confirm.", deleteGo: "Delete", cancel: "Cancel",
122
122
  loadFailed: "Failed to load", tour: "Chat tour", tourBtnTitle: "Show the chat tour on an agent's chat", tourNoAgent: "Choose an agent before opening the chat tour.",
@@ -190,7 +190,7 @@ register("chat", {
190
190
  cmd_wake: "喚醒已暫停的 instance", cmd_save: "把對話存成檔案",
191
191
  tourTitle: "歡迎使用網頁聊天", tourStep: "{0} / {1}", tourBack: "上一步", tourNext: "下一步", tourDone: "知道了", tourSkip: "略過",
192
192
  tour1: "在清單裡選一個 instance,就能跟它對話。手機上請按 ☰ 打開清單。",
193
- tour2: "這是這個 Agent 的對話。如果它也有 Telegram 或 Discord 聊天,在這裡送出的訊息是否也出現在那裡,由「設定 → 網頁」的網頁轉發決定。",
193
+ tour2: "這是這個 Agent 的對話。如果它也有 Telegram 或 Discord 聊天,在這裡送出的訊息是否也出現在那裡,由「設定 → 聊天與連線」的網頁轉發決定。",
194
194
  tour3: "按 📎 附上檔案和圖片,也可以直接貼上或拖到聊天裡。",
195
195
  tour4: "Agent 工作時,輸入框會出現「中止回覆」:中斷目前的回覆,instance 本身會繼續運行。",
196
196
  tour5: "看到「等你回應」標記,表示 Agent 在終端機上等你,例如權限詢問。到它的聊天裡按按鈕回應即可。",
@@ -255,7 +255,7 @@ register("chat", {
255
255
  file_empty: "空檔案", file_too_large: "超過 {0} MB", file_too_large_public: "超過 {0} MB,這是公開連結單次上傳的上限", file_too_many: "每則訊息最多 {0} 個檔案", file_too_much: "檔案合計會超過 {0} MB", removeFile: "移除", putBack: "放回輸入框",
256
256
  noMessages: "直接在下方輸入任務。",
257
257
  pick: "選一個 Agent 開始聊天。", noAgents: "先建立一個 Agent,再開始聊天。", newAgent: "新增 Agent", notFound: "沒有叫「{0}」的 instance", notFoundHint: "它可能已被刪除或改名。", backToList: "選擇 Agent",
258
- details: "Instance 詳細資料", start: "啟動 instance", stopInstance: "停止 instance", restart: "重新啟動 instance", delete: "刪除 instance…",
258
+ details: "Instance 詳細資料", fullWidth: "全寬", start: "啟動 instance", stopInstance: "停止 instance", restart: "重新啟動 instance", delete: "刪除 instance…",
259
259
  started: "{0} 已啟動", stoppedInst: "{0} 已停止", restarted: "{0} 已重新啟動", instanceDeleted: "{0} 已刪除",
260
260
  deleteTitle: "要刪除 {0} 嗎?", deleteHelp: "這會把 instance 從 fleet 移除並停止它,工作目錄會保留。請輸入「delete {0}」確認。", deleteGo: "刪除", cancel: "取消",
261
261
  loadFailed: "載入失敗", tour: "聊天導覽", tourBtnTitle: "在 Agent 的聊天上開啟聊天導覽", tourNoAgent: "請先選一個 Agent,再開啟聊天導覽。",