@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
@@ -0,0 +1,181 @@
1
+ """``write_approval.*``: the Agent's staged skill and memory writes (TAL-819).
2
+
3
+ With ``skills.write_approval`` or ``memory.write_approval`` on, the Agent stages writes under
4
+ ``<home>/pending/<kind>/<id>.json`` instead of committing them. These methods list them with
5
+ the diff an approval would apply, and approve or reject them through the Agent's own
6
+ ``/skills`` and ``/memory`` review handlers.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import contextlib
12
+ import difflib
13
+ import hashlib
14
+ import re
15
+ import tempfile
16
+ import threading
17
+ from pathlib import Path
18
+
19
+ from ..errors import InvalidParams, RpcError
20
+ from ..home import profile_home_param, scoped_home
21
+ from ..rpc import CallContext
22
+
23
+ KINDS = ("skills", "memory")
24
+ # The Agent names records ``uuid4().hex[:8]`` and builds their path from the id; anything else could leave the pending dir.
25
+ _ID = re.compile(r"[A-Za-z0-9_-]{1,64}")
26
+ # One review at a time in this process, so two approvals of one record cannot both replay it.
27
+ _LOCK = threading.Lock()
28
+
29
+
30
+ def _agent():
31
+ try:
32
+ from hermes_cli import write_approval_commands
33
+ from tools import write_approval
34
+ except ImportError as exc:
35
+ raise RpcError("This Hermes Agent cannot review staged writes", condition="write_approval_unavailable") from exc
36
+ return write_approval, write_approval_commands
37
+
38
+
39
+ def _kind(params: dict) -> str:
40
+ kind = str(params.get("kind") or "")
41
+ if kind not in KINDS:
42
+ raise InvalidParams("kind must be skills or memory")
43
+ return kind
44
+
45
+
46
+ def _memory_diff(payload: dict) -> str:
47
+ """Replay the record on a scratch copy of its file through the Agent's approve path; the diff is what approval commits."""
48
+ from tools.memory_tool import ENTRY_DELIMITER, apply_memory_pending, load_on_disk_store
49
+
50
+ store = load_on_disk_store()
51
+ target = "user" if payload.get("target") == "user" else "memory"
52
+ real = store._path_for(target)
53
+ before = list(store._entries_for(target))
54
+ with tempfile.TemporaryDirectory(prefix="talaria-pending-") as scratch:
55
+ copy = Path(scratch) / real.name
56
+ if real.is_file():
57
+ copy.write_bytes(real.read_bytes())
58
+ # The store resolves every read, lock and write through ``self._path_for``.
59
+ store._path_for = lambda t: Path(scratch) / ("USER.md" if t == "user" else "MEMORY.md")
60
+ result = apply_memory_pending(payload, store)
61
+ after = list(store._entries_for(target))
62
+ if not result.get("success"):
63
+ raise _Unapprovable(f"(approve would fail: {result.get('error') or 'unknown error'})")
64
+ lines = lambda entries: ENTRY_DELIMITER.join(entries).splitlines(keepends=True) # noqa: E731
65
+ diff = difflib.unified_diff(lines(before), lines(after), fromfile=f"a/{real.name}", tofile=f"b/{real.name}")
66
+ return "".join(diff) or "(no textual change)"
67
+
68
+
69
+ class _Unapprovable(Exception):
70
+ """A write with no diff the user could review: its message replaces the diff and approval is refused."""
71
+
72
+
73
+ def _skill_names(payload: dict) -> list[str]:
74
+ ops = payload.get("operations") or [] if payload.get("action") == "batch" else [payload]
75
+ return list(dict.fromkeys(str(op.get("name")) for op in ops if isinstance(op, dict) and op.get("name")))
76
+
77
+
78
+ def _item(wa, kind: str, record: dict) -> dict:
79
+ payload = record.get("payload") if isinstance(record.get("payload"), dict) else {}
80
+ if kind == "memory":
81
+ target = "user" if payload.get("target") == "user" else "memory"
82
+ else:
83
+ target = ", ".join(_skill_names(payload))
84
+ diff, approvable = _diff(wa, kind, record)
85
+ return {
86
+ "id": str(record.get("id") or ""), "kind": kind, "target": target, "op": str(payload.get("action") or record.get("action") or ""),
87
+ "summary": str(record.get("summary") or ""), "origin": str(record.get("origin") or "foreground"),
88
+ "created_at": float(record.get("created_at") or 0), "diff": diff,
89
+ "approvable": approvable, "revision": _revision(diff) if approvable else "",
90
+ }
91
+
92
+
93
+ def _diff(wa, kind: str, record: dict) -> tuple[str, bool]:
94
+ """The diff approving ``record`` applies and whether it may be approved; a diff that cannot be built is never approvable."""
95
+ payload = record.get("payload") if isinstance(record.get("payload"), dict) else {}
96
+ try:
97
+ return (_memory_diff(payload) if kind == "memory" else wa.skill_pending_diff(record)), True
98
+ except _Unapprovable as exc:
99
+ return str(exc), False
100
+ except Exception as exc: # noqa: BLE001 - one unreadable record must not hide the rest
101
+ return f"(diff unavailable: {exc})", False
102
+
103
+
104
+ def _apply_lock(kind: str, record: dict):
105
+ """Hold the Agent's own per-skill locks across the revision check and the apply (they are re-entrant in this thread, so
106
+ the Agent's apply takes them again). Memory needs none: the Agent applies a staged remove/patch only to the exact entry
107
+ it pinned at staging and an add only appends, so a concurrent write can never be dropped by an approval."""
108
+ if kind != "skills":
109
+ return contextlib.nullcontext()
110
+ from tools.skill_manager_tool import _skill_mutation_locks
111
+
112
+ return _skill_mutation_locks(_skill_names(record.get("payload") if isinstance(record.get("payload"), dict) else {}))
113
+
114
+
115
+ def _revision(diff: str) -> str:
116
+ """What the reviewer saw: the diff changes whenever the record or the file it applies to does."""
117
+ return hashlib.sha256(diff.encode("utf-8")).hexdigest()
118
+
119
+
120
+ def pending(kind: str) -> dict:
121
+ try:
122
+ wa, _ = _agent()
123
+ except RpcError:
124
+ return {"supported": False, "enabled": False, "items": []}
125
+ items = [_item(wa, kind, record) for record in wa.list_pending(kind) if _ID.fullmatch(str(record.get("id") or ""))]
126
+ return {"supported": True, "enabled": wa.write_approval_enabled(kind), "items": items}
127
+
128
+
129
+ def review(kind: str, verb: str, writes: list[dict]) -> dict:
130
+ """``approve`` or ``reject`` each write through the Agent's handler; a record that is gone afterwards was applied or dropped.
131
+
132
+ An approval applies only while the write's diff still has the ``revision`` the reviewer saw; a changed file or record
133
+ is refused, so nothing lands that the user did not review.
134
+ """
135
+ wa, commands = _agent()
136
+ if not writes or any(not (isinstance(w, dict) and _ID.fullmatch(str(w.get("id") or "")) and isinstance(w.get("revision"), str)) for w in writes):
137
+ raise InvalidParams("writes must be pending write ids with the revision reviewed")
138
+ results = []
139
+ with _LOCK:
140
+ for write in writes:
141
+ pending_id = write["id"]
142
+ record = wa.get_pending(kind, pending_id)
143
+ if record is None:
144
+ results.append({"id": pending_id, "done": False, "message": f"No pending {kind} write with id '{pending_id}'."})
145
+ continue
146
+ if verb == "reject":
147
+ message = commands.handle_pending_subcommand(kind, [verb, pending_id]) or ""
148
+ else:
149
+ with _apply_lock(kind, record):
150
+ diff, approvable = _diff(wa, kind, record)
151
+ if not approvable:
152
+ results.append({"id": pending_id, "done": False, "message": f"This write cannot be approved: {diff}"})
153
+ continue
154
+ if _revision(diff) != write["revision"]:
155
+ results.append({"id": pending_id, "done": False, "message": "This write's diff changed after you reviewed it. Review the new diff, then approve again."})
156
+ continue
157
+ store = None
158
+ if kind == "memory":
159
+ from tools.memory_tool import load_on_disk_store
160
+
161
+ store = load_on_disk_store()
162
+ message = commands.handle_pending_subcommand(kind, [verb, pending_id], memory_store=store) or ""
163
+ results.append({"id": pending_id, "done": wa.get_pending(kind, pending_id) is None, "message": message})
164
+ return {"results": results}
165
+
166
+
167
+ def register(registry) -> None:
168
+ @registry.method("write_approval.pending")
169
+ def pending_(ctx: CallContext, params: dict) -> dict:
170
+ kind = _kind(params)
171
+ with scoped_home(profile_home_param(params)):
172
+ return pending(kind)
173
+
174
+ for verb in ("approve", "reject"):
175
+ def handler(ctx: CallContext, params: dict, verb: str = verb) -> dict:
176
+ kind = _kind(params)
177
+ writes = list(params.get("writes") or [])
178
+ with scoped_home(profile_home_param(params)):
179
+ return review(kind, verb, writes)
180
+
181
+ registry.method(f"write_approval.{verb}")(handler)
@@ -13,6 +13,9 @@ from __future__ import annotations
13
13
 
14
14
  import json
15
15
  import logging
16
+ import os
17
+ import queue
18
+ import time
16
19
  import sys
17
20
  import threading
18
21
  import traceback
@@ -121,6 +124,9 @@ class RpcServer:
121
124
  def request_shutdown(self, exit_code: int = 0) -> None:
122
125
  self.exit_code = exit_code
123
126
  self._closed.set()
127
+ with self._active_lock:
128
+ for ctx in self._active.values():
129
+ ctx.cancel_event.set()
124
130
 
125
131
  # ── dispatch ──────────────────────────────────────────────────────────
126
132
  def _register(self, request: dict) -> CallContext | None:
@@ -182,12 +188,38 @@ class RpcServer:
182
188
 
183
189
  def serve_forever(self) -> int:
184
190
  """Read requests until stdin closes or shutdown is requested."""
185
- while not self._closed.is_set():
191
+ incoming = queue.Queue(maxsize=1)
192
+ def read_input():
186
193
  try:
187
- raw = self._in.readline()
194
+ try:
195
+ fd = self._in.fileno()
196
+ except (AttributeError, OSError, ValueError):
197
+ fd = None
198
+ if fd is None:
199
+ while raw := self._in.readline():
200
+ incoming.put(raw)
201
+ else:
202
+ # An unbuffered OS read cannot hold sys.stdin's Python buffer lock at interpreter exit.
203
+ pending = []
204
+ while chunk := os.read(fd, 65536):
205
+ lines = chunk.split(b"\n")
206
+ pending.append(lines[0])
207
+ for line in lines[1:]:
208
+ incoming.put(b"".join(pending))
209
+ pending = [line]
210
+ if pending:
211
+ incoming.put(b"".join(pending))
188
212
  except (OSError, ValueError):
189
- break
190
- if not raw:
213
+ pass
214
+ finally:
215
+ incoming.put(None)
216
+ threading.Thread(target=read_input, name="rpc-input", daemon=True).start()
217
+ while not self._closed.is_set():
218
+ try:
219
+ raw = incoming.get(timeout=.1)
220
+ except queue.Empty:
221
+ continue
222
+ if raw is None or self._closed.is_set():
191
223
  break
192
224
  raw = raw.strip()
193
225
  if not raw:
@@ -209,6 +241,15 @@ class RpcServer:
209
241
  continue
210
242
  ctx = self._register(request)
211
243
  threading.Thread(target=self._dispatch_slot, args=(request, ctx), name=f"rpc-{request.get('method')}", daemon=True).start()
244
+ if self._closed.is_set():
245
+ # Let the terminal reply reach stdout before the process returns its final exit code.
246
+ deadline = time.monotonic() + 5
247
+ while time.monotonic() < deadline:
248
+ with self._active_lock:
249
+ terminal_reply = any(ctx.method in {"runtime.shutdown", "runtime.handshake"} for ctx in self._active.values())
250
+ if not terminal_reply:
251
+ break
252
+ threading.Event().wait(.01)
212
253
  return self.exit_code
213
254
 
214
255
  def _dispatch_slot(self, request: dict, ctx: CallContext | None) -> None:
@@ -10,12 +10,15 @@ from __future__ import annotations
10
10
 
11
11
  import errno
12
12
  import importlib
13
+ import hashlib
13
14
  import json
14
15
  import math
15
16
  import os
17
+ import re
16
18
  import stat
17
19
  import subprocess
18
20
  import sys
21
+ import sysconfig
19
22
  import threading
20
23
  import time
21
24
  from pathlib import Path
@@ -24,11 +27,8 @@ from . import SIDECAR_RPC_VERSION
24
27
  from .errors import RpcError
25
28
 
26
29
  PIN_PATH = Path(__file__).resolve().parent.parent / "agent_dependency.json"
27
- _RESTART_REQUIRED_MESSAGE = (
28
- "Hermes Agent was updated while Talaria Web was running. "
29
- "Talaria Web cannot verify that the Agent update completed safely. "
30
- "Check the Agent update outcome and environment first. "
31
- "Restart Talaria Web manually before retrying this action."
30
+ _RUNTIME_UNAVAILABLE_MESSAGE = (
31
+ "Agent runtime is unavailable. Check the Agent update outcome before retrying this action."
32
32
  )
33
33
  _AGENT_UPDATE_MARKER = ".hermes-update-in-progress"
34
34
  _AGENT_RECOVERY_MARKERS = (".update-incomplete", ".lazy-refresh-incomplete")
@@ -40,11 +40,16 @@ _MARKER_SAFE_OPEN_AVAILABLE = bool(_O_NOFOLLOW) and bool(_O_NONBLOCK)
40
40
 
41
41
 
42
42
  class AgentRuntimeStale(RpcError):
43
- def __init__(self, update_state: str | None):
44
- data = {"retryable": True, "restart_scheduled": False}
43
+ def __init__(self, update_state: str | None, message: str | None = None, *, source_changed: bool = False):
44
+ data = {"retryable": True, "restart_scheduled": False, "agent_source_changed": source_changed}
45
45
  if update_state is not None:
46
46
  data["agent_update_state"] = update_state
47
- super().__init__(_RESTART_REQUIRED_MESSAGE, condition="agent_runtime_stale", data=data)
47
+ if message is None:
48
+ message = {
49
+ "active": "Agent update is in progress. Wait for it to finish before starting new work.",
50
+ "incomplete": "Agent update recovery is incomplete. Finish the Agent update before starting new work.",
51
+ }.get(update_state, _RUNTIME_UNAVAILABLE_MESSAGE)
52
+ super().__init__(message, condition="agent_runtime_stale", data=data)
48
53
 
49
54
 
50
55
  class AgentIncompatible(RpcError):
@@ -217,6 +222,45 @@ def installed_agent_version() -> str | None:
217
222
  return get_version_info().base_version
218
223
 
219
224
 
225
+ def _python_abi(major: int | str, minor: int | str, free_threaded: bool) -> str:
226
+ """``3.14`` or ``3.14t``: regular and free-threaded builds of one version load different native extensions."""
227
+ return f"{major}.{minor}{'t' if free_threaded else ''}"
228
+
229
+
230
+ def _site_packages_python(entry: str) -> tuple[str, Path] | None:
231
+ """The Python ABI a ``sys.path`` site-packages directory was built for, and that venv's interpreter."""
232
+ path = Path(entry)
233
+ if path.name != "site-packages" or not path.is_dir():
234
+ return None
235
+ match = re.fullmatch(r"python(\d+)\.(\d+)(t?)", path.parent.name)
236
+ if match and path.parent.parent.name in {"lib", "lib64"}:
237
+ return _python_abi(match[1], match[2], bool(match[3])), path.parent.parent.parent / "bin" / "python"
238
+ if path.parent.name.lower() == "lib":
239
+ venv = path.parent.parent
240
+ try:
241
+ config = (venv / "pyvenv.cfg").read_text(encoding="utf-8")
242
+ except OSError:
243
+ return None
244
+ found = re.search(r"^\s*version(?:_info)?\s*=\s*(\d+)\.(\d+)", config, re.MULTILINE)
245
+ if found:
246
+ free_threaded = re.search(r"^\s*executable\s*=.*python\d+\.\d+t(?:\.exe)?\s*$", config, re.MULTILINE | re.IGNORECASE)
247
+ return _python_abi(found[1], found[2], bool(free_threaded)), venv / "Scripts" / "python.exe"
248
+ return None
249
+
250
+
251
+ def _check_site_packages_python() -> None:
252
+ """Compiled Agent dependencies load lazily on the first chat; fail the handshake when ``sys.path`` holds
253
+ site-packages built for another Python (a stale ``HERMES_WEBUI_PYTHON`` after a PM environment update)."""
254
+ running = _python_abi(sys.version_info[0], sys.version_info[1], bool(sysconfig.get_config_var("Py_GIL_DISABLED")))
255
+ for entry in sys.path:
256
+ built = _site_packages_python(entry)
257
+ if built is not None and built[0] != running:
258
+ raise ImportError(
259
+ f"interpreter Python {running} cannot load Agent packages built for Python {built[0]} ({entry}); "
260
+ f"unset HERMES_WEBUI_PYTHON or point it at {built[1]}"
261
+ )
262
+
263
+
220
264
  class AgentRuntime:
221
265
  """Loads the Agent once and guards against a changed checkout."""
222
266
 
@@ -224,6 +268,7 @@ class AgentRuntime:
224
268
  self.hermes_home = Path(hermes_home)
225
269
  self._stale_lock = threading.Lock()
226
270
  self._stale = False
271
+ self._source_changed = False
227
272
  self._stale_stamp: tuple | None = None
228
273
  self.agent_dir = Path(agent_dir).resolve() if agent_dir else None
229
274
  self.pin = read_pin()
@@ -239,12 +284,18 @@ class AgentRuntime:
239
284
  if self.loaded:
240
285
  return
241
286
  try:
287
+ # Direct Agent imports skip CLI startup's PM tool PATH activation.
288
+ if self.agent_dir is not None and (self.agent_dir / "pm").is_dir():
289
+ compose_path = getattr(importlib.import_module("pm"), "store_first_path", None)
290
+ if compose_path is not None:
291
+ os.environ["PATH"] = compose_path(os.environ.get("PATH", ""))
242
292
  module = importlib.import_module("run_agent")
243
293
  getattr(module, "AIAgent")
244
294
  # Agent 0.21.3 snapshots its auth provider registry, discovered plugins included, when hermes_cli.auth
245
295
  # first imports. Take it here, under the launch profile and before any profile-scoped method runs, so
246
296
  # a named profile's plugin loaded later never enters that process-wide snapshot.
247
297
  importlib.import_module("hermes_cli.auth")
298
+ _check_site_packages_python()
248
299
  except Exception as exc: # noqa: BLE001 - reported as a handshake condition
249
300
  self.import_error = f"{type(exc).__name__}: {exc}"
250
301
  raise AgentIncompatible(f"Hermes Agent could not be imported: {self.import_error}", import_error=self.import_error)
@@ -276,9 +327,12 @@ class AgentRuntime:
276
327
 
277
328
  def update_transaction_state(self) -> str:
278
329
  live = _read_live_agent_update(self.hermes_home / _AGENT_UPDATE_MARKER)
279
- if live == "unknown":
330
+ if live in {"unknown", "active"}:
331
+ return live
332
+ repair = self.web_repair_state()
333
+ if repair == "unknown":
280
334
  return "unknown"
281
- recovery = False
335
+ recovery = repair == "present"
282
336
  for root in self._install_roots():
283
337
  for name in _AGENT_RECOVERY_MARKERS:
284
338
  presence = _marker_presence(root / name)
@@ -289,6 +343,16 @@ class AgentRuntime:
289
343
  return "incomplete"
290
344
  return "unverified" if live == "absent" else live
291
345
 
346
+ def web_repair_state(self) -> str:
347
+ if self.agent_dir is None:
348
+ return "absent"
349
+ from .agent_mutation import recovery_receipts
350
+ try:
351
+ receipts, _ = recovery_receipts(self)
352
+ return 'present' if receipts else 'absent'
353
+ except (OSError, UnicodeError):
354
+ return 'unknown'
355
+
292
356
  def is_stale(self) -> bool:
293
357
  """True when the checkout revision no longer matches the loaded module.
294
358
 
@@ -310,14 +374,18 @@ class AgentRuntime:
310
374
  fresh = None
311
375
  if fresh is not None:
312
376
  break
377
+ self._source_changed = fresh is not None and fresh != self.revision
313
378
  self._stale = fresh != self.revision
314
379
  self._stale_stamp = stamp if fresh is not None else None
315
380
  return self._stale
316
381
 
317
382
  def ensure_current(self) -> None:
318
- """Raise ``agent_runtime_stale`` when the checkout changed since import."""
383
+ """Refuse Agent work until source drift or a durable Web update obligation is reconciled."""
384
+ repair = self.web_repair_state()
385
+ if repair != "absent":
386
+ raise AgentRuntimeStale("unknown" if repair == "unknown" else self.update_transaction_state())
319
387
  if self.is_stale():
320
- raise AgentRuntimeStale(self.update_transaction_state())
388
+ raise AgentRuntimeStale(self.update_transaction_state(), source_changed=self._source_changed)
321
389
 
322
390
  # ── handshake ─────────────────────────────────────────────────────────
323
391
  def describe(self) -> dict:
@@ -335,6 +403,7 @@ class AgentRuntime:
335
403
  "pinned_image": self.pin["image"],
336
404
  "compatible": self.loaded,
337
405
  "stale": self.is_stale(),
406
+ "agent_source_changed": self._source_changed,
338
407
  "update_state": self.update_transaction_state(),
339
408
  "import_error": self.import_error,
340
409
  }
@@ -0,0 +1,35 @@
1
+ """One route-aware speed gate for the model catalog and chat request overrides."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import inspect
6
+ import re
7
+ from urllib.parse import urlparse
8
+
9
+
10
+ def fast_overrides(model: str, provider: str, base_url: str, tier: str) -> dict | None:
11
+ if tier not in ("priority", "ultrafast"):
12
+ return None
13
+ from hermes_cli import models
14
+
15
+ resolver = getattr(models, "resolve_fast_mode_overrides", None)
16
+ if resolver is not None:
17
+ if "tier" in inspect.signature(resolver).parameters:
18
+ return resolver(model, provider=provider, base_url=base_url, tier=tier)
19
+ return resolver(model, provider=provider, base_url=base_url) if tier == "priority" else None
20
+ # Older Agents have no resolver. Keep the former GPT-5/o-series gate, restricted to first-party routes.
21
+ hosts = {"openai": "api.openai.com", "openai-api": "api.openai.com", "openai-codex": "chatgpt.com"}
22
+ model = model.strip().lower().removeprefix("openai/")
23
+ host = urlparse(base_url).hostname if base_url else None
24
+ if tier == "priority" and provider in hosts and (not host or host == hosts[provider]) and (model.startswith("gpt-5") or re.match(r"o[0-9]", model)):
25
+ return {"service_tier": "priority"}
26
+ return None
27
+
28
+
29
+ def supported_speed_tiers(model: str, provider: str, base_url: str) -> list[dict]:
30
+ tiers = []
31
+ for tier in ("priority", "ultrafast"):
32
+ override = fast_overrides(model, provider, base_url, tier)
33
+ if override:
34
+ tiers.append({"id": "fast" if override.get("speed") == "fast" else tier, "service_tier": tier})
35
+ return [{"id": "standard", "service_tier": "default"}, *tiers] if tiers else []