@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.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +18 -2
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/calendar/server/handlers/google-auth.ts +1 -8
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +88 -35
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +36 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -3
- package/corpus/templates/clips/app/lib/camera-composite.ts +15 -1
- package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-crashes-when-a-camera-bubble-starts-at-a-tin.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +30 -40
- package/corpus/templates/clips/desktop/src/components/MicOffConfirmation.tsx +47 -0
- package/corpus/templates/clips/desktop/src/styles.css +110 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +114 -7
- package/corpus/templates/clips/shared/recording-capture.ts +18 -13
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/content/actions/create-content-database.ts +1 -1
- package/corpus/templates/content/actions/create-document.ts +1 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +3 -5
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +0 -3
- package/corpus/templates/content/app/components/editor/NotionConflictBanner.tsx +0 -4
- package/corpus/templates/content/app/components/editor/NotionSyncBar.tsx +4 -1
- package/corpus/templates/content/app/hooks/use-notion.ts +17 -15
- package/corpus/templates/crm/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +6 -1
- package/corpus/templates/dispatch/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/factory/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/macros/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +18 -3
- package/corpus/templates/mail/server/handlers/google-auth.ts +1 -8
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/.agents/skills/create-deck/SKILL.md +4 -0
- package/corpus/templates/slides/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +27 -2
- package/corpus/templates/slides/actions/_await-fit-check.ts +30 -5
- package/corpus/templates/slides/actions/add-slide.ts +6 -2
- package/corpus/templates/slides/actions/create-deck.ts +2 -1
- package/corpus/templates/slides/app/components/editor/GoogleDriveConnectionCta.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/GoogleSlidesReferenceImport.tsx +3 -3
- package/corpus/templates/slides/app/components/editor/PromptDialog.tsx +3 -1
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +1 -1
- package/corpus/templates/slides/app/lib/create-deck-generation.ts +1 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +35 -2
- package/corpus/templates/slides/app/routes/p.$id.tsx +3 -1
- package/corpus/templates/slides/changelog/2026-08-18-generated-slides-preserve-speaker-notes.md +6 -0
- package/corpus/templates/slides/server/handlers/assets.ts +23 -12
- package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +15 -6
- package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +15 -6
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +34 -19
- package/corpus/templates/slides/server/handlers/request-auth-context.ts +1 -0
- package/corpus/templates/slides/server/handlers/share.ts +1 -1
- package/corpus/templates/slides/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/server/routes/api/deck-agent-context.json.get.ts +1 -1
- package/corpus/templates/slides/server/routes/api/exports/[filename].get.ts +9 -3
- package/corpus/templates/slides/server/routes/api/exports/google-slides.post.ts +12 -5
- package/corpus/templates/slides/server/routes/api/exports/html.post.ts +9 -7
- package/corpus/templates/slides/server/routes/api/exports/pptx.post.ts +9 -7
- package/corpus/templates/slides/shared/api.ts +7 -1
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/agent/engine/translate-anthropic.js +27 -2
- package/dist/agent/production-agent.d.ts +2 -2
- package/dist/agent/production-agent.js +16 -8
- package/dist/agent/thread-data-builder.d.ts +1 -0
- package/dist/agent/thread-data-builder.js +6 -4
- package/dist/agent/tool-approval-store.d.ts +10 -1
- package/dist/agent/tool-approval-store.js +19 -2
- package/dist/agent/types.d.ts +9 -0
- package/dist/app-config/schema.d.ts +1 -0
- package/dist/app-config/workspace.d.ts +1 -0
- package/dist/app-config/workspace.js +8 -0
- package/dist/chat-threads/schema.d.ts +2 -2
- package/dist/client/AssistantChat.js +14 -6
- package/dist/client/EnvironmentBadge.d.ts +15 -0
- package/dist/client/EnvironmentBadge.js +79 -0
- package/dist/client/MultiTabAssistantChat.js +73 -17
- package/dist/client/agent-chat-adapter.js +11 -1
- package/dist/client/api-path.js +14 -1
- package/dist/client/app-providers.js +2 -1
- package/dist/client/chat/tool-call-display.d.ts +12 -2
- package/dist/client/chat/tool-call-display.js +17 -7
- package/dist/client/chat/widgets/WorkspaceFileWidget.js +1 -1
- package/dist/client/chat/widgets/builtin-tool-renderers.d.ts +6 -0
- package/dist/client/chat/widgets/builtin-tool-renderers.js +19 -0
- package/dist/client/onboarding/FirstRunOnboarding.js +46 -32
- package/dist/client/onboarding/use-onboarding.d.ts +8 -1
- package/dist/client/onboarding/use-onboarding.js +22 -7
- package/dist/client/org/TeamPage.js +15 -2
- package/dist/client/org/hooks.d.ts +2 -0
- package/dist/client/org/hooks.js +12 -0
- package/dist/client/org/index.d.ts +2 -2
- package/dist/client/org/index.js +1 -1
- package/dist/client/session-replay.js +58 -15
- package/dist/client/settings/SettingsTabsPage.js +19 -6
- package/dist/client/sharing/ShareButton.js +43 -18
- package/dist/client/sharing/useShareButtonController.d.ts +12 -2
- package/dist/client/sharing/useShareButtonController.js +38 -8
- package/dist/client/sse-event-processor.d.ts +7 -0
- package/dist/client/sse-event-processor.js +4 -1
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/use-action.js +26 -0
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.js +53 -0
- package/dist/dashboard-storage/schema.d.ts +2 -2
- package/dist/data-programs/schema.d.ts +2 -2
- package/dist/extensions/fetch-tool.js +8 -2
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/extensions/store.js +3 -0
- package/dist/localization/core-messages/ar-SA.js +1 -0
- package/dist/localization/core-messages/de-DE.js +1 -0
- package/dist/localization/core-messages/en-US.d.ts +1 -0
- package/dist/localization/core-messages/en-US.js +1 -0
- package/dist/localization/core-messages/es-ES.js +1 -0
- package/dist/localization/core-messages/fr-FR.js +1 -0
- package/dist/localization/core-messages/hi-IN.js +1 -0
- package/dist/localization/core-messages/ja-JP.js +1 -0
- package/dist/localization/core-messages/ko-KR.js +1 -0
- package/dist/localization/core-messages/pt-BR.js +1 -0
- package/dist/localization/core-messages/zh-CN.js +1 -0
- package/dist/localization/core-messages/zh-TW.js +1 -0
- package/dist/localization/core-messages.d.ts +1 -0
- package/dist/localization/default-messages.d.ts +4 -0
- package/dist/localization/default-messages.js +4 -0
- package/dist/mcp/embed-app.js +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/handlers.d.ts +6 -1
- package/dist/org/handlers.js +43 -0
- package/dist/org/index.d.ts +3 -3
- package/dist/org/index.js +2 -2
- package/dist/org/migrations.js +33 -0
- package/dist/org/plugin.js +10 -1
- package/dist/org/schema.d.ts +315 -0
- package/dist/org/schema.js +20 -1
- package/dist/org/types.d.ts +3 -0
- package/dist/org/workspace-app-access.d.ts +10 -0
- package/dist/org/workspace-app-access.js +179 -0
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/index.d.ts +10 -0
- package/dist/provider-api/index.js +45 -9
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +24 -4
- package/dist/server/poll.js +13 -3
- package/dist/server/sentry.d.ts +1 -1
- package/dist/sharing/access.d.ts +2 -2
- package/dist/sharing/access.js +56 -3
- package/dist/sharing/actions/list-resource-shares.d.ts +2 -0
- package/dist/sharing/actions/list-resource-shares.js +26 -1
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/actions/share-resource.js +23 -4
- package/dist/sharing/actions/unshare-resource.d.ts +1 -1
- package/dist/sharing/actions/unshare-resource.js +1 -1
- package/dist/sharing/registry.d.ts +12 -0
- package/dist/sharing/schema.d.ts +4 -4
- package/dist/sharing/schema.js +2 -2
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
- package/dist/vite/client.d.ts +5 -0
- package/dist/vite/client.js +64 -2
- package/dist/workspace-connections/actions/list-workspace-user-groups.d.ts +9 -1
- package/dist/workspace-connections/actions/list-workspace-user-groups.js +9 -4
- package/dist/workspace-connections/groups.d.ts +2 -0
- package/dist/workspace-connections/groups.js +16 -5
- package/dist/workspace-files/actions.d.ts +1 -8
- package/dist/workspace-files/actions.js +5 -21
- package/dist/workspace-files/index.d.ts +1 -1
- package/dist/workspace-files/index.js +1 -1
- package/dist/workspace-files/store.d.ts +18 -0
- package/dist/workspace-files/store.js +24 -3
- package/package.json +3 -3
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/default/.agents/skills/sharing/SKILL.md +27 -2
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +27 -2
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -11,7 +11,10 @@ import { openCommandMenu } from "@agent-native/core/client/navigation";
|
|
|
11
11
|
import { InvitationBanner, OrgSwitcher } from "@agent-native/core/client/org";
|
|
12
12
|
import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
13
13
|
import { SidebarFooterActions } from "@agent-native/toolkit/app-shell";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
isInboxScopedAppLabel,
|
|
16
|
+
normalizeMailLabel,
|
|
17
|
+
} from "@shared/gmail-labels";
|
|
15
18
|
import type { Label } from "@shared/types";
|
|
16
19
|
import {
|
|
17
20
|
IconMenu2,
|
|
@@ -171,6 +174,18 @@ function labelDepth(name: string): number {
|
|
|
171
174
|
return Math.max(0, name.split("/").length - 1);
|
|
172
175
|
}
|
|
173
176
|
|
|
177
|
+
// Gmail's inbox-only categories (important, social, promotions, ...) only
|
|
178
|
+
// ever exist inside the inbox, so their tab stays scoped there. Regular user
|
|
179
|
+
// labels are filed/archived independently of the inbox — routing them
|
|
180
|
+
// through /inbox forces `in:inbox` server-side and hides every message the
|
|
181
|
+
// user has archived out of the inbox while keeping the label, which reads as
|
|
182
|
+
// "label is empty" even though it has mail. Route those through /all so the
|
|
183
|
+
// label search is unscoped.
|
|
184
|
+
export function labelTabHref(labelId: string): string {
|
|
185
|
+
const view = isInboxScopedAppLabel(labelId) ? "inbox" : "all";
|
|
186
|
+
return `/${view}?label=${encodeURIComponent(labelId)}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
174
189
|
interface AppLayoutProps {
|
|
175
190
|
children: React.ReactNode;
|
|
176
191
|
}
|
|
@@ -590,7 +605,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
590
605
|
pinnedId: id,
|
|
591
606
|
label: aliasedName,
|
|
592
607
|
fullLabel: lbl.name,
|
|
593
|
-
href:
|
|
608
|
+
href: labelTabHref(lbl.id),
|
|
594
609
|
isActive: activeLabel === lbl.id,
|
|
595
610
|
color: lbl.color,
|
|
596
611
|
type: "label",
|
|
@@ -630,7 +645,7 @@ function AppLayoutInner({ children }: AppLayoutProps) {
|
|
|
630
645
|
id: active.id,
|
|
631
646
|
label: aliasedName,
|
|
632
647
|
fullLabel: active.name,
|
|
633
|
-
href:
|
|
648
|
+
href: labelTabHref(active.id),
|
|
634
649
|
isActive: true,
|
|
635
650
|
color: active.color,
|
|
636
651
|
type: "label",
|
|
@@ -58,23 +58,16 @@ function googleOAuthErrorPayload(
|
|
|
58
58
|
message: string;
|
|
59
59
|
code?: string;
|
|
60
60
|
accountId?: string;
|
|
61
|
-
existingOwner?: string;
|
|
62
|
-
attemptedOwner?: string;
|
|
63
61
|
} {
|
|
64
62
|
if (
|
|
65
63
|
error instanceof OAuthAccountOwnedByOtherUserError ||
|
|
66
64
|
error?.name === "OAuthAccountOwnedByOtherUserError"
|
|
67
65
|
) {
|
|
68
66
|
const account = error.accountId || "This Google account";
|
|
69
|
-
const existingOwner = error.existingOwner || undefined;
|
|
70
|
-
const attemptedOwner = error.attemptedOwner || undefined;
|
|
71
|
-
const message = `${account} is connected to another login. Sign out, then sign in with ${account}.`;
|
|
72
67
|
return {
|
|
73
|
-
message,
|
|
68
|
+
message: `${account} is already connected to another login. Sign out, then sign in with the login that originally connected it.`,
|
|
74
69
|
code: "account_owner_mismatch",
|
|
75
70
|
accountId: error.accountId,
|
|
76
|
-
existingOwner,
|
|
77
|
-
attemptedOwner,
|
|
78
71
|
};
|
|
79
72
|
}
|
|
80
73
|
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -25,6 +25,10 @@ Context, reference deck, or source material that the app already provides.
|
|
|
25
25
|
5. Navigate to the new deck.
|
|
26
26
|
6. Call `add-slide` once per slide in slide order, waiting for each result.
|
|
27
27
|
|
|
28
|
+
When speaker notes are requested, put presenter-only text in each slide's
|
|
29
|
+
`notes` field on `create-deck` or `add-slide`; keep it out of the slide HTML.
|
|
30
|
+
Preserve existing notes when editing or importing a source deck.
|
|
31
|
+
|
|
28
32
|
When the UI has already created the empty deck, keep its id and rename it before
|
|
29
33
|
adding the first slide. Call `patch-deck` with a `patch-deck-fields` operation
|
|
30
34
|
whose `fields.title` is the generated title. Do not leave the pre-created deck's
|
|
@@ -50,7 +50,7 @@ The agent modifies data in SQL, but the UI runs in the browser. SSE bridges same
|
|
|
50
50
|
|
|
51
51
|
For list/sidebar queries, use the same pattern — pass the counter into the queryKey of every list query you want to keep fresh.
|
|
52
52
|
|
|
53
|
-
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It
|
|
53
|
+
4. **Fallback** polling calls `/_agent-native/poll?since=N`. It polls every 2 seconds only while an agent run is in flight; otherwise it idles at 60 seconds whether or not SSE is connected (`SSE_FALLBACK_INTERVAL_MS` and `IDLE_POLL_INTERVAL_MS`, both 60 s). A hidden tab polls no faster than every 10 seconds (`HIDDEN_POLL_INTERVAL_MS`). Polling is the universal serverless fallback: new framework writes are read from the durable `sync_events` log, while the older DB timestamp scan remains as a slower safety net for direct SQL writes and older processes.
|
|
54
54
|
|
|
55
55
|
5. When the agent writes to the database, the version increments, SSE/polling detects it, and React Query refetches the affected queries.
|
|
56
56
|
|
|
@@ -18,6 +18,11 @@ Any resource a user **creates** (dashboards, documents, forms, decks, compositio
|
|
|
18
18
|
|
|
19
19
|
This is the framework-level primitive. Every ownable resource gets it for free — same API, same UI, same skill.
|
|
20
20
|
|
|
21
|
+
Workspace apps are the intentional organization-scoped exception: their default
|
|
22
|
+
visibility is `org`, configurable by an organization owner/admin. The creator is
|
|
23
|
+
stored as the app owner, and the creator or an organization owner/admin can
|
|
24
|
+
change the app's visibility or manage its share grants.
|
|
25
|
+
|
|
21
26
|
## Concepts
|
|
22
27
|
|
|
23
28
|
### Three visibility levels
|
|
@@ -26,7 +31,8 @@ This is the framework-level primitive. Every ownable resource gets it for free
|
|
|
26
31
|
- **`org`** — owner + explicit grants + anyone in the same org (read-only).
|
|
27
32
|
- **`public`** — owner + explicit grants + **anyone with the link** (read-only). Public docs do NOT appear in other users' list/sidebar/search results — `accessFilter` omits them by default. They're reachable by id (`resolveAccess` admits them) so direct links and SSR routes like `/p/:id` keep working. If a list endpoint legitimately needs cross-user public discovery (a template gallery, etc.), pass `accessFilter(table, shares, ctx, minRole, { includePublic: true })`.
|
|
28
33
|
|
|
29
|
-
Visibility is coarse. Explicit share grants are fine-grained (per user
|
|
34
|
+
Visibility is coarse. Explicit share grants are fine-grained (per user, reusable
|
|
35
|
+
organization group, or per org).
|
|
30
36
|
|
|
31
37
|
### Roles on a share grant
|
|
32
38
|
|
|
@@ -101,6 +107,7 @@ registerShareableResource({
|
|
|
101
107
|
// ...
|
|
102
108
|
allowPublic: false, // hides "Public" in the share dialog and rejects it server-side
|
|
103
109
|
requireOrgMemberForUserShares: true, // user shares must target an org member or pending invitee
|
|
110
|
+
supportsGroupShares: true, // enable reusable organization groups for this resource
|
|
104
111
|
});
|
|
105
112
|
```
|
|
106
113
|
|
|
@@ -111,6 +118,21 @@ Use both for resources that execute code or expose privileged data with the *vie
|
|
|
111
118
|
|
|
112
119
|
Defaults match historical behaviour: `allowPublic: true`, `requireOrgMemberForUserShares: false`. Resources that don't set the flags work as before.
|
|
113
120
|
|
|
121
|
+
### Reusable organization groups
|
|
122
|
+
|
|
123
|
+
The workspace organization model stores reusable groups in
|
|
124
|
+
`workspace_user_groups`. Organization owners/admins manage the groups and their
|
|
125
|
+
members through the existing group actions. Set `supportsGroupShares: true` on a
|
|
126
|
+
resource registration to enable `principalType: "group"` in the generic share
|
|
127
|
+
actions and the shared popover's autocomplete. Group ids are always checked
|
|
128
|
+
against the resource's organization, and membership is evaluated at access time
|
|
129
|
+
so group changes apply to existing shares.
|
|
130
|
+
|
|
131
|
+
Workspace apps opt into this flag and use the organization default visibility
|
|
132
|
+
setting. The app creator is the durable `owner_email`, while organization
|
|
133
|
+
owners/admins receive admin access through the registration's
|
|
134
|
+
`canManageAccess` callback.
|
|
135
|
+
|
|
114
136
|
## Filter list/read queries
|
|
115
137
|
|
|
116
138
|
```ts
|
|
@@ -197,6 +219,9 @@ All app share popovers should use the same compact surface contract:
|
|
|
197
219
|
- Add `ShareAgentsSection` only when the resource has a real agent-readable
|
|
198
220
|
link or prompt. Keep it collapsed by default and supply domain-specific
|
|
199
221
|
content through the shared section shell.
|
|
222
|
+
- When `supportsGroupShares` is enabled, keep the existing people input as the
|
|
223
|
+
only entry point and include organization groups in its autocomplete. Do not
|
|
224
|
+
add a separate group-management surface to each resource.
|
|
200
225
|
- App-specific tabs or controls may remain when they represent a real domain
|
|
201
226
|
action (for example, an embed-code editor), but they should retain the same
|
|
202
227
|
trigger, copy-row, access, and spacing language.
|
|
@@ -211,7 +236,7 @@ The framework auto-mounts these actions in every template — no per-template bo
|
|
|
211
236
|
|
|
212
237
|
| Action | Args | Purpose |
|
|
213
238
|
| -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
214
|
-
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
239
|
+
| `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user, group, or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
|
|
215
240
|
| `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
|
|
216
241
|
| `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
|
|
217
242
|
| `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
|
|
@@ -94,15 +94,40 @@ export function formatOverflowForTool(
|
|
|
94
94
|
deckId: string,
|
|
95
95
|
m: SlideFitMeasurement,
|
|
96
96
|
): string {
|
|
97
|
+
const hasHorizontal = (m.horizontalOverflow ?? 0) > 0;
|
|
98
|
+
const hasVertical = m.verticalOverflow > 0;
|
|
99
|
+
|
|
100
|
+
// A row of side-by-side cards/columns that's too wide is a *width formula*
|
|
101
|
+
// bug (fixed px flex-basis, a wrong container-width assumption, a missing
|
|
102
|
+
// `min-width: 0`), not a density bug. The old list was vertical-only —
|
|
103
|
+
// "tighten copy" / "fewer stacked cards" — which cannot shrink a fixed
|
|
104
|
+
// column width no matter how many times it's applied, so a horizontal
|
|
105
|
+
// overflow looped forever against fixes that could never touch the actual
|
|
106
|
+
// defect (see the Oliver Robertson Slack thread this regression test
|
|
107
|
+
// reproduces).
|
|
108
|
+
const fixes = [
|
|
109
|
+
...(hasHorizontal
|
|
110
|
+
? [
|
|
111
|
+
`Use percentage or flex-based column widths (e.g. \`flex: 1 1 0%\` with \`min-width: 0\`, or \`width: calc((100% - <gaps>) / <count>)\` measured against this slide's own content width) instead of a fixed pixel width per column.`,
|
|
112
|
+
`Reduce the number of side-by-side columns, or wrap to a second row, if the content cannot fit at the slide's actual content width.`,
|
|
113
|
+
]
|
|
114
|
+
: []),
|
|
115
|
+
...(hasVertical || !hasHorizontal
|
|
116
|
+
? [
|
|
117
|
+
`Tighten copy — shorter headings/bullets, drop low-value lines.`,
|
|
118
|
+
`Reduce vertical density — fewer stacked cards, smaller gaps, body font no smaller than 16px.`,
|
|
119
|
+
`Reduce slide padding (e.g. 40px top/bottom instead of 60-80px).`,
|
|
120
|
+
`Split across two slides only if the content cannot be compressed.`,
|
|
121
|
+
]
|
|
122
|
+
: []),
|
|
123
|
+
];
|
|
124
|
+
|
|
97
125
|
return [
|
|
98
126
|
``,
|
|
99
|
-
`⚠ Layout overflows the canvas${
|
|
127
|
+
`⚠ Layout overflows the canvas${hasVertical ? ` vertically by ${m.verticalOverflow}px` : ""}${hasHorizontal ? ` and horizontally by ${m.horizontalOverflow}px` : ""} — natural content is ${m.contentWidth ?? "unknown"}x${m.contentHeight}px inside a ${m.viewportWidth ?? "unknown"}x${m.viewportHeight}px content area.`,
|
|
100
128
|
``,
|
|
101
129
|
`Make one structural repair now with \`update-slide --deckId ${deckId} --slideId ${m.slideId}\`. Prefer small surgical patches (--find / --replace) over a full rewrite:`,
|
|
102
|
-
|
|
103
|
-
`2. Reduce vertical density — fewer stacked cards, smaller gaps, body font no smaller than 16px.`,
|
|
104
|
-
`3. Reduce slide padding (e.g. 40px top/bottom instead of 60-80px).`,
|
|
105
|
-
`4. Split across two slides only if the content cannot be compressed.`,
|
|
130
|
+
...fixes.map((fix, index) => `${index + 1}. ${fix}`),
|
|
106
131
|
``,
|
|
107
132
|
`Do **not** use zoom, \`transform: scale\`, clipping, \`overflow: scroll\`, or a smaller-than-16px body font. Preserve existing absolute text boxes and fix the normal-flow HTML. Verify the action result and then use \`view-screen\`; do not spin through another repair loop.`,
|
|
108
133
|
].join("\n");
|
|
@@ -97,6 +97,7 @@ export default defineAction({
|
|
|
97
97
|
"call it once per slide in slide order and wait for each result before adding the next slide. " +
|
|
98
98
|
"Avoid parallel add-slide calls for the same deck; sequential writes keep the editor and agent connection stable. " +
|
|
99
99
|
"If the deck has a designSystemId, first use `get-design-system` and apply its `agentContext` tokens/docs; do not use generic slide styling from the id alone. " +
|
|
100
|
+
"Pass presenter-only speaker notes in `notes`; keep them out of the slide HTML. " +
|
|
100
101
|
"Returns the new slide ID, 1-based slideNumber, and updated slide count.",
|
|
101
102
|
schema: z.object({
|
|
102
103
|
deckId: z.string().describe("Target deck ID"),
|
|
@@ -120,7 +121,10 @@ export default defineAction({
|
|
|
120
121
|
])
|
|
121
122
|
.optional()
|
|
122
123
|
.describe("Layout type hint"),
|
|
123
|
-
notes: z
|
|
124
|
+
notes: z
|
|
125
|
+
.string()
|
|
126
|
+
.optional()
|
|
127
|
+
.describe("Optional presenter-only speaker notes; keep them out of HTML"),
|
|
124
128
|
position: z
|
|
125
129
|
.preprocess((value) => {
|
|
126
130
|
if (typeof value !== "string") return value;
|
|
@@ -299,7 +303,7 @@ export default defineAction({
|
|
|
299
303
|
creativeContextReuseLabels: slideReuseLabels,
|
|
300
304
|
};
|
|
301
305
|
if (layout) newSlide.layout = layout;
|
|
302
|
-
if (notes) newSlide.notes = notes;
|
|
306
|
+
if (notes !== undefined) newSlide.notes = notes;
|
|
303
307
|
|
|
304
308
|
const insertIndex =
|
|
305
309
|
typeof position === "number"
|
|
@@ -96,12 +96,13 @@ export default defineAction({
|
|
|
96
96
|
"Create a new deck, optionally already populated with slides, or atomically replace all slides in an existing deck. " +
|
|
97
97
|
"For short AI-generated decks in MCP app hosts, pass all generated slides in this call so the real deck editor opens inline already populated. " +
|
|
98
98
|
"For longer decks or live in-app generation, create the deck with slides: [] and then use add-slide sequentially so progress appears live. " +
|
|
99
|
+
"Pass presenter-only speaker notes in each slide's `notes` field; keep them out of slide HTML. " +
|
|
99
100
|
"Pass deckId to replace an existing deck. " +
|
|
100
101
|
"Returns the deck id, title, and slide count.",
|
|
101
102
|
schema: z.object({
|
|
102
103
|
title: z.string().describe("Deck title"),
|
|
103
104
|
slides: SlidesSchema.describe(
|
|
104
|
-
"Array of slides with id, content (HTML), and
|
|
105
|
+
"Array of slides with id, content (HTML), optional layout, and presenter-only notes",
|
|
105
106
|
),
|
|
106
107
|
deckId: z
|
|
107
108
|
.string()
|
|
@@ -35,11 +35,11 @@ async function readJson<T>(response: Response): Promise<JsonReadResult<T>> {
|
|
|
35
35
|
try {
|
|
36
36
|
return { ok: true, data: (await response.json()) as T };
|
|
37
37
|
} catch (caught) {
|
|
38
|
+
const error = new Error("The server returned an unreadable response.");
|
|
39
|
+
(error as Error & { cause?: unknown }).cause = caught;
|
|
38
40
|
return {
|
|
39
41
|
ok: false,
|
|
40
|
-
error
|
|
41
|
-
cause: caught,
|
|
42
|
-
}),
|
|
42
|
+
error,
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -56,11 +56,11 @@ async function readJson<T>(response: Response): Promise<JsonReadResult<T>> {
|
|
|
56
56
|
try {
|
|
57
57
|
return { ok: true, data: (await response.json()) as T };
|
|
58
58
|
} catch (caught) {
|
|
59
|
+
const error = new Error("The server returned an unreadable response.");
|
|
60
|
+
(error as Error & { cause?: unknown }).cause = caught;
|
|
59
61
|
return {
|
|
60
62
|
ok: false,
|
|
61
|
-
error
|
|
62
|
-
cause: caught,
|
|
63
|
-
}),
|
|
63
|
+
error,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -55,7 +55,9 @@ export async function uploadPromptFiles(
|
|
|
55
55
|
message = data.error;
|
|
56
56
|
}
|
|
57
57
|
} catch (error) {
|
|
58
|
-
|
|
58
|
+
const uploadError = new Error(`Upload failed (${response.status})`);
|
|
59
|
+
(uploadError as Error & { cause?: unknown }).cause = error;
|
|
60
|
+
throw uploadError;
|
|
59
61
|
}
|
|
60
62
|
throw new Error(message);
|
|
61
63
|
}
|