@agent-native/core 0.79.17 → 0.79.19

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 (355) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +14 -0
  3. package/corpus/core/docs/content/file-uploads.md +11 -4
  4. package/corpus/core/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
  5. package/corpus/core/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
  6. package/corpus/core/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
  7. package/corpus/core/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
  8. package/corpus/core/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
  9. package/corpus/core/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
  10. package/corpus/core/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
  11. package/corpus/core/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
  12. package/corpus/core/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
  13. package/corpus/core/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
  14. package/corpus/core/docs/content/multi-app-workspace.md +3 -3
  15. package/corpus/core/docs/content/template-clips.md +14 -5
  16. package/corpus/core/package.json +1 -1
  17. package/corpus/core/src/agent/engine/builder-engine.ts +8 -3
  18. package/corpus/core/src/cli/mcp.ts +11 -6
  19. package/corpus/core/src/client/AssistantChat.tsx +6 -2
  20. package/corpus/core/src/client/chat/markdown-renderer.tsx +1 -0
  21. package/corpus/core/src/client/i18n.tsx +77 -65
  22. package/corpus/core/src/client/index.ts +7 -1
  23. package/corpus/core/src/client/org/OrgSwitcher.tsx +5 -5
  24. package/corpus/core/src/client/org/TeamPage.tsx +11 -3
  25. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +216 -0
  26. package/corpus/core/src/client/settings/index.ts +5 -0
  27. package/corpus/core/src/file-upload/index.ts +1 -0
  28. package/corpus/core/src/file-upload/registry.ts +22 -6
  29. package/corpus/core/src/file-upload/types.ts +6 -1
  30. package/corpus/core/src/integrations/adapters/email.ts +26 -18
  31. package/corpus/core/src/integrations/adapters/slack.ts +8 -7
  32. package/corpus/core/src/integrations/adapters/telegram.ts +9 -11
  33. package/corpus/core/src/integrations/adapters/whatsapp.ts +12 -9
  34. package/corpus/core/src/integrations/plugin.ts +79 -13
  35. package/corpus/core/src/onboarding/default-steps.ts +6 -3
  36. package/corpus/core/src/onboarding/types.ts +1 -1
  37. package/corpus/core/src/org/handlers.ts +1 -1
  38. package/corpus/core/src/server/agent-chat-plugin.ts +4 -7
  39. package/corpus/core/src/server/better-auth-instance.ts +19 -62
  40. package/corpus/core/src/server/core-routes-plugin.ts +93 -180
  41. package/corpus/core/src/server/create-server.ts +55 -116
  42. package/corpus/core/src/server/email-actions.ts +3 -6
  43. package/corpus/core/src/server/email.ts +52 -17
  44. package/corpus/core/src/server/index.ts +2 -1
  45. package/corpus/core/src/server/scoped-key-storage.ts +223 -0
  46. package/corpus/core/src/shared/agent-env.ts +3 -3
  47. package/corpus/core/src/sharing/actions/share-resource.ts +1 -1
  48. package/corpus/core/src/styles/agent-native.css +47 -3
  49. package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -2
  50. package/corpus/core/src/templates/workspace-root/README.md +1 -1
  51. package/corpus/core/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  52. package/corpus/core/src/terminal/pty-server.ts +3 -38
  53. package/corpus/core/src/triggers/dispatcher.ts +1 -2
  54. package/corpus/templates/.retired/issues/package.json +7 -0
  55. package/corpus/templates/.retired/meeting-notes/package.json +7 -0
  56. package/corpus/templates/.retired/recruiting/package.json +7 -0
  57. package/corpus/templates/.retired/scheduling/package.json +7 -0
  58. package/corpus/templates/.retired/voice/package.json +7 -0
  59. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  60. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -18
  61. package/corpus/templates/analytics/app/global.css +15 -0
  62. package/corpus/templates/analytics/app/i18n/zh-TW.ts +7 -1
  63. package/corpus/templates/analytics/app/i18n-data.ts +71 -2
  64. package/corpus/templates/analytics/app/pages/Ask.tsx +1 -1
  65. package/corpus/templates/analytics/app/pages/Settings.tsx +120 -73
  66. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +0 -11
  67. package/corpus/templates/analytics/app/routes/catalog.tsx +33 -176
  68. package/corpus/templates/analytics/app/routes/team.tsx +3 -2
  69. package/corpus/templates/analytics/changelog/2026-06-26-dashboard-templates-are-tucked-into-settings-and-show-simple.md +6 -0
  70. package/corpus/templates/analytics/changelog/2026-06-26-the-ask-tab-uses-a-softer-dark-gray-canvas-while-sidebar-cha.md +6 -0
  71. package/corpus/templates/analytics/changelog/2026-06-26-the-sessions-page-shows-a-single-page-title-instead-of-repea.md +6 -0
  72. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +37 -28
  73. package/corpus/templates/assets/app/routes/settings.tsx +65 -43
  74. package/corpus/templates/assets/app/routes/team.tsx +2 -10
  75. package/corpus/templates/brain/app/routes/settings.tsx +390 -358
  76. package/corpus/templates/brain/app/routes/team.tsx +2 -8
  77. package/corpus/templates/calendar/actions/db-connect.ts +5 -29
  78. package/corpus/templates/calendar/app/components/CloudUpgrade.tsx +8 -51
  79. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +2 -1
  80. package/corpus/templates/calendar/app/components/calendar/GoogleSetupWizard.tsx +4 -2
  81. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +0 -2
  82. package/corpus/templates/calendar/app/pages/Settings.tsx +304 -271
  83. package/corpus/templates/calendar/app/routes/_app.team.tsx +2 -17
  84. package/corpus/templates/calendar/server/handlers/google-auth.ts +22 -9
  85. package/corpus/templates/calendar/server/lib/booking-emails.ts +1 -1
  86. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +1 -1
  87. package/corpus/templates/calendar/server/lib/google-calendar.ts +48 -28
  88. package/corpus/templates/chat/app/components/layout/Header.tsx +0 -1
  89. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +4 -2
  90. package/corpus/templates/chat/app/routes/settings.tsx +54 -54
  91. package/corpus/templates/chat/app/routes/team.tsx +2 -10
  92. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +7 -2
  93. package/corpus/templates/clips/.agents/skills/recording/SKILL.md +1 -1
  94. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +7 -0
  95. package/corpus/templates/clips/AGENTS.md +8 -0
  96. package/corpus/templates/clips/actions/invite-member.ts +1 -1
  97. package/corpus/templates/clips/actions/request-transcript.ts +1 -1
  98. package/corpus/templates/clips/app/components/library/library-layout.tsx +325 -333
  99. package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +80 -40
  100. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +2 -0
  101. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +629 -643
  102. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +263 -158
  103. package/corpus/templates/clips/app/routes/share.$shareId.tsx +10 -2
  104. package/corpus/templates/clips/changelog/2026-06-26-long-desktop-recordings-are-checkpointed-so-macos-finalizati.md +6 -0
  105. package/corpus/templates/clips/changelog/2026-06-26-non-mac-desktop-recordings-wait-for-upload-transcription.md +6 -0
  106. package/corpus/templates/clips/changelog/2026-06-26-recording-details-button-stays-at-the-far-right-on-small-screen.md +6 -0
  107. package/corpus/templates/clips/changelog/2026-06-26-s3-compatible-storage-keys-now-save-securely-from-clips-sett.md +6 -0
  108. package/corpus/templates/clips/changelog/2026-06-26-shared-clip-links-guide-agents-through-processing-transcripts.md +6 -0
  109. package/corpus/templates/clips/changelog/2026-06-26-the-agent-sidebar-now-slides-in-smoothly-without-duplicate-e.md +6 -0
  110. package/corpus/templates/clips/changelog/2026-06-26-the-clip-details-sidebar-now-collapses-into-a-slide-out-pane.md +6 -0
  111. package/corpus/templates/clips/desktop/src/lib/recorder.ts +55 -3
  112. package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +217 -5
  113. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
  114. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +176 -5
  115. package/corpus/templates/clips/server/lib/public-agent-context.ts +31 -0
  116. package/corpus/templates/clips/server/lib/s3-upload-provider.ts +60 -14
  117. package/corpus/templates/clips/server/lib/video-storage.ts +37 -9
  118. package/corpus/templates/clips/server/routes/api/agent-transcript.json.get.ts +5 -0
  119. package/corpus/templates/content/app/components/layout/Header.tsx +0 -1
  120. package/corpus/templates/content/app/components/sidebar/NotionButton.tsx +1 -0
  121. package/corpus/templates/content/app/routes/_app.settings.tsx +54 -55
  122. package/corpus/templates/content/app/routes/_app.team.tsx +2 -28
  123. package/corpus/templates/content/server/lib/notion.ts +43 -11
  124. package/corpus/templates/content/server/routes/api/notion/auth-url.get.ts +2 -2
  125. package/corpus/templates/content/server/routes/api/notion/status.get.ts +3 -3
  126. package/corpus/templates/design/app/routes/settings.tsx +60 -38
  127. package/corpus/templates/design/app/routes/team.tsx +2 -10
  128. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +2 -2
  129. package/corpus/templates/dispatch/app/routes/settings.tsx +70 -55
  130. package/corpus/templates/dispatch/app/routes/team.tsx +5 -1
  131. package/corpus/templates/forms/actions/db-connect.ts +7 -36
  132. package/corpus/templates/forms/actions/navigate.ts +2 -2
  133. package/corpus/templates/forms/app/components/CloudUpgrade.tsx +8 -47
  134. package/corpus/templates/forms/app/components/layout/Header.tsx +0 -1
  135. package/corpus/templates/forms/app/components/layout/Layout.tsx +42 -25
  136. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +35 -76
  137. package/corpus/templates/forms/app/global.css +9 -25
  138. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +4 -4
  139. package/corpus/templates/forms/app/i18n/ar-SA.ts +1 -0
  140. package/corpus/templates/forms/app/i18n/de-DE.ts +1 -0
  141. package/corpus/templates/forms/app/i18n/en-US.ts +1 -0
  142. package/corpus/templates/forms/app/i18n/es-ES.ts +1 -0
  143. package/corpus/templates/forms/app/i18n/fr-FR.ts +1 -0
  144. package/corpus/templates/forms/app/i18n/hi-IN.ts +1 -0
  145. package/corpus/templates/forms/app/i18n/ja-JP.ts +1 -0
  146. package/corpus/templates/forms/app/i18n/ko-KR.ts +1 -0
  147. package/corpus/templates/forms/app/i18n/pt-BR.ts +1 -0
  148. package/corpus/templates/forms/app/i18n/zh-CN.ts +1 -0
  149. package/corpus/templates/forms/app/i18n/zh-TW.ts +1 -0
  150. package/corpus/templates/forms/app/lib/route-prewarm.ts +9 -8
  151. package/corpus/templates/forms/app/pages/AskPage.tsx +70 -0
  152. package/corpus/templates/forms/app/pages/FormsListPage.tsx +74 -81
  153. package/corpus/templates/forms/app/root.tsx +1 -1
  154. package/corpus/templates/forms/app/routes/_app.ask.tsx +14 -0
  155. package/corpus/templates/forms/app/routes/_app.settings.tsx +54 -54
  156. package/corpus/templates/forms/app/routes/_app.team.tsx +2 -9
  157. package/corpus/templates/forms/app/routes/_index.tsx +21 -130
  158. package/corpus/templates/forms/changelog/2026-06-26-ask-forms-opens-as-a-standard-app-tab-with-a-simpler-sidebar.md +6 -0
  159. package/corpus/templates/forms/changelog/2026-06-26-forms-are-shown-in-a-tighter-row-list-with-a-denser-sidebar.md +6 -0
  160. package/corpus/templates/forms/shared/navigation.ts +4 -2
  161. package/corpus/templates/macros/app/routes/settings.tsx +54 -54
  162. package/corpus/templates/macros/app/routes/team.tsx +2 -10
  163. package/corpus/templates/mail/actions/helpers.ts +2 -2
  164. package/corpus/templates/mail/app/components/GoogleConnectBanner.tsx +2 -1
  165. package/corpus/templates/mail/app/pages/SettingsPage.tsx +5 -5
  166. package/corpus/templates/mail/app/routes/team.tsx +3 -2
  167. package/corpus/templates/mail/server/handlers/emails.ts +3 -2
  168. package/corpus/templates/mail/server/handlers/google-auth.ts +19 -12
  169. package/corpus/templates/mail/server/lib/automation-engine.ts +3 -2
  170. package/corpus/templates/mail/server/lib/email-state.ts +2 -3
  171. package/corpus/templates/mail/server/lib/google-auth.ts +28 -11
  172. package/corpus/templates/mail/server/lib/jobs.ts +3 -2
  173. package/corpus/templates/mail/server/onboarding.ts +9 -6
  174. package/corpus/templates/mail/server/routes/api/attachments.get.ts +3 -3
  175. package/corpus/templates/plan/actions/request-plan-access.ts +1 -1
  176. package/corpus/templates/plan/app/components/layout/Header.tsx +0 -1
  177. package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +56 -4
  178. package/corpus/templates/plan/app/global.css +8 -3
  179. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +4 -2
  180. package/corpus/templates/plan/app/lib/route-prewarm.ts +0 -4
  181. package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
  182. package/corpus/templates/plan/app/routes/settings.tsx +75 -73
  183. package/corpus/templates/plan/app/routes/team.tsx +2 -8
  184. package/corpus/templates/plan/changelog/2026-06-26-canvas-grid-panning-now-stays-smooth-and-fills-the-workspace.md +6 -0
  185. package/corpus/templates/plan/server/lib/comment-notifications.ts +1 -1
  186. package/corpus/templates/slides/actions/check-image-gen.ts +2 -1
  187. package/corpus/templates/slides/actions/db-connect.ts +7 -45
  188. package/corpus/templates/slides/actions/edit-image.ts +6 -3
  189. package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
  190. package/corpus/templates/slides/actions/generate-image.ts +2 -2
  191. package/corpus/templates/slides/actions/generate-slides-ai.ts +5 -3
  192. package/corpus/templates/slides/actions/image-gen-status.ts +4 -3
  193. package/corpus/templates/slides/actions/image-search.ts +6 -3
  194. package/corpus/templates/slides/actions/search-images.ts +6 -3
  195. package/corpus/templates/slides/app/components/CloudUpgrade.tsx +8 -51
  196. package/corpus/templates/slides/app/components/layout/Header.tsx +0 -1
  197. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +0 -2
  198. package/corpus/templates/slides/app/routes/settings.tsx +54 -54
  199. package/corpus/templates/slides/app/routes/team.tsx +2 -12
  200. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +9 -9
  201. package/corpus/templates/slides/server/handlers/image-gen.ts +5 -1
  202. package/corpus/templates/slides/server/handlers/image-providers/gemini.ts +9 -1
  203. package/corpus/templates/slides/server/handlers/image-providers/index.ts +18 -8
  204. package/corpus/templates/slides/server/handlers/image-providers/openai.ts +10 -4
  205. package/corpus/templates/slides/server/handlers/image-providers/types.ts +1 -0
  206. package/corpus/templates/slides/server/lib/google-docs-oauth.ts +59 -34
  207. package/corpus/templates/slides/server/register-secrets.ts +60 -0
  208. package/corpus/templates/videos/actions/db-connect.ts +7 -45
  209. package/corpus/templates/videos/app/components/CloudUpgrade.tsx +8 -51
  210. package/corpus/templates/videos/app/components/Sidebar.tsx +1 -9
  211. package/corpus/templates/videos/app/components/layout/Header.tsx +0 -1
  212. package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -3
  213. package/corpus/templates/videos/app/routes/settings.tsx +54 -54
  214. package/corpus/templates/videos/app/routes/team.tsx +2 -8
  215. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  216. package/dist/agent/engine/builder-engine.js +8 -3
  217. package/dist/agent/engine/builder-engine.js.map +1 -1
  218. package/dist/cli/mcp.d.ts.map +1 -1
  219. package/dist/cli/mcp.js +3 -4
  220. package/dist/cli/mcp.js.map +1 -1
  221. package/dist/client/AssistantChat.d.ts.map +1 -1
  222. package/dist/client/AssistantChat.js +6 -2
  223. package/dist/client/AssistantChat.js.map +1 -1
  224. package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
  225. package/dist/client/chat/markdown-renderer.js +1 -0
  226. package/dist/client/chat/markdown-renderer.js.map +1 -1
  227. package/dist/client/i18n.d.ts.map +1 -1
  228. package/dist/client/i18n.js +20 -9
  229. package/dist/client/i18n.js.map +1 -1
  230. package/dist/client/index.d.ts +1 -1
  231. package/dist/client/index.d.ts.map +1 -1
  232. package/dist/client/index.js +1 -1
  233. package/dist/client/index.js.map +1 -1
  234. package/dist/client/org/OrgSwitcher.d.ts +3 -3
  235. package/dist/client/org/OrgSwitcher.js +2 -2
  236. package/dist/client/org/OrgSwitcher.js.map +1 -1
  237. package/dist/client/org/TeamPage.d.ts +6 -1
  238. package/dist/client/org/TeamPage.d.ts.map +1 -1
  239. package/dist/client/org/TeamPage.js +2 -2
  240. package/dist/client/org/TeamPage.js.map +1 -1
  241. package/dist/client/settings/SettingsTabsPage.d.ts +27 -0
  242. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -0
  243. package/dist/client/settings/SettingsTabsPage.js +108 -0
  244. package/dist/client/settings/SettingsTabsPage.js.map +1 -0
  245. package/dist/client/settings/index.d.ts +1 -0
  246. package/dist/client/settings/index.d.ts.map +1 -1
  247. package/dist/client/settings/index.js +1 -0
  248. package/dist/client/settings/index.js.map +1 -1
  249. package/dist/file-upload/index.d.ts +1 -1
  250. package/dist/file-upload/index.d.ts.map +1 -1
  251. package/dist/file-upload/index.js +1 -1
  252. package/dist/file-upload/index.js.map +1 -1
  253. package/dist/file-upload/registry.d.ts +1 -0
  254. package/dist/file-upload/registry.d.ts.map +1 -1
  255. package/dist/file-upload/registry.js +24 -6
  256. package/dist/file-upload/registry.js.map +1 -1
  257. package/dist/file-upload/types.d.ts +6 -1
  258. package/dist/file-upload/types.d.ts.map +1 -1
  259. package/dist/file-upload/types.js.map +1 -1
  260. package/dist/integrations/adapters/email.d.ts.map +1 -1
  261. package/dist/integrations/adapters/email.js +18 -18
  262. package/dist/integrations/adapters/email.js.map +1 -1
  263. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  264. package/dist/integrations/adapters/slack.js +8 -7
  265. package/dist/integrations/adapters/slack.js.map +1 -1
  266. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  267. package/dist/integrations/adapters/telegram.js +9 -9
  268. package/dist/integrations/adapters/telegram.js.map +1 -1
  269. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  270. package/dist/integrations/adapters/whatsapp.js +10 -9
  271. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  272. package/dist/integrations/plugin.d.ts.map +1 -1
  273. package/dist/integrations/plugin.js +47 -13
  274. package/dist/integrations/plugin.js.map +1 -1
  275. package/dist/notifications/routes.d.ts +3 -3
  276. package/dist/observability/routes.d.ts +6 -6
  277. package/dist/onboarding/default-steps.d.ts.map +1 -1
  278. package/dist/onboarding/default-steps.js +6 -5
  279. package/dist/onboarding/default-steps.js.map +1 -1
  280. package/dist/onboarding/types.d.ts +1 -1
  281. package/dist/onboarding/types.d.ts.map +1 -1
  282. package/dist/onboarding/types.js.map +1 -1
  283. package/dist/org/handlers.js +1 -1
  284. package/dist/org/handlers.js.map +1 -1
  285. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  286. package/dist/server/agent-chat-plugin.js +4 -6
  287. package/dist/server/agent-chat-plugin.js.map +1 -1
  288. package/dist/server/agent-engine-api-key-route.d.ts +2 -2
  289. package/dist/server/better-auth-instance.d.ts.map +1 -1
  290. package/dist/server/better-auth-instance.js +17 -56
  291. package/dist/server/better-auth-instance.js.map +1 -1
  292. package/dist/server/core-routes-plugin.d.ts +1 -1
  293. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  294. package/dist/server/core-routes-plugin.js +67 -153
  295. package/dist/server/core-routes-plugin.js.map +1 -1
  296. package/dist/server/create-server.d.ts +3 -9
  297. package/dist/server/create-server.d.ts.map +1 -1
  298. package/dist/server/create-server.js +37 -91
  299. package/dist/server/create-server.js.map +1 -1
  300. package/dist/server/email-actions.d.ts +2 -3
  301. package/dist/server/email-actions.d.ts.map +1 -1
  302. package/dist/server/email-actions.js +3 -6
  303. package/dist/server/email-actions.js.map +1 -1
  304. package/dist/server/email.d.ts +3 -3
  305. package/dist/server/email.d.ts.map +1 -1
  306. package/dist/server/email.js +40 -19
  307. package/dist/server/email.js.map +1 -1
  308. package/dist/server/index.d.ts +3 -3
  309. package/dist/server/index.d.ts.map +1 -1
  310. package/dist/server/index.js +3 -3
  311. package/dist/server/index.js.map +1 -1
  312. package/dist/server/scoped-key-storage.d.ts +22 -0
  313. package/dist/server/scoped-key-storage.d.ts.map +1 -0
  314. package/dist/server/scoped-key-storage.js +152 -0
  315. package/dist/server/scoped-key-storage.js.map +1 -0
  316. package/dist/shared/agent-env.d.ts +3 -3
  317. package/dist/shared/agent-env.d.ts.map +1 -1
  318. package/dist/shared/agent-env.js +3 -3
  319. package/dist/shared/agent-env.js.map +1 -1
  320. package/dist/sharing/actions/share-resource.js +1 -1
  321. package/dist/sharing/actions/share-resource.js.map +1 -1
  322. package/dist/styles/agent-native.css +47 -3
  323. package/dist/templates/workspace-root/AGENTS.md +3 -2
  324. package/dist/templates/workspace-root/README.md +1 -1
  325. package/dist/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  326. package/dist/terminal/pty-server.d.ts.map +1 -1
  327. package/dist/terminal/pty-server.js +3 -36
  328. package/dist/terminal/pty-server.js.map +1 -1
  329. package/dist/triggers/dispatcher.js +1 -1
  330. package/dist/triggers/dispatcher.js.map +1 -1
  331. package/docs/content/file-uploads.md +11 -4
  332. package/docs/content/locales/ar-SA/multi-app-workspace.md +3 -3
  333. package/docs/content/locales/de-DE/multi-app-workspace.md +3 -3
  334. package/docs/content/locales/es-ES/multi-app-workspace.md +3 -3
  335. package/docs/content/locales/fr-FR/multi-app-workspace.md +3 -3
  336. package/docs/content/locales/hi-IN/multi-app-workspace.md +3 -3
  337. package/docs/content/locales/ja-JP/multi-app-workspace.md +3 -3
  338. package/docs/content/locales/ko-KR/multi-app-workspace.md +3 -3
  339. package/docs/content/locales/pt-BR/multi-app-workspace.md +3 -3
  340. package/docs/content/locales/zh-CN/multi-app-workspace.md +3 -3
  341. package/docs/content/locales/zh-TW/multi-app-workspace.md +3 -3
  342. package/docs/content/multi-app-workspace.md +3 -3
  343. package/docs/content/template-clips.md +14 -5
  344. package/package.json +1 -1
  345. package/src/templates/workspace-root/AGENTS.md +3 -2
  346. package/src/templates/workspace-root/README.md +1 -1
  347. package/src/templates/workspace-root/scripts/repair-workspace-org.ts +29 -90
  348. package/corpus/core/src/server/env-var-writes.ts +0 -16
  349. package/corpus/templates/analytics/app/pages/Team.tsx +0 -9
  350. package/corpus/templates/calendar/app/pages/Team.tsx +0 -12
  351. package/corpus/templates/mail/app/pages/Team.tsx +0 -17
  352. package/dist/server/env-var-writes.d.ts +0 -10
  353. package/dist/server/env-var-writes.d.ts.map +0 -1
  354. package/dist/server/env-var-writes.js +0 -18
  355. package/dist/server/env-var-writes.js.map +0 -1
@@ -55,6 +55,8 @@
55
55
  --agent-native-lower-surface: hsl(
56
56
  var(--sidebar-background, var(--background))
57
57
  );
58
+ --agent-native-raised-surface: hsl(var(--background));
59
+ --agent-native-card-surface: hsl(var(--card));
58
60
  --agent-native-raised-border: hsl(var(--border));
59
61
  --agent-native-raised-radius: 8px;
60
62
  --agent-native-raised-shadow-left: -1px 0 3px rgb(0 0 0 / 0.018);
@@ -86,6 +88,16 @@
86
88
  hsl(var(--sidebar-background, var(--background))) 94%,
87
89
  black
88
90
  );
91
+ --agent-native-raised-surface: color-mix(
92
+ in srgb,
93
+ hsl(var(--background)) 78%,
94
+ hsl(var(--muted)) 22%
95
+ );
96
+ --agent-native-card-surface: color-mix(
97
+ in srgb,
98
+ var(--agent-native-raised-surface) 88%,
99
+ hsl(var(--muted)) 12%
100
+ );
89
101
  }
90
102
  }
91
103
 
@@ -126,7 +138,7 @@
126
138
  .agent-sidebar-main-surface {
127
139
  position: relative;
128
140
  z-index: 1;
129
- background: hsl(var(--background));
141
+ background: var(--agent-native-raised-surface);
130
142
  transition:
131
143
  border-radius 260ms cubic-bezier(0.32, 0.72, 0, 1),
132
144
  border-color 260ms cubic-bezier(0.32, 0.72, 0, 1),
@@ -136,17 +148,49 @@
136
148
  .agent-layout-shell
137
149
  :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
138
150
  > :first-child
139
- > :where(header, div).border-b:first-child,
151
+ > :where(header, div).border-b,
140
152
  .agent-layout-shell
141
153
  :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
142
- > :where(header, div).border-b:first-child,
154
+ > :where(header, div).border-b,
143
155
  .agent-layout-shell
144
156
  .agent-layout-left-drawer
145
157
  > :where(header, div).border-b:first-child,
158
+ .agent-layout-shell
159
+ .agent-layout-left-drawer
160
+ > :first-child
161
+ > :where(header, div).border-b,
146
162
  .agent-layout-shell .agent-native-shell-topbar {
147
163
  border-bottom-color: transparent !important;
148
164
  }
149
165
 
166
+ .agent-layout-shell
167
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
168
+ > :first-child
169
+ > :where(header, div).border-b,
170
+ .agent-layout-shell
171
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
172
+ > :where(header, div).border-b {
173
+ background-color: var(--agent-native-raised-surface) !important;
174
+ }
175
+
176
+ .agent-layout-shell
177
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
178
+ > :first-child
179
+ > :where(header, div).border-b.h-12,
180
+ .agent-layout-shell
181
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
182
+ > :where(header, div).border-b.h-12 {
183
+ min-height: 4rem;
184
+ height: 4rem;
185
+ }
186
+
187
+ .dark
188
+ .agent-layout-shell
189
+ :where(.agent-layout-main-surface, .agent-sidebar-main-surface)
190
+ :where(.bg-card) {
191
+ background-color: var(--agent-native-card-surface) !important;
192
+ }
193
+
150
194
  @media (min-width: 768px) {
151
195
  .agent-layout-main-surface,
152
196
  .agent-layout-shell > .agent-sidebar-shell > .agent-sidebar-main-surface {
@@ -170,7 +170,8 @@ Use the workspace root `.env` for shared identity and cross-app trust settings:
170
170
  - `WORKSPACE_OWNER_EMAIL` — initial owner/admin email for repairs and
171
171
  integration defaults.
172
172
  - `A2A_SECRET` — shared secret for cross-app A2A signing. Generate with
173
- `openssl rand -hex 32` or `pnpm repair:workspace-org -- --name ...`.
173
+ `openssl rand -hex 32` and configure through your deployment/scoped secret
174
+ manager.
174
175
 
175
176
  `DISPATCH_DEFAULT_OWNER_EMAIL` is optional. Set it only for trusted,
176
177
  single-workspace deployments where unlinked integration requests should run as
@@ -183,7 +184,7 @@ When asked to repair workspace org or A2A configuration:
183
184
  1. Read `.env` first. Do not infer the organization, domain, owner email, or
184
185
  secret from old examples.
185
186
  2. Run `pnpm repair:workspace-org -- --name "<org>" --domain example.com --owner-email owner@example.com`
186
- to create or update generic workspace identity values.
187
+ to validate generic workspace identity values without writing `.env`.
187
188
  3. Prefer the app's organization settings UI or authenticated org routes for
188
189
  changing `allowed_domain` and `a2a_secret`.
189
190
  4. If direct SQL is unavoidable, inspect the live schema first and use only
@@ -97,7 +97,7 @@ cross-app trust:
97
97
  - `A2A_SECRET` — shared signing secret for cross-app A2A calls.
98
98
 
99
99
  Run `pnpm repair:workspace-org -- --name "<org>" --domain example.com --owner-email owner@example.com`
100
- to fill or validate those values without committing secrets. Existing
100
+ to validate those values without writing env files. Existing
101
101
  organization rows should still be repaired through the app's org settings UI or
102
102
  authenticated org routes whenever possible.
103
103
 
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
- import crypto from "node:crypto";
4
3
  import fs from "node:fs";
5
4
  import path from "node:path";
6
5
 
@@ -10,8 +9,6 @@ interface Options {
10
9
  ownerEmail?: string;
11
10
  a2aSecret?: string;
12
11
  envPath: string;
13
- force: boolean;
14
- dryRun: boolean;
15
12
  setDispatchDefaultOwner: boolean;
16
13
  }
17
14
 
@@ -22,10 +19,10 @@ Options:
22
19
  --name <value> Sets WORKSPACE_ORG_NAME
23
20
  --domain <value> Sets WORKSPACE_ORG_DOMAIN
24
21
  --owner-email <value> Sets WORKSPACE_OWNER_EMAIL
25
- --a2a-secret <value> Sets A2A_SECRET (generated when omitted)
26
- --env <path> Env file to update (default: .env)
27
- --force Overwrite existing non-empty values
28
- --dry-run Print the changes without writing
22
+ --a2a-secret <value> Reads A2A_SECRET for validation
23
+ --env <path> Env file to read for fallback values (default: .env)
24
+ --force Accepted for compatibility; no file is written
25
+ --dry-run Accepted for compatibility; no file is written
29
26
  --set-dispatch-default-owner Also set DISPATCH_DEFAULT_OWNER_EMAIL
30
27
  `;
31
28
 
@@ -41,8 +38,6 @@ type RequiredKey = (typeof REQUIRED_KEYS)[number];
41
38
  function parseArgs(argv: string[]): Options {
42
39
  const opts: Options = {
43
40
  envPath: ".env",
44
- force: false,
45
- dryRun: false,
46
41
  setDispatchDefaultOwner: false,
47
42
  };
48
43
 
@@ -78,10 +73,8 @@ function parseArgs(argv: string[]): Options {
78
73
  opts.envPath = value();
79
74
  break;
80
75
  case "--force":
81
- opts.force = true;
82
76
  break;
83
77
  case "--dry-run":
84
- opts.dryRun = true;
85
78
  break;
86
79
  case "--set-dispatch-default-owner":
87
80
  opts.setDispatchDefaultOwner = true;
@@ -147,47 +140,6 @@ function validateEmail(email: string): void {
147
140
  }
148
141
  }
149
142
 
150
- function formatEnvValue(value: string): string {
151
- if (/^[A-Za-z0-9_@./:+-]+$/.test(value)) return value;
152
- return JSON.stringify(value);
153
- }
154
-
155
- function upsertEnvValue(
156
- content: string,
157
- key: string,
158
- value: string,
159
- force: boolean,
160
- ): { content: string; changed: boolean; skipped: boolean } {
161
- const lines = content.length > 0 ? content.split(/\r?\n/) : [];
162
- let found = false;
163
- let changed = false;
164
- let skipped = false;
165
-
166
- const next = lines.map((line) => {
167
- const match = line.match(/^(\s*)([A-Z0-9_]+)(\s*=\s*)(.*)$/);
168
- if (!match || match[2] !== key) return line;
169
-
170
- found = true;
171
- const existing = unquote(match[4]);
172
- if (existing && !force) {
173
- skipped = true;
174
- return line;
175
- }
176
-
177
- const replacement = `${match[1]}${key}${match[3]}${formatEnvValue(value)}`;
178
- if (replacement !== line) changed = true;
179
- return replacement;
180
- });
181
-
182
- if (!found) {
183
- if (next.length > 0 && next[next.length - 1] !== "") next.push("");
184
- next.push(`${key}=${formatEnvValue(value)}`);
185
- changed = true;
186
- }
187
-
188
- return { content: next.join("\n"), changed, skipped };
189
- }
190
-
191
143
  function firstValue(...values: Array<string | undefined>): string | undefined {
192
144
  return values.map((v) => v?.trim()).find(Boolean);
193
145
  }
@@ -213,13 +165,21 @@ function main(): void {
213
165
  process.env.WORKSPACE_OWNER_EMAIL,
214
166
  current.WORKSPACE_OWNER_EMAIL,
215
167
  )?.toLowerCase();
216
- const a2aSecret =
217
- firstValue(opts.a2aSecret, process.env.A2A_SECRET, current.A2A_SECRET) ??
218
- crypto.randomBytes(32).toString("hex");
168
+ const a2aSecret = firstValue(
169
+ opts.a2aSecret,
170
+ process.env.A2A_SECRET,
171
+ current.A2A_SECRET,
172
+ );
219
173
 
220
174
  if (!name) fail("--name or WORKSPACE_ORG_NAME is required.");
221
175
  if (!rawDomain) fail("--domain or WORKSPACE_ORG_DOMAIN is required.");
222
176
  if (!ownerEmail) fail("--owner-email or WORKSPACE_OWNER_EMAIL is required.");
177
+ if (!a2aSecret) {
178
+ fail(
179
+ "--a2a-secret or A2A_SECRET is required. This script reads existing " +
180
+ "configuration but does not write env files.",
181
+ );
182
+ }
223
183
 
224
184
  const domain = normalizeDomain(rawDomain);
225
185
  validateDomain(domain);
@@ -232,52 +192,31 @@ function main(): void {
232
192
  A2A_SECRET: a2aSecret,
233
193
  };
234
194
 
235
- let next = original.trimEnd();
236
- const changed: string[] = [];
237
- const skipped: string[] = [];
238
-
239
- for (const key of REQUIRED_KEYS) {
240
- const result = upsertEnvValue(next, key, desired[key], opts.force);
241
- next = result.content;
242
- if (result.changed) changed.push(key);
243
- if (result.skipped) skipped.push(key);
244
- }
245
-
195
+ const displayEntries: Array<[string, string]> = REQUIRED_KEYS.map((key) => [
196
+ key,
197
+ key === "A2A_SECRET" ? "[configured]" : desired[key],
198
+ ]);
246
199
  if (opts.setDispatchDefaultOwner) {
247
- const result = upsertEnvValue(
248
- next,
249
- "DISPATCH_DEFAULT_OWNER_EMAIL",
250
- ownerEmail,
251
- opts.force,
252
- );
253
- next = result.content;
254
- if (result.changed) changed.push("DISPATCH_DEFAULT_OWNER_EMAIL");
255
- if (result.skipped) skipped.push("DISPATCH_DEFAULT_OWNER_EMAIL");
256
- }
257
-
258
- next = next.trimEnd() + "\n";
259
-
260
- if (opts.dryRun) {
261
- console.log(next);
262
- } else {
263
- fs.writeFileSync(envPath, next);
200
+ displayEntries.push(["DISPATCH_DEFAULT_OWNER_EMAIL", ownerEmail]);
264
201
  }
265
202
 
266
203
  console.log(
267
- `${opts.dryRun ? "Validated" : "Updated"} ${path.relative(process.cwd(), envPath) || envPath}.`,
204
+ `Validated workspace org settings from ${path.relative(process.cwd(), envPath) || envPath}.`,
268
205
  );
269
- if (changed.length > 0) console.log(`Changed: ${changed.join(", ")}`);
270
- if (skipped.length > 0) {
271
- console.log(
272
- `Kept existing values: ${skipped.join(", ")} (use --force to overwrite)`,
273
- );
206
+ console.log("No env files were written.");
207
+ console.log("");
208
+ console.log("Resolved configuration:");
209
+ for (const [key, value] of displayEntries) {
210
+ console.log(`- ${key}: ${value}`);
274
211
  }
275
212
  console.log("");
276
213
  console.log("Next steps:");
277
214
  console.log("1. Sign in as WORKSPACE_OWNER_EMAIL.");
278
215
  console.log("2. Create or select the org named by WORKSPACE_ORG_NAME.");
279
216
  console.log("3. Set the org allowed domain to WORKSPACE_ORG_DOMAIN.");
280
- console.log("4. Set or sync the org A2A secret from A2A_SECRET across apps.");
217
+ console.log(
218
+ "4. Configure A2A_SECRET through the scoped secret/deployment secret manager for apps that need cross-app A2A.",
219
+ );
281
220
  }
282
221
 
283
222
  main();
@@ -1 +1 @@
1
- {"version":3,"file":"pty-server.d.ts","sourceRoot":"","sources":["../../src/terminal/pty-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,MAAM,IAAI,UAAU,EAC1B,MAAM,MAAM,CAAC;AA2Fd,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAuS1B"}
1
+ {"version":3,"file":"pty-server.d.ts","sourceRoot":"","sources":["../../src/terminal/pty-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,MAAM,IAAI,UAAU,EAC1B,MAAM,MAAM,CAAC;AAmFd,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,MAAM,EAAE,UAAU,CAAC;IACnB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CA4Q1B"}
@@ -18,13 +18,6 @@ async function getChildProcess() {
18
18
  }
19
19
  return _cp;
20
20
  }
21
- let _fs;
22
- async function getFs() {
23
- if (!_fs) {
24
- _fs = await import("node:fs");
25
- }
26
- return _fs;
27
- }
28
21
  /**
29
22
  * Kill a process and all its descendants.
30
23
  * node-pty's kill() only sends a signal to the shell, but child processes
@@ -241,9 +234,9 @@ export async function createPtyWebSocketServer(options = {}) {
241
234
  const msg = JSON.parse(str);
242
235
  if (msg.type === "agentNative.setEnvVars" &&
243
236
  Array.isArray(msg.data?.vars)) {
244
- const envPath = path.join(resolvedAppDir, ".env");
245
237
  const vars = msg.data.vars;
246
- // Validate env var names and sanitize values
238
+ // Legacy bridge message. Keep validating the keys, but do not persist
239
+ // them to .env or process.env; key storage is DB-scoped.
247
240
  const validKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;
248
241
  const sanitizedVars = vars.filter(({ key }) => {
249
242
  if (!validKeyPattern.test(key)) {
@@ -252,37 +245,11 @@ export async function createPtyWebSocketServer(options = {}) {
252
245
  }
253
246
  return true;
254
247
  });
255
- const fs = await getFs();
256
- let lines = [];
257
- try {
258
- lines = fs.readFileSync(envPath, "utf-8").split("\n");
259
- }
260
- catch { }
261
- for (const { key, value } of sanitizedVars) {
262
- // Strip newlines/null bytes to prevent line injection
263
- const safeValue = value.replace(/[\r\n\0]/g, "");
264
- // Quote values containing #, spaces, or quotes so dotenv parses correctly
265
- const needsQuoting = /[# "']/.test(safeValue);
266
- const quotedValue = needsQuoting
267
- ? `"${safeValue.replace(/"/g, '\\"')}"`
268
- : safeValue;
269
- const idx = lines.findIndex((l) => l.startsWith(`${key}=`));
270
- const entry = `${key}=${quotedValue}`;
271
- if (idx !== -1) {
272
- lines[idx] = entry;
273
- }
274
- else {
275
- lines.push(entry);
276
- }
277
- }
278
- while (lines.length > 0 && lines[lines.length - 1] === "") {
279
- lines.pop();
280
- }
281
- fs.writeFileSync(envPath, lines.join("\n") + "\n", "utf-8");
282
248
  if (ws.readyState === WebSocket.OPEN) {
283
249
  ws.send(JSON.stringify({
284
250
  type: "env-vars-saved",
285
251
  keys: sanitizedVars.map((v) => v.key),
252
+ storage: "scoped-secrets",
286
253
  }));
287
254
  }
288
255
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"pty-server.js","sourceRoot":"","sources":["../../src/terminal/pty-server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PTY WebSocket Server\n *\n * Creates an HTTP server with WebSocket support that spawns PTY processes\n * for AI CLI tools. Each WebSocket connection gets its own PTY.\n *\n * Used by both the embedded AgentTerminal component and the CLI frame.\n */\n\nimport {\n createServer as createHttpServer,\n type IncomingMessage,\n type Server as HttpServer,\n} from \"http\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport {\n CLI_REGISTRY,\n commandExists,\n isAllowedCommand,\n} from \"./cli-registry.js\";\n\n// Lazy singletons for Node-only modules (only available in Node.js)\nlet _cp: typeof import(\"child_process\") | undefined;\nasync function getChildProcess(): Promise<typeof import(\"child_process\")> {\n if (!_cp) {\n _cp = await import(\"node:child_process\");\n }\n return _cp;\n}\n\nlet _fs: typeof import(\"fs\") | undefined;\nasync function getFs(): Promise<typeof import(\"fs\")> {\n if (!_fs) {\n _fs = await import(\"node:fs\");\n }\n return _fs;\n}\n\n/**\n * Kill a process and all its descendants.\n * node-pty's kill() only sends a signal to the shell, but child processes\n * (like `builder`) may be in their own process group and survive as orphans.\n */\nasync function killProcessTree(pid: number, _logPrefix: string): Promise<void> {\n const cp = await getChildProcess();\n\n if (os.platform() === \"win32\") {\n try {\n cp.execSync(`taskkill /pid ${pid} /T /F`, { stdio: \"ignore\" });\n } catch {}\n return;\n }\n\n // Find all descendant PIDs (children, grandchildren, etc.)\n const descendants: number[] = [];\n function findDescendants(parentPid: number) {\n try {\n const output = cp\n .execSync(`pgrep -P ${parentPid}`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n })\n .trim();\n if (output) {\n for (const line of output.split(\"\\n\")) {\n const childPid = parseInt(line, 10);\n if (childPid && !isNaN(childPid)) {\n descendants.push(childPid);\n findDescendants(childPid);\n }\n }\n }\n } catch {\n // pgrep returns non-zero when no children found\n }\n }\n findDescendants(pid);\n\n // Kill descendants first (deepest first), then the parent\n for (const childPid of descendants.reverse()) {\n try {\n process.kill(childPid, \"SIGTERM\");\n } catch {}\n }\n\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {}\n\n // Force-kill any survivors after a short delay\n setTimeout(() => {\n for (const childPid of descendants) {\n try {\n process.kill(childPid, \"SIGKILL\");\n } catch {}\n }\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {}\n }, 500);\n}\n\nexport interface PtyServerOptions {\n /** Working directory for PTY processes. Defaults to process.cwd() */\n appDir?: string;\n /** Default CLI command. Defaults to 'claude' */\n command?: string;\n /** Port to listen on. Defaults to 0 (random available port) */\n port?: number;\n /** Auth check for WebSocket upgrade requests. Return false to reject. */\n authCheck?: (req: IncomingMessage) => boolean | Promise<boolean>;\n /** Log prefix for console output. Defaults to '[terminal]' */\n logPrefix?: string;\n}\n\nexport interface PtyServerResult {\n /** The underlying HTTP server */\n server: HttpServer;\n /** The actual port the server is listening on */\n port: number;\n /** Shut down the server and kill all PTY processes */\n close: () => void;\n}\n\nexport async function createPtyWebSocketServer(\n options: PtyServerOptions = {},\n): Promise<PtyServerResult> {\n const {\n appDir = process.cwd(),\n command: defaultCommand = \"claude\",\n port = 0,\n authCheck,\n logPrefix = \"[terminal]\",\n } = options;\n\n // Dynamic imports for optional native dependencies\n const { WebSocketServer, WebSocket } = await import(\"ws\");\n const pty = await import(\"node-pty\");\n\n const resolvedAppDir = path.resolve(appDir);\n const shell =\n os.platform() === \"win32\" ? \"cmd.exe\" : process.env.SHELL || \"/bin/zsh\";\n\n const server = createHttpServer((req, res) => {\n // CORS headers\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n res.writeHead(404);\n res.end();\n });\n\n const wss = new WebSocketServer({ noServer: true });\n\n // Handle WebSocket upgrades with optional auth\n server.on(\"upgrade\", async (req, socket, head) => {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n if (url.pathname !== \"/ws\") {\n socket.write(\"HTTP/1.1 404 Not Found\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n if (authCheck) {\n try {\n const allowed = await authCheck(req);\n if (!allowed) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n } catch {\n socket.write(\"HTTP/1.1 500 Internal Server Error\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n });\n\n // Track active PTY processes for cleanup\n const activePtys = new Set<ReturnType<typeof pty.spawn>>();\n\n wss.on(\"connection\", async (ws: InstanceType<typeof WebSocket>, req) => {\n const url = new URL(req.url || \"\", `http://${req.headers.host}`);\n const command = url.searchParams.get(\"command\") || defaultCommand;\n const extraFlags = url.searchParams.get(\"flags\") || \"\";\n console.log(`${logPrefix} WebSocket connected for command: ${command}`);\n\n const sendStatus = (status: string, message: string) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"setup-status\", status, message }));\n }\n };\n\n // Validate command against allowlist to prevent injection\n if (!isAllowedCommand(command)) {\n sendStatus(\n \"not-found\",\n `\"${command}\" is not a recognized CLI. Allowed: ${Object.keys(CLI_REGISTRY).join(\", \")}`,\n );\n if (ws.readyState === WebSocket.OPEN) ws.close();\n return;\n }\n\n // Reject flags containing shell metacharacters\n if (extraFlags && /[;&|`$(){}\\n\\r<>]/.test(extraFlags)) {\n sendStatus(\"failed\", \"Invalid flags: shell metacharacters not allowed\");\n if (ws.readyState === WebSocket.OPEN) ws.close();\n return;\n }\n\n // Check if CLI is installed; if not, use npx to run it\n let useNpx = false;\n if (!(await commandExists(command))) {\n const registry = CLI_REGISTRY[command];\n if (registry?.installPackage) {\n console.log(`${logPrefix} ${command} CLI not found, will use npx`);\n useNpx = true;\n } else {\n sendStatus(\n \"not-found\",\n `\"${command}\" not found on PATH. Please install it manually.`,\n );\n if (ws.readyState === WebSocket.OPEN) ws.close();\n return;\n }\n }\n\n // Build the command — use npx if CLI not found locally\n const baseCommand = useNpx\n ? `npx --yes ${CLI_REGISTRY[command].installPackage}`\n : command;\n const fullCommand = extraFlags\n ? `${baseCommand} ${extraFlags}`\n : baseCommand;\n console.log(`${logPrefix} Spawning PTY: ${fullCommand}`);\n\n // Build env, stripping CLI-specific nesting vars\n const registry = CLI_REGISTRY[command];\n const env: Record<string, string | undefined> = {\n ...process.env,\n TERM: \"xterm-256color\",\n };\n if (registry) {\n for (const v of registry.stripEnv) delete env[v];\n }\n\n let ptyProcess: ReturnType<typeof pty.spawn>;\n try {\n ptyProcess = pty.spawn(shell, [\"-l\", \"-c\", fullCommand], {\n name: \"xterm-256color\",\n cols: 120,\n rows: 40,\n cwd: resolvedAppDir,\n env: env as Record<string, string>,\n });\n } catch (err) {\n console.error(`${logPrefix} Failed to spawn PTY:`, err);\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(\n `\\r\\n\\x1b[31m${logPrefix} Failed to spawn PTY: ${err}\\x1b[0m\\r\\n`,\n );\n ws.close();\n }\n return;\n }\n\n activePtys.add(ptyProcess);\n console.log(`${logPrefix} PTY spawned (pid: ${ptyProcess.pid})`);\n\n ptyProcess.onData((data: string) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(data);\n }\n });\n\n ptyProcess.onExit(({ exitCode }) => {\n console.log(`${logPrefix} PTY exited with code ${exitCode}`);\n activePtys.delete(ptyProcess);\n if (exitCode === 127 && ws.readyState === WebSocket.OPEN) {\n ws.send(\n JSON.stringify({\n type: \"setup-status\",\n status: \"not-found\",\n message: `Command \"${command}\" not found. Please install it first.`,\n }),\n );\n }\n if (ws.readyState === WebSocket.OPEN) {\n ws.close();\n }\n });\n\n ws.on(\"message\", async (data: Buffer | string) => {\n const str = typeof data === \"string\" ? data : data.toString();\n\n try {\n const msg = JSON.parse(str);\n\n if (\n msg.type === \"agentNative.setEnvVars\" &&\n Array.isArray(msg.data?.vars)\n ) {\n const envPath = path.join(resolvedAppDir, \".env\");\n const vars: Array<{ key: string; value: string }> = msg.data.vars;\n\n // Validate env var names and sanitize values\n const validKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;\n const sanitizedVars = vars.filter(({ key }) => {\n if (!validKeyPattern.test(key)) {\n console.warn(`${logPrefix} Rejected invalid env var key: ${key}`);\n return false;\n }\n return true;\n });\n\n const fs = await getFs();\n let lines: string[] = [];\n try {\n lines = fs.readFileSync(envPath, \"utf-8\").split(\"\\n\");\n } catch {}\n\n for (const { key, value } of sanitizedVars) {\n // Strip newlines/null bytes to prevent line injection\n const safeValue = value.replace(/[\\r\\n\\0]/g, \"\");\n // Quote values containing #, spaces, or quotes so dotenv parses correctly\n const needsQuoting = /[# \"']/.test(safeValue);\n const quotedValue = needsQuoting\n ? `\"${safeValue.replace(/\"/g, '\\\\\"')}\"`\n : safeValue;\n const idx = lines.findIndex((l) => l.startsWith(`${key}=`));\n const entry = `${key}=${quotedValue}`;\n if (idx !== -1) {\n lines[idx] = entry;\n } else {\n lines.push(entry);\n }\n }\n\n while (lines.length > 0 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n fs.writeFileSync(envPath, lines.join(\"\\n\") + \"\\n\", \"utf-8\");\n\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(\n JSON.stringify({\n type: \"env-vars-saved\",\n keys: sanitizedVars.map((v) => v.key),\n }),\n );\n }\n return;\n }\n\n if (msg.type === \"resize\" && msg.cols != null && msg.rows != null) {\n const cols = Math.max(\n 1,\n Math.min(65535, Math.trunc(Number(msg.cols))),\n );\n const rows = Math.max(\n 1,\n Math.min(65535, Math.trunc(Number(msg.rows))),\n );\n if (!Number.isFinite(cols) || !Number.isFinite(rows)) return;\n ptyProcess.resize(cols, rows);\n return;\n }\n } catch {\n // Not JSON — regular terminal input\n }\n\n ptyProcess.write(str);\n });\n\n ws.on(\"close\", () => {\n console.log(\n `${logPrefix} WebSocket closed, killing PTY tree (pid: ${ptyProcess.pid})`,\n );\n activePtys.delete(ptyProcess);\n killProcessTree(ptyProcess.pid, logPrefix);\n });\n });\n\n return new Promise((resolve, reject) => {\n server.once(\"error\", (err) => {\n reject(err);\n });\n server.listen(port, \"127.0.0.1\", () => {\n const addr = server.address();\n const actualPort = typeof addr === \"object\" && addr ? addr.port : port;\n if (process.env.DEBUG)\n console.log(\n `${logPrefix} PTY WebSocket server on ws://localhost:${actualPort}/ws`,\n );\n\n resolve({\n server,\n port: actualPort,\n close: () => {\n for (const p of activePtys) {\n killProcessTree(p.pid, logPrefix);\n }\n activePtys.clear();\n wss.close();\n server.close();\n },\n });\n });\n });\n}\n"]}
1
+ {"version":3,"file":"pty-server.js","sourceRoot":"","sources":["../../src/terminal/pty-server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,YAAY,IAAI,gBAAgB,GAGjC,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,oEAAoE;AACpE,IAAI,GAA+C,CAAC;AACpD,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,GAAG,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,eAAe,CAAC,GAAW,EAAE,UAAkB;IAC5D,MAAM,EAAE,GAAG,MAAM,eAAe,EAAE,CAAC;IAEnC,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,EAAE,CAAC,QAAQ,CAAC,iBAAiB,GAAG,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO;IACT,CAAC;IAED,2DAA2D;IAC3D,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,SAAS,eAAe,CAAC,SAAiB;QACxC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,EAAE;iBACd,QAAQ,CAAC,YAAY,SAAS,EAAE,EAAE;gBACjC,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;aAClC,CAAC;iBACD,IAAI,EAAE,CAAC;YACV,IAAI,MAAM,EAAE,CAAC;gBACX,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBACpC,IAAI,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACjC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;wBAC3B,eAAe,CAAC,QAAQ,CAAC,CAAC;oBAC5B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gDAAgD;QAClD,CAAC;IACH,CAAC;IACD,eAAe,CAAC,GAAG,CAAC,CAAC;IAErB,0DAA0D;IAC1D,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,+CAA+C;IAC/C,UAAU,CAAC,GAAG,EAAE;QACd,KAAK,MAAM,QAAQ,IAAI,WAAW,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;QACZ,CAAC;QACD,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC,EAAE,GAAG,CAAC,CAAC;AACV,CAAC;AAwBD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,OAAO,GAAqB,EAAE;IAE9B,MAAM,EACJ,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,EACtB,OAAO,EAAE,cAAc,GAAG,QAAQ,EAClC,IAAI,GAAG,CAAC,EACR,SAAS,EACT,SAAS,GAAG,YAAY,GACzB,GAAG,OAAO,CAAC;IAEZ,mDAAmD;IACnD,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAErC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,KAAK,GACT,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,UAAU,CAAC;IAE1E,MAAM,MAAM,GAAG,gBAAgB,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3C,eAAe;QACf,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;QAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;QACpE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;QAE9D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACnB,GAAG,CAAC,GAAG,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpD,+CAA+C;IAC/C,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;QAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,IAAI,GAAG,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;YAC/C,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO;QACT,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;oBAClD,MAAM,CAAC,OAAO,EAAE,CAAC;oBACjB,OAAO;gBACT,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAC3D,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,OAAO;YACT,CAAC;QACH,CAAC;QAED,GAAG,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;YAC1C,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAgC,CAAC;IAE3D,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,EAAkC,EAAE,GAAG,EAAE,EAAE;QACrE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,cAAc,CAAC;QAClE,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,qCAAqC,OAAO,EAAE,CAAC,CAAC;QAExE,MAAM,UAAU,GAAG,CAAC,MAAc,EAAE,OAAe,EAAE,EAAE;YACrD,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACrC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YACrE,CAAC;QACH,CAAC,CAAC;QAEF,0DAA0D;QAC1D,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,UAAU,CACR,WAAW,EACX,IAAI,OAAO,uCAAuC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzF,CAAC;YACF,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;gBAAE,EAAE,CAAC,KAAK,EAAE,CAAC;YACjD,OAAO;QACT,CAAC;QAED,+CAA+C;QAC/C,IAAI,UAAU,IAAI,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACvD,UAAU,CAAC,QAAQ,EAAE,iDAAiD,CAAC,CAAC;YACxE,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;gBAAE,EAAE,CAAC,KAAK,EAAE,CAAC;YACjD,OAAO;QACT,CAAC;QAED,uDAAuD;QACvD,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,CAAC,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;YACvC,IAAI,QAAQ,EAAE,cAAc,EAAE,CAAC;gBAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,IAAI,OAAO,8BAA8B,CAAC,CAAC;gBACnE,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,UAAU,CACR,WAAW,EACX,IAAI,OAAO,kDAAkD,CAC9D,CAAC;gBACF,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;oBAAE,EAAE,CAAC,KAAK,EAAE,CAAC;gBACjD,OAAO;YACT,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,MAAM,WAAW,GAAG,MAAM;YACxB,CAAC,CAAC,aAAa,YAAY,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE;YACrD,CAAC,CAAC,OAAO,CAAC;QACZ,MAAM,WAAW,GAAG,UAAU;YAC5B,CAAC,CAAC,GAAG,WAAW,IAAI,UAAU,EAAE;YAChC,CAAC,CAAC,WAAW,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,kBAAkB,WAAW,EAAE,CAAC,CAAC;QAEzD,iDAAiD;QACjD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,GAAG,GAAuC;YAC9C,GAAG,OAAO,CAAC,GAAG;YACd,IAAI,EAAE,gBAAgB;SACvB,CAAC;QACF,IAAI,QAAQ,EAAE,CAAC;YACb,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ;gBAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;QAED,IAAI,UAAwC,CAAC;QAC7C,IAAI,CAAC;YACH,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE;gBACvD,IAAI,EAAE,gBAAgB;gBACtB,IAAI,EAAE,GAAG;gBACT,IAAI,EAAE,EAAE;gBACR,GAAG,EAAE,cAAc;gBACnB,GAAG,EAAE,GAA6B;aACnC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,GAAG,SAAS,uBAAuB,EAAE,GAAG,CAAC,CAAC;YACxD,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACrC,EAAE,CAAC,IAAI,CACL,eAAe,SAAS,yBAAyB,GAAG,aAAa,CAClE,CAAC;gBACF,EAAE,CAAC,KAAK,EAAE,CAAC;YACb,CAAC;YACD,OAAO;QACT,CAAC;QAED,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,sBAAsB,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC;QAEjE,UAAU,CAAC,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;YACjC,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACrC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;YACjC,OAAO,CAAC,GAAG,CAAC,GAAG,SAAS,yBAAyB,QAAQ,EAAE,CAAC,CAAC;YAC7D,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9B,IAAI,QAAQ,KAAK,GAAG,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACzD,EAAE,CAAC,IAAI,CACL,IAAI,CAAC,SAAS,CAAC;oBACb,IAAI,EAAE,cAAc;oBACpB,MAAM,EAAE,WAAW;oBACnB,OAAO,EAAE,YAAY,OAAO,uCAAuC;iBACpE,CAAC,CACH,CAAC;YACJ,CAAC;YACD,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACrC,EAAE,CAAC,KAAK,EAAE,CAAC;YACb,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,IAAqB,EAAE,EAAE;YAC/C,MAAM,GAAG,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YAE9D,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAE5B,IACE,GAAG,CAAC,IAAI,KAAK,wBAAwB;oBACrC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,EAC7B,CAAC;oBACD,MAAM,IAAI,GAA0C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;oBAElE,sEAAsE;oBACtE,yDAAyD;oBACzD,MAAM,eAAe,GAAG,0BAA0B,CAAC;oBACnD,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;wBAC5C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;4BAC/B,OAAO,CAAC,IAAI,CAAC,GAAG,SAAS,kCAAkC,GAAG,EAAE,CAAC,CAAC;4BAClE,OAAO,KAAK,CAAC;wBACf,CAAC;wBACD,OAAO,IAAI,CAAC;oBACd,CAAC,CAAC,CAAC;oBAEH,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;wBACrC,EAAE,CAAC,IAAI,CACL,IAAI,CAAC,SAAS,CAAC;4BACb,IAAI,EAAE,gBAAgB;4BACtB,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;4BACrC,OAAO,EAAE,gBAAgB;yBAC1B,CAAC,CACH,CAAC;oBACJ,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;oBAClE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CACnB,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAC9C,CAAC;oBACF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CACnB,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAC9C,CAAC;oBACF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;wBAAE,OAAO;oBAC7D,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBAC9B,OAAO;gBACT,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,oCAAoC;YACtC,CAAC;YAED,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,OAAO,CAAC,GAAG,CACT,GAAG,SAAS,6CAA6C,UAAU,CAAC,GAAG,GAAG,CAC3E,CAAC;YACF,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9B,eAAe,CAAC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YAC3B,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YAC9B,MAAM,UAAU,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACvE,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK;gBACnB,OAAO,CAAC,GAAG,CACT,GAAG,SAAS,2CAA2C,UAAU,KAAK,CACvE,CAAC;YAEJ,OAAO,CAAC;gBACN,MAAM;gBACN,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,GAAG,EAAE;oBACV,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;wBAC3B,eAAe,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;oBACpC,CAAC;oBACD,UAAU,CAAC,KAAK,EAAE,CAAC;oBACnB,GAAG,CAAC,KAAK,EAAE,CAAC;oBACZ,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,CAAC;aACF,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * PTY WebSocket Server\n *\n * Creates an HTTP server with WebSocket support that spawns PTY processes\n * for AI CLI tools. Each WebSocket connection gets its own PTY.\n *\n * Used by both the embedded AgentTerminal component and the CLI frame.\n */\n\nimport {\n createServer as createHttpServer,\n type IncomingMessage,\n type Server as HttpServer,\n} from \"http\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport {\n CLI_REGISTRY,\n commandExists,\n isAllowedCommand,\n} from \"./cli-registry.js\";\n\n// Lazy singletons for Node-only modules (only available in Node.js)\nlet _cp: typeof import(\"child_process\") | undefined;\nasync function getChildProcess(): Promise<typeof import(\"child_process\")> {\n if (!_cp) {\n _cp = await import(\"node:child_process\");\n }\n return _cp;\n}\n\n/**\n * Kill a process and all its descendants.\n * node-pty's kill() only sends a signal to the shell, but child processes\n * (like `builder`) may be in their own process group and survive as orphans.\n */\nasync function killProcessTree(pid: number, _logPrefix: string): Promise<void> {\n const cp = await getChildProcess();\n\n if (os.platform() === \"win32\") {\n try {\n cp.execSync(`taskkill /pid ${pid} /T /F`, { stdio: \"ignore\" });\n } catch {}\n return;\n }\n\n // Find all descendant PIDs (children, grandchildren, etc.)\n const descendants: number[] = [];\n function findDescendants(parentPid: number) {\n try {\n const output = cp\n .execSync(`pgrep -P ${parentPid}`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n })\n .trim();\n if (output) {\n for (const line of output.split(\"\\n\")) {\n const childPid = parseInt(line, 10);\n if (childPid && !isNaN(childPid)) {\n descendants.push(childPid);\n findDescendants(childPid);\n }\n }\n }\n } catch {\n // pgrep returns non-zero when no children found\n }\n }\n findDescendants(pid);\n\n // Kill descendants first (deepest first), then the parent\n for (const childPid of descendants.reverse()) {\n try {\n process.kill(childPid, \"SIGTERM\");\n } catch {}\n }\n\n try {\n process.kill(pid, \"SIGTERM\");\n } catch {}\n\n // Force-kill any survivors after a short delay\n setTimeout(() => {\n for (const childPid of descendants) {\n try {\n process.kill(childPid, \"SIGKILL\");\n } catch {}\n }\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {}\n }, 500);\n}\n\nexport interface PtyServerOptions {\n /** Working directory for PTY processes. Defaults to process.cwd() */\n appDir?: string;\n /** Default CLI command. Defaults to 'claude' */\n command?: string;\n /** Port to listen on. Defaults to 0 (random available port) */\n port?: number;\n /** Auth check for WebSocket upgrade requests. Return false to reject. */\n authCheck?: (req: IncomingMessage) => boolean | Promise<boolean>;\n /** Log prefix for console output. Defaults to '[terminal]' */\n logPrefix?: string;\n}\n\nexport interface PtyServerResult {\n /** The underlying HTTP server */\n server: HttpServer;\n /** The actual port the server is listening on */\n port: number;\n /** Shut down the server and kill all PTY processes */\n close: () => void;\n}\n\nexport async function createPtyWebSocketServer(\n options: PtyServerOptions = {},\n): Promise<PtyServerResult> {\n const {\n appDir = process.cwd(),\n command: defaultCommand = \"claude\",\n port = 0,\n authCheck,\n logPrefix = \"[terminal]\",\n } = options;\n\n // Dynamic imports for optional native dependencies\n const { WebSocketServer, WebSocket } = await import(\"ws\");\n const pty = await import(\"node-pty\");\n\n const resolvedAppDir = path.resolve(appDir);\n const shell =\n os.platform() === \"win32\" ? \"cmd.exe\" : process.env.SHELL || \"/bin/zsh\";\n\n const server = createHttpServer((req, res) => {\n // CORS headers\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n res.writeHead(404);\n res.end();\n });\n\n const wss = new WebSocketServer({ noServer: true });\n\n // Handle WebSocket upgrades with optional auth\n server.on(\"upgrade\", async (req, socket, head) => {\n const url = new URL(req.url || \"/\", `http://${req.headers.host}`);\n if (url.pathname !== \"/ws\") {\n socket.write(\"HTTP/1.1 404 Not Found\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n if (authCheck) {\n try {\n const allowed = await authCheck(req);\n if (!allowed) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n } catch {\n socket.write(\"HTTP/1.1 500 Internal Server Error\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit(\"connection\", ws, req);\n });\n });\n\n // Track active PTY processes for cleanup\n const activePtys = new Set<ReturnType<typeof pty.spawn>>();\n\n wss.on(\"connection\", async (ws: InstanceType<typeof WebSocket>, req) => {\n const url = new URL(req.url || \"\", `http://${req.headers.host}`);\n const command = url.searchParams.get(\"command\") || defaultCommand;\n const extraFlags = url.searchParams.get(\"flags\") || \"\";\n console.log(`${logPrefix} WebSocket connected for command: ${command}`);\n\n const sendStatus = (status: string, message: string) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: \"setup-status\", status, message }));\n }\n };\n\n // Validate command against allowlist to prevent injection\n if (!isAllowedCommand(command)) {\n sendStatus(\n \"not-found\",\n `\"${command}\" is not a recognized CLI. Allowed: ${Object.keys(CLI_REGISTRY).join(\", \")}`,\n );\n if (ws.readyState === WebSocket.OPEN) ws.close();\n return;\n }\n\n // Reject flags containing shell metacharacters\n if (extraFlags && /[;&|`$(){}\\n\\r<>]/.test(extraFlags)) {\n sendStatus(\"failed\", \"Invalid flags: shell metacharacters not allowed\");\n if (ws.readyState === WebSocket.OPEN) ws.close();\n return;\n }\n\n // Check if CLI is installed; if not, use npx to run it\n let useNpx = false;\n if (!(await commandExists(command))) {\n const registry = CLI_REGISTRY[command];\n if (registry?.installPackage) {\n console.log(`${logPrefix} ${command} CLI not found, will use npx`);\n useNpx = true;\n } else {\n sendStatus(\n \"not-found\",\n `\"${command}\" not found on PATH. Please install it manually.`,\n );\n if (ws.readyState === WebSocket.OPEN) ws.close();\n return;\n }\n }\n\n // Build the command — use npx if CLI not found locally\n const baseCommand = useNpx\n ? `npx --yes ${CLI_REGISTRY[command].installPackage}`\n : command;\n const fullCommand = extraFlags\n ? `${baseCommand} ${extraFlags}`\n : baseCommand;\n console.log(`${logPrefix} Spawning PTY: ${fullCommand}`);\n\n // Build env, stripping CLI-specific nesting vars\n const registry = CLI_REGISTRY[command];\n const env: Record<string, string | undefined> = {\n ...process.env,\n TERM: \"xterm-256color\",\n };\n if (registry) {\n for (const v of registry.stripEnv) delete env[v];\n }\n\n let ptyProcess: ReturnType<typeof pty.spawn>;\n try {\n ptyProcess = pty.spawn(shell, [\"-l\", \"-c\", fullCommand], {\n name: \"xterm-256color\",\n cols: 120,\n rows: 40,\n cwd: resolvedAppDir,\n env: env as Record<string, string>,\n });\n } catch (err) {\n console.error(`${logPrefix} Failed to spawn PTY:`, err);\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(\n `\\r\\n\\x1b[31m${logPrefix} Failed to spawn PTY: ${err}\\x1b[0m\\r\\n`,\n );\n ws.close();\n }\n return;\n }\n\n activePtys.add(ptyProcess);\n console.log(`${logPrefix} PTY spawned (pid: ${ptyProcess.pid})`);\n\n ptyProcess.onData((data: string) => {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(data);\n }\n });\n\n ptyProcess.onExit(({ exitCode }) => {\n console.log(`${logPrefix} PTY exited with code ${exitCode}`);\n activePtys.delete(ptyProcess);\n if (exitCode === 127 && ws.readyState === WebSocket.OPEN) {\n ws.send(\n JSON.stringify({\n type: \"setup-status\",\n status: \"not-found\",\n message: `Command \"${command}\" not found. Please install it first.`,\n }),\n );\n }\n if (ws.readyState === WebSocket.OPEN) {\n ws.close();\n }\n });\n\n ws.on(\"message\", async (data: Buffer | string) => {\n const str = typeof data === \"string\" ? data : data.toString();\n\n try {\n const msg = JSON.parse(str);\n\n if (\n msg.type === \"agentNative.setEnvVars\" &&\n Array.isArray(msg.data?.vars)\n ) {\n const vars: Array<{ key: string; value: string }> = msg.data.vars;\n\n // Legacy bridge message. Keep validating the keys, but do not persist\n // them to .env or process.env; key storage is DB-scoped.\n const validKeyPattern = /^[A-Za-z_][A-Za-z0-9_]*$/;\n const sanitizedVars = vars.filter(({ key }) => {\n if (!validKeyPattern.test(key)) {\n console.warn(`${logPrefix} Rejected invalid env var key: ${key}`);\n return false;\n }\n return true;\n });\n\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(\n JSON.stringify({\n type: \"env-vars-saved\",\n keys: sanitizedVars.map((v) => v.key),\n storage: \"scoped-secrets\",\n }),\n );\n }\n return;\n }\n\n if (msg.type === \"resize\" && msg.cols != null && msg.rows != null) {\n const cols = Math.max(\n 1,\n Math.min(65535, Math.trunc(Number(msg.cols))),\n );\n const rows = Math.max(\n 1,\n Math.min(65535, Math.trunc(Number(msg.rows))),\n );\n if (!Number.isFinite(cols) || !Number.isFinite(rows)) return;\n ptyProcess.resize(cols, rows);\n return;\n }\n } catch {\n // Not JSON — regular terminal input\n }\n\n ptyProcess.write(str);\n });\n\n ws.on(\"close\", () => {\n console.log(\n `${logPrefix} WebSocket closed, killing PTY tree (pid: ${ptyProcess.pid})`,\n );\n activePtys.delete(ptyProcess);\n killProcessTree(ptyProcess.pid, logPrefix);\n });\n });\n\n return new Promise((resolve, reject) => {\n server.once(\"error\", (err) => {\n reject(err);\n });\n server.listen(port, \"127.0.0.1\", () => {\n const addr = server.address();\n const actualPort = typeof addr === \"object\" && addr ? addr.port : port;\n if (process.env.DEBUG)\n console.log(\n `${logPrefix} PTY WebSocket server on ws://localhost:${actualPort}/ws`,\n );\n\n resolve({\n server,\n port: actualPort,\n close: () => {\n for (const p of activePtys) {\n killProcessTree(p.pid, logPrefix);\n }\n activePtys.clear();\n wss.close();\n server.close();\n },\n });\n });\n });\n}\n"]}
@@ -209,7 +209,7 @@ async function handleEvent(eventName, payload, eventMeta) {
209
209
  // Resolve API key for condition evaluation
210
210
  const owner = meta.createdBy || resource.owner;
211
211
  const userApiKey = await getOwnerActiveApiKey(owner);
212
- const apiKey = userApiKey || _deps.apiKey || process.env.ANTHROPIC_API_KEY;
212
+ const apiKey = userApiKey || _deps.apiKey;
213
213
  if (!apiKey) {
214
214
  console.warn(`[triggers] No API key for trigger "${resource.path}" — skipping`);
215
215
  continue;