@agent-native/core 0.161.23 → 0.163.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +27 -2
  4. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +18 -2
  5. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  6. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +27 -2
  7. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  8. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +27 -2
  9. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  10. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +27 -2
  11. package/corpus/templates/calendar/server/handlers/google-auth.ts +1 -8
  12. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  13. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
  14. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +88 -35
  15. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +36 -1
  16. package/corpus/templates/clips/app/i18n/en-US.ts +4 -3
  17. package/corpus/templates/clips/app/lib/camera-composite.ts +15 -1
  18. package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-crashes-when-a-camera-bubble-starts-at-a-tin.md +6 -0
  19. package/corpus/templates/clips/desktop/src/app.tsx +30 -40
  20. package/corpus/templates/clips/desktop/src/components/MicOffConfirmation.tsx +47 -0
  21. package/corpus/templates/clips/desktop/src/styles.css +110 -0
  22. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +114 -7
  23. package/corpus/templates/clips/shared/recording-capture.ts +18 -13
  24. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  25. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +27 -2
  26. package/corpus/templates/content/actions/create-content-database.ts +1 -1
  27. package/corpus/templates/content/actions/create-document.ts +1 -1
  28. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -5
  29. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +0 -3
  30. package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +0 -4
  31. package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +4 -1
  32. package/corpus/templates/content/app/hooks/use-notion.ts +17 -15
  33. package/corpus/templates/crm/.agents/skills/real-time-sync/SKILL.md +1 -1
  34. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +27 -2
  35. package/corpus/templates/design/.agents/skills/real-time-sync/SKILL.md +1 -1
  36. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +27 -2
  37. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +6 -1
  38. package/corpus/templates/dispatch/.agents/skills/real-time-sync/SKILL.md +1 -1
  39. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +27 -2
  40. package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +1 -1
  41. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +27 -2
  42. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  43. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +27 -2
  44. package/corpus/templates/macros/.agents/skills/real-time-sync/SKILL.md +1 -1
  45. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +27 -2
  46. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  47. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +27 -2
  48. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +18 -3
  49. package/corpus/templates/mail/server/handlers/google-auth.ts +1 -8
  50. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  51. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +27 -2
  52. package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +4 -0
  53. package/corpus/templates/slides/.agents/skills/real-time-sync/SKILL.md +1 -1
  54. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +27 -2
  55. package/corpus/templates/slides/actions/_await-fit-check.ts +30 -5
  56. package/corpus/templates/slides/actions/add-slide.ts +6 -2
  57. package/corpus/templates/slides/actions/create-deck.ts +2 -1
  58. package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +3 -3
  59. package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +3 -3
  60. package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -1
  61. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
  62. package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +1 -1
  63. package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -0
  64. package/corpus/templates/slides/app/pages/DeckEditor.tsx +35 -2
  65. package/corpus/templates/slides/app/routes/p.$id.tsx +3 -1
  66. package/corpus/templates/slides/changelog/2026-08-18-generated-slides-preserve-speaker-notes.md +6 -0
  67. package/corpus/templates/slides/server/handlers/assets.ts +23 -12
  68. package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +15 -6
  69. package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +15 -6
  70. package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +34 -19
  71. package/corpus/templates/slides/server/handlers/request-auth-context.ts +1 -0
  72. package/corpus/templates/slides/server/handlers/share.ts +1 -1
  73. package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
  74. package/corpus/templates/slides/server/routes/api/deck-agent-context.json.get.ts +1 -1
  75. package/corpus/templates/slides/server/routes/api/exports/[filename].get.ts +9 -3
  76. package/corpus/templates/slides/server/routes/api/exports/google-slides.post.ts +12 -5
  77. package/corpus/templates/slides/server/routes/api/exports/html.post.ts +9 -7
  78. package/corpus/templates/slides/server/routes/api/exports/pptx.post.ts +9 -7
  79. package/corpus/templates/slides/shared/api.ts +7 -1
  80. package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
  81. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +27 -2
  82. package/dist/agent/engine/translate-anthropic.js +27 -2
  83. package/dist/agent/production-agent.d.ts +2 -2
  84. package/dist/agent/production-agent.js +16 -8
  85. package/dist/agent/thread-data-builder.d.ts +1 -0
  86. package/dist/agent/thread-data-builder.js +6 -4
  87. package/dist/agent/tool-approval-store.d.ts +10 -1
  88. package/dist/agent/tool-approval-store.js +19 -2
  89. package/dist/agent/types.d.ts +9 -0
  90. package/dist/app-config/schema.d.ts +1 -0
  91. package/dist/app-config/workspace.d.ts +1 -0
  92. package/dist/app-config/workspace.js +8 -0
  93. package/dist/chat-threads/schema.d.ts +2 -2
  94. package/dist/client/AssistantChat.js +14 -6
  95. package/dist/client/EnvironmentBadge.d.ts +15 -0
  96. package/dist/client/EnvironmentBadge.js +79 -0
  97. package/dist/client/MultiTabAssistantChat.js +73 -17
  98. package/dist/client/agent-chat-adapter.js +11 -1
  99. package/dist/client/api-path.js +14 -1
  100. package/dist/client/app-providers.js +2 -1
  101. package/dist/client/chat/tool-call-display.d.ts +12 -2
  102. package/dist/client/chat/tool-call-display.js +17 -7
  103. package/dist/client/chat/widgets/WorkspaceFileWidget.js +1 -1
  104. package/dist/client/chat/widgets/builtin-tool-renderers.d.ts +6 -0
  105. package/dist/client/chat/widgets/builtin-tool-renderers.js +19 -0
  106. package/dist/client/onboarding/FirstRunOnboarding.js +46 -32
  107. package/dist/client/onboarding/use-onboarding.d.ts +8 -1
  108. package/dist/client/onboarding/use-onboarding.js +22 -7
  109. package/dist/client/org/TeamPage.js +15 -2
  110. package/dist/client/org/hooks.d.ts +2 -0
  111. package/dist/client/org/hooks.js +12 -0
  112. package/dist/client/org/index.d.ts +2 -2
  113. package/dist/client/org/index.js +1 -1
  114. package/dist/client/session-replay.js +58 -15
  115. package/dist/client/settings/SettingsTabsPage.js +19 -6
  116. package/dist/client/sharing/ShareButton.js +43 -18
  117. package/dist/client/sharing/useShareButtonController.d.ts +12 -2
  118. package/dist/client/sharing/useShareButtonController.js +38 -8
  119. package/dist/client/sse-event-processor.d.ts +7 -0
  120. package/dist/client/sse-event-processor.js +4 -1
  121. package/dist/client/ui/index.d.ts +1 -0
  122. package/dist/client/ui/index.js +1 -0
  123. package/dist/client/use-action.js +26 -0
  124. package/dist/collab/struct-routes.d.ts +1 -1
  125. package/dist/config.d.ts +15 -0
  126. package/dist/config.js +53 -0
  127. package/dist/dashboard-storage/schema.d.ts +2 -2
  128. package/dist/data-programs/schema.d.ts +2 -2
  129. package/dist/extensions/fetch-tool.js +8 -2
  130. package/dist/extensions/schema.d.ts +2 -2
  131. package/dist/extensions/store.js +3 -0
  132. package/dist/localization/core-messages/ar-SA.js +1 -0
  133. package/dist/localization/core-messages/de-DE.js +1 -0
  134. package/dist/localization/core-messages/en-US.d.ts +1 -0
  135. package/dist/localization/core-messages/en-US.js +1 -0
  136. package/dist/localization/core-messages/es-ES.js +1 -0
  137. package/dist/localization/core-messages/fr-FR.js +1 -0
  138. package/dist/localization/core-messages/hi-IN.js +1 -0
  139. package/dist/localization/core-messages/ja-JP.js +1 -0
  140. package/dist/localization/core-messages/ko-KR.js +1 -0
  141. package/dist/localization/core-messages/pt-BR.js +1 -0
  142. package/dist/localization/core-messages/zh-CN.js +1 -0
  143. package/dist/localization/core-messages/zh-TW.js +1 -0
  144. package/dist/localization/core-messages.d.ts +1 -0
  145. package/dist/localization/default-messages.d.ts +4 -0
  146. package/dist/localization/default-messages.js +4 -0
  147. package/dist/mcp/embed-app.js +1 -1
  148. package/dist/notifications/routes.d.ts +1 -1
  149. package/dist/org/handlers.d.ts +6 -1
  150. package/dist/org/handlers.js +43 -0
  151. package/dist/org/index.d.ts +3 -3
  152. package/dist/org/index.js +2 -2
  153. package/dist/org/migrations.js +33 -0
  154. package/dist/org/plugin.js +10 -1
  155. package/dist/org/schema.d.ts +315 -0
  156. package/dist/org/schema.js +20 -1
  157. package/dist/org/types.d.ts +3 -0
  158. package/dist/org/workspace-app-access.d.ts +10 -0
  159. package/dist/org/workspace-app-access.js +179 -0
  160. package/dist/progress/routes.d.ts +1 -1
  161. package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
  162. package/dist/provider-api/actions/provider-api.d.ts +7 -7
  163. package/dist/provider-api/index.d.ts +10 -0
  164. package/dist/provider-api/index.js +45 -9
  165. package/dist/resources/handlers.d.ts +1 -1
  166. package/dist/secrets/routes.d.ts +9 -9
  167. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  168. package/dist/server/auth.js +24 -4
  169. package/dist/server/poll.js +13 -3
  170. package/dist/server/sentry.d.ts +1 -1
  171. package/dist/sharing/access.d.ts +2 -2
  172. package/dist/sharing/access.js +56 -3
  173. package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
  174. package/dist/sharing/actions/list-resource-shares.js +26 -1
  175. package/dist/sharing/actions/share-resource.d.ts +1 -1
  176. package/dist/sharing/actions/share-resource.js +23 -4
  177. package/dist/sharing/actions/unshare-resource.d.ts +1 -1
  178. package/dist/sharing/actions/unshare-resource.js +1 -1
  179. package/dist/sharing/registry.d.ts +12 -0
  180. package/dist/sharing/schema.d.ts +4 -4
  181. package/dist/sharing/schema.js +2 -2
  182. package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  183. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
  184. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  185. package/dist/templates/default/.agents/skills/sharing/SKILL.md +27 -2
  186. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  187. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
  188. package/dist/vite/client.d.ts +5 -0
  189. package/dist/vite/client.js +64 -2
  190. package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +9 -1
  191. package/dist/workspace-connections/actions/list-workspace-user-groups.js +9 -4
  192. package/dist/workspace-connections/groups.d.ts +2 -0
  193. package/dist/workspace-connections/groups.js +16 -5
  194. package/dist/workspace-files/actions.d.ts +1 -8
  195. package/dist/workspace-files/actions.js +5 -21
  196. package/dist/workspace-files/index.d.ts +1 -1
  197. package/dist/workspace-files/index.js +1 -1
  198. package/dist/workspace-files/store.d.ts +18 -0
  199. package/dist/workspace-files/store.js +24 -3
  200. package/package.json +3 -3
  201. package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  202. package/src/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
  203. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  204. package/src/templates/default/.agents/skills/sharing/SKILL.md +27 -2
  205. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  206. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
@@ -536,3 +536,318 @@ export declare const orgInvitations: import("drizzle-orm/sqlite-core").SQLiteTab
536
536
  };
537
537
  dialect: 'sqlite';
538
538
  }>;
539
+ /** Workspace app access is framework-owned so every mounted app can enforce it. */
540
+ export declare const workspaceApps: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
541
+ name: "workspace_apps";
542
+ schema: undefined;
543
+ columns: {
544
+ ownerEmail: import("drizzle-orm/sqlite-core").SQLiteColumn<{
545
+ name: "owner_email";
546
+ tableName: "workspace_apps";
547
+ dataType: "string";
548
+ columnType: "SQLiteText";
549
+ data: string;
550
+ driverParam: string;
551
+ notNull: true;
552
+ hasDefault: true;
553
+ isPrimaryKey: false;
554
+ isAutoincrement: false;
555
+ hasRuntimeDefault: false;
556
+ enumValues: [string, ...string[]];
557
+ baseColumn: never;
558
+ identity: undefined;
559
+ generated: undefined;
560
+ }, {}, {
561
+ length: number;
562
+ }>;
563
+ orgId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
564
+ name: "org_id";
565
+ tableName: "workspace_apps";
566
+ dataType: "string";
567
+ columnType: "SQLiteText";
568
+ data: string;
569
+ driverParam: string;
570
+ notNull: false;
571
+ hasDefault: false;
572
+ isPrimaryKey: false;
573
+ isAutoincrement: false;
574
+ hasRuntimeDefault: false;
575
+ enumValues: [string, ...string[]];
576
+ baseColumn: never;
577
+ identity: undefined;
578
+ generated: undefined;
579
+ }, {}, {
580
+ length: number;
581
+ }>;
582
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
583
+ name: "id";
584
+ tableName: "workspace_apps";
585
+ dataType: "string";
586
+ columnType: "SQLiteText";
587
+ data: string;
588
+ driverParam: string;
589
+ notNull: true;
590
+ hasDefault: false;
591
+ isPrimaryKey: true;
592
+ isAutoincrement: false;
593
+ hasRuntimeDefault: false;
594
+ enumValues: [string, ...string[]];
595
+ baseColumn: never;
596
+ identity: undefined;
597
+ generated: undefined;
598
+ }, {}, {
599
+ length: number;
600
+ }>;
601
+ visibility: import("drizzle-orm/sqlite-core").SQLiteColumn<{
602
+ name: "visibility";
603
+ tableName: "workspace_apps";
604
+ dataType: "string";
605
+ columnType: "SQLiteText";
606
+ data: "org" | "private" | "public";
607
+ driverParam: string;
608
+ notNull: true;
609
+ hasDefault: true;
610
+ isPrimaryKey: false;
611
+ isAutoincrement: false;
612
+ hasRuntimeDefault: false;
613
+ enumValues: ["private", "org", "public"];
614
+ baseColumn: never;
615
+ identity: undefined;
616
+ generated: undefined;
617
+ }, {}, {
618
+ length: number;
619
+ }>;
620
+ name: import("drizzle-orm/sqlite-core").SQLiteColumn<{
621
+ name: "name";
622
+ tableName: "workspace_apps";
623
+ dataType: "string";
624
+ columnType: "SQLiteText";
625
+ data: string;
626
+ driverParam: string;
627
+ notNull: true;
628
+ hasDefault: false;
629
+ isPrimaryKey: false;
630
+ isAutoincrement: false;
631
+ hasRuntimeDefault: false;
632
+ enumValues: [string, ...string[]];
633
+ baseColumn: never;
634
+ identity: undefined;
635
+ generated: undefined;
636
+ }, {}, {
637
+ length: number;
638
+ }>;
639
+ description: import("drizzle-orm/sqlite-core").SQLiteColumn<{
640
+ name: "description";
641
+ tableName: "workspace_apps";
642
+ dataType: "string";
643
+ columnType: "SQLiteText";
644
+ data: string;
645
+ driverParam: string;
646
+ notNull: false;
647
+ hasDefault: false;
648
+ isPrimaryKey: false;
649
+ isAutoincrement: false;
650
+ hasRuntimeDefault: false;
651
+ enumValues: [string, ...string[]];
652
+ baseColumn: never;
653
+ identity: undefined;
654
+ generated: undefined;
655
+ }, {}, {
656
+ length: number;
657
+ }>;
658
+ path: import("drizzle-orm/sqlite-core").SQLiteColumn<{
659
+ name: "path";
660
+ tableName: "workspace_apps";
661
+ dataType: "string";
662
+ columnType: "SQLiteText";
663
+ data: string;
664
+ driverParam: string;
665
+ notNull: true;
666
+ hasDefault: false;
667
+ isPrimaryKey: false;
668
+ isAutoincrement: false;
669
+ hasRuntimeDefault: false;
670
+ enumValues: [string, ...string[]];
671
+ baseColumn: never;
672
+ identity: undefined;
673
+ generated: undefined;
674
+ }, {}, {
675
+ length: number;
676
+ }>;
677
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
678
+ name: "created_at";
679
+ tableName: "workspace_apps";
680
+ dataType: "number";
681
+ columnType: "SQLiteInteger";
682
+ data: number;
683
+ driverParam: number;
684
+ notNull: true;
685
+ hasDefault: false;
686
+ isPrimaryKey: false;
687
+ isAutoincrement: false;
688
+ hasRuntimeDefault: false;
689
+ enumValues: undefined;
690
+ baseColumn: never;
691
+ identity: undefined;
692
+ generated: undefined;
693
+ }, {}, {}>;
694
+ updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
695
+ name: "updated_at";
696
+ tableName: "workspace_apps";
697
+ dataType: "number";
698
+ columnType: "SQLiteInteger";
699
+ data: number;
700
+ driverParam: number;
701
+ notNull: true;
702
+ hasDefault: false;
703
+ isPrimaryKey: false;
704
+ isAutoincrement: false;
705
+ hasRuntimeDefault: false;
706
+ enumValues: undefined;
707
+ baseColumn: never;
708
+ identity: undefined;
709
+ generated: undefined;
710
+ }, {}, {}>;
711
+ };
712
+ dialect: 'sqlite';
713
+ }>;
714
+ export declare const workspaceAppShares: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
715
+ name: string;
716
+ schema: undefined;
717
+ columns: {
718
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
719
+ name: "id";
720
+ tableName: string;
721
+ dataType: "string";
722
+ columnType: "SQLiteText";
723
+ data: string;
724
+ driverParam: string;
725
+ notNull: true;
726
+ hasDefault: false;
727
+ isPrimaryKey: true;
728
+ isAutoincrement: false;
729
+ hasRuntimeDefault: false;
730
+ enumValues: [string, ...string[]];
731
+ baseColumn: never;
732
+ identity: undefined;
733
+ generated: undefined;
734
+ }, {}, {
735
+ length: number;
736
+ }>;
737
+ resourceId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
738
+ name: "resource_id";
739
+ tableName: string;
740
+ dataType: "string";
741
+ columnType: "SQLiteText";
742
+ data: string;
743
+ driverParam: string;
744
+ notNull: true;
745
+ hasDefault: false;
746
+ isPrimaryKey: false;
747
+ isAutoincrement: false;
748
+ hasRuntimeDefault: false;
749
+ enumValues: [string, ...string[]];
750
+ baseColumn: never;
751
+ identity: undefined;
752
+ generated: undefined;
753
+ }, {}, {
754
+ length: number;
755
+ }>;
756
+ principalType: import("drizzle-orm/sqlite-core").SQLiteColumn<{
757
+ name: "principal_type";
758
+ tableName: string;
759
+ dataType: "string";
760
+ columnType: "SQLiteText";
761
+ data: "group" | "org" | "user";
762
+ driverParam: string;
763
+ notNull: true;
764
+ hasDefault: false;
765
+ isPrimaryKey: false;
766
+ isAutoincrement: false;
767
+ hasRuntimeDefault: false;
768
+ enumValues: ["user", "group", "org"];
769
+ baseColumn: never;
770
+ identity: undefined;
771
+ generated: undefined;
772
+ }, {}, {
773
+ length: number;
774
+ }>;
775
+ principalId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
776
+ name: "principal_id";
777
+ tableName: string;
778
+ dataType: "string";
779
+ columnType: "SQLiteText";
780
+ data: string;
781
+ driverParam: string;
782
+ notNull: true;
783
+ hasDefault: false;
784
+ isPrimaryKey: false;
785
+ isAutoincrement: false;
786
+ hasRuntimeDefault: false;
787
+ enumValues: [string, ...string[]];
788
+ baseColumn: never;
789
+ identity: undefined;
790
+ generated: undefined;
791
+ }, {}, {
792
+ length: number;
793
+ }>;
794
+ role: import("drizzle-orm/sqlite-core").SQLiteColumn<{
795
+ name: "role";
796
+ tableName: string;
797
+ dataType: "string";
798
+ columnType: "SQLiteText";
799
+ data: "admin" | "commenter" | "editor" | "viewer";
800
+ driverParam: string;
801
+ notNull: true;
802
+ hasDefault: true;
803
+ isPrimaryKey: false;
804
+ isAutoincrement: false;
805
+ hasRuntimeDefault: false;
806
+ enumValues: ["viewer", "commenter", "editor", "admin"];
807
+ baseColumn: never;
808
+ identity: undefined;
809
+ generated: undefined;
810
+ }, {}, {
811
+ length: number;
812
+ }>;
813
+ createdBy: import("drizzle-orm/sqlite-core").SQLiteColumn<{
814
+ name: "created_by";
815
+ tableName: string;
816
+ dataType: "string";
817
+ columnType: "SQLiteText";
818
+ data: string;
819
+ driverParam: string;
820
+ notNull: true;
821
+ hasDefault: true;
822
+ isPrimaryKey: false;
823
+ isAutoincrement: false;
824
+ hasRuntimeDefault: false;
825
+ enumValues: [string, ...string[]];
826
+ baseColumn: never;
827
+ identity: undefined;
828
+ generated: undefined;
829
+ }, {}, {
830
+ length: number;
831
+ }>;
832
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
833
+ name: "created_at";
834
+ tableName: string;
835
+ dataType: "string";
836
+ columnType: "SQLiteText";
837
+ data: string;
838
+ driverParam: string;
839
+ notNull: true;
840
+ hasDefault: true;
841
+ isPrimaryKey: false;
842
+ isAutoincrement: false;
843
+ hasRuntimeDefault: false;
844
+ enumValues: [string, ...string[]];
845
+ baseColumn: never;
846
+ identity: undefined;
847
+ generated: undefined;
848
+ }, {}, {
849
+ length: number;
850
+ }>;
851
+ };
852
+ dialect: 'sqlite';
853
+ }>;
@@ -1,4 +1,4 @@
1
- import { table, text, integer } from "../db/schema.js";
1
+ import { table, text, integer, ownableColumns, createSharesTable, } from "../db/schema.js";
2
2
  export const organizations = table("organizations", {
3
3
  id: text("id").primaryKey(),
4
4
  name: text("name").notNull(),
@@ -39,3 +39,22 @@ export const orgInvitations = table("org_invitations", {
39
39
  status: text("status").notNull(),
40
40
  role: text("role"),
41
41
  });
42
+ /** Workspace app access is framework-owned so every mounted app can enforce it. */
43
+ export const workspaceApps = table("workspace_apps", {
44
+ id: text("id").primaryKey(),
45
+ ...ownableColumns(),
46
+ // Workspace apps are visible to their organization by default. The generic
47
+ // ownable primitive remains private-by-default for user-created resources;
48
+ // app creation is a deliberate workspace-level exception.
49
+ visibility: text("visibility", {
50
+ enum: ["private", "org", "public"],
51
+ })
52
+ .notNull()
53
+ .default("org"),
54
+ name: text("name").notNull(),
55
+ description: text("description"),
56
+ path: text("path").notNull(),
57
+ createdAt: integer("created_at").notNull(),
58
+ updatedAt: integer("updated_at").notNull(),
59
+ });
60
+ export const workspaceAppShares = createSharesTable("workspace_app_shares");
@@ -3,6 +3,7 @@
3
3
  */
4
4
  export type OrgRole = "owner" | "admin" | "member";
5
5
  export type RequiredAuthProvider = "google" | null;
6
+ export type WorkspaceAppDefaultVisibility = "private" | "org";
6
7
  export interface OrgContext {
7
8
  email: string;
8
9
  orgId: string | null;
@@ -43,6 +44,8 @@ export interface OrgInfo {
43
44
  workspaceUrl: string | null;
44
45
  /** Sign-in provider required for members of the active org. */
45
46
  requiredAuthProvider: RequiredAuthProvider;
47
+ /** Default visibility applied when a new workspace app is first registered. */
48
+ workspaceAppDefaultVisibility?: WorkspaceAppDefaultVisibility;
46
49
  /**
47
50
  * Whether the active org has an A2A secret. The value itself is never part
48
51
  * of this payload — owners/admins fetch it on demand from
@@ -0,0 +1,10 @@
1
+ export interface WorkspaceAppAccessContext {
2
+ email: string;
3
+ orgId?: string | null;
4
+ }
5
+ /**
6
+ * Enforce the workspace-app ACL before a hosted app's authenticated API
7
+ * surface is reached. The app shell remains cacheable and anonymous; this
8
+ * check protects the session-backed APIs/actions that make the app useful.
9
+ */
10
+ export declare function isWorkspaceAppAccessAllowed(appId: string, context: WorkspaceAppAccessContext): Promise<boolean>;
@@ -0,0 +1,179 @@
1
+ import { signA2AToken } from "../a2a/client.js";
2
+ import { getAppConfig } from "../app-config/index.js";
3
+ import { getDbExec } from "../db/client.js";
4
+ import { workspaceUserGroupsIncludeUser } from "../workspace-connections/groups.js";
5
+ import { getOrgA2ASecret, getOrgDomain } from "./context.js";
6
+ const WORKSPACE_APPS_ACTION_PATH = "/_agent-native/actions/list-workspace-apps";
7
+ const WORKSPACE_APP_ACCESS_TIMEOUT_MS = 2_500;
8
+ function normalizedEmail(email) {
9
+ return email.trim().toLowerCase();
10
+ }
11
+ function configuredWorkspaceDirectory() {
12
+ const workspace = getAppConfig().workspace;
13
+ return (workspace.orgDirectoryUrl?.trim() || workspace.gatewayUrl?.trim() || null);
14
+ }
15
+ function workspaceAppsActionUrl(base) {
16
+ try {
17
+ const baseUrl = new URL(base);
18
+ if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") {
19
+ return null;
20
+ }
21
+ const basePath = baseUrl.pathname.replace(/\/+$/, "");
22
+ baseUrl.pathname = `${basePath}${WORKSPACE_APPS_ACTION_PATH}`;
23
+ baseUrl.search = "";
24
+ baseUrl.searchParams.set("includeAgentCards", "false");
25
+ baseUrl.searchParams.set("audience", "all");
26
+ baseUrl.hash = "";
27
+ return baseUrl;
28
+ }
29
+ catch {
30
+ // coercion-ok: malformed configured URL is a typed unavailable registry.
31
+ return null;
32
+ }
33
+ }
34
+ function workspaceAppsFromResponse(value) {
35
+ if (Array.isArray(value))
36
+ return value;
37
+ if (value &&
38
+ typeof value === "object" &&
39
+ Array.isArray(value.apps)) {
40
+ return value.apps;
41
+ }
42
+ return [];
43
+ }
44
+ /**
45
+ * Hosted app databases are not the authority for workspace-app rows. Ask the
46
+ * Dispatch registry action, which resolves the ACL against its shared store,
47
+ * so an app-scoped database cannot accidentally turn a missing local row into
48
+ * access. A configured registry is fail-closed on every network/auth error.
49
+ */
50
+ async function hostedWorkspaceAppAccess(appId, context, email) {
51
+ const configuredDirectory = configuredWorkspaceDirectory();
52
+ if (!configuredDirectory)
53
+ return null;
54
+ const url = workspaceAppsActionUrl(configuredDirectory);
55
+ if (!url)
56
+ return false;
57
+ const orgId = context.orgId?.trim() || null;
58
+ const [orgDomain, orgSecret] = orgId
59
+ ? await Promise.all([getOrgDomain(orgId), getOrgA2ASecret(orgId)])
60
+ : [null, null];
61
+ let token;
62
+ try {
63
+ token = await signA2AToken(email, orgDomain?.trim() || undefined, orgSecret?.trim() || undefined, {
64
+ expiresIn: "1m",
65
+ preferGlobalSecret: true,
66
+ ...(orgId ? { extraClaims: { org_id: orgId } } : {}),
67
+ });
68
+ }
69
+ catch (error) {
70
+ console.error("[workspace-app-access] registry token unavailable", error);
71
+ return false;
72
+ }
73
+ const controller = new AbortController();
74
+ const timeout = setTimeout(() => controller.abort(), WORKSPACE_APP_ACCESS_TIMEOUT_MS);
75
+ try {
76
+ const response = await fetch(url, {
77
+ headers: {
78
+ accept: "application/json",
79
+ Authorization: `Bearer ${token}`,
80
+ },
81
+ signal: controller.signal,
82
+ });
83
+ if (!response.ok)
84
+ return false;
85
+ const apps = workspaceAppsFromResponse(
86
+ // coercion-ok: malformed registry JSON is an authorization failure.
87
+ await response.json().catch(() => null));
88
+ return apps.some((app) => app.id === appId);
89
+ }
90
+ catch (error) {
91
+ console.error("[workspace-app-access] registry access check failed", error);
92
+ return false;
93
+ }
94
+ finally {
95
+ clearTimeout(timeout);
96
+ }
97
+ }
98
+ /**
99
+ * Enforce the workspace-app ACL before a hosted app's authenticated API
100
+ * surface is reached. The app shell remains cacheable and anonymous; this
101
+ * check protects the session-backed APIs/actions that make the app useful.
102
+ */
103
+ export async function isWorkspaceAppAccessAllowed(appId, context) {
104
+ const normalizedAppId = appId.trim();
105
+ const email = normalizedEmail(context.email);
106
+ if (!normalizedAppId || normalizedAppId === "dispatch" || !email) {
107
+ return true;
108
+ }
109
+ const hostedAccess = await hostedWorkspaceAppAccess(normalizedAppId, context, email);
110
+ if (hostedAccess !== null)
111
+ return hostedAccess;
112
+ // Standalone/local deployments have no Dispatch registry URL. Keep the
113
+ // direct lookup for that mode, but never let missing or malformed ACL state
114
+ // grant access.
115
+ try {
116
+ const db = getDbExec();
117
+ const appResult = await db.execute({
118
+ sql: `SELECT owner_email, org_id, visibility
119
+ FROM workspace_apps WHERE id = ? LIMIT 1`,
120
+ args: [normalizedAppId],
121
+ });
122
+ const app = appResult.rows[0];
123
+ if (!app)
124
+ return false;
125
+ const ownerEmail = normalizedEmail(typeof app.owner_email === "string" ? app.owner_email : "");
126
+ const resourceOrgId = (typeof app.org_id === "string" ? app.org_id : "").trim() || null;
127
+ const orgId = context.orgId?.trim() || null;
128
+ const sameOrg = !!resourceOrgId && resourceOrgId === orgId;
129
+ if (ownerEmail === email && (!resourceOrgId || sameOrg))
130
+ return true;
131
+ if (!sameOrg || !orgId)
132
+ return false;
133
+ const memberResult = await db.execute({
134
+ sql: `SELECT role FROM org_members
135
+ WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
136
+ args: [orgId, email],
137
+ });
138
+ if (memberResult.rows.length === 0)
139
+ return false;
140
+ const memberRole = String(memberResult.rows[0]?.role ?? "");
141
+ if (memberRole === "owner" || memberRole === "admin")
142
+ return true;
143
+ if (app.visibility === "org")
144
+ return true;
145
+ if (app.visibility !== "private")
146
+ return false;
147
+ const userShare = await db.execute({
148
+ sql: `SELECT 1 FROM workspace_app_shares
149
+ WHERE resource_id = ? AND principal_type = 'user'
150
+ AND LOWER(principal_id) = ? LIMIT 1`,
151
+ args: [normalizedAppId, email],
152
+ });
153
+ if (userShare.rows.length > 0)
154
+ return true;
155
+ const orgShare = await db.execute({
156
+ sql: `SELECT 1 FROM workspace_app_shares
157
+ WHERE resource_id = ? AND principal_type = 'org'
158
+ AND principal_id = ? LIMIT 1`,
159
+ args: [normalizedAppId, orgId],
160
+ });
161
+ if (orgShare.rows.length > 0)
162
+ return true;
163
+ const groupShares = await db.execute({
164
+ sql: `SELECT principal_id FROM workspace_app_shares
165
+ WHERE resource_id = ? AND principal_type = 'group'`,
166
+ args: [normalizedAppId],
167
+ });
168
+ const groupIds = groupShares.rows
169
+ .map((row) => typeof row.principal_id === "string" ? row.principal_id : "")
170
+ .filter(Boolean);
171
+ return workspaceUserGroupsIncludeUser(resourceOrgId, groupIds, email);
172
+ }
173
+ catch (error) {
174
+ // Missing migrations, missing rows, and every other DB failure deny
175
+ // protected app access until the authoritative ACL is available.
176
+ console.error("[workspace-app-access] access check failed", error);
177
+ return false;
178
+ }
179
+ }
@@ -15,6 +15,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- ok: boolean;
19
18
  error?: undefined;
19
+ ok: boolean;
20
20
  }>>;
@@ -77,8 +77,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
77
77
  }, z.core.$strip>>, {
78
78
  message?: undefined;
79
79
  id?: undefined;
80
+ provider?: undefined;
80
81
  deleted?: undefined;
81
- found?: undefined;
82
82
  providers: {
83
83
  id: string;
84
84
  label: string;
@@ -89,7 +89,7 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
89
89
  updatedAt: number;
90
90
  }[];
91
91
  count: number;
92
- provider?: undefined;
92
+ found?: undefined;
93
93
  registered?: undefined;
94
94
  label?: undefined;
95
95
  } | {
@@ -105,9 +105,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
105
105
  } | {
106
106
  message?: undefined;
107
107
  count?: undefined;
108
+ provider?: undefined;
108
109
  deleted?: undefined;
109
110
  providers?: undefined;
110
- provider?: undefined;
111
111
  found: boolean;
112
112
  id: string;
113
113
  registered?: undefined;
@@ -115,19 +115,19 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
115
115
  } | {
116
116
  message?: undefined;
117
117
  count?: undefined;
118
- found?: undefined;
119
- providers?: undefined;
120
118
  provider?: undefined;
119
+ providers?: undefined;
120
+ found?: undefined;
121
121
  deleted: boolean;
122
122
  id: string;
123
123
  registered?: undefined;
124
124
  label?: undefined;
125
125
  } | {
126
126
  count?: undefined;
127
+ provider?: undefined;
127
128
  deleted?: undefined;
128
- found?: undefined;
129
129
  providers?: undefined;
130
- provider?: undefined;
130
+ found?: undefined;
131
131
  registered: boolean;
132
132
  id: string;
133
133
  label: string;
@@ -313,8 +313,6 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
313
313
  }, {
314
314
  id?: undefined;
315
315
  deleted?: undefined;
316
- provider?: undefined;
317
- found?: undefined;
318
316
  providers: {
319
317
  id: string;
320
318
  label: string;
@@ -325,6 +323,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
325
323
  updatedAt: number;
326
324
  }[];
327
325
  count: number;
326
+ provider?: undefined;
327
+ found?: undefined;
328
328
  registered?: undefined;
329
329
  label?: undefined;
330
330
  message?: undefined;
@@ -340,19 +340,19 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
340
340
  message?: undefined;
341
341
  } | {
342
342
  deleted?: undefined;
343
- provider?: undefined;
344
343
  providers?: undefined;
345
344
  count?: undefined;
345
+ provider?: undefined;
346
346
  found: boolean;
347
347
  id: string;
348
348
  registered?: undefined;
349
349
  label?: undefined;
350
350
  message?: undefined;
351
351
  } | {
352
- provider?: undefined;
353
- found?: undefined;
354
352
  providers?: undefined;
355
353
  count?: undefined;
354
+ provider?: undefined;
355
+ found?: undefined;
356
356
  deleted: boolean;
357
357
  id: string;
358
358
  registered?: undefined;
@@ -360,10 +360,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
360
360
  message?: undefined;
361
361
  } | {
362
362
  deleted?: undefined;
363
- provider?: undefined;
364
- found?: undefined;
365
363
  providers?: undefined;
366
364
  count?: undefined;
365
+ provider?: undefined;
366
+ found?: undefined;
367
367
  registered: boolean;
368
368
  id: string;
369
369
  label: string;
@@ -286,6 +286,16 @@ export interface ProviderApiConfig {
286
286
  accessErrorGuidance?: string;
287
287
  corpusRecipes?: readonly ProviderApiCorpusRecipe[];
288
288
  templateUses?: readonly WorkspaceConnectionTemplateUse[];
289
+ /**
290
+ * Some provider APIs (Slack's Web API is the documented case) answer every
291
+ * request with HTTP 200 and encode the real outcome as a boolean field in
292
+ * the JSON body instead. When set, a response with this field explicitly
293
+ * `false` is treated as a failed request — `response.ok` is flipped to
294
+ * `false` — so a caller (or the agent) that only checks the transport-level
295
+ * `ok`, the same signal every other provider uses for success, can't
296
+ * mistake a rejected send for a delivered one.
297
+ */
298
+ bodyOkField?: string;
289
299
  }
290
300
  export interface ProviderApiPlaceholder {
291
301
  name: string;