@agent-native/core 0.98.0 → 0.98.2

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 (345) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +32 -0
  3. package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
  4. package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +1 -1
  5. package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
  6. package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +1 -1
  7. package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
  8. package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +1 -1
  9. package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
  10. package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +1 -1
  11. package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
  12. package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +1 -1
  13. package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
  14. package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +1 -1
  15. package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
  16. package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +1 -1
  17. package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
  18. package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +1 -1
  19. package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
  20. package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +1 -1
  21. package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
  22. package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +1 -1
  23. package/corpus/core/docs/content/pr-visual-recap.mdx +50 -1
  24. package/corpus/core/docs/content/template-plan.mdx +1 -1
  25. package/corpus/core/package.json +2 -2
  26. package/corpus/core/src/action-change-marker.ts +8 -1
  27. package/corpus/core/src/changelog/parse.ts +8 -3
  28. package/corpus/core/src/cli/plan-local.ts +43 -11
  29. package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -9
  30. package/corpus/core/src/cli/recap.ts +356 -4
  31. package/corpus/core/src/cli/skills-content/local-files.ts +17 -12
  32. package/corpus/core/src/client/AgentPanel.tsx +2 -3
  33. package/corpus/core/src/client/AssistantChat.tsx +83 -39
  34. package/corpus/core/src/client/analytics.ts +125 -14
  35. package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +16 -2
  36. package/corpus/core/src/client/chat-model-groups.ts +28 -0
  37. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +442 -85
  38. package/corpus/core/src/client/composer/TiptapComposer.tsx +46 -29
  39. package/corpus/core/src/client/composer/VoiceButton.tsx +2 -1
  40. package/corpus/core/src/client/composer/index.ts +5 -0
  41. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +1206 -67
  42. package/corpus/core/src/client/index.ts +10 -0
  43. package/corpus/core/src/client/progress/RunsTray.tsx +13 -1
  44. package/corpus/core/src/client/session-replay.ts +10 -0
  45. package/corpus/core/src/client/settings/DemoModeSection.tsx +4 -28
  46. package/corpus/core/src/client/settings/SecretsSection.tsx +387 -266
  47. package/corpus/core/src/client/settings/SettingsPanel.tsx +117 -38
  48. package/corpus/core/src/client/url-scrub.ts +13 -0
  49. package/corpus/core/src/client/use-action.ts +12 -0
  50. package/corpus/core/src/client/use-agent-chat-home-handoff.ts +8 -1
  51. package/corpus/core/src/client/use-agent-engine-configured.ts +17 -3
  52. package/corpus/core/src/client/use-db-sync.ts +84 -34
  53. package/corpus/core/src/client/use-demo-mode-status.ts +44 -0
  54. package/corpus/core/src/client/use-pausing-interval.ts +14 -4
  55. package/corpus/core/src/integrations/scope-store.ts +1 -1
  56. package/corpus/core/src/integrations/usage-budget-store.ts +1 -1
  57. package/corpus/core/src/localization/default-messages.ts +44 -1
  58. package/corpus/core/src/mcp-client/workspace-servers.ts +4 -4
  59. package/corpus/core/src/secrets/crypto.ts +28 -8
  60. package/corpus/core/src/server/action-change.ts +5 -1
  61. package/corpus/core/src/server/action-routes.ts +8 -0
  62. package/corpus/core/src/server/poll.ts +1 -0
  63. package/corpus/core/src/server/realtime-voice.ts +299 -13
  64. package/corpus/core/src/styles/agent-native.css +2 -2
  65. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  66. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  67. package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  68. package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  69. package/corpus/core/src/vite/client.ts +9 -1
  70. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +2 -2
  71. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +10 -5
  72. package/corpus/templates/analytics/AGENTS.md +17 -13
  73. package/corpus/templates/analytics/actions/navigate.ts +59 -5
  74. package/corpus/templates/analytics/actions/view-screen.ts +3 -6
  75. package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +20 -3
  76. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +20 -5
  77. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
  78. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -6
  79. package/corpus/templates/analytics/app/global.css +19 -20
  80. package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +156 -0
  81. package/corpus/templates/analytics/app/lib/provider-corpus-job-sync.ts +26 -0
  82. package/corpus/templates/analytics/app/pages/Settings.tsx +35 -341
  83. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +38 -7
  84. package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +1 -1
  85. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +3 -0
  86. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +333 -272
  87. package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +72 -17
  88. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +297 -108
  89. package/corpus/templates/analytics/app/root.tsx +28 -8
  90. package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +2 -1
  91. package/corpus/templates/analytics/changelog/2026-06-25-referrer-dashboard-panels-show-external-domains.md +2 -1
  92. package/corpus/templates/analytics/changelog/2026-07-06-mobile-chat-header-is-more-compact-and-the-menu-button-opens-navigation.md +1 -0
  93. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +1 -0
  94. package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +1 -0
  95. package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +1 -0
  96. package/corpus/templates/analytics/changelog/2026-07-11-analytics-no-longer-repeatedly-restarts-background-requests-.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-07-11-analytics-only-asks-for-replay-storage-when-you-enable-sessi.md +6 -0
  98. package/corpus/templates/analytics/changelog/2026-07-11-charts-now-show-their-loading-skeleton-while-refreshing.md +6 -0
  99. package/corpus/templates/analytics/changelog/2026-07-11-realtime-voice-now-shows-a-clear-connection-indicator-comple.md +6 -0
  100. package/corpus/templates/analytics/changelog/2026-07-11-replay-event-counts-stay-hidden-until-recordings-finish-load.md +6 -0
  101. package/corpus/templates/analytics/changelog/2026-07-11-replay-storage-key-mismatches-show-actionable-setup-guidance.md +6 -0
  102. package/corpus/templates/analytics/changelog/2026-07-11-replay-timelines-group-continuous-scrolling-and-dev-tools-co.md +6 -0
  103. package/corpus/templates/analytics/changelog/2026-07-11-session-filters-now-stay-compact-in-a-settings-menu-at-mediu.md +6 -0
  104. package/corpus/templates/analytics/changelog/2026-07-11-session-replay-console-errors-now-link-to-matching-issues-or.md +6 -0
  105. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-load-large-recordings-faster-and-surface-fai.md +6 -0
  106. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-preserve-recorded-styles-and-viewport-layout.md +6 -0
  107. package/corpus/templates/analytics/changelog/2026-07-11-session-replays-stay-centered-instead-of-clipping-wide-recor.md +6 -0
  108. package/corpus/templates/analytics/changelog/2026-07-12-daily-dashboard-emails-reliably-include-the-complete-dashboa.md +6 -0
  109. package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-charts-trend-upward.md +6 -0
  110. package/corpus/templates/analytics/package.json +1 -1
  111. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -303
  112. package/corpus/templates/analytics/server/handlers/session-replay.ts +57 -0
  113. package/corpus/templates/analytics/server/jobs/dashboard-report.ts +2 -0
  114. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -1
  115. package/corpus/templates/analytics/server/lib/dashboard-report.ts +17 -33
  116. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +16 -3
  117. package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +12 -0
  118. package/corpus/templates/analytics/server/lib/session-replay.ts +208 -2
  119. package/corpus/templates/analytics/server/plugins/onboarding.ts +7 -79
  120. package/corpus/templates/analytics/server/routes/api/session-replay/recordings/[recordingId]/chunks.get.ts +1 -0
  121. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +2 -2
  122. package/corpus/templates/assets/app/global.css +4 -4
  123. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +0 -1
  124. package/corpus/templates/assets/app/routes/library.tsx +0 -1
  125. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +2 -2
  126. package/corpus/templates/brain/app/global.css +5 -5
  127. package/corpus/templates/brain/app/root.tsx +0 -3
  128. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +2 -2
  129. package/corpus/templates/calendar/app/root.tsx +1 -0
  130. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +2 -2
  131. package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
  132. package/corpus/templates/clips/app/hooks/use-auto-title.ts +74 -8
  133. package/corpus/templates/clips/app/hooks/use-library.ts +12 -25
  134. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +20 -22
  135. package/corpus/templates/clips/changelog/2026-07-11-clips-no-longer-stay-stuck-on-preparing-clip-when-they-are-r.md +6 -0
  136. package/corpus/templates/clips/changelog/2026-07-11-generated-titles-no-longer-cause-continuous-background-refreshes.md +6 -0
  137. package/corpus/templates/clips/changelog/2026-07-11-s3-storage-setup-stays-collapsed-until-you-choose-it-as-the-.md +6 -0
  138. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +2 -2
  139. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +2 -2
  140. package/corpus/templates/content/app/hooks/use-comments.ts +0 -1
  141. package/corpus/templates/content/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
  142. package/corpus/templates/content/changelog/2026-07-12-the-left-sidebar-stays-fixed-horizontally-while-scrolling-on.md +6 -0
  143. package/corpus/templates/design/app/components/layout/Header.tsx +1 -1
  144. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +2 -2
  145. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -2
  146. package/corpus/templates/macros/app/root.tsx +0 -3
  147. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +2 -2
  148. package/corpus/templates/mail/app/hooks/use-compose-state.ts +1 -0
  149. package/corpus/templates/mail/app/root.tsx +1 -12
  150. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +2 -2
  151. package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +17 -12
  152. package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +17 -12
  153. package/corpus/templates/plan/actions/validate-local-plan-source.ts +4 -4
  154. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -1
  155. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +5 -2
  156. package/corpus/templates/plan/app/hooks/use-plans.ts +6 -13
  157. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +41 -0
  158. package/corpus/templates/plan/app/lib/plan-tracking.ts +3 -0
  159. package/corpus/templates/plan/app/pages/PlansPage.tsx +14 -36
  160. package/corpus/templates/plan/app/root.tsx +13 -3
  161. package/corpus/templates/plan/changelog/2026-07-11-plan-refreshes-only-when-content-changes.md +6 -0
  162. package/corpus/templates/plan/changelog/2026-07-12-local-plan-source-now-stays-on-device.md +6 -0
  163. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +4 -1
  164. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
  165. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
  166. package/corpus/templates/slides/app/context/DeckContext.tsx +1 -0
  167. package/corpus/templates/slides/app/hooks/use-slide-comments.ts +7 -31
  168. package/corpus/templates/slides/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
  169. package/dist/action-change-marker.d.ts +1 -0
  170. package/dist/action-change-marker.d.ts.map +1 -1
  171. package/dist/action-change-marker.js +7 -1
  172. package/dist/action-change-marker.js.map +1 -1
  173. package/dist/changelog/parse.d.ts +4 -2
  174. package/dist/changelog/parse.d.ts.map +1 -1
  175. package/dist/changelog/parse.js +5 -3
  176. package/dist/changelog/parse.js.map +1 -1
  177. package/dist/cli/plan-local.d.ts +6 -6
  178. package/dist/cli/plan-local.d.ts.map +1 -1
  179. package/dist/cli/plan-local.js +36 -7
  180. package/dist/cli/plan-local.js.map +1 -1
  181. package/dist/cli/pr-visual-recap-workflow.d.ts +2 -8
  182. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  183. package/dist/cli/pr-visual-recap-workflow.js +2 -8
  184. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  185. package/dist/cli/recap.d.ts +22 -1
  186. package/dist/cli/recap.d.ts.map +1 -1
  187. package/dist/cli/recap.js +286 -2
  188. package/dist/cli/recap.js.map +1 -1
  189. package/dist/cli/skills-content/local-files.d.ts +1 -1
  190. package/dist/cli/skills-content/local-files.d.ts.map +1 -1
  191. package/dist/cli/skills-content/local-files.js +17 -12
  192. package/dist/cli/skills-content/local-files.js.map +1 -1
  193. package/dist/client/AgentPanel.d.ts.map +1 -1
  194. package/dist/client/AgentPanel.js +2 -3
  195. package/dist/client/AgentPanel.js.map +1 -1
  196. package/dist/client/AssistantChat.d.ts +7 -0
  197. package/dist/client/AssistantChat.d.ts.map +1 -1
  198. package/dist/client/AssistantChat.js +62 -40
  199. package/dist/client/AssistantChat.js.map +1 -1
  200. package/dist/client/analytics.d.ts +8 -0
  201. package/dist/client/analytics.d.ts.map +1 -1
  202. package/dist/client/analytics.js +103 -13
  203. package/dist/client/analytics.js.map +1 -1
  204. package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
  205. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  206. package/dist/client/blocks/library/wireframe-kit.js +9 -2
  207. package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
  208. package/dist/client/chat-model-groups.d.ts.map +1 -1
  209. package/dist/client/chat-model-groups.js +24 -0
  210. package/dist/client/chat-model-groups.js.map +1 -1
  211. package/dist/client/composer/RealtimeVoiceMode.d.ts +40 -4
  212. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
  213. package/dist/client/composer/RealtimeVoiceMode.js +172 -42
  214. package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
  215. package/dist/client/composer/TiptapComposer.d.ts +4 -0
  216. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  217. package/dist/client/composer/TiptapComposer.js +47 -29
  218. package/dist/client/composer/TiptapComposer.js.map +1 -1
  219. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  220. package/dist/client/composer/VoiceButton.js +2 -2
  221. package/dist/client/composer/VoiceButton.js.map +1 -1
  222. package/dist/client/composer/index.d.ts +2 -2
  223. package/dist/client/composer/index.d.ts.map +1 -1
  224. package/dist/client/composer/index.js +1 -1
  225. package/dist/client/composer/index.js.map +1 -1
  226. package/dist/client/composer/useRealtimeVoiceMode.d.ts +100 -3
  227. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  228. package/dist/client/composer/useRealtimeVoiceMode.js +952 -51
  229. package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
  230. package/dist/client/index.d.ts +3 -2
  231. package/dist/client/index.d.ts.map +1 -1
  232. package/dist/client/index.js +3 -2
  233. package/dist/client/index.js.map +1 -1
  234. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  235. package/dist/client/progress/RunsTray.js +10 -1
  236. package/dist/client/progress/RunsTray.js.map +1 -1
  237. package/dist/client/session-replay.d.ts +2 -0
  238. package/dist/client/session-replay.d.ts.map +1 -1
  239. package/dist/client/session-replay.js +7 -0
  240. package/dist/client/session-replay.js.map +1 -1
  241. package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
  242. package/dist/client/settings/DemoModeSection.js +4 -23
  243. package/dist/client/settings/DemoModeSection.js.map +1 -1
  244. package/dist/client/settings/SecretsSection.d.ts +2 -3
  245. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  246. package/dist/client/settings/SecretsSection.js +46 -22
  247. package/dist/client/settings/SecretsSection.js.map +1 -1
  248. package/dist/client/settings/SettingsPanel.d.ts +9 -0
  249. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  250. package/dist/client/settings/SettingsPanel.js +46 -12
  251. package/dist/client/settings/SettingsPanel.js.map +1 -1
  252. package/dist/client/url-scrub.d.ts.map +1 -1
  253. package/dist/client/url-scrub.js +14 -0
  254. package/dist/client/url-scrub.js.map +1 -1
  255. package/dist/client/use-action.d.ts +2 -0
  256. package/dist/client/use-action.d.ts.map +1 -1
  257. package/dist/client/use-action.js +10 -0
  258. package/dist/client/use-action.js.map +1 -1
  259. package/dist/client/use-agent-chat-home-handoff.d.ts +2 -0
  260. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
  261. package/dist/client/use-agent-chat-home-handoff.js +7 -1
  262. package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
  263. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  264. package/dist/client/use-agent-engine-configured.js +17 -3
  265. package/dist/client/use-agent-engine-configured.js.map +1 -1
  266. package/dist/client/use-db-sync.d.ts +8 -2
  267. package/dist/client/use-db-sync.d.ts.map +1 -1
  268. package/dist/client/use-db-sync.js +57 -32
  269. package/dist/client/use-db-sync.js.map +1 -1
  270. package/dist/client/use-demo-mode-status.d.ts +12 -0
  271. package/dist/client/use-demo-mode-status.d.ts.map +1 -0
  272. package/dist/client/use-demo-mode-status.js +30 -0
  273. package/dist/client/use-demo-mode-status.js.map +1 -0
  274. package/dist/client/use-pausing-interval.d.ts.map +1 -1
  275. package/dist/client/use-pausing-interval.js +16 -4
  276. package/dist/client/use-pausing-interval.js.map +1 -1
  277. package/dist/collab/struct-routes.d.ts +1 -1
  278. package/dist/integrations/scope-store.js +1 -1
  279. package/dist/integrations/scope-store.js.map +1 -1
  280. package/dist/integrations/usage-budget-store.js +1 -1
  281. package/dist/integrations/usage-budget-store.js.map +1 -1
  282. package/dist/localization/default-messages.d.ts +41 -1
  283. package/dist/localization/default-messages.d.ts.map +1 -1
  284. package/dist/localization/default-messages.js +41 -1
  285. package/dist/localization/default-messages.js.map +1 -1
  286. package/dist/mcp-client/workspace-servers.js +4 -4
  287. package/dist/mcp-client/workspace-servers.js.map +1 -1
  288. package/dist/notifications/routes.d.ts +3 -3
  289. package/dist/progress/routes.d.ts +1 -1
  290. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  291. package/dist/resources/handlers.d.ts +3 -3
  292. package/dist/secrets/crypto.d.ts +7 -6
  293. package/dist/secrets/crypto.d.ts.map +1 -1
  294. package/dist/secrets/crypto.js +30 -11
  295. package/dist/secrets/crypto.js.map +1 -1
  296. package/dist/server/action-change.d.ts +1 -0
  297. package/dist/server/action-change.d.ts.map +1 -1
  298. package/dist/server/action-change.js +4 -1
  299. package/dist/server/action-change.js.map +1 -1
  300. package/dist/server/action-routes.d.ts.map +1 -1
  301. package/dist/server/action-routes.js +5 -0
  302. package/dist/server/action-routes.js.map +1 -1
  303. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  304. package/dist/server/poll.d.ts.map +1 -1
  305. package/dist/server/poll.js +1 -0
  306. package/dist/server/poll.js.map +1 -1
  307. package/dist/server/realtime-voice.d.ts +7 -0
  308. package/dist/server/realtime-voice.d.ts.map +1 -1
  309. package/dist/server/realtime-voice.js +222 -12
  310. package/dist/server/realtime-voice.js.map +1 -1
  311. package/dist/styles/agent-native.css +2 -2
  312. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  313. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  314. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  315. package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
  316. package/dist/vite/client.d.ts.map +1 -1
  317. package/dist/vite/client.js +6 -1
  318. package/dist/vite/client.js.map +1 -1
  319. package/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
  320. package/docs/content/locales/ar-SA/template-plan.mdx +1 -1
  321. package/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
  322. package/docs/content/locales/de-DE/template-plan.mdx +1 -1
  323. package/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
  324. package/docs/content/locales/es-ES/template-plan.mdx +1 -1
  325. package/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
  326. package/docs/content/locales/fr-FR/template-plan.mdx +1 -1
  327. package/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
  328. package/docs/content/locales/hi-IN/template-plan.mdx +1 -1
  329. package/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
  330. package/docs/content/locales/ja-JP/template-plan.mdx +1 -1
  331. package/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
  332. package/docs/content/locales/ko-KR/template-plan.mdx +1 -1
  333. package/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
  334. package/docs/content/locales/pt-BR/template-plan.mdx +1 -1
  335. package/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
  336. package/docs/content/locales/zh-CN/template-plan.mdx +1 -1
  337. package/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
  338. package/docs/content/locales/zh-TW/template-plan.mdx +1 -1
  339. package/docs/content/pr-visual-recap.mdx +50 -1
  340. package/docs/content/template-plan.mdx +1 -1
  341. package/package.json +2 -2
  342. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
  343. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
  344. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
  345. package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
@@ -1 +1 @@
1
- {"version":3,"file":"DemoModeSection.d.ts","sourceRoot":"","sources":["../../../src/client/settings/DemoModeSection.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAmBH,wBAAgB,eAAe,gCA4F9B;AAED,wBAAgB,YAAY,gCAE3B"}
1
+ {"version":3,"file":"DemoModeSection.d.ts","sourceRoot":"","sources":["../../../src/client/settings/DemoModeSection.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAYH,wBAAgB,eAAe,gCA2E9B;AAED,wBAAgB,YAAY,gCAE3B"}
@@ -13,29 +13,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  * accidentally turned off on stage.
14
14
  */
15
15
  import { IconEyeOff } from "@tabler/icons-react";
16
- import { useQuery } from "@tanstack/react-query";
17
16
  import { useEffect, useState } from "react";
18
17
  import { agentNativePath } from "../api-path.js";
19
- import { useChangeVersion } from "../use-change-version.js";
20
- const DEMO_STATUS_URL = agentNativePath("/_agent-native/demo/status");
18
+ import { useDemoModeStatus } from "../use-demo-mode-status.js";
21
19
  const DEMO_MODE_WRITE_URL = agentNativePath("/_agent-native/application-state/demo-mode");
22
20
  export function DemoModeSection() {
23
21
  const [enabled, setEnabled] = useState(null);
24
- const demoModeVersion = useChangeVersion("app-state:demo-mode");
25
- const { data } = useQuery({
26
- queryKey: ["agent-native", "demo-mode", demoModeVersion],
27
- queryFn: async () => {
28
- const res = await fetch(DEMO_STATUS_URL, {
29
- credentials: "same-origin",
30
- });
31
- if (!res.ok)
32
- return null;
33
- return (await res.json());
34
- },
35
- staleTime: Infinity,
36
- });
37
- const serverEnabled = data?.enabled;
38
- const forced = data?.forced === true;
22
+ const { enabled: serverEnabled, forced, isLoading } = useDemoModeStatus();
39
23
  // Surface the server value once it arrives (and on subsequent polls), but
40
24
  // never clobber an in-flight optimistic toggle with a stale read. When
41
25
  // forced by env, always reflect the locked-on state.
@@ -43,13 +27,10 @@ export function DemoModeSection() {
43
27
  if (forced) {
44
28
  setEnabled(true);
45
29
  }
46
- else if (typeof serverEnabled === "boolean") {
30
+ else if (!isLoading) {
47
31
  setEnabled((prev) => (prev === null ? serverEnabled : prev));
48
32
  }
49
- else if (serverEnabled === undefined && data !== undefined) {
50
- setEnabled((prev) => (prev === null ? false : prev));
51
- }
52
- }, [serverEnabled, forced, data]);
33
+ }, [serverEnabled, forced, isLoading]);
53
34
  const toggle = async (next) => {
54
35
  if (forced)
55
36
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"DemoModeSection.js","sourceRoot":"","sources":["../../../src/client/settings/DemoModeSection.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * <DemoModeSection /> — toggle that replaces contact/free-text names, emails,\n * and numbers with realistic fake data everywhere (UI + what the agent sees)\n * while preserving labels, IDs, and structure so the app keeps working.\n *\n * The toggle is stored in application_state under `demo-mode`\n * (`{ enabled: boolean }`) and written via `PUT\n * /_agent-native/application-state/demo-mode` (optimistic — flip first,\n * write in the background). It READS from `/_agent-native/demo/status`\n * instead, which ORs the per-user toggle with the `DEMO_MODE` env: a hosted\n * demo deployment is forced on and the switch is locked so it can't be\n * accidentally turned off on stage.\n */\n\nimport { IconEyeOff } from \"@tabler/icons-react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { useEffect, useState } from \"react\";\n\nimport { agentNativePath } from \"../api-path.js\";\nimport { useChangeVersion } from \"../use-change-version.js\";\n\ninterface DemoStatus {\n enabled?: boolean;\n forced?: boolean;\n}\n\nconst DEMO_STATUS_URL = agentNativePath(\"/_agent-native/demo/status\");\nconst DEMO_MODE_WRITE_URL = agentNativePath(\n \"/_agent-native/application-state/demo-mode\",\n);\n\nexport function DemoModeSection() {\n const [enabled, setEnabled] = useState<boolean | null>(null);\n const demoModeVersion = useChangeVersion(\"app-state:demo-mode\");\n\n const { data } = useQuery({\n queryKey: [\"agent-native\", \"demo-mode\", demoModeVersion],\n queryFn: async () => {\n const res = await fetch(DEMO_STATUS_URL, {\n credentials: \"same-origin\",\n });\n if (!res.ok) return null;\n return (await res.json()) as DemoStatus | null;\n },\n staleTime: Infinity,\n });\n\n const serverEnabled = data?.enabled;\n const forced = data?.forced === true;\n\n // Surface the server value once it arrives (and on subsequent polls), but\n // never clobber an in-flight optimistic toggle with a stale read. When\n // forced by env, always reflect the locked-on state.\n useEffect(() => {\n if (forced) {\n setEnabled(true);\n } else if (typeof serverEnabled === \"boolean\") {\n setEnabled((prev) => (prev === null ? serverEnabled : prev));\n } else if (serverEnabled === undefined && data !== undefined) {\n setEnabled((prev) => (prev === null ? false : prev));\n }\n }, [serverEnabled, forced, data]);\n\n const toggle = async (next: boolean) => {\n if (forced) return;\n const previous = enabled;\n // Optimistic: flip immediately, write in the background.\n setEnabled(next);\n try {\n const res = await fetch(DEMO_MODE_WRITE_URL, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify({ enabled: next }),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n } catch {\n setEnabled(previous);\n }\n };\n\n return (\n <div className=\"flex items-start justify-between gap-3 rounded-md border border-border bg-accent/30 px-2.5 py-2\">\n <div className=\"min-w-0\">\n <div className=\"text-[11px] font-medium text-foreground\">\n Enable demo mode\n </div>\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n Replace contact/free-text names, emails, and numbers with realistic\n fake data everywhere — in the UI and what the agent sees. Labels, IDs,\n and structure are preserved so the app keeps working.\n </p>\n {forced && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n Enforced by the <code>DEMO_MODE</code> environment variable — can't\n be turned off here.\n </p>\n )}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={!!enabled}\n aria-label=\"Enable demo mode\"\n disabled={enabled === null || forced}\n onClick={() => toggle(!enabled)}\n // Theme tokens; streaming agent owns layout.\n className={`relative inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-full transition-colors ${\n enabled\n ? \"bg-primary\"\n : \"bg-muted-foreground/30 hover:bg-muted-foreground/50\"\n } ${enabled === null || forced ? \"opacity-60\" : \"\"}`}\n >\n <span\n className={`inline-block h-3 w-3 transform rounded-full bg-background transition-transform ${\n enabled ? \"translate-x-3.5\" : \"translate-x-0.5\"\n }`}\n />\n </button>\n </div>\n );\n}\n\nexport function DemoModeIcon() {\n return <IconEyeOff size={14} />;\n}\n"]}
1
+ {"version":3,"file":"DemoModeSection.js","sourceRoot":"","sources":["../../../src/client/settings/DemoModeSection.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * <DemoModeSection /> — toggle that replaces contact/free-text names, emails,\n * and numbers with realistic fake data everywhere (UI + what the agent sees)\n * while preserving labels, IDs, and structure so the app keeps working.\n *\n * The toggle is stored in application_state under `demo-mode`\n * (`{ enabled: boolean }`) and written via `PUT\n * /_agent-native/application-state/demo-mode` (optimistic — flip first,\n * write in the background). It READS from `/_agent-native/demo/status`\n * instead, which ORs the per-user toggle with the `DEMO_MODE` env: a hosted\n * demo deployment is forced on and the switch is locked so it can't be\n * accidentally turned off on stage.\n */\n\nimport { IconEyeOff } from \"@tabler/icons-react\";\nimport { useEffect, useState } from \"react\";\n\nimport { agentNativePath } from \"../api-path.js\";\nimport { useDemoModeStatus } from \"../use-demo-mode-status.js\";\n\nconst DEMO_MODE_WRITE_URL = agentNativePath(\n \"/_agent-native/application-state/demo-mode\",\n);\n\nexport function DemoModeSection() {\n const [enabled, setEnabled] = useState<boolean | null>(null);\n const { enabled: serverEnabled, forced, isLoading } = useDemoModeStatus();\n\n // Surface the server value once it arrives (and on subsequent polls), but\n // never clobber an in-flight optimistic toggle with a stale read. When\n // forced by env, always reflect the locked-on state.\n useEffect(() => {\n if (forced) {\n setEnabled(true);\n } else if (!isLoading) {\n setEnabled((prev) => (prev === null ? serverEnabled : prev));\n }\n }, [serverEnabled, forced, isLoading]);\n\n const toggle = async (next: boolean) => {\n if (forced) return;\n const previous = enabled;\n // Optimistic: flip immediately, write in the background.\n setEnabled(next);\n try {\n const res = await fetch(DEMO_MODE_WRITE_URL, {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n credentials: \"include\",\n body: JSON.stringify({ enabled: next }),\n });\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n } catch {\n setEnabled(previous);\n }\n };\n\n return (\n <div className=\"flex items-start justify-between gap-3 rounded-md border border-border bg-accent/30 px-2.5 py-2\">\n <div className=\"min-w-0\">\n <div className=\"text-[11px] font-medium text-foreground\">\n Enable demo mode\n </div>\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n Replace contact/free-text names, emails, and numbers with realistic\n fake data everywhere — in the UI and what the agent sees. Labels, IDs,\n and structure are preserved so the app keeps working.\n </p>\n {forced && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n Enforced by the <code>DEMO_MODE</code> environment variable — can't\n be turned off here.\n </p>\n )}\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={!!enabled}\n aria-label=\"Enable demo mode\"\n disabled={enabled === null || forced}\n onClick={() => toggle(!enabled)}\n // Theme tokens; streaming agent owns layout.\n className={`relative inline-flex h-4 w-7 shrink-0 cursor-pointer items-center rounded-full transition-colors ${\n enabled\n ? \"bg-primary\"\n : \"bg-muted-foreground/30 hover:bg-muted-foreground/50\"\n } ${enabled === null || forced ? \"opacity-60\" : \"\"}`}\n >\n <span\n className={`inline-block h-3 w-3 transform rounded-full bg-background transition-transform ${\n enabled ? \"translate-x-3.5\" : \"translate-x-0.5\"\n }`}\n />\n </button>\n </div>\n );\n}\n\nexport function DemoModeIcon() {\n return <IconEyeOff size={14} />;\n}\n"]}
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * <SecretsSection /> — renders the registered secrets from the framework
3
- * secrets registry. Fetches `/_agent-native/secrets` on mount and shows a
4
- * card per secret with a masked input + Save / Rotate / Delete / Test
5
- * buttons (api-key kind) or a Connect / Disconnect button (oauth kind).
3
+ * secrets registry. Configured keys stay compact; adding or editing one
4
+ * progressively discloses its controls.
6
5
  */
7
6
  import React from "react";
8
7
  export interface SecretsSectionProps {
@@ -1 +1 @@
1
- {"version":3,"file":"SecretsSection.d.ts","sourceRoot":"","sources":["../../../src/client/settings/SecretsSection.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,OAAO,KAAoD,MAAM,OAAO,CAAC;AAoCzE,MAAM,WAAW,mBAAmB;IAClC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,mBAAmB,qBAmE/D"}
1
+ {"version":3,"file":"SecretsSection.d.ts","sourceRoot":"","sources":["../../../src/client/settings/SecretsSection.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAoD,MAAM,OAAO,CAAC;AA4CzE,MAAM,WAAW,mBAAmB;IAClC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,mBAAmB,qBA8G/D"}
@@ -1,13 +1,13 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * <SecretsSection /> — renders the registered secrets from the framework
4
- * secrets registry. Fetches `/_agent-native/secrets` on mount and shows a
5
- * card per secret with a masked input + Save / Rotate / Delete / Test
6
- * buttons (api-key kind) or a Connect / Disconnect button (oauth kind).
4
+ * secrets registry. Configured keys stay compact; adding or editing one
5
+ * progressively discloses its controls.
7
6
  */
8
- import { IconCheck, IconExternalLink, IconLoader2, IconPlugConnected, IconPlus, IconTrash, IconRefresh, } from "@tabler/icons-react";
7
+ import { IconCheck, IconChevronRight, IconExternalLink, IconLoader2, IconPlugConnected, IconPlus, IconTrash, IconRefresh, } from "@tabler/icons-react";
9
8
  import React, { useEffect, useMemo, useState, useCallback } from "react";
10
9
  import { agentNativePath } from "../api-path.js";
10
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "../components/ui/dropdown-menu.js";
11
11
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
12
12
  const ENDPOINT = agentNativePath("/_agent-native/secrets");
13
13
  function notifySecretsChanged() {
@@ -21,6 +21,8 @@ export function SecretsSection({ focusKey }) {
21
21
  const [secrets, setSecrets] = useState(null);
22
22
  const [error, setError] = useState(null);
23
23
  const [reloadToken, setReloadToken] = useState(0);
24
+ const [openSecretKey, setOpenSecretKey] = useState(focusKey ?? null);
25
+ const [customKeyOpen, setCustomKeyOpen] = useState(false);
24
26
  useEffect(() => {
25
27
  let cancelled = false;
26
28
  fetch(ENDPOINT)
@@ -43,6 +45,12 @@ export function SecretsSection({ focusKey }) {
43
45
  };
44
46
  }, [reloadToken]);
45
47
  const reload = useCallback(() => setReloadToken((t) => t + 1), []);
48
+ useEffect(() => {
49
+ if (focusKey) {
50
+ setCustomKeyOpen(false);
51
+ setOpenSecretKey(focusKey);
52
+ }
53
+ }, [focusKey]);
46
54
  if (error) {
47
55
  return (_jsxs("p", { className: "text-[10px] text-red-500", children: ["Failed to load secrets: ", error] }));
48
56
  }
@@ -50,21 +58,36 @@ export function SecretsSection({ focusKey }) {
50
58
  return (_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground", children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "Loading\u2026"] }));
51
59
  }
52
60
  if (secrets.length === 0) {
53
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("p", { className: "text-[10px] text-muted-foreground", children: ["No secrets registered yet. Templates register API keys and connections via ", _jsx("code", { children: "registerRequiredSecret()" }), "."] }), _jsx(AdHocKeysSection, {})] }));
61
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx(KeysHeader, { onCustomKey: () => setCustomKeyOpen(true) }), _jsx(AdHocKeysSection, { showForm: customKeyOpen, onShowFormChange: setCustomKeyOpen, showEmptyState: true })] }));
54
62
  }
55
- return (_jsxs("div", { className: "space-y-2", children: [secrets.map((secret) => (_jsx(SecretCard, { secret: secret, onChanged: reload, focusInput: focusKey === secret.key }, secret.key))), _jsx(AdHocKeysSection, {})] }));
63
+ const visibleSecrets = secrets.filter((secret) => secret.status !== "unset" || secret.key === openSecretKey);
64
+ const availableSecrets = secrets.filter((secret) => secret.status === "unset" && secret.key !== openSecretKey);
65
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx(KeysHeader, { availableSecrets: availableSecrets, onSecret: (key) => {
66
+ setCustomKeyOpen(false);
67
+ setOpenSecretKey(key);
68
+ }, onCustomKey: () => {
69
+ setOpenSecretKey(null);
70
+ setCustomKeyOpen(true);
71
+ } }), visibleSecrets.length > 0 && (_jsx("div", { className: "overflow-hidden rounded-md border border-border", children: visibleSecrets.map((secret) => (_jsx(SecretCard, { secret: secret, onChanged: reload, open: openSecretKey === secret.key, onOpenChange: (open) => {
72
+ if (open)
73
+ setCustomKeyOpen(false);
74
+ setOpenSecretKey(open ? secret.key : null);
75
+ }, focusInput: openSecretKey === secret.key }, secret.key))) })), _jsx(AdHocKeysSection, { showForm: customKeyOpen, onShowFormChange: setCustomKeyOpen, showEmptyState: visibleSecrets.length === 0 })] }));
76
+ }
77
+ function KeysHeader({ availableSecrets = [], onSecret, onCustomKey, }) {
78
+ return (_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("p", { className: "text-[11px] font-medium text-foreground", children: "Keys" }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "inline-flex items-center gap-1 rounded-md border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground", children: [_jsx(IconPlus, { size: 11 }), "New"] }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-60", children: [availableSecrets.length > 0 && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuLabel, { children: "Choose a key" }), availableSecrets.map((secret) => (_jsxs(DropdownMenuItem, { onSelect: () => onSecret?.(secret.key), className: "flex items-center justify-between gap-3", children: [_jsx("span", { className: "truncate", children: secret.label }), secret.required && (_jsx("span", { className: "text-[9px] font-semibold uppercase tracking-wide text-amber-600 dark:text-amber-400", children: "Required" }))] }, secret.key))), _jsx(DropdownMenuSeparator, {})] })), _jsxs(DropdownMenuItem, { onSelect: onCustomKey, children: [_jsx(IconPlus, { size: 14 }), "Custom"] })] })] })] }));
56
79
  }
57
- function SecretCard({ secret, onChanged, focusInput }) {
80
+ function SecretCard({ secret, onChanged, open, onOpenChange, focusInput, }) {
58
81
  const [value, setValue] = useState("");
59
82
  const [busy, setBusy] = useState(null);
60
83
  const [confirmDelete, setConfirmDelete] = useState(false);
61
84
  const [toast, setToast] = useState(null);
62
85
  const inputRef = React.useRef(null);
63
86
  useEffect(() => {
64
- if (focusInput && inputRef.current) {
87
+ if (open && focusInput && inputRef.current) {
65
88
  inputRef.current.focus();
66
89
  }
67
- }, [focusInput]);
90
+ }, [focusInput, open]);
68
91
  const setToastAndClear = (kind, text, ms = 2500) => {
69
92
  setToast({ kind, text });
70
93
  setTimeout(() => setToast(null), ms);
@@ -153,19 +176,18 @@ function SecretCard({ secret, onChanged, focusInput }) {
153
176
  return (_jsx("span", { className: "rounded-full bg-accent/60 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-muted-foreground", children: "Optional" }));
154
177
  }, [secret.status, secret.required]);
155
178
  const isOAuth = secret.kind === "oauth";
156
- return (_jsxs("div", { className: "rounded-md border border-border px-2.5 py-2 bg-accent/30", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-[11px] font-medium text-foreground truncate", children: secret.label }), secret.description && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5", children: secret.description }))] }), _jsx("div", { className: "shrink-0", children: pill })] }), isOAuth ? (_jsxs("div", { className: "mt-2 flex items-center gap-1.5", children: [secret.oauthConnectUrl && (_jsxs("a", { href: secret.oauthConnectUrl, className: "inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium no-underline", style: { backgroundColor: "#00B5FF", color: "white" }, children: [_jsx(IconPlugConnected, { size: 10 }), secret.status === "set" ? "Reconnect" : "Connect"] })), secret.docsUrl && (_jsxs("a", { href: secret.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground", children: ["Docs", _jsx(IconExternalLink, { size: 10 })] }))] })) : (_jsxs("div", { className: "mt-2 space-y-1.5", children: [secret.status === "set" && (_jsxs("div", { className: "flex items-center gap-2 text-[10px] text-muted-foreground", children: [_jsx("span", { children: "Stored value ending in" }), _jsx("code", { className: "rounded bg-background px-1 py-0.5 text-foreground", children: secret.last4 })] })), _jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { ref: inputRef, type: "password", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: (e) => {
157
- if (e.key === "Enter")
158
- handleSave();
159
- }, placeholder: secret.status === "set"
160
- ? "Enter new value to rotate"
161
- : "Paste key", className: "flex-1 rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent" }), _jsx("button", { type: "button", onClick: handleSave, disabled: !value.trim() || busy !== null, className: "inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40", style: { backgroundColor: "#00B5FF", color: "white" }, children: busy === "save" ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : secret.status === "set" ? (_jsxs(_Fragment, { children: [_jsx(IconRefresh, { size: 10 }), "Rotate"] })) : ("Save") })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [secret.status === "set" && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleTest, disabled: busy !== null, className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-foreground disabled:opacity-40", children: busy === "test" ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Test") }), _jsxs("button", { type: "button", onClick: () => setConfirmDelete(true), disabled: busy !== null, className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-red-500 disabled:opacity-40", children: [_jsx(IconTrash, { size: 10 }), "Remove"] })] })), secret.docsUrl && (_jsxs("a", { href: secret.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground ms-auto", children: ["Get key", _jsx(IconExternalLink, { size: 10 })] }))] }), confirmDelete && (_jsxs("div", { className: "flex items-center gap-1.5 rounded border border-red-500/30 bg-red-500/10 px-2 py-1.5 text-[10px] text-red-500", children: [_jsx("span", { className: "min-w-0 flex-1", children: "Remove this saved value?" }), _jsx("button", { type: "button", onClick: handleDelete, disabled: busy !== null, className: "inline-flex items-center gap-1 rounded border border-red-500/40 px-1.5 py-0.5 font-medium disabled:opacity-40", children: busy === "delete" ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Confirm") }), _jsx("button", { type: "button", onClick: () => setConfirmDelete(false), disabled: busy !== null, className: "rounded border border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground disabled:opacity-40", children: "Cancel" })] }))] })), toast && (_jsx("p", { className: `mt-1.5 text-[10px] ${toast.kind === "ok" ? "text-green-500" : "text-red-500"}`, children: toast.text }))] }));
179
+ return (_jsxs("div", { className: "border-b border-border last:border-b-0", children: [_jsxs("button", { type: "button", "aria-expanded": open, onClick: () => onOpenChange(!open), className: "flex w-full items-center gap-2 px-2.5 py-2 text-start transition-colors hover:bg-accent/30", children: [_jsx(IconChevronRight, { size: 13, className: `shrink-0 text-muted-foreground transition-transform ${open ? "rotate-90" : ""}` }), _jsx("span", { className: "min-w-0 flex-1 truncate text-[11px] font-medium text-foreground", children: secret.label }), secret.status === "set" && secret.last4 && (_jsxs("code", { className: "text-[10px] text-muted-foreground", children: ["\u2022\u2022\u2022\u2022", secret.last4] })), _jsx("span", { className: "shrink-0", children: pill })] }), open && (_jsxs("div", { className: "border-t border-border/60 bg-accent/20 px-3 pb-3 pt-2.5", children: [secret.description && (_jsx("p", { className: "mb-2 text-[10px] leading-relaxed text-muted-foreground", children: secret.description })), isOAuth ? (_jsxs("div", { className: "mt-2 flex items-center gap-1.5", children: [secret.oauthConnectUrl && (_jsxs("a", { href: secret.oauthConnectUrl, className: "inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium no-underline", style: { backgroundColor: "#00B5FF", color: "white" }, children: [_jsx(IconPlugConnected, { size: 10 }), secret.status === "set" ? "Reconnect" : "Connect"] })), secret.docsUrl && (_jsxs("a", { href: secret.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground", children: ["Docs", _jsx(IconExternalLink, { size: 10 })] }))] })) : (_jsxs("div", { className: "mt-2 space-y-1.5", children: [secret.status === "set" && (_jsxs("div", { className: "flex items-center gap-2 text-[10px] text-muted-foreground", children: [_jsx("span", { children: "Stored value ending in" }), _jsx("code", { className: "rounded bg-background px-1 py-0.5 text-foreground", children: secret.last4 })] })), _jsxs("div", { className: "flex gap-1.5", children: [_jsx("input", { ref: inputRef, type: "password", "aria-label": secret.label, value: value, onChange: (e) => setValue(e.target.value), onKeyDown: (e) => {
180
+ if (e.key === "Enter")
181
+ handleSave();
182
+ }, placeholder: secret.status === "set"
183
+ ? "Enter new value to rotate"
184
+ : "Paste key", className: "flex-1 rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent" }), _jsx("button", { type: "button", onClick: handleSave, disabled: !value.trim() || busy !== null, className: "inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40", style: { backgroundColor: "#00B5FF", color: "white" }, children: busy === "save" ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : secret.status === "set" ? (_jsxs(_Fragment, { children: [_jsx(IconRefresh, { size: 10 }), "Rotate"] })) : ("Save") })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [secret.status === "set" && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: handleTest, disabled: busy !== null, className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-foreground disabled:opacity-40", children: busy === "test" ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Test") }), _jsxs("button", { type: "button", onClick: () => setConfirmDelete(true), disabled: busy !== null, className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-red-500 disabled:opacity-40", children: [_jsx(IconTrash, { size: 10 }), "Remove"] })] })), secret.docsUrl && (_jsxs("a", { href: secret.docsUrl, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground ms-auto", children: ["Get key", _jsx(IconExternalLink, { size: 10 })] }))] }), confirmDelete && (_jsxs("div", { className: "flex items-center gap-1.5 rounded border border-red-500/30 bg-red-500/10 px-2 py-1.5 text-[10px] text-red-500", children: [_jsx("span", { className: "min-w-0 flex-1", children: "Remove this saved value?" }), _jsx("button", { type: "button", onClick: handleDelete, disabled: busy !== null, className: "inline-flex items-center gap-1 rounded border border-red-500/40 px-1.5 py-0.5 font-medium disabled:opacity-40", children: busy === "delete" ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Confirm") }), _jsx("button", { type: "button", onClick: () => setConfirmDelete(false), disabled: busy !== null, className: "rounded border border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground disabled:opacity-40", children: "Cancel" })] }))] })), toast && (_jsx("p", { className: `mt-1.5 text-[10px] ${toast.kind === "ok" ? "text-green-500" : "text-red-500"}`, children: toast.text }))] }))] }));
162
185
  }
163
186
  const ADHOC_ENDPOINT = agentNativePath("/_agent-native/secrets/adhoc");
164
- function AdHocKeysSection() {
187
+ function AdHocKeysSection({ showForm, onShowFormChange, showEmptyState, }) {
165
188
  const [keys, setKeys] = useState([]);
166
189
  const [loading, setLoading] = useState(true);
167
190
  const [reloadToken, setReloadToken] = useState(0);
168
- const [showForm, setShowForm] = useState(false);
169
191
  const [formName, setFormName] = useState("");
170
192
  const [formValue, setFormValue] = useState("");
171
193
  const [formDescription, setFormDescription] = useState("");
@@ -206,13 +228,13 @@ function AdHocKeysSection() {
206
228
  };
207
229
  }, [reloadToken]);
208
230
  const resetForm = useCallback(() => {
209
- setShowForm(false);
231
+ onShowFormChange(false);
210
232
  setFormName("");
211
233
  setFormValue("");
212
234
  setFormDescription("");
213
235
  setFormScope("user");
214
236
  setFormError(null);
215
- }, []);
237
+ }, [onShowFormChange]);
216
238
  const handleAdd = useCallback(async () => {
217
239
  const name = formName.trim();
218
240
  const value = formValue.trim();
@@ -241,6 +263,7 @@ function AdHocKeysSection() {
241
263
  }
242
264
  resetForm();
243
265
  showToast("ok", "Key saved");
266
+ notifySecretsChanged();
244
267
  reload();
245
268
  }
246
269
  catch (err) {
@@ -272,14 +295,15 @@ function AdHocKeysSection() {
272
295
  }
273
296
  showToast("ok", "Key deleted");
274
297
  setConfirmDeleteName(null);
298
+ notifySecretsChanged();
275
299
  reload();
276
300
  }
277
301
  finally {
278
302
  setDeletingName(null);
279
303
  }
280
304
  }, [showToast, reload]);
281
- return (_jsxs("div", { className: "mt-3 space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-[11px] font-medium text-foreground", children: "Additional Keys" }), !showForm && (_jsxs("button", { type: "button", onClick: () => setShowForm(true), className: "inline-flex items-center gap-1 rounded border border-border px-2 py-0.5 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40", children: [_jsx(IconPlus, { size: 10 }), "Add Key"] }))] }), _jsxs("p", { className: "text-[10px] text-muted-foreground/60 leading-relaxed", children: ["Keys are referenced in automations as", " ", _jsx("code", { className: "rounded bg-background px-1 py-0.5 text-[9px]", children: "${keys.KEY_NAME}" }), ". Values are encrypted and never shown to the AI agent."] }), showForm && (_jsxs("div", { className: "rounded-md border border-border px-2.5 py-2 bg-accent/30 space-y-1.5", children: [_jsx("input", { value: formName, onChange: (e) => setFormName(e.target.value.toUpperCase().replace(/[^A-Z0-9_-]/g, "")), className: "w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "KEY_NAME (e.g. SLACK_WEBHOOK)" }), _jsx("input", { type: "password", value: formValue, onChange: (e) => setFormValue(e.target.value), className: "w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Secret value" }), _jsx("input", { value: formDescription, onChange: (e) => setFormDescription(e.target.value), className: "w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Description (optional)" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("select", { value: formScope, onChange: (e) => setFormScope(e.target.value), className: "rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none focus:ring-1 focus:ring-accent", children: [_jsx("option", { value: "user", children: "Personal" }), _jsx("option", { value: "workspace", children: "Workspace" })] }), _jsxs("div", { className: "ms-auto flex items-center gap-1.5", children: [_jsx("button", { type: "button", onClick: resetForm, className: "rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground", children: "Cancel" }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !formName.trim() || !formValue.trim() || formBusy, className: "inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40", style: { backgroundColor: "#00B5FF", color: "white" }, children: formBusy ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Save") })] })] }), formError && _jsx("p", { className: "text-[10px] text-red-500", children: formError })] })), loading ? (_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground", children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "Loading..."] })) : keys.length === 0 && !showForm ? (_jsx("p", { className: "text-[10px] text-muted-foreground", children: "No additional keys yet." })) : (keys.map((key) => (_jsx("div", { className: "rounded-md border border-border px-2.5 py-2 bg-accent/30", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-[11px] font-medium text-foreground font-mono truncate", children: key.name }), _jsx("span", { className: `rounded-full px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${key.scope === "workspace"
282
- ? "bg-blue-500/15 text-blue-500"
283
- : "bg-accent/60 text-muted-foreground"}`, children: key.scope === "workspace" ? "workspace" : "personal" })] }), key.description && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5", children: key.description })), _jsx("div", { className: "flex items-center gap-2 text-[10px] text-muted-foreground mt-0.5", children: _jsxs("span", { children: ["Ending in", " ", _jsx("code", { className: "rounded bg-background px-1 py-0.5 text-foreground", children: key.last4 })] }) })] }), _jsx("div", { className: "shrink-0", children: confirmDeleteName === key.name ? (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => handleDelete(key.name), disabled: deletingName === key.name, className: "rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40", children: deletingName === key.name ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Confirm") }), _jsx("button", { type: "button", onClick: () => setConfirmDeleteName(null), className: "rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground", children: "Cancel" })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setConfirmDeleteName(key.name), className: "text-muted-foreground hover:text-red-500", children: _jsx(IconTrash, { size: 12 }) }) }), _jsx(TooltipContent, { children: "Delete" })] })) })] }) }, `${key.scope}-${key.name}`)))), toast && (_jsx("p", { className: `text-[10px] ${toast.kind === "ok" ? "text-green-500" : "text-red-500"}`, children: toast.text }))] }));
305
+ return (_jsxs("div", { className: "space-y-2", children: [showForm && (_jsxs("div", { className: "rounded-md border border-border px-2.5 py-2 bg-accent/30 space-y-1.5", children: [_jsx("input", { value: formName, onChange: (e) => setFormName(e.target.value.toUpperCase().replace(/[^A-Z0-9_-]/g, "")), className: "w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", "aria-label": "Key name", placeholder: "KEY_NAME" }), _jsx("input", { type: "password", "aria-label": "Secret value", value: formValue, onChange: (e) => setFormValue(e.target.value), className: "w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Secret value" }), _jsx("input", { value: formDescription, "aria-label": "Description", onChange: (e) => setFormDescription(e.target.value), className: "w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Description (optional)" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("select", { "aria-label": "Scope", value: formScope, onChange: (e) => setFormScope(e.target.value), className: "rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none focus:ring-1 focus:ring-accent", children: [_jsx("option", { value: "user", children: "Personal" }), _jsx("option", { value: "workspace", children: "Workspace" })] }), _jsxs("div", { className: "ms-auto flex items-center gap-1.5", children: [_jsx("button", { type: "button", onClick: resetForm, className: "rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground", children: "Cancel" }), _jsx("button", { type: "button", onClick: handleAdd, disabled: !formName.trim() || !formValue.trim() || formBusy, className: "inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40", style: { backgroundColor: "#00B5FF", color: "white" }, children: formBusy ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Save") })] })] }), formError && _jsx("p", { className: "text-[10px] text-red-500", children: formError })] })), loading ? (_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground", children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "Loading..."] })) : keys.length === 0 && !showForm && showEmptyState ? (_jsx("p", { className: "text-[10px] text-muted-foreground", children: "No keys added yet." })) : keys.length > 0 ? (_jsx("div", { className: "overflow-hidden rounded-md border border-border", children: keys.map((key) => (_jsx("div", { className: "border-b border-border px-2.5 py-2 last:border-b-0", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-[11px] font-medium text-foreground font-mono truncate", children: key.name }), _jsx("span", { className: `rounded-full px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${key.scope === "workspace"
306
+ ? "bg-blue-500/15 text-blue-500"
307
+ : "bg-accent/60 text-muted-foreground"}`, children: key.scope === "workspace" ? "workspace" : "personal" })] }), key.description && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5", children: key.description })), _jsx("div", { className: "flex items-center gap-2 text-[10px] text-muted-foreground mt-0.5", children: _jsxs("span", { children: ["Ending in", " ", _jsx("code", { className: "rounded bg-background px-1 py-0.5 text-foreground", children: key.last4 })] }) })] }), _jsx("div", { className: "shrink-0", children: confirmDeleteName === key.name ? (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => handleDelete(key.name), disabled: deletingName === key.name, className: "rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40", children: deletingName === key.name ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Confirm") }), _jsx("button", { type: "button", onClick: () => setConfirmDeleteName(null), className: "rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground", children: "Cancel" })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setConfirmDeleteName(key.name), className: "text-muted-foreground hover:text-red-500", children: _jsx(IconTrash, { size: 12 }) }) }), _jsx(TooltipContent, { children: "Delete" })] })) })] }) }, `${key.scope}-${key.name}`))) })) : null, toast && (_jsx("p", { className: `text-[10px] ${toast.kind === "ok" ? "text-green-500" : "text-red-500"}`, children: toast.text }))] }));
284
308
  }
285
309
  //# sourceMappingURL=SecretsSection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SecretsSection.js","sourceRoot":"","sources":["../../../src/client/settings/SecretsSection.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * <SecretsSection /> — renders the registered secrets from the framework\n * secrets registry. Fetches `/_agent-native/secrets` on mount and shows a\n * card per secret with a masked input + Save / Rotate / Delete / Test\n * buttons (api-key kind) or a Connect / Disconnect button (oauth kind).\n */\n\nimport {\n IconCheck,\n IconExternalLink,\n IconLoader2,\n IconPlugConnected,\n IconPlus,\n IconTrash,\n IconRefresh,\n} from \"@tabler/icons-react\";\nimport React, { useEffect, useMemo, useState, useCallback } from \"react\";\n\nimport { agentNativePath } from \"../api-path.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\n\ninterface SecretStatus {\n key: string;\n label: string;\n description?: string;\n docsUrl?: string;\n scope: \"user\" | \"workspace\";\n kind: \"api-key\" | \"oauth\";\n required: boolean;\n status: \"set\" | \"unset\" | \"invalid\";\n last4?: string;\n updatedAt?: number;\n oauthProvider?: string;\n oauthConnectUrl?: string;\n error?: string;\n}\n\nconst ENDPOINT = agentNativePath(\"/_agent-native/secrets\");\n\nfunction notifySecretsChanged() {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(\n new CustomEvent(\"agent-engine:configured-changed\", {\n detail: { source: \"secrets\" },\n }),\n );\n}\n\nexport interface SecretsSectionProps {\n /** Optional hash fragment to focus a specific secret (e.g. \"secrets:OPENAI_API_KEY\"). */\n focusKey?: string;\n}\n\nexport function SecretsSection({ focusKey }: SecretsSectionProps) {\n const [secrets, setSecrets] = useState<SecretStatus[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [reloadToken, setReloadToken] = useState(0);\n\n useEffect(() => {\n let cancelled = false;\n fetch(ENDPOINT)\n .then(async (r) => {\n if (!r.ok) {\n throw new Error(`Failed to load secrets (${r.status})`);\n }\n return (await r.json()) as SecretStatus[];\n })\n .then((data) => {\n if (!cancelled) setSecrets(data);\n })\n .catch((err) => {\n if (!cancelled) setError(err?.message ?? \"Failed to load\");\n });\n return () => {\n cancelled = true;\n };\n }, [reloadToken]);\n\n const reload = useCallback(() => setReloadToken((t) => t + 1), []);\n\n if (error) {\n return (\n <p className=\"text-[10px] text-red-500\">\n Failed to load secrets: {error}\n </p>\n );\n }\n if (secrets === null) {\n return (\n <div className=\"flex items-center gap-1.5 text-[10px] text-muted-foreground\">\n <IconLoader2 size={10} className=\"animate-spin\" />\n Loading…\n </div>\n );\n }\n if (secrets.length === 0) {\n return (\n <div className=\"space-y-2\">\n <p className=\"text-[10px] text-muted-foreground\">\n No secrets registered yet. Templates register API keys and connections\n via <code>registerRequiredSecret()</code>.\n </p>\n <AdHocKeysSection />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n {secrets.map((secret) => (\n <SecretCard\n key={secret.key}\n secret={secret}\n onChanged={reload}\n focusInput={focusKey === secret.key}\n />\n ))}\n <AdHocKeysSection />\n </div>\n );\n}\n\ninterface SecretCardProps {\n secret: SecretStatus;\n onChanged: () => void;\n focusInput?: boolean;\n}\n\nfunction SecretCard({ secret, onChanged, focusInput }: SecretCardProps) {\n const [value, setValue] = useState(\"\");\n const [busy, setBusy] = useState<null | \"save\" | \"delete\" | \"test\">(null);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [toast, setToast] = useState<{\n kind: \"ok\" | \"err\";\n text: string;\n } | null>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (focusInput && inputRef.current) {\n inputRef.current.focus();\n }\n }, [focusInput]);\n\n const setToastAndClear = (kind: \"ok\" | \"err\", text: string, ms = 2500) => {\n setToast({ kind, text });\n setTimeout(() => setToast(null), ms);\n };\n\n const handleSave = async () => {\n if (!value.trim() || busy) return;\n setBusy(\"save\");\n try {\n const res = await fetch(`${ENDPOINT}/${encodeURIComponent(secret.key)}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ value: value.trim() }),\n });\n if (!res.ok) {\n const err = await res\n .json()\n .then((j: { error?: string }) => j.error)\n .catch(() => null);\n setToastAndClear(\"err\", err ?? `Save failed (${res.status})`);\n return;\n }\n setValue(\"\");\n setConfirmDelete(false);\n setToastAndClear(\"ok\", \"Saved\");\n notifySecretsChanged();\n onChanged();\n } finally {\n setBusy(null);\n }\n };\n\n const handleDelete = async () => {\n if (busy) return;\n setBusy(\"delete\");\n try {\n const res = await fetch(`${ENDPOINT}/${encodeURIComponent(secret.key)}`, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!res.ok) {\n const err = await res\n .json()\n .then((j: { error?: string }) => j.error)\n .catch(() => null);\n setToastAndClear(\"err\", err ?? `Delete failed (${res.status})`);\n return;\n }\n setToastAndClear(\"ok\", \"Removed\");\n setConfirmDelete(false);\n notifySecretsChanged();\n onChanged();\n } finally {\n setBusy(null);\n }\n };\n\n const handleTest = async () => {\n if (busy) return;\n setBusy(\"test\");\n try {\n const res = await fetch(\n `${ENDPOINT}/${encodeURIComponent(secret.key)}/test`,\n {\n method: \"POST\",\n },\n );\n const body = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n };\n if (res.ok && body.ok) {\n setToastAndClear(\"ok\", \"Working\");\n } else {\n setToastAndClear(\n \"err\",\n body.error ?? (body.ok === false ? \"Invalid\" : `Test failed`),\n );\n }\n } finally {\n setBusy(null);\n }\n };\n\n const pill = useMemo(() => {\n if (secret.status === \"set\") {\n return (\n <span className=\"flex items-center gap-1 text-[10px] text-green-500\">\n <IconCheck size={10} />\n Set\n </span>\n );\n }\n if (secret.required) {\n return (\n <span className=\"rounded-full bg-red-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-red-500\">\n Required\n </span>\n );\n }\n return (\n <span className=\"rounded-full bg-accent/60 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-muted-foreground\">\n Optional\n </span>\n );\n }, [secret.status, secret.required]);\n\n const isOAuth = secret.kind === \"oauth\";\n\n return (\n <div className=\"rounded-md border border-border px-2.5 py-2 bg-accent/30\">\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0\">\n <div className=\"text-[11px] font-medium text-foreground truncate\">\n {secret.label}\n </div>\n {secret.description && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n {secret.description}\n </p>\n )}\n </div>\n <div className=\"shrink-0\">{pill}</div>\n </div>\n\n {isOAuth ? (\n <div className=\"mt-2 flex items-center gap-1.5\">\n {secret.oauthConnectUrl && (\n <a\n href={secret.oauthConnectUrl}\n className=\"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium no-underline\"\n style={{ backgroundColor: \"#00B5FF\", color: \"white\" }}\n >\n <IconPlugConnected size={10} />\n {secret.status === \"set\" ? \"Reconnect\" : \"Connect\"}\n </a>\n )}\n {secret.docsUrl && (\n <a\n href={secret.docsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground\"\n >\n Docs\n <IconExternalLink size={10} />\n </a>\n )}\n </div>\n ) : (\n <div className=\"mt-2 space-y-1.5\">\n {secret.status === \"set\" && (\n <div className=\"flex items-center gap-2 text-[10px] text-muted-foreground\">\n <span>Stored value ending in</span>\n <code className=\"rounded bg-background px-1 py-0.5 text-foreground\">\n {secret.last4}\n </code>\n </div>\n )}\n <div className=\"flex gap-1.5\">\n <input\n ref={inputRef}\n type=\"password\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleSave();\n }}\n placeholder={\n secret.status === \"set\"\n ? \"Enter new value to rotate\"\n : \"Paste key\"\n }\n className=\"flex-1 rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n />\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={!value.trim() || busy !== null}\n className=\"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40\"\n style={{ backgroundColor: \"#00B5FF\", color: \"white\" }}\n >\n {busy === \"save\" ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : secret.status === \"set\" ? (\n <>\n <IconRefresh size={10} />\n Rotate\n </>\n ) : (\n \"Save\"\n )}\n </button>\n </div>\n <div className=\"flex items-center gap-1.5\">\n {secret.status === \"set\" && (\n <>\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={busy !== null}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-foreground disabled:opacity-40\"\n >\n {busy === \"test\" ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Test\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDelete(true)}\n disabled={busy !== null}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-red-500 disabled:opacity-40\"\n >\n <IconTrash size={10} />\n Remove\n </button>\n </>\n )}\n {secret.docsUrl && (\n <a\n href={secret.docsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground ms-auto\"\n >\n Get key\n <IconExternalLink size={10} />\n </a>\n )}\n </div>\n {confirmDelete && (\n <div className=\"flex items-center gap-1.5 rounded border border-red-500/30 bg-red-500/10 px-2 py-1.5 text-[10px] text-red-500\">\n <span className=\"min-w-0 flex-1\">Remove this saved value?</span>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={busy !== null}\n className=\"inline-flex items-center gap-1 rounded border border-red-500/40 px-1.5 py-0.5 font-medium disabled:opacity-40\"\n >\n {busy === \"delete\" ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Confirm\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDelete(false)}\n disabled={busy !== null}\n className=\"rounded border border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground disabled:opacity-40\"\n >\n Cancel\n </button>\n </div>\n )}\n </div>\n )}\n\n {toast && (\n <p\n className={`mt-1.5 text-[10px] ${\n toast.kind === \"ok\" ? \"text-green-500\" : \"text-red-500\"\n }`}\n >\n {toast.text}\n </p>\n )}\n </div>\n );\n}\n\n// ─── Ad-hoc Keys Section ──────────────────────────────────────────────────\n\ninterface AdHocKey {\n name: string;\n scope: \"user\" | \"workspace\";\n scopeId: string;\n description: string | null;\n last4: string;\n createdAt: number;\n updatedAt: number;\n}\n\nconst ADHOC_ENDPOINT = agentNativePath(\"/_agent-native/secrets/adhoc\");\n\nfunction AdHocKeysSection() {\n const [keys, setKeys] = useState<AdHocKey[]>([]);\n const [loading, setLoading] = useState(true);\n const [reloadToken, setReloadToken] = useState(0);\n const [showForm, setShowForm] = useState(false);\n const [formName, setFormName] = useState(\"\");\n const [formValue, setFormValue] = useState(\"\");\n const [formDescription, setFormDescription] = useState(\"\");\n const [formScope, setFormScope] = useState<\"user\" | \"workspace\">(\"user\");\n const [formBusy, setFormBusy] = useState(false);\n const [formError, setFormError] = useState<string | null>(null);\n const [confirmDeleteName, setConfirmDeleteName] = useState<string | null>(\n null,\n );\n const [deletingName, setDeletingName] = useState<string | null>(null);\n const [toast, setToast] = useState<{\n kind: \"ok\" | \"err\";\n text: string;\n } | null>(null);\n\n const showToast = useCallback(\n (kind: \"ok\" | \"err\", text: string, ms = 2500) => {\n setToast({ kind, text });\n setTimeout(() => setToast(null), ms);\n },\n [],\n );\n\n const reload = useCallback(() => setReloadToken((t) => t + 1), []);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n fetch(ADHOC_ENDPOINT)\n .then(async (r) => {\n if (!r.ok) throw new Error(`Failed to load (${r.status})`);\n return (await r.json()) as AdHocKey[];\n })\n .then((data) => {\n if (!cancelled) {\n setKeys(data);\n setLoading(false);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setKeys([]);\n setLoading(false);\n }\n });\n return () => {\n cancelled = true;\n };\n }, [reloadToken]);\n\n const resetForm = useCallback(() => {\n setShowForm(false);\n setFormName(\"\");\n setFormValue(\"\");\n setFormDescription(\"\");\n setFormScope(\"user\");\n setFormError(null);\n }, []);\n\n const handleAdd = useCallback(async () => {\n const name = formName.trim();\n const value = formValue.trim();\n if (!name || !value || formBusy) return;\n setFormBusy(true);\n setFormError(null);\n try {\n const res = await fetch(ADHOC_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n name,\n value,\n description: formDescription.trim() || undefined,\n scope: formScope,\n }),\n });\n if (!res.ok) {\n const body = await res\n .json()\n .then((j: { error?: string }) => j.error)\n .catch(() => null);\n setFormError(body ?? `Save failed (${res.status})`);\n return;\n }\n resetForm();\n showToast(\"ok\", \"Key saved\");\n reload();\n } catch (err: any) {\n setFormError(err?.message ?? \"Failed to save\");\n } finally {\n setFormBusy(false);\n }\n }, [\n formName,\n formValue,\n formDescription,\n formScope,\n formBusy,\n resetForm,\n showToast,\n reload,\n ]);\n\n const handleDelete = useCallback(\n async (name: string) => {\n setDeletingName(name);\n try {\n const res = await fetch(\n `${ADHOC_ENDPOINT}/${encodeURIComponent(name)}`,\n {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n if (!res.ok) {\n showToast(\"err\", \"Failed to delete key\");\n return;\n }\n showToast(\"ok\", \"Key deleted\");\n setConfirmDeleteName(null);\n reload();\n } finally {\n setDeletingName(null);\n }\n },\n [showToast, reload],\n );\n\n return (\n <div className=\"mt-3 space-y-2\">\n <div className=\"flex items-center justify-between\">\n <p className=\"text-[11px] font-medium text-foreground\">\n Additional Keys\n </p>\n {!showForm && (\n <button\n type=\"button\"\n onClick={() => setShowForm(true)}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-0.5 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40\"\n >\n <IconPlus size={10} />\n Add Key\n </button>\n )}\n </div>\n <p className=\"text-[10px] text-muted-foreground/60 leading-relaxed\">\n Keys are referenced in automations as{\" \"}\n <code className=\"rounded bg-background px-1 py-0.5 text-[9px]\">\n {\"${keys.KEY_NAME}\"}\n </code>\n . Values are encrypted and never shown to the AI agent.\n </p>\n\n {showForm && (\n <div className=\"rounded-md border border-border px-2.5 py-2 bg-accent/30 space-y-1.5\">\n <input\n value={formName}\n onChange={(e) =>\n setFormName(\n e.target.value.toUpperCase().replace(/[^A-Z0-9_-]/g, \"\"),\n )\n }\n className=\"w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n placeholder=\"KEY_NAME (e.g. SLACK_WEBHOOK)\"\n />\n <input\n type=\"password\"\n value={formValue}\n onChange={(e) => setFormValue(e.target.value)}\n className=\"w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n placeholder=\"Secret value\"\n />\n <input\n value={formDescription}\n onChange={(e) => setFormDescription(e.target.value)}\n className=\"w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n placeholder=\"Description (optional)\"\n />\n <div className=\"flex items-center gap-2\">\n <select\n value={formScope}\n onChange={(e) =>\n setFormScope(e.target.value as \"user\" | \"workspace\")\n }\n className=\"rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none focus:ring-1 focus:ring-accent\"\n >\n <option value=\"user\">Personal</option>\n <option value=\"workspace\">Workspace</option>\n </select>\n <div className=\"ms-auto flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={resetForm}\n className=\"rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleAdd}\n disabled={!formName.trim() || !formValue.trim() || formBusy}\n className=\"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40\"\n style={{ backgroundColor: \"#00B5FF\", color: \"white\" }}\n >\n {formBusy ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Save\"\n )}\n </button>\n </div>\n </div>\n {formError && <p className=\"text-[10px] text-red-500\">{formError}</p>}\n </div>\n )}\n\n {loading ? (\n <div className=\"flex items-center gap-1.5 text-[10px] text-muted-foreground\">\n <IconLoader2 size={10} className=\"animate-spin\" />\n Loading...\n </div>\n ) : keys.length === 0 && !showForm ? (\n <p className=\"text-[10px] text-muted-foreground\">\n No additional keys yet.\n </p>\n ) : (\n keys.map((key) => (\n <div\n key={`${key.scope}-${key.name}`}\n className=\"rounded-md border border-border px-2.5 py-2 bg-accent/30\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] font-medium text-foreground font-mono truncate\">\n {key.name}\n </span>\n <span\n className={`rounded-full px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${\n key.scope === \"workspace\"\n ? \"bg-blue-500/15 text-blue-500\"\n : \"bg-accent/60 text-muted-foreground\"\n }`}\n >\n {key.scope === \"workspace\" ? \"workspace\" : \"personal\"}\n </span>\n </div>\n {key.description && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n {key.description}\n </p>\n )}\n <div className=\"flex items-center gap-2 text-[10px] text-muted-foreground mt-0.5\">\n <span>\n Ending in{\" \"}\n <code className=\"rounded bg-background px-1 py-0.5 text-foreground\">\n {key.last4}\n </code>\n </span>\n </div>\n </div>\n <div className=\"shrink-0\">\n {confirmDeleteName === key.name ? (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleDelete(key.name)}\n disabled={deletingName === key.name}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40\"\n >\n {deletingName === key.name ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Confirm\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteName(null)}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n ) : (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteName(key.name)}\n className=\"text-muted-foreground hover:text-red-500\"\n >\n <IconTrash size={12} />\n </button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n )}\n </div>\n </div>\n </div>\n ))\n )}\n\n {toast && (\n <p\n className={`text-[10px] ${toast.kind === \"ok\" ? \"text-green-500\" : \"text-red-500\"}`}\n >\n {toast.text}\n </p>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"SecretsSection.js","sourceRoot":"","sources":["../../../src/client/settings/SecretsSection.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * <SecretsSection /> — renders the registered secrets from the framework\n * secrets registry. Configured keys stay compact; adding or editing one\n * progressively discloses its controls.\n */\n\nimport {\n IconCheck,\n IconChevronRight,\n IconExternalLink,\n IconLoader2,\n IconPlugConnected,\n IconPlus,\n IconTrash,\n IconRefresh,\n} from \"@tabler/icons-react\";\nimport React, { useEffect, useMemo, useState, useCallback } from \"react\";\n\nimport { agentNativePath } from \"../api-path.js\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"../components/ui/dropdown-menu.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\n\ninterface SecretStatus {\n key: string;\n label: string;\n description?: string;\n docsUrl?: string;\n scope: \"user\" | \"workspace\";\n kind: \"api-key\" | \"oauth\";\n required: boolean;\n status: \"set\" | \"unset\" | \"invalid\";\n last4?: string;\n updatedAt?: number;\n oauthProvider?: string;\n oauthConnectUrl?: string;\n error?: string;\n}\n\nconst ENDPOINT = agentNativePath(\"/_agent-native/secrets\");\n\nfunction notifySecretsChanged() {\n if (typeof window === \"undefined\") return;\n window.dispatchEvent(\n new CustomEvent(\"agent-engine:configured-changed\", {\n detail: { source: \"secrets\" },\n }),\n );\n}\n\nexport interface SecretsSectionProps {\n /** Optional hash fragment to focus a specific secret (e.g. \"secrets:OPENAI_API_KEY\"). */\n focusKey?: string;\n}\n\nexport function SecretsSection({ focusKey }: SecretsSectionProps) {\n const [secrets, setSecrets] = useState<SecretStatus[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [reloadToken, setReloadToken] = useState(0);\n const [openSecretKey, setOpenSecretKey] = useState<string | null>(\n focusKey ?? null,\n );\n const [customKeyOpen, setCustomKeyOpen] = useState(false);\n\n useEffect(() => {\n let cancelled = false;\n fetch(ENDPOINT)\n .then(async (r) => {\n if (!r.ok) {\n throw new Error(`Failed to load secrets (${r.status})`);\n }\n return (await r.json()) as SecretStatus[];\n })\n .then((data) => {\n if (!cancelled) setSecrets(data);\n })\n .catch((err) => {\n if (!cancelled) setError(err?.message ?? \"Failed to load\");\n });\n return () => {\n cancelled = true;\n };\n }, [reloadToken]);\n\n const reload = useCallback(() => setReloadToken((t) => t + 1), []);\n\n useEffect(() => {\n if (focusKey) {\n setCustomKeyOpen(false);\n setOpenSecretKey(focusKey);\n }\n }, [focusKey]);\n\n if (error) {\n return (\n <p className=\"text-[10px] text-red-500\">\n Failed to load secrets: {error}\n </p>\n );\n }\n if (secrets === null) {\n return (\n <div className=\"flex items-center gap-1.5 text-[10px] text-muted-foreground\">\n <IconLoader2 size={10} className=\"animate-spin\" />\n Loading…\n </div>\n );\n }\n if (secrets.length === 0) {\n return (\n <div className=\"space-y-3\">\n <KeysHeader onCustomKey={() => setCustomKeyOpen(true)} />\n <AdHocKeysSection\n showForm={customKeyOpen}\n onShowFormChange={setCustomKeyOpen}\n showEmptyState\n />\n </div>\n );\n }\n\n const visibleSecrets = secrets.filter(\n (secret) => secret.status !== \"unset\" || secret.key === openSecretKey,\n );\n const availableSecrets = secrets.filter(\n (secret) => secret.status === \"unset\" && secret.key !== openSecretKey,\n );\n\n return (\n <div className=\"space-y-3\">\n <KeysHeader\n availableSecrets={availableSecrets}\n onSecret={(key) => {\n setCustomKeyOpen(false);\n setOpenSecretKey(key);\n }}\n onCustomKey={() => {\n setOpenSecretKey(null);\n setCustomKeyOpen(true);\n }}\n />\n {visibleSecrets.length > 0 && (\n <div className=\"overflow-hidden rounded-md border border-border\">\n {visibleSecrets.map((secret) => (\n <SecretCard\n key={secret.key}\n secret={secret}\n onChanged={reload}\n open={openSecretKey === secret.key}\n onOpenChange={(open) => {\n if (open) setCustomKeyOpen(false);\n setOpenSecretKey(open ? secret.key : null);\n }}\n focusInput={openSecretKey === secret.key}\n />\n ))}\n </div>\n )}\n <AdHocKeysSection\n showForm={customKeyOpen}\n onShowFormChange={setCustomKeyOpen}\n showEmptyState={visibleSecrets.length === 0}\n />\n </div>\n );\n}\n\nfunction KeysHeader({\n availableSecrets = [],\n onSecret,\n onCustomKey,\n}: {\n availableSecrets?: SecretStatus[];\n onSecret?: (key: string) => void;\n onCustomKey: () => void;\n}) {\n return (\n <div className=\"flex items-center justify-between gap-3\">\n <p className=\"text-[11px] font-medium text-foreground\">Keys</p>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 rounded-md border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground\"\n >\n <IconPlus size={11} />\n New\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-60\">\n {availableSecrets.length > 0 && (\n <>\n <DropdownMenuLabel>Choose a key</DropdownMenuLabel>\n {availableSecrets.map((secret) => (\n <DropdownMenuItem\n key={secret.key}\n onSelect={() => onSecret?.(secret.key)}\n className=\"flex items-center justify-between gap-3\"\n >\n <span className=\"truncate\">{secret.label}</span>\n {secret.required && (\n <span className=\"text-[9px] font-semibold uppercase tracking-wide text-amber-600 dark:text-amber-400\">\n Required\n </span>\n )}\n </DropdownMenuItem>\n ))}\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onCustomKey}>\n <IconPlus size={14} />\n Custom\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n );\n}\n\ninterface SecretCardProps {\n secret: SecretStatus;\n onChanged: () => void;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n focusInput?: boolean;\n}\n\nfunction SecretCard({\n secret,\n onChanged,\n open,\n onOpenChange,\n focusInput,\n}: SecretCardProps) {\n const [value, setValue] = useState(\"\");\n const [busy, setBusy] = useState<null | \"save\" | \"delete\" | \"test\">(null);\n const [confirmDelete, setConfirmDelete] = useState(false);\n const [toast, setToast] = useState<{\n kind: \"ok\" | \"err\";\n text: string;\n } | null>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n if (open && focusInput && inputRef.current) {\n inputRef.current.focus();\n }\n }, [focusInput, open]);\n\n const setToastAndClear = (kind: \"ok\" | \"err\", text: string, ms = 2500) => {\n setToast({ kind, text });\n setTimeout(() => setToast(null), ms);\n };\n\n const handleSave = async () => {\n if (!value.trim() || busy) return;\n setBusy(\"save\");\n try {\n const res = await fetch(`${ENDPOINT}/${encodeURIComponent(secret.key)}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ value: value.trim() }),\n });\n if (!res.ok) {\n const err = await res\n .json()\n .then((j: { error?: string }) => j.error)\n .catch(() => null);\n setToastAndClear(\"err\", err ?? `Save failed (${res.status})`);\n return;\n }\n setValue(\"\");\n setConfirmDelete(false);\n setToastAndClear(\"ok\", \"Saved\");\n notifySecretsChanged();\n onChanged();\n } finally {\n setBusy(null);\n }\n };\n\n const handleDelete = async () => {\n if (busy) return;\n setBusy(\"delete\");\n try {\n const res = await fetch(`${ENDPOINT}/${encodeURIComponent(secret.key)}`, {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n });\n if (!res.ok) {\n const err = await res\n .json()\n .then((j: { error?: string }) => j.error)\n .catch(() => null);\n setToastAndClear(\"err\", err ?? `Delete failed (${res.status})`);\n return;\n }\n setToastAndClear(\"ok\", \"Removed\");\n setConfirmDelete(false);\n notifySecretsChanged();\n onChanged();\n } finally {\n setBusy(null);\n }\n };\n\n const handleTest = async () => {\n if (busy) return;\n setBusy(\"test\");\n try {\n const res = await fetch(\n `${ENDPOINT}/${encodeURIComponent(secret.key)}/test`,\n {\n method: \"POST\",\n },\n );\n const body = (await res.json().catch(() => ({}))) as {\n ok?: boolean;\n error?: string;\n };\n if (res.ok && body.ok) {\n setToastAndClear(\"ok\", \"Working\");\n } else {\n setToastAndClear(\n \"err\",\n body.error ?? (body.ok === false ? \"Invalid\" : `Test failed`),\n );\n }\n } finally {\n setBusy(null);\n }\n };\n\n const pill = useMemo(() => {\n if (secret.status === \"set\") {\n return (\n <span className=\"flex items-center gap-1 text-[10px] text-green-500\">\n <IconCheck size={10} />\n Set\n </span>\n );\n }\n if (secret.required) {\n return (\n <span className=\"rounded-full bg-red-500/15 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-red-500\">\n Required\n </span>\n );\n }\n return (\n <span className=\"rounded-full bg-accent/60 px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-muted-foreground\">\n Optional\n </span>\n );\n }, [secret.status, secret.required]);\n\n const isOAuth = secret.kind === \"oauth\";\n\n return (\n <div className=\"border-b border-border last:border-b-0\">\n <button\n type=\"button\"\n aria-expanded={open}\n onClick={() => onOpenChange(!open)}\n className=\"flex w-full items-center gap-2 px-2.5 py-2 text-start transition-colors hover:bg-accent/30\"\n >\n <IconChevronRight\n size={13}\n className={`shrink-0 text-muted-foreground transition-transform ${open ? \"rotate-90\" : \"\"}`}\n />\n <span className=\"min-w-0 flex-1 truncate text-[11px] font-medium text-foreground\">\n {secret.label}\n </span>\n {secret.status === \"set\" && secret.last4 && (\n <code className=\"text-[10px] text-muted-foreground\">\n ••••{secret.last4}\n </code>\n )}\n <span className=\"shrink-0\">{pill}</span>\n </button>\n\n {open && (\n <div className=\"border-t border-border/60 bg-accent/20 px-3 pb-3 pt-2.5\">\n {secret.description && (\n <p className=\"mb-2 text-[10px] leading-relaxed text-muted-foreground\">\n {secret.description}\n </p>\n )}\n {isOAuth ? (\n <div className=\"mt-2 flex items-center gap-1.5\">\n {secret.oauthConnectUrl && (\n <a\n href={secret.oauthConnectUrl}\n className=\"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium no-underline\"\n style={{ backgroundColor: \"#00B5FF\", color: \"white\" }}\n >\n <IconPlugConnected size={10} />\n {secret.status === \"set\" ? \"Reconnect\" : \"Connect\"}\n </a>\n )}\n {secret.docsUrl && (\n <a\n href={secret.docsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground\"\n >\n Docs\n <IconExternalLink size={10} />\n </a>\n )}\n </div>\n ) : (\n <div className=\"mt-2 space-y-1.5\">\n {secret.status === \"set\" && (\n <div className=\"flex items-center gap-2 text-[10px] text-muted-foreground\">\n <span>Stored value ending in</span>\n <code className=\"rounded bg-background px-1 py-0.5 text-foreground\">\n {secret.last4}\n </code>\n </div>\n )}\n <div className=\"flex gap-1.5\">\n <input\n ref={inputRef}\n type=\"password\"\n aria-label={secret.label}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleSave();\n }}\n placeholder={\n secret.status === \"set\"\n ? \"Enter new value to rotate\"\n : \"Paste key\"\n }\n className=\"flex-1 rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n />\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={!value.trim() || busy !== null}\n className=\"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40\"\n style={{ backgroundColor: \"#00B5FF\", color: \"white\" }}\n >\n {busy === \"save\" ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : secret.status === \"set\" ? (\n <>\n <IconRefresh size={10} />\n Rotate\n </>\n ) : (\n \"Save\"\n )}\n </button>\n </div>\n <div className=\"flex items-center gap-1.5\">\n {secret.status === \"set\" && (\n <>\n <button\n type=\"button\"\n onClick={handleTest}\n disabled={busy !== null}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-foreground disabled:opacity-40\"\n >\n {busy === \"test\" ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Test\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDelete(true)}\n disabled={busy !== null}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] text-muted-foreground hover:text-red-500 disabled:opacity-40\"\n >\n <IconTrash size={10} />\n Remove\n </button>\n </>\n )}\n {secret.docsUrl && (\n <a\n href={secret.docsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] no-underline text-muted-foreground hover:text-foreground ms-auto\"\n >\n Get key\n <IconExternalLink size={10} />\n </a>\n )}\n </div>\n {confirmDelete && (\n <div className=\"flex items-center gap-1.5 rounded border border-red-500/30 bg-red-500/10 px-2 py-1.5 text-[10px] text-red-500\">\n <span className=\"min-w-0 flex-1\">\n Remove this saved value?\n </span>\n <button\n type=\"button\"\n onClick={handleDelete}\n disabled={busy !== null}\n className=\"inline-flex items-center gap-1 rounded border border-red-500/40 px-1.5 py-0.5 font-medium disabled:opacity-40\"\n >\n {busy === \"delete\" ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Confirm\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDelete(false)}\n disabled={busy !== null}\n className=\"rounded border border-border px-1.5 py-0.5 text-muted-foreground hover:text-foreground disabled:opacity-40\"\n >\n Cancel\n </button>\n </div>\n )}\n </div>\n )}\n\n {toast && (\n <p\n className={`mt-1.5 text-[10px] ${\n toast.kind === \"ok\" ? \"text-green-500\" : \"text-red-500\"\n }`}\n >\n {toast.text}\n </p>\n )}\n </div>\n )}\n </div>\n );\n}\n\n// ─── Ad-hoc Keys Section ──────────────────────────────────────────────────\n\ninterface AdHocKey {\n name: string;\n scope: \"user\" | \"workspace\";\n scopeId: string;\n description: string | null;\n last4: string;\n createdAt: number;\n updatedAt: number;\n}\n\nconst ADHOC_ENDPOINT = agentNativePath(\"/_agent-native/secrets/adhoc\");\n\nfunction AdHocKeysSection({\n showForm,\n onShowFormChange,\n showEmptyState,\n}: {\n showForm: boolean;\n onShowFormChange: (show: boolean) => void;\n showEmptyState: boolean;\n}) {\n const [keys, setKeys] = useState<AdHocKey[]>([]);\n const [loading, setLoading] = useState(true);\n const [reloadToken, setReloadToken] = useState(0);\n const [formName, setFormName] = useState(\"\");\n const [formValue, setFormValue] = useState(\"\");\n const [formDescription, setFormDescription] = useState(\"\");\n const [formScope, setFormScope] = useState<\"user\" | \"workspace\">(\"user\");\n const [formBusy, setFormBusy] = useState(false);\n const [formError, setFormError] = useState<string | null>(null);\n const [confirmDeleteName, setConfirmDeleteName] = useState<string | null>(\n null,\n );\n const [deletingName, setDeletingName] = useState<string | null>(null);\n const [toast, setToast] = useState<{\n kind: \"ok\" | \"err\";\n text: string;\n } | null>(null);\n\n const showToast = useCallback(\n (kind: \"ok\" | \"err\", text: string, ms = 2500) => {\n setToast({ kind, text });\n setTimeout(() => setToast(null), ms);\n },\n [],\n );\n\n const reload = useCallback(() => setReloadToken((t) => t + 1), []);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n fetch(ADHOC_ENDPOINT)\n .then(async (r) => {\n if (!r.ok) throw new Error(`Failed to load (${r.status})`);\n return (await r.json()) as AdHocKey[];\n })\n .then((data) => {\n if (!cancelled) {\n setKeys(data);\n setLoading(false);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setKeys([]);\n setLoading(false);\n }\n });\n return () => {\n cancelled = true;\n };\n }, [reloadToken]);\n\n const resetForm = useCallback(() => {\n onShowFormChange(false);\n setFormName(\"\");\n setFormValue(\"\");\n setFormDescription(\"\");\n setFormScope(\"user\");\n setFormError(null);\n }, [onShowFormChange]);\n\n const handleAdd = useCallback(async () => {\n const name = formName.trim();\n const value = formValue.trim();\n if (!name || !value || formBusy) return;\n setFormBusy(true);\n setFormError(null);\n try {\n const res = await fetch(ADHOC_ENDPOINT, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n name,\n value,\n description: formDescription.trim() || undefined,\n scope: formScope,\n }),\n });\n if (!res.ok) {\n const body = await res\n .json()\n .then((j: { error?: string }) => j.error)\n .catch(() => null);\n setFormError(body ?? `Save failed (${res.status})`);\n return;\n }\n resetForm();\n showToast(\"ok\", \"Key saved\");\n notifySecretsChanged();\n reload();\n } catch (err: any) {\n setFormError(err?.message ?? \"Failed to save\");\n } finally {\n setFormBusy(false);\n }\n }, [\n formName,\n formValue,\n formDescription,\n formScope,\n formBusy,\n resetForm,\n showToast,\n reload,\n ]);\n\n const handleDelete = useCallback(\n async (name: string) => {\n setDeletingName(name);\n try {\n const res = await fetch(\n `${ADHOC_ENDPOINT}/${encodeURIComponent(name)}`,\n {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n if (!res.ok) {\n showToast(\"err\", \"Failed to delete key\");\n return;\n }\n showToast(\"ok\", \"Key deleted\");\n setConfirmDeleteName(null);\n notifySecretsChanged();\n reload();\n } finally {\n setDeletingName(null);\n }\n },\n [showToast, reload],\n );\n\n return (\n <div className=\"space-y-2\">\n {showForm && (\n <div className=\"rounded-md border border-border px-2.5 py-2 bg-accent/30 space-y-1.5\">\n <input\n value={formName}\n onChange={(e) =>\n setFormName(\n e.target.value.toUpperCase().replace(/[^A-Z0-9_-]/g, \"\"),\n )\n }\n className=\"w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n aria-label=\"Key name\"\n placeholder=\"KEY_NAME\"\n />\n <input\n type=\"password\"\n aria-label=\"Secret value\"\n value={formValue}\n onChange={(e) => setFormValue(e.target.value)}\n className=\"w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n placeholder=\"Secret value\"\n />\n <input\n value={formDescription}\n aria-label=\"Description\"\n onChange={(e) => setFormDescription(e.target.value)}\n className=\"w-full rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent\"\n placeholder=\"Description (optional)\"\n />\n <div className=\"flex items-center gap-2\">\n <select\n aria-label=\"Scope\"\n value={formScope}\n onChange={(e) =>\n setFormScope(e.target.value as \"user\" | \"workspace\")\n }\n className=\"rounded border border-border bg-background px-2 py-1 text-[11px] text-foreground outline-none focus:ring-1 focus:ring-accent\"\n >\n <option value=\"user\">Personal</option>\n <option value=\"workspace\">Workspace</option>\n </select>\n <div className=\"ms-auto flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={resetForm}\n className=\"rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleAdd}\n disabled={!formName.trim() || !formValue.trim() || formBusy}\n className=\"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium disabled:opacity-40\"\n style={{ backgroundColor: \"#00B5FF\", color: \"white\" }}\n >\n {formBusy ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Save\"\n )}\n </button>\n </div>\n </div>\n {formError && <p className=\"text-[10px] text-red-500\">{formError}</p>}\n </div>\n )}\n\n {loading ? (\n <div className=\"flex items-center gap-1.5 text-[10px] text-muted-foreground\">\n <IconLoader2 size={10} className=\"animate-spin\" />\n Loading...\n </div>\n ) : keys.length === 0 && !showForm && showEmptyState ? (\n <p className=\"text-[10px] text-muted-foreground\">No keys added yet.</p>\n ) : keys.length > 0 ? (\n <div className=\"overflow-hidden rounded-md border border-border\">\n {keys.map((key) => (\n <div\n key={`${key.scope}-${key.name}`}\n className=\"border-b border-border px-2.5 py-2 last:border-b-0\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[11px] font-medium text-foreground font-mono truncate\">\n {key.name}\n </span>\n <span\n className={`rounded-full px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${\n key.scope === \"workspace\"\n ? \"bg-blue-500/15 text-blue-500\"\n : \"bg-accent/60 text-muted-foreground\"\n }`}\n >\n {key.scope === \"workspace\" ? \"workspace\" : \"personal\"}\n </span>\n </div>\n {key.description && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5\">\n {key.description}\n </p>\n )}\n <div className=\"flex items-center gap-2 text-[10px] text-muted-foreground mt-0.5\">\n <span>\n Ending in{\" \"}\n <code className=\"rounded bg-background px-1 py-0.5 text-foreground\">\n {key.last4}\n </code>\n </span>\n </div>\n </div>\n <div className=\"shrink-0\">\n {confirmDeleteName === key.name ? (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleDelete(key.name)}\n disabled={deletingName === key.name}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40\"\n >\n {deletingName === key.name ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Confirm\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteName(null)}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n ) : (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteName(key.name)}\n className=\"text-muted-foreground hover:text-red-500\"\n >\n <IconTrash size={12} />\n </button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n )}\n </div>\n </div>\n </div>\n ))}\n </div>\n ) : null}\n\n {toast && (\n <p\n className={`text-[10px] ${toast.kind === \"ok\" ? \"text-green-500\" : \"text-red-500\"}`}\n >\n {toast.text}\n </p>\n )}\n </div>\n );\n}\n"]}
@@ -1,5 +1,14 @@
1
1
  import React from "react";
2
2
  import type { SettingsTabItem } from "./SettingsTabsPage.js";
3
+ export declare function AppDefaultModelField({ engine, models, value, defaultModel, disabled, onValueChange, onEnter, }: {
4
+ engine: string;
5
+ models: string[];
6
+ value: string;
7
+ defaultModel?: string;
8
+ disabled?: boolean;
9
+ onValueChange: (value: string) => void;
10
+ onEnter?: () => void;
11
+ }): React.JSX.Element;
3
12
  export interface SettingsPanelProps {
4
13
  isDevMode: boolean;
5
14
  onToggleDevMode: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/settings/SettingsPanel.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAQN,MAAM,OAAO,CAAC;AA2Bf,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAomE/B,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAw6BD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,qBAEtD;AAED,wBAAgB,oBAAoB,IAAI,eAAe,EAAE,CAiFxD"}
1
+ {"version":3,"file":"SettingsPanel.d.ts","sourceRoot":"","sources":["../../../src/client/settings/SettingsPanel.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAQN,MAAM,OAAO,CAAC;AA2Bf,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,uBAAuB,CAAC;AAwoB/B,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,MAAM,EACN,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,aAAa,EACb,OAAO,GACR,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,qBAqDA;AAs+CD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAw6BD,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,qBAEtD;AAED,wBAAgB,oBAAoB,IAAI,eAAe,EAAE,CAiFxD"}