@maudecode/talaria-web 1.18.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (567) hide show
  1. package/_release.json +8 -8
  2. package/dist/api/auth-raw.js +16 -16
  3. package/dist/api/auth-raw.js.map +1 -1
  4. package/dist/api/automation-raw.d.ts +2 -2
  5. package/dist/api/automation-raw.js +32 -32
  6. package/dist/api/automation-raw.js.map +1 -1
  7. package/dist/api/automation-router.d.ts +102 -22
  8. package/dist/api/automation-router.js +15 -13
  9. package/dist/api/automation-router.js.map +1 -1
  10. package/dist/api/chat-router.d.ts +1205 -34
  11. package/dist/api/chat-router.js +158 -78
  12. package/dist/api/chat-router.js.map +1 -1
  13. package/dist/api/git-router.d.ts +2 -2
  14. package/dist/api/git-router.js +29 -29
  15. package/dist/api/git-router.js.map +1 -1
  16. package/dist/api/raw-routes.d.ts +3 -3
  17. package/dist/api/raw-routes.js +63 -61
  18. package/dist/api/raw-routes.js.map +1 -1
  19. package/dist/api/router.d.ts +6 -6
  20. package/dist/api/router.js +22 -22
  21. package/dist/api/router.js.map +1 -1
  22. package/dist/api/session-visibility.d.ts +4 -4
  23. package/dist/api/session-visibility.js +26 -16
  24. package/dist/api/session-visibility.js.map +1 -1
  25. package/dist/api/sessions-router.d.ts +1928 -124
  26. package/dist/api/sessions-router.js +177 -173
  27. package/dist/api/sessions-router.js.map +1 -1
  28. package/dist/api/settings-router.d.ts +427 -9
  29. package/dist/api/settings-router.js +48 -32
  30. package/dist/api/settings-router.js.map +1 -1
  31. package/dist/api/sse-routes.d.ts +2 -2
  32. package/dist/api/sse-routes.js +63 -63
  33. package/dist/api/sse-routes.js.map +1 -1
  34. package/dist/api/tools-raw.d.ts +5 -0
  35. package/dist/api/tools-raw.js +58 -33
  36. package/dist/api/tools-raw.js.map +1 -1
  37. package/dist/api/tools-router.d.ts +663 -91
  38. package/dist/api/tools-router.js +309 -52
  39. package/dist/api/tools-router.js.map +1 -1
  40. package/dist/api/transcribe-stream.d.ts +16 -0
  41. package/dist/api/transcribe-stream.js +172 -0
  42. package/dist/api/transcribe-stream.js.map +1 -0
  43. package/dist/app.d.ts +4 -1
  44. package/dist/app.js +66 -47
  45. package/dist/app.js.map +1 -1
  46. package/dist/auth/gate.js +10 -9
  47. package/dist/auth/gate.js.map +1 -1
  48. package/dist/auth/passkeys.d.ts +15 -14
  49. package/dist/auth/passkeys.js +89 -91
  50. package/dist/auth/passkeys.js.map +1 -1
  51. package/dist/auth/store.d.ts +17 -7
  52. package/dist/auth/store.js +93 -52
  53. package/dist/auth/store.js.map +1 -1
  54. package/dist/bin/talaria-web.js +12 -81
  55. package/dist/bin/talaria-web.js.map +1 -1
  56. package/dist/cli/ctl.js +2 -1
  57. package/dist/cli/ctl.js.map +1 -1
  58. package/dist/cli/dotenv.d.ts +5 -0
  59. package/dist/cli/dotenv.js +14 -2
  60. package/dist/cli/dotenv.js.map +1 -1
  61. package/dist/cli/launcher.js +5 -5
  62. package/dist/cli/launcher.js.map +1 -1
  63. package/dist/cli/main.d.ts +1 -0
  64. package/dist/cli/main.js +85 -0
  65. package/dist/cli/main.js.map +1 -0
  66. package/dist/cli/supervise.d.ts +2 -0
  67. package/dist/cli/supervise.js +67 -4
  68. package/dist/cli/supervise.js.map +1 -1
  69. package/dist/config/agent-config.d.ts +34 -11
  70. package/dist/config/agent-config.js +113 -58
  71. package/dist/config/agent-config.js.map +1 -1
  72. package/dist/config.d.ts +2 -0
  73. package/dist/config.js +14 -5
  74. package/dist/config.js.map +1 -1
  75. package/dist/fs/atomic.d.ts +1 -0
  76. package/dist/fs/atomic.js +4 -1
  77. package/dist/fs/atomic.js.map +1 -1
  78. package/dist/fs/stat.d.ts +1 -0
  79. package/dist/fs/stat.js +11 -0
  80. package/dist/fs/stat.js.map +1 -0
  81. package/dist/http/context.d.ts +14 -9
  82. package/dist/http/context.js +29 -20
  83. package/dist/http/context.js.map +1 -1
  84. package/dist/onboarding.d.ts +2 -2
  85. package/dist/onboarding.js +10 -8
  86. package/dist/onboarding.js.map +1 -1
  87. package/dist/profiles/profiles.d.ts +10 -4
  88. package/dist/profiles/profiles.js +77 -30
  89. package/dist/profiles/profiles.js.map +1 -1
  90. package/dist/projects.d.ts +15 -6
  91. package/dist/projects.js +55 -47
  92. package/dist/projects.js.map +1 -1
  93. package/dist/providers/catalog.d.ts +78 -12
  94. package/dist/providers/catalog.js +445 -141
  95. package/dist/providers/catalog.js.map +1 -1
  96. package/dist/providers/env-file.d.ts +10 -3
  97. package/dist/providers/env-file.js +24 -75
  98. package/dist/providers/env-file.js.map +1 -1
  99. package/dist/providers/runtime-env.d.ts +4 -2
  100. package/dist/providers/runtime-env.js +9 -6
  101. package/dist/providers/runtime-env.js.map +1 -1
  102. package/dist/providers/tables.d.ts +3 -1
  103. package/dist/providers/tables.js +4 -2
  104. package/dist/providers/tables.js.map +1 -1
  105. package/dist/redact.js +18 -9
  106. package/dist/redact.js.map +1 -1
  107. package/dist/release.d.ts +7 -0
  108. package/dist/release.js +14 -0
  109. package/dist/release.js.map +1 -1
  110. package/dist/runtime.d.ts +5 -1
  111. package/dist/runtime.js +233 -90
  112. package/dist/runtime.js.map +1 -1
  113. package/dist/server.js +10 -0
  114. package/dist/server.js.map +1 -1
  115. package/dist/sessions/anchor.d.ts +9 -3
  116. package/dist/sessions/anchor.js +28 -36
  117. package/dist/sessions/anchor.js.map +1 -1
  118. package/dist/sessions/background-events.d.ts +2 -0
  119. package/dist/sessions/background-events.js +10 -0
  120. package/dist/sessions/background-events.js.map +1 -0
  121. package/dist/sessions/background-tasks.d.ts +26 -20
  122. package/dist/sessions/background-tasks.js +88 -86
  123. package/dist/sessions/background-tasks.js.map +1 -1
  124. package/dist/sessions/background-updates.d.ts +15 -8
  125. package/dist/sessions/background-updates.js +101 -25
  126. package/dist/sessions/background-updates.js.map +1 -1
  127. package/dist/sessions/cli-sessions.d.ts +15 -5
  128. package/dist/sessions/cli-sessions.js +62 -43
  129. package/dist/sessions/cli-sessions.js.map +1 -1
  130. package/dist/sessions/completions.d.ts +30 -2
  131. package/dist/sessions/completions.js +294 -53
  132. package/dist/sessions/completions.js.map +1 -1
  133. package/dist/sessions/compress.d.ts +8 -0
  134. package/dist/sessions/compress.js +2 -2
  135. package/dist/sessions/compress.js.map +1 -1
  136. package/dist/sessions/drafts.d.ts +14 -10
  137. package/dist/sessions/drafts.js +38 -43
  138. package/dist/sessions/drafts.js.map +1 -1
  139. package/dist/sessions/gateway-sessions.d.ts +46 -0
  140. package/dist/sessions/gateway-sessions.js +378 -0
  141. package/dist/sessions/gateway-sessions.js.map +1 -0
  142. package/dist/sessions/goals.d.ts +31 -0
  143. package/dist/sessions/goals.js +75 -0
  144. package/dist/sessions/goals.js.map +1 -0
  145. package/dist/sessions/journal.d.ts +5 -79
  146. package/dist/sessions/journal.js +15 -606
  147. package/dist/sessions/journal.js.map +1 -1
  148. package/dist/sessions/list.d.ts +27 -18
  149. package/dist/sessions/list.js +133 -131
  150. package/dist/sessions/list.js.map +1 -1
  151. package/dist/sessions/merge.d.ts +68 -10
  152. package/dist/sessions/merge.js +259 -51
  153. package/dist/sessions/merge.js.map +1 -1
  154. package/dist/sessions/notices.d.ts +22 -0
  155. package/dist/sessions/notices.js +72 -0
  156. package/dist/sessions/notices.js.map +1 -0
  157. package/dist/sessions/pending.d.ts +10 -4
  158. package/dist/sessions/pending.js +83 -7
  159. package/dist/sessions/pending.js.map +1 -1
  160. package/dist/sessions/prefix-index.d.ts +82 -0
  161. package/dist/sessions/prefix-index.js +232 -0
  162. package/dist/sessions/prefix-index.js.map +1 -0
  163. package/dist/sessions/recovery.d.ts +4 -7
  164. package/dist/sessions/recovery.js +97 -281
  165. package/dist/sessions/recovery.js.map +1 -1
  166. package/dist/sessions/relay.d.ts +20 -20
  167. package/dist/sessions/relay.js +205 -127
  168. package/dist/sessions/relay.js.map +1 -1
  169. package/dist/sessions/service.d.ts +162 -59
  170. package/dist/sessions/service.js +1133 -521
  171. package/dist/sessions/service.js.map +1 -1
  172. package/dist/sessions/session.d.ts +18 -2
  173. package/dist/sessions/session.js +29 -5
  174. package/dist/sessions/session.js.map +1 -1
  175. package/dist/sessions/shares.d.ts +7 -6
  176. package/dist/sessions/shares.js +22 -45
  177. package/dist/sessions/shares.js.map +1 -1
  178. package/dist/sessions/source-kind.js +1 -0
  179. package/dist/sessions/source-kind.js.map +1 -1
  180. package/dist/sessions/state-db-identity.d.ts +18 -0
  181. package/dist/sessions/state-db-identity.js +67 -0
  182. package/dist/sessions/state-db-identity.js.map +1 -0
  183. package/dist/sessions/state-db-worker.js +3 -1
  184. package/dist/sessions/state-db-worker.js.map +1 -1
  185. package/dist/sessions/state-db.d.ts +53 -8
  186. package/dist/sessions/state-db.js +576 -50
  187. package/dist/sessions/state-db.js.map +1 -1
  188. package/dist/sessions/storage/backend.d.ts +162 -0
  189. package/dist/sessions/storage/backend.js +19 -0
  190. package/dist/sessions/storage/backend.js.map +1 -0
  191. package/dist/sessions/storage/conformance.d.ts +20 -0
  192. package/dist/sessions/storage/conformance.js +237 -0
  193. package/dist/sessions/storage/conformance.js.map +1 -0
  194. package/dist/sessions/storage/document.d.ts +16 -0
  195. package/dist/sessions/storage/document.js +44 -0
  196. package/dist/sessions/storage/document.js.map +1 -0
  197. package/dist/sessions/storage/json-documents.d.ts +23 -0
  198. package/dist/sessions/storage/json-documents.js +233 -0
  199. package/dist/sessions/storage/json-documents.js.map +1 -0
  200. package/dist/sessions/storage/json-files.d.ts +12 -0
  201. package/dist/sessions/storage/json-files.js +124 -0
  202. package/dist/sessions/storage/json-files.js.map +1 -0
  203. package/dist/sessions/storage/json-installation.d.ts +3 -0
  204. package/dist/sessions/storage/json-installation.js +31 -0
  205. package/dist/sessions/storage/json-installation.js.map +1 -0
  206. package/dist/sessions/storage/json-journal.d.ts +114 -0
  207. package/dist/sessions/storage/json-journal.js +686 -0
  208. package/dist/sessions/storage/json-journal.js.map +1 -0
  209. package/dist/sessions/storage/json-recovery.d.ts +4 -0
  210. package/dist/sessions/storage/json-recovery.js +195 -0
  211. package/dist/sessions/storage/json-recovery.js.map +1 -0
  212. package/dist/sessions/storage/json.d.ts +68 -0
  213. package/dist/sessions/storage/json.js +258 -0
  214. package/dist/sessions/storage/json.js.map +1 -0
  215. package/dist/sessions/storage/row.d.ts +6 -0
  216. package/dist/sessions/storage/row.js +49 -0
  217. package/dist/sessions/storage/row.js.map +1 -0
  218. package/dist/sessions/storage/search-text.d.ts +4 -0
  219. package/dist/sessions/storage/search-text.js +16 -0
  220. package/dist/sessions/storage/search-text.js.map +1 -0
  221. package/dist/sessions/store.d.ts +63 -73
  222. package/dist/sessions/store.js +305 -611
  223. package/dist/sessions/store.js.map +1 -1
  224. package/dist/sessions/streams.d.ts +4 -0
  225. package/dist/sessions/streams.js +9 -1
  226. package/dist/sessions/streams.js.map +1 -1
  227. package/dist/sessions/titles.js +1 -1
  228. package/dist/sessions/titles.js.map +1 -1
  229. package/dist/sessions/todo.d.ts +5 -0
  230. package/dist/sessions/todo.js +28 -21
  231. package/dist/sessions/todo.js.map +1 -1
  232. package/dist/sessions/tool-display.d.ts +5 -4
  233. package/dist/sessions/tool-display.js +22 -16
  234. package/dist/sessions/tool-display.js.map +1 -1
  235. package/dist/sessions/turn-context.d.ts +10 -1
  236. package/dist/sessions/turn-context.js +7 -4
  237. package/dist/sessions/turn-context.js.map +1 -1
  238. package/dist/sessions/turn.d.ts +87 -17
  239. package/dist/sessions/turn.js +795 -347
  240. package/dist/sessions/turn.js.map +1 -1
  241. package/dist/sessions/wakeup-pause.d.ts +8 -13
  242. package/dist/sessions/wakeup-pause.js +31 -49
  243. package/dist/sessions/wakeup-pause.js.map +1 -1
  244. package/dist/sessions/window.js +13 -12
  245. package/dist/sessions/window.js.map +1 -1
  246. package/dist/settings.d.ts +19 -7
  247. package/dist/settings.js +179 -183
  248. package/dist/settings.js.map +1 -1
  249. package/dist/sidecar/client.d.ts +17 -3
  250. package/dist/sidecar/client.js +78 -8
  251. package/dist/sidecar/client.js.map +1 -1
  252. package/dist/sidecar/discover.d.ts +2 -1
  253. package/dist/sidecar/discover.js +93 -10
  254. package/dist/sidecar/discover.js.map +1 -1
  255. package/dist/sidecar/env.d.ts +4 -0
  256. package/dist/sidecar/env.js +3 -0
  257. package/dist/sidecar/env.js.map +1 -0
  258. package/dist/sidecar/fake.js +19 -2
  259. package/dist/sidecar/fake.js.map +1 -1
  260. package/dist/test/env-file.d.ts +5 -0
  261. package/dist/test/env-file.js +88 -0
  262. package/dist/test/env-file.js.map +1 -0
  263. package/dist/test/harness.d.ts +1 -0
  264. package/dist/test/harness.js +1 -1
  265. package/dist/test/harness.js.map +1 -1
  266. package/dist/test/passkeys.d.ts +22 -0
  267. package/dist/test/passkeys.js +62 -0
  268. package/dist/test/passkeys.js.map +1 -0
  269. package/dist/test/storage.d.ts +15 -0
  270. package/dist/test/storage.js +26 -0
  271. package/dist/test/storage.js.map +1 -0
  272. package/dist/tools/commands.d.ts +6 -1
  273. package/dist/tools/commands.js +8 -2
  274. package/dist/tools/commands.js.map +1 -1
  275. package/dist/tools/connectors.d.ts +33 -0
  276. package/dist/tools/connectors.js +121 -0
  277. package/dist/tools/connectors.js.map +1 -0
  278. package/dist/tools/crons.d.ts +38 -1
  279. package/dist/tools/crons.js +82 -15
  280. package/dist/tools/crons.js.map +1 -1
  281. package/dist/tools/dashboard-plugins.d.ts +5 -5
  282. package/dist/tools/dashboard-plugins.js +14 -14
  283. package/dist/tools/dashboard-plugins.js.map +1 -1
  284. package/dist/tools/extensions.d.ts +5 -4
  285. package/dist/tools/extensions.js +213 -207
  286. package/dist/tools/extensions.js.map +1 -1
  287. package/dist/tools/gateway-restart.d.ts +62 -0
  288. package/dist/tools/gateway-restart.js +142 -0
  289. package/dist/tools/gateway-restart.js.map +1 -0
  290. package/dist/tools/health.d.ts +15 -3
  291. package/dist/tools/health.js +97 -34
  292. package/dist/tools/health.js.map +1 -1
  293. package/dist/tools/hygiene.d.ts +4 -3
  294. package/dist/tools/hygiene.js +23 -9
  295. package/dist/tools/hygiene.js.map +1 -1
  296. package/dist/tools/kanban.d.ts +4 -2
  297. package/dist/tools/kanban.js +28 -19
  298. package/dist/tools/kanban.js.map +1 -1
  299. package/dist/tools/memory-masks.d.ts +5 -0
  300. package/dist/tools/memory-masks.js +256 -0
  301. package/dist/tools/memory-masks.js.map +1 -0
  302. package/dist/tools/memory.d.ts +29 -3
  303. package/dist/tools/memory.js +69 -27
  304. package/dist/tools/memory.js.map +1 -1
  305. package/dist/tools/plugin-settings.d.ts +15 -0
  306. package/dist/tools/plugin-settings.js +90 -0
  307. package/dist/tools/plugin-settings.js.map +1 -0
  308. package/dist/tools/skills.d.ts +9 -4
  309. package/dist/tools/skills.js +44 -13
  310. package/dist/tools/skills.js.map +1 -1
  311. package/dist/tools/update-notifications.d.ts +34 -15
  312. package/dist/tools/update-notifications.js +141 -57
  313. package/dist/tools/update-notifications.js.map +1 -1
  314. package/dist/tools/update-rollback.d.ts +11 -0
  315. package/dist/tools/update-rollback.js +28 -0
  316. package/dist/tools/update-rollback.js.map +1 -0
  317. package/dist/tools/updates.d.ts +93 -33
  318. package/dist/tools/updates.js +1051 -345
  319. package/dist/tools/updates.js.map +1 -1
  320. package/dist/util.d.ts +2 -0
  321. package/dist/util.js +5 -0
  322. package/dist/util.js.map +1 -1
  323. package/dist/workspace/git.d.ts +16 -1
  324. package/dist/workspace/git.js +291 -11
  325. package/dist/workspace/git.js.map +1 -1
  326. package/dist/workspace/media.d.ts +12 -9
  327. package/dist/workspace/media.js +31 -20
  328. package/dist/workspace/media.js.map +1 -1
  329. package/dist/workspace/rollback.d.ts +2 -2
  330. package/dist/workspace/rollback.js +5 -5
  331. package/dist/workspace/rollback.js.map +1 -1
  332. package/dist/workspace/workspaces.d.ts +15 -19
  333. package/dist/workspace/workspaces.js +55 -127
  334. package/dist/workspace/workspaces.js.map +1 -1
  335. package/dist/workspace/worktrees.js +170 -32
  336. package/dist/workspace/worktrees.js.map +1 -1
  337. package/package.json +5 -3
  338. package/sidecar/agent_dependency.json +4 -4
  339. package/sidecar/agent_support.json +26 -0
  340. package/sidecar/scripts/record-fixtures.py +12 -3
  341. package/sidecar/scripts/replay_sidecar.py +8 -0
  342. package/sidecar/scripts/suite_runner.py +302 -0
  343. package/sidecar/scripts/test.sh +12 -4
  344. package/sidecar/talaria_sidecar/__init__.py +6 -1
  345. package/sidecar/talaria_sidecar/__main__.py +4 -2
  346. package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
  347. package/sidecar/talaria_sidecar/agent_services.py +1053 -0
  348. package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
  349. package/sidecar/talaria_sidecar/home.py +43 -1
  350. package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
  351. package/sidecar/talaria_sidecar/methods/aux.py +139 -31
  352. package/sidecar/talaria_sidecar/methods/chat.py +847 -134
  353. package/sidecar/talaria_sidecar/methods/commands.py +213 -4
  354. package/sidecar/talaria_sidecar/methods/config.py +123 -4
  355. package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
  356. package/sidecar/talaria_sidecar/methods/cron.py +366 -34
  357. package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
  358. package/sidecar/talaria_sidecar/methods/gateway.py +194 -54
  359. package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
  360. package/sidecar/talaria_sidecar/methods/goals.py +81 -41
  361. package/sidecar/talaria_sidecar/methods/kanban.py +80 -27
  362. package/sidecar/talaria_sidecar/methods/memory.py +84 -0
  363. package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
  364. package/sidecar/talaria_sidecar/methods/process.py +160 -11
  365. package/sidecar/talaria_sidecar/methods/profiles.py +44 -6
  366. package/sidecar/talaria_sidecar/methods/providers.py +196 -26
  367. package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
  368. package/sidecar/talaria_sidecar/methods/skills.py +67 -4
  369. package/sidecar/talaria_sidecar/methods/state_db.py +277 -70
  370. package/sidecar/talaria_sidecar/methods/stt.py +159 -78
  371. package/sidecar/talaria_sidecar/methods/text.py +14 -1
  372. package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
  373. package/sidecar/talaria_sidecar/methods/usage.py +113 -14
  374. package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
  375. package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
  376. package/sidecar/talaria_sidecar/rpc.py +45 -4
  377. package/sidecar/talaria_sidecar/runtime.py +81 -12
  378. package/sidecar/talaria_sidecar/speed.py +35 -0
  379. package/static/dist/FILES.txt +126 -127
  380. package/static/dist/assets/AppShell-cey33v9s.js +8 -0
  381. package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
  382. package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
  383. package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
  384. package/static/dist/assets/Field-j8uqoigz.js +9 -0
  385. package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
  386. package/static/dist/assets/Markdown-lahuichm.js +598 -0
  387. package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
  388. package/static/dist/assets/Select-gqatm2e0.js +1 -0
  389. package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
  390. package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
  391. package/static/dist/assets/States-e7dkgtxf.js +1 -0
  392. package/static/dist/assets/Toaster-bfqqy786.js +1 -0
  393. package/static/dist/assets/_app-n1n6pfx1.js +1 -0
  394. package/static/dist/assets/{_app.ext._extensionId-gfbzpoou.js → _app.ext._extensionId-buxjxav3.js} +1 -1
  395. package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
  396. package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
  397. package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
  398. package/static/dist/assets/_app.logs-dm873z90.js +1 -0
  399. package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
  400. package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
  401. package/static/dist/assets/{_app.session._sessionId-fn1bhde6.js → _app.session._sessionId-g2vzghvc.js} +1 -1
  402. package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
  403. package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
  404. package/static/dist/assets/_app.skills-cii852yq.js +1 -0
  405. package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
  406. package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
  407. package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
  408. package/static/dist/assets/{abnfDiagram-VCTEODGH-c8kdixke.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
  409. package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
  410. package/static/dist/assets/{architectureDiagram-5GKGNRK7-cku06x1p.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
  411. package/static/dist/assets/archive-b1j004vn.js +1 -0
  412. package/static/dist/assets/back-g74gkozu.js +1 -0
  413. package/static/dist/assets/{blockDiagram-I7D4REHJ-jzthp1wa.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
  414. package/static/dist/assets/{c4Diagram-7LVT6UL2-mwr67mt8.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
  415. package/static/dist/assets/channel-es95o4y8.js +1 -0
  416. package/static/dist/assets/{chunk-4HAMMTFA-gpq1y228.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
  417. package/static/dist/assets/{chunk-75Z2AOVW-ktje58c4.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
  418. package/static/dist/assets/{chunk-DU6HZSFF-ofajdixh.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
  419. package/static/dist/assets/{chunk-F27PBJKO-cmev85ti.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
  420. package/static/dist/assets/{chunk-GMAD6QVW-htjgt22y.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
  421. package/static/dist/assets/{chunk-GVQU2GXP-qndvoxl7.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
  422. package/static/dist/assets/{chunk-IMKFNOWR-e5bkd5q6.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
  423. package/static/dist/assets/{chunk-L3NEJ4N5-mj1155r6.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
  424. package/static/dist/assets/{chunk-OSK3NFVY-e7gkikcw.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
  425. package/static/dist/assets/{chunk-P2QGCYS3-f7t54xfm.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
  426. package/static/dist/assets/{chunk-POPQ4Y6H-i927v9oa.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
  427. package/static/dist/assets/{chunk-PWAF6VOD-m84lmnyt.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
  428. package/static/dist/assets/{chunk-SHT3W25Y-mi0tlcu9.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
  429. package/static/dist/assets/{chunk-SVP7TREG-dnau702j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
  430. package/static/dist/assets/{chunk-TICWLB2K-edem1gkg.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
  431. package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
  432. package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
  433. package/static/dist/assets/copied-bli9tbcx.js +1 -0
  434. package/static/dist/assets/{copy-magtofyp.js → copy-jamtd1pf.js} +1 -1
  435. package/static/dist/assets/{cynefin-OW5HDTMX-siqlulkl.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
  436. package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-i648tah9.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
  437. package/static/dist/assets/{dagre-GXQ25YYZ-mwn6uc17.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
  438. package/static/dist/assets/{diagram-S7CK7UJ4-l8abxaes.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
  439. package/static/dist/assets/{diagram-UQ7AKVKN-mekq7zgq.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
  440. package/static/dist/assets/{diagram-VSXAHHWV-fnky6lvc.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
  441. package/static/dist/assets/{diagram-VX7I27RA-xe6r5qfw.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
  442. package/static/dist/assets/{diagram-Z3DM3KII-nq07dg7k.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
  443. package/static/dist/assets/{ebnfDiagram-PWID7BFC-c62ipm3g.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
  444. package/static/dist/assets/{erDiagram-RLTQ6QDP-h39kmnzy.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
  445. package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
  446. package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
  447. package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
  448. package/static/dist/assets/{ganttDiagram-EL5Y4UJY-ngbsyp37.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
  449. package/static/dist/assets/{gitGraph-4MIJSDKK-fr2i7caa.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
  450. package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-eravdti4.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
  451. package/static/dist/assets/{highlighted-body-KPVGNVTW-jwpop9p8.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
  452. package/static/dist/assets/host-hzm8n85n.js +1 -0
  453. package/static/dist/assets/index-drdcaqeq.css +2 -0
  454. package/static/dist/assets/index-jzm844he.js +11 -0
  455. package/static/dist/assets/{info-A6RAGUB7-h11x0dxo.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
  456. package/static/dist/assets/{infoDiagram-27XIBGKW-dfh47dw9.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
  457. package/static/dist/assets/{ishikawaDiagram-5VMMS53U-i6ypq351.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
  458. package/static/dist/assets/{journeyDiagram-3NMN7TZE-lduf1z95.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
  459. package/static/dist/assets/{kanban-definition-UXKFOSKX-e18bu4pg.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
  460. package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
  461. package/static/dist/assets/{line-meizqsvn.js → line-h0ojzsvs.js} +1 -1
  462. package/static/dist/assets/link-k01ryaf9.js +1 -0
  463. package/static/dist/assets/login-bsae49ew.js +1 -0
  464. package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
  465. package/static/dist/assets/{mermaid-parser.core-ntne45i9.js → mermaid-parser.core-bnre27u8.js} +3 -3
  466. package/static/dist/assets/{mindmap-definition-YA3MSWOX-27b26eok.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
  467. package/static/dist/assets/onboarding-c65tysya.js +1 -0
  468. package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
  469. package/static/dist/assets/{packet-AYTQ26CC-l6jdka8p.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
  470. package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
  471. package/static/dist/assets/{pegDiagram-XKGWAZYB-g1er3bxj.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
  472. package/static/dist/assets/{pie-WAS4IAKB-i0ylcrt9.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
  473. package/static/dist/assets/{pieDiagram-E7YTZNPT-fbz1e55z.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
  474. package/static/dist/assets/{quadrantDiagram-AXDQQJYC-hhue7d8o.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
  475. package/static/dist/assets/{radar-RG4KPBEZ-f9b70aa4.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
  476. package/static/dist/assets/{railroad-74A4TZTK-lgsuoeda.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
  477. package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
  478. package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
  479. package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
  480. package/static/dist/assets/{railroadDiagram-O6MQD6OU-eqpy9fnz.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
  481. package/static/dist/assets/{refresh-cw-hlwb02qv.js → refresh-cw-mqbkv2a3.js} +1 -1
  482. package/static/dist/assets/refresh-l29ljp76.js +1 -0
  483. package/static/dist/assets/{requirementDiagram-BXWQKSXE-ogf6puhi.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
  484. package/static/dist/assets/{sankeyDiagram-P5KCCOFB-fqb8xcjf.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
  485. package/static/dist/assets/saved-ndd4t2xb.js +1 -0
  486. package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-dlcz6qjz.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
  487. package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
  488. package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
  489. package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
  490. package/static/dist/assets/{stateDiagram-D77RDMKH-fyoznpcs.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
  491. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
  492. package/static/dist/assets/{swimlanes-42K2YHIH-oefldhfy.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
  493. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
  494. package/static/dist/assets/{timeline-definition-24CTP7MA-b1vl2zil.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
  495. package/static/dist/assets/toast-i3h34v6o.js +64 -0
  496. package/static/dist/assets/{treeView-Q6P3EWNA-f7hcci5o.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
  497. package/static/dist/assets/{treemap-WGGIJYW6-nl85071a.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
  498. package/static/dist/assets/untitled-oaoya4qj.js +1 -0
  499. package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
  500. package/static/dist/assets/{useParams-b4dq6n4q.js → useParams-gjc70qru.js} +1 -1
  501. package/static/dist/assets/{useSearch-ipfmv3he.js → useSearch-e6ae539u.js} +1 -1
  502. package/static/dist/assets/{vennDiagram-4TSXK5OY-h5hzbk0n.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
  503. package/static/dist/assets/{wardley-WFR3VGLG-jftvpm3e.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
  504. package/static/dist/assets/{wardleyDiagram-VM6X3IG4-hedh85ge.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
  505. package/static/dist/assets/{xychartDiagram-S5SC5T6Z-e49523ab.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
  506. package/static/dist/index.html +1 -1
  507. package/static/dist/sw.js +1 -1
  508. package/static/dist/assets/AppShell-g3bkgnvt.js +0 -1
  509. package/static/dist/assets/ChatPage-oo7bdan6.js +0 -25
  510. package/static/dist/assets/Dialog-g355qxhp.js +0 -1
  511. package/static/dist/assets/ExtensionRoute-i2y9fvjm.js +0 -1
  512. package/static/dist/assets/HubRoute-lmkrbw47.js +0 -2
  513. package/static/dist/assets/Markdown-j4kut4j2.js +0 -598
  514. package/static/dist/assets/RightPanel-ohlsdzfl.js +0 -1
  515. package/static/dist/assets/Select-kddq75qc.js +0 -1
  516. package/static/dist/assets/SessionListPanel-lu3oy0hw.js +0 -1
  517. package/static/dist/assets/SettingsLayout-o9bv4mgb.js +0 -1
  518. package/static/dist/assets/States-eq6fe29m.js +0 -1
  519. package/static/dist/assets/Toaster-pc247u9f.js +0 -1
  520. package/static/dist/assets/_app-f8n1i0m1.js +0 -1
  521. package/static/dist/assets/_app.index-bzzv80hk.js +0 -1
  522. package/static/dist/assets/_app.insights-dzixbryi.js +0 -1
  523. package/static/dist/assets/_app.kanban-c6hep2us.js +0 -1
  524. package/static/dist/assets/_app.logs-i69qds98.js +0 -1
  525. package/static/dist/assets/_app.memory-kl4vf0gd.js +0 -1
  526. package/static/dist/assets/_app.profiles-b8zinmyp.js +0 -1
  527. package/static/dist/assets/_app.settings-cg8plwmf.js +0 -1
  528. package/static/dist/assets/_app.settings._section-bkwbi9zn.js +0 -3
  529. package/static/dist/assets/_app.skills-cs47sbvs.js +0 -1
  530. package/static/dist/assets/_app.tasks-dwvk64tc.js +0 -1
  531. package/static/dist/assets/_app.todos-c8xjm8p3.js +0 -1
  532. package/static/dist/assets/_app.workspaces-ehvd1gds.js +0 -1
  533. package/static/dist/assets/architecture-7GRP2DOG-6crvnylg.js +0 -1
  534. package/static/dist/assets/back-h7aun7ew.js +0 -1
  535. package/static/dist/assets/cancel-fhi0vcnu.js +0 -1
  536. package/static/dist/assets/channel-b2zo73z1.js +0 -1
  537. package/static/dist/assets/classDiagram-ZZMXUADV-oe99st8x.js +0 -1
  538. package/static/dist/assets/classDiagram-v2-VYDZK3BY-oe99st8x.js +0 -1
  539. package/static/dist/assets/copied-hcplv46p.js +0 -1
  540. package/static/dist/assets/endpoints-klbxod4t.js +0 -64
  541. package/static/dist/assets/eventmodeling-NTZA5JFV-obfede4u.js +0 -1
  542. package/static/dist/assets/flowDiagram-HODETNUW-kdpsp1je.js +0 -1
  543. package/static/dist/assets/host-i828xuo7.js +0 -1
  544. package/static/dist/assets/index-eh8zilnv.css +0 -2
  545. package/static/dist/assets/index-r648f4o1.js +0 -11
  546. package/static/dist/assets/lazyRouteComponent-e1y4t2i9.js +0 -1
  547. package/static/dist/assets/link-oot2yn73.js +0 -1
  548. package/static/dist/assets/login-gu28l9ou.js +0 -1
  549. package/static/dist/assets/mermaid-HWGCJPDP-mtwrj8fn.js +0 -1
  550. package/static/dist/assets/onboarding-lkphzu1s.js +0 -1
  551. package/static/dist/assets/onboarding_model_label-ftpjdwqk.js +0 -1
  552. package/static/dist/assets/railroad-abnf-HS5TGJTU-nf9d6pdx.js +0 -1
  553. package/static/dist/assets/railroad-ebnf-LZEXJU2U-f7ummkt5.js +0 -1
  554. package/static/dist/assets/railroad-peg-WCYAUIDC-oczq5tqs.js +0 -1
  555. package/static/dist/assets/refresh-abtu93ke.js +0 -1
  556. package/static/dist/assets/saved-girnabkf.js +0 -1
  557. package/static/dist/assets/settings_section_extensions_title-h14cwk6f.js +0 -1
  558. package/static/dist/assets/share._token-kl0r7ido.js +0 -2
  559. package/static/dist/assets/sliders-horizontal-n1zm34qq.js +0 -1
  560. package/static/dist/assets/sse-iwku0sjo.js +0 -1
  561. package/static/dist/assets/stateDiagram-v2-MP3YSRHH-ixhx8r46.js +0 -1
  562. package/static/dist/assets/swimlanesDiagram-VR7AAH4N-h9ersk2e.js +0 -8
  563. package/static/dist/assets/todoStore-jjr5yr78.js +0 -1
  564. package/static/dist/assets/units-kgxzxfhi.js +0 -1
  565. package/static/dist/assets/untitled-cikfjntn.js +0 -1
  566. package/static/dist/assets/useForm-kqoqg0k9.js +0 -1
  567. package/static/dist/assets/useLocale-o59tbiea.js +0 -1
@@ -1,4 +1,3 @@
1
- /** Skills, memory, prompts, commands, notes, insights, logs, health, MCP, plugins, updates, diagnostics (Python `api/routes.py` handlers of the same paths). */
2
1
  import { implement } from '@orpc/server';
3
2
  import { createHash } from 'node:crypto';
4
3
  import { join } from 'node:path';
@@ -6,24 +5,32 @@ import { toolsContract } from '@maudecode/talaria-web-contracts';
6
5
  import { HttpError, requireFields } from './router.js';
7
6
  import { requestSessionIdGuard } from './session-visibility.js';
8
7
  import { activeProfileName, ensureTrustedAuthSession, sessionCanManageServer } from '../auth/gate.js';
9
- import { HttpFailure } from '../sessions/service.js';
8
+ import { currentChatReadiness, HttpFailure } from '../sessions/service.js';
10
9
  import { SessionNotFound } from '../sessions/store.js';
11
10
  import { insightsSessionRows } from '../sessions/state-db.js';
12
11
  import { ConfigUnavailable } from '../config/agent-config.js';
13
12
  import { SidecarError } from '../sidecar/client.js';
14
13
  import { createPrompt, deletePrompt, externalNotesEnabled, loadPrompts, readMemory, writeMemory } from '../tools/memory.js';
15
14
  import { JoplinError, joplinNote, joplinSearch, notesSources } from '../tools/mcp.js';
15
+ import { catalogNames, connectorOperation, connectorsPage, connectorTools, rememberCatalogNames } from '../tools/connectors.js';
16
16
  import { resolveWikiLocation, wikiPages } from '../tools/wiki.js';
17
17
  import { buildInsights } from '../tools/insights.js';
18
- import { commandCatalog } from '../tools/commands.js';
19
- import { agentHealth, applyDashboardConfig, dashboardConfig, dashboardStatus, gatewayStatus, parseDashboardConfig, readLogTail, systemHealth } from '../tools/health.js';
18
+ import { commandCatalog, SESSION_EXEC_COMMANDS } from '../tools/commands.js';
19
+ import { spokenText } from './tools-raw.js';
20
+ import { agentHealth, applyDashboardConfig, dashboardConfig, dashboardStatus, gatewayStatus, parseDashboardConfig, readLogTail, remoteGatewayBaseUrl, systemHealth } from '../tools/health.js';
21
+ import { restartGateway } from '../tools/gateway-restart.js';
20
22
  import { projectOsDashboard } from '../tools/project-os.js';
23
+ import { PluginSettingsInvalid, planPluginSettings, pluginSettingsView, serializePluginSettingsSave } from '../tools/plugin-settings.js';
24
+ import { credentialShadowed, RuntimeCredentialError, writeRuntimeCredential } from '../providers/runtime-env.js';
25
+ import { EnvWriteError, loadEnvFile } from '../providers/env-file.js';
21
26
  import { loadGatewaySessionIdentityMap } from '../sessions/list.js';
22
27
  import { gitBadge } from '../workspace/git.js';
23
28
  import { sanitizeError } from '../workspace/media.js';
24
29
  import { normalizeChannel, updatesCheckView } from '../tools/updates.js';
25
30
  import { pyBool } from '../settings.js';
26
31
  import { str } from '../util.js';
32
+ import { redactString } from '../redact.js';
33
+ import { GATEWAY_RESTART_NOW } from '../tools/update-notifications.js';
27
34
  const os = implement(toolsContract).$context().use(requestSessionIdGuard);
28
35
  function failure(error) {
29
36
  if (error instanceof HttpError)
@@ -48,6 +55,8 @@ async function run(fn) {
48
55
  }
49
56
  }
50
57
  const home = (ctx) => ctx.deps.profileHome(activeProfileName(ctx));
58
+ /** Profile homes with an `stt.warm` in flight (TAL-916). */
59
+ const warmingHomes = new Set();
51
60
  function runningSidecar(ctx) {
52
61
  const sidecar = ctx.deps.sidecar();
53
62
  if (!sidecar)
@@ -62,14 +71,89 @@ function commandFailure(error, notFound, message) {
62
71
  throw new HttpError(400, error.message);
63
72
  return failure(error);
64
73
  }
74
+ /** TAL-820: several profiles have third-party plugins and one of them loads its plugins into the shared sidecar process. */
75
+ async function pluginIsolationAdvisory(ctx) {
76
+ if (ctx.deps.isolatedProfileMode())
77
+ return false;
78
+ const { profiles } = await runningSidecar(ctx).call('plugins.isolation', { base_home: ctx.deps.profileHome('default') });
79
+ const withPlugins = profiles.filter((profile) => profile.third_party_plugins > 0);
80
+ return withPlugins.length > 1 && withPlugins.some((profile) => profile.isolation === 'in_process');
81
+ }
82
+ /** TAL-806: the active profile's plugins that declare settings; none on an Agent without the settings module. */
83
+ async function pluginSettingsList(ctx) {
84
+ const result = await runningSidecar(ctx).call('plugins.settings', { profile_home: home(ctx) });
85
+ return result.plugins.map((entry) => ({ key: entry.key, fields: pluginSettingsFieldsView(ctx, entry.fields) }));
86
+ }
87
+ const pluginSettingsFieldsView = (ctx, fields) => {
88
+ const rootProfile = ctx.deps.isRootProfile(activeProfileName(ctx));
89
+ return pluginSettingsView(fields, (envVar) => credentialShadowed(ctx.deps.config.env, rootProfile, envVar));
90
+ };
91
+ /** A refusal that proves nothing was written; a timeout or a sidecar exit leaves the outcome unknown. */
92
+ const definitiveRefusal = (error) => error instanceof SidecarError ? ['plugin_settings_managed', 'plugin_settings_changed', 'plugin_not_found'].includes(error.condition) || error.code === -32602
93
+ : error instanceof EnvWriteError ? error.condition !== 'sidecar_unavailable'
94
+ : error instanceof RuntimeCredentialError;
95
+ /** TAL-818: a sidecar `connectors.*` condition as the HTTP status the contract names; the body's `code` is the condition. */
96
+ const CONNECTOR_STATUS = {
97
+ connectors_unavailable: 404, connector_not_found: 404, connection_not_found: 404, operation_not_found: 404,
98
+ connectors_sign_in: 403, connectors_forbidden: 403, policy_invalid: 400, connectors_failed: 502,
99
+ policy_conflict: 409, connectors_org_required: 409, operation_settled: 409, operation_refused: 409,
100
+ };
101
+ async function connectorCall(ctx, method, params) {
102
+ try {
103
+ // A connect waits up to 31 s for its link; every portal request inside a call is bounded at 30 s.
104
+ return await runningSidecar(ctx).call(method, { ...params, profile_home: home(ctx) }, { timeoutMs: 90_000 });
105
+ }
106
+ catch (error) {
107
+ const status = error instanceof SidecarError ? CONNECTOR_STATUS[error.condition] : undefined;
108
+ if (status !== undefined)
109
+ throw new HttpError(status, error.message, { code: error.condition });
110
+ if (error instanceof SidecarError && error.code === -32602)
111
+ throw new HttpError(400, error.message);
112
+ throw error;
113
+ }
114
+ }
115
+ /** The catalog's app names for the active profile: the last page read's, else one catalog read; none when it fails. */
116
+ async function connectorNames(ctx) {
117
+ return catalogNames(home(ctx)) ?? await connectorCall(ctx, 'connectors.catalog', {}).then((r) => rememberCatalogNames(home(ctx), r.connectors), () => ({}));
118
+ }
119
+ /** An operation as the contract shows it, with the apps' catalog names. */
120
+ const operationView = async (ctx, snapshot) => connectorOperation(snapshot, await connectorNames(ctx));
121
+ /** The rules, or why they cannot be read (a portal refusal or failure): the page then fails closed and says why. */
122
+ const connectorPolicy = (ctx) => connectorCall(ctx, 'connectors.policy.get', {}).then((policy) => ({ policy, error: null }), (error) => { if (error instanceof HttpError)
123
+ return { policy: null, error: error.message }; throw error; });
65
124
  const health = (ctx) => agentHealth({ env: ctx.deps.config.env, hermesHome: ctx.deps.config.hermesHome, profileHome: () => home(ctx), fetch: () => ctx.deps.fetch, now: ctx.deps.nowSeconds });
125
+ /**
126
+ * TAL-805: the active profile's gateway mode from sidecar `gateway.mode`; null for a remote gateway. A named profile never
127
+ * borrows the root's health: when the sidecar cannot answer, it reads `stopped`, while the root profile reads null and keeps
128
+ * its health. The root profile's gateway in another container (`health` alive from its fresh runtime status) is invisible
129
+ * to the sidecar's process checks, so it stays `own`.
130
+ */
131
+ async function gatewayMode(ctx, health) {
132
+ if (remoteGatewayBaseUrl(ctx.deps.config.env) !== null)
133
+ return null;
134
+ const sidecar = ctx.deps.sidecar();
135
+ const name = activeProfileName(ctx);
136
+ const isDefault = ctx.deps.isRootProfile(name);
137
+ let mode = null;
138
+ try {
139
+ if (sidecar)
140
+ mode = (await sidecar.call('gateway.mode', { profile_home: home(ctx), name, is_default: isDefault }, { timeoutMs: 10_000 })).gateway_mode;
141
+ }
142
+ catch {
143
+ mode = null;
144
+ }
145
+ if (mode === null)
146
+ return isDefault ? null : 'stopped';
147
+ return mode === 'stopped' && isDefault && health.alive === true ? 'own' : mode;
148
+ }
66
149
  /** Python `_gateway_status_payload` for the active profile. */
67
150
  async function currentGatewayStatus(ctx) {
68
151
  const sessionsPath = join(home(ctx), 'sessions', 'sessions.json');
69
- return gatewayStatus(await health(ctx), loadGatewaySessionIdentityMap(sessionsPath), sessionsPath);
152
+ const probe = await health(ctx);
153
+ return gatewayStatus(probe, loadGatewaySessionIdentityMap(sessionsPath), sessionsPath, await gatewayMode(ctx, probe));
70
154
  }
71
155
  const GATEWAY_ACTION_TIMEOUT_S = 60;
72
- /** Python `_handle_gateway_lifecycle` through sidecar `gateway.control`: 409 busy, 504 timeout, 500 failure; CLI output never leaves the server. */
156
+ /** Python `_handle_gateway_lifecycle` through sidecar `gateway.control`: 409 busy, 504 timeout, 500 failure; only the Agent's first error line (`reason`) leaves the server, never its CLI output (TAL-884). */
73
157
  async function gatewayAction(ctx, action) {
74
158
  const sidecar = ctx.deps.sidecar();
75
159
  if (!sidecar)
@@ -85,8 +169,10 @@ async function gatewayAction(ctx, action) {
85
169
  throw new HttpError(409, 'Another gateway action is already in progress; try again shortly.', { ok: false, action });
86
170
  if (outcome.timed_out)
87
171
  throw new HttpError(504, `Gateway ${action} timed out after ${String(GATEWAY_ACTION_TIMEOUT_S)} seconds`, { ok: false, action });
88
- if (outcome.status === 'failed' && outcome.returncode !== undefined)
89
- throw new HttpError(500, `Gateway ${action} failed with exit code ${String(outcome.returncode)}`, { ok: false, action, returncode: outcome.returncode });
172
+ if (outcome.status === 'failed' && outcome.returncode !== undefined) {
173
+ const error = outcome.reason ? `Gateway ${action} failed: ${outcome.reason}` : `Gateway ${action} failed with exit code ${String(outcome.returncode)}`;
174
+ throw new HttpError(500, error, { ok: false, action, returncode: outcome.returncode });
175
+ }
90
176
  if (outcome.status === 'failed')
91
177
  throw new HttpError(500, outcome.message, { ok: false, action });
92
178
  return { ok: true, action, message: `Gateway ${action} completed.`, status: await currentGatewayStatus(ctx) };
@@ -115,39 +201,54 @@ async function updateNotificationScope(ctx, tab) {
115
201
  tab: tab ?? null,
116
202
  };
117
203
  }
118
- async function applyWithNotification(ctx, target, apply, confirmed = false, tab) {
119
- const scope = await updateNotificationScope(ctx, tab);
204
+ async function applyWithNotification(ctx, input, action) {
205
+ const target = updateTarget(input.target);
206
+ const confirmed = input.confirmed_agent_revision !== undefined || input.agent_refresh_token !== undefined;
207
+ const scope = await updateNotificationScope(ctx, input.tab_id);
120
208
  const active = ctx.deps.updateNotifications.activeUpdate(scope, target);
121
209
  if (active)
122
- ctx.deps.updateNotifications.watch(scope, active.id);
210
+ (await ctx.deps.updateNotifications.watch(scope, active.id));
123
211
  if (active && (active.phase === 'applying' || active.phase === 'restarting')) {
124
212
  return { ok: false, status: 'already_in_progress', message: 'Update already in progress', notification_id: active.id };
125
213
  }
126
- const notification = active ?? ctx.deps.updateNotifications.begin(scope, target);
214
+ const notification = active ?? (await ctx.deps.updateNotifications.begin(scope, target));
127
215
  if (active?.phase === 'awaiting_confirmation' && confirmed)
128
- ctx.deps.updateNotifications.transition(notification.id, 'applying');
216
+ (await ctx.deps.updateNotifications.transition(notification.id, 'applying'));
129
217
  try {
130
- const result = await apply();
218
+ const options = { agentChannel: input.agent_channel, confirmedRevision: input.confirmed_agent_revision, version: input.version, refreshToken: input.agent_refresh_token, mutationIntent: principalHash(scope.owner, scope.profile, notification.id) };
219
+ const result = action === 'apply' ? await ctx.deps.updates.apply(target, bodyChannel(input.channel), () => true, options)
220
+ : action === 'force' ? await ctx.deps.updates.force(target, bodyChannel(input.channel), options)
221
+ : await ctx.deps.updates.clearLock(target, options);
131
222
  const verifiedIdentity = typeof result.verified_revision === 'string'
132
223
  ? { revision: result.verified_revision, version: typeof result.verified_version === 'string' ? result.verified_version : null }
133
224
  : undefined;
134
225
  if (result.confirmation_required === true)
135
- ctx.deps.updateNotifications.transition(notification.id, 'awaiting_confirmation', null, verifiedIdentity);
226
+ (await ctx.deps.updateNotifications.transition(notification.id, 'awaiting_confirmation', null, verifiedIdentity, result.message));
136
227
  else if (result.restart_blocked === true)
137
- ctx.deps.updateNotifications.transition(notification.id, 'blocked', null, verifiedIdentity, result.message);
228
+ (await ctx.deps.updateNotifications.transition(notification.id, 'blocked', null, verifiedIdentity, result.message));
138
229
  else if (result.ok !== true)
139
- ctx.deps.updateNotifications.transition(notification.id, 'failed', null, verifiedIdentity, result.message || result.error);
230
+ (await ctx.deps.updateNotifications.transition(notification.id, 'failed', null, verifiedIdentity, result.message || result.error));
140
231
  else if (target === 'webui' && result.restart_scheduled === true) {
141
- ctx.deps.updateNotifications.transition(notification.id, 'restarting', str(result.sourceRevision || result.candidate_revision), verifiedIdentity);
232
+ await ctx.deps.updateNotifications.transition(notification.id, 'restarting', str(result.sourceRevision || result.candidate_revision), verifiedIdentity);
233
+ }
234
+ else if (result.gateway_restart === 'waiting_for_idle' || (target === 'agent' && ctx.deps.gatewayRestarts.pendingId() !== null)) {
235
+ // TAL-953: the gateway restarts once its own work drains. A restart already waiting covers this update too, and a
236
+ // repeated request that found the Agent current follows that wait rather than reporting success before it.
237
+ const detail = result.stash_conflict === true ? str(result.message) : null;
238
+ await ctx.deps.updateNotifications.transition(notification.id, 'waiting_for_idle', null, verifiedIdentity, detail);
239
+ const pending = (await ctx.deps.gatewayRestarts.schedule(notification.id, scope.profile, detail));
240
+ if (pending !== notification.id)
241
+ (await ctx.deps.updateNotifications.watch(scope, pending));
242
+ return { ...result, notification_id: pending };
142
243
  }
143
244
  else {
144
245
  // A kept Agent stash needs the user's attention; its recovery commands ride on the success record.
145
- ctx.deps.updateNotifications.transition(notification.id, 'succeeded', null, verifiedIdentity, result.stash_conflict === true ? result.message : undefined);
246
+ await ctx.deps.updateNotifications.transition(notification.id, 'succeeded', null, verifiedIdentity, result.stash_conflict === true ? result.message : undefined);
146
247
  }
147
248
  return { ...result, notification_id: notification.id };
148
249
  }
149
250
  catch (error) {
150
- ctx.deps.updateNotifications.transition(notification.id, 'failed', null, undefined, error instanceof Error ? error.message : null);
251
+ await ctx.deps.updateNotifications.transition(notification.id, 'failed', null, undefined, error instanceof Error ? error.message : null);
151
252
  throw error;
152
253
  }
153
254
  }
@@ -225,10 +326,10 @@ export function sanitizeClientEvent(payload) {
225
326
  out.event = 'unknown';
226
327
  return out;
227
328
  }
228
- function memoryWorkspace(ctx, sessionId, workspace) {
329
+ async function memoryWorkspace(ctx, sessionId, workspace) {
229
330
  if (sessionId) {
230
331
  try {
231
- const session = ctx.deps.sessionStore.get(sessionId, { metadataOnly: true });
332
+ const session = (await ctx.deps.sessionStore.get(sessionId, { metadataOnly: true }));
232
333
  if (!ctx.deps.workspaces.profileSupportsLocalIo(session.profile))
233
334
  return null;
234
335
  const ws = str(session.workspace).trim();
@@ -241,11 +342,11 @@ function memoryWorkspace(ctx, sessionId, workspace) {
241
342
  const profile = activeProfileName(ctx);
242
343
  if (!ctx.deps.workspaces.profileSupportsLocalIo(profile))
243
344
  return null;
244
- const raw = workspace || (ctx.deps.config.env.TERMINAL_CWD ?? '') || ctx.deps.workspaces.lastWorkspace(profile);
345
+ const raw = workspace || (ctx.deps.config.env.TERMINAL_CWD ?? '') || (await ctx.deps.workspaces.lastWorkspace(profile));
245
346
  if (!raw)
246
347
  return null;
247
348
  try {
248
- return ctx.deps.workspaces.resolveTrusted(raw, profile);
349
+ return (await ctx.deps.workspaces.resolveTrusted(raw, profile));
249
350
  }
250
351
  catch {
251
352
  return null;
@@ -277,7 +378,13 @@ async function wikiLocation(ctx) {
277
378
  const config = await ctx.deps.agentConfig.read(profileHome).catch(() => ({}));
278
379
  return resolveWikiLocation(ctx.deps.config.env, profileHome, config, ctx.deps.config.homeDir);
279
380
  }
381
+ /** TAL-819: the Agent's review handler per write; its message can quote the entry text an approval replaced or removed. */
382
+ async function reviewPendingWrites(ctx, verb, input) {
383
+ const { results } = await runningSidecar(ctx).call(`write_approval.${verb}`, { profile_home: home(ctx), kind: input.kind, writes: input.writes });
384
+ return { results: results.map((r) => ({ ...r, message: redactString(r.message, ctx.deps.sessions.deps.redactEnabled()) })) };
385
+ }
280
386
  export const toolsRouter = os.router({
387
+ toolsetsCatalog: os.toolsetsCatalog.handler(({ input, context: { ctx } }) => run(() => runningSidecar(ctx).call('toolsets.catalog', { profile_home: home(ctx), enabled_toolsets: input.toolsets }))),
281
388
  skills: {
282
389
  list: os.skills.list.handler(({ input, context: { ctx } }) => run(async () => ({ skills: await ctx.deps.skills.list(home(ctx), str(input.category).trim() || null) }))),
283
390
  usage: os.skills.usage.handler(({ context: { ctx } }) => run(() => ctx.deps.skills.usage(home(ctx)))),
@@ -308,14 +415,31 @@ export const toolsRouter = os.router({
308
415
  memory: {
309
416
  get: os.memory.get.handler(({ input, context: { ctx } }) => run(async () => {
310
417
  const config = await ctx.deps.agentConfig.read(home(ctx));
311
- return readMemory(home(ctx), config, memoryWorkspace(ctx, str(input.session_id), str(input.workspace)), ctx.deps.config.env, ctx.deps.sessions.deps.redactEnabled());
418
+ return readMemory(home(ctx), config, (await memoryWorkspace(ctx, str(input.session_id), str(input.workspace))), ctx.deps.config.env, ctx.deps.sessions.deps.redactEnabled(), ctx.deps.auth.signingKey());
312
419
  })),
313
420
  write: os.memory.write.handler(({ input, context: { ctx } }) => run(async () => {
314
421
  const section = input.section ?? input.target;
315
422
  if (section === undefined || input.content === undefined)
316
423
  throw new HttpError(400, 'Missing required field(s): section, content');
317
- return writeMemory(home(ctx), await ctx.deps.agentConfig.read(home(ctx)), str(section), str(input.content));
424
+ const profileHome = home(ctx);
425
+ return writeMemory(profileHome, await ctx.deps.agentConfig.read(profileHome), str(section), str(input.content), input.revision, {
426
+ key: ctx.deps.auth.signingKey(),
427
+ check: (target, content) => runningSidecar(ctx).call('memory.check', { profile_home: profileHome, target, content }),
428
+ write: (target, base, content) => runningSidecar(ctx).call('memory.write', { profile_home: profileHome, section: target, base, content }),
429
+ });
430
+ })),
431
+ },
432
+ pendingWrites: {
433
+ list: os.pendingWrites.list.handler(({ input, context: { ctx } }) => run(async () => {
434
+ // Without the Agent nothing can be reviewed, so the page shows no panel (the Agent's own status reports it down).
435
+ const sidecar = ctx.deps.sidecar();
436
+ const { enabled, items } = sidecar ? await sidecar.call('write_approval.pending', { profile_home: home(ctx), kind: input.kind }) : { enabled: false, items: [] };
437
+ const redact = (text) => redactString(text, ctx.deps.sessions.deps.redactEnabled());
438
+ // Display text is redacted like the memory page; `revision` stays the sidecar's hash of the raw diff it rechecks.
439
+ return { kind: input.kind, visible: items.length > 0, enabled, items: items.map((item) => ({ ...item, summary: redact(item.summary), diff: redact(item.diff) })) };
318
440
  })),
441
+ approve: os.pendingWrites.approve.handler(({ input, context: { ctx } }) => run(() => reviewPendingWrites(ctx, 'approve', input))),
442
+ reject: os.pendingWrites.reject.handler(({ input, context: { ctx } }) => run(() => reviewPendingWrites(ctx, 'reject', input))),
319
443
  },
320
444
  prompts: {
321
445
  list: os.prompts.list.handler(({ context: { ctx } }) => run(() => ({ prompts: loadPrompts(home(ctx)) }))),
@@ -337,8 +461,19 @@ export const toolsRouter = os.router({
337
461
  const command = str(input.command).trim();
338
462
  if (!command)
339
463
  throw new HttpError(400, 'command is required');
464
+ const [, name = '', args = ''] = /^\/?(\S*)\s*([\s\S]*)$/.exec(command) ?? [];
465
+ const sessionId = str(input.session_id).trim();
466
+ if (sessionId)
467
+ (await ctx.deps.sessions.assertWritable(sessionId));
468
+ // TAL-902: a session command runs on the chat's own agent (the request guard already checked the chat's profile).
469
+ if (SESSION_EXEC_COMMANDS.has(name.toLowerCase())) {
470
+ return { output: await ctx.deps.turns.refine(sessionId ? (await ctx.deps.sessionStore.get(sessionId)) : null, args.trim()) };
471
+ }
472
+ // TAL-904: a chat's command runs under that chat's session and the workspace its next turn would use. An unknown
473
+ // chat (404) or a workspace that turn would refuse (400) refuses the command rather than run it half-bound.
474
+ const chat = sessionId ? { session_id: sessionId, workspace: (await ctx.deps.sessions.turnWorkspace((await ctx.deps.sessionStore.get(sessionId, { metadataOnly: true })))) } : {};
340
475
  try {
341
- return { output: (await runningSidecar(ctx).call('commands.exec', { profile_home: home(ctx), command }, { timeoutMs: 120_000 })).output };
476
+ return { output: (await runningSidecar(ctx).call('commands.exec', { profile_home: home(ctx), command, ...chat }, { timeoutMs: 120_000 })).output };
342
477
  }
343
478
  catch (error) {
344
479
  return commandFailure(error, 'command_not_found', 'Plugin command not found');
@@ -401,10 +536,10 @@ export const toolsRouter = os.router({
401
536
  browse: os.wiki.browse.handler(({ context: { ctx } }) => run(async () => wikiPages.browse(await wikiLocation(ctx)))),
402
537
  page: os.wiki.page.handler(({ input, context: { ctx } }) => run(async () => wikiPages.page(await wikiLocation(ctx), str(input.path)))),
403
538
  },
404
- insights: os.insights.handler(({ input, context: { ctx } }) => run(() => {
539
+ insights: os.insights.handler(({ input, context: { ctx } }) => run(async () => {
405
540
  let entries = [];
406
541
  try {
407
- entries = ctx.deps.sessionStore.readIndexEntries();
542
+ entries = (await ctx.deps.sessionStore.readIndexEntries());
408
543
  }
409
544
  catch {
410
545
  entries = [];
@@ -413,13 +548,13 @@ export const toolsRouter = os.router({
413
548
  })),
414
549
  logs: os.logs.handler(({ input, context: { ctx } }) => run(() => readLogTail(home(ctx), input.file, input.tail))),
415
550
  ops: {
416
- agent: os.ops.agent.handler(({ context: { ctx } }) => run(() => health(ctx))),
551
+ agent: os.ops.agent.handler(({ context: { ctx } }) => run(async () => { const [gateway, chat] = await Promise.all([health(ctx), currentChatReadiness(ctx.deps.sidecar())]); return { ...gateway, chat }; })),
417
552
  system: os.ops.system.handler(({ context: { ctx } }) => run(() => systemHealth(ctx.deps.config.homeDir, ctx.deps.runtimeDiagnostics()))),
418
553
  restart: os.ops.restart.handler(({ context: { ctx } }) => run(async () => {
419
554
  const sidecar = ctx.deps.sidecar();
420
555
  if (!sidecar)
421
556
  throw new HttpError(500, 'Hermes Agent sidecar is not running');
422
- const outcome = await sidecar.call('gateway.restart', { profile_home: home(ctx) }, { timeoutMs: 300_000 });
557
+ const outcome = await restartGateway(sidecar, home(ctx));
423
558
  if (outcome.status === 'completed')
424
559
  return { ok: true, message: 'Gateway service restarted successfully' };
425
560
  if (outcome.status === 'busy')
@@ -433,11 +568,11 @@ export const toolsRouter = os.router({
433
568
  await ctx.deps.agentConfig.update(home(ctx), (config) => { applyDashboardConfig(config, next); });
434
569
  return next;
435
570
  })),
436
- projectOs: os.ops.projectOs.handler(({ input, context: { ctx } }) => run(() => {
571
+ projectOs: os.ops.projectOs.handler(({ input, context: { ctx } }) => run(async () => {
437
572
  const profile = activeProfileName(ctx);
438
573
  return projectOsDashboard(str(input.board), {
439
574
  localIo: ctx.deps.workspaces.profileSupportsLocalIo(profile),
440
- lastWorkspace: ctx.deps.workspaces.lastWorkspace(profile),
575
+ lastWorkspace: (await ctx.deps.workspaces.lastWorkspace(profile)),
441
576
  boards: async () => (await runningSidecar(ctx).call('kanban.boards', { profile_home: home(ctx), include_archived: true })).boards,
442
577
  git: async (repoRoot) => gitBadge(await ctx.deps.git.status(repoRoot, { useCache: true })),
443
578
  cwd: process.cwd(),
@@ -471,9 +606,48 @@ export const toolsRouter = os.router({
471
606
  update: os.mcp.update.handler(({ input, context: { ctx } }) => run(() => { const { name, ...body } = input; return ctx.deps.mcp.update(home(ctx), decodeURIComponent(name), body); })),
472
607
  delete: os.mcp.delete.handler(({ input, context: { ctx } }) => run(() => ctx.deps.mcp.delete(home(ctx), decodeURIComponent(input.name)))),
473
608
  },
609
+ connectors: {
610
+ // Fails closed: no sidecar, or one that cannot answer, hides the page.
611
+ available: os.connectors.available.handler(({ context: { ctx } }) => run(async () => ({ available: ctx.deps.sidecar() ? await connectorCall(ctx, 'connectors.available', {}).then((r) => r.available, () => false) : false }))),
612
+ page: os.connectors.page.handler(({ context: { ctx } }) => run(async () => {
613
+ if (!ctx.deps.sidecar() || !(await connectorCall(ctx, 'connectors.available', {})).available)
614
+ return { available: false, connectors: [], policy_revision: null, rules_error: null };
615
+ const [catalog, accounts, policy] = await Promise.all([connectorCall(ctx, 'connectors.catalog', {}), connectorCall(ctx, 'connectors.accounts', {}), connectorPolicy(ctx)]);
616
+ rememberCatalogNames(home(ctx), catalog.connectors);
617
+ return connectorsPage(catalog.connectors, accounts.accounts, policy.policy, policy.error);
618
+ })),
619
+ tools: os.connectors.tools.handler(({ input, context: { ctx } }) => run(async () => {
620
+ const [listing, policy] = await Promise.all([connectorCall(ctx, 'connectors.tools', { connector: input.connector }), connectorPolicy(ctx)]);
621
+ return connectorTools(listing, policy.policy);
622
+ })),
623
+ setPolicy: os.connectors.setPolicy.handler(({ input, context: { ctx } }) => run(async () => {
624
+ const change = input.tool === undefined ? (typeof input.enabled === 'boolean' ? { enabled: input.enabled } : null)
625
+ : typeof input.tool_enabled === 'boolean' && input.enabled === undefined ? { tool: input.tool, tool_enabled: input.tool_enabled } : null;
626
+ if (!change)
627
+ throw new HttpError(400, 'Send `enabled`, or `tool` with `tool_enabled`.', { code: 'policy_invalid' });
628
+ const { revision } = await connectorCall(ctx, 'connectors.policy.set', { connector: input.connector, expected_revision: input.revision, ...change });
629
+ return { ok: true, revision };
630
+ })),
631
+ connect: os.connectors.connect.handler(({ input, context: { ctx } }) => run(async () => operationView(ctx, await connectorCall(ctx, 'connectors.connect', { connector: input.connector })))),
632
+ removeAccount: os.connectors.removeAccount.handler(({ input, context: { ctx } }) => run(async () => {
633
+ await connectorCall(ctx, 'connectors.remove', { connection_id: input.connection_id });
634
+ return { ok: true };
635
+ })),
636
+ operation: os.connectors.operation.handler(({ input, context: { ctx } }) => run(async () => operationView(ctx, await connectorCall(ctx, 'connectors.operation', { op_id: input.op_id })))),
637
+ respond: os.connectors.respond.handler(({ input, context: { ctx } }) => run(async () => {
638
+ // Only a move the operation offers now reaches the Agent: the view decides, the sidecar applies.
639
+ const view = connectorOperation(await connectorCall(ctx, 'connectors.operation', { op_id: input.op_id }));
640
+ const { action } = input;
641
+ const offered = action === 'continue' ? view.can_continue : view.targets.some((t) => t.name === input.target && t.actions.includes(action));
642
+ if (!offered)
643
+ throw new HttpError(409, 'That move is not open on this connection.', { code: 'operation_refused' });
644
+ return operationView(ctx, await connectorCall(ctx, 'connectors.respond', { op_id: input.op_id, action, ...(input.target ? { target: input.target } : {}), ...(input.env ? { env: input.env } : {}) }));
645
+ })),
646
+ },
474
647
  plugins: os.plugins.handler(({ context: { ctx } }) => run(async () => {
475
648
  const sidecar = ctx.deps.sidecar();
476
649
  const hooks = ['pre_tool_call', 'post_tool_call', 'pre_llm_call', 'post_llm_call'];
650
+ const editable = await sessionCanManageServer(ctx, await ensureTrustedAuthSession(ctx));
477
651
  if (!sidecar)
478
652
  return { plugins: [], empty: true, supported_hooks: hooks, read_only: true, unavailable: true };
479
653
  try {
@@ -483,22 +657,80 @@ export const toolsRouter = os.router({
483
657
  if (v && typeof v === 'object' && !Array.isArray(v) && typeof v.provider === 'string')
484
658
  selected[k] = str(v.provider).trim().toLowerCase();
485
659
  const result = await sidecar.call('plugins.list', { profile_home: home(ctx), selected_providers: selected });
486
- return { plugins: result.plugins, empty: result.plugins.length === 0, supported_hooks: result.supported_hooks, read_only: true };
660
+ // A settings failure leaves the list itself readable.
661
+ const declared = await pluginSettingsList(ctx).catch((error) => { ctx.deps.log(`[plugins] settings fields failed: ${str(error.message)}`); return []; });
662
+ const settings = new Map(declared.map((entry) => [entry.key, entry.fields]));
663
+ const plugins = result.plugins.map((plugin) => settings.has(plugin.key) ? { ...plugin, settings: settings.get(plugin.key) } : plugin);
664
+ // An advisory failure leaves the list itself readable.
665
+ const advisory = await pluginIsolationAdvisory(ctx).catch((error) => { ctx.deps.log(`[plugins] isolation advisory failed: ${str(error.message)}`); return false; });
666
+ return { plugins, empty: plugins.length === 0, supported_hooks: result.supported_hooks, read_only: !editable, plugin_isolation_advisory: advisory };
487
667
  }
488
668
  catch (error) {
489
669
  ctx.deps.log(`[plugins] visibility payload failed: ${str(error.message)}`);
490
670
  return { plugins: [], empty: true, supported_hooks: hooks, read_only: true, unavailable: true };
491
671
  }
492
672
  })),
673
+ pluginSettings: os.pluginSettings.handler(({ input, context: { ctx } }) => run(() => serializePluginSettingsSave(async () => {
674
+ const sidecar = runningSidecar(ctx);
675
+ const fields = (await pluginSettingsList(ctx)).find((entry) => entry.key === input.key)?.fields;
676
+ if (!fields)
677
+ throw new HttpError(404, `Plugin '${input.key}' declares no settings`);
678
+ let plan;
679
+ try {
680
+ plan = planPluginSettings(fields, input.values ?? {}, input.secrets ?? {});
681
+ }
682
+ catch (error) {
683
+ if (error instanceof PluginSettingsInvalid)
684
+ throw new HttpError(400, error.message);
685
+ throw error;
686
+ }
687
+ const secretFields = fields.filter((field) => field.env && field.env in plan.secrets);
688
+ // Secrets never reach config.yaml: each goes to the profile `.env` under the name the manifest field declares. They are
689
+ // written first and restored if a later write fails, so a refused save changes neither file. The save call always runs:
690
+ // it resolves the plugin again and refuses (before writing) when a secret's `.env` name no longer matches its manifest.
691
+ const credential = (envVar, value) => writeRuntimeCredential({ env: ctx.deps.config.env, sidecar: ctx.deps.sidecar, log: ctx.deps.log }, ctx.deps.isRootProfile(activeProfileName(ctx)), home(ctx), envVar, value);
692
+ const previous = loadEnvFile(join(home(ctx), '.env'));
693
+ const applied = [];
694
+ let result;
695
+ try {
696
+ for (const [envVar, value] of Object.entries(plan.secrets)) {
697
+ await credential(envVar, value);
698
+ applied.push(envVar);
699
+ }
700
+ result = await sidecar.call('plugins.settings_save', { profile_home: home(ctx), key: input.key, values: plan.values, secret_envs: Object.fromEntries(secretFields.map((field) => [field.key, field.env])) });
701
+ }
702
+ catch (error) {
703
+ if (!definitiveRefusal(error)) {
704
+ throw new HttpError(503, 'The Agent sidecar stopped before confirming the save, so it may be partly applied; reload Settings to see what was saved', { condition: 'plugin_settings_unconfirmed' });
705
+ }
706
+ for (const envVar of applied.reverse()) {
707
+ await credential(envVar, previous[envVar] ?? null).catch((restore) => { ctx.deps.log(`[plugins] could not restore ${envVar} after a failed settings save: ${str(restore.message)}`); });
708
+ }
709
+ if (error instanceof SidecarError && error.condition === 'plugin_settings_managed')
710
+ throw new HttpError(403, error.message, { condition: error.condition });
711
+ if (error instanceof SidecarError && error.condition === 'plugin_settings_changed')
712
+ throw new HttpError(409, `${error.message}; reload and try again`, { condition: error.condition });
713
+ if (error instanceof SidecarError && error.condition === 'plugin_not_found')
714
+ throw new HttpError(404, error.message);
715
+ if (error instanceof SidecarError && error.code === -32602)
716
+ throw new HttpError(400, error.message);
717
+ if (error instanceof RuntimeCredentialError)
718
+ throw new HttpError(503, error.message);
719
+ if (error instanceof EnvWriteError)
720
+ throw new HttpError(error.status, `Failed to save a secret: ${error.message}`, { condition: error.condition });
721
+ throw error;
722
+ }
723
+ return { ok: true, key: result.key, written: [...result.written, ...secretFields.map((field) => field.key)], settings: pluginSettingsFieldsView(ctx, result.fields) };
724
+ }))),
493
725
  updates: {
494
- check: os.updates.check.handler(({ context: { ctx } }) => run(() => {
495
- const settings = ctx.deps.settings.load();
726
+ check: os.updates.check.handler(({ context: { ctx } }) => run(async () => {
727
+ const settings = (await ctx.deps.settings.load());
496
728
  if (settings.check_for_updates === false)
497
729
  return updatesCheckView({ disabled: true });
498
730
  return updatesCheckView(ctx.deps.updates.cachedStatus(!pyBool(settings.ignore_agent_updates)));
499
731
  })),
500
732
  checkNow: os.updates.checkNow.handler(({ input, context: { ctx } }) => run(async () => {
501
- const settings = ctx.deps.settings.load();
733
+ const settings = (await ctx.deps.settings.load());
502
734
  const force = pyBool(input.force);
503
735
  if (settings.check_for_updates === false && !force)
504
736
  return updatesCheckView({ disabled: true });
@@ -507,58 +739,83 @@ export const toolsRouter = os.router({
507
739
  ctx.deps.log(`[updates] checking for updates (force=${String(force)}, channel=${channel})`);
508
740
  return updatesCheckView(await ctx.deps.updates.check(force, !pyBool(settings.ignore_agent_updates), channel, input.agent_channel));
509
741
  })),
510
- apply: os.updates.apply.handler(({ input, context: { ctx } }) => run(() => { const target = updateTarget(input.target); return applyWithNotification(ctx, target, () => ctx.deps.updates.apply(target, bodyChannel(input.channel), () => true, { agentChannel: input.agent_channel, confirmedRevision: input.confirmed_agent_revision }), input.confirmed_agent_revision !== undefined, input.tab_id); })),
511
- force: os.updates.force.handler(({ input, context: { ctx } }) => run(() => { const target = updateTarget(input.target); return applyWithNotification(ctx, target, () => ctx.deps.updates.force(target, bodyChannel(input.channel), { agentChannel: input.agent_channel, confirmedRevision: input.confirmed_agent_revision }), input.confirmed_agent_revision !== undefined, input.tab_id); })),
512
- clearLock: os.updates.clearLock.handler(({ input, context: { ctx } }) => run(() => { const target = updateTarget(input.target); return applyWithNotification(ctx, target, () => ctx.deps.updates.clearLock(target, { agentChannel: input.agent_channel, confirmedRevision: input.confirmed_agent_revision }), input.confirmed_agent_revision !== undefined, input.tab_id); })),
513
- summary: os.updates.summary.handler(({ input, context: { ctx } }) => run(() => ctx.deps.updates.summarize(input.target, ctx.deps.settings.load().check_for_updates === false))),
742
+ apply: os.updates.apply.handler(({ input, context: { ctx } }) => run(() => applyWithNotification(ctx, input, 'apply'))),
743
+ force: os.updates.force.handler(({ input, context: { ctx } }) => run(() => applyWithNotification(ctx, input, 'force'))),
744
+ clearLock: os.updates.clearLock.handler(({ input, context: { ctx } }) => run(() => applyWithNotification(ctx, input, 'clearLock'))),
745
+ summary: os.updates.summary.handler(({ input, context: { ctx } }) => run(async () => ctx.deps.updates.summarize(input.target, (await ctx.deps.settings.load()).check_for_updates === false))),
514
746
  },
515
747
  updateNotifications: {
516
748
  list: os.updateNotifications.list.handler(({ input, context: { ctx } }) => run(async () => {
517
749
  const scope = await updateNotificationScope(ctx, input.tab_id);
518
- const frontendBuild = ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId());
519
- return { ...ctx.deps.updateNotifications.list(scope), frontend_build: frontendBuild };
750
+ const frontendBuild = (await ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId()));
751
+ return { ...(await ctx.deps.updateNotifications.list(scope)), frontend_build: frontendBuild };
520
752
  })),
521
753
  read: os.updateNotifications.read.handler(({ input, context: { ctx } }) => run(async () => {
522
- const notification = ctx.deps.updateNotifications.read(await updateNotificationScope(ctx, input.tab_id), input.id);
754
+ const notification = (await ctx.deps.updateNotifications.read(await updateNotificationScope(ctx, input.tab_id), input.id));
523
755
  if (!notification)
524
756
  throw new HttpError(404, 'Update notification not found');
525
757
  return notification;
526
758
  })),
527
759
  dismiss: os.updateNotifications.dismiss.handler(({ input, context: { ctx } }) => run(async () => {
528
- const result = ctx.deps.updateNotifications.dismiss(await updateNotificationScope(ctx, input.tab_id), input.id);
760
+ const result = (await ctx.deps.updateNotifications.dismiss(await updateNotificationScope(ctx, input.tab_id), input.id));
529
761
  if (result === 'acknowledgement_required')
530
762
  throw new HttpError(409, 'This notification requires acknowledgement before it can be dismissed');
531
763
  return { ok: true };
532
764
  })),
533
765
  clear: os.updateNotifications.clear.handler(({ input, context: { ctx } }) => run(async () => {
534
766
  const scope = await updateNotificationScope(ctx, input.tab_id);
535
- const frontendBuild = ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId());
536
- return { ...ctx.deps.updateNotifications.clear(scope), frontend_build: frontendBuild };
767
+ const frontendBuild = (await ctx.deps.updateNotifications.syncTabBuild(scope, input.loaded_build ?? null, ctx.deps.spa.buildId()));
768
+ return { ...(await ctx.deps.updateNotifications.clear(scope)), frontend_build: frontendBuild };
537
769
  })),
538
770
  cancel: os.updateNotifications.cancel.handler(({ input, context: { ctx } }) => run(async () => {
539
- const notification = ctx.deps.updateNotifications.cancelUpdate(await updateNotificationScope(ctx), input.id);
771
+ const notification = (await ctx.deps.updateNotifications.cancelUpdate(await updateNotificationScope(ctx), input.id));
540
772
  if (!notification)
541
773
  throw new HttpError(404, 'Awaiting update notification not found');
542
774
  return notification;
543
775
  })),
544
776
  action: os.updateNotifications.action.handler(({ input, context: { ctx } }) => run(async () => {
545
- const notification = ctx.deps.updateNotifications.action(await updateNotificationScope(ctx, input.tab_id), input.id, input.action_id);
777
+ const notification = (await ctx.deps.updateNotifications.action(await updateNotificationScope(ctx, input.tab_id), input.id, input.action_id));
546
778
  if (!notification)
547
779
  throw new HttpError(404, 'Notification action not found');
780
+ if (input.action_id === GATEWAY_RESTART_NOW)
781
+ ctx.deps.gatewayRestarts.restartNow(notification.id);
548
782
  return notification;
549
783
  })),
550
784
  },
551
785
  transcribeCapability: os.transcribeCapability.handler(({ context: { ctx } }) => run(async () => {
786
+ const unavailable = { ok: true, available: false, provider: 'none', streaming: false, warm_supported: false };
552
787
  const sidecar = ctx.deps.sidecar();
553
788
  if (!sidecar)
554
- return { ok: true, available: false, provider: 'none' };
789
+ return unavailable;
555
790
  try {
556
791
  const cap = await sidecar.call('stt.capability', { profile_home: home(ctx) });
557
- return { ok: true, available: cap.available, provider: cap.provider || 'none' };
792
+ return { ok: true, available: cap.available, provider: cap.provider || 'none', streaming: cap.available && cap.streaming, warm_supported: cap.available && cap.warm_supported };
558
793
  }
559
794
  catch {
560
- return { ok: true, available: false, provider: 'none' };
795
+ return unavailable;
796
+ }
797
+ })),
798
+ speech: {
799
+ prepare: os.speech.prepare.handler(({ input, context: { ctx } }) => run(async () => ({ spoken_text: await spokenText(ctx, input.text.trim()) }))),
800
+ },
801
+ transcribeWarm: os.transcribeWarm.handler(({ context: { ctx } }) => run(() => {
802
+ const sidecar = ctx.deps.sidecar();
803
+ const profileHome = home(ctx);
804
+ // One load per profile at a time: a record start during a running load joins it rather than holding another sidecar slot.
805
+ if (sidecar && !warmingHomes.has(profileHome)) {
806
+ warmingHomes.add(profileHome);
807
+ // The load outlives this request's write lease: it is the profile's activity until it settles, so the profile
808
+ // cannot be deleted under it. Taken while the request's lease still refuses a deletion in progress.
809
+ const release = ctx.deps.profileActivity(activeProfileName(ctx));
810
+ // A first use downloads the model, and the Agent's load cannot be cancelled, so the call has no deadline: the entry
811
+ // lives exactly as long as the sidecar worker (a sidecar exit rejects it). Nobody waits on it.
812
+ void sidecar.call('stt.warm', { profile_home: profileHome }, { timeoutMs: 0 })
813
+ .then((result) => { if (result.action === 'error')
814
+ ctx.deps.log(`[stt] warm-up failed (${result.provider}): ${str(result.error)}`); })
815
+ .catch((error) => { ctx.deps.log(`[stt] warm-up failed: ${str(error.message)}`); })
816
+ .finally(() => { warmingHomes.delete(profileHome); release(); });
561
817
  }
818
+ return { ok: true };
562
819
  })),
563
820
  clientEvents: os.clientEvents.handler(({ input, context: { ctx } }) => run(() => {
564
821
  if (ctx.deps.clientEventLimiter.limited(ctx.peer || 'unknown'))