@songsid/agend 2.3.5-alpha.3 → 2.3.5-alpha.5

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 (865) hide show
  1. package/THIRD_PARTY_NOTICES.md +52 -0
  2. package/dist/accounts-view.d.ts +97 -0
  3. package/dist/accounts-view.js +116 -0
  4. package/dist/accounts-view.js.map +1 -0
  5. package/dist/agent-cli-instructions.md +1 -1
  6. package/dist/agent-credentials.d.ts +24 -0
  7. package/dist/agent-credentials.js +66 -0
  8. package/dist/agent-credentials.js.map +1 -0
  9. package/dist/agent-endpoint.d.ts +3 -1
  10. package/dist/agent-endpoint.js +13 -0
  11. package/dist/agent-endpoint.js.map +1 -1
  12. package/dist/agent-file-read.js +1 -1
  13. package/dist/agent-file-read.js.map +1 -1
  14. package/dist/agent-runtime-api.d.ts +4 -0
  15. package/dist/agent-runtime-api.js +59 -0
  16. package/dist/agent-runtime-api.js.map +1 -0
  17. package/dist/agent-runtime-change.d.ts +76 -0
  18. package/dist/agent-runtime-change.js +114 -0
  19. package/dist/agent-runtime-change.js.map +1 -0
  20. package/dist/agent-workspace.d.ts +93 -0
  21. package/dist/agent-workspace.js +353 -0
  22. package/dist/agent-workspace.js.map +1 -0
  23. package/dist/auth-api.d.ts +27 -0
  24. package/dist/auth-api.js +168 -3
  25. package/dist/auth-api.js.map +1 -1
  26. package/dist/authority/session-authorizations.d.ts +28 -4
  27. package/dist/authority/session-authorizations.js +63 -17
  28. package/dist/authority/session-authorizations.js.map +1 -1
  29. package/dist/backend/antigravity.js +3 -1
  30. package/dist/backend/antigravity.js.map +1 -1
  31. package/dist/backend/codex-footer-hints.d.ts +7 -0
  32. package/dist/backend/codex-footer-hints.js +41 -0
  33. package/dist/backend/codex-footer-hints.js.map +1 -0
  34. package/dist/backend/codex-metadata.d.ts +14 -0
  35. package/dist/backend/codex-metadata.js +45 -0
  36. package/dist/backend/codex-metadata.js.map +1 -1
  37. package/dist/backend/codex-quota-history.d.ts +7 -0
  38. package/dist/backend/codex-quota-history.js +57 -0
  39. package/dist/backend/codex-quota-history.js.map +1 -0
  40. package/dist/backend/codex-session-lookup.d.ts +6 -0
  41. package/dist/backend/codex-session-lookup.js +1 -1
  42. package/dist/backend/codex-session-lookup.js.map +1 -1
  43. package/dist/backend/codex-speed.d.ts +14 -0
  44. package/dist/backend/codex-speed.js +35 -0
  45. package/dist/backend/codex-speed.js.map +1 -0
  46. package/dist/backend/codex.d.ts +7 -0
  47. package/dist/backend/codex.js +85 -24
  48. package/dist/backend/codex.js.map +1 -1
  49. package/dist/backend/grok-weekly-reset.d.ts +24 -0
  50. package/dist/backend/grok-weekly-reset.js +95 -0
  51. package/dist/backend/grok-weekly-reset.js.map +1 -0
  52. package/dist/backend/grok.d.ts +30 -1
  53. package/dist/backend/grok.js +301 -54
  54. package/dist/backend/grok.js.map +1 -1
  55. package/dist/backend/kiro.d.ts +3 -0
  56. package/dist/backend/kiro.js +50 -2
  57. package/dist/backend/kiro.js.map +1 -1
  58. package/dist/backend/muse.js +5 -3
  59. package/dist/backend/muse.js.map +1 -1
  60. package/dist/backend/native-pane.d.ts +3 -1
  61. package/dist/backend/native-pane.js +2 -2
  62. package/dist/backend/native-pane.js.map +1 -1
  63. package/dist/backend/types.d.ts +13 -1
  64. package/dist/backend/types.js +3 -0
  65. package/dist/backend/types.js.map +1 -1
  66. package/dist/build-provenance-cli.d.ts +3 -0
  67. package/dist/build-provenance-cli.js +11 -0
  68. package/dist/build-provenance-cli.js.map +1 -0
  69. package/dist/build-provenance.d.ts +20 -0
  70. package/dist/build-provenance.js +67 -0
  71. package/dist/build-provenance.js.map +1 -0
  72. package/dist/build-provenance.json +1 -0
  73. package/dist/cache-ledger.d.ts +95 -0
  74. package/dist/cache-ledger.js +276 -4
  75. package/dist/cache-ledger.js.map +1 -1
  76. package/dist/cache-service.d.ts +5 -0
  77. package/dist/cache-service.js +16 -4
  78. package/dist/cache-service.js.map +1 -1
  79. package/dist/channel/adapters/discord.js +11 -3
  80. package/dist/channel/adapters/discord.js.map +1 -1
  81. package/dist/channel/adapters/telegram.d.ts +51 -0
  82. package/dist/channel/adapters/telegram.js +235 -17
  83. package/dist/channel/adapters/telegram.js.map +1 -1
  84. package/dist/channel/mcp-tools.js +3 -3
  85. package/dist/channel/mcp-tools.js.map +1 -1
  86. package/dist/channel/types.d.ts +2 -0
  87. package/dist/claude-auth-status.d.ts +48 -0
  88. package/dist/claude-auth-status.js +149 -0
  89. package/dist/claude-auth-status.js.map +1 -0
  90. package/dist/cli.js +138 -37
  91. package/dist/cli.js.map +1 -1
  92. package/dist/config-validator.js +21 -1
  93. package/dist/config-validator.js.map +1 -1
  94. package/dist/cross-instance-notice.d.ts +10 -0
  95. package/dist/cross-instance-notice.js +67 -5
  96. package/dist/cross-instance-notice.js.map +1 -1
  97. package/dist/daemon.d.ts +70 -1
  98. package/dist/daemon.js +547 -25
  99. package/dist/daemon.js.map +1 -1
  100. package/dist/dashboard-permissions.d.ts +8 -0
  101. package/dist/dashboard-permissions.js +16 -0
  102. package/dist/dashboard-permissions.js.map +1 -1
  103. package/dist/delivery-consumed-watch.d.ts +23 -1
  104. package/dist/delivery-consumed-watch.js +30 -3
  105. package/dist/delivery-consumed-watch.js.map +1 -1
  106. package/dist/delivery-reconciliation.d.ts +1 -1
  107. package/dist/delivery-reconciliation.js +1 -1
  108. package/dist/delivery-reconciliation.js.map +1 -1
  109. package/dist/doctor.js +20 -9
  110. package/dist/doctor.js.map +1 -1
  111. package/dist/export-import.d.ts +7 -0
  112. package/dist/export-import.js +44 -10
  113. package/dist/export-import.js.map +1 -1
  114. package/dist/fleet-context.d.ts +2 -0
  115. package/dist/fleet-manager.d.ts +362 -7
  116. package/dist/fleet-manager.js +1522 -91
  117. package/dist/fleet-manager.js.map +1 -1
  118. package/dist/fleet-windows-runtime.d.ts +8 -2
  119. package/dist/fleet-windows-runtime.js +93 -6
  120. package/dist/fleet-windows-runtime.js.map +1 -1
  121. package/dist/general-knowledge/skills/concepts/SKILL.md +425 -0
  122. package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
  123. package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +1 -0
  124. package/dist/general-knowledge/skills/fleet-health/SKILL.md +2 -2
  125. package/dist/general-knowledge/skills/instance-lifecycle/SKILL.md +3 -1
  126. package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +41 -4
  127. package/dist/general-knowledge/skills/session-management/SKILL.md +1 -1
  128. package/dist/general-knowledge/skills/tui-effort/SKILL.md +10 -10
  129. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +31 -15
  130. package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
  131. package/dist/general-role.d.ts +1 -1
  132. package/dist/general-role.js +1 -0
  133. package/dist/general-role.js.map +1 -1
  134. package/dist/hub/admission.d.ts +28 -0
  135. package/dist/hub/admission.js +62 -0
  136. package/dist/hub/admission.js.map +1 -0
  137. package/dist/hub/attachments/limits.d.ts +20 -0
  138. package/dist/hub/attachments/limits.js +48 -0
  139. package/dist/hub/attachments/limits.js.map +1 -0
  140. package/dist/hub/attachments/store.d.ts +116 -0
  141. package/dist/hub/attachments/store.js +246 -0
  142. package/dist/hub/attachments/store.js.map +1 -0
  143. package/dist/hub/audit/index.d.ts +62 -0
  144. package/dist/hub/audit/index.js +344 -0
  145. package/dist/hub/audit/index.js.map +1 -0
  146. package/dist/hub/browser-certificate.d.ts +38 -0
  147. package/dist/hub/browser-certificate.js +247 -0
  148. package/dist/hub/browser-certificate.js.map +1 -0
  149. package/dist/hub/buttons-model.d.ts +9 -0
  150. package/dist/hub/buttons-model.js +42 -0
  151. package/dist/hub/buttons-model.js.map +1 -0
  152. package/dist/hub/buttons.d.ts +54 -0
  153. package/dist/hub/buttons.js +346 -0
  154. package/dist/hub/buttons.js.map +1 -0
  155. package/dist/hub/catalog.d.ts +74 -0
  156. package/dist/hub/catalog.js +195 -0
  157. package/dist/hub/catalog.js.map +1 -0
  158. package/dist/hub/client.d.ts +69 -0
  159. package/dist/hub/client.js +300 -0
  160. package/dist/hub/client.js.map +1 -0
  161. package/dist/hub/compose/member.d.ts +139 -0
  162. package/dist/hub/compose/member.js +450 -0
  163. package/dist/hub/compose/member.js.map +1 -0
  164. package/dist/hub/compose/server.d.ts +77 -0
  165. package/dist/hub/compose/server.js +349 -0
  166. package/dist/hub/compose/server.js.map +1 -0
  167. package/dist/hub/compose/views.d.ts +12 -0
  168. package/dist/hub/compose/views.js +4 -0
  169. package/dist/hub/compose/views.js.map +1 -0
  170. package/dist/hub/db.d.ts +56 -0
  171. package/dist/hub/db.js +188 -0
  172. package/dist/hub/db.js.map +1 -0
  173. package/dist/hub/directory/config.d.ts +39 -0
  174. package/dist/hub/directory/config.js +108 -0
  175. package/dist/hub/directory/config.js.map +1 -0
  176. package/dist/hub/directory/directory.d.ts +18 -0
  177. package/dist/hub/directory/directory.js +320 -0
  178. package/dist/hub/directory/directory.js.map +1 -0
  179. package/dist/hub/directory/index.d.ts +7 -0
  180. package/dist/hub/directory/index.js +4 -0
  181. package/dist/hub/directory/index.js.map +1 -0
  182. package/dist/hub/directory/profiles.d.ts +41 -0
  183. package/dist/hub/directory/profiles.js +90 -0
  184. package/dist/hub/directory/profiles.js.map +1 -0
  185. package/dist/hub/directory/types.d.ts +71 -0
  186. package/dist/hub/directory/types.js +14 -0
  187. package/dist/hub/directory/types.js.map +1 -0
  188. package/dist/hub/execution/cli-provider.d.ts +23 -0
  189. package/dist/hub/execution/cli-provider.js +341 -0
  190. package/dist/hub/execution/cli-provider.js.map +1 -0
  191. package/dist/hub/execution/index.d.ts +13 -0
  192. package/dist/hub/execution/index.js +8 -0
  193. package/dist/hub/execution/index.js.map +1 -0
  194. package/dist/hub/execution/model-broker.d.ts +24 -0
  195. package/dist/hub/execution/model-broker.js +208 -0
  196. package/dist/hub/execution/model-broker.js.map +1 -0
  197. package/dist/hub/execution/provider-setup.d.ts +11 -0
  198. package/dist/hub/execution/provider-setup.js +21 -0
  199. package/dist/hub/execution/provider-setup.js.map +1 -0
  200. package/dist/hub/execution/sandbox-runner.d.ts +1 -0
  201. package/dist/hub/execution/sandbox-runner.js +221 -0
  202. package/dist/hub/execution/sandbox-runner.js.map +1 -0
  203. package/dist/hub/execution/service.d.ts +136 -0
  204. package/dist/hub/execution/service.js +459 -0
  205. package/dist/hub/execution/service.js.map +1 -0
  206. package/dist/hub/execution/store.d.ts +61 -0
  207. package/dist/hub/execution/store.js +182 -0
  208. package/dist/hub/execution/store.js.map +1 -0
  209. package/dist/hub/execution/views.d.ts +20 -0
  210. package/dist/hub/execution/views.js +48 -0
  211. package/dist/hub/execution/views.js.map +1 -0
  212. package/dist/hub/http/compose.d.ts +20 -0
  213. package/dist/hub/http/compose.js +518 -0
  214. package/dist/hub/http/compose.js.map +1 -0
  215. package/dist/hub/http/core.d.ts +49 -0
  216. package/dist/hub/http/core.js +124 -0
  217. package/dist/hub/http/core.js.map +1 -0
  218. package/dist/hub/http/deps.d.ts +61 -0
  219. package/dist/hub/http/deps.js +2 -0
  220. package/dist/hub/http/deps.js.map +1 -0
  221. package/dist/hub/http/schema.d.ts +14 -0
  222. package/dist/hub/http/schema.js +80 -0
  223. package/dist/hub/http/schema.js.map +1 -0
  224. package/dist/hub/identity.d.ts +32 -0
  225. package/dist/hub/identity.js +80 -0
  226. package/dist/hub/identity.js.map +1 -0
  227. package/dist/hub/init/browser-certificate.d.ts +9 -0
  228. package/dist/hub/init/browser-certificate.js +78 -0
  229. package/dist/hub/init/browser-certificate.js.map +1 -0
  230. package/dist/hub/init/browser-tls.d.ts +18 -0
  231. package/dist/hub/init/browser-tls.js +62 -0
  232. package/dist/hub/init/browser-tls.js.map +1 -0
  233. package/dist/hub/init/cli.d.ts +3 -0
  234. package/dist/hub/init/cli.js +83 -0
  235. package/dist/hub/init/cli.js.map +1 -0
  236. package/dist/hub/init/directory-certificate.d.ts +24 -0
  237. package/dist/hub/init/directory-certificate.js +222 -0
  238. package/dist/hub/init/directory-certificate.js.map +1 -0
  239. package/dist/hub/init/existing-fleet.d.ts +6 -0
  240. package/dist/hub/init/existing-fleet.js +58 -0
  241. package/dist/hub/init/existing-fleet.js.map +1 -0
  242. package/dist/hub/init/handoff.d.ts +8 -0
  243. package/dist/hub/init/handoff.js +36 -0
  244. package/dist/hub/init/handoff.js.map +1 -0
  245. package/dist/hub/init/identity.d.ts +5 -0
  246. package/dist/hub/init/identity.js +24 -0
  247. package/dist/hub/init/identity.js.map +1 -0
  248. package/dist/hub/init/initializer.d.ts +24 -0
  249. package/dist/hub/init/initializer.js +385 -0
  250. package/dist/hub/init/initializer.js.map +1 -0
  251. package/dist/hub/init/inventory.d.ts +17 -0
  252. package/dist/hub/init/inventory.js +33 -0
  253. package/dist/hub/init/inventory.js.map +1 -0
  254. package/dist/hub/init/layout.d.ts +32 -0
  255. package/dist/hub/init/layout.js +53 -0
  256. package/dist/hub/init/layout.js.map +1 -0
  257. package/dist/hub/init/network.d.ts +18 -0
  258. package/dist/hub/init/network.js +104 -0
  259. package/dist/hub/init/network.js.map +1 -0
  260. package/dist/hub/init/plan-digest.d.ts +5 -0
  261. package/dist/hub/init/plan-digest.js +47 -0
  262. package/dist/hub/init/plan-digest.js.map +1 -0
  263. package/dist/hub/init/prompt.d.ts +26 -0
  264. package/dist/hub/init/prompt.js +110 -0
  265. package/dist/hub/init/prompt.js.map +1 -0
  266. package/dist/hub/init/secret-file.d.ts +1 -0
  267. package/dist/hub/init/secret-file.js +59 -0
  268. package/dist/hub/init/secret-file.js.map +1 -0
  269. package/dist/hub/init/text.d.ts +127 -0
  270. package/dist/hub/init/text.js +247 -0
  271. package/dist/hub/init/text.js.map +1 -0
  272. package/dist/hub/init/types.d.ts +114 -0
  273. package/dist/hub/init/types.js +9 -0
  274. package/dist/hub/init/types.js.map +1 -0
  275. package/dist/hub/init/wizard.d.ts +34 -0
  276. package/dist/hub/init/wizard.js +554 -0
  277. package/dist/hub/init/wizard.js.map +1 -0
  278. package/dist/hub/initialization.d.ts +23 -0
  279. package/dist/hub/initialization.js +28 -0
  280. package/dist/hub/initialization.js.map +1 -0
  281. package/dist/hub/member/agent-mode.d.ts +6 -0
  282. package/dist/hub/member/agent-mode.js +23 -0
  283. package/dist/hub/member/agent-mode.js.map +1 -0
  284. package/dist/hub/member/attachments.d.ts +29 -0
  285. package/dist/hub/member/attachments.js +107 -0
  286. package/dist/hub/member/attachments.js.map +1 -0
  287. package/dist/hub/member/exposure-api.d.ts +87 -0
  288. package/dist/hub/member/exposure-api.js +64 -0
  289. package/dist/hub/member/exposure-api.js.map +1 -0
  290. package/dist/hub/member/exposures.d.ts +123 -0
  291. package/dist/hub/member/exposures.js +282 -0
  292. package/dist/hub/member/exposures.js.map +1 -0
  293. package/dist/hub/member/pairing-api.d.ts +85 -0
  294. package/dist/hub/member/pairing-api.js +385 -0
  295. package/dist/hub/member/pairing-api.js.map +1 -0
  296. package/dist/hub/member/quota.d.ts +20 -0
  297. package/dist/hub/member/quota.js +98 -0
  298. package/dist/hub/member/quota.js.map +1 -0
  299. package/dist/hub/member-journal.d.ts +104 -0
  300. package/dist/hub/member-journal.js +336 -0
  301. package/dist/hub/member-journal.js.map +1 -0
  302. package/dist/hub/member-reconciliation.d.ts +14 -0
  303. package/dist/hub/member-reconciliation.js +97 -0
  304. package/dist/hub/member-reconciliation.js.map +1 -0
  305. package/dist/hub/mount.d.ts +39 -0
  306. package/dist/hub/mount.js +123 -0
  307. package/dist/hub/mount.js.map +1 -0
  308. package/dist/hub/pairing-client.d.ts +17 -0
  309. package/dist/hub/pairing-client.js +108 -0
  310. package/dist/hub/pairing-client.js.map +1 -0
  311. package/dist/hub/pairing.d.ts +65 -0
  312. package/dist/hub/pairing.js +211 -0
  313. package/dist/hub/pairing.js.map +1 -0
  314. package/dist/hub/policy.d.ts +63 -0
  315. package/dist/hub/policy.js +147 -0
  316. package/dist/hub/policy.js.map +1 -0
  317. package/dist/hub/preview.d.ts +32 -0
  318. package/dist/hub/preview.js +64 -0
  319. package/dist/hub/preview.js.map +1 -0
  320. package/dist/hub/private-files.d.ts +5 -0
  321. package/dist/hub/private-files.js +44 -0
  322. package/dist/hub/private-files.js.map +1 -0
  323. package/dist/hub/profile.d.ts +59 -0
  324. package/dist/hub/profile.js +73 -0
  325. package/dist/hub/profile.js.map +1 -0
  326. package/dist/hub/protocol.d.ts +779 -0
  327. package/dist/hub/protocol.js +93 -0
  328. package/dist/hub/protocol.js.map +1 -0
  329. package/dist/hub/quota.d.ts +24 -0
  330. package/dist/hub/quota.js +112 -0
  331. package/dist/hub/quota.js.map +1 -0
  332. package/dist/hub/representative.d.ts +141 -0
  333. package/dist/hub/representative.js +528 -0
  334. package/dist/hub/representative.js.map +1 -0
  335. package/dist/hub/retention.d.ts +17 -0
  336. package/dist/hub/retention.js +45 -0
  337. package/dist/hub/retention.js.map +1 -0
  338. package/dist/hub/rooms.d.ts +120 -0
  339. package/dist/hub/rooms.js +535 -0
  340. package/dist/hub/rooms.js.map +1 -0
  341. package/dist/hub/runtime.d.ts +106 -0
  342. package/dist/hub/runtime.js +298 -0
  343. package/dist/hub/runtime.js.map +1 -0
  344. package/dist/hub/server.d.ts +56 -0
  345. package/dist/hub/server.js +202 -0
  346. package/dist/hub/server.js.map +1 -0
  347. package/dist/hub/service-start.d.ts +17 -0
  348. package/dist/hub/service-start.js +109 -0
  349. package/dist/hub/service-start.js.map +1 -0
  350. package/dist/hub/sessions.d.ts +53 -0
  351. package/dist/hub/sessions.js +196 -0
  352. package/dist/hub/sessions.js.map +1 -0
  353. package/dist/hub/socket.d.ts +24 -0
  354. package/dist/hub/socket.js +79 -0
  355. package/dist/hub/socket.js.map +1 -0
  356. package/dist/hub/store.d.ts +77 -0
  357. package/dist/hub/store.js +88 -0
  358. package/dist/hub/store.js.map +1 -0
  359. package/dist/hub/tls.d.ts +31 -0
  360. package/dist/hub/tls.js +135 -0
  361. package/dist/hub/tls.js.map +1 -0
  362. package/dist/hub/types.d.ts +401 -0
  363. package/dist/hub/types.js +2 -0
  364. package/dist/hub/types.js.map +1 -0
  365. package/dist/hub/validation.d.ts +33 -0
  366. package/dist/hub/validation.js +136 -0
  367. package/dist/hub/validation.js.map +1 -0
  368. package/dist/hub/version-floor.d.ts +10 -0
  369. package/dist/hub/version-floor.js +45 -0
  370. package/dist/hub/version-floor.js.map +1 -0
  371. package/dist/hub-browser-certificate-policy.d.ts +31 -0
  372. package/dist/hub-browser-certificate-policy.js +25 -0
  373. package/dist/hub-browser-certificate-policy.js.map +1 -0
  374. package/dist/hub-membership-settings.d.ts +6 -0
  375. package/dist/hub-membership-settings.js +21 -0
  376. package/dist/hub-membership-settings.js.map +1 -0
  377. package/dist/hub-mode.d.ts +15 -0
  378. package/dist/hub-mode.js +17 -0
  379. package/dist/hub-mode.js.map +1 -0
  380. package/dist/hub-pairing-summary.d.ts +48 -0
  381. package/dist/hub-pairing-summary.js +36 -0
  382. package/dist/hub-pairing-summary.js.map +1 -0
  383. package/dist/hub-report-target.d.ts +32 -0
  384. package/dist/hub-report-target.js +33 -0
  385. package/dist/hub-report-target.js.map +1 -0
  386. package/dist/hub-retention-policy.d.ts +14 -0
  387. package/dist/hub-retention-policy.js +15 -0
  388. package/dist/hub-retention-policy.js.map +1 -0
  389. package/dist/instance-config-impact.js +3 -0
  390. package/dist/instance-config-impact.js.map +1 -1
  391. package/dist/instance-lifecycle.d.ts +17 -2
  392. package/dist/instance-lifecycle.js +58 -8
  393. package/dist/instance-lifecycle.js.map +1 -1
  394. package/dist/instance-topic-delete.d.ts +77 -0
  395. package/dist/instance-topic-delete.js +123 -0
  396. package/dist/instance-topic-delete.js.map +1 -0
  397. package/dist/instructions.d.ts +1 -1
  398. package/dist/instructions.js +1 -1
  399. package/dist/instructions.js.map +1 -1
  400. package/dist/kiro-engine-status.d.ts +11 -0
  401. package/dist/kiro-engine-status.js +6 -0
  402. package/dist/kiro-engine-status.js.map +1 -1
  403. package/dist/launchd-service-domain.d.ts +5 -0
  404. package/dist/launchd-service-domain.js +21 -0
  405. package/dist/launchd-service-domain.js.map +1 -0
  406. package/dist/locale.js +125 -3
  407. package/dist/locale.js.map +1 -1
  408. package/dist/log-service.d.ts +28 -0
  409. package/dist/log-service.js +29 -0
  410. package/dist/log-service.js.map +1 -1
  411. package/dist/log-steps.d.ts +4 -3
  412. package/dist/log-steps.js +32 -7
  413. package/dist/log-steps.js.map +1 -1
  414. package/dist/logger.d.ts +16 -2
  415. package/dist/logger.js +346 -66
  416. package/dist/logger.js.map +1 -1
  417. package/dist/login-flows.d.ts +15 -7
  418. package/dist/login-flows.js +29 -3
  419. package/dist/login-flows.js.map +1 -1
  420. package/dist/login-manager.js +25 -4
  421. package/dist/login-manager.js.map +1 -1
  422. package/dist/ls-rows.js +3 -4
  423. package/dist/ls-rows.js.map +1 -1
  424. package/dist/missed-offline.d.ts +25 -0
  425. package/dist/missed-offline.js +79 -0
  426. package/dist/missed-offline.js.map +1 -0
  427. package/dist/native-instance-api.d.ts +0 -1
  428. package/dist/native-instance-api.js +15 -3
  429. package/dist/native-instance-api.js.map +1 -1
  430. package/dist/native-instance-input.d.ts +3 -0
  431. package/dist/native-instance-input.js +6 -1
  432. package/dist/native-instance-input.js.map +1 -1
  433. package/dist/native-instance-registry.d.ts +6 -0
  434. package/dist/native-instance-registry.js +24 -0
  435. package/dist/native-instance-registry.js.map +1 -1
  436. package/dist/native-mcp.d.ts +3 -0
  437. package/dist/native-mcp.js +15 -2
  438. package/dist/native-mcp.js.map +1 -1
  439. package/dist/native-pane-lifecycle.d.ts +8 -0
  440. package/dist/native-pane-lifecycle.js +13 -4
  441. package/dist/native-pane-lifecycle.js.map +1 -1
  442. package/dist/native-pane-manager.js +17 -9
  443. package/dist/native-pane-manager.js.map +1 -1
  444. package/dist/needs-you-hub.d.ts +9 -1
  445. package/dist/needs-you-hub.js +46 -8
  446. package/dist/needs-you-hub.js.map +1 -1
  447. package/dist/needs-you.d.ts +47 -2
  448. package/dist/needs-you.js +31 -3
  449. package/dist/needs-you.js.map +1 -1
  450. package/dist/office-share-page.js +3 -3
  451. package/dist/office-share-page.js.map +1 -1
  452. package/dist/office-share.d.ts +11 -0
  453. package/dist/office-share.js +14 -0
  454. package/dist/office-share.js.map +1 -1
  455. package/dist/office-talk.d.ts +26 -0
  456. package/dist/office-talk.js +50 -0
  457. package/dist/office-talk.js.map +1 -0
  458. package/dist/outbound-handlers.d.ts +14 -0
  459. package/dist/outbound-handlers.js +49 -6
  460. package/dist/outbound-handlers.js.map +1 -1
  461. package/dist/outbound-schemas.d.ts +33 -1
  462. package/dist/outbound-schemas.js +29 -16
  463. package/dist/outbound-schemas.js.map +1 -1
  464. package/dist/pane-quota-history.d.ts +9 -0
  465. package/dist/pane-quota-history.js +67 -0
  466. package/dist/pane-quota-history.js.map +1 -0
  467. package/dist/pause-marker.d.ts +1 -1
  468. package/dist/pause-marker.js +1 -1
  469. package/dist/pause-marker.js.map +1 -1
  470. package/dist/platform-general.d.ts +46 -0
  471. package/dist/platform-general.js +91 -0
  472. package/dist/platform-general.js.map +1 -0
  473. package/dist/public-web-gateway.js +7 -0
  474. package/dist/public-web-gateway.js.map +1 -1
  475. package/dist/public-web-link.d.ts +6 -0
  476. package/dist/public-web-link.js +9 -0
  477. package/dist/public-web-link.js.map +1 -1
  478. package/dist/queued-handoffs.d.ts +33 -0
  479. package/dist/queued-handoffs.js +75 -0
  480. package/dist/queued-handoffs.js.map +1 -0
  481. package/dist/quickstart.d.ts +13 -0
  482. package/dist/quickstart.js +81 -5
  483. package/dist/quickstart.js.map +1 -1
  484. package/dist/quota-notice.d.ts +7 -0
  485. package/dist/quota-notice.js +40 -0
  486. package/dist/quota-notice.js.map +1 -1
  487. package/dist/reply-buttons-controller.js +10 -6
  488. package/dist/reply-buttons-controller.js.map +1 -1
  489. package/dist/reply-polls.d.ts +2 -2
  490. package/dist/reply-polls.js +3 -3
  491. package/dist/reply-polls.js.map +1 -1
  492. package/dist/runtime-api.d.ts +2 -0
  493. package/dist/runtime-api.js +106 -13
  494. package/dist/runtime-api.js.map +1 -1
  495. package/dist/runtime-build-info.d.ts +9 -0
  496. package/dist/runtime-build-info.js +59 -0
  497. package/dist/runtime-build-info.js.map +1 -0
  498. package/dist/runtime-bundle.d.ts +6 -1
  499. package/dist/runtime-bundle.js +17 -9
  500. package/dist/runtime-bundle.js.map +1 -1
  501. package/dist/runtime-cli.d.ts +13 -1
  502. package/dist/runtime-cli.js +173 -19
  503. package/dist/runtime-cli.js.map +1 -1
  504. package/dist/runtime-client-store.d.ts +27 -1
  505. package/dist/runtime-client-store.js +86 -6
  506. package/dist/runtime-client-store.js.map +1 -1
  507. package/dist/runtime-client.d.ts +74 -0
  508. package/dist/runtime-client.js +336 -26
  509. package/dist/runtime-client.js.map +1 -1
  510. package/dist/runtime-connection.d.ts +22 -0
  511. package/dist/runtime-connection.js +93 -0
  512. package/dist/runtime-connection.js.map +1 -0
  513. package/dist/runtime-coordinator.d.ts +16 -0
  514. package/dist/runtime-coordinator.js +287 -62
  515. package/dist/runtime-coordinator.js.map +1 -1
  516. package/dist/runtime-credential-profiles.d.ts +78 -0
  517. package/dist/runtime-credential-profiles.js +280 -0
  518. package/dist/runtime-credential-profiles.js.map +1 -0
  519. package/dist/runtime-install.d.ts +50 -0
  520. package/dist/runtime-install.js +186 -0
  521. package/dist/runtime-install.js.map +1 -0
  522. package/dist/runtime-pane-assets.d.ts +1 -1
  523. package/dist/runtime-pane-assets.js +1 -1
  524. package/dist/runtime-pane-assets.js.map +1 -1
  525. package/dist/runtime-pane-boot.d.ts +7 -0
  526. package/dist/runtime-pane-boot.js +23 -0
  527. package/dist/runtime-pane-boot.js.map +1 -1
  528. package/dist/runtime-pane-codex-index.d.ts +10 -1
  529. package/dist/runtime-pane-codex-index.js +131 -27
  530. package/dist/runtime-pane-codex-index.js.map +1 -1
  531. package/dist/runtime-pane-host.d.ts +19 -0
  532. package/dist/runtime-pane-host.js +50 -7
  533. package/dist/runtime-pane-host.js.map +1 -1
  534. package/dist/runtime-pane-link.d.ts +7 -0
  535. package/dist/runtime-pane-link.js +93 -2
  536. package/dist/runtime-pane-link.js.map +1 -1
  537. package/dist/runtime-pane-mcp-relay.d.ts +1 -0
  538. package/dist/runtime-pane-mcp-relay.js +10 -0
  539. package/dist/runtime-pane-mcp-relay.js.map +1 -1
  540. package/dist/runtime-pane-mcp.d.ts +4 -0
  541. package/dist/runtime-pane-mcp.js +6 -3
  542. package/dist/runtime-pane-mcp.js.map +1 -1
  543. package/dist/runtime-pane-native.d.ts +32 -2
  544. package/dist/runtime-pane-native.js +55 -6
  545. package/dist/runtime-pane-native.js.map +1 -1
  546. package/dist/runtime-pane-port.d.ts +5 -0
  547. package/dist/runtime-pane-port.js +17 -1
  548. package/dist/runtime-pane-port.js.map +1 -1
  549. package/dist/runtime-pane-process.d.ts +1 -1
  550. package/dist/runtime-pane-process.js +11 -2
  551. package/dist/runtime-pane-process.js.map +1 -1
  552. package/dist/runtime-pane-protocol.d.ts +11 -1
  553. package/dist/runtime-pane-protocol.js +27 -5
  554. package/dist/runtime-pane-protocol.js.map +1 -1
  555. package/dist/runtime-pane-quota-history.d.ts +6 -0
  556. package/dist/runtime-pane-quota-history.js +44 -0
  557. package/dist/runtime-pane-quota-history.js.map +1 -0
  558. package/dist/runtime-pane-service.d.ts +5 -0
  559. package/dist/runtime-pane-service.js +47 -12
  560. package/dist/runtime-pane-service.js.map +1 -1
  561. package/dist/runtime-pane-transcript.d.ts +5 -0
  562. package/dist/runtime-pane-transcript.js +66 -5
  563. package/dist/runtime-pane-transcript.js.map +1 -1
  564. package/dist/runtime-pane-worker.js +19 -6
  565. package/dist/runtime-pane-worker.js.map +1 -1
  566. package/dist/runtime-protocol.d.ts +30 -2
  567. package/dist/runtime-protocol.js +30 -0
  568. package/dist/runtime-protocol.js.map +1 -1
  569. package/dist/runtime-update-activity.d.ts +21 -0
  570. package/dist/runtime-update-activity.js +51 -0
  571. package/dist/runtime-update-activity.js.map +1 -0
  572. package/dist/runtime-update-artifact.d.ts +31 -0
  573. package/dist/runtime-update-artifact.js +252 -0
  574. package/dist/runtime-update-artifact.js.map +1 -0
  575. package/dist/runtime-update-install.d.ts +31 -0
  576. package/dist/runtime-update-install.js +205 -0
  577. package/dist/runtime-update-install.js.map +1 -0
  578. package/dist/runtime-update-journal.d.ts +44 -0
  579. package/dist/runtime-update-journal.js +121 -0
  580. package/dist/runtime-update-journal.js.map +1 -0
  581. package/dist/runtime-update-lock.d.ts +48 -0
  582. package/dist/runtime-update-lock.js +217 -0
  583. package/dist/runtime-update-lock.js.map +1 -0
  584. package/dist/runtime-update-owners.d.ts +29 -0
  585. package/dist/runtime-update-owners.js +240 -0
  586. package/dist/runtime-update-owners.js.map +1 -0
  587. package/dist/runtime-update-protocol.d.ts +15 -0
  588. package/dist/runtime-update-protocol.js +13 -0
  589. package/dist/runtime-update-protocol.js.map +1 -0
  590. package/dist/runtime-windows-bridge.d.ts +2 -1
  591. package/dist/runtime-windows-bridge.js +11 -1
  592. package/dist/runtime-windows-bridge.js.map +1 -1
  593. package/dist/scheduler/db.d.ts +2 -1
  594. package/dist/scheduler/db.js +23 -9
  595. package/dist/scheduler/db.js.map +1 -1
  596. package/dist/scheduler/task-board-text.js +1 -1
  597. package/dist/scheduler/task-board-text.js.map +1 -1
  598. package/dist/scheduler/task-board.d.ts +13 -0
  599. package/dist/scheduler/task-board.js +28 -3
  600. package/dist/scheduler/task-board.js.map +1 -1
  601. package/dist/service-drain.d.ts +19 -0
  602. package/dist/service-drain.js +64 -0
  603. package/dist/service-drain.js.map +1 -0
  604. package/dist/service-installer.d.ts +7 -2
  605. package/dist/service-installer.js +13 -10
  606. package/dist/service-installer.js.map +1 -1
  607. package/dist/settings-api.d.ts +20 -0
  608. package/dist/settings-api.js +414 -4
  609. package/dist/settings-api.js.map +1 -1
  610. package/dist/settings-baseline.d.ts +6 -0
  611. package/dist/settings-baseline.js +3 -1
  612. package/dist/settings-baseline.js.map +1 -1
  613. package/dist/settings-change.js +29 -6
  614. package/dist/settings-change.js.map +1 -1
  615. package/dist/settings-effect.d.ts +13 -0
  616. package/dist/settings-effect.js +98 -1
  617. package/dist/settings-effect.js.map +1 -1
  618. package/dist/settings-http-confirmation.d.ts +3 -0
  619. package/dist/settings-http-confirmation.js +28 -1
  620. package/dist/settings-http-confirmation.js.map +1 -1
  621. package/dist/settings-instance-patch.js +27 -0
  622. package/dist/settings-instance-patch.js.map +1 -1
  623. package/dist/setup-wizard.js +6 -2
  624. package/dist/setup-wizard.js.map +1 -1
  625. package/dist/task-board-tool.d.ts +13 -1
  626. package/dist/task-board-tool.js +104 -4
  627. package/dist/task-board-tool.js.map +1 -1
  628. package/dist/task-board-waker.d.ts +6 -0
  629. package/dist/task-board-waker.js +4 -0
  630. package/dist/task-board-waker.js.map +1 -1
  631. package/dist/tmux-binary.d.ts +59 -0
  632. package/dist/tmux-binary.js +200 -0
  633. package/dist/tmux-binary.js.map +1 -0
  634. package/dist/tmux-control.js +4 -4
  635. package/dist/tmux-control.js.map +1 -1
  636. package/dist/tmux-exec-helper.js +32 -1
  637. package/dist/tmux-exec-helper.js.map +1 -1
  638. package/dist/tmux-manager.d.ts +1 -1
  639. package/dist/tmux-manager.js +45 -36
  640. package/dist/tmux-manager.js.map +1 -1
  641. package/dist/tmux-read.js +4 -3
  642. package/dist/tmux-read.js.map +1 -1
  643. package/dist/tool-permissions.d.ts +5 -2
  644. package/dist/tool-permissions.js +6 -5
  645. package/dist/tool-permissions.js.map +1 -1
  646. package/dist/tool-progress.d.ts +2 -0
  647. package/dist/tool-progress.js +19 -3
  648. package/dist/tool-progress.js.map +1 -1
  649. package/dist/topic-commands.js +10 -5
  650. package/dist/topic-commands.js.map +1 -1
  651. package/dist/transcript-monitor.d.ts +20 -0
  652. package/dist/transcript-monitor.js +47 -3
  653. package/dist/transcript-monitor.js.map +1 -1
  654. package/dist/transcript-needles.d.ts +7 -0
  655. package/dist/transcript-needles.js +9 -1
  656. package/dist/transcript-needles.js.map +1 -1
  657. package/dist/transcript-records.d.ts +1 -1
  658. package/dist/transcript-records.js +2 -1
  659. package/dist/transcript-records.js.map +1 -1
  660. package/dist/types.d.ts +6 -0
  661. package/dist/ui/account-identity.js +27 -0
  662. package/dist/ui/accounts-view.js +214 -0
  663. package/dist/ui/agent-runtime-settings.js +68 -0
  664. package/dist/ui/agent-runtime.js +20 -2
  665. package/dist/ui/backend-signin.js +39 -21
  666. package/dist/ui/chat-ambient.js +1 -1
  667. package/dist/ui/chat-md-strings.js +3 -0
  668. package/dist/ui/chat-render.js +3 -670
  669. package/dist/ui/chat-store.js +1 -1
  670. package/dist/ui/chat-strings.js +3 -333
  671. package/dist/ui/chat-thread.js +3 -919
  672. package/dist/ui/chat-time.js +3 -80
  673. package/dist/ui/chat-tour.js +1 -1
  674. package/dist/ui/credential-profile-select.js +54 -0
  675. package/dist/ui/fleet-office-dialogue.d.ts +30 -0
  676. package/dist/ui/fleet-office-dialogue.js +382 -0
  677. package/dist/ui/fleet-office-pack.d.ts +9 -0
  678. package/dist/ui/fleet-office-pack.js +76 -4
  679. package/dist/ui/fleet-office-skin.js +23 -5
  680. package/dist/ui/fleet-office-store.js +5 -0
  681. package/dist/ui/fleet-office.js +173 -6
  682. package/dist/ui/fleet-task-card.js +10 -6
  683. package/dist/ui/fleet-task-common.js +12 -2
  684. package/dist/ui/fleet-task-menu.js +188 -0
  685. package/dist/ui/fleet-task-stats.js +124 -0
  686. package/dist/ui/fleet-task-view.js +340 -0
  687. package/dist/ui/fleet-tasks.js +131 -43
  688. package/dist/ui/fleet-usage.js +90 -27
  689. package/dist/ui/html-attachment.js +3 -40
  690. package/dist/ui/hub-agent-copy.js +23 -0
  691. package/dist/ui/hub-button-actions.js +65 -0
  692. package/dist/ui/hub-chat-store.js +158 -0
  693. package/dist/ui/hub-chat-strings.js +77 -0
  694. package/dist/ui/hub-client.js +329 -0
  695. package/dist/ui/hub-owner-strings.js +51 -0
  696. package/dist/ui/hub-provider-guidance.js +31 -0
  697. package/dist/ui/hub-quota.js +85 -0
  698. package/dist/ui/hub-strings.js +162 -0
  699. package/dist/ui/hub-switcher.js +27 -0
  700. package/dist/ui/native-instance-settings.js +5 -8
  701. package/dist/ui/native-pane-recovery.js +1 -1
  702. package/dist/ui/office-share-page.js +4 -2
  703. package/dist/ui/panel-chat.js +36 -49
  704. package/dist/ui/panel-details.js +1 -1
  705. package/dist/ui/panel-fleet.js +82 -12
  706. package/dist/ui/panel-hub.js +619 -0
  707. package/dist/ui/panel-log.js +2 -2
  708. package/dist/ui/panel-needs.js +24 -8
  709. package/dist/ui/panel-runtimes.js +239 -45
  710. package/dist/ui/panel-settings.js +266 -192
  711. package/dist/ui/panel-windows-cli.js +88 -42
  712. package/dist/ui/preview-pages.js +1 -1
  713. package/dist/ui/preview-panel.js +92 -6
  714. package/dist/ui/preview-versions.js +1 -1
  715. package/dist/ui/preview.js +3 -476
  716. package/dist/ui/runtime-commands.d.ts +4 -0
  717. package/dist/ui/runtime-commands.js +59 -0
  718. package/dist/ui/search-dialog.js +2 -0
  719. package/dist/ui/settings-access-strings.js +42 -0
  720. package/dist/ui/settings-agent-filters.js +94 -0
  721. package/dist/ui/settings-appearance.js +122 -23
  722. package/dist/ui/settings-build-version.js +35 -0
  723. package/dist/ui/settings-codex-copy.js +19 -0
  724. package/dist/ui/settings-devices.js +253 -0
  725. package/dist/ui/settings-dialogs.js +33 -12
  726. package/dist/ui/settings-guests.js +25 -11
  727. package/dist/ui/settings-hub-browser-certificate.js +74 -0
  728. package/dist/ui/settings-hub-membership.js +72 -0
  729. package/dist/ui/settings-hub-retention.js +52 -0
  730. package/dist/ui/settings-hub.js +196 -0
  731. package/dist/ui/settings-layout.js +242 -0
  732. package/dist/ui/settings-model.js +24 -2
  733. package/dist/ui/settings-outside.js +104 -38
  734. package/dist/ui/settings-registry.js +9 -4
  735. package/dist/ui/settings-shared-strings.js +143 -0
  736. package/dist/ui/settings-shared.js +345 -0
  737. package/dist/ui/settings-shortcuts.js +65 -0
  738. package/dist/ui/settings-strings.js +89 -32
  739. package/dist/ui/settings-web-authority.js +17 -11
  740. package/dist/ui/shared/accounts.css +15 -0
  741. package/dist/ui/shared/app-i18n.js +2 -2
  742. package/dist/ui/shared/app-needs.js +1 -1
  743. package/dist/ui/shared/app-route.js +6 -1
  744. package/dist/ui/shared/app-session.js +6 -2
  745. package/dist/ui/shared/app-shell.js +81 -15
  746. package/dist/ui/shared/app.css +1114 -13
  747. package/dist/ui/shared/app.js +12 -3
  748. package/dist/ui/shared/chat-composer.js +68 -0
  749. package/dist/ui/shared/chat-md-strings.js +9 -0
  750. package/dist/ui/shared/chat-render.js +682 -0
  751. package/dist/ui/shared/chat-strings.js +333 -0
  752. package/dist/ui/shared/chat-thread.js +969 -0
  753. package/dist/ui/shared/chat-time.js +80 -0
  754. package/dist/ui/shared/header-tools.js +3 -5
  755. package/dist/ui/shared/html-attachment.js +42 -0
  756. package/dist/ui/shared/hub-chat.css +85 -0
  757. package/dist/ui/shared/hub-owner.css +33 -0
  758. package/dist/ui/shared/hub-quota.css +8 -0
  759. package/dist/ui/shared/hub.css +71 -0
  760. package/dist/ui/shared/instance-nav.js +3 -2
  761. package/dist/ui/shared/machine-name.js +13 -0
  762. package/dist/ui/shared/page-head.js +8 -0
  763. package/dist/ui/shared/panel-view.js +77 -4
  764. package/dist/ui/shared/preview.js +476 -0
  765. package/dist/ui/shared/runtime-install.css +26 -0
  766. package/dist/ui/shared/settings-width.js +31 -0
  767. package/dist/ui/shared/side-rail.js +15 -0
  768. package/dist/ui/shared/signin.js +172 -0
  769. package/dist/ui/shared/task-board.css +95 -0
  770. package/dist/ui/shared/tokens.css +1 -0
  771. package/dist/ui/shared/ui-dialog.js +2 -2
  772. package/dist/ui/shared/ui-menu.js +3 -3
  773. package/dist/ui/shared/usage-dialog.js +18 -1
  774. package/dist/ui/shared/view-history.css +17 -0
  775. package/dist/ui/shared/view-history.js +438 -0
  776. package/dist/ui/shared/view-strings.js +16 -0
  777. package/dist/ui/shared/workspace.css +20 -0
  778. package/dist/ui/signin.html +21 -0
  779. package/dist/ui/windows-cli-catalog.js +41 -12
  780. package/dist/ui/workspace-panel.js +189 -0
  781. package/dist/ui/workspace-strings.js +35 -0
  782. package/dist/unattended-install.d.ts +11 -2
  783. package/dist/unattended-install.js +41 -6
  784. package/dist/unattended-install.js.map +1 -1
  785. package/dist/usage/capacity.d.ts +69 -0
  786. package/dist/usage/capacity.js +119 -0
  787. package/dist/usage/capacity.js.map +1 -0
  788. package/dist/usage/i18n-keys.d.ts +1 -1
  789. package/dist/usage/i18n-keys.js +3 -0
  790. package/dist/usage/i18n-keys.js.map +1 -1
  791. package/dist/usage/profile-timeline.d.ts +16 -0
  792. package/dist/usage/profile-timeline.js +58 -0
  793. package/dist/usage/profile-timeline.js.map +1 -0
  794. package/dist/usage/providers.js +2 -1
  795. package/dist/usage/providers.js.map +1 -1
  796. package/dist/usage/quota-history.d.ts +43 -0
  797. package/dist/usage/quota-history.js +168 -0
  798. package/dist/usage/quota-history.js.map +1 -0
  799. package/dist/usage/usage-api.d.ts +31 -0
  800. package/dist/usage/usage-api.js +80 -1
  801. package/dist/usage/usage-api.js.map +1 -1
  802. package/dist/usage-report.d.ts +25 -1
  803. package/dist/usage-report.js +55 -4
  804. package/dist/usage-report.js.map +1 -1
  805. package/dist/usage-rollup.d.ts +6 -1
  806. package/dist/usage-rollup.js +16 -4
  807. package/dist/usage-rollup.js.map +1 -1
  808. package/dist/view-api.d.ts +16 -0
  809. package/dist/view-api.js +105 -23
  810. package/dist/view-api.js.map +1 -1
  811. package/dist/view-history.d.ts +84 -0
  812. package/dist/view-history.js +116 -0
  813. package/dist/view-history.js.map +1 -0
  814. package/dist/web-api.d.ts +49 -2
  815. package/dist/web-api.js +279 -8
  816. package/dist/web-api.js.map +1 -1
  817. package/dist/web-backend-login.d.ts +23 -1
  818. package/dist/web-backend-login.js +11 -17
  819. package/dist/web-backend-login.js.map +1 -1
  820. package/dist/web-device-login.d.ts +153 -0
  821. package/dist/web-device-login.js +278 -0
  822. package/dist/web-device-login.js.map +1 -0
  823. package/dist/web-office-skins.d.ts +9 -0
  824. package/dist/web-office-skins.js +16 -1
  825. package/dist/web-office-skins.js.map +1 -1
  826. package/dist/web-session-authorization.d.ts +13 -2
  827. package/dist/web-session-authorization.js +10 -3
  828. package/dist/web-session-authorization.js.map +1 -1
  829. package/dist/web-session.d.ts +35 -0
  830. package/dist/web-session.js +7 -0
  831. package/dist/web-session.js.map +1 -1
  832. package/dist/web-settings-patch.d.ts +3 -1
  833. package/dist/web-settings-patch.js +4 -1
  834. package/dist/web-settings-patch.js.map +1 -1
  835. package/dist/web-shell-routes.d.ts +6 -0
  836. package/dist/web-shell-routes.js +7 -0
  837. package/dist/web-shell-routes.js.map +1 -1
  838. package/dist/web-terminal.d.ts +4 -30
  839. package/dist/web-terminal.js +9 -6
  840. package/dist/web-terminal.js.map +1 -1
  841. package/dist/windows-agents.d.ts +4 -1
  842. package/dist/windows-agents.js +14 -10
  843. package/dist/windows-agents.js.map +1 -1
  844. package/dist/windows-cli-api.d.ts +12 -1
  845. package/dist/windows-cli-api.js +29 -2
  846. package/dist/windows-cli-api.js.map +1 -1
  847. package/dist/windows-cli-providers.d.ts +0 -9
  848. package/dist/windows-cli-providers.js +4 -9
  849. package/dist/windows-cli-providers.js.map +1 -1
  850. package/dist/windows-cli-worker.d.ts +25 -0
  851. package/dist/windows-cli-worker.js +98 -7
  852. package/dist/windows-cli-worker.js.map +1 -1
  853. package/dist/windows-cli.d.ts +11 -0
  854. package/dist/windows-cli.js +17 -3
  855. package/dist/windows-cli.js.map +1 -1
  856. package/dist/yaml-shared-nodes.js +8 -3
  857. package/dist/yaml-shared-nodes.js.map +1 -1
  858. package/launcher/agend-install.cjs +8 -1
  859. package/launcher/launchd-session-type.cjs +14 -0
  860. package/launcher/postinstall.cjs +27 -2
  861. package/launcher/private-home.cjs +1 -1
  862. package/launcher/tmux-bundle.cjs +247 -0
  863. package/package.json +3 -2
  864. package/templates/launchd.plist.ejs +3 -1
  865. package/templates/runtime-install/install.ps1 +270 -0
@@ -1,3 +1,4 @@
1
+ import { SettingsBuildVersion } from "./settings-build-version.js";
1
2
  // #1408 step 3: the Settings panel (/settings[/<section>]) — agents, connections, ClassicBot rooms, general defaults,
2
3
  // the developer YAML. Behind the session gate (/ui/js/), loaded the first time it is opened.
3
4
  //
@@ -25,18 +26,21 @@ import { Menu } from "/assets/ui-menu.js";
25
26
  import { toast } from "/assets/ui-toast.js";
26
27
  import { GroupMark, groupLabel, groupOf as navGroupOf, modelText } from "/assets/instance-nav.js";
27
28
  import "./settings-strings.js";
29
+ import "./settings-shared-strings.js"; // see settings-shared.js: the words Shared agent settings added, which an older settings-strings.js in an open tab lacks
30
+ import "./settings-access-strings.js"; // the words Access & security added (settings.webLoginQr…): an older settings-strings.js from a tab that visited Fleet first lacks them (#3061)
28
31
  import { api, attach, confirmedWrite, newKey } from "./settings-confirm.js";
29
32
  import { dismissOperation, operationActive, restartFleet, startOperation, takeLeftover } from "./settings-apply.js";
30
33
  import {
31
- ACCESS_MODES, AGENT_MODES, DASHBOARD_FEATURES, SEPARATE_FEATURE_KEYS, DEFAULT_SCHEMA, ownChoiceImpact, HANG_TIMEOUT_DEFAULT_MINUTES, LOG_LEVELS, TOOL_PROGRESS, TOOL_SETS, VISIBILITY_MODES, batchImpact,
34
+ ACCESS_MODES, DASHBOARD_FEATURES, SEPARATE_FEATURE_KEYS, DEFAULT_SCHEMA, ownChoiceImpact, HANG_TIMEOUT_DEFAULT_MINUTES, TOOL_PROGRESS, TOOL_SETS, VISIBILITY_MODES, batchImpact,
32
35
  changedFields, channelId, channelsOf, chLabel, connectionState, dashboardDefault, effectiveSummary, fleetModel, fromYaml, fullModelRequests, groupAgents,
33
- hasOwn, impactOf, localeOptions, defaultsImpact, requestImpact, nonNegative, positive, replyGuardSupported, sameValue, shortName, STATUS_ORDER, toYaml,
34
- toolSetDefault, visibilityDefault, worstImpact,
36
+ hasOwn, impactOf, defaultsImpact, requestImpact, nonNegative, positive, replyGuardSupported, sameValue, shortName, STATUS_ORDER, toYaml,
37
+ visibilityDefault, worstImpact,
35
38
  } from "./settings-model.js";
36
39
  import {
37
- AgentDialog, BackendSelect, BotDialog, ChipList, ClassicDialog, DefaultMark, Drawer, Feedback, Impact, InEffect, Inherited, Label, ModelSelect,
40
+ AgentDialog, BackendSelect, BotDialog, ChipList, ClassicDialog, DefaultMark, Feedback, Impact, InEffect, Inherited, Label,
38
41
  NewBotDialog, Override, Select, ask, impactText, inAgentDefaults, valueText,
39
42
  } from "./settings-dialogs.js";
43
+ import { SharedAgentSettings, sharedNotes } from "./settings-shared.js";
40
44
  import { SetupWizard } from "./settings-wizard.js";
41
45
  import { CreateInstanceDialog } from "./panel-fleet.js";
42
46
  import { RuntimesPanel } from "./panel-runtimes.js";
@@ -46,7 +50,7 @@ import { takeAgentRequest } from "./settings-request.js";
46
50
  // #1604: This device — the preview opt-in (one path: the app's confirm, then preview.js) and the tour, from the chat.
47
51
  import { setPreviewOptIn } from "./panel-chat.js";
48
52
  import { startTour } from "./chat-tour.js";
49
- import "./chat-strings.js";
53
+ import "/assets/chat-strings.js";
50
54
  import { AppearanceSection } from "./settings-appearance.js";
51
55
  import { GuestsCard } from "./settings-guests.js";
52
56
  import { OfficeSharesCard } from "./office-share-dialog.js";
@@ -54,8 +58,32 @@ import { PageSharesCard } from "./page-share-dialog.js";
54
58
  import { syncStage, useDraft } from "./settings-draft.js";
55
59
  import { WebAuthorityCard } from "./settings-web-authority.js";
56
60
  import { OutsideCard } from "./settings-outside.js";
61
+ import { DevicesCard } from "./settings-devices.js";
62
+ /** The pure owner Settings switch is available while off; its pairing UI remains lazy and member-mark gated. */
63
+ function HubCardSlot() {
64
+ const [Card, setCard] = useState(null);
65
+ useEffect(() => { let live = true; import("./settings-hub-membership.js").then((m) => { if (live) setCard(() => m.HubMembershipSettings); }, () => {}); return () => { live = false; }; }, []);
66
+ return Card ? html`<${Card} />` : null;
67
+ }
68
+ function HubBrowserCertificateSlot() {
69
+ const [Card, setCard] = useState(null);
70
+ useEffect(() => { let live = true; import("./settings-hub-browser-certificate.js").then(m => { if (live) setCard(() => m.HubBrowserCertificateSettings); }, () => {}); return () => { live = false; }; }, []);
71
+ return Card ? html`<${Card} />` : null;
72
+ }
73
+ function HubRetentionSlot() {
74
+ const [Card, setCard] = useState(null);
75
+ useEffect(() => { let live = true; import("./settings-hub-retention.js").then(m => { if (live) setCard(() => m.HubRetentionSettings); }, () => {}); return () => { live = false; }; }, []);
76
+ return Card ? html`<${Card} />` : null;
77
+ }
57
78
  import { NamedLinkTest, setTypedTunnelToken } from "./settings-named-test.js";
58
79
  import { SignInList } from "./backend-signin.js";
80
+ import { AccountsView, defaultsBackendOptions } from "./accounts-view.js"; // #3212: SignInList stays exported for a page that still imports it
81
+ import { ProviderMark } from "./provider-marks.js";
82
+ import { CliProductMark, cliLabel } from "./cli-picker.js";
83
+ import { SettingsPageHead, SettingsTabs, SettingsTabPanel, useSettingsTabs, revealSettingsTarget, layoutText } from "./settings-layout.js";
84
+ import { AgentFilters, agentFilterText, agentRuntime, agentRuntimeOffline, agentStatus, filterAgentGroups } from "./settings-agent-filters.js";
85
+ import { useRuntimeCatalog } from "./runtime-catalog.js";
86
+ import { ShortcutsHelpRow } from "./settings-shortcuts.js";
59
87
  import { GeneralLocation } from "./general-location.js";
60
88
 
61
89
  const tn = (k, ...v) => t(`settings.${k}`, ...v);
@@ -65,7 +93,6 @@ const APPLY_ERRORS = new Set(["unsupported_sensitive_effect", "confirmation_diff
65
93
  // #2726: a code or words of the setup host (the wizard's commit) in the page's language; anything else as it came.
66
94
  export const applyErrorText = (code) => (APPLY_ERRORS.has(code) ? tn(`applyError_${code}`) : tn("applyErrorOther", hostText(String(code), lang())));
67
95
  const ICONS = { preferences: "user", look: "palette", agents: "bot", runtimes: "view", "agent-defaults": "sliders", chat: "chat", "web-dashboard": "globe", access: "key", advanced: "code" };
68
- const RELEASES = "https://github.com/songsid/AgEnD/releases";
69
96
 
70
97
  /** GET under the panel's lease → { ok, status, body }. */
71
98
  async function read(lease, path) {
@@ -107,7 +134,7 @@ async function loadLive(lease) {
107
134
  if (!lease.current()) return null;
108
135
  const live = {}, classicLive = {};
109
136
  if (f.ok && f.body && Array.isArray(f.body.instances)) for (const i of f.body.instances) {
110
- live[i.name] = { status: i.status, state: i.state, backend: i.backend, model: i.model, model_display: modelText(i, i.model_display), effort: i.effort, effort_supported: i.effort_supported, runtime:i.runtime, capabilities:i.capabilities };
137
+ live[i.name] = { status: i.status, state: i.state, backend: i.backend, model: i.model, model_display: modelText(i, i.model_display), effort: i.effort, effort_supported: i.effort_supported, runtime:i.runtime, capabilities:i.capabilities, machine_id:i.machine_id, machine_name:i.machine_name, machine_status:i.machine_status };
111
138
  if (i.classic) classicLive[i.name] = { status: i.status, state: i.state };
112
139
  }
113
140
  // /api/fleet carries live state for ClassicBot rooms; the profiles are the fallback for one not listed there yet.
@@ -115,7 +142,7 @@ async function loadLive(lease) {
115
142
  if (!lease.current()) return null;
116
143
  const classicStatus = {};
117
144
  if (pr.ok && Array.isArray(pr.body)) for (const r of pr.body) classicStatus[r.instance_name] = r.status;
118
- return { live, classicLive, classicStatus, fleetUp: f.ok, version: (f.ok && f.body && f.body.version) || "" };
145
+ return { live, classicLive, classicStatus, fleetUp: f.ok, version: (f.ok && f.body && f.body.version) || "", build: f.ok && f.body ? f.body.build : null };
119
146
  }
120
147
 
121
148
  export function SettingsPanel({ route, navKey }) {
@@ -381,20 +408,30 @@ export function SettingsPanel({ route, navKey }) {
381
408
  const formKey = data && !data.error ? `${data.loadedAt}:${draftEpoch}` : "";
382
409
  // #2347 regrouping: each card where the person looks for it (the IA in #2347 §3); a form split across sections (the
383
410
  // defaults, Web) is one form with one draft, shown a part at a time.
384
- const sectionBody = section === "preferences" ? html`<${DeviceSection} key=${you.key} /><${AppearanceSection} ...${you} part="device" />`
411
+ const sectionBody = section === "preferences" ? html`<${DeviceSection} key=${you.key} />`
385
412
  : section === "look" ? html`<${AppearanceSection} ...${you} part="look" />`
386
413
  : section === "runtimes" ? html`<${RuntimesPanel} navKey=${navKey} />`
387
414
  : !data ? html`<${Skeleton} lines=${6} />`
388
415
  : data.error ? html`<${ErrorState} message=${tn("configLoadFailed")} onRetry=${reload} />`
389
- : section === "agents" ? html`<${YamlLock} staged=${staged}><${Agents} ctx=${ctx} search=${search} openDialog=${toDialog} /></${YamlLock}>${ctx.providerOk ? html`<${ProviderKeys} ctx=${ctx} />` : null}`
416
+ : section === "agents" ? html`<${YamlLock} staged=${staged}><${Agents} ctx=${ctx} search=${search} clearSearch=${() => setSearch("")} openDialog=${toDialog} /></${YamlLock}><details class="s-ui-disclosure s-ai-accounts"><summary><span>${layoutText("aiAccounts")}</span><small>${layoutText("aiAccountsSummary")}</small></summary><div class="s-disclosure-body s-auth-body">
417
+ <div class="s-auth-scope"><${Icon} name="view" size=${18} /><div><strong>${layoutText("aiHostScope")}</strong><p>${layoutText("aiAccountsHint")}</p><a href=${settingsPath("runtimes")}>${layoutText("aiWindowsLink")}<span aria-hidden="true">→</span></a></div></div>
418
+ <${AccountsView} instances=${ctx.fleet.instances || {}} stageAgent=${ctx.stageAgent}
419
+ stageDefault=${(backend, profile) => {
420
+ // One change for every CLI's fleet default, carrying the whole map (the write replaces it whole).
421
+ const opts = defaultsBackendOptions((ctx.fleet.defaults || {}).backend_options, stagedRef.current.get("defaults:account")?.request?.body?.backend_options, backend, profile);
422
+ if (!opts) { ctx.unstage("defaults:account"); return; }
423
+ ctx.stage("defaults:account", { label: tn("updateDefaults"), count: 1, impact: defaultsImpact(ctx.schema, "backend_options"),
424
+ request: { method: "PUT", url: "/api/settings/fleet/defaults", body: { backend_options: opts } } });
425
+ }} />${ctx.providerOk ? html`<${ProviderKeys} ctx=${ctx} />` : html`<section class="s-auth-section s-api-unavailable"><header class="s-auth-section-head"><div><h3>${layoutText("apiKeysTitle")}</h3><p>${layoutText("apiKeysHint")}</p></div><span class="s-auth-state">${layoutText("apiKeysUnavailableState")}</span></header><p class="note">${layoutText("apiKeysUnavailable")}</p></section>`}
426
+ </div></details>`
390
427
  : section === "agent-defaults" ? html`<${GeneralLocation} /><${YamlLock} staged=${staged}><${General} key=${formKey} ctx=${ctx} part="fleet" /></${YamlLock}>`
391
428
  : section === "chat" ? html`<${YamlLock} staged=${staged}><${Bots} ctx=${ctx} search=${search} openDialog=${toDialog} /></${YamlLock}>
392
429
  <${WebSection} key=${formKey} ctx=${ctx} staged=${staged} part="chat" />
393
- <div id="classicbot" class="s-anchor"><h2 class="s-ap-group">ClassicBot</h2><${Classic} ctx=${ctx} search=${search} openDialog=${toDialog} />
394
- <${General} key=${formKey} ctx=${ctx} part="classic" /></div>`
430
+ <div id="classicbot" class="s-anchor s-classic-area"><section class="card s-chat-classic"><h2 class="s-ap-group">ClassicBot</h2><${Classic} ctx=${ctx} search=${search} openDialog=${toDialog} /></section>
431
+ <details class="s-ui-disclosure s-classic-defaults"><summary>${layoutText("classicDefaults")}</summary><div class="s-disclosure-body"><${General} key=${formKey} ctx=${ctx} part="classic" /></div></details></div>`
395
432
  : section === "web-dashboard" ? html`<${WebSection} key=${formKey} ctx=${ctx} staged=${staged} part="dashboard" /><${AppearanceSection} ...${you} part="dashboard" />`
396
433
  : section === "access" ? html`<${WebSection} key=${formKey} ctx=${ctx} staged=${staged} part="access" />`
397
- : html`<${Developer} key=${`dev:${draftEpoch}`} ctx=${ctx} /><${WebSection} key=${formKey} ctx=${ctx} staged=${staged} part="readonly" />`;
434
+ : html`<${AdvancedSettings} ctx=${ctx} staged=${staged} formKey=${formKey} draftEpoch=${draftEpoch} />`;
398
435
  // #2347 §6: the setting a search result opened — brought into view once its section is drawn (its data may still be
399
436
  // on its way), focused, and flashed for 2 s.
400
437
  const wanted = useRef(null);
@@ -413,6 +450,7 @@ export function SettingsPanel({ route, navKey }) {
413
450
  if (++tries < 40) timer = setTimeout(find, 50); else wanted.current = null;
414
451
  return;
415
452
  }
453
+ if (revealSettingsTarget(el)) { timer = setTimeout(find, 0); return; }
416
454
  wanted.current = null;
417
455
  // #2347 §10: a setting in a closed drawer (Advanced) is shown — every drawer around it opens first.
418
456
  for (let d = el.closest && el.closest("details"); d; d = d.parentElement && d.parentElement.closest("details")) d.open = true;
@@ -453,7 +491,14 @@ export function SettingsPanel({ route, navKey }) {
453
491
  if (!id) return;
454
492
  let el = null;
455
493
  try { el = document.getElementById(decodeURIComponent(id)); } catch { el = null; }
456
- if (el && typeof el.scrollIntoView === "function") el.scrollIntoView({ block: "start" });
494
+ if (!el) return;
495
+ const show = () => {
496
+ // Hash links, like settings-search targets, must reveal every enclosing disclosure before scrolling.
497
+ for (let d = el.closest && el.closest("details"); d; d = d.parentElement && d.parentElement.closest("details")) d.open = true;
498
+ if (typeof el.scrollIntoView === "function") el.scrollIntoView({ block: "start" });
499
+ };
500
+ if (revealSettingsTarget(el)) { const timer = setTimeout(show, 0); return () => clearTimeout(timer); }
501
+ show();
457
502
  }, [section, navKey, !!data]);
458
503
  // A dialog belongs to the navigation that opened it (its draft names one object, never another).
459
504
  const open = dialog && dialog.key === navKey ? dialog : null;
@@ -464,7 +509,7 @@ export function SettingsPanel({ route, navKey }) {
464
509
  // Which one is shown is the root's data-view: its class stays exactly the effects producer's ("panel p-settings", #1629).
465
510
  const atList = typeof location !== "undefined" && location.pathname === "/settings";
466
511
  return html`<div data-effect-panel="settings" class="panel p-settings" data-view=${atList ? "index" : "section"}>
467
- <${PanelHeader} title=${tn("title")} sub=${data && data.version ? html`<a class="pill ver" href=${data.version.includes("-") ? `${RELEASES}/latest` : `${RELEASES}/tag/v${data.version}`} target="_blank" rel="noopener">v${data.version}</a>` : null}>
512
+ <${PanelHeader} title=${tn("title")} sub=${data ? html`<${SettingsBuildVersion} version=${data.version} build=${data.build} />` : null}>
468
513
  <button type="button" class="btn btn-ghost btn-sm" disabled=${!ctx || yamlStaged(staged)} title=${ctx && yamlStaged(staged) ? tn("yamlUnsaved") : undefined} onClick=${openWizard}><${Icon} name="wand" size=${16} /><span class="hide-narrow">${tn("wizardButton")}</span></button>
469
514
  <button type="button" class="icon-btn" aria-label=${tn("helpButton")} title=${tn("helpButton")} onClick=${() => setDialog({ kind: "help", key: navKey })}><${Icon} name="info" /></button>
470
515
  </${PanelHeader}>
@@ -472,14 +517,15 @@ export function SettingsPanel({ route, navKey }) {
472
517
  <span class="s-nav-head" id=${`s-grp-${g.id}`}>${tn(`grp_${g.id}`)}</span>
473
518
  ${g.sections.map((k) => html`<a key=${k} href=${sectionPath(k)} class=${`seg-item${k === section ? " active" : ""}`}
474
519
  aria-current=${k === section ? "page" : undefined}><${Icon} name=${ICONS[k]} size=${16} /><span>${tn(`sec_${k}`)}</span></a>`)}</div>`)}</div></nav>
475
- <div data-trust="panel-content" class="panel-body"><div class="col">
520
+ <div data-trust="panel-content" class="panel-body"><div class="col" data-settings-section=${section}>
476
521
  <a class="s-back" href=${settingsPath()}><${Icon} name="back" size=${16} /><span>${tn("title")}</span><span class="s-back-here">${tn(`sec_${section}`)}</span></a>
522
+ ${section !== "runtimes" ? html`<${SettingsPageHead} section=${section}>${section === "agents" && ctx ? html`<button type="button" id="newAgentBtn" class="btn btn-primary" disabled=${yamlStaged(staged)} onClick=${() => toDialog({ kind: "create" })}><${Icon} name="plus" size=${16} />${tn("newAgent")}</button>` : null}</${SettingsPageHead}>` : null}
477
523
  ${searchable ? html`<div class="s-toolbar"><label class="s-search"><${Icon} name="search" size=${14} /><span class="sr-only">${tn("searchAll")}</span>
478
524
  <input type="search" value=${search} placeholder=${tn("searchAll")} onInput=${(e) => setSearch(e.target.value)} /></label></div>` : null}
479
525
  ${op ? html`<${OperationCard} op=${op} schema=${data && data.schema} />` : null}
480
526
  <${PendingChanges} inline=${true} />
481
527
  ${ctx && (section === "agents" || section === "chat") ? html`<${FirstRunCard} onConnect=${openWizard} />` : null}
482
- ${sectionBody}
528
+ <div class="s-section-layout" data-section=${section}>${sectionBody}</div>
483
529
  </div></div>
484
530
  ${staged.size ? html`<${PendingBar} staged=${staged} busy=${opBusy(op)} onApply=${apply} onDiscard=${discard} section=${section} />` : null}
485
531
  ${open && ctx ? renderDialog(open, ctx, close) : null}
@@ -487,6 +533,14 @@ export function SettingsPanel({ route, navKey }) {
487
533
  </div>`;
488
534
  }
489
535
 
536
+ function AdvancedSettings({ ctx, staged, formKey, draftEpoch }) {
537
+ const [tab, setTab] = useSettingsTabs("advanced", "editor");
538
+ return html`<div class="s-advanced-layout"><${SettingsTabs} id="advanced" value=${tab} onChange=${setTab} items=${[{ id: "editor", label: layoutText("editor") }, { id: "effective", label: layoutText("effective") }]} />
539
+ <${SettingsTabPanel} group="advanced" id="editor" active=${tab === "editor"}><${Developer} key=${`dev:${draftEpoch}`} ctx=${ctx} /></${SettingsTabPanel}>
540
+ <${SettingsTabPanel} group="advanced" id="effective" active=${tab === "effective"}><${WebSection} key=${formKey} ctx=${ctx} staged=${staged} part="readonly" /></${SettingsTabPanel}>
541
+ </div>`;
542
+ }
543
+
490
544
  /**
491
545
  * #1604, #1665: Preferences. Synced across the person's devices (kept on the host, app-prefs.js): theme (theme.js),
492
546
  * language (app-i18n.js) and HTML previews (preview.js, through the app's confirm). On the public link they are
@@ -608,17 +662,23 @@ export function DeviceSection() {
608
662
  setTimeout(go, 0);
609
663
  };
610
664
  const publicLink = typeof document !== "undefined" && document.body && document.body.dataset.publicLink === "1";
611
- return html`<${ProfileCard} />
612
- <section class="card s-device s-synced"><h3>${tn("syncedTitle")}</h3>
613
- <p class="sub">${publicLink ? tn("syncedPublicLink") : tn("syncedLead")}</p>
614
- <${DevicePrefs} labels=${true} />
615
- ${P() ? html`<label class="check"><input id="pref-previews" type="checkbox" checked=${on} onChange=${(e) => { const want = e.target.checked; setPreviewOptIn(want).then(setOn); }} />
616
- <span>${t("chat.previews")}</span></label>` : null}
617
- </section>
618
- <section class="card s-device s-local"><h3>${tn("deviceTitle")}</h3>
619
- <p class="sub">${tn("deviceLead")}</p>
620
- <div class="s-device-row"><button type="button" id="tourBtn" class="btn" title=${t("chat.tourBtnTitle")} onClick=${replay}><${Icon} name="info" size=${16} />${t("chat.tour")}</button></div>
621
- </section>`;
665
+ return html`<div class="s-pref-stack">
666
+ <section class="card s-device s-pref-personal"><h3>${tn("prefsProfileGroup")}</h3>
667
+ <${ProfileCard} embedded=${true} />
668
+ <div class="s-pref-name-format"><${DevicePrefs} labels=${true} fields=${["names"]} /></div>
669
+ </section>
670
+ <section class="card s-device s-synced s-pref-content"><div class="s-pref-group-head"><h3>${tn("prefsContentGroup")}</h3><span class="s-scope" title=${publicLink ? tn("syncedPublicLink") : tn("syncedLead")}>${tn("prefsAccountScope")}</span></div>
671
+ ${publicLink ? html`<p class="sub">${tn("syncedPublicLink")}</p>` : null}
672
+ <${DevicePrefs} labels=${true} fields=${["language"]} />
673
+ ${P() ? html`<label class="check s-pref-preview"><span>${t("chat.previews")}</span><input id="pref-previews" class="s-ui-toggle" type="checkbox" checked=${on} onChange=${(e) => { const want = e.target.checked; setPreviewOptIn(want).then(setOn); }} /><small>${layoutText("previewsPersonalHint")}</small></label>` : null}
674
+ </section>
675
+ <section class="card s-device s-local s-pref-help"><h3>${tn("prefsHelpGroup")}</h3>
676
+ <div class="s-pref-help-row"><div><strong>${t("chat.tour")}</strong><p class="sub">${tn("prefsTourHint")}</p></div>
677
+ <button type="button" id="tourBtn" class="btn" title=${t("chat.tourBtnTitle")} onClick=${replay}><${Icon} name="info" size=${16} />${tn("prefsReplayTour")}</button></div>
678
+ <${ShortcutsHelpRow} />
679
+ </section>
680
+ <a class="s-pref-look-link" href=${settingsPath("look")}>${tn("prefsLookHint")}<${Icon} name="chevron" size=${16} /></a>
681
+ </div>`;
622
682
  }
623
683
 
624
684
  /**
@@ -628,7 +688,7 @@ export function DeviceSection() {
628
688
  * refuses one; this only shows what it says.
629
689
  */
630
690
  const view = (b) => ({ phase: "ready", name: b.name || "", shown: b.shown || "", id: b.id || "", bound: b.bound === true, platform: b.platform_name || "", error: "" });
631
- export function ProfileCard() {
691
+ export function ProfileCard({ embedded = false } = {}) {
632
692
  const [state, setState] = useState({ phase: "loading", name: "", shown: "", id: "", bound: false, platform: "", error: "" });
633
693
  const [draft, setDraft] = useState("");
634
694
  const lease = useLease();
@@ -655,16 +715,22 @@ export function ProfileCard() {
655
715
  };
656
716
  const busy = state.phase !== "ready";
657
717
  const changed = draft.trim() !== state.name;
658
- return html`<section class="card s-device s-profile"><h3>${tn("profileTitle")}</h3>
659
- <p class="sub">${state.bound ? tn("profileLeadBound") : tn("profileLeadUnbound")}</p>
660
- <div class="field"><label for="profile-name">${tn("profileName")}</label>
661
- <input id="profile-name" type="text" maxlength="200" autocomplete="nickname" value=${draft} disabled=${busy}
718
+ const initial = [...(state.shown || state.name || "web-user")][0]?.toUpperCase() || "W";
719
+ const fields = html`<div class="s-pref-profile-layout">
720
+ ${embedded ? html`<span class="s-pref-avatar" aria-hidden="true">${initial}</span>` : null}
721
+ <div class="s-pref-profile-main"><div class="field"><label for="profile-name">${tn("profileName")}</label>
722
+ <div class="s-pref-name-action"><input id="profile-name" type="text" maxlength="200" autocomplete="nickname" value=${draft} disabled=${busy}
662
723
  placeholder=${state.platform || "web-user"} aria-invalid=${state.error ? "true" : "false"} aria-describedby="profile-help"
663
724
  onInput=${(e) => setDraft(e.target.value)} onKeyDown=${(e) => { if (e.key === "Enter" && changed && draft.trim()) save(false); }} />
664
- <p class="sub" id="profile-help">${state.error ? html`<span class="err" role="alert">${state.error}</span>` : tn("profileHelp", state.shown || "web-user", state.id)}</p></div>
665
- <div class="s-device-row"><button type="button" class="btn primary" disabled=${busy || !changed || !draft.trim()} onClick=${() => save(false)}>${tn("profileSave")}</button>
666
- ${state.name ? html`<button type="button" class="btn" disabled=${busy} onClick=${() => save(true)}>${state.bound ? tn("profileUseAccount", state.platform || "web-user") : tn("profileClear")}</button>` : null}</div>
667
- </section>`;
725
+ <button type="button" class="btn primary" disabled=${busy || !changed || !draft.trim()} onClick=${() => save(false)}>${embedded ? tn("prefsSaveName") : tn("profileSave")}</button></div>
726
+ <p class="sub" id="profile-help">${state.error ? html`<span class="err" role="alert">${state.error}</span>` : tn("profileHelp", state.shown || "web-user", state.id)}</p>
727
+ </div>
728
+ <p class="sub s-pref-immediate">${tn("prefsNameImmediate")}</p>
729
+ ${state.name ? html`<div class="s-device-row"><button type="button" class="btn btn-ghost btn-sm" disabled=${busy} onClick=${() => save(true)}>${state.bound ? tn("profileUseAccount", state.platform || "web-user") : tn("profileClear")}</button></div>` : null}
730
+ <details class="s-pref-identity-details"><summary>${layoutText("profileIdentityDetails")}</summary><p class="sub">${state.bound ? tn("profileLeadBound") : tn("profileLeadUnbound")}</p></details>
731
+ </div></div>`;
732
+ return embedded ? html`<div class="s-profile s-pref-profile-fields">${fields}</div>`
733
+ : html`<section class="card s-device s-profile"><h3>${tn("profileTitle")}</h3>${fields}</section>`;
668
734
  }
669
735
 
670
736
  /** The operation in hand still owns Apply: its writes and job, or a restart of AgEnD from the press to its end. */
@@ -761,60 +827,67 @@ function agentChannelLabel(inst, chs) {
761
827
  return idx >= 0 ? `${chs[idx].type} (${chLabel(idx)})` : inst.channel_id;
762
828
  }
763
829
 
764
- function Agents({ ctx, search, openDialog }) {
830
+ function Agents({ ctx, search, clearSearch, openDialog }) {
765
831
  const insts = ctx.fleet.instances || {};
766
832
  const [collapsed, setCollapsed] = useState(() => new Set());
767
833
  const [busy, setBusy] = useState(() => new Map()); // name → the action under way
834
+ const [runtime, setRuntime] = useState("");
835
+ const [status, setStatus] = useState("");
836
+ // The computers' names come from the same list as the Runtime page (revoked ones included, so an Agent still bound to one can say so).
837
+ const catalog = useRuntimeCatalog(Object.values(insts).some((inst) => inst?.machine_id));
838
+ // A fleet with remote Runtimes off answers { enabled: false, machines: [] }: that is no list, not an empty one.
839
+ const machines = catalog.data && catalog.data.enabled !== false ? new Map(catalog.data.machines.map((machine) => [machine.id, { name: machine.name, status: machine.status }])) : null;
768
840
  const chs = channelsOf(ctx.fleet);
769
841
  // #2172: the sidebar's grouping — an agent in a team under its team, else under its first tag.
770
842
  const teamsOf = (name) => Object.keys(ctx.fleet.teams || {}).filter((t) => Array.isArray(ctx.fleet.teams[t]?.members) && ctx.fleet.teams[t].members.includes(name));
771
- const groups = groupAgents(insts, ctx.live, search, (name) => navGroupOf({ tags: insts[name]?.tags, teams: teamsOf(name) }), groupLabel);
843
+ const groups = filterAgentGroups(groupAgents(insts, ctx.live, search, (name) => navGroupOf({ tags: insts[name]?.tags, teams: teamsOf(name) }), groupLabel), insts, ctx.live, { runtime, status });
844
+ const active = !!(runtime || status || search.trim());
772
845
  // One action per agent at a time: the whole row is off (Settings and ⋯ too), and the pressed button says it is working.
773
846
  const run = async (name, action, work) => {
774
847
  if (busy.has(name)) return;
775
848
  setBusy((b) => new Map(b).set(name, action));
776
849
  try { await work(); } finally { setBusy((b) => { const n = new Map(b); n.delete(name); return n; }); }
777
850
  };
778
- const head = html`<div class="list-head"><span>${Object.keys(insts).length === 1 ? tn("countAgent") : tn("countAgents", Object.keys(insts).length)}</span>
779
- <button type="button" id="newAgentBtn" class="btn btn-primary" onClick=${() => openDialog({ kind: "create" })}><${Icon} name="plus" size=${16} />${tn("newAgent")}</button></div>`;
780
- // #2233: after the agents, each login on this machine with Sign in (backend-signin.js).
781
- const signIns = html`<${SignInList} />`;
782
- if (!Object.keys(insts).length) return html`${head}<${Empty} icon="bot" title=${tn("noAgents")} />${signIns}`;
783
- if (!groups.length) return html`${head}<${Empty} icon="search" title=${tn("noAgentMatch", search.trim())} />${signIns}`;
784
- return html`${head}<div class="s-list">${groups.map(({ group, names }) => {
785
- const folded = collapsed.has(group) && !search.trim(); // searching opens every group
851
+ const head = html`<${AgentFilters} instances=${insts} live=${ctx.live} machines=${machines} runtime=${runtime} status=${status} active=${active}
852
+ matched=${groups.reduce((count, group) => count + group.names.length, 0)} total=${Object.keys(insts).length} onRuntime=${setRuntime} onStatus=${setStatus}
853
+ onClear=${() => { setRuntime(""); setStatus(""); clearSearch(); }} />`;
854
+ if (!Object.keys(insts).length) return html`${head}<${Empty} icon="bot" title=${tn("noAgents")} />`;
855
+ if (!groups.length) return html`${head}<${Empty} icon="search" title=${search.trim() ? tn("noAgentMatch", search.trim()) : agentFilterText("noMatch")} hint=${agentFilterText("noMatchHint")} />`;
856
+ return html`${head}<div class="s-list s-agents-list">
857
+ <div class="s-list-columns s-agent-columns" aria-hidden="true"><span>${tn("uiAgentColumnName")}</span><span>${agentFilterText("runtime")}</span><span>${tn("uiAgentColumnCli")}</span><span>${tn("uiListColumnState")}</span><span>${tn("uiListColumnActions")}</span></div>${groups.map(({ group, names }) => {
858
+ const folded = collapsed.has(group) && !active; // searching/filtering opens every matching group
786
859
  return html`<section key=${group} class="s-group">
787
860
  <button type="button" class="s-group-head" aria-expanded=${folded ? "false" : "true"}
788
861
  onClick=${() => setCollapsed((c) => { const n = new Set(c); n.has(group) ? n.delete(group) : n.add(group); return n; })}>
789
862
  <${Icon} name="chevron" size=${14} cls=${folded ? "caret folded" : "caret"} /><${GroupMark} group=${group} /><span class="grow">${groupLabel(group)}</span><span class="count">${names.length}</span></button>
790
863
  ${folded ? null : names.map((name) => {
791
864
  const inst = insts[name];
792
- const st = (ctx.live[name] && ctx.live[name].status) || "stopped";
865
+ const st = agentStatus(ctx.live[name]);
793
866
  const sum = effectiveSummary(ctx.live[name] || {}, inst, ctx.fleet.defaults || {});
794
867
  const ch = agentChannelLabel(inst, chs);
795
868
  const working = busy.has(name), doing = busy.get(name);
796
869
  const label = (action, text) => (doing === action ? tn("working") : text);
797
- return html`<div key=${name} class="s-row">
798
- <span class=${dotClass(st)} title=${tn(STATUS_KEY[st] || "stStopped")} aria-hidden="true"></span>
799
- <span class="s-name" title=${name}>${shortName(name, inst)}</span>
800
- ${inst.runtime === "windows" ? html`<span class="tag">Windows</span>` : null}
801
- <span class="s-meta" title=${sum.backend}>${sum.model}</span>
802
- <span class="s-br" aria-hidden="true"></span>
803
- ${inst.runtime !== "windows" || ctx.live[name]?.capabilities?.effort === true ? html`<span class="tag">${tn("effortTag", sum.effort)}</span>` : null}
804
- ${ch ? html`<span class=${`tag${ch.includes("persona") ? " persona" : ""}`}>${ch}</span>` : null}
805
- <span class="sr-only">${tn(STATUS_KEY[st] || "stStopped")}</span>
870
+ const runtimeTarget = agentRuntime(inst, ctx.live[name], machines);
871
+ return html`<div key=${name} class="s-row s-agent-row">
872
+ <div class="s-agent-identity"><span class="s-name" title=${name}>${shortName(name, inst)}</span>
873
+ <div class="s-agent-context">${inst.runtime !== "windows" || ctx.live[name]?.capabilities?.effort === true ? html`<span class="tag">${tn("effortTag", sum.effort)}</span>` : null}
874
+ ${ch ? html`<span class=${`tag${ch.includes("persona") ? " persona" : ""}`}>${ch}</span>` : null}</div>
875
+ </div>
876
+ <div class="s-agent-runtime"><span class=${`tag${runtimeTarget.gone ? " warn" : ""}`} title=${runtimeTarget.title || runtimeTarget.label}>${runtimeTarget.label}</span></div>
877
+ <div class="s-agent-cli"><${CliProductMark} id=${sum.backend} size=${20} /><span><strong>${cliLabel(sum.backend)}</strong><span class="s-meta" title=${sum.model}>${sum.model}</span></span></div>
878
+ <span class="s-agent-status"><span class=${dotClass(agentStatus(ctx.live[name]))} aria-hidden="true"></span><span>${agentFilterText(agentStatus(ctx.live[name]))}${agentRuntimeOffline(inst, ctx.live[name]) ? html`<small class="s-agent-runtime-state">${agentFilterText("offline")}</small>` : null}</span></span>
806
879
  <span class="s-actions">
807
880
  ${inst.runtime === "windows" ? html`<a class="btn btn-sm" href=${chatPath(name)}>${t("app.chat")}</a>` : null}
808
881
  <button type="button" class="btn btn-sm" disabled=${working} onClick=${() => openDialog({ kind: "agent", name, inst })}>${tn("settingsButton")}</button>
809
882
  ${st === "running" ? html`<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => run(name, "pause", () => ctx.pauseWake(name, "pause"))}>${label("pause", tn("pause"))}</button>` : null}
810
883
  ${st === "paused" ? html`<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => run(name, "wake", () => ctx.pauseWake(name, "wake"))}>${label("wake", tn("wake"))}</button>` : null}
811
- ${st !== "paused" ? html`<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => run(name, "startStop", () => ctx.startStop(name, st === "running"))}>${label("startStop", st === "running" ? tn("stop") : tn("start"))}</button>` : null}
812
- <${Menu} label=${t("app.more")} items=${[{ key: "delete", label: tn("deleteAgentMenu"), icon: "trash", danger: true, disabled: working, onSelect: () => ctx.deleteAgent(name) }]} />
884
+ ${["running", "stopped", "crashed"].includes(st) ? html`<button type="button" class="btn btn-sm" disabled=${working} onClick=${() => run(name, "startStop", () => ctx.startStop(name, st === "running"))}>${label("startStop", st === "running" ? tn("stop") : tn("start"))}</button>` : null}
885
+ <${Menu} cls="s-agent-menu" fit=${true} label=${t("app.more")} items=${[{ key: "delete", label: tn("deleteAgentMenu"), icon: "trash", danger: true, disabled: working, onSelect: () => ctx.deleteAgent(name) }]} />
813
886
  </span>
814
887
  </div>`;
815
888
  })}
816
889
  </section>`;
817
- })}</div>${signIns}`;
890
+ })}</div>`;
818
891
  }
819
892
 
820
893
  function ConnectionRetry({ id, ctx }) {
@@ -844,10 +917,10 @@ function Bots({ ctx, search, openDialog }) {
844
917
  const all = channelsOf(ctx.fleet);
845
918
  const needle = search.trim().toLowerCase();
846
919
  const rows = all.map((ch, i) => ({ ch, i })).filter(({ ch }) => !needle || [ch.id, ch.type, ch.group_id, ch.bot_token_env].some((v) => String(v ?? "").toLowerCase().includes(needle)));
847
- const head = html`<div class="list-head"><span>${all.length === 1 ? tn("countBot") : tn("countBots", all.length)}</span>
920
+ const head = html`<div class="list-head s-list-toolbar"><span>${all.length === 1 ? tn("countBot") : tn("countBots", all.length)}</span>
848
921
  <button type="button" id="newBotBtn" class="btn btn-primary" onClick=${() => openDialog({ kind: "newBot" })}><${Icon} name="plus" size=${16} />${tn("newBot")}</button></div>`;
849
- return html`${head}
850
- ${!rows.length ? html`<${Empty} icon="plug" title=${needle ? tn("noAgentMatch", search.trim()) : tn("noBots")} />` : html`<div class="s-list">${rows.map(({ ch, i }) => {
922
+ return html`<section class="card s-chat-connections"><div class="s-chat-section-head"><h3>${layoutText("chatConnections")}</h3>${head}</div>
923
+ ${!rows.length ? html`<div class="s-chat-empty"><${Icon} name="plug" size=${22} /><p>${needle ? tn("noAgentMatch", search.trim()) : tn("noBots")}</p></div>` : html`<div class="s-list s-connections-list"><div class="s-list-columns s-connection-columns" aria-hidden="true"><span>${tn("uiConnectionColumnService")}</span><span>${tn("uiConnectionColumnInfo")}</span><span>${tn("uiListColumnActions")}</span></div>${rows.map(({ ch, i }) => {
851
924
  const users = (ch.access && ch.access.allowed_users) || [];
852
925
  const meta = ctx.connections.find((c, j) => channelId(c, j) === channelId(ch, i)) || {};
853
926
  const token = meta.token_present;
@@ -872,7 +945,7 @@ function Bots({ ctx, search, openDialog }) {
872
945
  ${!overPublicLink && ctx.fleetUp && meta.status !== "connected" ? html`<${ConnectionRetry} id=${channelId(ch, i)} ctx=${ctx} />` : null}
873
946
  <button type="button" class="btn btn-sm" onClick=${() => openDialog({ kind: "bot", id: channelId(ch, i) })}>${tn("settingsButton")}</button></span>
874
947
  </div>`;
875
- })}</div>`}`;
948
+ })}</div>`}</section>`;
876
949
  }
877
950
 
878
951
  /**
@@ -922,40 +995,40 @@ function ProviderKeys({ ctx }) {
922
995
  } catch { say(spec.id, { error: tn("failed") }); }
923
996
  finally { inFlight.current.delete(spec.id); if (lease.current()) setBusy(new Set(inFlight.current)); }
924
997
  };
925
- return html`<section class="card s-provider-keys"><h3>${tn("providerKeys")}</h3>
926
- ${!ctx.providerSecrets.length ? html`<p class="note">${tn("noProviderVerifiers")}</p>` : ctx.providerSecrets.map((spec) => html`<div key=${spec.id} class="s-key">
927
- <div class="s-key-row"><strong>${spec.display_name}</strong><span class="tag">${spec.token_present ? tn("keyConfigured") : tn("keyNotConfigured")}</span>
928
- ${spec.verifier === "available" ? html`<input type="password" autocomplete="new-password" aria-label=${tn("providerKeyInput", spec.display_name)}
929
- placeholder=${spec.token_present ? tn("keyConfigured") : tn("keyNotConfigured")} value=${keys[spec.id] || ""} onInput=${(e) => setKeys((k) => ({ ...k, [spec.id]: e.target.value }))} />
930
- <button type="button" class="btn btn-sm btn-primary" disabled=${busy.has(spec.id)} onClick=${() => go(spec)}>${tn("verifyApply")}</button>`
931
- : html`<span class="tag">${tn("unsupportedVerifier")}</span>`}</div>
932
- ${spec.verifier === "available" ? null : html`<p class="note">${tn("unsupportedVerifierHint")}</p>`}
933
- ${notes[spec.id] ? html`<p class=${`feedback${notes[spec.id].error ? " error" : ""}`} role="status">${notes[spec.id].error || notes[spec.id].text}</p>` : null}
934
- </div>`)}
998
+ return html`<section class="card s-provider-keys s-auth-section"><header class="s-auth-section-head"><div><h3>${layoutText("apiKeysTitle")}</h3><p>${layoutText("apiKeysHint")}</p></div></header>
999
+ ${!ctx.providerSecrets.length ? html`<p class="note">${tn("noProviderVerifiers")}</p>` : html`<div class="s-api-key-list">${ctx.providerSecrets.map((spec) => {
1000
+ const provider = spec.id.split(".")[0], mark = ["openai", "anthropic"].includes(provider) ? provider : null;
1001
+ return html`<div key=${spec.id} class="s-key s-api-key-row">
1002
+ <div class="s-api-key-heading"><span class="s-provider-symbol">${mark ? html`<${ProviderMark} provider=${mark} size=${22} />` : html`<${Icon} name="key" size=${22} />`}</span><strong>${spec.display_name}</strong><span class=${`s-auth-state${spec.token_present ? " is-usable" : ""}`}>${spec.token_present ? tn("keyConfigured") : tn("keyNotConfigured")}</span></div>
1003
+ ${spec.verifier === "available" ? html`<div class="s-api-key-form"><label><span>${tn("providerKeyInput", spec.display_name)}</span><input type="password" autocomplete="new-password" aria-label=${tn("providerKeyInput", spec.display_name)}
1004
+ placeholder=${layoutText(spec.token_present ? "apiReplacePlaceholder" : "apiNewPlaceholder")} value=${keys[spec.id] || ""} onInput=${(e) => setKeys((k) => ({ ...k, [spec.id]: e.target.value }))} /></label>
1005
+ <button type="button" class="btn btn-sm btn-primary" disabled=${busy.has(spec.id)} onClick=${() => go(spec)}>${tn("verifyApply")}</button></div>`
1006
+ : html`<div class="s-api-key-unsupported"><span class="s-auth-state">${tn("unsupportedVerifier")}</span><p class="note">${tn("unsupportedVerifierHint")}</p></div>`}
1007
+ ${notes[spec.id] ? html`<p class=${`feedback${notes[spec.id].error ? " error" : ""}`} role="status">${notes[spec.id].error || notes[spec.id].text}</p>` : null}
1008
+ </div>`;
1009
+ })}</div>`}
1010
+ <p class="note s-api-action-note">${tn("uiProviderKeyActionHint")}</p>
935
1011
  </section>`;
936
1012
  }
937
1013
 
938
1014
  function Classic({ ctx, search, openDialog }) {
939
1015
  const rooms = Object.entries((ctx.classic && ctx.classic.channels) || {}).map(([key, ch]) => ({ key, ...ch }));
940
- if (!rooms.length) return html`<${Empty} icon="room" title=${tn("noClassic")} />`;
1016
+ if (!rooms.length) return html`<div class="s-chat-empty"><${Icon} name="room" size=${22} /><p>${tn("noClassic")}</p></div>`;
941
1017
  const needle = search.trim().toLowerCase();
942
1018
  const list = rooms.filter((c) => !needle || String(c.name || "").toLowerCase().includes(needle) || String(c.instanceName || "").toLowerCase().includes(needle))
943
1019
  .sort((a, b) => ((STATUS_ORDER[ctx.classicRuntime(a.instanceName).status] ?? 9) - (STATUS_ORDER[ctx.classicRuntime(b.instanceName).status] ?? 9))
944
1020
  || String(a.name || "").localeCompare(String(b.name || "")));
945
- if (!list.length) return html`<${Empty} icon="search" title=${tn("noAgentMatch", search.trim())} />`;
946
- return html`<div class="list-head"><span>${rooms.length === 1 ? tn("countRoom") : tn("countRooms", rooms.length)}</span></div><div class="s-list">${list.map((c) => {
1021
+ if (!list.length) return html`<div class="s-chat-empty"><${Icon} name="search" size=${22} /><p>${tn("noAgentMatch", search.trim())}</p></div>`;
1022
+ return html`<div class="list-head s-list-toolbar"><span>${rooms.length === 1 ? tn("countRoom") : tn("countRooms", rooms.length)}</span></div><div class="s-list s-classic-list"><div class="s-list-columns s-classic-columns" aria-hidden="true"><span>${tn("uiClassicColumnRoom")}</span><span>${tn("uiAgentColumnCli")}</span><span>${tn("uiListColumnState")}</span><span>${tn("uiListColumnActions")}</span></div>${list.map((c) => {
947
1023
  const rt = ctx.classicRuntime(c.instanceName);
948
1024
  const sum = effectiveSummary(ctx.live[c.instanceName] || {}, c, ctx.fleet.defaults || {}, (ctx.classic && ctx.classic.defaults) || {});
949
1025
  const adapter = c.adapterId || "discord";
950
- return html`<div key=${c.key} class="s-row">
951
- <span class=${dotClass(rt.execution)} title=${tn(`exec_${rt.execution}`)} aria-hidden="true"></span>
952
- <span class="s-name" title=${c.instanceName || ""}>${shortName(c.name || c.instanceName || "?", { display_name: c.display_name })}</span>
953
- <span class="s-meta" title=${sum.backend}>${sum.model}</span>
954
- <span class="s-br" aria-hidden="true"></span>
955
- <span class="tag">${tn("effortTag", sum.effort)}</span>
956
- <span class=${`tag${adapter !== "discord" ? " persona" : ""}`}>${adapter}</span>
957
- ${c.collab ? html`<span class="tag">collab</span>` : null}
958
- <span class="tag">${tn(`exec_${rt.execution}`)}</span>
1026
+ return html`<div key=${c.key} class="s-row s-classic-row">
1027
+ <div class="s-classic-identity"><span class="s-name" title=${c.instanceName || ""}>${shortName(c.name || c.instanceName || "?", { display_name: c.display_name })}</span>
1028
+ <div class="s-agent-context"><span class="tag">${tn("effortTag", sum.effort)}</span><span class=${`tag${adapter !== "discord" ? " persona" : ""}`}>${adapter}</span>${c.collab ? html`<span class="tag">collab</span>` : null}</div>
1029
+ </div>
1030
+ <div class="s-classic-cli"><${CliProductMark} id=${sum.backend} size=${20} /><span><strong>${cliLabel(sum.backend)}</strong><span class="s-meta" title=${sum.model}>${sum.model}</span></span></div>
1031
+ <span class="s-classic-status"><span class=${dotClass(rt.execution)} aria-hidden="true"></span><span>${tn(`exec_${rt.execution}`)}</span></span>
959
1032
  <span class="s-actions">
960
1033
  <button type="button" class="btn btn-sm" onClick=${() => openDialog({ kind: "classic", room: c })}>${tn("settingsButton")}</button>
961
1034
  ${rt.status === "running" ? html`<button type="button" class="btn btn-sm" onClick=${() => ctx.pauseWake(c.instanceName, "pause")}>${tn("pause")}</button>` : null}
@@ -1005,7 +1078,6 @@ function General({ ctx, part = "all" }) {
1005
1078
  const { schema } = ctx;
1006
1079
  const d = ctx.fleet.defaults || {}, c = (ctx.classic && ctx.classic.defaults) || {};
1007
1080
  const hang = d.hang_detector || {}, startup = d.startup || {};
1008
- const primary = channelsOf(ctx.fleet)[0];
1009
1081
  const original = useMemo(() => ({ c: structuredClone(c) }), []);
1010
1082
  const base = useMemo(() => generalForm(d, c, ctx.fleet, schema), []);
1011
1083
  const [f, setF] = useDraft(ctx, "general", () => base);
@@ -1021,6 +1093,9 @@ function General({ ctx, part = "all" }) {
1021
1093
  const warnings = { concurrency: f.concurrency.trim() !== "" && num(f.concurrency) > 4 ? "concurrencyWarning" : "", stagger: num(f.stagger) < 100 ? "staggerWarning" : "" };
1022
1094
  const ready = !Object.values(errors).some(Boolean);
1023
1095
  const firstError = Object.values(errors).find(Boolean);
1096
+ // What saving the edited fields costs (the schema's impact, the agents that set the field themselves): shown under each
1097
+ // edited field, and added up on the Save bar.
1098
+ const notes = sharedNotes({ schema, fleet: ctx.fleet, classic: ctx.classic, classicStatus: (name) => ctx.classicRuntime(name).status, live: ctx.live, fleetUp: ctx.fleetUp, f, base, errors });
1024
1099
  // #2347: every edit, staged as it is made (the first render included: a draft kept from before is staged again).
1025
1100
  useEffect(() => {
1026
1101
  if (!ready) {
@@ -1067,10 +1142,12 @@ function General({ ctx, part = "all" }) {
1067
1142
  // that sets it (POST /ui/config; a change to it waits for a fleet admin's OK, as it did there).
1068
1143
  const roots = f.roots.map((r) => String(r).trim()).filter(Boolean); // ChipList keeps "2024" as a number; paths are text
1069
1144
  syncStage(ctx, "fleet:project_roots", sameValue(roots, base.roots) ? null : { label: tn("projectRootsTitle"), count: 1,
1070
- impact: impactOf(schema, "fleet.project_roots"), request: { method: "POST", url: "/ui/config", body: { project_roots: roots } } });
1145
+ impact: impactOf(schema, "fleet.project_roots"), notes: notes.bar.roots,
1146
+ request: { method: "POST", url: "/ui/config", body: { project_roots: roots } } });
1071
1147
  const dKeys = Object.keys(defaultsPatch), cKeys = Object.keys(classicPatch);
1148
+ // The bar says what this Save costs in the page's own words (how many agents restart), not a bare impact label.
1072
1149
  syncStage(ctx, "defaults:fleet", dKeys.length ? { label: tn("updateDefaults"), count: dKeys.length,
1073
- impact: batchImpact(schema, dKeys, (k) => defaultsImpact(schema, k)),
1150
+ impact: batchImpact(schema, dKeys, (k) => defaultsImpact(schema, k)), notes: notes.bar.defaults,
1074
1151
  request: { method: "PUT", url: "/api/settings/fleet/defaults", body: defaultsPatch } } : null);
1075
1152
  syncStage(ctx, "defaults:classic", cKeys.length ? { label: tn("updateClassicDefaults"), count: cKeys.length,
1076
1153
  impact: cKeys.every((k) => impactOf(schema, `classic_defaults.${k}`) === "now") ? "now" : "fleet",
@@ -1084,39 +1161,17 @@ function General({ ctx, part = "all" }) {
1084
1161
  log_level: !d.log_level, agent_mode: !d.agent_mode, hangOn: !hasOwn(hang, "enabled"), hang: !hasOwn(hang, "timeout_minutes"),
1085
1162
  concurrency: !hasOwn(startup, "concurrency"), stagger: !hasOwn(startup, "stagger_delay_ms"),
1086
1163
  };
1087
- const dm = (k) => (unset[k] && sameValue(f[k], base[k]) ? html`<${DefaultMark} />` : null);
1088
1164
  const fromDefaults = (k, value, target) => ({ text: valueText(value), builtin: !hasOwn(d, k), from: inAgentDefaults(target) });
1089
- const L = (text, field, id, k) => html`<${Label} text=${text} schema=${schema} field=${field} htmlFor=${id} mark=${k ? dm(k) : null} />`;
1165
+ const L = (text, field, id) => html`<${Label} text=${text} schema=${schema} field=${field} htmlFor=${id} />`;
1090
1166
  const fleetReply = replyGuardSupported(f.backend, f.agent_mode, d.kiro_ui) ? tn("replyGuardSupported") : tn("replyGuardUnsupported", f.backend, f.agent_mode);
1091
1167
  const classicReply = replyGuardSupported(f.classicBackend, f.agent_mode, d.kiro_ui) ? tn("replyGuardSupported") : tn("replyGuardUnsupported", f.classicBackend, f.agent_mode);
1092
1168
  // #2347: Agent defaults show the fleet's part; Chat & connections ClassicBot's. One form, one draft either way.
1093
1169
  const fleetPart = part !== "classic", classicPart = part !== "fleet";
1094
- return html`<div class=${`form s-general s-part-${part}`}>
1095
- ${fleetPart ? html`<section class="card"><h3>${tn("defaultsTitle")}</h3>
1096
- <div class="grid2">
1097
- <div class=${fc("field", "locale")}>${L(tn("language"), "defaults.locale", "g-locale", "locale")}<${Select} id="g-locale" value=${f.locale} onChange=${set("locale")}
1098
- options=${localeOptions(f.locale).map((o) => (o.auto ? { value: "", label: tn("localeAuto") } : o))} /></div>
1099
- <div class=${fc("field", "backend")}>${L(tn("defaultBackend"), "defaults.backend", "g-be", "backend")}<${BackendSelect} id="g-be" value=${f.backend} onChange=${set("backend")} /></div>
1100
- <div class=${fc("field", "model")}>${L(tn("defaultModel"), "defaults.model", "g-model", "model")}<${ModelSelect} id="g-model" value=${f.model} onChange=${set("model")}
1101
- backend=${f.backend || "claude-code"} inherit=${tn("modelCliDefault")} /></div>
1102
- <div class=${fc("field", "auto")}>${L(`${tn("autoPause")} (${tn("minutes")})`, "defaults.auto_pause_after", "g-auto", "auto")}<input id="g-auto" type="number" min="0" step="1" class=${errors.auto ? "invalid" : ""} value=${f.auto} onInput=${(e) => set("auto")(e.target.value)} /><${Feedback} error=${errors.auto} /></div>
1103
- <div class=${fc("field", "tool_progress")}>${L(tn("toolProgress"), "defaults.tool_progress", "g-tp", "tool_progress")}<${Select} id="g-tp" value=${f.tool_progress} onChange=${set("tool_progress")} options=${TOOL_PROGRESS} /></div>
1104
- <div class=${fc("field", "visibility")}>${L(tn("crossInstanceVisibility"), "defaults.cross_instance_visibility", "g-vis", "visibility")}<${Select} id="g-vis" value=${f.visibility} onChange=${set("visibility")} options=${VISIBILITY_MODES} />
1105
- <p class="note">${tn("crossInstanceVisibilityHint")}</p></div>
1106
- <div class=${fc("field", "tips")}>${L(tn("dailyTips"), "defaults.tips", "g-tips", "tips")}<${Select} id="g-tips" value=${f.tips} onChange=${set("tips")} options=${noticeChoices()} /><${InEffect} text=${noticeLabel(noticeMode(f.tips))} /><p class="note">${tn("dailyTipsHint")}</p></div>
1107
- <div class=${fc("field", "replyTriggers")}><label class="check"><input id="g-reply-triggers" type="checkbox" checked=${f.replyTriggers} onChange=${(e) => set("replyTriggers")(e.target.checked)} /><span>${tn("replyTriggers")}</span>${dm("replyTriggers")}<${Impact} schema=${schema} field="defaults.reply_triggers" /></label><p class="note">${tn("replyTriggersHint")}</p></div>
1108
- <div class=${fc("field", "reply")}><label class="check"><input id="g-reply" type="checkbox" checked=${f.reply} onChange=${(e) => set("reply")(e.target.checked)} /><span>${tn("replyCompletionGuard")}</span>${dm("reply")}<${Impact} schema=${schema} field="defaults.reply_completion_guard" /></label>
1109
- <p class="note">${fleetReply}</p></div>
1110
- </div>
1111
- <fieldset id="g-dash" class=${fc("field dash-perms", ...DASHBOARD_FEATURES.map((k) => `dash_${k}`))}><legend>${L(tn("dashboardAccess"), "defaults.dashboard")}</legend>
1112
- <p class="note">${tn("dashboardDefaultsHint")}</p>
1113
- ${DASHBOARD_FEATURES.map((k) => html`<label key=${k} class="check"><input type="checkbox" checked=${f[`dash_${k}`]}
1114
- onChange=${(e) => set(`dash_${k}`)(e.target.checked)} /><span>${tn(`dashboard_${k}`)}</span></label>`)}
1115
- </fieldset>
1116
- </section>` : null}
1117
- ${classicPart ? html`<section class="card"><h3>${tn("classicDefaultsTitle")}</h3>
1170
+ return html`<div class=${fleetPart ? "s-defaults-layout" : "s-classic-layout"}><div class=${`form s-general s-part-${part}`}>
1171
+ ${fleetPart ? html`<${SharedAgentSettings} ctx=${ctx} form=${{ f, set, base, errors, warnings, unset, fc, notes, replyNote: fleetReply }} />` : null}
1172
+ ${classicPart ? html`<section class="card s-classic-defaults-card"><h3>${tn("classicDefaultsTitle")}</h3>
1118
1173
  <div class="grid2">
1119
- <div class=${fc("field", "classicBackend")}>${L(tn("classicBackend"), "classic_defaults.backend", "g-cbe")}<${BackendSelect} id="g-cbe" value=${f.classicBackend} onChange=${set("classicBackend")} />
1174
+ <div class=${fc("field", "classicBackend")}>${L(tn("classicBackend"), "classic_defaults.backend", "g-cbe")}<${BackendSelect} id="g-cbe" value=${f.classicBackend} onChange=${set("classicBackend")} hostOnly />
1120
1175
  ${!c.backend && f.classicBackend === base.classicBackend ? html`<${Inherited} text=${valueText(f.classicBackend, "backend")} builtin=${!d.backend} from=${inAgentDefaults("#g-be")} />` : null}</div>
1121
1176
  <div class=${fc("field", "classicToolProgress", "classicToolProgressInherit")}>${L(tn("toolProgress"), "classic_defaults.tool_progress", "g-ctp")}
1122
1177
  <${Override} inherit=${f.classicToolProgressInherit} onInherit=${set("classicToolProgressInherit")} inherited=${fromDefaults("tool_progress", d.tool_progress ?? "off", "#g-tp")}>
@@ -1135,31 +1190,7 @@ function General({ ctx, part = "all" }) {
1135
1190
  <div id="g-guilds" class=${fc("field", "guilds")}>${L(tn("allowedGuilds"), "classic.allowed_guilds")}<${ChipList} items=${f.guilds} onChange=${set("guilds")} placeholder=${tn("guildIdPlaceholder")} label=${tn("allowedGuilds")} /></div>
1136
1191
  </div>
1137
1192
  </section>` : null}
1138
- ${fleetPart ? html`<section class="card" id="project-roots"><h3>${tn("projectRootsTitle")}</h3>
1139
- <p class="note">${tn("projectRootsHint")}</p>
1140
- <div id="g-roots" class=${fc("field", "roots")}>${L(tn("projectRootsTitle"), "fleet.project_roots")}<${ChipList} items=${f.roots} onChange=${set("roots")} placeholder="/path/to/projects" label=${tn("projectRootsTitle")} />
1141
- ${f.roots.length ? null : html`<${InEffect} text=${tn("projectRootsAnywhere")} />`}</div>
1142
- </section>` : null}
1143
- ${fleetPart ? html`<${Drawer} title=${tn("advancedSection")}>
1144
- <section class="card"><h3>${tn("runtimeResources")}</h3><div class="grid2">
1145
- <div class=${fc("field", "tool_set")}>${L(tn("toolSet"), "defaults.tool_set", "g-ts", "tool_set")}<${Select} id="g-ts" value=${f.tool_set} onChange=${set("tool_set")}
1146
- options=${[{ value: "", label: tn("toolSetUnset", toolSetDefault({}, {}), toolSetDefault({}, { general_topic: true })) }, ...TOOL_SETS]} /></div>
1147
- <div class=${fc("field", "log_level")}>${L(tn("logLevel"), "defaults.log_level", "g-ll", "log_level")}<${Select} id="g-ll" value=${f.log_level} onChange=${set("log_level")} options=${LOG_LEVELS} /></div>
1148
- <div class=${fc("field", "agent_mode")}>${L(tn("agentMode"), "defaults.agent_mode", "g-am", "agent_mode")}<${Select} id="g-am" value=${f.agent_mode} onChange=${set("agent_mode")} options=${AGENT_MODES} /></div>
1149
- </div></section>
1150
- <section class="card"><h3>${tn("detection")}</h3><div class="grid2">
1151
- <label class=${fc("check", "hangOn")}><input id="g-hang-on" type="checkbox" checked=${f.hangOn} onChange=${(e) => set("hangOn")(e.target.checked)} /><span>${tn("hangEnabled")}</span>${dm("hangOn")}<${Impact} schema=${schema} field="defaults.hang_detector" /></label>
1152
- <div class=${fc("field", "hang")}>${L(`${tn("hangTimeout")} (${tn("minutes")})`, "defaults.hang_detector", "g-hang", "hang")}<input id="g-hang" type="number" min="0.1" step="0.5" class=${errors.hang ? "invalid" : ""} value=${f.hang} onInput=${(e) => set("hang")(e.target.value)} /><${Feedback} error=${errors.hang} /></div>
1153
- </div></section>
1154
- <section class="card"><h3>${tn("startup")}</h3><div class="grid2">
1155
- <div class=${fc("field", "concurrency")}>${L(tn("concurrency"), "fleet.spawn_concurrency", "g-conc")}<input id="g-conc" type="number" min="1" max="20" step="1" class=${errors.concurrency ? "invalid" : ""} value=${f.concurrency} onInput=${(e) => set("concurrency")(e.target.value)} /><${Feedback} error=${errors.concurrency} warning=${warnings.concurrency} />
1156
- ${f.concurrency.trim() === "" ? html`<${InEffect} text=${tn("concurrencyAuto")} />` : null}</div>
1157
- <div class=${fc("field", "stagger")}>${L(`${tn("staggerDelay")} (ms)`, "fleet.spawn_stagger_ms", "g-stag", "stagger")}<input id="g-stag" type="number" min="0" max="30000" step="100" class=${errors.stagger ? "invalid" : ""} value=${f.stagger} onInput=${(e) => set("stagger")(e.target.value)} /><${Feedback} error=${errors.stagger} warning=${warnings.stagger} /></div>
1158
- </div></section>
1159
- <section class="card"><h3>${tn("accessTitle")}</h3>
1160
- <p class="note">${primary ? tn("accessMovedHint", primary.id || chLabel(0)) : tn("noBots")}</p></section>
1161
- </${Drawer}>` : null}
1162
- </div>`;
1193
+ </div></div>`;
1163
1194
  }
1164
1195
 
1165
1196
  /**
@@ -1199,6 +1230,7 @@ export function uploadMbInEffect(web) {
1199
1230
  }
1200
1231
  function WebSection({ ctx, staged, part = "all" }) {
1201
1232
  const { schema } = ctx;
1233
+ const [accessTab, setAccessTab] = useSettingsTabs("access", "login");
1202
1234
  const web = ctx.fleet.web || {}, local = (web.session && web.session.local) || {}, term = ctx.fleet.web_terminal || {};
1203
1235
  // Over the public link the fields read only; the Guests and Web authority cards are not offered (the server never
1204
1236
  // serves their reads there).
@@ -1210,13 +1242,14 @@ function WebSection({ ctx, staged, part = "all" }) {
1210
1242
  usagePub: web.usage_report_on_public_link === true, // #2122: off by default
1211
1243
  levels: web.office_levels !== false, // #2661: on by default
1212
1244
  cdn: web.preview_cdn === true, // #2911 (7): off by default
1245
+ loginQr: web.login_qr === true, // #3061 (P2b): off by default
1213
1246
  pub: { allow_public: (web.public_link && web.public_link.allow_public) ?? true, ttl_minutes: (web.public_link && web.public_link.ttl_minutes) ?? 120, protocol: (web.public_link && web.public_link.protocol) ?? "http2", hostname: (web.public_link && web.public_link.hostname) ?? "", tunnel_token_env: (web.public_link && web.public_link.tunnel_token_env) ?? "", origin_port: (web.public_link && web.public_link.origin_port) ?? 19282, auto_open: (web.public_link && web.public_link.auto_open) ?? false },
1214
1247
  session: { absolute_hours: local.absolute_hours ?? null, idle_hours: local.idle_hours ?? null },
1215
1248
  terminal: { enabled: term.enabled ?? null, ttl_minutes: term.ttl_minutes ?? null },
1216
1249
  }), []);
1217
1250
  const text = (v) => (v === null || v === undefined ? "" : String(v));
1218
1251
  /** #2347: a field's row class: `s-dirty` while it differs from what is saved (the draft may come from before). */
1219
- const savedForm = useMemo(() => ({ notify: String(original.notify), echo: original.echo, log: original.log, usagePub: original.usagePub, levels: original.levels, cdn: original.cdn, pub: original.pub.allow_public,
1252
+ const savedForm = useMemo(() => ({ notify: String(original.notify), echo: original.echo, log: original.log, usagePub: original.usagePub, levels: original.levels, cdn: original.cdn, loginQr: original.loginQr, pub: original.pub.allow_public,
1220
1253
  ttl: String(original.pub.ttl_minutes), protocol: original.pub.protocol, hostname: original.pub.hostname, originPort: String(original.pub.origin_port),
1221
1254
  abs: text(original.session.absolute_hours), idle: text(original.session.idle_hours), termOn: original.terminal.enabled !== false,
1222
1255
  termTtl: text(original.terminal.ttl_minutes), autoOpen: original.pub.auto_open }), []);
@@ -1230,7 +1263,7 @@ function WebSection({ ctx, staged, part = "all" }) {
1230
1263
  return {
1231
1264
  notify: String(pick(pending, "notify_login", original.notify)),
1232
1265
  echo: pick(pending, "echo_to_channel", original.echo), log: pick(pending, "log_tab", original.log), usagePub: pick(pending, "usage_report_on_public_link", original.usagePub),
1233
- levels: pick(pending, "office_levels", original.levels), cdn: pick(pending, "preview_cdn", original.cdn),
1266
+ levels: pick(pending, "office_levels", original.levels), cdn: pick(pending, "preview_cdn", original.cdn), loginQr: pick(pending, "login_qr", original.loginQr),
1234
1267
  pub: pick(pub, "allow_public", original.pub.allow_public), ttl: String(pick(pub, "ttl_minutes", original.pub.ttl_minutes)), protocol: pick(pub, "protocol", original.pub.protocol),
1235
1268
  hostname: pick(pub, "hostname", original.pub.hostname), originPort: String(pick(pub, "origin_port", original.pub.origin_port)), autoOpen: pick(pub, "auto_open", original.pub.auto_open),
1236
1269
  abs: text(pick(session, "absolute_hours", original.session.absolute_hours)), idle: text(pick(session, "idle_hours", original.session.idle_hours)),
@@ -1284,6 +1317,7 @@ function WebSection({ ctx, staged, part = "all" }) {
1284
1317
  ...(f.usagePub !== original.usagePub ? { usage_report_on_public_link: f.usagePub } : {}),
1285
1318
  ...(f.levels !== original.levels ? { office_levels: f.levels } : {}),
1286
1319
  ...(f.cdn !== original.cdn ? { preview_cdn: f.cdn } : {}),
1320
+ ...(f.loginQr !== original.loginQr ? { login_qr: f.loginQr } : {}),
1287
1321
  ...(Object.keys(publicPatch).length ? { public_link: publicPatch } : {}),
1288
1322
  ...(Object.keys(sessionPatch).length ? { session: { local: sessionPatch } } : {}),
1289
1323
  ...(Object.keys(terminalPatch).length ? { web_terminal: terminalPatch } : {}),
@@ -1295,6 +1329,7 @@ function WebSection({ ctx, staged, part = "all" }) {
1295
1329
  ...(body.usage_report_on_public_link !== undefined ? ["web.usage_report_on_public_link"] : []),
1296
1330
  ...(body.office_levels !== undefined ? ["web.office_levels"] : []),
1297
1331
  ...(body.preview_cdn !== undefined ? ["web.preview_cdn"] : []),
1332
+ ...(body.login_qr !== undefined ? ["web.login_qr"] : []),
1298
1333
  ...Object.keys(publicPatch).map((k) => `web.public_link.${k}`),
1299
1334
  ...Object.keys(sessionPatch).map((k) => `web.session.local.${k}`),
1300
1335
  ...Object.keys(terminalPatch).map((k) => `web_terminal.${k}`),
@@ -1329,17 +1364,35 @@ function WebSection({ ctx, staged, part = "all" }) {
1329
1364
  if (v === undefined) return html`${roText(webReadOnlyDefault(path, ctx.fleet))} <${DefaultMark} />${capped ? html` <span class="tag">${tn("cappedByTotal")}</span>` : null}`;
1330
1365
  return applies === v ? roText(v) : html`${roText(v)} <span class="tag">${tn("inEffectShort", roText(applies))}</span>`;
1331
1366
  };
1332
- // #2347: one form, one draft, shown where each part belongs — Access & security (sessions, the browser terminal, the
1333
- // public link and its fixed address, guests, web authority), Chat & connections (web echo), Web dashboard (the Log tab,
1334
- // usage over the public link), Advanced (what only fleet.yaml sets).
1367
+ // One Web draft remains mounted across the Access tabs. A tab only changes what is visible;
1368
+ // validation, confirmation and staged writes continue to belong to the existing form.
1335
1369
  const has = (p) => part === "all" || part === p;
1336
1370
  const lock = (body) => html`<fieldset class="s-web-fields" disabled=${overPublicLink}>${body}</fieldset>`;
1371
+ const tabs = [
1372
+ { id: "login", label: layoutText("accessLogin") },
1373
+ { id: "guests", label: layoutText("accessGuests") },
1374
+ { id: "sharing", label: layoutText("accessSharing") },
1375
+ ];
1376
+ const toggleRow = (key, id, label, hint, impact) => html`<div class=${fc("s-setting-row", key)}>
1377
+ <div class="s-setting-copy"><label for=${id}>${part === "dashboard" ? layoutText(`revDashboard_${key}`) : tn(label)}<${Impact} schema=${schema} field=${impact} /></label>
1378
+ <p class="note" id=${`${id}-hint`}>${part === "dashboard" ? layoutText(`revDashboardHint_${key}`) : tn(hint)}</p>
1379
+ ${part === "dashboard" ? html`<details class="s-setting-details"><summary>${layoutText("revDetails")}</summary><p class="note"><strong>${tn(label)}</strong> ${tn(hint)}</p></details>` : null}
1380
+ </div>
1381
+ <input class="s-ui-toggle" id=${id} type="checkbox" checked=${f[key]} aria-describedby=${`${id}-hint`} onChange=${(e) => set(key)(e.target.checked)} />
1382
+ </div>`;
1383
+ const configured = (path) => { const [top, key] = path.split("."); return (top === "web" ? web : term)[key] !== undefined; };
1337
1384
  return html`<div class=${`form s-web s-part-${part}`}>
1338
- ${has("access") ? html`<p class="sub">${tn("webLead")}</p>` : null}
1339
- ${overPublicLink && part !== "readonly" ? html`<p class="note" role="status" id="webPublicRefused">${tn("webPublicRefused")}</p>` : null}
1340
- ${has("access") ? lock(html`<section class="card"><h3>${tn("webSessionTitle")}</h3>
1341
- <p class="note">${tn("webSessionHint")}</p>
1342
- <div class=${fc("field", "notify")}><label for="webNotifyLogin">${tn("webNotifyLogin")}<${Impact} schema=${schema} field="web.notify_login" /></label><${Select} id="webNotifyLogin" value=${f.notify} onChange=${set("notify")} options=${noticeChoices()} /><${InEffect} text=${noticeLabel(noticeMode(f.notify))} />${web.notify_login === undefined ? html`<${DefaultMark} />` : null}<p class="note">${tn("webNotifyLoginHint")}</p></div>
1385
+ ${overPublicLink && part !== "readonly" ? html`<p class="note s-access-notice" role="status" id="webPublicRefused">${tn("webPublicRefused")}</p>` : null}
1386
+ ${has("access") ? html`<${SettingsTabs} id="access" value=${accessTab} onChange=${setAccessTab} items=${tabs} />
1387
+ <div class="s-access-banner"><${Icon} name="info" size=${18} /><p>${layoutText("revAccessPolicy")}</p><details class="s-access-policy"><summary>${layoutText("revDetails")}</summary><p class="note">${tn("webLead")}</p></details></div>
1388
+ <${SettingsTabPanel} group="access" id="login" active=${accessTab === "login"}>
1389
+ <div class="s-access-login-layout"><div class="s-access-stack">
1390
+ ${/* #3008: a web-only fleet's connections from outside — changed on this computer only, shown (read-only) elsewhere. */ ""}
1391
+ <${OutsideCard} />
1392
+ ${/* Refs #3061 (P2a): sign a new device in with its 8-character code — approved here by the verified owner. */ ""}
1393
+ <${DevicesCard} />
1394
+ ${lock(html`<section class="card s-access-session"><h3>${layoutText("revLoginSessions")}</h3>
1395
+ <div class=${fc("field", "notify")}><label for="webNotifyLogin">${tn("webNotifyLogin")}<${Impact} schema=${schema} field="web.notify_login" /></label><${Select} id="webNotifyLogin" value=${f.notify} onChange=${set("notify")} options=${noticeChoices()} /><${InEffect} text=${noticeLabel(noticeMode(f.notify))} /></div>
1343
1396
  <div class="grid2">
1344
1397
  <div class=${fc("field", "abs")}><label for="webSessionAbsolute">${tn("sessionAbsolute")}</label><input id="webSessionAbsolute" type="number" min="1" max="720" step="any"
1345
1398
  class=${errors.abs ? "invalid" : ""} value=${f.abs} onInput=${(e) => set("abs")(e.target.value)} /><${Feedback} error=${errors.abs} />
@@ -1348,8 +1401,16 @@ function WebSection({ ctx, staged, part = "all" }) {
1348
1401
  class=${errors.idle ? "invalid" : ""} value=${f.idle} onInput=${(e) => set("idle")(e.target.value)} /><${Feedback} error=${errors.idle} />
1349
1402
  ${value(f.idle) === null && !errors.abs ? html`<${InEffect} text=${tn("hoursValue", idle)} why=${idle < 48 ? tn("cappedBySession") : null} />` : null}</div>
1350
1403
  </div>
1351
- </section>
1352
- <section class="card"><h3>${tn("webTerminalTitle")}</h3>
1404
+ <p class="note s-session-ceiling">${layoutText("revPublicSessionLimit")}</p>
1405
+ ${/* Refs #3061 (P2b): the QR code on a new device's sign-in page (a web-only fleet's "Sign in with another device"). */ ""}
1406
+ <label class=${fc("check", "loginQr")}><input id="webLoginQr" type="checkbox" checked=${f.loginQr} aria-describedby="webLoginQr-hint" onChange=${(e) => set("loginQr")(e.target.checked)} /><span>${tn("webLoginQr")}</span><${Impact} schema=${schema} field="web.login_qr" /></label>
1407
+ <p class="note" id="webLoginQr-hint">${tn("webLoginQrHint")}</p>
1408
+ <details class="s-setting-details"><summary>${layoutText("revSessionDetails")}</summary><p class="note">${tn("webSessionHint")}</p><p class="note">${tn("webNotifyLoginHint")}</p></details>
1409
+ </section>`)}
1410
+ ${!overPublicLink ? html`<${WebAuthorityCard} ctx=${ctx} staged=${staged} />` : null}
1411
+ ${!overPublicLink ? html`<${HubCardSlot} />` : null}
1412
+ ${!overPublicLink && ctx.fleet.hub?.hubId ? html`<${HubRetentionSlot} /><${HubBrowserCertificateSlot} />` : null}
1413
+ <details class="drawer s-terminal-disclosure"><summary>${tn("webTerminalTitle")}</summary><div class="drawer-body">${lock(html`<section class="card s-access-terminal"><h3>${tn("webTerminalTitle")}</h3>
1353
1414
  <p class="note">${tn("webTerminalHint")}</p>
1354
1415
  <label class=${fc("check", "termOn")}><input id="webTerminalEnabled" type="checkbox" checked=${f.termOn} onChange=${(e) => set("termOn")(e.target.checked)} /><span>${tn("webTerminalEnabled")}</span><${Impact} schema=${schema} field="web_terminal.enabled" /></label>
1355
1416
  <div class="grid2">
@@ -1357,8 +1418,18 @@ function WebSection({ ctx, staged, part = "all" }) {
1357
1418
  class=${errors.termTtl ? "invalid" : ""} value=${f.termTtl} onInput=${(e) => set("termTtl")(e.target.value)} /><${Feedback} error=${errors.termTtl} />
1358
1419
  ${value(f.termTtl) === null ? html`<${InEffect} text=${tn("minutesValue", 10)} />` : null}</div>
1359
1420
  </div>
1360
- </section>
1361
- <section class="card"><h3>${tn("publicLinkTitle")}</h3>
1421
+ </section>`)}</div></details>
1422
+ </div><aside class="card s-access-related"><h3>${layoutText("revRelatedAccess")}</h3>
1423
+ <button type="button" onClick=${() => setAccessTab("guests")}><${Icon} name="user" size=${18} /><span><strong>${layoutText("accessGuests")}</strong><small>${layoutText("revRelatedGuests")}</small></span><${Icon} name="chevron" size=${16} /></button>
1424
+ <button type="button" onClick=${() => setAccessTab("sharing")}><${Icon} name="globe" size=${18} /><span><strong>${layoutText("accessSharing")}</strong><small>${layoutText("revRelatedSharing")}</small></span><${Icon} name="chevron" size=${16} /></button>
1425
+ </aside></div>
1426
+ </${SettingsTabPanel}>
1427
+ <${SettingsTabPanel} group="access" id="guests" active=${accessTab === "guests"}>
1428
+ ${!overPublicLink ? html`<${GuestsCard} ctx=${ctx} staged=${staged} />` : html`<p class="note">${tn("webPublicRefused")}</p>`}
1429
+ </${SettingsTabPanel}>
1430
+ <${SettingsTabPanel} group="access" id="sharing" active=${accessTab === "sharing"}>
1431
+ <div class="s-access-stack">
1432
+ ${lock(html`<section class="card s-public-entry"><h3>${layoutText("revPublicEntry")}</h3>
1362
1433
  <label class=${fc("check", "pub")}><input id="publicWebLink" type="checkbox" checked=${f.pub} onChange=${(e) => set("pub")(e.target.checked)} /><span>${tn("publicLink")}</span><${Impact} schema=${schema} field="web.public_link.allow_public" /></label>
1363
1434
  <p class="note">${tn("publicLinkHint")}</p>
1364
1435
  <div class="grid2">
@@ -1374,35 +1445,31 @@ function WebSection({ ctx, staged, part = "all" }) {
1374
1445
  ${named ? html`<p class="note" id="publicTtlNamedHint">${tn("publicTtlNamedHint")}</p>` : null}
1375
1446
  ${named || f.autoOpen ? html`<label class=${fc("check", "autoOpen")}><input id="publicAutoOpen" type="checkbox" checked=${f.autoOpen} onChange=${(e) => set("autoOpen")(e.target.checked)} /><span>${tn("publicAutoOpen")}</span><${Impact} schema=${schema} field="web.public_link.auto_open" /></label>
1376
1447
  <p class="note">${tn("publicAutoOpenHint")}</p><${Feedback} error=${errors.autoOpen} />` : null}
1448
+
1449
+ ${!overPublicLink ? html`<div class="s-public-credentials"><${PublicTunnelToken} /></div>` : null}
1450
+ </section>`)}
1451
+ <div class="s-sharing-list"><h3>${layoutText("revReadOnlySharing")}</h3><p class="note">${layoutText("revSharingOrigin")}</p><${OfficeSharesCard} /><${PageSharesCard} /></div>
1452
+ </div>
1453
+ </${SettingsTabPanel}>` : null}
1454
+ ${has("chat") ? lock(html`<section class="card s-web-chat"><h3>${layoutText("messageBehavior")}</h3>
1455
+ ${toggleRow("echo", "webEchoToChannel", "webEcho", "webEchoHint", "web.echo_to_channel")}
1377
1456
  </section>`) : null}
1378
- ${has("access") && !overPublicLink ? html`<${PublicTunnelToken} />` : null}
1379
- ${has("access") ? html`<${OfficeSharesCard} />` : null}
1380
- ${has("access") ? html`<${PageSharesCard} />` : null}
1381
- ${has("access") && !overPublicLink ? html`<${GuestsCard} ctx=${ctx} staged=${staged} /><${WebAuthorityCard} ctx=${ctx} staged=${staged} />` : null}
1382
- ${/* #3008: a web-only fleet's connections from outside — changed on this computer only, shown (read-only) elsewhere. */ ""}
1383
- ${has("access") ? html`<${OutsideCard} />` : null}
1384
- ${has("chat") ? lock(html`<section class="card"><h3>${tn("webChat")}</h3>
1385
- <label class=${fc("check", "echo")}><input id="webEchoToChannel" type="checkbox" checked=${f.echo} onChange=${(e) => set("echo")(e.target.checked)} /><span>${tn("webEcho")}</span><${Impact} schema=${schema} field="web.echo_to_channel" /></label>
1386
- <p class="note">${tn("webEchoHint")}</p>
1387
- </section>`) : null}
1388
- ${has("dashboard") ? lock(html`<section class="card"><h3>${tn("webDashboardTitle")}</h3>
1389
- <label class=${fc("check", "log")}><input id="webLogTab" type="checkbox" checked=${f.log} onChange=${(e) => set("log")(e.target.checked)} /><span>${tn("webLogTab")}</span><${Impact} schema=${schema} field="web.log_tab" /></label>
1390
- <p class="note">${tn("webLogTabHint")}</p>
1391
- <label class=${fc("check", "usagePub")}><input id="webUsagePublic" type="checkbox" checked=${f.usagePub} onChange=${(e) => set("usagePub")(e.target.checked)} /><span>${tn("webUsagePublic")}</span><${Impact} schema=${schema} field="web.usage_report_on_public_link" /></label>
1392
- <p class="note">${tn("webUsagePublicHint")}</p>
1393
- <label class=${fc("check", "levels")}><input id="webOfficeLevels" type="checkbox" checked=${f.levels} onChange=${(e) => set("levels")(e.target.checked)} /><span>${tn("webOfficeLevels")}</span><${Impact} schema=${schema} field="web.office_levels" /></label>
1394
- <p class="note">${tn("webOfficeLevelsHint")}</p>
1395
- <label class=${fc("check", "cdn")}><input id="webPreviewCdn" type="checkbox" checked=${f.cdn} onChange=${(e) => set("cdn")(e.target.checked)} /><span>${tn("webPreviewCdn")}</span><${Impact} schema=${schema} field="web.preview_cdn" /></label>
1396
- <p class="note">${tn("webPreviewCdnHint")}</p>
1457
+ ${has("dashboard") ? lock(html`<section class="card s-dashboard-features"><h3>${layoutText("dashboardFeatures")}</h3>
1458
+ ${toggleRow("log", "webLogTab", "webLogTab", "webLogTabHint", "web.log_tab")}
1459
+ ${toggleRow("usagePub", "webUsagePublic", "webUsagePublic", "webUsagePublicHint", "web.usage_report_on_public_link")}
1460
+ ${toggleRow("levels", "webOfficeLevels", "webOfficeLevels", "webOfficeLevelsHint", "web.office_levels")}
1461
+ ${toggleRow("cdn", "webPreviewCdn", "webPreviewCdn", "webPreviewCdnHint", "web.preview_cdn")}
1397
1462
  </section>`) : null}
1398
- ${has("readonly") ? html`<section class="card s-web-readonly"><h3>${tn("webReadOnlyTitle")}</h3>
1399
- <p class="note">${tn("webReadOnlyLead")}</p>
1400
- <dl class="s-web-ro">${WEB_READ_ONLY.map((k) => html`<div key=${k}><dt><code>${k}</code></dt><dd>${shown(k)}</dd></div>`)}</dl>
1401
- <p class="note">${tn("webSearchHint")}</p>
1402
- </section>` : null}
1463
+ ${has("readonly") ? html`<div class="s-effective-view"><p class="s-effective-notice"><${Icon} name="info" size=${18} />${layoutText("revEffectiveHint")}</p>
1464
+ <section class="card s-web-readonly"><h3 class="sr-only">${tn("webReadOnlyTitle")}</h3>
1465
+ <div class="s-ro-columns" aria-hidden="true"><span>${layoutText("effectiveKey")}</span><span>${layoutText("effectiveValue")}</span><span>${layoutText("effectiveSource")}</span></div>
1466
+ ${["web", "web_terminal"].map(group => html`<h4 class="s-ro-group">${group === "web" ? tn("sec_web-dashboard") : tn("webTerminalTitle")}</h4>
1467
+ <dl class="s-web-ro">${WEB_READ_ONLY.filter(k => k.startsWith(`${group}.`)).map((k) => html`<div key=${k}><dt><code>${k}</code></dt><dd class="s-ro-value">${shown(k)}</dd><dd class="s-ro-source" aria-label=${layoutText("effectiveSource")}><span class="tag">${layoutText(configured(k) ? "effectiveSourceConfig" : "effectiveSourceDefault")}</span></dd></div>`)}</dl>`)}
1468
+ </section><div class="s-effective-footnotes"><p class="note">${tn("webReadOnlyLead")}</p><p class="note">${tn("webSearchHint")}</p></div>
1469
+ <div class="s-effective-actions"><button type="button" class="btn" onClick=${() => revealSettingsTarget(document.getElementById("advanced-panel-editor"))}><${Icon} name="edit" size=${16} />${layoutText("revGoEditor")}</button></div>
1470
+ </div>` : null}
1403
1471
  </div>`;
1404
1472
  }
1405
-
1406
1473
  /**
1407
1474
  * Developer: the fleet model as YAML or JSON, to read, copy, download — or edit. #2347: an edit's Apply stages its
1408
1475
  * writes in the Save bar like every form's change (Save writes them, in order, then one apply; Discard drops them),
@@ -1456,14 +1523,15 @@ function Developer({ ctx }) {
1456
1523
  return html`<section class="card s-dev">
1457
1524
  <div class="s-dev-bar">
1458
1525
  <div class="seg-inline" role="group" aria-label=${tn("format")}>
1459
- ${["yaml", "json"].map((k) => html`<button key=${k} type="button" class=${`btn btn-sm${fmt === k ? " on" : ""}`} aria-pressed=${fmt === k ? "true" : "false"} onClick=${() => setFmt(k)}>${k.toUpperCase()}</button>`)}</div>
1460
- <button type="button" class="btn btn-sm" disabled=${blocked && !editing} title=${blocked && !editing ? tn("devFormsUnsaved") : undefined} onClick=${() => setEditing(!editing)}>${editing ? tn("viewMode") : tn("editMode")}</button>
1526
+ ${["yaml", "json"].map((k) => html`<button key=${k} type="button" class=${`btn btn-sm${fmt === k ? " on" : ""}`} aria-pressed=${fmt === k ? "true" : "false"} onClick=${() => setFmt(k)}>${k.toUpperCase()}</button>`)}</div><p class="s-dev-context"><${Icon} name="info" size=${15} />${layoutText("revEditorContext")}</p>
1527
+ <div class="s-dev-actions"><button type="button" class="btn btn-sm" disabled=${blocked && !editing} title=${blocked && !editing ? tn("devFormsUnsaved") : undefined} onClick=${() => setEditing(!editing)}>${editing ? tn("viewMode") : tn("editMode")}</button>
1461
1528
  <button type="button" class="btn btn-sm" title=${tn("copy")} onClick=${copy}><${Icon} name="copy" size=${14} /><span class="lbl">${tn("copy")}</span></button>
1462
- <button type="button" class="btn btn-sm" title=${tn("devDownload")} onClick=${download}><${Icon} name="download" size=${14} /><span class="lbl">${tn("devDownload")}</span></button>
1529
+ <button type="button" class="btn btn-sm" title=${tn("devDownload")} onClick=${download}><${Icon} name="download" size=${14} /><span class="lbl">${tn("devDownload")}</span></button></div>
1463
1530
  </div>
1464
1531
  ${editing ? html`<textarea class="s-yaml" aria-label=${tn("devEditor")} spellcheck=${false} wrap="off" value=${draft} onInput=${(e) => setDraft(e.target.value)}></textarea>
1465
1532
  <div class="save-row"><button type="button" class="btn btn-primary" disabled=${blocked} onClick=${save}>${tn("devApply")}</button><span class="note">${tn("devApplyHint")}</span></div>`
1466
- : html`<pre class="s-yaml">${text}</pre>`}
1533
+ : html`<pre class="s-yaml" tabindex="0">${text}</pre>`}
1534
+ <div class="s-dev-state"><span class="s-dev-file">fleet.yaml</span><${Icon} name=${editing ? "edit" : "view"} size=${14} /><span>${layoutText(editing ? "developerEditing" : "developerReadOnly")}</span></div>
1467
1535
  ${blocked ? html`<p class="note s-dev-blocked" role="status">${tn("devFormsUnsaved")}</p>`
1468
1536
  : held && !msg ? html`<p class="note s-dev-held" role="status">${tn("devStaged", heldCount)}</p>` : null}
1469
1537
  ${msg ? html`<p class=${`feedback${msg.error ? " error" : ""}`} role="status">${msg.error || msg.text}</p>` : null}
@@ -1476,16 +1544,23 @@ function Developer({ ctx }) {
1476
1544
  */
1477
1545
  function PendingBar({ staged, busy, onApply, onDiscard, section }) {
1478
1546
  const changes = [...staged.values()];
1479
- const kinds = [...new Set(changes.filter((c) => !c.invalid).map((c) => c.impact))];
1547
+ // What Save will cost, one line each: a change that knows its own words (the shared agent settings: how many agents
1548
+ // restart) says them; any other says its impact label.
1549
+ const costs = [];
1550
+ for (const c of changes) {
1551
+ if (c.invalid) continue;
1552
+ for (const line of Array.isArray(c.notes) && c.notes.length ? c.notes : [impactText(c.impact)]) if (!costs.includes(line)) costs.push(line);
1553
+ }
1480
1554
  const invalid = changes.filter((c) => c.invalid).length;
1481
1555
  // #2382 review: a field to fix in another section is named, and the message goes there (its field focused).
1482
1556
  const elsewhere = changes.find((c) => c.invalid && c.section && c.section !== section);
1557
+ const problem = elsewhere || changes.find((c) => c.invalid && c.target);
1483
1558
  const count = changes.reduce((n, c) => n + (Number.isInteger(c.count) && c.count > 0 ? c.count : 1), 0);
1484
1559
  return html`<div data-trust="panel-controls" class="s-pending" role="region" aria-label=${tn("pendingRegion")}>
1485
1560
  <strong>${tn("changesPending", count)}</strong>
1486
- <span class="note">${kinds.map(impactText).join(" · ")}</span>
1561
+ <span class="note">${costs.join(" · ")}</span>
1487
1562
  <span class="s-pending-actions">
1488
- ${!invalid ? null : elsewhere ? html`<button type="button" class="link-btn feedback error s-fix" role="status" onClick=${() => goToTarget(elsewhere.section, elsewhere.target)}>${tn("fixToSaveIn", invalid, tn(`sec_${elsewhere.section}`))}</button>`
1563
+ ${!invalid ? null : problem ? html`<button type="button" class="link-btn feedback error s-fix" role="status" onClick=${() => goToTarget(problem.section || section, problem.target)}>${elsewhere ? tn("fixToSaveIn", invalid, tn(`sec_${elsewhere.section}`)) : tn("fixToSave", invalid)}</button>`
1489
1564
  : html`<span class="feedback error s-fix" role="status">${tn("fixToSave", invalid)}</span>`}
1490
1565
  <button type="button" class="btn" onClick=${onDiscard} disabled=${busy}>${tn("discard")}</button>
1491
1566
  <button type="button" class="btn btn-primary" onClick=${onApply} disabled=${busy || invalid > 0} title=${busy ? tn("applyBusyLocal") : undefined}>${tn("applyChanges")}</button>
@@ -1592,12 +1667,11 @@ function PublicTunnelToken() {
1592
1667
  } catch { if (lease.current()) setMessage(tn("applyFailed")); }
1593
1668
  finally { inFlight.current = false; if (lease.current()) setBusy(false); }
1594
1669
  };
1595
- return html`<section class="card"><h3>${tn("namedToken")}</h3>
1670
+ return html`<section class="card s-tunnel-token"><div class="s-token-head"><h3>${tn("namedToken")}</h3><span class="tag">${present ? tn("keyConfigured") : tn("keyNotConfigured")}</span></div>
1596
1671
  <p class="note">${tn("namedTokenHint")}</p>
1597
- <span class="tag">${present ? tn("keyConfigured") : tn("keyNotConfigured")}</span>
1598
- <input id="publicTunnelToken" type="password" autocomplete="new-password" aria-label=${tn("namedToken")} value=${secret} onInput=${e => { setSecret(e.target.value); setTypedTunnelToken(e.target.value); }} />
1599
- <button type="button" class="btn btn-sm" disabled=${busy || !secret} onClick=${() => go(false)}>${tn("namedTokenSet")}</button>
1600
- <button type="button" class="btn btn-sm" disabled=${busy || !present} onClick=${() => go(true)}>${tn("namedTokenClear")}</button>
1672
+ <details class="s-token-editor"><summary>${layoutText(present ? "revUpdateCredential" : "revSetCredential")}</summary><div class="s-token-editor-body"><input class="s-token-input" id="publicTunnelToken" type="password" autocomplete="new-password" aria-label=${tn("namedToken")} value=${secret} onInput=${e => { setSecret(e.target.value); setTypedTunnelToken(e.target.value); }} />
1673
+ <div class="s-token-actions"><button type="button" class="btn btn-sm" disabled=${busy || !secret} onClick=${() => go(false)}>${tn("namedTokenSet")}</button>
1674
+ <button type="button" class="btn btn-sm" disabled=${busy || !present} onClick=${() => go(true)}>${tn("namedTokenClear")}</button></div></div></details>
1601
1675
  ${message ? html`<p class="note" role="status">${message}</p>` : null}
1602
1676
  </section>`;
1603
1677
  }