@agent-native/core 0.47.1 → 0.48.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 (808) hide show
  1. package/bin/agent-native.js +41 -0
  2. package/dist/a2a/handlers.js +2 -2
  3. package/dist/a2a/handlers.js.map +1 -1
  4. package/dist/a2a/server.js +2 -2
  5. package/dist/a2a/server.js.map +1 -1
  6. package/dist/action.d.ts +43 -2
  7. package/dist/action.d.ts.map +1 -1
  8. package/dist/action.js.map +1 -1
  9. package/dist/agent/context-xray/actions/context-evict.d.ts +7 -1
  10. package/dist/agent/context-xray/actions/context-evict.d.ts.map +1 -1
  11. package/dist/agent/context-xray/actions/context-manifest-get.d.ts +4 -1
  12. package/dist/agent/context-xray/actions/context-manifest-get.d.ts.map +1 -1
  13. package/dist/agent/context-xray/actions/context-pin.d.ts +7 -1
  14. package/dist/agent/context-xray/actions/context-pin.d.ts.map +1 -1
  15. package/dist/agent/context-xray/actions/context-report.d.ts +12 -1
  16. package/dist/agent/context-xray/actions/context-report.d.ts.map +1 -1
  17. package/dist/agent/context-xray/actions/context-restore.d.ts +7 -1
  18. package/dist/agent/context-xray/actions/context-restore.d.ts.map +1 -1
  19. package/dist/agent/context-xray/apply-directives.d.ts.map +1 -1
  20. package/dist/agent/context-xray/apply-directives.js.map +1 -1
  21. package/dist/agent/context-xray/schema.d.ts +10 -10
  22. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  23. package/dist/agent/engine/ai-sdk-engine.js +26 -3
  24. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  25. package/dist/agent/engine/anthropic-engine.d.ts +1 -1
  26. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  27. package/dist/agent/engine/builder-engine.d.ts +1 -1
  28. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  29. package/dist/agent/engine/builder-engine.js +47 -8
  30. package/dist/agent/engine/builder-engine.js.map +1 -1
  31. package/dist/agent/engine/builtin.js +1 -1
  32. package/dist/agent/engine/builtin.js.map +1 -1
  33. package/dist/agent/engine/output-tokens.d.ts +1 -1
  34. package/dist/agent/engine/output-tokens.d.ts.map +1 -1
  35. package/dist/agent/engine/output-tokens.js +6 -2
  36. package/dist/agent/engine/output-tokens.js.map +1 -1
  37. package/dist/agent/engine/registry.d.ts.map +1 -1
  38. package/dist/agent/engine/registry.js +7 -4
  39. package/dist/agent/engine/registry.js.map +1 -1
  40. package/dist/agent/engine/types.d.ts +19 -0
  41. package/dist/agent/engine/types.d.ts.map +1 -1
  42. package/dist/agent/engine/types.js +6 -0
  43. package/dist/agent/engine/types.js.map +1 -1
  44. package/dist/agent/model-config.d.ts +22 -14
  45. package/dist/agent/model-config.d.ts.map +1 -1
  46. package/dist/agent/model-config.js +113 -8
  47. package/dist/agent/model-config.js.map +1 -1
  48. package/dist/agent/production-agent.d.ts +19 -1
  49. package/dist/agent/production-agent.d.ts.map +1 -1
  50. package/dist/agent/production-agent.js +253 -39
  51. package/dist/agent/production-agent.js.map +1 -1
  52. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  53. package/dist/agent/run-loop-with-resume.js +10 -0
  54. package/dist/agent/run-loop-with-resume.js.map +1 -1
  55. package/dist/agent/run-manager.d.ts +1 -0
  56. package/dist/agent/run-manager.d.ts.map +1 -1
  57. package/dist/agent/run-manager.js +36 -9
  58. package/dist/agent/run-manager.js.map +1 -1
  59. package/dist/agent/run-store.d.ts +47 -4
  60. package/dist/agent/run-store.d.ts.map +1 -1
  61. package/dist/agent/run-store.js +154 -4
  62. package/dist/agent/run-store.js.map +1 -1
  63. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  64. package/dist/agent/thread-data-builder.js +57 -2
  65. package/dist/agent/thread-data-builder.js.map +1 -1
  66. package/dist/agent/types.d.ts +3 -0
  67. package/dist/agent/types.d.ts.map +1 -1
  68. package/dist/agent/types.js.map +1 -1
  69. package/dist/agent-web/generator.d.ts +3 -3
  70. package/dist/appearance/actions/change-appearance.d.ts +6 -1
  71. package/dist/appearance/actions/change-appearance.d.ts.map +1 -1
  72. package/dist/application-state/handlers.d.ts +2 -2
  73. package/dist/application-state/handlers.d.ts.map +1 -1
  74. package/dist/application-state/store.d.ts.map +1 -1
  75. package/dist/application-state/store.js +17 -0
  76. package/dist/application-state/store.js.map +1 -1
  77. package/dist/catalog.json +2 -1
  78. package/dist/cli/code-agent-commands.d.ts.map +1 -1
  79. package/dist/cli/code-agent-commands.js +2 -0
  80. package/dist/cli/code-agent-commands.js.map +1 -1
  81. package/dist/cli/code-agent-connector.js +7 -13
  82. package/dist/cli/code-agent-connector.js.map +1 -1
  83. package/dist/cli/code-agent-executor.d.ts +54 -2
  84. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  85. package/dist/cli/code-agent-executor.js +504 -48
  86. package/dist/cli/code-agent-executor.js.map +1 -1
  87. package/dist/cli/code-agent-runs.d.ts +13 -0
  88. package/dist/cli/code-agent-runs.d.ts.map +1 -1
  89. package/dist/cli/code-agent-runs.js +36 -0
  90. package/dist/cli/code-agent-runs.js.map +1 -1
  91. package/dist/cli/code.js +59 -5
  92. package/dist/cli/code.js.map +1 -1
  93. package/dist/cli/connect.js +141 -3
  94. package/dist/cli/connect.js.map +1 -1
  95. package/dist/cli/index.js +0 -0
  96. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  97. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  98. package/dist/cli/recap.js +476 -46
  99. package/dist/cli/recap.js.map +1 -1
  100. package/dist/cli/skills.js +298 -179
  101. package/dist/cli/skills.js.map +1 -1
  102. package/dist/client/AgentPanel.d.ts.map +1 -1
  103. package/dist/client/AgentPanel.js +29 -2
  104. package/dist/client/AgentPanel.js.map +1 -1
  105. package/dist/client/AgentTaskCard.d.ts.map +1 -1
  106. package/dist/client/AgentTaskCard.js +17 -2
  107. package/dist/client/AgentTaskCard.js.map +1 -1
  108. package/dist/client/AssistantChat.d.ts +1 -1
  109. package/dist/client/AssistantChat.d.ts.map +1 -1
  110. package/dist/client/AssistantChat.js +310 -1732
  111. package/dist/client/AssistantChat.js.map +1 -1
  112. package/dist/client/CommandMenu.d.ts +1 -1
  113. package/dist/client/CommandMenu.d.ts.map +1 -1
  114. package/dist/client/CommandMenu.js +1 -1
  115. package/dist/client/CommandMenu.js.map +1 -1
  116. package/dist/client/HighlightedCodeBlock.d.ts +40 -0
  117. package/dist/client/HighlightedCodeBlock.d.ts.map +1 -0
  118. package/dist/client/HighlightedCodeBlock.js +110 -0
  119. package/dist/client/HighlightedCodeBlock.js.map +1 -0
  120. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  121. package/dist/client/MultiTabAssistantChat.js +8 -1
  122. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  123. package/dist/client/PoweredByBadge.d.ts +2 -2
  124. package/dist/client/PoweredByBadge.d.ts.map +1 -1
  125. package/dist/client/RunStuckBanner.d.ts +1 -1
  126. package/dist/client/RunStuckBanner.d.ts.map +1 -1
  127. package/dist/client/StarfieldBackground.d.ts.map +1 -1
  128. package/dist/client/StarfieldBackground.js +10 -5
  129. package/dist/client/StarfieldBackground.js.map +1 -1
  130. package/dist/client/Turnstile.d.ts +1 -1
  131. package/dist/client/Turnstile.d.ts.map +1 -1
  132. package/dist/client/agent-chat-adapter.d.ts +3 -2
  133. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  134. package/dist/client/agent-chat-adapter.js +13 -9
  135. package/dist/client/agent-chat-adapter.js.map +1 -1
  136. package/dist/client/app-providers.d.ts +99 -0
  137. package/dist/client/app-providers.d.ts.map +1 -0
  138. package/dist/client/app-providers.js +19 -0
  139. package/dist/client/app-providers.js.map +1 -0
  140. package/dist/client/assistant-ui-recovery.d.ts +1 -1
  141. package/dist/client/auth-redirect-url.d.ts +1 -1
  142. package/dist/client/auth-redirect-url.d.ts.map +1 -1
  143. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts +0 -19
  144. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  145. package/dist/client/blocks/library/AnnotatedCodeBlock.js +141 -55
  146. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  147. package/dist/client/blocks/library/DiffBlock.js +1 -1
  148. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  149. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
  150. package/dist/client/blocks/library/FileTreeBlock.js +1 -1
  151. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
  152. package/dist/client/blocks/library/HighlightedCode.d.ts.map +1 -1
  153. package/dist/client/blocks/library/HighlightedCode.js +5 -3
  154. package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
  155. package/dist/client/blocks/library/annotation-rail.d.ts +5 -4
  156. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  157. package/dist/client/blocks/library/annotation-rail.js +22 -3
  158. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  159. package/dist/client/blocks/library/diagram.js +1 -1
  160. package/dist/client/blocks/library/diagram.js.map +1 -1
  161. package/dist/client/blocks/library/diff.config.d.ts +3 -2
  162. package/dist/client/blocks/library/diff.config.d.ts.map +1 -1
  163. package/dist/client/blocks/library/diff.config.js +4 -3
  164. package/dist/client/blocks/library/diff.config.js.map +1 -1
  165. package/dist/client/blocks/library/question-form.d.ts.map +1 -1
  166. package/dist/client/blocks/library/question-form.js +2 -1
  167. package/dist/client/blocks/library/question-form.js.map +1 -1
  168. package/dist/client/blocks/library/wireframe-kit.d.ts +1 -1
  169. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
  170. package/dist/client/blocks/library/wireframe.js +1 -1
  171. package/dist/client/blocks/library/wireframe.js.map +1 -1
  172. package/dist/client/chat/attachment-adapters.d.ts +58 -0
  173. package/dist/client/chat/attachment-adapters.d.ts.map +1 -0
  174. package/dist/client/chat/attachment-adapters.js +331 -0
  175. package/dist/client/chat/attachment-adapters.js.map +1 -0
  176. package/dist/client/chat/index.d.ts +13 -0
  177. package/dist/client/chat/index.d.ts.map +1 -0
  178. package/dist/client/chat/index.js +13 -0
  179. package/dist/client/chat/index.js.map +1 -0
  180. package/dist/client/chat/markdown-renderer.d.ts +49 -0
  181. package/dist/client/chat/markdown-renderer.d.ts.map +1 -0
  182. package/dist/client/chat/markdown-renderer.js +391 -0
  183. package/dist/client/chat/markdown-renderer.js.map +1 -0
  184. package/dist/client/chat/message-components.d.ts +35 -0
  185. package/dist/client/chat/message-components.d.ts.map +1 -0
  186. package/dist/client/chat/message-components.js +452 -0
  187. package/dist/client/chat/message-components.js.map +1 -0
  188. package/dist/client/chat/repo-helpers.d.ts +41 -0
  189. package/dist/client/chat/repo-helpers.d.ts.map +1 -0
  190. package/dist/client/chat/repo-helpers.js +61 -0
  191. package/dist/client/chat/repo-helpers.js.map +1 -0
  192. package/dist/client/chat/run-recovery.d.ts +41 -0
  193. package/dist/client/chat/run-recovery.d.ts.map +1 -0
  194. package/dist/client/chat/run-recovery.js +348 -0
  195. package/dist/client/chat/run-recovery.js.map +1 -0
  196. package/dist/client/chat/tool-call-display.d.ts +34 -0
  197. package/dist/client/chat/tool-call-display.d.ts.map +1 -0
  198. package/dist/client/chat/tool-call-display.js +284 -0
  199. package/dist/client/chat/tool-call-display.js.map +1 -0
  200. package/dist/client/code-agent-chat-adapter.d.ts.map +1 -1
  201. package/dist/client/code-agent-chat-adapter.js +20 -0
  202. package/dist/client/code-agent-chat-adapter.js.map +1 -1
  203. package/dist/client/collab/index.d.ts +10 -0
  204. package/dist/client/collab/index.d.ts.map +1 -0
  205. package/dist/client/collab/index.js +10 -0
  206. package/dist/client/collab/index.js.map +1 -0
  207. package/dist/client/components/AgentPresenceChip.d.ts +1 -1
  208. package/dist/client/components/AgentPresenceChip.d.ts.map +1 -1
  209. package/dist/client/components/ApiKeySettings.d.ts +1 -1
  210. package/dist/client/components/ApiKeySettings.d.ts.map +1 -1
  211. package/dist/client/components/CodeAgentIndicator.d.ts +1 -1
  212. package/dist/client/components/CodeAgentIndicator.d.ts.map +1 -1
  213. package/dist/client/components/CodeRequiredDialog.d.ts +1 -1
  214. package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
  215. package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
  216. package/dist/client/components/LiveCursorOverlay.js.map +1 -1
  217. package/dist/client/components/PresenceBar.d.ts +1 -1
  218. package/dist/client/components/PresenceBar.d.ts.map +1 -1
  219. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  220. package/dist/client/composer/PromptComposer.js +6 -26
  221. package/dist/client/composer/PromptComposer.js.map +1 -1
  222. package/dist/client/composer/TiptapComposer.d.ts +8 -2
  223. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  224. package/dist/client/composer/TiptapComposer.js +21 -9
  225. package/dist/client/composer/TiptapComposer.js.map +1 -1
  226. package/dist/client/composer/VoiceButton.d.ts +2 -2
  227. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  228. package/dist/client/composer/index.d.ts +1 -1
  229. package/dist/client/composer/index.d.ts.map +1 -1
  230. package/dist/client/composer/index.js +1 -1
  231. package/dist/client/composer/index.js.map +1 -1
  232. package/dist/client/composer/use-skills.d.ts +1 -1
  233. package/dist/client/context-xray/ContextMeter.d.ts +1 -1
  234. package/dist/client/context-xray/ContextMeter.d.ts.map +1 -1
  235. package/dist/client/context-xray/ContextMeter.js +3 -3
  236. package/dist/client/context-xray/ContextMeter.js.map +1 -1
  237. package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
  238. package/dist/client/context-xray/ContextXRayPanel.js +4 -3
  239. package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
  240. package/dist/client/context-xray/format.d.ts +11 -0
  241. package/dist/client/context-xray/format.d.ts.map +1 -1
  242. package/dist/client/context-xray/format.js +16 -0
  243. package/dist/client/context-xray/format.js.map +1 -1
  244. package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
  245. package/dist/client/conversation/AgentConversation.js +8 -53
  246. package/dist/client/conversation/AgentConversation.js.map +1 -1
  247. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +1 -1
  248. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
  249. package/dist/client/conversation/use-near-bottom-autoscroll.js +14 -1
  250. package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
  251. package/dist/client/create-query-client.d.ts +28 -0
  252. package/dist/client/create-query-client.d.ts.map +1 -0
  253. package/dist/client/create-query-client.js +78 -0
  254. package/dist/client/create-query-client.js.map +1 -0
  255. package/dist/client/db-admin/DevDatabaseLink.d.ts +1 -1
  256. package/dist/client/db-admin/DevDatabaseLink.d.ts.map +1 -1
  257. package/dist/client/db-admin/RowSidePanel.d.ts +1 -1
  258. package/dist/client/db-admin/RowSidePanel.d.ts.map +1 -1
  259. package/dist/client/db-admin/RowSidePanel.js +2 -2
  260. package/dist/client/db-admin/RowSidePanel.js.map +1 -1
  261. package/dist/client/db-admin/TableEditor.d.ts +1 -1
  262. package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
  263. package/dist/client/db-admin/TableEditor.js +1 -1
  264. package/dist/client/db-admin/TableEditor.js.map +1 -1
  265. package/dist/client/db-admin/cell-format.d.ts +1 -1
  266. package/dist/client/db-admin/cell-format.d.ts.map +1 -1
  267. package/dist/client/dev-overlay/DevOverlay.d.ts +1 -1
  268. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  269. package/dist/client/editor/index.d.ts +2 -0
  270. package/dist/client/editor/index.d.ts.map +1 -0
  271. package/dist/client/editor/index.js +2 -0
  272. package/dist/client/editor/index.js.map +1 -0
  273. package/dist/client/error-format.d.ts.map +1 -1
  274. package/dist/client/error-format.js +4 -0
  275. package/dist/client/error-format.js.map +1 -1
  276. package/dist/client/extensions/AgentNativeExtensionFrame.d.ts +1 -1
  277. package/dist/client/extensions/AgentNativeExtensionFrame.d.ts.map +1 -1
  278. package/dist/client/extensions/EmbeddedExtension.d.ts +1 -1
  279. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  280. package/dist/client/extensions/ExtensionSlot.d.ts +1 -1
  281. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  282. package/dist/client/extensions/ExtensionViewerPage.d.ts +1 -1
  283. package/dist/client/extensions/ExtensionViewerPage.d.ts.map +1 -1
  284. package/dist/client/guided-questions.d.ts +6 -6
  285. package/dist/client/host-bridge.d.ts.map +1 -1
  286. package/dist/client/host-bridge.js +2 -0
  287. package/dist/client/host-bridge.js.map +1 -1
  288. package/dist/client/index.d.ts +7 -6
  289. package/dist/client/index.d.ts.map +1 -1
  290. package/dist/client/index.js +5 -3
  291. package/dist/client/index.js.map +1 -1
  292. package/dist/client/onboarding/OnboardingBanner.d.ts +1 -1
  293. package/dist/client/onboarding/OnboardingBanner.d.ts.map +1 -1
  294. package/dist/client/onboarding/OnboardingPanel.d.ts +1 -1
  295. package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
  296. package/dist/client/onboarding/SetupButton.d.ts +1 -1
  297. package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
  298. package/dist/client/org/InvitationBanner.d.ts +1 -1
  299. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  300. package/dist/client/org/OrgSwitcher.d.ts +1 -1
  301. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  302. package/dist/client/org/RequireActiveOrg.d.ts +1 -1
  303. package/dist/client/org/RequireActiveOrg.d.ts.map +1 -1
  304. package/dist/client/org/hooks.d.ts +3 -3
  305. package/dist/client/org/hooks.d.ts.map +1 -1
  306. package/dist/client/progress/RunsTray.d.ts +2 -2
  307. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  308. package/dist/client/progress/RunsTray.js +34 -9
  309. package/dist/client/progress/RunsTray.js.map +1 -1
  310. package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
  311. package/dist/client/resources/ResourceEditor.js +1 -1
  312. package/dist/client/resources/ResourceEditor.js.map +1 -1
  313. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  314. package/dist/client/resources/ResourcesPanel.js +2 -0
  315. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  316. package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts +1 -1
  317. package/dist/client/rich-markdown-editor/BubbleToolbar.d.ts.map +1 -1
  318. package/dist/client/rich-markdown-editor/CodeBlockNode.d.ts.map +1 -1
  319. package/dist/client/rich-markdown-editor/CodeBlockNode.js +2 -1
  320. package/dist/client/rich-markdown-editor/CodeBlockNode.js.map +1 -1
  321. package/dist/client/rich-markdown-editor/ImageExtension.d.ts.map +1 -1
  322. package/dist/client/rich-markdown-editor/ImageExtension.js +2 -1
  323. package/dist/client/rich-markdown-editor/ImageExtension.js.map +1 -1
  324. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +1 -1
  325. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
  326. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +1 -1
  327. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  328. package/dist/client/rich-markdown-editor/RichMarkdownEditor.d.ts +1 -1
  329. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
  330. package/dist/client/rich-markdown-editor/SharedRichEditor.js +2 -3
  331. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
  332. package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts +1 -1
  333. package/dist/client/rich-markdown-editor/SlashCommandMenu.d.ts.map +1 -1
  334. package/dist/client/route-state.d.ts +12 -2
  335. package/dist/client/route-state.d.ts.map +1 -1
  336. package/dist/client/route-state.js +1 -1
  337. package/dist/client/route-state.js.map +1 -1
  338. package/dist/client/route-warmup.d.ts +1 -1
  339. package/dist/client/route-warmup.d.ts.map +1 -1
  340. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  341. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  342. package/dist/client/settings/useBuilderStatus.d.ts +2 -2
  343. package/dist/client/sharing/ShareDialog.d.ts +1 -1
  344. package/dist/client/sharing/ShareDialog.d.ts.map +1 -1
  345. package/dist/client/sse-event-processor.d.ts +8 -0
  346. package/dist/client/sse-event-processor.d.ts.map +1 -1
  347. package/dist/client/sse-event-processor.js +33 -10
  348. package/dist/client/sse-event-processor.js.map +1 -1
  349. package/dist/client/terminal/AgentTerminal.d.ts +1 -1
  350. package/dist/client/terminal/AgentTerminal.d.ts.map +1 -1
  351. package/dist/client/terminal/AgentTerminal.js +4 -2
  352. package/dist/client/terminal/AgentTerminal.js.map +1 -1
  353. package/dist/client/tool-cells/BashCell.d.ts +25 -0
  354. package/dist/client/tool-cells/BashCell.d.ts.map +1 -0
  355. package/dist/client/tool-cells/BashCell.js +49 -0
  356. package/dist/client/tool-cells/BashCell.js.map +1 -0
  357. package/dist/client/tool-cells/EditCell.d.ts +24 -0
  358. package/dist/client/tool-cells/EditCell.d.ts.map +1 -0
  359. package/dist/client/tool-cells/EditCell.js +126 -0
  360. package/dist/client/tool-cells/EditCell.js.map +1 -0
  361. package/dist/client/tool-cells/FilesChangedSummary.d.ts +13 -0
  362. package/dist/client/tool-cells/FilesChangedSummary.d.ts.map +1 -0
  363. package/dist/client/tool-cells/FilesChangedSummary.js +98 -0
  364. package/dist/client/tool-cells/FilesChangedSummary.js.map +1 -0
  365. package/dist/client/tool-cells/WriteCell.d.ts +17 -0
  366. package/dist/client/tool-cells/WriteCell.d.ts.map +1 -0
  367. package/dist/client/tool-cells/WriteCell.js +26 -0
  368. package/dist/client/tool-cells/WriteCell.js.map +1 -0
  369. package/dist/client/tool-cells/index.d.ts +8 -0
  370. package/dist/client/tool-cells/index.d.ts.map +1 -0
  371. package/dist/client/tool-cells/index.js +5 -0
  372. package/dist/client/tool-cells/index.js.map +1 -0
  373. package/dist/client/transcription/BuilderTranscriptionCta.d.ts +1 -1
  374. package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -1
  375. package/dist/client/use-chat-threads.d.ts +1 -1
  376. package/dist/client/use-chat-threads.d.ts.map +1 -1
  377. package/dist/client/use-chat-threads.js +11 -8
  378. package/dist/client/use-chat-threads.js.map +1 -1
  379. package/dist/client/use-db-sync.d.ts +2 -0
  380. package/dist/client/use-db-sync.d.ts.map +1 -1
  381. package/dist/client/use-db-sync.js +329 -302
  382. package/dist/client/use-db-sync.js.map +1 -1
  383. package/dist/code-agents/transcript-normalizer.d.ts +15 -1
  384. package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
  385. package/dist/code-agents/transcript-normalizer.js +47 -0
  386. package/dist/code-agents/transcript-normalizer.js.map +1 -1
  387. package/dist/coding-tools/index.d.ts +75 -0
  388. package/dist/coding-tools/index.d.ts.map +1 -1
  389. package/dist/coding-tools/index.js +137 -10
  390. package/dist/coding-tools/index.js.map +1 -1
  391. package/dist/collab/client.d.ts +1 -1
  392. package/dist/collab/client.js +20 -14
  393. package/dist/collab/client.js.map +1 -1
  394. package/dist/collab/ydoc-manager.d.ts +1 -1
  395. package/dist/collab/ydoc-manager.d.ts.map +1 -1
  396. package/dist/collab/ydoc-manager.js +1 -1
  397. package/dist/collab/ydoc-manager.js.map +1 -1
  398. package/dist/db/client.d.ts +9 -1
  399. package/dist/db/client.d.ts.map +1 -1
  400. package/dist/db/client.js +204 -48
  401. package/dist/db/client.js.map +1 -1
  402. package/dist/db/create-get-db.d.ts +38 -0
  403. package/dist/db/create-get-db.d.ts.map +1 -1
  404. package/dist/db/create-get-db.js +204 -4
  405. package/dist/db/create-get-db.js.map +1 -1
  406. package/dist/db/migrations.d.ts.map +1 -1
  407. package/dist/db/migrations.js +159 -67
  408. package/dist/db/migrations.js.map +1 -1
  409. package/dist/demo/actions/toggle-demo-mode.d.ts +6 -1
  410. package/dist/demo/actions/toggle-demo-mode.d.ts.map +1 -1
  411. package/dist/deploy/build.d.ts.map +1 -1
  412. package/dist/deploy/build.js +80 -39
  413. package/dist/deploy/build.js.map +1 -1
  414. package/dist/deploy/workspace-deploy.js +20 -10
  415. package/dist/deploy/workspace-deploy.js.map +1 -1
  416. package/dist/extensions/schema.d.ts +51 -51
  417. package/dist/extensions/slots/schema.d.ts +13 -13
  418. package/dist/file-upload/actions/upload-image.d.ts +26 -1
  419. package/dist/file-upload/actions/upload-image.d.ts.map +1 -1
  420. package/dist/file-upload/index.d.ts +1 -1
  421. package/dist/file-upload/index.d.ts.map +1 -1
  422. package/dist/file-upload/index.js +1 -1
  423. package/dist/file-upload/index.js.map +1 -1
  424. package/dist/file-upload/pre-upload-attachments.d.ts +37 -0
  425. package/dist/file-upload/pre-upload-attachments.d.ts.map +1 -1
  426. package/dist/file-upload/pre-upload-attachments.js +79 -19
  427. package/dist/file-upload/pre-upload-attachments.js.map +1 -1
  428. package/dist/index.d.ts +1 -1
  429. package/dist/index.d.ts.map +1 -1
  430. package/dist/index.js.map +1 -1
  431. package/dist/integrations/adapters/slack.js +1 -1
  432. package/dist/integrations/adapters/slack.js.map +1 -1
  433. package/dist/integrations/plugin.js +1 -1
  434. package/dist/integrations/plugin.js.map +1 -1
  435. package/dist/jobs/scheduler.js +70 -21
  436. package/dist/jobs/scheduler.js.map +1 -1
  437. package/dist/mcp/actions/create-org-service-token.d.ts +14 -0
  438. package/dist/mcp/actions/create-org-service-token.d.ts.map +1 -0
  439. package/dist/mcp/actions/create-org-service-token.js +74 -0
  440. package/dist/mcp/actions/create-org-service-token.js.map +1 -0
  441. package/dist/mcp/actions/list-org-service-tokens.d.ts +17 -0
  442. package/dist/mcp/actions/list-org-service-tokens.d.ts.map +1 -0
  443. package/dist/mcp/actions/list-org-service-tokens.js +42 -0
  444. package/dist/mcp/actions/list-org-service-tokens.js.map +1 -0
  445. package/dist/mcp/actions/revoke-org-service-token.d.ts +7 -0
  446. package/dist/mcp/actions/revoke-org-service-token.d.ts.map +1 -0
  447. package/dist/mcp/actions/revoke-org-service-token.js +28 -0
  448. package/dist/mcp/actions/revoke-org-service-token.js.map +1 -0
  449. package/dist/mcp/actions/service-token-access.d.ts +24 -0
  450. package/dist/mcp/actions/service-token-access.d.ts.map +1 -0
  451. package/dist/mcp/actions/service-token-access.js +63 -0
  452. package/dist/mcp/actions/service-token-access.js.map +1 -0
  453. package/dist/mcp/build-server.d.ts +42 -11
  454. package/dist/mcp/build-server.d.ts.map +1 -1
  455. package/dist/mcp/build-server.js +53 -3
  456. package/dist/mcp/build-server.js.map +1 -1
  457. package/dist/mcp/connect-route.d.ts +35 -0
  458. package/dist/mcp/connect-route.d.ts.map +1 -1
  459. package/dist/mcp/connect-route.js +57 -2
  460. package/dist/mcp/connect-route.js.map +1 -1
  461. package/dist/mcp/connect-store.d.ts +43 -0
  462. package/dist/mcp/connect-store.d.ts.map +1 -1
  463. package/dist/mcp/connect-store.js +129 -12
  464. package/dist/mcp/connect-store.js.map +1 -1
  465. package/dist/mcp/oauth-token.d.ts +10 -0
  466. package/dist/mcp/oauth-token.d.ts.map +1 -1
  467. package/dist/mcp/oauth-token.js +2 -0
  468. package/dist/mcp/oauth-token.js.map +1 -1
  469. package/dist/mcp/server.d.ts.map +1 -1
  470. package/dist/mcp/server.js +3 -0
  471. package/dist/mcp/server.js.map +1 -1
  472. package/dist/mcp-client/routes.js +1 -1
  473. package/dist/mcp-client/routes.js.map +1 -1
  474. package/dist/org/context.d.ts +4 -0
  475. package/dist/org/context.d.ts.map +1 -1
  476. package/dist/org/context.js +10 -0
  477. package/dist/org/context.js.map +1 -1
  478. package/dist/org/handlers.d.ts +11 -7
  479. package/dist/org/handlers.d.ts.map +1 -1
  480. package/dist/org/handlers.js +0 -8
  481. package/dist/org/handlers.js.map +1 -1
  482. package/dist/org/migrations.d.ts.map +1 -1
  483. package/dist/org/migrations.js +8 -0
  484. package/dist/org/migrations.js.map +1 -1
  485. package/dist/org/schema.d.ts +15 -15
  486. package/dist/progress/actions.d.ts.map +1 -1
  487. package/dist/progress/actions.js +13 -5
  488. package/dist/progress/actions.js.map +1 -1
  489. package/dist/provider-api/actions/delete-staged-dataset.d.ts +9 -0
  490. package/dist/provider-api/actions/delete-staged-dataset.d.ts.map +1 -0
  491. package/dist/provider-api/actions/delete-staged-dataset.js +35 -0
  492. package/dist/provider-api/actions/delete-staged-dataset.js.map +1 -0
  493. package/dist/provider-api/actions/list-staged-datasets.d.ts +15 -0
  494. package/dist/provider-api/actions/list-staged-datasets.d.ts.map +1 -0
  495. package/dist/provider-api/actions/list-staged-datasets.js +41 -0
  496. package/dist/provider-api/actions/list-staged-datasets.js.map +1 -0
  497. package/dist/provider-api/actions/query-staged-dataset.d.ts +29 -0
  498. package/dist/provider-api/actions/query-staged-dataset.d.ts.map +1 -0
  499. package/dist/provider-api/actions/query-staged-dataset.js +116 -0
  500. package/dist/provider-api/actions/query-staged-dataset.js.map +1 -0
  501. package/dist/provider-api/custom-registry.d.ts.map +1 -1
  502. package/dist/provider-api/custom-registry.js.map +1 -1
  503. package/dist/provider-api/index.d.ts +10 -10
  504. package/dist/provider-api/index.js +0 -5
  505. package/dist/provider-api/index.js.map +1 -1
  506. package/dist/provider-api/staged-datasets-aggregate.d.ts +46 -0
  507. package/dist/provider-api/staged-datasets-aggregate.d.ts.map +1 -0
  508. package/dist/provider-api/staged-datasets-aggregate.js +209 -0
  509. package/dist/provider-api/staged-datasets-aggregate.js.map +1 -0
  510. package/dist/provider-api/staged-datasets-store.d.ts +76 -0
  511. package/dist/provider-api/staged-datasets-store.d.ts.map +1 -0
  512. package/dist/provider-api/staged-datasets-store.js +319 -0
  513. package/dist/provider-api/staged-datasets-store.js.map +1 -0
  514. package/dist/provider-api/staging.d.ts +100 -0
  515. package/dist/provider-api/staging.d.ts.map +1 -0
  516. package/dist/provider-api/staging.js +281 -0
  517. package/dist/provider-api/staging.js.map +1 -0
  518. package/dist/resources/handlers.d.ts.map +1 -1
  519. package/dist/resources/handlers.js +13 -1
  520. package/dist/resources/handlers.js.map +1 -1
  521. package/dist/scripts/call-agent.d.ts.map +1 -1
  522. package/dist/scripts/call-agent.js +1 -2
  523. package/dist/scripts/call-agent.js.map +1 -1
  524. package/dist/scripts/resources/migrate-learnings.d.ts +1 -1
  525. package/dist/scripts/resources/migrate-learnings.d.ts.map +1 -1
  526. package/dist/scripts/resources/migrate-learnings.js +1 -1
  527. package/dist/scripts/resources/migrate-learnings.js.map +1 -1
  528. package/dist/secrets/schema.d.ts +7 -7
  529. package/dist/server/action-discovery.d.ts.map +1 -1
  530. package/dist/server/action-discovery.js +14 -0
  531. package/dist/server/action-discovery.js.map +1 -1
  532. package/dist/server/action-routes.d.ts.map +1 -1
  533. package/dist/server/action-routes.js +3 -2
  534. package/dist/server/action-routes.js.map +1 -1
  535. package/dist/server/agent-chat-plugin.d.ts +33 -0
  536. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  537. package/dist/server/agent-chat-plugin.js +251 -180
  538. package/dist/server/agent-chat-plugin.js.map +1 -1
  539. package/dist/server/agent-discovery.d.ts.map +1 -1
  540. package/dist/server/agent-discovery.js +13 -16
  541. package/dist/server/agent-discovery.js.map +1 -1
  542. package/dist/server/agent-teams-run-queue.d.ts +31 -8
  543. package/dist/server/agent-teams-run-queue.d.ts.map +1 -1
  544. package/dist/server/agent-teams-run-queue.js +61 -18
  545. package/dist/server/agent-teams-run-queue.js.map +1 -1
  546. package/dist/server/agent-teams.d.ts +27 -1
  547. package/dist/server/agent-teams.d.ts.map +1 -1
  548. package/dist/server/agent-teams.js +214 -14
  549. package/dist/server/agent-teams.js.map +1 -1
  550. package/dist/server/app-base-path.d.ts +20 -0
  551. package/dist/server/app-base-path.d.ts.map +1 -1
  552. package/dist/server/app-base-path.js +36 -0
  553. package/dist/server/app-base-path.js.map +1 -1
  554. package/dist/server/attachment-actions.d.ts +43 -0
  555. package/dist/server/attachment-actions.d.ts.map +1 -0
  556. package/dist/server/attachment-actions.js +214 -0
  557. package/dist/server/attachment-actions.js.map +1 -0
  558. package/dist/server/auth.js +1 -1
  559. package/dist/server/auth.js.map +1 -1
  560. package/dist/server/complete-text.d.ts +56 -0
  561. package/dist/server/complete-text.d.ts.map +1 -0
  562. package/dist/server/complete-text.js +147 -0
  563. package/dist/server/complete-text.js.map +1 -0
  564. package/dist/server/core-routes-plugin.d.ts +4 -0
  565. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  566. package/dist/server/core-routes-plugin.js +49 -29
  567. package/dist/server/core-routes-plugin.js.map +1 -1
  568. package/dist/server/cors-origins.d.ts.map +1 -1
  569. package/dist/server/cors-origins.js +6 -1
  570. package/dist/server/cors-origins.js.map +1 -1
  571. package/dist/server/create-server.d.ts.map +1 -1
  572. package/dist/server/create-server.js +2 -1
  573. package/dist/server/create-server.js.map +1 -1
  574. package/dist/server/csrf.d.ts +1 -1
  575. package/dist/server/csrf.d.ts.map +1 -1
  576. package/dist/server/email-actions.d.ts +19 -0
  577. package/dist/server/email-actions.d.ts.map +1 -0
  578. package/dist/server/email-actions.js +191 -0
  579. package/dist/server/email-actions.js.map +1 -0
  580. package/dist/server/embed-route.js +1 -1
  581. package/dist/server/embed-route.js.map +1 -1
  582. package/dist/server/embed-session.d.ts.map +1 -1
  583. package/dist/server/embed-session.js +5 -1
  584. package/dist/server/embed-session.js.map +1 -1
  585. package/dist/server/entry-server.d.ts +24 -0
  586. package/dist/server/entry-server.d.ts.map +1 -0
  587. package/dist/server/entry-server.js +54 -0
  588. package/dist/server/entry-server.js.map +1 -0
  589. package/dist/server/framework-request-handler.d.ts.map +1 -1
  590. package/dist/server/framework-request-handler.js +2 -10
  591. package/dist/server/framework-request-handler.js.map +1 -1
  592. package/dist/server/google-oauth.d.ts.map +1 -1
  593. package/dist/server/google-oauth.js +2 -9
  594. package/dist/server/google-oauth.js.map +1 -1
  595. package/dist/server/google-realtime-session.d.ts.map +1 -1
  596. package/dist/server/google-realtime-session.js +6 -4
  597. package/dist/server/google-realtime-session.js.map +1 -1
  598. package/dist/server/h3-helpers.d.ts +39 -0
  599. package/dist/server/h3-helpers.d.ts.map +1 -1
  600. package/dist/server/h3-helpers.js +104 -1
  601. package/dist/server/h3-helpers.js.map +1 -1
  602. package/dist/server/index.d.ts +2 -1
  603. package/dist/server/index.d.ts.map +1 -1
  604. package/dist/server/index.js +2 -1
  605. package/dist/server/index.js.map +1 -1
  606. package/dist/server/onboarding-html.d.ts.map +1 -1
  607. package/dist/server/onboarding-html.js +1 -8
  608. package/dist/server/onboarding-html.js.map +1 -1
  609. package/dist/server/open-route.d.ts.map +1 -1
  610. package/dist/server/open-route.js +1 -0
  611. package/dist/server/open-route.js.map +1 -1
  612. package/dist/server/prompts/framework-core-compact.d.ts +19 -0
  613. package/dist/server/prompts/framework-core-compact.d.ts.map +1 -0
  614. package/dist/server/prompts/framework-core-compact.js +69 -0
  615. package/dist/server/prompts/framework-core-compact.js.map +1 -0
  616. package/dist/server/prompts/framework-core.d.ts +26 -0
  617. package/dist/server/prompts/framework-core.d.ts.map +1 -0
  618. package/dist/server/prompts/framework-core.js +130 -0
  619. package/dist/server/prompts/framework-core.js.map +1 -0
  620. package/dist/server/prompts/index.d.ts +9 -0
  621. package/dist/server/prompts/index.d.ts.map +1 -0
  622. package/dist/server/prompts/index.js +9 -0
  623. package/dist/server/prompts/index.js.map +1 -0
  624. package/dist/server/prompts/model-overlays.d.ts +18 -0
  625. package/dist/server/prompts/model-overlays.d.ts.map +1 -0
  626. package/dist/server/prompts/model-overlays.js +46 -0
  627. package/dist/server/prompts/model-overlays.js.map +1 -0
  628. package/dist/server/prompts/shared-rules.d.ts +29 -0
  629. package/dist/server/prompts/shared-rules.d.ts.map +1 -0
  630. package/dist/server/prompts/shared-rules.js +54 -0
  631. package/dist/server/prompts/shared-rules.js.map +1 -0
  632. package/dist/server/security-headers.d.ts +7 -1
  633. package/dist/server/security-headers.d.ts.map +1 -1
  634. package/dist/server/security-headers.js +11 -0
  635. package/dist/server/security-headers.js.map +1 -1
  636. package/dist/server/ssr-handler.d.ts.map +1 -1
  637. package/dist/server/ssr-handler.js +135 -46
  638. package/dist/server/ssr-handler.js.map +1 -1
  639. package/dist/server/transcribe-voice.d.ts.map +1 -1
  640. package/dist/server/transcribe-voice.js +7 -4
  641. package/dist/server/transcribe-voice.js.map +1 -1
  642. package/dist/settings/store.d.ts.map +1 -1
  643. package/dist/settings/store.js +9 -0
  644. package/dist/settings/store.js.map +1 -1
  645. package/dist/shared/markdown-block-split.d.ts +39 -0
  646. package/dist/shared/markdown-block-split.d.ts.map +1 -0
  647. package/dist/shared/markdown-block-split.js +97 -0
  648. package/dist/shared/markdown-block-split.js.map +1 -0
  649. package/dist/shared/reasoning-effort.js +13 -1
  650. package/dist/shared/reasoning-effort.js.map +1 -1
  651. package/dist/shared/streaming-text-smoothing.d.ts +18 -0
  652. package/dist/shared/streaming-text-smoothing.d.ts.map +1 -1
  653. package/dist/shared/streaming-text-smoothing.js +70 -4
  654. package/dist/shared/streaming-text-smoothing.js.map +1 -1
  655. package/dist/sharing/actions/list-resource-shares.d.ts +24 -1
  656. package/dist/sharing/actions/list-resource-shares.d.ts.map +1 -1
  657. package/dist/sharing/actions/set-resource-visibility.d.ts +8 -1
  658. package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -1
  659. package/dist/sharing/actions/share-resource.d.ts +12 -1
  660. package/dist/sharing/actions/share-resource.d.ts.map +1 -1
  661. package/dist/sharing/actions/unshare-resource.d.ts +8 -1
  662. package/dist/sharing/actions/unshare-resource.d.ts.map +1 -1
  663. package/dist/sharing/schema.d.ts +10 -10
  664. package/dist/styles/agent-conversation.css +239 -0
  665. package/dist/templates/default/.agents/skills/delegate-to-agent/SKILL.md +50 -2
  666. package/dist/templates/default/AGENTS.md +1 -1
  667. package/dist/templates/default/DEVELOPING.md +19 -0
  668. package/dist/templates/default/app/entry.client.tsx +4 -1
  669. package/dist/templates/default/app/entry.server.tsx +4 -56
  670. package/dist/templates/default/app/global.css +3 -2
  671. package/dist/templates/default/app/root.tsx +8 -24
  672. package/dist/templates/default/app/routes/_index.tsx +0 -13
  673. package/dist/templates/default/package.json +6 -5
  674. package/dist/templates/default/tsconfig.json +2 -1
  675. package/dist/templates/starter-shell-sync.spec.ts +118 -0
  676. package/dist/templates/ui-primitives-sync.spec.ts +399 -0
  677. package/dist/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +50 -2
  678. package/dist/terminal/pty-server.js +1 -1
  679. package/dist/terminal/pty-server.js.map +1 -1
  680. package/dist/triggers/dispatcher.js +1 -1
  681. package/dist/triggers/dispatcher.js.map +1 -1
  682. package/dist/usage/store.d.ts.map +1 -1
  683. package/dist/usage/store.js +60 -7
  684. package/dist/usage/store.js.map +1 -1
  685. package/dist/vite/client.d.ts.map +1 -1
  686. package/dist/vite/client.js +44 -12
  687. package/dist/vite/client.js.map +1 -1
  688. package/dist/workspace-files/schema.d.ts +8 -8
  689. package/dist/workspace-files/tool.d.ts.map +1 -1
  690. package/dist/workspace-files/tool.js +0 -1
  691. package/dist/workspace-files/tool.js.map +1 -1
  692. package/docs/content/a2a-protocol.md +18 -12
  693. package/docs/content/actions.md +42 -10
  694. package/docs/content/agent-mentions.md +7 -8
  695. package/docs/content/agent-teams.md +23 -37
  696. package/docs/content/agent-web-surfaces.md +18 -9
  697. package/docs/content/authentication.md +6 -17
  698. package/docs/content/automations.md +43 -15
  699. package/docs/content/cli-adapters.md +25 -24
  700. package/docs/content/client.md +66 -17
  701. package/docs/content/cloneable-saas.md +19 -23
  702. package/docs/content/code-agents-ui.md +3 -31
  703. package/docs/content/components.md +308 -0
  704. package/docs/content/context-awareness.md +4 -0
  705. package/docs/content/creating-templates.md +4 -2
  706. package/docs/content/cross-app-sso.md +45 -19
  707. package/docs/content/database.md +26 -1
  708. package/docs/content/deployment.md +3 -1
  709. package/docs/content/dispatch.md +9 -37
  710. package/docs/content/drop-in-agent.md +123 -2
  711. package/docs/content/embedding-sdk.md +35 -0
  712. package/docs/content/extensions.md +2 -2
  713. package/docs/content/external-agents.md +86 -171
  714. package/docs/content/faq.md +6 -27
  715. package/docs/content/frames.md +9 -12
  716. package/docs/content/getting-started.md +80 -77
  717. package/docs/content/key-concepts.md +29 -19
  718. package/docs/content/mcp-apps.md +103 -0
  719. package/docs/content/mcp-clients.md +2 -2
  720. package/docs/content/mcp-protocol.md +40 -17
  721. package/docs/content/messaging.md +11 -4
  722. package/docs/content/migration-workbench.md +4 -47
  723. package/docs/content/multi-app-workspace.md +48 -17
  724. package/docs/content/multi-tenancy.md +1 -1
  725. package/docs/content/notifications.md +8 -6
  726. package/docs/content/observability.md +26 -15
  727. package/docs/content/onboarding.md +7 -1
  728. package/docs/content/pr-visual-recap.md +203 -23
  729. package/docs/content/progress.md +5 -5
  730. package/docs/content/pure-agent-apps.md +3 -1
  731. package/docs/content/real-time-collaboration.md +106 -0
  732. package/docs/content/recurring-jobs.md +17 -1
  733. package/docs/content/security.md +17 -3
  734. package/docs/content/server.md +39 -3
  735. package/docs/content/sharing.md +20 -1
  736. package/docs/content/skills-guide.md +151 -125
  737. package/docs/content/template-analytics.md +8 -0
  738. package/docs/content/template-assets.md +2 -0
  739. package/docs/content/template-brain.md +59 -3
  740. package/docs/content/template-calendar.md +8 -0
  741. package/docs/content/template-clips.md +11 -2
  742. package/docs/content/template-content.md +24 -4
  743. package/docs/content/template-design.md +19 -17
  744. package/docs/content/template-dispatch.md +2 -0
  745. package/docs/content/template-forms.md +28 -1
  746. package/docs/content/template-mail.md +17 -0
  747. package/docs/content/template-plan.md +177 -10
  748. package/docs/content/template-slides.md +51 -12
  749. package/docs/content/template-videos.md +17 -0
  750. package/docs/content/tracking.md +17 -13
  751. package/docs/content/using-your-agent.md +15 -5
  752. package/docs/content/voice-input.md +1 -1
  753. package/docs/content/what-is-agent-native.md +5 -6
  754. package/docs/content/workspace-connections.md +138 -424
  755. package/docs/content/workspace-management.md +12 -128
  756. package/docs/content/workspace.md +125 -199
  757. package/docs/content/writing-agent-instructions.md +17 -1
  758. package/package.json +25 -6
  759. package/src/templates/default/.agents/skills/delegate-to-agent/SKILL.md +50 -2
  760. package/src/templates/default/AGENTS.md +1 -1
  761. package/src/templates/default/DEVELOPING.md +19 -0
  762. package/src/templates/default/app/entry.client.tsx +4 -1
  763. package/src/templates/default/app/entry.server.tsx +4 -56
  764. package/src/templates/default/app/global.css +3 -2
  765. package/src/templates/default/app/root.tsx +8 -24
  766. package/src/templates/default/app/routes/_index.tsx +0 -13
  767. package/src/templates/default/package.json +6 -5
  768. package/src/templates/default/tsconfig.json +2 -1
  769. package/src/templates/starter-shell-sync.spec.ts +118 -0
  770. package/src/templates/ui-primitives-sync.spec.ts +399 -0
  771. package/src/templates/workspace-core/.agents/skills/delegate-to-agent/SKILL.md +50 -2
  772. package/tsconfig.base.json +2 -10
  773. package/dist/cli/app-skill.d.ts +0 -157
  774. package/dist/cli/app-skill.d.ts.map +0 -1
  775. package/dist/cli/audit-agent-web.d.ts +0 -2
  776. package/dist/cli/audit-agent-web.d.ts.map +0 -1
  777. package/dist/cli/code-agent-connector.d.ts +0 -17
  778. package/dist/cli/code-agent-connector.d.ts.map +0 -1
  779. package/dist/cli/code.d.ts +0 -66
  780. package/dist/cli/code.d.ts.map +0 -1
  781. package/dist/cli/connect.d.ts +0 -140
  782. package/dist/cli/connect.d.ts.map +0 -1
  783. package/dist/cli/context-xray-local.d.ts +0 -16
  784. package/dist/cli/context-xray-local.d.ts.map +0 -1
  785. package/dist/cli/create-workspace.d.ts +0 -8
  786. package/dist/cli/create-workspace.d.ts.map +0 -1
  787. package/dist/cli/index.d.ts +0 -3
  788. package/dist/cli/index.d.ts.map +0 -1
  789. package/dist/cli/info.d.ts +0 -2
  790. package/dist/cli/info.d.ts.map +0 -1
  791. package/dist/cli/mcp-config-writers.d.ts +0 -82
  792. package/dist/cli/mcp-config-writers.d.ts.map +0 -1
  793. package/dist/cli/mcp.d.ts +0 -16
  794. package/dist/cli/mcp.d.ts.map +0 -1
  795. package/dist/cli/migrate.d.ts +0 -38
  796. package/dist/cli/migrate.d.ts.map +0 -1
  797. package/dist/cli/plan-local.d.ts +0 -43
  798. package/dist/cli/plan-local.d.ts.map +0 -1
  799. package/dist/cli/plan-publish-store.d.ts +0 -62
  800. package/dist/cli/plan-publish-store.d.ts.map +0 -1
  801. package/dist/cli/pr-visual-recap-workflow.d.ts +0 -11
  802. package/dist/cli/pr-visual-recap-workflow.d.ts.map +0 -1
  803. package/dist/cli/recap.d.ts +0 -297
  804. package/dist/cli/recap.d.ts.map +0 -1
  805. package/dist/cli/skills.d.ts +0 -162
  806. package/dist/cli/skills.d.ts.map +0 -1
  807. package/dist/cli/workspace-dev.d.ts +0 -96
  808. package/dist/cli/workspace-dev.d.ts.map +0 -1
@@ -4,6 +4,7 @@ import { resourceListAllOwners, resourcePut, } from "../resources/store.js";
4
4
  import { runAgentLoop, actionsToEngineTools, getOwnerActiveApiKey, } from "../agent/production-agent.js";
5
5
  import { getStoredModelForEngine, resolveEngine, } from "../agent/engine/index.js";
6
6
  import { createThread } from "../chat-threads/store.js";
7
+ import { startRun, resolveRunSoftTimeoutMs } from "../agent/run-manager.js";
7
8
  const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
8
9
  export function parseJobFrontmatter(content) {
9
10
  const match = content.match(FRONTMATTER_RE);
@@ -333,28 +334,76 @@ async function executeJob(resource, meta, body, deps, now) {
333
334
  content: [{ type: "text", text: jobText }],
334
335
  },
335
336
  ];
336
- // 5-minute timeout
337
- const controller = new AbortController();
338
- const timeout = setTimeout(() => controller.abort(), 5 * 60 * 1000);
339
- const events = [];
340
- const send = (event) => {
341
- events.push(event);
342
- };
343
- try {
344
- await runAgentLoop({
345
- engine,
346
- model,
347
- systemPrompt,
348
- tools,
349
- messages,
350
- actions,
351
- send,
352
- signal: controller.signal,
337
+ // Route through startRun (from run-manager) instead of calling
338
+ // runAgentLoop directly. This adds:
339
+ // 1. A heartbeat row in agent_runs so a serverless kill is detected
340
+ // by reapAllStaleRuns on the next startup and the row is flipped
341
+ // to 'errored' no more stranded lastStatus:"running" in the job
342
+ // frontmatter after the next tick resets it via the stuck-guard.
343
+ // 2. The soft-timeout infrastructure so the job checkpoints cleanly
344
+ // before serverless hard-kill rather than dying mid-flight.
345
+ // 3. SQL abort checks so a displaced/reaped run self-aborts instead
346
+ // of completing invisibly and potentially overwriting newer state.
347
+ const runId = `job-${jobName.replace(/[^a-zA-Z0-9._-]/g, "-")}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
348
+ // Use the same soft-timeout logic as interactive runs. On hosted
349
+ // runtimes this clamps to 40s (under the gateway wall); locally it
350
+ // defaults to 0 (no framework timeout). The 5-minute hard-abort
351
+ // below is still provided as a backstop via the startRun signal.
352
+ const softTimeoutMs = resolveRunSoftTimeoutMs(undefined, {
353
+ useHostedDefault: true,
354
+ });
355
+ // Hard-abort backstop: 5 minutes. On hosted runtimes the soft-timeout
356
+ // will fire first; locally this is the only guard.
357
+ const hardAbortTimer = setTimeout(() => {
358
+ // startRun's abort controller handles this below, but we still need
359
+ // the handle to clear it in the finally block.
360
+ }, 5 * 60 * 1000);
361
+ let jobError = null;
362
+ await new Promise((resolve, reject) => {
363
+ const activeRun = startRun(runId, thread.id, async (send, signal) => {
364
+ try {
365
+ await runAgentLoop({
366
+ engine,
367
+ model,
368
+ systemPrompt,
369
+ tools,
370
+ messages,
371
+ actions,
372
+ send,
373
+ signal,
374
+ threadId: thread.id,
375
+ });
376
+ }
377
+ catch (err) {
378
+ throw err;
379
+ }
380
+ },
381
+ // onComplete: run finished (completed or aborted)
382
+ async (run) => {
383
+ if (run.status === "completed") {
384
+ resolve();
385
+ }
386
+ else {
387
+ reject(new Error(`Job run ended with status: ${run.status}`));
388
+ }
389
+ }, {
390
+ softTimeoutMs,
391
+ // turnId defaults to runId — fine for single-turn jobs
353
392
  });
354
- }
355
- finally {
356
- clearTimeout(timeout);
357
- }
393
+ // Hard-abort backstop: abort the run-manager's own controller after
394
+ // 5 minutes if it hasn't finished naturally.
395
+ clearTimeout(hardAbortTimer);
396
+ setTimeout(() => {
397
+ if (activeRun.status === "running") {
398
+ activeRun.abort.abort("job_hard_timeout");
399
+ reject(new Error("Job timed out after 5 minutes"));
400
+ }
401
+ }, 5 * 60 * 1000);
402
+ }).catch((err) => {
403
+ jobError = err;
404
+ });
405
+ if (jobError)
406
+ throw jobError;
358
407
  // Success — update status. Compute the next run from completion time,
359
408
  // not the job's start time `now`: a long run could otherwise schedule a
360
409
  // nextRun that's already in the past and re-fire immediately next tick.
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/jobs/scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["import { runWithRequestContext } from \"../server/request-context.js\";\nimport { nextOccurrence, isValidCron, describeCron } from \"./cron.js\";\nimport {\n resourceListAllOwners,\n resourcePut,\n type Resource,\n} from \"../resources/store.js\";\nimport {\n runAgentLoop,\n actionsToEngineTools,\n getOwnerActiveApiKey,\n type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport {\n getStoredModelForEngine,\n resolveEngine,\n} from \"../agent/engine/index.js\";\nimport type { AgentEngine } from \"../agent/engine/types.js\";\nimport { createThread } from \"../chat-threads/store.js\";\nimport type { AgentChatEvent } from \"../agent/types.js\";\n\n// ─── Frontmatter parsing ────────────────────────────────────────────────────\n\nexport interface JobFrontmatter {\n schedule: string;\n enabled: boolean;\n createdBy?: string;\n orgId?: string;\n runAs?: \"creator\" | \"shared\";\n lastRun?: string;\n lastStatus?: \"success\" | \"error\" | \"running\" | \"skipped\";\n lastError?: string;\n nextRun?: string;\n}\n\nconst FRONTMATTER_RE = /^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/;\n\nexport function parseJobFrontmatter(content: string): {\n meta: JobFrontmatter;\n body: string;\n} {\n const match = content.match(FRONTMATTER_RE);\n if (!match) {\n return {\n meta: { schedule: \"\", enabled: false },\n body: content,\n };\n }\n\n const yamlBlock = match[1];\n const body = match[2].trim();\n\n const meta: JobFrontmatter = { schedule: \"\", enabled: true };\n\n for (const line of yamlBlock.split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n let value = line.slice(colonIdx + 1).trim();\n\n // Strip quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n switch (key) {\n case \"schedule\":\n meta.schedule = value;\n break;\n case \"enabled\":\n meta.enabled = value !== \"false\";\n break;\n case \"createdBy\":\n meta.createdBy = value;\n break;\n case \"orgId\":\n meta.orgId = value;\n break;\n case \"runAs\":\n meta.runAs =\n value === \"shared\" || value === \"creator\" ? value : undefined;\n break;\n case \"lastRun\":\n meta.lastRun = value;\n break;\n case \"lastStatus\":\n meta.lastStatus = value as JobFrontmatter[\"lastStatus\"];\n break;\n case \"lastError\":\n // Reverse the escaping applied in buildJobContent.\n meta.lastError = value\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n break;\n case \"nextRun\":\n meta.nextRun = value;\n break;\n }\n }\n\n return { meta, body };\n}\n\nexport function buildJobContent(meta: JobFrontmatter, body: string): string {\n const lines = [`---`];\n lines.push(`schedule: \"${meta.schedule}\"`);\n lines.push(`enabled: ${meta.enabled}`);\n if (meta.createdBy) lines.push(`createdBy: ${meta.createdBy}`);\n if (meta.orgId) lines.push(`orgId: ${meta.orgId}`);\n if (meta.runAs) lines.push(`runAs: ${meta.runAs}`);\n if (meta.lastRun) lines.push(`lastRun: ${meta.lastRun}`);\n if (meta.lastStatus) lines.push(`lastStatus: ${meta.lastStatus}`);\n if (meta.lastError) {\n // Escape backslash, quote, then CR/LF. The frontmatter parser splits on\n // \"\\n\", so an un-escaped newline (common in stack traces) would otherwise\n // split the value across lines and corrupt/truncate the stored error.\n const escaped = meta.lastError\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\n/g, \"\\\\n\");\n lines.push(`lastError: \"${escaped}\"`);\n }\n if (meta.nextRun) lines.push(`nextRun: ${meta.nextRun}`);\n lines.push(`---`);\n lines.push(\"\");\n lines.push(body);\n return lines.join(\"\\n\");\n}\n\n// ─── Job execution ──────────────────────────────────────────────────────────\n\nexport interface SchedulerDeps {\n getActions: () => Record<string, ActionEntry>;\n getSystemPrompt: (owner: string) => Promise<string>;\n /** Optional engine override. Defaults to the resolved request engine. */\n engine?: AgentEngine;\n apiKey?: string;\n model?: string;\n /** App/template id used for org-scoped per-app model defaults. */\n appId?: string;\n}\n\nlet _isRunning = false;\n\n// Skip the DB query on every tick if we recently confirmed no jobs exist.\n// `_hasJobsCache` is invalidated whenever a `jobs/*` resource is written or\n// deleted (subscribed below), and refreshed at most every 5 minutes.\nlet _hasJobsCache: boolean | undefined;\nlet _lastJobsCheck = 0;\nconst JOBS_CHECK_INTERVAL_MS = 5 * 60_000;\nlet _emitterSubscribed = false;\n\nfunction subscribeToJobsResourceEvents(): void {\n if (_emitterSubscribed) return;\n _emitterSubscribed = true;\n // Lazy import to avoid circular deps at module load\n import(\"../resources/emitter.js\")\n .then(({ getResourcesEmitter }) => {\n getResourcesEmitter().on(\"resources\", (event: any) => {\n if (typeof event?.path === \"string\" && event.path.startsWith(\"jobs/\")) {\n _hasJobsCache = undefined;\n }\n });\n })\n .catch((err) => {\n console.warn(\n \"[jobs] resource-event subscription failed:\",\n err instanceof Error ? err.message : err,\n );\n });\n}\n\n/**\n * Process all due recurring jobs. Called every 60 seconds.\n * Sequential execution with 5-minute timeout per job.\n */\nexport async function processRecurringJobs(deps: SchedulerDeps): Promise<void> {\n // Prevent concurrent runs\n if (_isRunning) return;\n\n subscribeToJobsResourceEvents();\n\n // Skip if we recently confirmed there are no job resources to run.\n const nowMs = Date.now();\n if (\n _hasJobsCache === false &&\n nowMs - _lastJobsCheck < JOBS_CHECK_INTERVAL_MS\n ) {\n return;\n }\n\n _isRunning = true;\n\n try {\n const jobResources = await resourceListAllOwners(\"jobs/\");\n _hasJobsCache = jobResources.some(\n (r) => r.path.endsWith(\".md\") && !r.path.endsWith(\".keep\"),\n );\n _lastJobsCheck = nowMs;\n if (!_hasJobsCache) return;\n const now = new Date();\n\n for (const resource of jobResources) {\n // Skip non-markdown or .keep files\n if (!resource.path.endsWith(\".md\")) continue;\n if (resource.path.endsWith(\".keep\")) continue;\n\n const { meta, body } = parseJobFrontmatter(resource.content);\n\n // Skip disabled or missing schedule\n if (!meta.enabled || !meta.schedule) continue;\n if (!isValidCron(meta.schedule)) continue;\n\n // Skip if currently running, unless it has been stuck for more than 10 minutes\n // (server crash mid-job leaves lastStatus=running forever without this guard)\n if (meta.lastStatus === \"running\") {\n const stuckCutoff = 10 * 60 * 1000;\n if (\n meta.lastRun &&\n now.getTime() - new Date(meta.lastRun).getTime() < stuckCutoff\n ) {\n continue;\n }\n // Stuck — reset so the next check can re-run it\n meta.lastStatus = \"error\";\n meta.lastError = \"Job timed out or server crashed mid-run\";\n const next = nextOccurrence(meta.schedule, now);\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n continue;\n }\n\n // Check if due\n if (meta.nextRun) {\n const nextRunDate = new Date(meta.nextRun);\n if (nextRunDate > now) continue;\n } else {\n // No nextRun computed yet — seed it from `now` so the job waits for its\n // real next occurrence. Computing from new Date(0) (the epoch) always\n // returns a 1970 date, which is < now, so the job would fire\n // immediately on first sight regardless of its schedule.\n const next = nextOccurrence(meta.schedule, now);\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n continue;\n }\n\n // Skip if body is empty\n if (!body.trim()) continue;\n\n // Execute the job\n await executeJob(resource, meta, body, deps, now);\n }\n } catch (err) {\n // Transient WS / connection drops (Neon serverless): silently retry next\n // tick instead of spamming stderr — `retryOnConnectionError` already did\n // its retry budget at the driver level.\n const { isConnectionError } = await import(\"../db/client.js\");\n if (isConnectionError(err)) {\n _hasJobsCache = undefined; // force re-check on next successful tick\n _lastJobsCheck = 0;\n return;\n }\n // Unwrap ErrorEvent (Neon WS driver emits these on network failure) so logs show the real cause\n const detail =\n err instanceof Error\n ? err\n : ((err as any)?.error ?? (err as any)?.message ?? err);\n console.error(\"[recurring-jobs] Error processing jobs:\", detail);\n } finally {\n _isRunning = false;\n }\n}\n\n/**\n * Validate that the run-as user still exists and (if scoped to an org) is\n * still a member of that org. Skips the check for the dev-mode bypass\n * identity and the shared-owner sentinel, neither of which map to a real\n * user row.\n *\n * SECURITY: without this check the scheduler keeps running jobs as\n * `meta.createdBy` indefinitely — even after the user has been deleted,\n * removed from the org, or had their account disabled. The cron entry\n * itself is left intact so an admin can purge it manually after the\n * underlying user-state issue is investigated. See audit 12 #10.\n */\nasync function isJobRunAsStillValid(\n jobUserEmail: string,\n jobOrgId: string | undefined,\n): Promise<{ ok: boolean; reason?: string }> {\n // Shared-owner sentinel isn't a real user (used by jobs run as the\n // workspace identity).\n if (jobUserEmail === \"__shared__\") return { ok: true };\n try {\n const { getDbExec } = await import(\"../db/client.js\");\n const db = getDbExec();\n // Better Auth's user table is named \"user\" (singular). The reserved\n // word is quoted to avoid ambiguity in Postgres.\n const userResult = await db.execute({\n sql: `SELECT 1 FROM \"user\" WHERE email = ? LIMIT 1`,\n args: [jobUserEmail],\n });\n if (!userResult.rows || userResult.rows.length === 0) {\n return { ok: false, reason: `user \"${jobUserEmail}\" no longer exists` };\n }\n if (jobOrgId) {\n const memberResult = await db.execute({\n sql: `SELECT 1 FROM org_members WHERE org_id = ? AND LOWER(email) = LOWER(?) LIMIT 1`,\n args: [jobOrgId, jobUserEmail],\n });\n if (!memberResult.rows || memberResult.rows.length === 0) {\n return {\n ok: false,\n reason: `user \"${jobUserEmail}\" is no longer a member of org \"${jobOrgId}\"`,\n };\n }\n }\n return { ok: true };\n } catch (err: any) {\n // Tables may not exist on a brand-new install (no auth tables yet).\n // Treat that as \"valid\" rather than blocking every job. The check is\n // only meaningful once the auth tables exist.\n const msg = err?.message?.toLowerCase() ?? \"\";\n if (\n msg.includes(\"does not exist\") ||\n msg.includes(\"no such table\") ||\n msg.includes(\"undefined table\")\n ) {\n return { ok: true };\n }\n // Any other DB error: be conservative and let the job run rather than\n // blocking on an unexpected failure mode (e.g. transient connection\n // issue). We log so it's visible.\n console.warn(\n `[recurring-jobs] User/membership validation failed for \"${jobUserEmail}\":`,\n err?.message,\n );\n return { ok: true };\n }\n}\n\nasync function executeJob(\n resource: Resource,\n meta: JobFrontmatter,\n body: string,\n deps: SchedulerDeps,\n now: Date,\n): Promise<void> {\n const jobName = resource.path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n\n // Set owner context so all scoped operations (app-state, resources, etc.)\n // operate on the correct user's data\n const effectiveRunAs = meta.runAs ?? \"creator\";\n const jobUserEmail =\n effectiveRunAs === \"creator\"\n ? meta.createdBy || resource.owner\n : resource.owner;\n const jobOrgId = meta.orgId ?? undefined;\n\n // SECURITY (audit 12 #10): re-validate the run-as user/membership on\n // every tick. Sharing revocation, user deletion, and org-member removal\n // must take effect for already-scheduled jobs. Skip the tick on\n // failure; leave the cron entry alone so an admin can purge after\n // investigation.\n const validity = await isJobRunAsStillValid(jobUserEmail, jobOrgId);\n if (!validity.ok) {\n console.warn(\n `[recurring-jobs] Skipping job \"${jobName}\": ${validity.reason}. ` +\n `User/membership no longer valid — leaving cron entry for admin review.`,\n );\n // Mark as skipped without resetting nextRun so an admin can find it.\n meta.lastRun = now.toISOString();\n meta.lastStatus = \"skipped\";\n meta.lastError = validity.reason;\n await updateResource(resource, meta, body);\n return;\n }\n\n // Mark as running\n meta.lastRun = now.toISOString();\n meta.lastStatus = \"running\";\n meta.lastError = undefined;\n await updateResource(resource, meta, body);\n\n await runWithRequestContext(\n { userEmail: jobUserEmail, orgId: jobOrgId },\n async () => {\n try {\n const actions = deps.getActions();\n const systemPrompt = await deps.getSystemPrompt(jobUserEmail);\n const tools = actionsToEngineTools(actions);\n\n // Prefer the job runner's saved Anthropic key so recurring jobs\n // don't silently bill the shared platform key once a user has\n // brought their own. Falls back to the platform key when absent.\n const userApiKey = await getOwnerActiveApiKey(jobUserEmail);\n const engine =\n deps.engine ??\n (await resolveEngine({\n apiKey: userApiKey ?? deps.apiKey,\n appId: deps.appId,\n }));\n const model =\n deps.model ??\n (await getStoredModelForEngine(engine, { appId: deps.appId })) ??\n engine.defaultModel;\n\n // Create a chat thread for this run\n const threadTitle = `Job: ${jobName} — ${now.toLocaleDateString()}`;\n const thread = await createThread(jobUserEmail, { title: threadTitle });\n\n const jobText = `[Recurring Job: ${jobName}]\\nSchedule: ${describeCron(meta.schedule)}\\n\\nExecute the following job instructions:\\n\\n${body}`;\n const messages = [\n {\n role: \"user\" as const,\n content: [{ type: \"text\" as const, text: jobText }],\n },\n ];\n\n // 5-minute timeout\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5 * 60 * 1000);\n\n const events: AgentChatEvent[] = [];\n const send = (event: AgentChatEvent) => {\n events.push(event);\n };\n\n try {\n await runAgentLoop({\n engine,\n model,\n systemPrompt,\n tools,\n messages,\n actions,\n send,\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeout);\n }\n\n // Success — update status. Compute the next run from completion time,\n // not the job's start time `now`: a long run could otherwise schedule a\n // nextRun that's already in the past and re-fire immediately next tick.\n const next = nextOccurrence(meta.schedule, new Date());\n meta.lastStatus = \"success\";\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n\n console.log(\n `[recurring-jobs] Job \"${jobName}\" completed. Next run: ${meta.nextRun}`,\n );\n } catch (err: any) {\n // Error — update status. Use completion time (see success path).\n const next = nextOccurrence(meta.schedule, new Date());\n meta.lastStatus = \"error\";\n meta.lastError = err?.message?.slice(0, 200) || \"Unknown error\";\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n\n console.error(\n `[recurring-jobs] Job \"${jobName}\" failed:`,\n err?.message,\n );\n }\n },\n ); // end runWithRequestContext\n}\n\nasync function updateResource(\n resource: Resource,\n meta: JobFrontmatter,\n body: string,\n): Promise<void> {\n const content = buildJobContent(meta, body);\n await resourcePut(resource.owner, resource.path, content);\n}\n"]}
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/jobs/scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["import { runWithRequestContext } from \"../server/request-context.js\";\nimport { nextOccurrence, isValidCron, describeCron } from \"./cron.js\";\nimport {\n resourceListAllOwners,\n resourcePut,\n type Resource,\n} from \"../resources/store.js\";\nimport {\n runAgentLoop,\n actionsToEngineTools,\n getOwnerActiveApiKey,\n type ActionEntry,\n} from \"../agent/production-agent.js\";\nimport {\n getStoredModelForEngine,\n resolveEngine,\n} from \"../agent/engine/index.js\";\nimport type { AgentEngine } from \"../agent/engine/types.js\";\nimport { createThread } from \"../chat-threads/store.js\";\nimport { startRun, resolveRunSoftTimeoutMs } from \"../agent/run-manager.js\";\n\n// ─── Frontmatter parsing ────────────────────────────────────────────────────\n\nexport interface JobFrontmatter {\n schedule: string;\n enabled: boolean;\n createdBy?: string;\n orgId?: string;\n runAs?: \"creator\" | \"shared\";\n lastRun?: string;\n lastStatus?: \"success\" | \"error\" | \"running\" | \"skipped\";\n lastError?: string;\n nextRun?: string;\n}\n\nconst FRONTMATTER_RE = /^---\\n([\\s\\S]*?)\\n---\\n?([\\s\\S]*)$/;\n\nexport function parseJobFrontmatter(content: string): {\n meta: JobFrontmatter;\n body: string;\n} {\n const match = content.match(FRONTMATTER_RE);\n if (!match) {\n return {\n meta: { schedule: \"\", enabled: false },\n body: content,\n };\n }\n\n const yamlBlock = match[1];\n const body = match[2].trim();\n\n const meta: JobFrontmatter = { schedule: \"\", enabled: true };\n\n for (const line of yamlBlock.split(\"\\n\")) {\n const colonIdx = line.indexOf(\":\");\n if (colonIdx === -1) continue;\n const key = line.slice(0, colonIdx).trim();\n let value = line.slice(colonIdx + 1).trim();\n\n // Strip quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n switch (key) {\n case \"schedule\":\n meta.schedule = value;\n break;\n case \"enabled\":\n meta.enabled = value !== \"false\";\n break;\n case \"createdBy\":\n meta.createdBy = value;\n break;\n case \"orgId\":\n meta.orgId = value;\n break;\n case \"runAs\":\n meta.runAs =\n value === \"shared\" || value === \"creator\" ? value : undefined;\n break;\n case \"lastRun\":\n meta.lastRun = value;\n break;\n case \"lastStatus\":\n meta.lastStatus = value as JobFrontmatter[\"lastStatus\"];\n break;\n case \"lastError\":\n // Reverse the escaping applied in buildJobContent.\n meta.lastError = value\n .replace(/\\\\n/g, \"\\n\")\n .replace(/\\\\r/g, \"\\r\")\n .replace(/\\\\\"/g, '\"')\n .replace(/\\\\\\\\/g, \"\\\\\");\n break;\n case \"nextRun\":\n meta.nextRun = value;\n break;\n }\n }\n\n return { meta, body };\n}\n\nexport function buildJobContent(meta: JobFrontmatter, body: string): string {\n const lines = [`---`];\n lines.push(`schedule: \"${meta.schedule}\"`);\n lines.push(`enabled: ${meta.enabled}`);\n if (meta.createdBy) lines.push(`createdBy: ${meta.createdBy}`);\n if (meta.orgId) lines.push(`orgId: ${meta.orgId}`);\n if (meta.runAs) lines.push(`runAs: ${meta.runAs}`);\n if (meta.lastRun) lines.push(`lastRun: ${meta.lastRun}`);\n if (meta.lastStatus) lines.push(`lastStatus: ${meta.lastStatus}`);\n if (meta.lastError) {\n // Escape backslash, quote, then CR/LF. The frontmatter parser splits on\n // \"\\n\", so an un-escaped newline (common in stack traces) would otherwise\n // split the value across lines and corrupt/truncate the stored error.\n const escaped = meta.lastError\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\n/g, \"\\\\n\");\n lines.push(`lastError: \"${escaped}\"`);\n }\n if (meta.nextRun) lines.push(`nextRun: ${meta.nextRun}`);\n lines.push(`---`);\n lines.push(\"\");\n lines.push(body);\n return lines.join(\"\\n\");\n}\n\n// ─── Job execution ──────────────────────────────────────────────────────────\n\nexport interface SchedulerDeps {\n getActions: () => Record<string, ActionEntry>;\n getSystemPrompt: (owner: string) => Promise<string>;\n /** Optional engine override. Defaults to the resolved request engine. */\n engine?: AgentEngine;\n apiKey?: string;\n model?: string;\n /** App/template id used for org-scoped per-app model defaults. */\n appId?: string;\n}\n\nlet _isRunning = false;\n\n// Skip the DB query on every tick if we recently confirmed no jobs exist.\n// `_hasJobsCache` is invalidated whenever a `jobs/*` resource is written or\n// deleted (subscribed below), and refreshed at most every 5 minutes.\nlet _hasJobsCache: boolean | undefined;\nlet _lastJobsCheck = 0;\nconst JOBS_CHECK_INTERVAL_MS = 5 * 60_000;\nlet _emitterSubscribed = false;\n\nfunction subscribeToJobsResourceEvents(): void {\n if (_emitterSubscribed) return;\n _emitterSubscribed = true;\n // Lazy import to avoid circular deps at module load\n import(\"../resources/emitter.js\")\n .then(({ getResourcesEmitter }) => {\n getResourcesEmitter().on(\"resources\", (event: any) => {\n if (typeof event?.path === \"string\" && event.path.startsWith(\"jobs/\")) {\n _hasJobsCache = undefined;\n }\n });\n })\n .catch((err) => {\n console.warn(\n \"[jobs] resource-event subscription failed:\",\n err instanceof Error ? err.message : err,\n );\n });\n}\n\n/**\n * Process all due recurring jobs. Called every 60 seconds.\n * Sequential execution with 5-minute timeout per job.\n */\nexport async function processRecurringJobs(deps: SchedulerDeps): Promise<void> {\n // Prevent concurrent runs\n if (_isRunning) return;\n\n subscribeToJobsResourceEvents();\n\n // Skip if we recently confirmed there are no job resources to run.\n const nowMs = Date.now();\n if (\n _hasJobsCache === false &&\n nowMs - _lastJobsCheck < JOBS_CHECK_INTERVAL_MS\n ) {\n return;\n }\n\n _isRunning = true;\n\n try {\n const jobResources = await resourceListAllOwners(\"jobs/\");\n _hasJobsCache = jobResources.some(\n (r) => r.path.endsWith(\".md\") && !r.path.endsWith(\".keep\"),\n );\n _lastJobsCheck = nowMs;\n if (!_hasJobsCache) return;\n const now = new Date();\n\n for (const resource of jobResources) {\n // Skip non-markdown or .keep files\n if (!resource.path.endsWith(\".md\")) continue;\n if (resource.path.endsWith(\".keep\")) continue;\n\n const { meta, body } = parseJobFrontmatter(resource.content);\n\n // Skip disabled or missing schedule\n if (!meta.enabled || !meta.schedule) continue;\n if (!isValidCron(meta.schedule)) continue;\n\n // Skip if currently running, unless it has been stuck for more than 10 minutes\n // (server crash mid-job leaves lastStatus=running forever without this guard)\n if (meta.lastStatus === \"running\") {\n const stuckCutoff = 10 * 60 * 1000;\n if (\n meta.lastRun &&\n now.getTime() - new Date(meta.lastRun).getTime() < stuckCutoff\n ) {\n continue;\n }\n // Stuck — reset so the next check can re-run it\n meta.lastStatus = \"error\";\n meta.lastError = \"Job timed out or server crashed mid-run\";\n const next = nextOccurrence(meta.schedule, now);\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n continue;\n }\n\n // Check if due\n if (meta.nextRun) {\n const nextRunDate = new Date(meta.nextRun);\n if (nextRunDate > now) continue;\n } else {\n // No nextRun computed yet — seed it from `now` so the job waits for its\n // real next occurrence. Computing from new Date(0) (the epoch) always\n // returns a 1970 date, which is < now, so the job would fire\n // immediately on first sight regardless of its schedule.\n const next = nextOccurrence(meta.schedule, now);\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n continue;\n }\n\n // Skip if body is empty\n if (!body.trim()) continue;\n\n // Execute the job\n await executeJob(resource, meta, body, deps, now);\n }\n } catch (err) {\n // Transient WS / connection drops (Neon serverless): silently retry next\n // tick instead of spamming stderr — `retryOnConnectionError` already did\n // its retry budget at the driver level.\n const { isConnectionError } = await import(\"../db/client.js\");\n if (isConnectionError(err)) {\n _hasJobsCache = undefined; // force re-check on next successful tick\n _lastJobsCheck = 0;\n return;\n }\n // Unwrap ErrorEvent (Neon WS driver emits these on network failure) so logs show the real cause\n const detail =\n err instanceof Error\n ? err\n : ((err as any)?.error ?? (err as any)?.message ?? err);\n console.error(\"[recurring-jobs] Error processing jobs:\", detail);\n } finally {\n _isRunning = false;\n }\n}\n\n/**\n * Validate that the run-as user still exists and (if scoped to an org) is\n * still a member of that org. Skips the check for the dev-mode bypass\n * identity and the shared-owner sentinel, neither of which map to a real\n * user row.\n *\n * SECURITY: without this check the scheduler keeps running jobs as\n * `meta.createdBy` indefinitely — even after the user has been deleted,\n * removed from the org, or had their account disabled. The cron entry\n * itself is left intact so an admin can purge it manually after the\n * underlying user-state issue is investigated. See audit 12 #10.\n */\nasync function isJobRunAsStillValid(\n jobUserEmail: string,\n jobOrgId: string | undefined,\n): Promise<{ ok: boolean; reason?: string }> {\n // Shared-owner sentinel isn't a real user (used by jobs run as the\n // workspace identity).\n if (jobUserEmail === \"__shared__\") return { ok: true };\n try {\n const { getDbExec } = await import(\"../db/client.js\");\n const db = getDbExec();\n // Better Auth's user table is named \"user\" (singular). The reserved\n // word is quoted to avoid ambiguity in Postgres.\n const userResult = await db.execute({\n sql: `SELECT 1 FROM \"user\" WHERE email = ? LIMIT 1`,\n args: [jobUserEmail],\n });\n if (!userResult.rows || userResult.rows.length === 0) {\n return { ok: false, reason: `user \"${jobUserEmail}\" no longer exists` };\n }\n if (jobOrgId) {\n const memberResult = await db.execute({\n sql: `SELECT 1 FROM org_members WHERE org_id = ? AND LOWER(email) = LOWER(?) LIMIT 1`,\n args: [jobOrgId, jobUserEmail],\n });\n if (!memberResult.rows || memberResult.rows.length === 0) {\n return {\n ok: false,\n reason: `user \"${jobUserEmail}\" is no longer a member of org \"${jobOrgId}\"`,\n };\n }\n }\n return { ok: true };\n } catch (err: any) {\n // Tables may not exist on a brand-new install (no auth tables yet).\n // Treat that as \"valid\" rather than blocking every job. The check is\n // only meaningful once the auth tables exist.\n const msg = err?.message?.toLowerCase() ?? \"\";\n if (\n msg.includes(\"does not exist\") ||\n msg.includes(\"no such table\") ||\n msg.includes(\"undefined table\")\n ) {\n return { ok: true };\n }\n // Any other DB error: be conservative and let the job run rather than\n // blocking on an unexpected failure mode (e.g. transient connection\n // issue). We log so it's visible.\n console.warn(\n `[recurring-jobs] User/membership validation failed for \"${jobUserEmail}\":`,\n err?.message,\n );\n return { ok: true };\n }\n}\n\nasync function executeJob(\n resource: Resource,\n meta: JobFrontmatter,\n body: string,\n deps: SchedulerDeps,\n now: Date,\n): Promise<void> {\n const jobName = resource.path.replace(/^jobs\\//, \"\").replace(/\\.md$/, \"\");\n\n // Set owner context so all scoped operations (app-state, resources, etc.)\n // operate on the correct user's data\n const effectiveRunAs = meta.runAs ?? \"creator\";\n const jobUserEmail =\n effectiveRunAs === \"creator\"\n ? meta.createdBy || resource.owner\n : resource.owner;\n const jobOrgId = meta.orgId ?? undefined;\n\n // SECURITY (audit 12 #10): re-validate the run-as user/membership on\n // every tick. Sharing revocation, user deletion, and org-member removal\n // must take effect for already-scheduled jobs. Skip the tick on\n // failure; leave the cron entry alone so an admin can purge after\n // investigation.\n const validity = await isJobRunAsStillValid(jobUserEmail, jobOrgId);\n if (!validity.ok) {\n console.warn(\n `[recurring-jobs] Skipping job \"${jobName}\": ${validity.reason}. ` +\n `User/membership no longer valid — leaving cron entry for admin review.`,\n );\n // Mark as skipped without resetting nextRun so an admin can find it.\n meta.lastRun = now.toISOString();\n meta.lastStatus = \"skipped\";\n meta.lastError = validity.reason;\n await updateResource(resource, meta, body);\n return;\n }\n\n // Mark as running\n meta.lastRun = now.toISOString();\n meta.lastStatus = \"running\";\n meta.lastError = undefined;\n await updateResource(resource, meta, body);\n\n await runWithRequestContext(\n { userEmail: jobUserEmail, orgId: jobOrgId },\n async () => {\n try {\n const actions = deps.getActions();\n const systemPrompt = await deps.getSystemPrompt(jobUserEmail);\n const tools = actionsToEngineTools(actions);\n\n // Prefer the job runner's saved Anthropic key so recurring jobs\n // don't silently bill the shared platform key once a user has\n // brought their own. Falls back to the platform key when absent.\n const userApiKey = await getOwnerActiveApiKey(jobUserEmail);\n const engine =\n deps.engine ??\n (await resolveEngine({\n apiKey: userApiKey ?? deps.apiKey,\n appId: deps.appId,\n }));\n const model =\n deps.model ??\n (await getStoredModelForEngine(engine, { appId: deps.appId })) ??\n engine.defaultModel;\n\n // Create a chat thread for this run\n const threadTitle = `Job: ${jobName} — ${now.toLocaleDateString()}`;\n const thread = await createThread(jobUserEmail, { title: threadTitle });\n\n const jobText = `[Recurring Job: ${jobName}]\\nSchedule: ${describeCron(meta.schedule)}\\n\\nExecute the following job instructions:\\n\\n${body}`;\n const messages = [\n {\n role: \"user\" as const,\n content: [{ type: \"text\" as const, text: jobText }],\n },\n ];\n\n // Route through startRun (from run-manager) instead of calling\n // runAgentLoop directly. This adds:\n // 1. A heartbeat row in agent_runs so a serverless kill is detected\n // by reapAllStaleRuns on the next startup and the row is flipped\n // to 'errored' — no more stranded lastStatus:\"running\" in the job\n // frontmatter after the next tick resets it via the stuck-guard.\n // 2. The soft-timeout infrastructure so the job checkpoints cleanly\n // before serverless hard-kill rather than dying mid-flight.\n // 3. SQL abort checks so a displaced/reaped run self-aborts instead\n // of completing invisibly and potentially overwriting newer state.\n const runId = `job-${jobName.replace(/[^a-zA-Z0-9._-]/g, \"-\")}-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n\n // Use the same soft-timeout logic as interactive runs. On hosted\n // runtimes this clamps to 40s (under the gateway wall); locally it\n // defaults to 0 (no framework timeout). The 5-minute hard-abort\n // below is still provided as a backstop via the startRun signal.\n const softTimeoutMs = resolveRunSoftTimeoutMs(undefined, {\n useHostedDefault: true,\n });\n\n // Hard-abort backstop: 5 minutes. On hosted runtimes the soft-timeout\n // will fire first; locally this is the only guard.\n const hardAbortTimer = setTimeout(\n () => {\n // startRun's abort controller handles this below, but we still need\n // the handle to clear it in the finally block.\n },\n 5 * 60 * 1000,\n );\n\n let jobError: Error | null = null;\n await new Promise<void>((resolve, reject) => {\n const activeRun = startRun(\n runId,\n thread.id,\n async (send, signal) => {\n try {\n await runAgentLoop({\n engine,\n model,\n systemPrompt,\n tools,\n messages,\n actions,\n send,\n signal,\n threadId: thread.id,\n });\n } catch (err) {\n throw err;\n }\n },\n // onComplete: run finished (completed or aborted)\n async (run) => {\n if (run.status === \"completed\") {\n resolve();\n } else {\n reject(new Error(`Job run ended with status: ${run.status}`));\n }\n },\n {\n softTimeoutMs,\n // turnId defaults to runId — fine for single-turn jobs\n },\n );\n\n // Hard-abort backstop: abort the run-manager's own controller after\n // 5 minutes if it hasn't finished naturally.\n clearTimeout(hardAbortTimer);\n setTimeout(\n () => {\n if (activeRun.status === \"running\") {\n activeRun.abort.abort(\"job_hard_timeout\");\n reject(new Error(\"Job timed out after 5 minutes\"));\n }\n },\n 5 * 60 * 1000,\n );\n }).catch((err: any) => {\n jobError = err;\n });\n\n if (jobError) throw jobError;\n\n // Success — update status. Compute the next run from completion time,\n // not the job's start time `now`: a long run could otherwise schedule a\n // nextRun that's already in the past and re-fire immediately next tick.\n const next = nextOccurrence(meta.schedule, new Date());\n meta.lastStatus = \"success\";\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n\n console.log(\n `[recurring-jobs] Job \"${jobName}\" completed. Next run: ${meta.nextRun}`,\n );\n } catch (err: any) {\n // Error — update status. Use completion time (see success path).\n const next = nextOccurrence(meta.schedule, new Date());\n meta.lastStatus = \"error\";\n meta.lastError = err?.message?.slice(0, 200) || \"Unknown error\";\n meta.nextRun = next.toISOString();\n await updateResource(resource, meta, body);\n\n console.error(\n `[recurring-jobs] Job \"${jobName}\" failed:`,\n err?.message,\n );\n }\n },\n ); // end runWithRequestContext\n}\n\nasync function updateResource(\n resource: Resource,\n meta: JobFrontmatter,\n body: string,\n): Promise<void> {\n const content = buildJobContent(meta, body);\n await resourcePut(resource.owner, resource.path, content);\n}\n"]}
@@ -0,0 +1,14 @@
1
+ declare const _default: import("../../action.js").ActionDefinition<{
2
+ name: string;
3
+ ttlDays?: number | undefined;
4
+ }, {
5
+ token: string;
6
+ id: string;
7
+ serviceName: string;
8
+ serviceEmail: string;
9
+ orgId: string;
10
+ ttlDays: number;
11
+ note: string;
12
+ }>;
13
+ export default _default;
14
+ //# sourceMappingURL=create-org-service-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-org-service-token.d.ts","sourceRoot":"","sources":["../../../src/mcp/actions/create-org-service-token.ts"],"names":[],"mappings":";;;;;;;;;;;;AA2BA,wBA0DG"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Mint an org-scoped SERVICE token for CI and other non-human callers (e.g.
3
+ * the `PLAN_RECAP_TOKEN` GitHub secret used by PR Visual Recap). Unlike a
4
+ * personal connect token, the credential belongs to the ORG: it keeps working
5
+ * when the human who minted it leaves or revokes their own tokens, and rows
6
+ * created with it are org-scoped so every org member can see them.
7
+ *
8
+ * SECURITY:
9
+ * - Gated to org owners/admins (see service-token-access.ts).
10
+ * - The token value appears ONLY in this action's response — it is never
11
+ * stored (only its `jti`) and never logged.
12
+ * - Not callable by the sandboxed agent tool loop (`toolCallable: false`):
13
+ * minting a long-lived credential must be an explicit human/HTTP/CLI act,
14
+ * never a prompt-injection target.
15
+ * - Revocable via `revoke-org-service-token` — same `revoked_at` gate the
16
+ * personal-token revocation path uses.
17
+ */
18
+ import { z } from "zod";
19
+ import { defineAction } from "../../action.js";
20
+ import { getRequestContext } from "../../server/request-context.js";
21
+ import { getAppProductionUrl } from "../../server/app-url.js";
22
+ import { mintOrgServiceToken } from "../connect-route.js";
23
+ import { requireServiceTokenCaller, ServiceTokenError, } from "./service-token-access.js";
24
+ export default defineAction({
25
+ description: "Create a named, org-scoped service token (for CI like PR Visual Recap's PLAN_RECAP_TOKEN). The token acts as a service principal owned by the organization, not a person. Org owner/admin only. The token value is returned ONCE and never stored — copy it immediately.",
26
+ schema: z.object({
27
+ name: z
28
+ .string()
29
+ .min(1)
30
+ .max(64)
31
+ .describe("Short service name, e.g. 'ci' or 'pr-recap'"),
32
+ ttlDays: z
33
+ .number()
34
+ .int()
35
+ .min(1)
36
+ .max(365)
37
+ .optional()
38
+ .describe("Token lifetime in days (1-365, default 365)"),
39
+ }),
40
+ toolCallable: false,
41
+ run: async (args, ctx) => {
42
+ const caller = await requireServiceTokenCaller({
43
+ userEmail: ctx?.userEmail,
44
+ orgId: ctx?.orgId,
45
+ level: "manage",
46
+ });
47
+ // App origin for OAuth-signed tokens (resource/issuer binding). The MCP
48
+ // path provides requestOrigin via runWithRequestContext; the HTTP action
49
+ // route falls back to the configured production URL. Deployments with
50
+ // A2A_SECRET don't depend on it (the A2A signer ignores appUrl).
51
+ const appUrl = (getRequestContext()?.requestOrigin || getAppProductionUrl()).replace(/\/+$/, "");
52
+ if (!appUrl && !process.env.A2A_SECRET?.trim()) {
53
+ throw new ServiceTokenError("Could not determine the app URL needed to mint a token. Set APP_URL on the deployment.", 500);
54
+ }
55
+ const minted = await mintOrgServiceToken({
56
+ serviceName: args.name,
57
+ orgId: caller.orgId,
58
+ createdBy: caller.email,
59
+ ttlDays: args.ttlDays,
60
+ appUrl,
61
+ });
62
+ return {
63
+ // The ONLY place the secret ever appears. Never stored, never logged.
64
+ token: minted.token,
65
+ id: minted.id,
66
+ serviceName: minted.serviceName,
67
+ serviceEmail: minted.serviceEmail,
68
+ orgId: caller.orgId,
69
+ ttlDays: minted.ttlDays,
70
+ note: "Store this token now (e.g. as the PLAN_RECAP_TOKEN GitHub Actions secret). It will not be shown again. Revoke it any time with revoke-org-service-token.",
71
+ };
72
+ },
73
+ });
74
+ //# sourceMappingURL=create-org-service-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-org-service-token.js","sourceRoot":"","sources":["../../../src/mcp/actions/create-org-service-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,yBAAyB,EACzB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAEnC,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,0QAA0Q;IAC5Q,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,CAAC,6CAA6C,CAAC;QAC1D,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,6CAA6C,CAAC;KAC3D,CAAC;IACF,YAAY,EAAE,KAAK;IACnB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC;YAC7C,SAAS,EAAE,GAAG,EAAE,SAAS;YACzB,KAAK,EAAE,GAAG,EAAE,KAAK;YACjB,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;QAEH,wEAAwE;QACxE,yEAAyE;QACzE,sEAAsE;QACtE,iEAAiE;QACjE,MAAM,MAAM,GAAG,CACb,iBAAiB,EAAE,EAAE,aAAa,IAAI,mBAAmB,EAAE,CAC5D,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtB,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,CAAC;YAC/C,MAAM,IAAI,iBAAiB,CACzB,wFAAwF,EACxF,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC;YACvC,WAAW,EAAE,IAAI,CAAC,IAAI;YACtB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,KAAK;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM;SACP,CAAC,CAAC;QAEH,OAAO;YACL,sEAAsE;YACtE,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,IAAI,EAAE,0JAA0J;SACjK,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["/**\n * Mint an org-scoped SERVICE token for CI and other non-human callers (e.g.\n * the `PLAN_RECAP_TOKEN` GitHub secret used by PR Visual Recap). Unlike a\n * personal connect token, the credential belongs to the ORG: it keeps working\n * when the human who minted it leaves or revokes their own tokens, and rows\n * created with it are org-scoped so every org member can see them.\n *\n * SECURITY:\n * - Gated to org owners/admins (see service-token-access.ts).\n * - The token value appears ONLY in this action's response — it is never\n * stored (only its `jti`) and never logged.\n * - Not callable by the sandboxed agent tool loop (`toolCallable: false`):\n * minting a long-lived credential must be an explicit human/HTTP/CLI act,\n * never a prompt-injection target.\n * - Revocable via `revoke-org-service-token` — same `revoked_at` gate the\n * personal-token revocation path uses.\n */\nimport { z } from \"zod\";\nimport { defineAction } from \"../../action.js\";\nimport { getRequestContext } from \"../../server/request-context.js\";\nimport { getAppProductionUrl } from \"../../server/app-url.js\";\nimport { mintOrgServiceToken } from \"../connect-route.js\";\nimport {\n requireServiceTokenCaller,\n ServiceTokenError,\n} from \"./service-token-access.js\";\n\nexport default defineAction({\n description:\n \"Create a named, org-scoped service token (for CI like PR Visual Recap's PLAN_RECAP_TOKEN). The token acts as a service principal owned by the organization, not a person. Org owner/admin only. The token value is returned ONCE and never stored — copy it immediately.\",\n schema: z.object({\n name: z\n .string()\n .min(1)\n .max(64)\n .describe(\"Short service name, e.g. 'ci' or 'pr-recap'\"),\n ttlDays: z\n .number()\n .int()\n .min(1)\n .max(365)\n .optional()\n .describe(\"Token lifetime in days (1-365, default 365)\"),\n }),\n toolCallable: false,\n run: async (args, ctx) => {\n const caller = await requireServiceTokenCaller({\n userEmail: ctx?.userEmail,\n orgId: ctx?.orgId,\n level: \"manage\",\n });\n\n // App origin for OAuth-signed tokens (resource/issuer binding). The MCP\n // path provides requestOrigin via runWithRequestContext; the HTTP action\n // route falls back to the configured production URL. Deployments with\n // A2A_SECRET don't depend on it (the A2A signer ignores appUrl).\n const appUrl = (\n getRequestContext()?.requestOrigin || getAppProductionUrl()\n ).replace(/\\/+$/, \"\");\n if (!appUrl && !process.env.A2A_SECRET?.trim()) {\n throw new ServiceTokenError(\n \"Could not determine the app URL needed to mint a token. Set APP_URL on the deployment.\",\n 500,\n );\n }\n\n const minted = await mintOrgServiceToken({\n serviceName: args.name,\n orgId: caller.orgId,\n createdBy: caller.email,\n ttlDays: args.ttlDays,\n appUrl,\n });\n\n return {\n // The ONLY place the secret ever appears. Never stored, never logged.\n token: minted.token,\n id: minted.id,\n serviceName: minted.serviceName,\n serviceEmail: minted.serviceEmail,\n orgId: caller.orgId,\n ttlDays: minted.ttlDays,\n note: \"Store this token now (e.g. as the PLAN_RECAP_TOKEN GitHub Actions secret). It will not be shown again. Revoke it any time with revoke-org-service-token.\",\n };\n },\n});\n"]}
@@ -0,0 +1,17 @@
1
+ declare const _default: import("../../action.js").ActionDefinition<{
2
+ includeRevoked?: boolean | undefined;
3
+ }, {
4
+ orgId: string;
5
+ tokens: {
6
+ id: string;
7
+ serviceName: string | null;
8
+ serviceEmail: string;
9
+ label: string | null;
10
+ createdBy: string | null;
11
+ createdAt: number | null;
12
+ lastUsedAt: number | null;
13
+ revokedAt: number | null;
14
+ }[];
15
+ }>;
16
+ export default _default;
17
+ //# sourceMappingURL=list-org-service-tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-org-service-tokens.d.ts","sourceRoot":"","sources":["../../../src/mcp/actions/list-org-service-tokens.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAWA,wBA+BG"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * List the active org service tokens — metadata only (name, who minted it,
3
+ * created/last-used/revoked timestamps). Token values are never stored, so
4
+ * they can never appear here. Any org member may list; minting and revoking
5
+ * are owner/admin-gated.
6
+ */
7
+ import { z } from "zod";
8
+ import { defineAction } from "../../action.js";
9
+ import { listOrgServiceTokens } from "../connect-store.js";
10
+ import { requireServiceTokenCaller } from "./service-token-access.js";
11
+ export default defineAction({
12
+ description: "List your organization's service tokens (CI credentials such as PLAN_RECAP_TOKEN): name, who created them, created/last-used times, and revocation state. Token values are never stored and never shown. Any org member can list.",
13
+ schema: z.object({
14
+ includeRevoked: z
15
+ .boolean()
16
+ .optional()
17
+ .describe("Also include revoked tokens (default false)"),
18
+ }),
19
+ http: { method: "GET" },
20
+ run: async (args, ctx) => {
21
+ const caller = await requireServiceTokenCaller({
22
+ userEmail: ctx?.userEmail,
23
+ orgId: ctx?.orgId,
24
+ level: "read",
25
+ });
26
+ const rows = await listOrgServiceTokens(caller.orgId);
27
+ const tokens = rows
28
+ .filter((row) => args.includeRevoked || row.revokedAt == null)
29
+ .map((row) => ({
30
+ id: row.id,
31
+ serviceName: row.serviceName,
32
+ serviceEmail: row.ownerEmail,
33
+ label: row.label,
34
+ createdBy: row.createdBy,
35
+ createdAt: row.createdAt,
36
+ lastUsedAt: row.lastUsedAt,
37
+ revokedAt: row.revokedAt,
38
+ }));
39
+ return { orgId: caller.orgId, tokens };
40
+ },
41
+ });
42
+ //# sourceMappingURL=list-org-service-tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-org-service-tokens.js","sourceRoot":"","sources":["../../../src/mcp/actions/list-org-service-tokens.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,mOAAmO;IACrO,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,cAAc,EAAE,CAAC;aACd,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,6CAA6C,CAAC;KAC3D,CAAC;IACF,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IACvB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC;YAC7C,SAAS,EAAE,GAAG,EAAE,SAAS;YACzB,KAAK,EAAE,GAAG,EAAE,KAAK;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,oBAAoB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI;aAChB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,IAAI,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC;aAC7D,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACb,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,YAAY,EAAE,GAAG,CAAC,UAAU;YAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,SAAS,EAAE,GAAG,CAAC,SAAS;SACzB,CAAC,CAAC,CAAC;QACN,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC;CACF,CAAC,CAAC","sourcesContent":["/**\n * List the active org service tokens — metadata only (name, who minted it,\n * created/last-used/revoked timestamps). Token values are never stored, so\n * they can never appear here. Any org member may list; minting and revoking\n * are owner/admin-gated.\n */\nimport { z } from \"zod\";\nimport { defineAction } from \"../../action.js\";\nimport { listOrgServiceTokens } from \"../connect-store.js\";\nimport { requireServiceTokenCaller } from \"./service-token-access.js\";\n\nexport default defineAction({\n description:\n \"List your organization's service tokens (CI credentials such as PLAN_RECAP_TOKEN): name, who created them, created/last-used times, and revocation state. Token values are never stored and never shown. Any org member can list.\",\n schema: z.object({\n includeRevoked: z\n .boolean()\n .optional()\n .describe(\"Also include revoked tokens (default false)\"),\n }),\n http: { method: \"GET\" },\n run: async (args, ctx) => {\n const caller = await requireServiceTokenCaller({\n userEmail: ctx?.userEmail,\n orgId: ctx?.orgId,\n level: \"read\",\n });\n const rows = await listOrgServiceTokens(caller.orgId);\n const tokens = rows\n .filter((row) => args.includeRevoked || row.revokedAt == null)\n .map((row) => ({\n id: row.id,\n serviceName: row.serviceName,\n serviceEmail: row.ownerEmail,\n label: row.label,\n createdBy: row.createdBy,\n createdAt: row.createdAt,\n lastUsedAt: row.lastUsedAt,\n revokedAt: row.revokedAt,\n }));\n return { orgId: caller.orgId, tokens };\n },\n});\n"]}
@@ -0,0 +1,7 @@
1
+ declare const _default: import("../../action.js").ActionDefinition<{
2
+ id: string;
3
+ }, {
4
+ ok: boolean;
5
+ }>;
6
+ export default _default;
7
+ //# sourceMappingURL=revoke-org-service-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke-org-service-token.d.ts","sourceRoot":"","sources":["../../../src/mcp/actions/revoke-org-service-token.ts"],"names":[],"mappings":";;;;;AAYA,wBAgBG"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Revoke an org service token by id. Owner/admin only. Uses the same
3
+ * `revoked_at` gate as personal-token revocation, so the token stops
4
+ * authenticating on its next request. The revoke is scoped by org id AND
5
+ * kind='service' in SQL — a caller can never revoke another org's token or a
6
+ * personal token through this action.
7
+ */
8
+ import { z } from "zod";
9
+ import { defineAction } from "../../action.js";
10
+ import { revokeOrgServiceToken } from "../connect-store.js";
11
+ import { requireServiceTokenCaller } from "./service-token-access.js";
12
+ export default defineAction({
13
+ description: "Revoke one of your organization's service tokens by id (get ids from list-org-service-tokens). The token stops working immediately. Org owner/admin only. Idempotent.",
14
+ schema: z.object({
15
+ id: z.string().min(1).describe("Service token id to revoke"),
16
+ }),
17
+ toolCallable: false,
18
+ run: async (args, ctx) => {
19
+ const caller = await requireServiceTokenCaller({
20
+ userEmail: ctx?.userEmail,
21
+ orgId: ctx?.orgId,
22
+ level: "manage",
23
+ });
24
+ const revoked = await revokeOrgServiceToken(caller.orgId, args.id);
25
+ return { ok: revoked };
26
+ },
27
+ });
28
+ //# sourceMappingURL=revoke-org-service-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke-org-service-token.js","sourceRoot":"","sources":["../../../src/mcp/actions/revoke-org-service-token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,uKAAuK;IACzK,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;KAC7D,CAAC;IACF,YAAY,EAAE,KAAK;IACnB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC;YAC7C,SAAS,EAAE,GAAG,EAAE,SAAS;YACzB,KAAK,EAAE,GAAG,EAAE,KAAK;YACjB,KAAK,EAAE,QAAQ;SAChB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACnE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;IACzB,CAAC;CACF,CAAC,CAAC","sourcesContent":["/**\n * Revoke an org service token by id. Owner/admin only. Uses the same\n * `revoked_at` gate as personal-token revocation, so the token stops\n * authenticating on its next request. The revoke is scoped by org id AND\n * kind='service' in SQL — a caller can never revoke another org's token or a\n * personal token through this action.\n */\nimport { z } from \"zod\";\nimport { defineAction } from \"../../action.js\";\nimport { revokeOrgServiceToken } from \"../connect-store.js\";\nimport { requireServiceTokenCaller } from \"./service-token-access.js\";\n\nexport default defineAction({\n description:\n \"Revoke one of your organization's service tokens by id (get ids from list-org-service-tokens). The token stops working immediately. Org owner/admin only. Idempotent.\",\n schema: z.object({\n id: z.string().min(1).describe(\"Service token id to revoke\"),\n }),\n toolCallable: false,\n run: async (args, ctx) => {\n const caller = await requireServiceTokenCaller({\n userEmail: ctx?.userEmail,\n orgId: ctx?.orgId,\n level: \"manage\",\n });\n const revoked = await revokeOrgServiceToken(caller.orgId, args.id);\n return { ok: revoked };\n },\n});\n"]}
@@ -0,0 +1,24 @@
1
+ import type { OrgRole } from "../../org/types.js";
2
+ export declare class ServiceTokenError extends Error {
3
+ statusCode: number;
4
+ constructor(message: string, statusCode: number);
5
+ }
6
+ /** Look up the caller's role in `orgId`, or null when not a member. */
7
+ export declare function getOrgRoleForEmail(orgId: string, email: string): Promise<OrgRole | null>;
8
+ export interface ServiceTokenCallerContext {
9
+ email: string;
10
+ orgId: string;
11
+ role: OrgRole;
12
+ }
13
+ /**
14
+ * Resolve and gate the caller for a service-token action. Throws
15
+ * `ServiceTokenError` (401/400/403) on failure so the action route maps it to
16
+ * the right HTTP status.
17
+ */
18
+ export declare function requireServiceTokenCaller(params: {
19
+ userEmail: string | undefined;
20
+ orgId: string | null | undefined;
21
+ /** 'manage' = mint/revoke (owner/admin only); 'read' = list (any member). */
22
+ level: "manage" | "read";
23
+ }): Promise<ServiceTokenCallerContext>;
24
+ //# sourceMappingURL=service-token-access.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-token-access.d.ts","sourceRoot":"","sources":["../../../src/mcp/actions/service-token-access.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,UAAU,EAAE,MAAM,CAAC;gBACP,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAKhD;AAED,uEAAuE;AACvE,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAczB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,6EAA6E;IAC7E,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,yBAAyB,CAAC,CA0BrC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Shared gating for the org service-token actions.
3
+ *
4
+ * GATING DECISION: the org model HAS roles (`org_members.role` is
5
+ * 'owner' | 'admin' | 'member' — see `org/types.ts`), so minting and revoking
6
+ * service tokens require the caller to be an org **owner or admin**. Listing
7
+ * is allowed for any org member (token values are never stored, so the list
8
+ * only exposes metadata).
9
+ *
10
+ * Synthetic service identities (`svc-*@service.<orgId>`) are never inserted
11
+ * into `org_members`, so a leaked service token can NOT mint further service
12
+ * tokens or revoke others — the role lookup simply finds no membership.
13
+ */
14
+ import { getDbExec } from "../../db/client.js";
15
+ export class ServiceTokenError extends Error {
16
+ statusCode;
17
+ constructor(message, statusCode) {
18
+ super(message);
19
+ this.name = "ServiceTokenError";
20
+ this.statusCode = statusCode;
21
+ }
22
+ }
23
+ /** Look up the caller's role in `orgId`, or null when not a member. */
24
+ export async function getOrgRoleForEmail(orgId, email) {
25
+ try {
26
+ const { rows } = await getDbExec().execute({
27
+ sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
28
+ args: [orgId, email.toLowerCase()],
29
+ });
30
+ const role = rows[0]?.role;
31
+ return role === "owner" || role === "admin" || role === "member"
32
+ ? role
33
+ : null;
34
+ }
35
+ catch {
36
+ // org tables not provisioned (template without orgs) → no membership.
37
+ return null;
38
+ }
39
+ }
40
+ /**
41
+ * Resolve and gate the caller for a service-token action. Throws
42
+ * `ServiceTokenError` (401/400/403) on failure so the action route maps it to
43
+ * the right HTTP status.
44
+ */
45
+ export async function requireServiceTokenCaller(params) {
46
+ const email = params.userEmail?.trim();
47
+ if (!email) {
48
+ throw new ServiceTokenError("Sign in to manage org service tokens.", 401);
49
+ }
50
+ const orgId = params.orgId?.trim();
51
+ if (!orgId) {
52
+ throw new ServiceTokenError("No active organization. Service tokens are org-scoped — join or create an organization first.", 400);
53
+ }
54
+ const role = await getOrgRoleForEmail(orgId, email);
55
+ if (!role) {
56
+ throw new ServiceTokenError("You are not a member of this organization.", 403);
57
+ }
58
+ if (params.level === "manage" && role === "member") {
59
+ throw new ServiceTokenError("Only org owners or admins can create or revoke service tokens.", 403);
60
+ }
61
+ return { email, orgId, role };
62
+ }
63
+ //# sourceMappingURL=service-token-access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-token-access.js","sourceRoot":"","sources":["../../../src/mcp/actions/service-token-access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG/C,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,UAAU,CAAS;IACnB,YAAY,OAAe,EAAE,UAAkB;QAC7C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAa,EACb,KAAa;IAEb,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC;YACzC,GAAG,EAAE,4EAA4E;YACjF,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;SACnC,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAC3B,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ;YAC9D,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,sEAAsE;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAQD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,MAK/C;IACC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,iBAAiB,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,iBAAiB,CACzB,+FAA+F,EAC/F,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACpD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,iBAAiB,CACzB,4CAA4C,EAC5C,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACnD,MAAM,IAAI,iBAAiB,CACzB,gEAAgE,EAChE,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAChC,CAAC","sourcesContent":["/**\n * Shared gating for the org service-token actions.\n *\n * GATING DECISION: the org model HAS roles (`org_members.role` is\n * 'owner' | 'admin' | 'member' — see `org/types.ts`), so minting and revoking\n * service tokens require the caller to be an org **owner or admin**. Listing\n * is allowed for any org member (token values are never stored, so the list\n * only exposes metadata).\n *\n * Synthetic service identities (`svc-*@service.<orgId>`) are never inserted\n * into `org_members`, so a leaked service token can NOT mint further service\n * tokens or revoke others — the role lookup simply finds no membership.\n */\nimport { getDbExec } from \"../../db/client.js\";\nimport type { OrgRole } from \"../../org/types.js\";\n\nexport class ServiceTokenError extends Error {\n statusCode: number;\n constructor(message: string, statusCode: number) {\n super(message);\n this.name = \"ServiceTokenError\";\n this.statusCode = statusCode;\n }\n}\n\n/** Look up the caller's role in `orgId`, or null when not a member. */\nexport async function getOrgRoleForEmail(\n orgId: string,\n email: string,\n): Promise<OrgRole | null> {\n try {\n const { rows } = await getDbExec().execute({\n sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, email.toLowerCase()],\n });\n const role = rows[0]?.role;\n return role === \"owner\" || role === \"admin\" || role === \"member\"\n ? role\n : null;\n } catch {\n // org tables not provisioned (template without orgs) → no membership.\n return null;\n }\n}\n\nexport interface ServiceTokenCallerContext {\n email: string;\n orgId: string;\n role: OrgRole;\n}\n\n/**\n * Resolve and gate the caller for a service-token action. Throws\n * `ServiceTokenError` (401/400/403) on failure so the action route maps it to\n * the right HTTP status.\n */\nexport async function requireServiceTokenCaller(params: {\n userEmail: string | undefined;\n orgId: string | null | undefined;\n /** 'manage' = mint/revoke (owner/admin only); 'read' = list (any member). */\n level: \"manage\" | \"read\";\n}): Promise<ServiceTokenCallerContext> {\n const email = params.userEmail?.trim();\n if (!email) {\n throw new ServiceTokenError(\"Sign in to manage org service tokens.\", 401);\n }\n const orgId = params.orgId?.trim();\n if (!orgId) {\n throw new ServiceTokenError(\n \"No active organization. Service tokens are org-scoped — join or create an organization first.\",\n 400,\n );\n }\n const role = await getOrgRoleForEmail(orgId, email);\n if (!role) {\n throw new ServiceTokenError(\n \"You are not a member of this organization.\",\n 403,\n );\n }\n if (params.level === \"manage\" && role === \"member\") {\n throw new ServiceTokenError(\n \"Only org owners or admins can create or revoke service tokens.\",\n 403,\n );\n }\n return { email, orgId, role };\n}\n"]}