@songsid/agend 2.3.2-beta.1 → 2.3.2-beta.11

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 (298) hide show
  1. package/THIRD_PARTY_NOTICES.md +40 -0
  2. package/dist/agent-cli.js +69 -2
  3. package/dist/agent-cli.js.map +1 -1
  4. package/dist/agent-endpoint.js +11 -0
  5. package/dist/agent-endpoint.js.map +1 -1
  6. package/dist/agent-whats-new.js +3 -0
  7. package/dist/agent-whats-new.js.map +1 -1
  8. package/dist/antigravity-usage-scan.d.ts +58 -0
  9. package/dist/antigravity-usage-scan.js +257 -0
  10. package/dist/antigravity-usage-scan.js.map +1 -0
  11. package/dist/antigravity-usage-worker.d.ts +1 -0
  12. package/dist/antigravity-usage-worker.js +10 -0
  13. package/dist/antigravity-usage-worker.js.map +1 -0
  14. package/dist/auth-api.js +4 -0
  15. package/dist/auth-api.js.map +1 -1
  16. package/dist/backend/kiro-classic-archive.d.ts +52 -0
  17. package/dist/backend/kiro-classic-archive.js +444 -0
  18. package/dist/backend/kiro-classic-archive.js.map +1 -0
  19. package/dist/backend/kiro-identity.d.ts +83 -0
  20. package/dist/backend/kiro-identity.js +144 -0
  21. package/dist/backend/kiro-identity.js.map +1 -1
  22. package/dist/backend/kiro-migration-verify.d.ts +10 -0
  23. package/dist/backend/kiro-migration-verify.js +52 -0
  24. package/dist/backend/kiro-migration-verify.js.map +1 -0
  25. package/dist/backend/kiro-retired-model.d.ts +62 -0
  26. package/dist/backend/kiro-retired-model.js +160 -0
  27. package/dist/backend/kiro-retired-model.js.map +1 -0
  28. package/dist/backend/kiro-v2-store-worker.js +21 -1
  29. package/dist/backend/kiro-v2-store-worker.js.map +1 -1
  30. package/dist/backend/kiro-v2-store.d.ts +8 -0
  31. package/dist/backend/kiro-v2-store.js.map +1 -1
  32. package/dist/backend/kiro.d.ts +169 -2
  33. package/dist/backend/kiro.js +703 -28
  34. package/dist/backend/kiro.js.map +1 -1
  35. package/dist/backend/types.d.ts +108 -0
  36. package/dist/backend/types.js +9 -0
  37. package/dist/backend/types.js.map +1 -1
  38. package/dist/backend-signin-guide.d.ts +1 -0
  39. package/dist/backend-signin-guide.js +9 -0
  40. package/dist/backend-signin-guide.js.map +1 -0
  41. package/dist/backend-signin-pending.d.ts +10 -0
  42. package/dist/backend-signin-pending.js +44 -0
  43. package/dist/backend-signin-pending.js.map +1 -0
  44. package/dist/browser-backend-signins.d.ts +56 -0
  45. package/dist/browser-backend-signins.js +189 -0
  46. package/dist/browser-backend-signins.js.map +1 -0
  47. package/dist/cache-ledger.d.ts +38 -2
  48. package/dist/cache-ledger.js +133 -8
  49. package/dist/cache-ledger.js.map +1 -1
  50. package/dist/cache-prices.d.ts +2 -1
  51. package/dist/cache-prices.js +5 -2
  52. package/dist/cache-prices.js.map +1 -1
  53. package/dist/cache-service.d.ts +68 -0
  54. package/dist/cache-service.js +355 -13
  55. package/dist/cache-service.js.map +1 -1
  56. package/dist/channel/adapters/discord.d.ts +11 -0
  57. package/dist/channel/adapters/discord.js +71 -14
  58. package/dist/channel/adapters/discord.js.map +1 -1
  59. package/dist/channel/ipc-timeouts.js +3 -0
  60. package/dist/channel/ipc-timeouts.js.map +1 -1
  61. package/dist/channel/mcp-tools.js +41 -2
  62. package/dist/channel/mcp-tools.js.map +1 -1
  63. package/dist/channel/tool-router.js +2 -1
  64. package/dist/channel/tool-router.js.map +1 -1
  65. package/dist/classic-channel-manager.d.ts +11 -0
  66. package/dist/classic-channel-manager.js +39 -1
  67. package/dist/classic-channel-manager.js.map +1 -1
  68. package/dist/cli.js +54 -2
  69. package/dist/cli.js.map +1 -1
  70. package/dist/config-validator.d.ts +7 -1
  71. package/dist/config-validator.js +55 -10
  72. package/dist/config-validator.js.map +1 -1
  73. package/dist/config.d.ts +19 -0
  74. package/dist/config.js +33 -1
  75. package/dist/config.js.map +1 -1
  76. package/dist/cpu-quota.d.ts +23 -0
  77. package/dist/cpu-quota.js +86 -0
  78. package/dist/cpu-quota.js.map +1 -0
  79. package/dist/daemon.d.ts +68 -0
  80. package/dist/daemon.js +448 -26
  81. package/dist/daemon.js.map +1 -1
  82. package/dist/dashboard-permissions.d.ts +31 -6
  83. package/dist/dashboard-permissions.js +84 -9
  84. package/dist/dashboard-permissions.js.map +1 -1
  85. package/dist/doctor.js +2 -1
  86. package/dist/doctor.js.map +1 -1
  87. package/dist/fleet-control-audit.d.ts +1 -1
  88. package/dist/fleet-control-audit.js +3 -0
  89. package/dist/fleet-control-audit.js.map +1 -1
  90. package/dist/fleet-manager.d.ts +133 -2
  91. package/dist/fleet-manager.js +905 -94
  92. package/dist/fleet-manager.js.map +1 -1
  93. package/dist/forged-envelope-scan.d.ts +9 -0
  94. package/dist/forged-envelope-scan.js +30 -5
  95. package/dist/forged-envelope-scan.js.map +1 -1
  96. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
  97. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +24 -1
  98. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +49 -1
  99. package/dist/general-knowledge/skills/web-appearance/SKILL.md +49 -1
  100. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +47 -9
  101. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +54 -11
  102. package/dist/instance-config-impact.js +10 -5
  103. package/dist/instance-config-impact.js.map +1 -1
  104. package/dist/instance-lifecycle.d.ts +23 -0
  105. package/dist/instance-lifecycle.js +62 -12
  106. package/dist/instance-lifecycle.js.map +1 -1
  107. package/dist/kiro-db-reader.d.ts +5 -0
  108. package/dist/kiro-db-reader.js +18 -0
  109. package/dist/kiro-db-reader.js.map +1 -1
  110. package/dist/kiro-engine-status.d.ts +2 -0
  111. package/dist/kiro-engine-status.js +9 -0
  112. package/dist/kiro-engine-status.js.map +1 -1
  113. package/dist/kiro-migrate.d.ts +60 -0
  114. package/dist/kiro-migrate.js +160 -0
  115. package/dist/kiro-migrate.js.map +1 -0
  116. package/dist/kiro-session-proof.d.ts +41 -0
  117. package/dist/kiro-session-proof.js +89 -0
  118. package/dist/kiro-session-proof.js.map +1 -0
  119. package/dist/kiro-transcript-lane.d.ts +2 -0
  120. package/dist/kiro-transcript-lane.js.map +1 -1
  121. package/dist/kiro-transcript-worker.js +1 -0
  122. package/dist/kiro-transcript-worker.js.map +1 -1
  123. package/dist/kiro-tui-forensic.d.ts +12 -0
  124. package/dist/kiro-tui-forensic.js +110 -0
  125. package/dist/kiro-tui-forensic.js.map +1 -0
  126. package/dist/kiro-usage-run.d.ts +7 -0
  127. package/dist/kiro-usage-run.js +39 -0
  128. package/dist/kiro-usage-run.js.map +1 -0
  129. package/dist/kiro-usage-scan.d.ts +49 -0
  130. package/dist/kiro-usage-scan.js +223 -0
  131. package/dist/kiro-usage-scan.js.map +1 -0
  132. package/dist/kiro-usage-worker.d.ts +1 -0
  133. package/dist/kiro-usage-worker.js +10 -0
  134. package/dist/kiro-usage-worker.js.map +1 -0
  135. package/dist/kiro-usage.d.ts +58 -0
  136. package/dist/kiro-usage.js +310 -0
  137. package/dist/kiro-usage.js.map +1 -0
  138. package/dist/locale.js +230 -8
  139. package/dist/locale.js.map +1 -1
  140. package/dist/log-service.js +1 -1
  141. package/dist/log-service.js.map +1 -1
  142. package/dist/login-url.d.ts +4 -0
  143. package/dist/login-url.js +22 -0
  144. package/dist/login-url.js.map +1 -0
  145. package/dist/needs-you-hub.d.ts +2 -1
  146. package/dist/needs-you-hub.js +1 -1
  147. package/dist/needs-you-hub.js.map +1 -1
  148. package/dist/needs-you.d.ts +10 -2
  149. package/dist/needs-you.js +10 -2
  150. package/dist/needs-you.js.map +1 -1
  151. package/dist/notice-delivery.d.ts +16 -0
  152. package/dist/notice-delivery.js +35 -0
  153. package/dist/notice-delivery.js.map +1 -0
  154. package/dist/office-share-page.d.ts +16 -0
  155. package/dist/office-share-page.js +85 -0
  156. package/dist/office-share-page.js.map +1 -0
  157. package/dist/office-share-service.d.ts +91 -0
  158. package/dist/office-share-service.js +176 -0
  159. package/dist/office-share-service.js.map +1 -0
  160. package/dist/office-share.d.ts +268 -0
  161. package/dist/office-share.js +574 -0
  162. package/dist/office-share.js.map +1 -0
  163. package/dist/opencode-usage-scan.d.ts +28 -0
  164. package/dist/opencode-usage-scan.js +92 -0
  165. package/dist/opencode-usage-scan.js.map +1 -0
  166. package/dist/opencode-usage-worker.d.ts +1 -0
  167. package/dist/opencode-usage-worker.js +10 -0
  168. package/dist/opencode-usage-worker.js.map +1 -0
  169. package/dist/outbound-handlers.js +22 -2
  170. package/dist/outbound-handlers.js.map +1 -1
  171. package/dist/outbound-schemas.d.ts +65 -2
  172. package/dist/outbound-schemas.js +56 -2
  173. package/dist/outbound-schemas.js.map +1 -1
  174. package/dist/public-web-gateway.js +7 -1
  175. package/dist/public-web-gateway.js.map +1 -1
  176. package/dist/quickstart-api.js +13 -2
  177. package/dist/quickstart-api.js.map +1 -1
  178. package/dist/quickstart.js +2 -1
  179. package/dist/quickstart.js.map +1 -1
  180. package/dist/remote-card-answer.d.ts +83 -0
  181. package/dist/remote-card-answer.js +208 -0
  182. package/dist/remote-card-answer.js.map +1 -0
  183. package/dist/remote-card-prompt.d.ts +38 -0
  184. package/dist/remote-card-prompt.js +86 -0
  185. package/dist/remote-card-prompt.js.map +1 -0
  186. package/dist/reply-triggers.d.ts +2 -0
  187. package/dist/reply-triggers.js +3 -0
  188. package/dist/reply-triggers.js.map +1 -0
  189. package/dist/settings-api.d.ts +2 -0
  190. package/dist/settings-api.js +41 -16
  191. package/dist/settings-api.js.map +1 -1
  192. package/dist/settings-change.js +20 -14
  193. package/dist/settings-change.js.map +1 -1
  194. package/dist/settings-effect.js +7 -1
  195. package/dist/settings-effect.js.map +1 -1
  196. package/dist/settings-instance-patch.js +4 -1
  197. package/dist/settings-instance-patch.js.map +1 -1
  198. package/dist/setup-form.d.ts +1 -1
  199. package/dist/setup-form.js +55 -6
  200. package/dist/setup-form.js.map +1 -1
  201. package/dist/setup-host.d.ts +9 -0
  202. package/dist/setup-host.js +127 -6
  203. package/dist/setup-host.js.map +1 -1
  204. package/dist/setup-signin-assets.d.ts +2 -0
  205. package/dist/setup-signin-assets.js +6 -0
  206. package/dist/setup-signin-assets.js.map +1 -0
  207. package/dist/setup-wizard.js +2 -0
  208. package/dist/setup-wizard.js.map +1 -1
  209. package/dist/structured-signin-transport.d.ts +8 -0
  210. package/dist/structured-signin-transport.js +79 -0
  211. package/dist/structured-signin-transport.js.map +1 -0
  212. package/dist/structured-signin.d.ts +131 -0
  213. package/dist/structured-signin.js +388 -0
  214. package/dist/structured-signin.js.map +1 -0
  215. package/dist/tool-permissions.js +29 -0
  216. package/dist/tool-permissions.js.map +1 -1
  217. package/dist/topic-commands.js +6 -2
  218. package/dist/topic-commands.js.map +1 -1
  219. package/dist/transcript-sources.d.ts +27 -2
  220. package/dist/transcript-sources.js +104 -40
  221. package/dist/transcript-sources.js.map +1 -1
  222. package/dist/turn-reply-guard.d.ts +1 -1
  223. package/dist/turn-reply-guard.js +1 -1
  224. package/dist/turn-reply-guard.js.map +1 -1
  225. package/dist/types.d.ts +33 -8
  226. package/dist/ui/backend-signin.js +63 -10
  227. package/dist/ui/chat-store.js +3 -2
  228. package/dist/ui/chat-strings.js +4 -4
  229. package/dist/ui/fleet-office-editor.js +68 -11
  230. package/dist/ui/fleet-office-layout.js +110 -35
  231. package/dist/ui/fleet-office-model.js +6 -3
  232. package/dist/ui/fleet-office-overview.js +167 -0
  233. package/dist/ui/fleet-office-pack.d.ts +13 -3
  234. package/dist/ui/fleet-office-pack.js +214 -24
  235. package/dist/ui/fleet-office-skin.js +98 -23
  236. package/dist/ui/fleet-office-store.js +82 -5
  237. package/dist/ui/fleet-office-view.js +5 -4
  238. package/dist/ui/fleet-office-zones.js +232 -21
  239. package/dist/ui/fleet-office.js +549 -186
  240. package/dist/ui/fleet-usage.js +19 -15
  241. package/dist/ui/office-share-dialog.js +145 -0
  242. package/dist/ui/office-share-page.js +164 -0
  243. package/dist/ui/panel-chat.js +22 -3
  244. package/dist/ui/panel-log.js +4 -4
  245. package/dist/ui/panel-needs.js +5 -5
  246. package/dist/ui/panel-settings.js +38 -12
  247. package/dist/ui/settings-dialogs.js +8 -1
  248. package/dist/ui/settings-guests.js +17 -7
  249. package/dist/ui/settings-model.js +22 -6
  250. package/dist/ui/settings-registry.js +4 -0
  251. package/dist/ui/settings-strings.js +18 -2
  252. package/dist/ui/shared/app-i18n.js +4 -2
  253. package/dist/ui/shared/app-shell.js +14 -6
  254. package/dist/ui/shared/app-stream.js +2 -1
  255. package/dist/ui/shared/app.css +85 -4
  256. package/dist/ui/shared/office/cozy.png +0 -0
  257. package/dist/ui/shared/side-panel.js +95 -0
  258. package/dist/ui/structured-signin.js +115 -0
  259. package/dist/usage-report.d.ts +20 -0
  260. package/dist/usage-report.js +54 -17
  261. package/dist/usage-report.js.map +1 -1
  262. package/dist/usage-rollup.d.ts +9 -1
  263. package/dist/usage-rollup.js +20 -4
  264. package/dist/usage-rollup.js.map +1 -1
  265. package/dist/web-api.d.ts +23 -1
  266. package/dist/web-api.js +292 -3
  267. package/dist/web-api.js.map +1 -1
  268. package/dist/web-auth.js +1 -1
  269. package/dist/web-auth.js.map +1 -1
  270. package/dist/web-backend-login.d.ts +1 -7
  271. package/dist/web-backend-login.js +2 -24
  272. package/dist/web-backend-login.js.map +1 -1
  273. package/dist/web-office-acts.d.ts +173 -0
  274. package/dist/web-office-acts.js +285 -0
  275. package/dist/web-office-acts.js.map +1 -0
  276. package/dist/web-office-pack-read.d.ts +35 -0
  277. package/dist/web-office-pack-read.js +252 -0
  278. package/dist/web-office-pack-read.js.map +1 -0
  279. package/dist/web-office-pack-tools.d.ts +232 -0
  280. package/dist/web-office-pack-tools.js +754 -0
  281. package/dist/web-office-pack-tools.js.map +1 -0
  282. package/dist/web-office-skins.d.ts +71 -6
  283. package/dist/web-office-skins.js +321 -35
  284. package/dist/web-office-skins.js.map +1 -1
  285. package/dist/web-office-store.d.ts +5 -2
  286. package/dist/web-office-store.js +69 -10
  287. package/dist/web-office-store.js.map +1 -1
  288. package/dist/web-settings-patch.d.ts +2 -1
  289. package/dist/web-settings-patch.js +4 -1
  290. package/dist/web-settings-patch.js.map +1 -1
  291. package/dist/working-recovery.d.ts +2 -2
  292. package/dist/working-recovery.js +43 -8
  293. package/dist/working-recovery.js.map +1 -1
  294. package/dist/working-state-journal.d.ts +2 -0
  295. package/dist/working-state-journal.js +16 -1
  296. package/dist/working-state-journal.js.map +1 -1
  297. package/package.json +3 -2
  298. package/templates/windows-shortcuts.ps1 +155 -140
@@ -0,0 +1,86 @@
1
+ import { t } from "./locale.js";
2
+ /** Buttons per card at most: Discord's 25 less room for Skip / Back. Beyond it the card is answered in words or the pane. */
3
+ export const REMOTE_CARD_MAX_OPTIONS = 20;
4
+ /** A button label's length at most (Discord's limit is 80; long ones are clipped with an ellipsis). */
5
+ const LABEL_MAX = 60;
6
+ /** A typed answer's length at most. */
7
+ export const REMOTE_CARD_TEXT_MAX = 4_000;
8
+ const clip = (text, max = LABEL_MAX) => (text.length > max ? `${text.slice(0, max - 1)}…` : text);
9
+ /** The message and buttons for `card`, asked by `instance`. */
10
+ export function remoteCardPrompt(instance, card) {
11
+ if (card.kind === "input") {
12
+ return {
13
+ message: [t("card.input_intro", card.server, instance), ...card.rows.map(row => ` ${row}`), t("card.input_hint")].join("\n"),
14
+ choices: [
15
+ ...(card.actions.includes("Decline") ? [{ action: "decline", label: t("card.decline") }] : []),
16
+ { action: "cancel", label: t("card.cancel") },
17
+ ],
18
+ webInput: null,
19
+ };
20
+ }
21
+ if (card.page === "suboptions") {
22
+ const titles = card.options.map(option => option.title);
23
+ return {
24
+ message: [t("card.sub_intro", instance), card.question, ...card.options.map(o => `${o.checked ? "☑" : "☐"} ${o.title}`)].join("\n"),
25
+ choices: [
26
+ { action: "sub-all", label: clip(t("card.sub_all", titles.join(", "))) },
27
+ ...(card.options.length <= REMOTE_CARD_MAX_OPTIONS && card.options.length > 1
28
+ ? card.options.map(o => ({ action: `sub-${o.n}`, label: clip(t("card.sub_only", o.title)) })) : []),
29
+ { action: "back", label: t("card.back") },
30
+ ],
31
+ webInput: null,
32
+ };
33
+ }
34
+ const listed = card.options.map(o => {
35
+ const title = `${o.n}. ${o.title}${o.recommended ? ` ${t("card.recommended")}` : ""}`;
36
+ return o.description ? `${title} — ${o.description}` : title;
37
+ });
38
+ const buttons = card.options.length <= REMOTE_CARD_MAX_OPTIONS
39
+ ? card.options.map(o => ({ action: `opt-${o.n}`, label: clip(`${o.n}. ${o.title}${o.recommended ? " ★" : ""}`) })) : [];
40
+ return {
41
+ message: [t("card.question_intro", instance), card.question, ...listed, card.freeText ? t("card.question_hint_text") : t("card.question_hint")].join("\n"),
42
+ choices: [...buttons, { action: "skip", label: t("card.skip") }],
43
+ webInput: card.freeText ? { action: "text", label: t("card.answer_in_words") } : null,
44
+ };
45
+ }
46
+ /** The action a button id stands for (null: not one of ours). `text` takes the typed answer. */
47
+ export function remoteCardAction(action, text) {
48
+ const option = /^opt-(\d{1,2})$/.exec(action);
49
+ if (option)
50
+ return { kind: "option", n: Number(option[1]) };
51
+ const sub = /^sub-(\d{1,2}|all)$/.exec(action);
52
+ if (sub)
53
+ return { kind: "suboptions", only: sub[1] === "all" ? null : Number(sub[1]) };
54
+ switch (action) {
55
+ case "back":
56
+ case "skip":
57
+ case "decline":
58
+ case "cancel": return { kind: action };
59
+ case "text": return typeof text === "string" && text.trim() ? { kind: "text", text: text.slice(0, REMOTE_CARD_TEXT_MAX) } : null;
60
+ default: return null;
61
+ }
62
+ }
63
+ /** What the person chose, in words, for the outcome line (never the typed answer itself: it is in their own message). */
64
+ export function remoteCardChoiceLabel(card, action) {
65
+ switch (action.kind) {
66
+ case "option": return clip(card.options?.find(o => o.n === action.n)?.title ?? `#${action.n}`);
67
+ case "suboptions": return action.only === null ? t("card.sub_all_short") : clip(t("card.sub_only", card.options?.find(o => o.n === action.only)?.title ?? `#${action.only}`));
68
+ case "text": return t("card.in_words");
69
+ case "skip": return t("card.skip");
70
+ case "back": return t("card.back");
71
+ case "decline": return t("card.decline");
72
+ case "cancel": return t("card.cancel");
73
+ }
74
+ }
75
+ /** The line the card's message collapses to once a person's answer was keyed in (or was not). */
76
+ export function remoteCardOutcomeText(instance, who, choice, outcome) {
77
+ switch (outcome.outcome) {
78
+ case "answered": return t("card.answered", who, choice);
79
+ case "suboptions": return t("card.opened_sub", who, choice);
80
+ case "back": return t("card.went_back", who);
81
+ case "stale": return t("card.stale", instance);
82
+ case "refused": return t("card.refused", instance);
83
+ case "stopped": return t("card.stopped", instance);
84
+ }
85
+ }
86
+ //# sourceMappingURL=remote-card-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-card-prompt.js","sourceRoot":"","sources":["../src/remote-card-prompt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Opt-in ClassicBot collab addressing; fleet-topic bot admission is independent. */
2
+ export declare const DEFAULT_REPLY_TRIGGERS = false;
@@ -0,0 +1,3 @@
1
+ /** Opt-in ClassicBot collab addressing; fleet-topic bot admission is independent. */
2
+ export const DEFAULT_REPLY_TRIGGERS = false;
3
+ //# sourceMappingURL=reply-triggers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-triggers.js","sourceRoot":"","sources":["../src/reply-triggers.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC"}
@@ -42,6 +42,8 @@ export interface SettingsApiContext extends AppShellContext {
42
42
  };
43
43
  /** #1920 phase 3: Settings → Web sign-ins → Guests. */
44
44
  guestOverview?(): unknown;
45
+ /** #2667: the ClassicBot rooms' instance names — a guest grant may name one, so a save's validation knows them. */
46
+ classicRoomNames?(): string[];
45
47
  revokeGuestWebSessions?(owner: {
46
48
  adapterId: string;
47
49
  userId: string;
@@ -1,3 +1,6 @@
1
+ import { officeInputPatch } from "./dashboard-permissions.js";
2
+ import { setNoticeMode } from "./notice-delivery.js";
3
+ import { DEFAULT_REPLY_TRIGGERS } from "./reply-triggers.js";
1
4
  import { PUBLIC_TUNNEL_SECRET_ID, PUBLIC_TUNNEL_TOKEN_HINT } from "./public-tunnel-config.js";
2
5
  import { withSpawnHoldReply } from "./spawn-hold-reply.js";
3
6
  import { normalizeSettingsInstancePatch, removesInstanceOverride } from "./settings-instance-patch.js";
@@ -183,6 +186,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
183
186
  const path = url.pathname;
184
187
  if (!isSettingsPath(path))
185
188
  return false;
189
+ // #2667: validated with the ClassicBot rooms there are now — a guest grant naming one is not an unknown name.
190
+ const validateFleet = (config) => validateFleetConfig(config, { rooms: ctx.classicRoomNames?.() ?? [] });
186
191
  const method = req.method ?? "GET";
187
192
  // ── The page: the app shell, which mounts the Settings panel (#1408 step 3) ──
188
193
  if (isSettingsPage(path)) {
@@ -200,6 +205,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
200
205
  if (method === "GET" && path === "/api/settings/schema") {
201
206
  json(res, 200, {
202
207
  ...buildSettingsImpactSchema(),
208
+ reply_triggers_default: DEFAULT_REPLY_TRIGGERS,
203
209
  // Non-null means a restart cannot clear the fleet row, so the page shows
204
210
  // the mismatch instead of offering a button that can never succeed.
205
211
  fleet_signature_mismatch: ctx.fleetSignatureMismatchKeys?.() ?? null,
@@ -899,12 +905,18 @@ export function handleSettingsRequest(req, res, url, ctx) {
899
905
  // (a shorter sign-in time), and the audit must still name who did it. A confirmation's replay is no one's: null.
900
906
  const auditBy = parsed.guests?.grants !== undefined && !isSettingsReplay(req) ? guestSettingsCaller(req, url, ctx) : null;
901
907
  const changes = [];
902
- const web = { ...cfg.web };
908
+ let web = { ...cfg.web };
903
909
  let webTerminal = cfg.web_terminal;
904
910
  if (parsed.canvasWorker !== undefined) {
905
911
  web.experimental = { ...web.experimental, canvas_worker: parsed.canvasWorker };
906
912
  changes.push({ path: ["web", "experimental", "canvas_worker"], value: parsed.canvasWorker });
907
913
  }
914
+ if (parsed.notifyLogin !== undefined) {
915
+ const holder = { defaults: cfg.defaults, web };
916
+ setNoticeMode(holder, "login", parsed.notifyLogin);
917
+ web = holder.web;
918
+ changes.push({ path: ["web", "notify_login"], value: web.notify_login }, { path: ["web", "notice_delivery", "login"], remove: true });
919
+ }
908
920
  if (parsed.echo !== undefined) {
909
921
  web.echo_to_channel = parsed.echo;
910
922
  changes.push({ path: ["web", "echo_to_channel"], value: parsed.echo });
@@ -981,8 +993,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
981
993
  }
982
994
  if (!changes.length)
983
995
  return json(res, 200, { ok: true });
984
- const before = validateFleetConfig(cfg);
985
- const after = validateFleetConfig({ ...cfg, web, web_terminal: webTerminal });
996
+ const before = validateFleet(cfg);
997
+ const after = validateFleet({ ...cfg, web, web_terminal: webTerminal });
986
998
  if (rejectIfWorse(res, before, after))
987
999
  return;
988
1000
  const previous = { web: cfg.web, hadWeb: "web" in cfg, terminal: cfg.web_terminal, hadTerminal: "web_terminal" in cfg };
@@ -1096,8 +1108,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1096
1108
  const changes = parsed.map(c => c.value === null
1097
1109
  ? { path: ["web", "appearance", c.group, c.key], value: undefined, remove: true }
1098
1110
  : { path: ["web", "appearance", c.group, c.key], value: c.value });
1099
- const before = validateFleetConfig(cfg);
1100
- const after = validateFleetConfig({ ...cfg, web });
1111
+ const before = validateFleet(cfg);
1112
+ const after = validateFleet({ ...cfg, web });
1101
1113
  if (rejectIfWorse(res, before, after))
1102
1114
  return;
1103
1115
  const previous = { web: cfg.web, hadWeb: "web" in cfg };
@@ -1137,7 +1149,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1137
1149
  const restored = restoreRedactedSecrets(body, cfg.defaults);
1138
1150
  if ("path" in restored)
1139
1151
  return json(res, 400, { error: `redacted value has no stored credential: defaults.${restored.path}` });
1140
- const merged = { ...cfg.defaults, ...restored.value };
1152
+ const merged = { ...cfg.defaults, ...officeInputPatch(restored.value) };
1141
1153
  // #1310: locale:null means "clear the key" (user chose Auto). Mirrors
1142
1154
  // how the instance save handles model ("" → delete) and nullable overrides.
1143
1155
  if (body.locale === null || body.locale === "")
@@ -1145,11 +1157,16 @@ export function handleSettingsRequest(req, res, url, ctx) {
1145
1157
  // General → Defaults' "not set" for the tool profile: the key goes (worker for an agent, general for a General).
1146
1158
  if (body.tool_set === null || body.tool_set === "")
1147
1159
  delete merged.tool_set;
1148
- const before = validateFleetConfig(cfg);
1149
- const after = validateFleetConfig({ ...cfg, defaults: merged });
1160
+ const before = validateFleet(cfg);
1161
+ const after = validateFleet({ ...cfg, defaults: merged });
1150
1162
  if (rejectIfWorse(res, before, after))
1151
1163
  return;
1152
- settingsWrite(req, () => { cfg.defaults = merged; ctx.saveFleetConfig(); });
1164
+ settingsWrite(req, () => {
1165
+ cfg.defaults = merged;
1166
+ if (typeof body.tips === "boolean" || body.tips === "dm")
1167
+ setNoticeMode(cfg, "tips", body.tips);
1168
+ ctx.saveFleetConfig();
1169
+ });
1153
1170
  json(res, 200, { ok: true, warnings: saveWarnings(before, after) });
1154
1171
  }).catch(() => json(res, 400, { error: "bad request" }));
1155
1172
  return true;
@@ -1239,8 +1256,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1239
1256
  }
1240
1257
  const next = { ...cfg, channels: normalizedBody };
1241
1258
  delete next.channel; // channels[] supersedes the legacy single channel
1242
- const before = validateFleetConfig(cfg);
1243
- const after = validateFleetConfig(next);
1259
+ const before = validateFleet(cfg);
1260
+ const after = validateFleet(next);
1244
1261
  if (rejectIfWorse(res, before, after))
1245
1262
  return;
1246
1263
  const previous = { channels: cfg.channels, channel: cfg.channel, hadChannel: "channel" in cfg };
@@ -1291,6 +1308,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1291
1308
  delete merged.tool_progress;
1292
1309
  if (body.reply_completion_guard === null)
1293
1310
  delete merged.reply_completion_guard;
1311
+ if (body.reply_triggers === null)
1312
+ delete merged.reply_triggers;
1294
1313
  const before = validateClassicBotConfig(classic);
1295
1314
  const after = validateClassicBotConfig({ ...classic, defaults: merged });
1296
1315
  if (rejectIfWorse(res, before, after))
@@ -1340,6 +1359,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1340
1359
  "model",
1341
1360
  "auto_pause_after",
1342
1361
  "collab",
1362
+ "reply_triggers",
1343
1363
  "context_lines",
1344
1364
  "tool_progress",
1345
1365
  "reply_completion_guard",
@@ -1357,6 +1377,9 @@ export function handleSettingsRequest(req, res, url, ctx) {
1357
1377
  && (typeof body.auto_pause_after !== "number" || !Number.isFinite(body.auto_pause_after) || body.auto_pause_after < 0)) {
1358
1378
  return json(res, 400, { error: "auto_pause_after must be a non-negative finite number" });
1359
1379
  }
1380
+ if (body.reply_triggers !== undefined && body.reply_triggers !== null && typeof body.reply_triggers !== "boolean") {
1381
+ return json(res, 400, { error: "reply_triggers must be a boolean" });
1382
+ }
1360
1383
  if (body.collab !== undefined && typeof body.collab !== "boolean")
1361
1384
  return json(res, 400, { error: "collab must be a boolean" });
1362
1385
  if (body.context_lines !== undefined && (!Number.isInteger(body.context_lines) || body.context_lines < 0)) {
@@ -1396,6 +1419,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1396
1419
  delete merged.tool_progress;
1397
1420
  if (body.reply_completion_guard === null)
1398
1421
  delete merged.reply_completion_guard;
1422
+ if (body.reply_triggers === null)
1423
+ delete merged.reply_triggers;
1399
1424
  channels[key] = merged;
1400
1425
  const before = validateClassicBotConfig(previous);
1401
1426
  const after = validateClassicBotConfig(classic);
@@ -1615,7 +1640,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1615
1640
  json(res, 400, { error: `redacted value has no stored credential: instances.${name}.${restored.path}` });
1616
1641
  return;
1617
1642
  }
1618
- const patch = restored.value;
1643
+ const patch = officeInputPatch(restored.value);
1619
1644
  let mergedInst;
1620
1645
  try {
1621
1646
  mergedInst = normalizeSettingsInstancePatch(base, patch);
@@ -1624,8 +1649,8 @@ export function handleSettingsRequest(req, res, url, ctx) {
1624
1649
  json(res, 400, { error: "unsupported_instance_null" });
1625
1650
  return;
1626
1651
  }
1627
- const before = validateFleetConfig(cfg);
1628
- const after = validateFleetConfig({ ...cfg, instances: { ...cfg.instances, [name]: mergedInst } });
1652
+ const before = validateFleet(cfg);
1653
+ const after = validateFleet({ ...cfg, instances: { ...cfg.instances, [name]: mergedInst } });
1629
1654
  if (rejectIfWorse(res, before, after))
1630
1655
  return;
1631
1656
  settingsWrite(req, () => {
@@ -1685,7 +1710,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1685
1710
  // Settings → Agents → Delete, confirmed: the same removal as delete_instance — the agent stops, nothing of it is
1686
1711
  // left behind (schedules, team places), and its fleet.yaml entry goes.
1687
1712
  const execution = settingsRequestExecution(req), authorization = authorizeExplicitInstanceRemoval("dashboard-confirmed");
1688
- (execution ? ctx.removeInstance(name, authorization, execution) : ctx.removeInstance(name, authorization)).then(() => json(res, 200, { ok: true, deleted: name, warnings: validateFleetConfig(cfg).warnings }), (err) => json(res, 500, { error: err.message }));
1713
+ (execution ? ctx.removeInstance(name, authorization, execution) : ctx.removeInstance(name, authorization)).then(() => json(res, 200, { ok: true, deleted: name, warnings: validateFleet(cfg).warnings }), (err) => json(res, 500, { error: err.message }));
1689
1714
  return true;
1690
1715
  }
1691
1716
  // DELETE never blocks on validation; surface any resulting warnings.
@@ -1694,7 +1719,7 @@ export function handleSettingsRequest(req, res, url, ctx) {
1694
1719
  clearPausedMarker(join(ctx.dataDir, "instances", name));
1695
1720
  ctx.saveFleetConfig();
1696
1721
  });
1697
- json(res, 200, { ok: true, warnings: validateFleetConfig(cfg).warnings });
1722
+ json(res, 200, { ok: true, warnings: validateFleet(cfg).warnings });
1698
1723
  return true;
1699
1724
  }
1700
1725
  if (method === "POST" || method === "PATCH") {