openclaw-multi-auto 1.3.7 → 1.3.9

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 (414) hide show
  1. package/dist/{accounts-L9ByEpnP.js → accounts-C9HcPI9h.js} +2 -2
  2. package/dist/{accounts-BOzyfwW4.js → accounts-C_lW3Ag9.js} +2 -2
  3. package/dist/{accounts-yfBeCZtS.js → accounts-Tgelvk0C.js} +17 -17
  4. package/dist/{active-listener-D1yqT1cw.js → active-listener-BEdprTkn.js} +2 -2
  5. package/dist/{api-key-rotation-DtsNS2Nb.js → api-key-rotation-BJpKWXy0.js} +2 -2
  6. package/dist/{audio-preflight-DpxQCpsA.js → audio-preflight-BMvgEQ5j.js} +32 -32
  7. package/dist/{audio-transcription-runner-28fcRNNi.js → audio-transcription-runner-gLFfz8fr.js} +12 -12
  8. package/dist/{audit-membership-runtime-DWyHWAHM.js → audit-membership-runtime-Dntemq07.js} +4 -4
  9. package/dist/build-info.json +3 -3
  10. package/dist/bundled/boot-md/handler.js +51 -51
  11. package/dist/bundled/bootstrap-extra-files/handler.js +6 -6
  12. package/dist/bundled/command-logger/handler.js +2 -2
  13. package/dist/bundled/session-memory/handler.js +51 -51
  14. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  15. package/dist/{channel-activity-xHOMiarp.js → channel-activity-BDnjYF7B.js} +3 -3
  16. package/dist/{chrome-DwizpzOC.js → chrome-DxxEKrY7.js} +18 -18
  17. package/dist/{commands-registry-V1zZ5pPC.js → commands-registry-D5qXbFJn.js} +4 -4
  18. package/dist/control-ui/apple-touch-icon.png +0 -0
  19. package/dist/control-ui/assets/de-Bm0iuKxz.js +2 -0
  20. package/dist/control-ui/assets/de-Bm0iuKxz.js.map +1 -0
  21. package/dist/control-ui/assets/index-7XbUBC_m.js +8380 -0
  22. package/dist/control-ui/assets/index-7XbUBC_m.js.map +1 -0
  23. package/dist/control-ui/assets/index-E0j6Tkrc.css +1 -0
  24. package/dist/control-ui/assets/pt-BR-C2uaHesk.js +2 -0
  25. package/dist/control-ui/assets/pt-BR-C2uaHesk.js.map +1 -0
  26. package/dist/control-ui/assets/zh-CN-CqPGpAps.js +2 -0
  27. package/dist/control-ui/assets/zh-CN-CqPGpAps.js.map +1 -0
  28. package/dist/control-ui/assets/zh-TW-Cyl5GDQh.js +2 -0
  29. package/dist/control-ui/assets/zh-TW-Cyl5GDQh.js.map +1 -0
  30. package/dist/control-ui/favicon-32.png +0 -0
  31. package/dist/control-ui/favicon.ico +0 -0
  32. package/dist/control-ui/favicon.svg +22 -0
  33. package/dist/control-ui/index.html +17 -0
  34. package/dist/{deliver-D4o6VIur.js → deliver-DbdywYJE.js} +21 -21
  35. package/dist/deliver-runtime-BFs7iAZF.js +36 -0
  36. package/dist/deps-send-discord.runtime-DZUccI6Z.js +26 -0
  37. package/dist/deps-send-imessage.runtime-CF3OpoqY.js +25 -0
  38. package/dist/deps-send-signal.runtime-Cw4-ozeO.js +24 -0
  39. package/dist/deps-send-slack.runtime-BDsDhS1P.js +22 -0
  40. package/dist/deps-send-telegram.runtime-D_4xVasO.js +27 -0
  41. package/dist/deps-send-whatsapp.runtime-DK8jqd14.js +60 -0
  42. package/dist/{diagnostic-Bn4PZjMZ.js → diagnostic-Co6Kghr-.js} +2 -2
  43. package/dist/{errors-CCLeFWAg.js → errors-xt401nuk.js} +1 -1
  44. package/dist/{fetch-BlJWzEP6.js → fetch-DuraYswo.js} +5 -5
  45. package/dist/{fetch-guard-ChYBwfiy.js → fetch-guard-DWr0d00H.js} +2 -2
  46. package/dist/{frontmatter-CvaMP376.js → frontmatter-BkTfEZ93.js} +3 -3
  47. package/dist/{fs-safe-0jAo_Whb.js → fs-safe-CTYUrIgQ.js} +4 -4
  48. package/dist/{github-copilot-token-D13V9YBz.js → github-copilot-token-BDioPmd6.js} +7 -7
  49. package/dist/{image-Bbn53mzj.js → image-eT7Y-nP5.js} +6 -6
  50. package/dist/{image-ops-CehkHxmW.js → image-ops-BuUnEOE0.js} +2 -2
  51. package/dist/image-runtime-BcAK3n8a.js +29 -0
  52. package/dist/{ir-DAP-B-Xw.js → ir-B83looB-.js} +8 -8
  53. package/dist/{legacy-names-TyzbVqa_.js → legacy-names-DOC03BkU.js} +1 -1
  54. package/dist/llm-slug-generator.js +51 -51
  55. package/dist/{logger-DMZQQtxK.js → logger-BfjWMCSD.js} +7 -7
  56. package/dist/{login-DiCctRo1.js → login-CrIwcrVI.js} +5 -5
  57. package/dist/{login-qr-MUbXgjtd.js → login-qr-BpPDZdl_.js} +10 -10
  58. package/dist/{manager-BW_NSIMl.js → manager-1bvuGrNR.js} +13 -13
  59. package/dist/manager-runtime-FO1Sx3W8.js +18 -0
  60. package/dist/{model-selection-idoqPmw0.js → model-selection-Dna0Gz1k.js} +43 -43
  61. package/dist/{outbound-C2kanETZ.js → outbound-ChDjtuD6.js} +6 -6
  62. package/dist/{outbound-attachment-DBrYWX8h.js → outbound-attachment-DqHlD21U.js} +2 -2
  63. package/dist/{path-alias-guards-DqXRZmsL.js → path-alias-guards-BzvdLvTI.js} +1 -1
  64. package/dist/{paths-CCxysrzL.js → paths-Bkr-BCxW.js} +4 -4
  65. package/dist/{paths-C6TxBCvO.js → paths-Cvc9EM8Y.js} +5 -5
  66. package/dist/{pi-embedded-BaGj07T0.js → pi-embedded-BQQa91aA.js} +158 -158
  67. package/dist/{pi-embedded-helpers-wy0DZvx1.js → pi-embedded-helpers-CLXm10bV.js} +52 -52
  68. package/dist/{plugin-sdk/pi-model-discovery-v-XPUOOf.js → pi-model-discovery-Dymwdjt0.js} +2 -2
  69. package/dist/pi-model-discovery-runtime-BeY4EUPp.js +11 -0
  70. package/dist/{pi-tools.before-tool-call.runtime-BuLxSyx9.js → pi-tools.before-tool-call.runtime-Cwab_5W1.js} +9 -9
  71. package/dist/plugin-sdk/index.js +50 -50
  72. package/dist/plugin-sdk/mattermost.js +3 -3
  73. package/dist/plugin-sdk/signal.js +2 -2
  74. package/dist/plugin-sdk/zalo.js +2 -2
  75. package/dist/{plugins-CWkRQYDj.js → plugins-4Rj4OjLY.js} +11 -11
  76. package/dist/{proxy-env-Cq5gdrbj.js → proxy-env-DlmzDx8x.js} +1 -1
  77. package/dist/{proxy-fetch-CCjEYbFm.js → proxy-fetch-B2pEfjbR.js} +1 -1
  78. package/dist/{pw-ai-Cl1Lc7RC.js → pw-ai-DNMjFMqH.js} +14 -14
  79. package/dist/{qmd-manager-BsYsO9Ii.js → qmd-manager-BtIKUaO9.js} +10 -10
  80. package/dist/{query-expansion-DtLc3wjL.js → query-expansion-CX-1fS52.js} +6 -6
  81. package/dist/{plugin-sdk/redact-DjVX-1N3.js → redact-COik8ET1.js} +1 -1
  82. package/dist/{run-with-concurrency-D_ZpbgEG.js → run-with-concurrency-BgYfgkXT.js} +4 -4
  83. package/dist/runtime-whatsapp-login.runtime-DUb55byQ.js +13 -0
  84. package/dist/runtime-whatsapp-outbound.runtime-Bii_xSfI.js +22 -0
  85. package/dist/{send-Dx2RkUOZ.js → send-6lz6rNVP.js} +6 -6
  86. package/dist/{send-vmONuVgL.js → send-BHTiZcH3.js} +26 -26
  87. package/dist/{send-Bj776ESJ.js → send-L7gRiwyd.js} +7 -7
  88. package/dist/{send-DcxmcFi_.js → send-PE6cwoTe.js} +8 -8
  89. package/dist/{send-BQERFNyo.js → send-dfu6_rgf.js} +5 -5
  90. package/dist/{session-A4QhBRvH.js → session-D8ImowSs.js} +8 -8
  91. package/dist/{skill-commands-CMzBZKG2.js → skill-commands-DNqJ-kwn.js} +9 -9
  92. package/dist/{skills-CE_iqvM5.js → skills-7ODkHQYp.js} +22 -22
  93. package/dist/slash-commands.runtime-CVw6566g.js +16 -0
  94. package/dist/slash-dispatch.runtime-B9Ygtzi4.js +56 -0
  95. package/dist/slash-skill-commands.runtime-DxZ4z5h6.js +20 -0
  96. package/dist/{store--eR1R_UX.js → store-D89wDcz9.js} +2 -2
  97. package/dist/subagent-registry-runtime-DL1Wv7nA.js +56 -0
  98. package/dist/{subsystem-Di1z8l0Z.js → subsystem-B45WV3qB.js} +14 -14
  99. package/dist/{tables-d739Y1xW.js → tables-mE4cJBN2.js} +1 -1
  100. package/dist/{plugin-sdk/target-errors-Blia4S69.js → target-errors-mnlwhAjP.js} +2 -2
  101. package/dist/{thinking-DXYisHiZ.js → thinking-BeGmb5k6.js} +7 -7
  102. package/dist/{tokens-DxnY9ui_.js → tokens-q32vI39c.js} +1 -1
  103. package/dist/{tool-images-2cBx1W8h.js → tool-images-RZdHiZcG.js} +2 -2
  104. package/dist/{web-CzWRVmFt.js → web-Btj-e8kN.js} +55 -55
  105. package/dist/{whatsapp-actions-iEArE_Ez.js → whatsapp-actions-BHbJJyqw.js} +21 -21
  106. package/dist/{workspace-CUVC6GX1.js → workspace-U-DyR64O.js} +20 -20
  107. package/package.json +7 -5
  108. package/scripts/create-instance.sh +66 -27
  109. package/scripts/install-maca.sh +1 -1
  110. package/scripts/npm_publish.sh +5 -1
  111. package/ui/index.html +16 -0
  112. package/ui/node_modules/.bin/jiti +21 -0
  113. package/ui/node_modules/.bin/lessc +21 -0
  114. package/ui/node_modules/.bin/marked +21 -0
  115. package/ui/node_modules/.bin/playwright +21 -0
  116. package/ui/node_modules/.bin/sass +21 -0
  117. package/ui/node_modules/.bin/tsx +21 -0
  118. package/ui/node_modules/.bin/vite +21 -0
  119. package/ui/node_modules/.bin/vitest +21 -0
  120. package/ui/node_modules/.bin/yaml +21 -0
  121. package/ui/package.json +27 -0
  122. package/ui/public/apple-touch-icon.png +0 -0
  123. package/ui/public/favicon-32.png +0 -0
  124. package/ui/public/favicon.ico +0 -0
  125. package/ui/public/favicon.svg +22 -0
  126. package/ui/src/css.d.ts +1 -0
  127. package/ui/src/i18n/index.ts +3 -0
  128. package/ui/src/i18n/lib/lit-controller.ts +22 -0
  129. package/ui/src/i18n/lib/registry.ts +64 -0
  130. package/ui/src/i18n/lib/translate.ts +123 -0
  131. package/ui/src/i18n/lib/types.ts +9 -0
  132. package/ui/src/i18n/locales/de.ts +129 -0
  133. package/ui/src/i18n/locales/en.ts +337 -0
  134. package/ui/src/i18n/locales/pt-BR.ts +128 -0
  135. package/ui/src/i18n/locales/zh-CN.ts +330 -0
  136. package/ui/src/i18n/locales/zh-TW.ts +125 -0
  137. package/ui/src/i18n/test/translate.test.ts +56 -0
  138. package/ui/src/main.ts +2 -0
  139. package/ui/src/styles/base.css +385 -0
  140. package/ui/src/styles/chat/grouped.css +300 -0
  141. package/ui/src/styles/chat/layout.css +481 -0
  142. package/ui/src/styles/chat/sidebar.css +117 -0
  143. package/ui/src/styles/chat/text.css +146 -0
  144. package/ui/src/styles/chat/tool-cards.css +202 -0
  145. package/ui/src/styles/chat.css +5 -0
  146. package/ui/src/styles/components.css +2612 -0
  147. package/ui/src/styles/config.css +1658 -0
  148. package/ui/src/styles/layout.css +621 -0
  149. package/ui/src/styles/layout.mobile.css +374 -0
  150. package/ui/src/styles.css +5 -0
  151. package/ui/src/ui/__screenshots__/config-form.browser.test.ts/config-form-renderer-flags-unsupported-unions-1.png +0 -0
  152. package/ui/src/ui/__screenshots__/config-form.browser.test.ts/config-form-renderer-renders-inputs-and-patches-values-1.png +0 -0
  153. package/ui/src/ui/__screenshots__/config-form.browser.test.ts/config-form-renderer-renders-union-literals-as-select-options-1.png +0 -0
  154. package/ui/src/ui/__screenshots__/navigation.browser.test.ts/control-UI-routing-auto-scrolls-chat-history-to-the-latest-message-1.png +0 -0
  155. package/ui/src/ui/app-channels.ts +279 -0
  156. package/ui/src/ui/app-chat.ts +266 -0
  157. package/ui/src/ui/app-defaults.ts +50 -0
  158. package/ui/src/ui/app-events.ts +5 -0
  159. package/ui/src/ui/app-gateway.node.test.ts +229 -0
  160. package/ui/src/ui/app-gateway.ts +349 -0
  161. package/ui/src/ui/app-lifecycle.node.test.ts +44 -0
  162. package/ui/src/ui/app-lifecycle.ts +109 -0
  163. package/ui/src/ui/app-polling.ts +69 -0
  164. package/ui/src/ui/app-render-usage-tab.ts +273 -0
  165. package/ui/src/ui/app-render.helpers.node.test.ts +286 -0
  166. package/ui/src/ui/app-render.helpers.ts +574 -0
  167. package/ui/src/ui/app-render.ts +1168 -0
  168. package/ui/src/ui/app-scroll.test.ts +275 -0
  169. package/ui/src/ui/app-scroll.ts +179 -0
  170. package/ui/src/ui/app-settings.test.ts +70 -0
  171. package/ui/src/ui/app-settings.ts +440 -0
  172. package/ui/src/ui/app-tool-stream.node.test.ts +139 -0
  173. package/ui/src/ui/app-tool-stream.ts +455 -0
  174. package/ui/src/ui/app-view-state.ts +321 -0
  175. package/ui/src/ui/app.ts +621 -0
  176. package/ui/src/ui/assistant-identity.ts +23 -0
  177. package/ui/src/ui/chat/constants.ts +12 -0
  178. package/ui/src/ui/chat/copy-as-markdown.ts +97 -0
  179. package/ui/src/ui/chat/grouped-render.ts +287 -0
  180. package/ui/src/ui/chat/message-extract.test.ts +64 -0
  181. package/ui/src/ui/chat/message-extract.ts +122 -0
  182. package/ui/src/ui/chat/message-normalizer.test.ts +179 -0
  183. package/ui/src/ui/chat/message-normalizer.ts +101 -0
  184. package/ui/src/ui/chat/tool-cards.ts +156 -0
  185. package/ui/src/ui/chat/tool-helpers.test.ts +141 -0
  186. package/ui/src/ui/chat/tool-helpers.ts +37 -0
  187. package/ui/src/ui/chat-event-reload.test.ts +47 -0
  188. package/ui/src/ui/chat-event-reload.ts +16 -0
  189. package/ui/src/ui/chat-markdown.browser.test.ts +37 -0
  190. package/ui/src/ui/components/resizable-divider.ts +110 -0
  191. package/ui/src/ui/config-form.browser.test.ts +443 -0
  192. package/ui/src/ui/controllers/agent-files.ts +126 -0
  193. package/ui/src/ui/controllers/agent-identity.ts +59 -0
  194. package/ui/src/ui/controllers/agent-skills.ts +33 -0
  195. package/ui/src/ui/controllers/agents.test.ts +61 -0
  196. package/ui/src/ui/controllers/agents.ts +64 -0
  197. package/ui/src/ui/controllers/assistant-identity.ts +34 -0
  198. package/ui/src/ui/controllers/channels.ts +94 -0
  199. package/ui/src/ui/controllers/channels.types.ts +15 -0
  200. package/ui/src/ui/controllers/chat.test.ts +568 -0
  201. package/ui/src/ui/controllers/chat.ts +318 -0
  202. package/ui/src/ui/controllers/config/form-coerce.ts +160 -0
  203. package/ui/src/ui/controllers/config/form-utils.node.test.ts +455 -0
  204. package/ui/src/ui/controllers/config/form-utils.ts +90 -0
  205. package/ui/src/ui/controllers/config.test.ts +289 -0
  206. package/ui/src/ui/controllers/config.ts +219 -0
  207. package/ui/src/ui/controllers/control-ui-bootstrap.test.ts +82 -0
  208. package/ui/src/ui/controllers/control-ui-bootstrap.ts +49 -0
  209. package/ui/src/ui/controllers/cron-filters.test.ts +81 -0
  210. package/ui/src/ui/controllers/cron.test.ts +1070 -0
  211. package/ui/src/ui/controllers/cron.ts +921 -0
  212. package/ui/src/ui/controllers/debug.ts +60 -0
  213. package/ui/src/ui/controllers/devices.ts +159 -0
  214. package/ui/src/ui/controllers/exec-approval.ts +100 -0
  215. package/ui/src/ui/controllers/exec-approvals.ts +170 -0
  216. package/ui/src/ui/controllers/logs.ts +147 -0
  217. package/ui/src/ui/controllers/nodes.ts +32 -0
  218. package/ui/src/ui/controllers/presence.ts +37 -0
  219. package/ui/src/ui/controllers/sessions.test.ts +104 -0
  220. package/ui/src/ui/controllers/sessions.ts +127 -0
  221. package/ui/src/ui/controllers/skills.ts +157 -0
  222. package/ui/src/ui/controllers/usage.node.test.ts +181 -0
  223. package/ui/src/ui/controllers/usage.ts +315 -0
  224. package/ui/src/ui/data/moonshot-kimi-k2.ts +45 -0
  225. package/ui/src/ui/device-auth.ts +73 -0
  226. package/ui/src/ui/device-identity.ts +112 -0
  227. package/ui/src/ui/external-link.test.ts +18 -0
  228. package/ui/src/ui/external-link.ts +19 -0
  229. package/ui/src/ui/focus-mode.browser.test.ts +39 -0
  230. package/ui/src/ui/format.test.ts +101 -0
  231. package/ui/src/ui/format.ts +60 -0
  232. package/ui/src/ui/gateway.ts +360 -0
  233. package/ui/src/ui/icons.ts +256 -0
  234. package/ui/src/ui/markdown.test.ts +85 -0
  235. package/ui/src/ui/markdown.ts +139 -0
  236. package/ui/src/ui/navigation.browser.test.ts +188 -0
  237. package/ui/src/ui/navigation.test.ts +189 -0
  238. package/ui/src/ui/navigation.ts +165 -0
  239. package/ui/src/ui/open-external-url.test.ts +108 -0
  240. package/ui/src/ui/open-external-url.ts +73 -0
  241. package/ui/src/ui/presenter.ts +85 -0
  242. package/ui/src/ui/storage.node.test.ts +63 -0
  243. package/ui/src/ui/storage.ts +99 -0
  244. package/ui/src/ui/test-helpers/app-mount.ts +27 -0
  245. package/ui/src/ui/text-direction.test.ts +24 -0
  246. package/ui/src/ui/text-direction.ts +30 -0
  247. package/ui/src/ui/theme-transition.ts +109 -0
  248. package/ui/src/ui/theme.ts +16 -0
  249. package/ui/src/ui/tool-display.ts +159 -0
  250. package/ui/src/ui/types/chat-types.ts +44 -0
  251. package/ui/src/ui/types.ts +627 -0
  252. package/ui/src/ui/ui-types.ts +54 -0
  253. package/ui/src/ui/usage-helpers.node.test.ts +43 -0
  254. package/ui/src/ui/usage-helpers.ts +321 -0
  255. package/ui/src/ui/usage-types.ts +22 -0
  256. package/ui/src/ui/uuid.test.ts +41 -0
  257. package/ui/src/ui/uuid.ts +57 -0
  258. package/ui/src/ui/views/agents-panels-status-files.ts +461 -0
  259. package/ui/src/ui/views/agents-panels-tools-skills.browser.test.ts +102 -0
  260. package/ui/src/ui/views/agents-panels-tools-skills.ts +537 -0
  261. package/ui/src/ui/views/agents-utils.test.ts +100 -0
  262. package/ui/src/ui/views/agents-utils.ts +502 -0
  263. package/ui/src/ui/views/agents.ts +499 -0
  264. package/ui/src/ui/views/channel-config-extras.ts +49 -0
  265. package/ui/src/ui/views/channels.config.ts +155 -0
  266. package/ui/src/ui/views/channels.discord.ts +65 -0
  267. package/ui/src/ui/views/channels.googlechat.ts +79 -0
  268. package/ui/src/ui/views/channels.imessage.ts +65 -0
  269. package/ui/src/ui/views/channels.nostr-profile-form.ts +321 -0
  270. package/ui/src/ui/views/channels.nostr.ts +237 -0
  271. package/ui/src/ui/views/channels.shared.ts +38 -0
  272. package/ui/src/ui/views/channels.signal.ts +69 -0
  273. package/ui/src/ui/views/channels.slack.ts +65 -0
  274. package/ui/src/ui/views/channels.telegram.ts +120 -0
  275. package/ui/src/ui/views/channels.ts +325 -0
  276. package/ui/src/ui/views/channels.types.ts +62 -0
  277. package/ui/src/ui/views/channels.whatsapp.ts +118 -0
  278. package/ui/src/ui/views/chat-image-open.browser.test.ts +70 -0
  279. package/ui/src/ui/views/chat.test.ts +227 -0
  280. package/ui/src/ui/views/chat.ts +616 -0
  281. package/ui/src/ui/views/config-form.analyze.ts +267 -0
  282. package/ui/src/ui/views/config-form.node.ts +1073 -0
  283. package/ui/src/ui/views/config-form.render.ts +478 -0
  284. package/ui/src/ui/views/config-form.search.node.test.ts +69 -0
  285. package/ui/src/ui/views/config-form.shared.ts +96 -0
  286. package/ui/src/ui/views/config-form.ts +4 -0
  287. package/ui/src/ui/views/config-search.node.test.ts +50 -0
  288. package/ui/src/ui/views/config-search.ts +92 -0
  289. package/ui/src/ui/views/config.browser.test.ts +233 -0
  290. package/ui/src/ui/views/config.ts +820 -0
  291. package/ui/src/ui/views/cron.test.ts +741 -0
  292. package/ui/src/ui/views/cron.ts +1758 -0
  293. package/ui/src/ui/views/debug.ts +151 -0
  294. package/ui/src/ui/views/exec-approval.ts +89 -0
  295. package/ui/src/ui/views/gateway-url-confirmation.ts +40 -0
  296. package/ui/src/ui/views/instances.ts +89 -0
  297. package/ui/src/ui/views/logs.ts +155 -0
  298. package/ui/src/ui/views/markdown-sidebar.ts +40 -0
  299. package/ui/src/ui/views/nodes-exec-approvals.ts +617 -0
  300. package/ui/src/ui/views/nodes-shared.ts +67 -0
  301. package/ui/src/ui/views/nodes.ts +485 -0
  302. package/ui/src/ui/views/overview-hints.ts +16 -0
  303. package/ui/src/ui/views/overview.node.test.ts +39 -0
  304. package/ui/src/ui/views/overview.ts +361 -0
  305. package/ui/src/ui/views/sessions.test.ts +81 -0
  306. package/ui/src/ui/views/sessions.ts +321 -0
  307. package/ui/src/ui/views/skills-grouping.ts +40 -0
  308. package/ui/src/ui/views/skills-shared.ts +52 -0
  309. package/ui/src/ui/views/skills.ts +192 -0
  310. package/ui/src/ui/views/usage-metrics.ts +578 -0
  311. package/ui/src/ui/views/usage-query.ts +277 -0
  312. package/ui/src/ui/views/usage-render-details.test.ts +136 -0
  313. package/ui/src/ui/views/usage-render-details.ts +1083 -0
  314. package/ui/src/ui/views/usage-render-overview.ts +796 -0
  315. package/ui/src/ui/views/usage-styles/usageStyles-part1.ts +701 -0
  316. package/ui/src/ui/views/usage-styles/usageStyles-part2.ts +702 -0
  317. package/ui/src/ui/views/usage-styles/usageStyles-part3.ts +551 -0
  318. package/ui/src/ui/views/usage.ts +836 -0
  319. package/ui/src/ui/views/usageStyles.ts +5 -0
  320. package/ui/src/ui/views/usageTypes.ts +105 -0
  321. package/ui/vite.config.ts +43 -0
  322. package/ui/vitest.config.ts +15 -0
  323. package/ui/vitest.node.config.ts +10 -0
  324. package/dist/deliver-runtime-P-G3bPjW.js +0 -36
  325. package/dist/deps-send-discord.runtime-DnbhTFX9.js +0 -26
  326. package/dist/deps-send-imessage.runtime-BOiQ6mDx.js +0 -25
  327. package/dist/deps-send-signal.runtime-CTcl388M.js +0 -24
  328. package/dist/deps-send-slack.runtime-CCqBz4Kg.js +0 -22
  329. package/dist/deps-send-telegram.runtime-DGSKTCpH.js +0 -27
  330. package/dist/deps-send-whatsapp.runtime-CJkTHkah.js +0 -60
  331. package/dist/image-runtime-CVv2ra9J.js +0 -29
  332. package/dist/manager-runtime-BN6VevdC.js +0 -18
  333. package/dist/pi-model-discovery-BGgOlX8N.js +0 -134
  334. package/dist/pi-model-discovery-runtime-Bwmi4Ev8.js +0 -11
  335. package/dist/plugin-sdk/accounts-CJWOBzwB.js +0 -35
  336. package/dist/plugin-sdk/accounts-DP1-L-QS.js +0 -288
  337. package/dist/plugin-sdk/accounts-DZhWlEg3.js +0 -46
  338. package/dist/plugin-sdk/active-listener-B_sLJTXM.js +0 -50
  339. package/dist/plugin-sdk/api-key-rotation-BRE4X2tf.js +0 -181
  340. package/dist/plugin-sdk/audio-preflight-DGEUDxxR.js +0 -69
  341. package/dist/plugin-sdk/audio-transcription-runner-DkoPNPYt.js +0 -2176
  342. package/dist/plugin-sdk/audit-membership-runtime-DSBHHw7o.js +0 -58
  343. package/dist/plugin-sdk/channel-activity-F3d0yUwy.js +0 -94
  344. package/dist/plugin-sdk/channel-web-QF7EpjeP.js +0 -2256
  345. package/dist/plugin-sdk/chrome-BXoCyCkY.js +0 -2415
  346. package/dist/plugin-sdk/commands-registry-t7cXBTfN.js +0 -1125
  347. package/dist/plugin-sdk/config-BkEnz2Po.js +0 -17913
  348. package/dist/plugin-sdk/deliver-B6AG_l67.js +0 -1694
  349. package/dist/plugin-sdk/deliver-runtime-D585kJZc.js +0 -32
  350. package/dist/plugin-sdk/deps-send-discord.runtime-a_OKY2js.js +0 -23
  351. package/dist/plugin-sdk/deps-send-imessage.runtime-Baxy9TD4.js +0 -22
  352. package/dist/plugin-sdk/deps-send-signal.runtime-BwXoCrFl.js +0 -21
  353. package/dist/plugin-sdk/deps-send-slack.runtime-CLmKjgso.js +0 -19
  354. package/dist/plugin-sdk/deps-send-telegram.runtime-BKfdBKnZ.js +0 -24
  355. package/dist/plugin-sdk/deps-send-whatsapp.runtime-BOTwkbx_.js +0 -57
  356. package/dist/plugin-sdk/diagnostic-CsP-lEkI.js +0 -319
  357. package/dist/plugin-sdk/errors-DaiAM-yU.js +0 -54
  358. package/dist/plugin-sdk/fetch-guard-DETCcJzQ.js +0 -156
  359. package/dist/plugin-sdk/fs-safe-B8y811FR.js +0 -352
  360. package/dist/plugin-sdk/image-DjTEkYZE.js +0 -2310
  361. package/dist/plugin-sdk/image-ops-BSiMpAw4.js +0 -584
  362. package/dist/plugin-sdk/image-runtime-6xPp8m5a.js +0 -25
  363. package/dist/plugin-sdk/ir-DQ7_HbvK.js +0 -1296
  364. package/dist/plugin-sdk/local-roots-BUP4YBmR.js +0 -186
  365. package/dist/plugin-sdk/logger-CZY9KIoY.js +0 -1163
  366. package/dist/plugin-sdk/login-BxEKLlCo.js +0 -57
  367. package/dist/plugin-sdk/login-qr-BQIpMPr9.js +0 -320
  368. package/dist/plugin-sdk/manager-I6KbPihW.js +0 -3917
  369. package/dist/plugin-sdk/manager-runtime-CFfYYWIQ.js +0 -15
  370. package/dist/plugin-sdk/outbound-NS6UHnB6.js +0 -212
  371. package/dist/plugin-sdk/outbound-attachment-Dy6fyf6H.js +0 -19
  372. package/dist/plugin-sdk/path-alias-guards-DBjLbIX_.js +0 -43
  373. package/dist/plugin-sdk/paths-vTM3Lh3X.js +0 -166
  374. package/dist/plugin-sdk/pi-embedded-helpers-1R1gu7eX.js +0 -9627
  375. package/dist/plugin-sdk/pi-model-discovery-runtime-Do9o-dUd.js +0 -8
  376. package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-D4sFsIks.js +0 -354
  377. package/dist/plugin-sdk/plugins-DeBZB9l_.js +0 -864
  378. package/dist/plugin-sdk/proxy-fetch-ChxOhWF4.js +0 -38
  379. package/dist/plugin-sdk/pw-ai-DEOmCSSC.js +0 -1938
  380. package/dist/plugin-sdk/qmd-manager-HyYKoEch.js +0 -1448
  381. package/dist/plugin-sdk/query-expansion-CeyKUeDW.js +0 -1011
  382. package/dist/plugin-sdk/reply-DAo_Jt8K.js +0 -97916
  383. package/dist/plugin-sdk/resolve-outbound-target-B42qgQS9.js +0 -40
  384. package/dist/plugin-sdk/run-with-concurrency-Bt_ks0Qa.js +0 -1994
  385. package/dist/plugin-sdk/runtime-whatsapp-login.runtime-B6W989eF.js +0 -10
  386. package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-c_GDFy37.js +0 -19
  387. package/dist/plugin-sdk/send-CQpMudwO.js +0 -2587
  388. package/dist/plugin-sdk/send-DQHLzVyO.js +0 -414
  389. package/dist/plugin-sdk/send-DTB24bEF.js +0 -3135
  390. package/dist/plugin-sdk/send-DfHadjZ_.js +0 -503
  391. package/dist/plugin-sdk/send-XXlW2iny.js +0 -540
  392. package/dist/plugin-sdk/session-6TF6MyaC.js +0 -169
  393. package/dist/plugin-sdk/skill-commands-CkGeFUMl.js +0 -342
  394. package/dist/plugin-sdk/skills-CBkHBYPq.js +0 -1428
  395. package/dist/plugin-sdk/slash-commands.runtime-CxliuGaP.js +0 -13
  396. package/dist/plugin-sdk/slash-dispatch.runtime-DFaeYlJQ.js +0 -52
  397. package/dist/plugin-sdk/slash-skill-commands.runtime-0M0OLCxq.js +0 -16
  398. package/dist/plugin-sdk/ssrf-cFtplYtS.js +0 -202
  399. package/dist/plugin-sdk/store-5nyxY3WU.js +0 -81
  400. package/dist/plugin-sdk/subagent-registry-runtime-DCtmDwna.js +0 -52
  401. package/dist/plugin-sdk/tables-C47P4GTN.js +0 -55
  402. package/dist/plugin-sdk/thinking-Bo2eosVa.js +0 -1206
  403. package/dist/plugin-sdk/tokens-DgNRBwIg.js +0 -52
  404. package/dist/plugin-sdk/tool-images-Gk_-0y2N.js +0 -274
  405. package/dist/plugin-sdk/web-CVxZbXyH.js +0 -56
  406. package/dist/plugin-sdk/whatsapp-actions-Bw0H9g-n.js +0 -80
  407. package/dist/redact-ClbcYG1J.js +0 -319
  408. package/dist/runtime-whatsapp-login.runtime-IeylZEl4.js +0 -13
  409. package/dist/runtime-whatsapp-outbound.runtime-ClBRuLsq.js +0 -22
  410. package/dist/slash-commands.runtime-Cpn2tYW4.js +0 -16
  411. package/dist/slash-dispatch.runtime-DoBAQBU5.js +0 -56
  412. package/dist/slash-skill-commands.runtime-DKMvvdDW.js +0 -20
  413. package/dist/subagent-registry-runtime-ppWS3tVu.js +0 -56
  414. package/dist/target-errors-CBI2Ga0y.js +0 -195
@@ -0,0 +1,318 @@
1
+ import { extractText } from "../chat/message-extract.ts";
2
+ import type { GatewayBrowserClient } from "../gateway.ts";
3
+ import type { ChatAttachment } from "../ui-types.ts";
4
+ import { generateUUID } from "../uuid.ts";
5
+
6
+ const SILENT_REPLY_PATTERN = /^\s*NO_REPLY\s*$/;
7
+
8
+ function isSilentReplyStream(text: string): boolean {
9
+ return SILENT_REPLY_PATTERN.test(text);
10
+ }
11
+ /** Client-side defense-in-depth: detect assistant messages whose text is purely NO_REPLY. */
12
+ function isAssistantSilentReply(message: unknown): boolean {
13
+ if (!message || typeof message !== "object") {
14
+ return false;
15
+ }
16
+ const entry = message as Record<string, unknown>;
17
+ const role = typeof entry.role === "string" ? entry.role.toLowerCase() : "";
18
+ if (role !== "assistant") {
19
+ return false;
20
+ }
21
+ // entry.text takes precedence — matches gateway extractAssistantTextForSilentCheck
22
+ if (typeof entry.text === "string") {
23
+ return isSilentReplyStream(entry.text);
24
+ }
25
+ const text = extractText(message);
26
+ return typeof text === "string" && isSilentReplyStream(text);
27
+ }
28
+
29
+ export type ChatState = {
30
+ client: GatewayBrowserClient | null;
31
+ connected: boolean;
32
+ sessionKey: string;
33
+ chatLoading: boolean;
34
+ chatMessages: unknown[];
35
+ chatThinkingLevel: string | null;
36
+ chatSending: boolean;
37
+ chatMessage: string;
38
+ chatAttachments: ChatAttachment[];
39
+ chatRunId: string | null;
40
+ chatStream: string | null;
41
+ chatStreamStartedAt: number | null;
42
+ lastError: string | null;
43
+ };
44
+
45
+ export type ChatEventPayload = {
46
+ runId: string;
47
+ sessionKey: string;
48
+ state: "delta" | "final" | "aborted" | "error";
49
+ message?: unknown;
50
+ errorMessage?: string;
51
+ };
52
+
53
+ export async function loadChatHistory(state: ChatState) {
54
+ if (!state.client || !state.connected) {
55
+ return;
56
+ }
57
+ state.chatLoading = true;
58
+ state.lastError = null;
59
+ try {
60
+ const res = await state.client.request<{ messages?: Array<unknown>; thinkingLevel?: string }>(
61
+ "chat.history",
62
+ {
63
+ sessionKey: state.sessionKey,
64
+ limit: 200,
65
+ },
66
+ );
67
+ const messages = Array.isArray(res.messages) ? res.messages : [];
68
+ state.chatMessages = messages.filter((message) => !isAssistantSilentReply(message));
69
+ state.chatThinkingLevel = res.thinkingLevel ?? null;
70
+ } catch (err) {
71
+ state.lastError = String(err);
72
+ } finally {
73
+ state.chatLoading = false;
74
+ }
75
+ }
76
+
77
+ function dataUrlToBase64(dataUrl: string): { content: string; mimeType: string } | null {
78
+ const match = /^data:([^;]+);base64,(.+)$/.exec(dataUrl);
79
+ if (!match) {
80
+ return null;
81
+ }
82
+ return { mimeType: match[1], content: match[2] };
83
+ }
84
+
85
+ type AssistantMessageNormalizationOptions = {
86
+ roleRequirement: "required" | "optional";
87
+ roleCaseSensitive?: boolean;
88
+ requireContentArray?: boolean;
89
+ allowTextField?: boolean;
90
+ };
91
+
92
+ function normalizeAssistantMessage(
93
+ message: unknown,
94
+ options: AssistantMessageNormalizationOptions,
95
+ ): Record<string, unknown> | null {
96
+ if (!message || typeof message !== "object") {
97
+ return null;
98
+ }
99
+ const candidate = message as Record<string, unknown>;
100
+ const roleValue = candidate.role;
101
+ if (typeof roleValue === "string") {
102
+ const role = options.roleCaseSensitive ? roleValue : roleValue.toLowerCase();
103
+ if (role !== "assistant") {
104
+ return null;
105
+ }
106
+ } else if (options.roleRequirement === "required") {
107
+ return null;
108
+ }
109
+
110
+ if (options.requireContentArray) {
111
+ return Array.isArray(candidate.content) ? candidate : null;
112
+ }
113
+ if (!("content" in candidate) && !(options.allowTextField && "text" in candidate)) {
114
+ return null;
115
+ }
116
+ return candidate;
117
+ }
118
+
119
+ function normalizeAbortedAssistantMessage(message: unknown): Record<string, unknown> | null {
120
+ return normalizeAssistantMessage(message, {
121
+ roleRequirement: "required",
122
+ roleCaseSensitive: true,
123
+ requireContentArray: true,
124
+ });
125
+ }
126
+
127
+ function normalizeFinalAssistantMessage(message: unknown): Record<string, unknown> | null {
128
+ return normalizeAssistantMessage(message, {
129
+ roleRequirement: "optional",
130
+ allowTextField: true,
131
+ });
132
+ }
133
+
134
+ export async function sendChatMessage(
135
+ state: ChatState,
136
+ message: string,
137
+ attachments?: ChatAttachment[],
138
+ ): Promise<string | null> {
139
+ if (!state.client || !state.connected) {
140
+ return null;
141
+ }
142
+ const msg = message.trim();
143
+ const hasAttachments = attachments && attachments.length > 0;
144
+ if (!msg && !hasAttachments) {
145
+ return null;
146
+ }
147
+
148
+ const now = Date.now();
149
+
150
+ // Build user message content blocks
151
+ const contentBlocks: Array<{ type: string; text?: string; source?: unknown }> = [];
152
+ if (msg) {
153
+ contentBlocks.push({ type: "text", text: msg });
154
+ }
155
+ // Add image previews to the message for display
156
+ if (hasAttachments) {
157
+ for (const att of attachments) {
158
+ contentBlocks.push({
159
+ type: "image",
160
+ source: { type: "base64", media_type: att.mimeType, data: att.dataUrl },
161
+ });
162
+ }
163
+ }
164
+
165
+ state.chatMessages = [
166
+ ...state.chatMessages,
167
+ {
168
+ role: "user",
169
+ content: contentBlocks,
170
+ timestamp: now,
171
+ },
172
+ ];
173
+
174
+ state.chatSending = true;
175
+ state.lastError = null;
176
+ const runId = generateUUID();
177
+ state.chatRunId = runId;
178
+ state.chatStream = "";
179
+ state.chatStreamStartedAt = now;
180
+
181
+ // Convert attachments to API format
182
+ const apiAttachments = hasAttachments
183
+ ? attachments
184
+ .map((att) => {
185
+ const parsed = dataUrlToBase64(att.dataUrl);
186
+ if (!parsed) {
187
+ return null;
188
+ }
189
+ return {
190
+ type: "image",
191
+ mimeType: parsed.mimeType,
192
+ content: parsed.content,
193
+ };
194
+ })
195
+ .filter((a): a is NonNullable<typeof a> => a !== null)
196
+ : undefined;
197
+
198
+ try {
199
+ await state.client.request("chat.send", {
200
+ sessionKey: state.sessionKey,
201
+ message: msg,
202
+ deliver: false,
203
+ idempotencyKey: runId,
204
+ attachments: apiAttachments,
205
+ });
206
+ return runId;
207
+ } catch (err) {
208
+ const error = String(err);
209
+ state.chatRunId = null;
210
+ state.chatStream = null;
211
+ state.chatStreamStartedAt = null;
212
+ state.lastError = error;
213
+ state.chatMessages = [
214
+ ...state.chatMessages,
215
+ {
216
+ role: "assistant",
217
+ content: [{ type: "text", text: "Error: " + error }],
218
+ timestamp: Date.now(),
219
+ },
220
+ ];
221
+ return null;
222
+ } finally {
223
+ state.chatSending = false;
224
+ }
225
+ }
226
+
227
+ export async function abortChatRun(state: ChatState): Promise<boolean> {
228
+ if (!state.client || !state.connected) {
229
+ return false;
230
+ }
231
+ const runId = state.chatRunId;
232
+ try {
233
+ await state.client.request(
234
+ "chat.abort",
235
+ runId ? { sessionKey: state.sessionKey, runId } : { sessionKey: state.sessionKey },
236
+ );
237
+ return true;
238
+ } catch (err) {
239
+ state.lastError = String(err);
240
+ return false;
241
+ }
242
+ }
243
+
244
+ export function handleChatEvent(state: ChatState, payload?: ChatEventPayload) {
245
+ if (!payload) {
246
+ return null;
247
+ }
248
+ if (payload.sessionKey !== state.sessionKey) {
249
+ return null;
250
+ }
251
+
252
+ // Final from another run (e.g. sub-agent announce): refresh history to show new message.
253
+ // See https://github.com/openclaw/openclaw/issues/1909
254
+ if (payload.runId && state.chatRunId && payload.runId !== state.chatRunId) {
255
+ if (payload.state === "final") {
256
+ const finalMessage = normalizeFinalAssistantMessage(payload.message);
257
+ if (finalMessage && !isAssistantSilentReply(finalMessage)) {
258
+ state.chatMessages = [...state.chatMessages, finalMessage];
259
+ return null;
260
+ }
261
+ return "final";
262
+ }
263
+ return null;
264
+ }
265
+
266
+ if (payload.state === "delta") {
267
+ const next = extractText(payload.message);
268
+ if (typeof next === "string" && !isSilentReplyStream(next)) {
269
+ const current = state.chatStream ?? "";
270
+ if (!current || next.length >= current.length) {
271
+ state.chatStream = next;
272
+ }
273
+ }
274
+ } else if (payload.state === "final") {
275
+ const finalMessage = normalizeFinalAssistantMessage(payload.message);
276
+ if (finalMessage && !isAssistantSilentReply(finalMessage)) {
277
+ state.chatMessages = [...state.chatMessages, finalMessage];
278
+ } else if (state.chatStream?.trim() && !isSilentReplyStream(state.chatStream)) {
279
+ state.chatMessages = [
280
+ ...state.chatMessages,
281
+ {
282
+ role: "assistant",
283
+ content: [{ type: "text", text: state.chatStream }],
284
+ timestamp: Date.now(),
285
+ },
286
+ ];
287
+ }
288
+ state.chatStream = null;
289
+ state.chatRunId = null;
290
+ state.chatStreamStartedAt = null;
291
+ } else if (payload.state === "aborted") {
292
+ const normalizedMessage = normalizeAbortedAssistantMessage(payload.message);
293
+ if (normalizedMessage && !isAssistantSilentReply(normalizedMessage)) {
294
+ state.chatMessages = [...state.chatMessages, normalizedMessage];
295
+ } else {
296
+ const streamedText = state.chatStream ?? "";
297
+ if (streamedText.trim() && !isSilentReplyStream(streamedText)) {
298
+ state.chatMessages = [
299
+ ...state.chatMessages,
300
+ {
301
+ role: "assistant",
302
+ content: [{ type: "text", text: streamedText }],
303
+ timestamp: Date.now(),
304
+ },
305
+ ];
306
+ }
307
+ }
308
+ state.chatStream = null;
309
+ state.chatRunId = null;
310
+ state.chatStreamStartedAt = null;
311
+ } else if (payload.state === "error") {
312
+ state.chatStream = null;
313
+ state.chatRunId = null;
314
+ state.chatStreamStartedAt = null;
315
+ state.lastError = payload.errorMessage ?? "chat error";
316
+ }
317
+ return payload.state;
318
+ }
@@ -0,0 +1,160 @@
1
+ import { schemaType, type JsonSchema } from "../../views/config-form.shared.ts";
2
+
3
+ function coerceNumberString(value: string, integer: boolean): number | undefined | string {
4
+ const trimmed = value.trim();
5
+ if (trimmed === "") {
6
+ return undefined;
7
+ }
8
+ const parsed = Number(trimmed);
9
+ if (!Number.isFinite(parsed)) {
10
+ return value;
11
+ }
12
+ if (integer && !Number.isInteger(parsed)) {
13
+ return value;
14
+ }
15
+ return parsed;
16
+ }
17
+
18
+ function coerceBooleanString(value: string): boolean | string {
19
+ const trimmed = value.trim();
20
+ if (trimmed === "true") {
21
+ return true;
22
+ }
23
+ if (trimmed === "false") {
24
+ return false;
25
+ }
26
+ return value;
27
+ }
28
+
29
+ /**
30
+ * Walk a form value tree alongside its JSON Schema and coerce string values
31
+ * to their schema-defined types (number, boolean).
32
+ *
33
+ * HTML `<input>` elements always produce string `.value` properties. Even
34
+ * though the form rendering code converts values correctly for most paths,
35
+ * some interactions (map-field repopulation, re-renders, paste, etc.) can
36
+ * leak raw strings into the config form state. This utility acts as a
37
+ * safety net before serialization so that `config.set` always receives
38
+ * correctly typed JSON.
39
+ */
40
+ export function coerceFormValues(value: unknown, schema: JsonSchema): unknown {
41
+ if (value === null || value === undefined) {
42
+ return value;
43
+ }
44
+
45
+ if (schema.allOf && schema.allOf.length > 0) {
46
+ let next: unknown = value;
47
+ for (const segment of schema.allOf) {
48
+ next = coerceFormValues(next, segment);
49
+ }
50
+ return next;
51
+ }
52
+
53
+ const type = schemaType(schema);
54
+
55
+ // Handle anyOf/oneOf — try to match the value against a variant
56
+ if (schema.anyOf || schema.oneOf) {
57
+ const variants = (schema.anyOf ?? schema.oneOf ?? []).filter(
58
+ (v) => !(v.type === "null" || (Array.isArray(v.type) && v.type.includes("null"))),
59
+ );
60
+
61
+ if (variants.length === 1) {
62
+ return coerceFormValues(value, variants[0]);
63
+ }
64
+
65
+ // Try number/boolean coercion for string values
66
+ if (typeof value === "string") {
67
+ for (const variant of variants) {
68
+ const variantType = schemaType(variant);
69
+ if (variantType === "number" || variantType === "integer") {
70
+ const coerced = coerceNumberString(value, variantType === "integer");
71
+ if (coerced === undefined || typeof coerced === "number") {
72
+ return coerced;
73
+ }
74
+ }
75
+ if (variantType === "boolean") {
76
+ const coerced = coerceBooleanString(value);
77
+ if (typeof coerced === "boolean") {
78
+ return coerced;
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ // For non-string values (objects, arrays), try to recurse into matching variant
85
+ for (const variant of variants) {
86
+ const variantType = schemaType(variant);
87
+ if (variantType === "object" && typeof value === "object" && !Array.isArray(value)) {
88
+ return coerceFormValues(value, variant);
89
+ }
90
+ if (variantType === "array" && Array.isArray(value)) {
91
+ return coerceFormValues(value, variant);
92
+ }
93
+ }
94
+
95
+ return value;
96
+ }
97
+
98
+ if (type === "number" || type === "integer") {
99
+ if (typeof value === "string") {
100
+ const coerced = coerceNumberString(value, type === "integer");
101
+ if (coerced === undefined || typeof coerced === "number") {
102
+ return coerced;
103
+ }
104
+ }
105
+ return value;
106
+ }
107
+
108
+ if (type === "boolean") {
109
+ if (typeof value === "string") {
110
+ const coerced = coerceBooleanString(value);
111
+ if (typeof coerced === "boolean") {
112
+ return coerced;
113
+ }
114
+ }
115
+ return value;
116
+ }
117
+
118
+ if (type === "object") {
119
+ if (typeof value !== "object" || Array.isArray(value)) {
120
+ return value;
121
+ }
122
+ const obj = value as Record<string, unknown>;
123
+ const props = schema.properties ?? {};
124
+ const additional =
125
+ schema.additionalProperties && typeof schema.additionalProperties === "object"
126
+ ? schema.additionalProperties
127
+ : null;
128
+ const result: Record<string, unknown> = {};
129
+ for (const [key, val] of Object.entries(obj)) {
130
+ const propSchema = props[key] ?? additional;
131
+ const coerced = propSchema ? coerceFormValues(val, propSchema) : val;
132
+ // Omit undefined — "clear field = unset" for optional properties
133
+ if (coerced !== undefined) {
134
+ result[key] = coerced;
135
+ }
136
+ }
137
+ return result;
138
+ }
139
+
140
+ if (type === "array") {
141
+ if (!Array.isArray(value)) {
142
+ return value;
143
+ }
144
+ if (Array.isArray(schema.items)) {
145
+ // Tuple form: each index has its own schema
146
+ const tuple = schema.items;
147
+ return value.map((item, i) => {
148
+ const s = i < tuple.length ? tuple[i] : undefined;
149
+ return s ? coerceFormValues(item, s) : item;
150
+ });
151
+ }
152
+ const itemsSchema = schema.items;
153
+ if (!itemsSchema) {
154
+ return value;
155
+ }
156
+ return value.map((item) => coerceFormValues(item, itemsSchema)).filter((v) => v !== undefined);
157
+ }
158
+
159
+ return value;
160
+ }