@agent-native/core 0.161.17 → 0.161.22

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 (176) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/adding-a-feature/SKILL.md +10 -0
  3. package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  4. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +29 -2
  5. package/corpus/templates/analytics/AGENTS.md +1 -0
  6. package/corpus/templates/analytics/server/plugins/auth.ts +4 -0
  7. package/corpus/templates/assets/.agents/skills/adding-a-feature/SKILL.md +10 -0
  8. package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  9. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +29 -2
  10. package/corpus/templates/assets/AGENTS.md +1 -0
  11. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +10 -0
  12. package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  13. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +29 -2
  14. package/corpus/templates/brain/AGENTS.md +1 -0
  15. package/corpus/templates/calendar/.agents/skills/adding-a-feature/SKILL.md +10 -0
  16. package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  17. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +29 -2
  18. package/corpus/templates/calendar/AGENTS.md +1 -0
  19. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
  20. package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  21. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
  22. package/corpus/templates/chat/AGENTS.md +4 -0
  23. package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  24. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +29 -2
  25. package/corpus/templates/clips/AGENTS.md +1 -0
  26. package/corpus/templates/clips/actions/finalize-meeting.ts +57 -21
  27. package/corpus/templates/clips/actions/get-meeting.ts +11 -3
  28. package/corpus/templates/clips/actions/request-transcript.ts +183 -8
  29. package/corpus/templates/clips/actions/update-meeting.ts +66 -14
  30. package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +80 -135
  31. package/corpus/templates/clips/app/components/player/video-player.tsx +4 -0
  32. package/corpus/templates/clips/app/hooks/use-playback-position.ts +10 -2
  33. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  34. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +470 -35
  35. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +1 -0
  36. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +26 -25
  37. package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -0
  38. package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-opens-welcome-window-on-first-launch.md +6 -0
  39. package/corpus/templates/clips/changelog/2026-08-18-meeting-notes-support-rich-editing-for-personal-notes-summar.md +6 -0
  40. package/corpus/templates/clips/changelog/2026-08-18-pending-recording-files-now-use-a-clips-prefixed-name.md +6 -0
  41. package/corpus/templates/clips/desktop/src/main.tsx +0 -3
  42. package/corpus/templates/clips/desktop/src/shared/config.ts +0 -1
  43. package/corpus/templates/clips/desktop/src/styles.css +0 -118
  44. package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +0 -1
  45. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +0 -45
  46. package/corpus/templates/clips/desktop/src-tauri/src/config.rs +1 -4
  47. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +0 -10
  48. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +57 -5
  49. package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +13 -3
  50. package/corpus/templates/content/.agents/skills/adding-a-feature/SKILL.md +10 -0
  51. package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  52. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +29 -2
  53. package/corpus/templates/content/AGENTS.md +1 -0
  54. package/corpus/templates/crm/.agents/skills/adding-a-feature/SKILL.md +10 -0
  55. package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  56. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +29 -2
  57. package/corpus/templates/crm/AGENTS.md +1 -0
  58. package/corpus/templates/design/.agents/skills/adding-a-feature/SKILL.md +10 -0
  59. package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  60. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +29 -2
  61. package/corpus/templates/design/AGENTS.md +1 -0
  62. package/corpus/templates/design/app/i18n-data.ts +11 -0
  63. package/corpus/templates/design/app/lib/agent-chat.ts +9 -8
  64. package/corpus/templates/dispatch/.agents/skills/adding-a-feature/SKILL.md +10 -0
  65. package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  66. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +29 -2
  67. package/corpus/templates/dispatch/AGENTS.md +5 -5
  68. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +10 -0
  69. package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  70. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +29 -2
  71. package/corpus/templates/factory/AGENTS.md +1 -0
  72. package/corpus/templates/forms/.agents/skills/adding-a-feature/SKILL.md +10 -0
  73. package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  74. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +29 -2
  75. package/corpus/templates/forms/AGENTS.md +1 -0
  76. package/corpus/templates/macros/.agents/skills/adding-a-feature/SKILL.md +10 -0
  77. package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  78. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +29 -2
  79. package/corpus/templates/macros/AGENTS.md +1 -0
  80. package/corpus/templates/mail/.agents/skills/adding-a-feature/SKILL.md +10 -0
  81. package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  82. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +29 -2
  83. package/corpus/templates/mail/AGENTS.md +1 -0
  84. package/corpus/templates/mail/app/components/email/EmailList.tsx +74 -22
  85. package/corpus/templates/mail/app/components/email/infinite-pagination.ts +82 -0
  86. package/corpus/templates/mail/app/hooks/use-emails.ts +1 -0
  87. package/corpus/templates/mail/app/pages/InboxPage.tsx +15 -10
  88. package/corpus/templates/mail/app/pages/inbox-zero.ts +35 -0
  89. package/corpus/templates/mail/changelog/2026-08-18-pinned-labels-load-matches.md +6 -0
  90. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +10 -0
  91. package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  92. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +29 -2
  93. package/corpus/templates/plan/AGENTS.md +1 -0
  94. package/corpus/templates/slides/.agents/skills/adding-a-feature/SKILL.md +10 -0
  95. package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  96. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +29 -2
  97. package/corpus/templates/slides/AGENTS.md +2 -1
  98. package/corpus/templates/slides/actions/get-deck.ts +5 -1
  99. package/corpus/templates/slides/actions/list-decks.ts +29 -8
  100. package/corpus/templates/slides/actions/view-screen.ts +7 -3
  101. package/corpus/templates/slides/changelog/2026-08-18-decks-appear-under-mine.md +6 -0
  102. package/corpus/templates/slides/shared/ownership.ts +6 -0
  103. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +10 -0
  104. package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  105. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +29 -2
  106. package/corpus/templates/tasks/AGENTS.md +1 -0
  107. package/dist/action.js +43 -1
  108. package/dist/app-config/schema.d.ts +2 -0
  109. package/dist/app-config/workspace.d.ts +2 -0
  110. package/dist/app-config/workspace.js +18 -0
  111. package/dist/catalog.json +23 -23
  112. package/dist/client/analytics.d.ts +1 -0
  113. package/dist/client/api-path.js +7 -3
  114. package/dist/client/chat/run-recovery.js +1 -1
  115. package/dist/client/frame.js +20 -6
  116. package/dist/client/org/workspace-app-links.js +10 -1
  117. package/dist/client/route-state.js +17 -13
  118. package/dist/collab/awareness.d.ts +2 -2
  119. package/dist/collab/routes.d.ts +1 -1
  120. package/dist/collab/struct-routes.d.ts +1 -1
  121. package/dist/deploy/build.js +26 -2
  122. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  123. package/dist/notifications/routes.d.ts +1 -1
  124. package/dist/observability/routes.d.ts +5 -5
  125. package/dist/provider-api/actions/custom-provider-registration.d.ts +14 -14
  126. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  127. package/dist/secrets/routes.d.ts +9 -9
  128. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  129. package/dist/server/app-origin-config.d.ts +1 -0
  130. package/dist/server/app-origin-config.js +3 -0
  131. package/dist/server/auth.d.ts +6 -0
  132. package/dist/server/auth.js +25 -7
  133. package/dist/server/cookie-namespace.js +17 -2
  134. package/dist/server/credential-provider.js +5 -2
  135. package/dist/server/derived-secret.js +3 -2
  136. package/dist/server/onboarding-html.js +34 -2
  137. package/dist/server/workspace-oauth.js +11 -6
  138. package/dist/shared/runtime-config.d.ts +2 -0
  139. package/dist/shared/runtime-config.js +12 -3
  140. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
  141. package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  142. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
  143. package/dist/templates/chat/AGENTS.md +4 -0
  144. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +10 -0
  145. package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  146. package/dist/templates/default/.agents/skills/secrets/SKILL.md +29 -2
  147. package/dist/templates/default/AGENTS.md +4 -0
  148. package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  149. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +29 -2
  150. package/dist/templates/headless/AGENTS.md +4 -0
  151. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +10 -0
  152. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  153. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -2
  154. package/dist/templates/workspace-core/AGENTS.md +4 -0
  155. package/dist/templates/workspace-root/AGENTS.md +9 -0
  156. package/dist/vite/client.js +5 -2
  157. package/docs/content/deployment.mdx +70 -0
  158. package/docs/content/faq.mdx +1 -1
  159. package/package.json +2 -2
  160. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
  161. package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  162. package/src/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
  163. package/src/templates/chat/AGENTS.md +4 -0
  164. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +10 -0
  165. package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  166. package/src/templates/default/.agents/skills/secrets/SKILL.md +29 -2
  167. package/src/templates/default/AGENTS.md +4 -0
  168. package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  169. package/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -2
  170. package/src/templates/headless/AGENTS.md +4 -0
  171. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +10 -0
  172. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
  173. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -2
  174. package/src/templates/workspace-core/AGENTS.md +4 -0
  175. package/src/templates/workspace-root/AGENTS.md +9 -0
  176. package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +0 -314
@@ -36,6 +36,7 @@ generating or editing a plan.
36
36
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private
37
37
  Builder/internal data, customer data, or credential-looking literals. Use
38
38
  secrets/OAuth/runtime configuration and obvious placeholders in examples.
39
+ - For external integrations, inspect the workspace/provider connection catalog first; reuse its scoped resolver.
39
40
  - Use `view-screen` or application state when the active page/selection is
40
41
  unclear.
41
42
  - Default to structured visual artifacts over long Markdown. Text is one block
@@ -76,6 +76,16 @@ Builder/internal data, or customer data in the action, UI, seed data, fixtures,
76
76
  docs, prompts, or generated extension/app content. Register required secrets,
77
77
  use OAuth helpers, or read scoped values from the vault/credential store.
78
78
 
79
+ Before writing custom setup or credential UI, perform the shared-primitive
80
+ preflight from `agent-native-toolkit`: inspect the workspace/provider connection
81
+ catalog first, then settings, secrets/vault, OAuth, onboarding, and provider API
82
+ support. Reuse an existing connection's app grant and scoped credential
83
+ resolver; only use app-local vault or OAuth primitives when no reusable
84
+ connection exists. Keep any wizard thin and provider-specific - it may explain
85
+ prerequisites, ordering, or readiness, but must not become a second vault or
86
+ custom credential transport. Do not mark each field `required` by reflex;
87
+ model onboarding around the logical connection outcome.
88
+
79
89
  If the feature involves attachments, images, recordings, screenshots, exports,
80
90
  or other file-like payloads, design the upload path in the same change:
81
91
  provider upload first, then URL/id/blob handle in SQL. Do not add base64/binary
@@ -152,6 +152,30 @@ preference, notification preference, or usage/billing surface, register it as a
152
152
  settings tab or app settings panel first. Only add sidebar UI when it is needed
153
153
  in the moment of agent use.
154
154
 
155
+ ## Integration Setup Preflight
156
+
157
+ Before building any setup, settings, credential, OAuth, or connection surface,
158
+ search the workspace/provider connection catalog first. If the provider already
159
+ has a reusable connection, use its catalog, app grant, and scoped credential
160
+ resolver rather than registering a parallel secret. Only then classify fields
161
+ that still need app-local setup by lifecycle and scope:
162
+
163
+ | Need | Default primitive |
164
+ | --- | --- |
165
+ | Deploy- or app-level configuration | Runtime configuration or deployment env vars |
166
+ | Existing workspace/provider connection | Workspace-connection catalog/grant plus `resolveWorkspaceConnectionCredential(s)ForApp` |
167
+ | App-local API/service key with no reusable connection | `registerRequiredSecret({ kind: "api-key" })` and the vault |
168
+ | Authorization-code or refresh-token flow | `kind: "oauth"` with `@agent-native/core/oauth-tokens` |
169
+ | Account, customer, or other non-secret identifiers | Scoped connection metadata or app data |
170
+ | Provider-specific prerequisites, sequencing, or health | A thin app-local guide over the shared primitives |
171
+
172
+ Do not register every provider field as a generic secret, mark every field as
173
+ required, or create a second credential-management surface. One logical
174
+ connection should normally produce one onboarding outcome. A custom setup page
175
+ is appropriate only when it adds domain-specific guidance or readiness checks;
176
+ it should link to or call the shared settings, OAuth, and action surfaces rather
177
+ than duplicating their storage or transport.
178
+
155
179
  ## Reusable Kits
156
180
 
157
181
  - **Settings kit**: a searchable settings page with account, workspace, AI
@@ -3,8 +3,8 @@ name: secrets
3
3
  description: >-
4
4
  Declaratively register API keys and service credentials a template needs so
5
5
  they appear in the agent sidebar settings UI and the onboarding checklist.
6
- Use for any third-party API key (OpenAI, Stripe, Twilio, etc.) and for
7
- surfacing OAuth connections in the unified settings UI.
6
+ Use before adding any third-party credential or setup UI so API keys, OAuth
7
+ connections, and scoped configuration use the correct shared primitive.
8
8
  scope: dev
9
9
  metadata:
10
10
  internal: true
@@ -24,6 +24,33 @@ encrypted `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
24
24
  `${keys.NAME}` substitution. Examples must use obvious placeholders such as
25
25
  `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not real-looking copied values.
26
26
 
27
+ ## Credential Modeling Preflight
28
+
29
+ Before registering a provider's fields, inspect the workspace/provider connection
30
+ catalog first. If a reusable connection exists, use its app grant and scoped
31
+ `resolveWorkspaceConnectionCredential(s)ForApp` path instead of registering a
32
+ parallel secret. Only classify fields for app-local setup when no reusable
33
+ connection exists:
34
+
35
+ - **API or service key** - register it as `kind: "api-key"` with the narrowest
36
+ correct `scope`, a human label, a description, a docs link, and a validator.
37
+ - **OAuth authorization or refresh token** - use the OAuth token store and
38
+ register a `kind: "oauth"` entry so the shared UI renders Connect and the
39
+ runtime owns status, refresh, and reauthorization.
40
+ - **Deploy- or app-level configuration** - use deployment/runtime
41
+ configuration, not a per-user secret row.
42
+ - **Account, customer, manager, or other non-secret identifier** - store it as
43
+ scoped connection metadata or app data, not as a masked secret field.
44
+
45
+ `required: true` is for a logical setup requirement. If a provider needs
46
+ several values, do not automatically create one required checklist item per
47
+ field; use one composite onboarding step or a registered connection readiness
48
+ check.
49
+
50
+ Custom setup UI is allowed for provider-specific prerequisites, ordering, or
51
+ health checks, but it must delegate credential storage and connection state to
52
+ the shared vault/OAuth/settings surfaces.
53
+
27
54
  ## When to use
28
55
 
29
56
  Use this for any external credential your template needs: API keys, service
@@ -23,6 +23,7 @@ Read the relevant skill before deeper work:
23
23
  resources; persist only URLs, ids, or handles.
24
24
  - Never hardcode secrets or private/customer data; use vault/OAuth/runtime
25
25
  configuration and fake placeholders in examples.
26
+ - For external integrations, inspect the workspace/provider connection catalog first; reuse its scoped resolver.
26
27
  - Use actions for deck lifecycle, slide edits, imports, exports, images, design
27
28
  systems, and sharing. Do not write deck/slide rows directly. Read the action
28
29
  schema if a parameter is unclear.
@@ -44,7 +45,7 @@ Read the relevant skill before deeper work:
44
45
  within tolerance; hold Cmd/Ctrl to bypass snapping. With 2+ compatible
45
46
  selected objects, use the contextual toolbar to align to selection bounds;
46
47
  distribute only when 3+ objects are selected.
47
- - Follow linked design-system tokens; read `design-systems` for per-source actions.
48
+ - Follow linked design-system tokens.
48
49
  - Import/export actions are shortcuts, not capability limits. For exact Google
49
50
  Drive API needs, use `provider-api-catalog`, `provider-api-docs`, and
50
51
  `provider-api-request`; auth comes from the user's Google Docs OAuth. Stage
@@ -6,6 +6,7 @@ import { z } from "zod";
6
6
 
7
7
  import { formatSlideHtml } from "../server/lib/slide-content-patch.js";
8
8
  import { summarizeSlideAnimationTargets } from "../server/lib/validate-slide-animations.js";
9
+ import { normalizeOwnerEmail } from "../shared/ownership.js";
9
10
  import { hashSlideContent } from "../shared/slide-fit.js";
10
11
  import "../server/db/index.js"; // ensure registerShareableResource runs
11
12
 
@@ -112,6 +113,7 @@ export default defineAction({
112
113
  const data = JSON.parse(row.data);
113
114
  const slides = data?.slides || [];
114
115
  const ownerEmail = getRequestUserEmail();
116
+ const normalizedOwnerEmail = normalizeOwnerEmail(ownerEmail);
115
117
  const selectedSlideIndex =
116
118
  args.slideId === undefined
117
119
  ? -1
@@ -198,7 +200,9 @@ export default defineAction({
198
200
  id: row.id,
199
201
  title: row.title || data?.title,
200
202
  visibility: row.visibility,
201
- createdByMe: ownerEmail ? row.ownerEmail === ownerEmail : false,
203
+ createdByMe:
204
+ normalizedOwnerEmail !== null &&
205
+ normalizeOwnerEmail(row.ownerEmail) === normalizedOwnerEmail,
202
206
  designSystemId: row.designSystemId ?? null,
203
207
  slideCount: slides.length,
204
208
  slideNumbering:
@@ -2,10 +2,11 @@ import { defineAction } from "@agent-native/core";
2
2
  import { buildDeepLink } from "@agent-native/core/server";
3
3
  import { getRequestUserEmail } from "@agent-native/core/server/request-context";
4
4
  import { accessFilter } from "@agent-native/core/sharing";
5
- import { and, desc, eq } from "drizzle-orm";
5
+ import { and, desc, eq, sql } from "drizzle-orm";
6
6
  import { z } from "zod";
7
7
 
8
8
  import { getDb, schema } from "../server/db/index.js";
9
+ import { normalizeOwnerEmail } from "../shared/ownership.js";
9
10
  import { getDeckUrl } from "./_app-url.js";
10
11
 
11
12
  function slidesDeepLink(): string {
@@ -47,24 +48,28 @@ export default defineAction({
47
48
  run: async (args, ctx) => {
48
49
  const db = getDb();
49
50
  const ownerEmail = getRequestUserEmail();
51
+ const normalizedOwnerEmail = normalizeOwnerEmail(ownerEmail);
50
52
  if (
51
53
  args.includeSlides === "true" &&
52
54
  ctx?.caller === "frontend" &&
53
- !ownerEmail
55
+ normalizedOwnerEmail === null
54
56
  ) {
55
57
  const err = new Error("Unauthorized") as Error & { statusCode?: number };
56
58
  err.statusCode = 401;
57
59
  throw err;
58
60
  }
59
61
 
60
- if (args.createdBy === "me" && !ownerEmail) {
62
+ if (args.createdBy === "me" && normalizedOwnerEmail === null) {
61
63
  return { count: 0, decks: [] };
62
64
  }
63
65
 
64
66
  const visibleDecks = accessFilter(schema.decks, schema.deckShares);
65
67
  const where =
66
- args.createdBy === "me" && ownerEmail
67
- ? and(visibleDecks, eq(schema.decks.ownerEmail, ownerEmail))
68
+ args.createdBy === "me" && normalizedOwnerEmail !== null
69
+ ? and(
70
+ visibleDecks,
71
+ sql`lower(trim(${schema.decks.ownerEmail})) = ${normalizedOwnerEmail}`,
72
+ )
68
73
  : visibleDecks;
69
74
 
70
75
  if (args.light === "true") {
@@ -79,11 +84,23 @@ export default defineAction({
79
84
  title: schema.decks.title,
80
85
  updatedAt: schema.decks.updatedAt,
81
86
  visibility: schema.decks.visibility,
87
+ ownerEmail: schema.decks.ownerEmail,
82
88
  })
83
89
  .from(schema.decks)
84
90
  .where(where)
85
91
  .orderBy(desc(schema.decks.updatedAt));
86
- return { count: rows.length, decks: rows };
92
+ return {
93
+ count: rows.length,
94
+ decks: rows.map((row) => ({
95
+ id: row.id,
96
+ title: row.title,
97
+ updatedAt: row.updatedAt,
98
+ visibility: row.visibility,
99
+ createdByMe:
100
+ normalizedOwnerEmail !== null &&
101
+ normalizeOwnerEmail(row.ownerEmail) === normalizedOwnerEmail,
102
+ })),
103
+ };
87
104
  }
88
105
 
89
106
  if (args.includeSlides !== "true") {
@@ -112,7 +129,9 @@ export default defineAction({
112
129
  url: getDeckUrl(row.id),
113
130
  visibility: row.visibility,
114
131
  designSystemId: row.designSystemId ?? null,
115
- createdByMe: ownerEmail ? row.ownerEmail === ownerEmail : false,
132
+ createdByMe:
133
+ normalizedOwnerEmail !== null &&
134
+ normalizeOwnerEmail(row.ownerEmail) === normalizedOwnerEmail,
116
135
  createdAt: row.createdAt,
117
136
  updatedAt: row.updatedAt,
118
137
  })),
@@ -138,7 +157,9 @@ export default defineAction({
138
157
  id: row.id,
139
158
  title: row.title,
140
159
  visibility: row.visibility,
141
- createdByMe: ownerEmail ? row.ownerEmail === ownerEmail : false,
160
+ createdByMe:
161
+ normalizedOwnerEmail !== null &&
162
+ normalizeOwnerEmail(row.ownerEmail) === normalizedOwnerEmail,
142
163
  designSystemId: row.designSystemId ?? data.designSystemId ?? null,
143
164
  createdAt:
144
165
  typeof data.createdAt === "string" ? data.createdAt : row.createdAt,
@@ -8,6 +8,7 @@ import { and, desc, eq } from "drizzle-orm";
8
8
  import { z } from "zod";
9
9
 
10
10
  import { getDb, schema } from "../server/db/index.js";
11
+ import { normalizeOwnerEmail } from "../shared/ownership.js";
11
12
  import { hashSlideContent, type DeckFitState } from "../shared/slide-fit.js";
12
13
  import { readAppStateForCurrentTab } from "./_tab-state.js";
13
14
 
@@ -369,11 +370,14 @@ export default defineAction({
369
370
  .where(accessFilter(schema.decks, schema.deckShares))
370
371
  .orderBy(desc(schema.decks.updatedAt));
371
372
 
372
- const userEmail = getRequestUserEmail();
373
+ const normalizedUserEmail = normalizeOwnerEmail(getRequestUserEmail());
373
374
  const filteredRows =
374
375
  navigation?.deckFilter === "created-by-me"
375
- ? userEmail
376
- ? rows.filter((row) => row.ownerEmail === userEmail)
376
+ ? normalizedUserEmail !== null
377
+ ? rows.filter(
378
+ (row) =>
379
+ normalizeOwnerEmail(row.ownerEmail) === normalizedUserEmail,
380
+ )
377
381
  : []
378
382
  : rows;
379
383
  const lines: string[] = [];
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-18
4
+ ---
5
+
6
+ Decks now appear correctly under Mine.
@@ -0,0 +1,6 @@
1
+ export function normalizeOwnerEmail(
2
+ email: string | null | undefined,
3
+ ): string | null {
4
+ const normalized = email?.trim().toLowerCase();
5
+ return normalized || null;
6
+ }
@@ -76,6 +76,16 @@ Builder/internal data, or customer data in the action, UI, seed data, fixtures,
76
76
  docs, prompts, or generated extension/app content. Register required secrets,
77
77
  use OAuth helpers, or read scoped values from the vault/credential store.
78
78
 
79
+ Before writing custom setup or credential UI, perform the shared-primitive
80
+ preflight from `agent-native-toolkit`: inspect the workspace/provider connection
81
+ catalog first, then settings, secrets/vault, OAuth, onboarding, and provider API
82
+ support. Reuse an existing connection's app grant and scoped credential
83
+ resolver; only use app-local vault or OAuth primitives when no reusable
84
+ connection exists. Keep any wizard thin and provider-specific - it may explain
85
+ prerequisites, ordering, or readiness, but must not become a second vault or
86
+ custom credential transport. Do not mark each field `required` by reflex;
87
+ model onboarding around the logical connection outcome.
88
+
79
89
  If the feature involves attachments, images, recordings, screenshots, exports,
80
90
  or other file-like payloads, design the upload path in the same change:
81
91
  provider upload first, then URL/id/blob handle in SQL. Do not add base64/binary
@@ -152,6 +152,30 @@ preference, notification preference, or usage/billing surface, register it as a
152
152
  settings tab or app settings panel first. Only add sidebar UI when it is needed
153
153
  in the moment of agent use.
154
154
 
155
+ ## Integration Setup Preflight
156
+
157
+ Before building any setup, settings, credential, OAuth, or connection surface,
158
+ search the workspace/provider connection catalog first. If the provider already
159
+ has a reusable connection, use its catalog, app grant, and scoped credential
160
+ resolver rather than registering a parallel secret. Only then classify fields
161
+ that still need app-local setup by lifecycle and scope:
162
+
163
+ | Need | Default primitive |
164
+ | --- | --- |
165
+ | Deploy- or app-level configuration | Runtime configuration or deployment env vars |
166
+ | Existing workspace/provider connection | Workspace-connection catalog/grant plus `resolveWorkspaceConnectionCredential(s)ForApp` |
167
+ | App-local API/service key with no reusable connection | `registerRequiredSecret({ kind: "api-key" })` and the vault |
168
+ | Authorization-code or refresh-token flow | `kind: "oauth"` with `@agent-native/core/oauth-tokens` |
169
+ | Account, customer, or other non-secret identifiers | Scoped connection metadata or app data |
170
+ | Provider-specific prerequisites, sequencing, or health | A thin app-local guide over the shared primitives |
171
+
172
+ Do not register every provider field as a generic secret, mark every field as
173
+ required, or create a second credential-management surface. One logical
174
+ connection should normally produce one onboarding outcome. A custom setup page
175
+ is appropriate only when it adds domain-specific guidance or readiness checks;
176
+ it should link to or call the shared settings, OAuth, and action surfaces rather
177
+ than duplicating their storage or transport.
178
+
155
179
  ## Reusable Kits
156
180
 
157
181
  - **Settings kit**: a searchable settings page with account, workspace, AI
@@ -3,8 +3,8 @@ name: secrets
3
3
  description: >-
4
4
  Declaratively register API keys and service credentials a template needs so
5
5
  they appear in the agent sidebar settings UI and the onboarding checklist.
6
- Use for any third-party API key (OpenAI, Stripe, Twilio, etc.) and for
7
- surfacing OAuth connections in the unified settings UI.
6
+ Use before adding any third-party credential or setup UI so API keys, OAuth
7
+ connections, and scoped configuration use the correct shared primitive.
8
8
  scope: dev
9
9
  metadata:
10
10
  internal: true
@@ -24,6 +24,33 @@ encrypted `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
24
24
  `${keys.NAME}` substitution. Examples must use obvious placeholders such as
25
25
  `<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not real-looking copied values.
26
26
 
27
+ ## Credential Modeling Preflight
28
+
29
+ Before registering a provider's fields, inspect the workspace/provider connection
30
+ catalog first. If a reusable connection exists, use its app grant and scoped
31
+ `resolveWorkspaceConnectionCredential(s)ForApp` path instead of registering a
32
+ parallel secret. Only classify fields for app-local setup when no reusable
33
+ connection exists:
34
+
35
+ - **API or service key** - register it as `kind: "api-key"` with the narrowest
36
+ correct `scope`, a human label, a description, a docs link, and a validator.
37
+ - **OAuth authorization or refresh token** - use the OAuth token store and
38
+ register a `kind: "oauth"` entry so the shared UI renders Connect and the
39
+ runtime owns status, refresh, and reauthorization.
40
+ - **Deploy- or app-level configuration** - use deployment/runtime
41
+ configuration, not a per-user secret row.
42
+ - **Account, customer, manager, or other non-secret identifier** - store it as
43
+ scoped connection metadata or app data, not as a masked secret field.
44
+
45
+ `required: true` is for a logical setup requirement. If a provider needs
46
+ several values, do not automatically create one required checklist item per
47
+ field; use one composite onboarding step or a registered connection readiness
48
+ check.
49
+
50
+ Custom setup UI is allowed for provider-specific prerequisites, ordering, or
51
+ health checks, but it must delegate credential storage and connection state to
52
+ the shared vault/OAuth/settings surfaces.
53
+
27
54
  ## When to use
28
55
 
29
56
  Use this for any external credential your template needs: API keys, service
@@ -14,6 +14,7 @@ Read the matching skill before acting. This file is the always-on layer; the ski
14
14
  ## Core Rules
15
15
 
16
16
  - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
17
+ - For external integrations, inspect the workspace/provider connection catalog first; reuse its scoped resolver.
17
18
  - Follow the root framework contract: data in SQL, actions first, application state for navigation/selection, and shared agent chat for AI work.
18
19
  - Do not use `db-query` for normal task operations.
19
20
  - Call `view-screen` first when the user's visible task context matters (especially on `/tasks`).
package/dist/action.js CHANGED
@@ -393,11 +393,53 @@ const TYPE_SUBSTITUTE_KEYS = [
393
393
  "$ref",
394
394
  "not",
395
395
  ];
396
+ /**
397
+ * `format` values OpenAI's function-schema validator accepts. Anything else --
398
+ * `uri` from `z.string().url()`, `binary`, `regex`, … -- is answered with
399
+ * "'<x>' is not a valid format" and a 400 for the WHOLE request.
400
+ *
401
+ * Dropping an unknown format only widens what the schema accepts, and the
402
+ * action's own zod schema still validates the value server-side, so nothing is
403
+ * actually loosened. Kept as an allowlist rather than a denylist: a new format
404
+ * we have not heard of should degrade to "unconstrained", not to a 400 that
405
+ * takes every other tool in the payload down with it.
406
+ */
407
+ const PROVIDER_SUPPORTED_FORMATS = new Set([
408
+ "date-time",
409
+ "time",
410
+ "date",
411
+ "duration",
412
+ "email",
413
+ "hostname",
414
+ "ipv4",
415
+ "ipv6",
416
+ "uuid",
417
+ ]);
418
+ /**
419
+ * Keywords that only ever CONSTRAIN a value and that OpenAI's validator rejects
420
+ * outright. Removing a constraint can never make a previously-valid document
421
+ * invalid, so this is safe in a way that rewriting structure would not be.
422
+ */
423
+ const PROVIDER_REJECTED_KEYWORDS = [
424
+ "propertyNames",
425
+ "patternProperties",
426
+ "dependentSchemas",
427
+ "dependentRequired",
428
+ "if",
429
+ "then",
430
+ "else",
431
+ "not",
432
+ ];
396
433
  export function stripUnsupportedSchemaKeywords(node) {
397
434
  if (!node || typeof node !== "object" || Array.isArray(node))
398
435
  return node;
399
436
  const obj = node;
400
- delete obj.propertyNames;
437
+ for (const keyword of PROVIDER_REJECTED_KEYWORDS)
438
+ delete obj[keyword];
439
+ if (typeof obj.format === "string" &&
440
+ !PROVIDER_SUPPORTED_FORMATS.has(obj.format)) {
441
+ delete obj.format;
442
+ }
401
443
  for (const key of SUBSCHEMA_VALUE_KEYS) {
402
444
  // `items`/`additionalItems` may also be an array of subschemas.
403
445
  const value = obj[key];
@@ -40,6 +40,8 @@ export declare const appConfigSchema: z.ZodObject<{
40
40
  publicUploadFallback: z.ZodDefault<z.ZodBoolean>;
41
41
  }, z.core.$strip>>;
42
42
  workspace: z.ZodPrefault<z.ZodObject<{
43
+ isWorkspace: z.ZodOptional<z.ZodBoolean>;
44
+ appsJson: z.ZodOptional<z.ZodString>;
43
45
  gatewayUrl: z.ZodOptional<z.ZodString>;
44
46
  oauthOrigin: z.ZodOptional<z.ZodString>;
45
47
  }, z.core.$strip>>;
@@ -16,6 +16,8 @@ import { z } from "zod";
16
16
  * in the process down with it.
17
17
  */
18
18
  export declare const workspaceConfig: z.ZodObject<{
19
+ isWorkspace: z.ZodOptional<z.ZodBoolean>;
20
+ appsJson: z.ZodOptional<z.ZodString>;
19
21
  gatewayUrl: z.ZodOptional<z.ZodString>;
20
22
  oauthOrigin: z.ZodOptional<z.ZodString>;
21
23
  }, z.core.$strip>;
@@ -16,6 +16,24 @@ import { z } from "zod";
16
16
  * in the process down with it.
17
17
  */
18
18
  export const workspaceConfig = z.object({
19
+ isWorkspace: z
20
+ .boolean()
21
+ .optional()
22
+ .meta({
23
+ env: ["AGENT_NATIVE_WORKSPACE", "VITE_AGENT_NATIVE_WORKSPACE"],
24
+ doc: "Whether this app is mounted inside a shared workspace gateway.",
25
+ }),
26
+ appsJson: z
27
+ .string()
28
+ .min(1)
29
+ .optional()
30
+ .meta({
31
+ env: [
32
+ "AGENT_NATIVE_WORKSPACE_APPS_JSON",
33
+ "VITE_AGENT_NATIVE_WORKSPACE_APPS_JSON",
34
+ ],
35
+ doc: "Serialized workspace app manifest used by mounted app runtimes.",
36
+ }),
19
37
  gatewayUrl: z
20
38
  .string()
21
39
  .min(1)
package/dist/catalog.json CHANGED
@@ -7,28 +7,28 @@
7
7
  "@radix-ui/react-popover": "^1.1.19",
8
8
  "@radix-ui/react-select": "^2.3.3",
9
9
  "@radix-ui/react-tooltip": "^1.2.12",
10
- "@tiptap/core": "3.28.0",
11
- "@tiptap/extension-blockquote": "3.28.0",
12
- "@tiptap/extension-bubble-menu": "3.28.0",
13
- "@tiptap/extension-code-block-lowlight": "3.28.0",
14
- "@tiptap/extension-collaboration": "3.28.0",
15
- "@tiptap/extension-collaboration-caret": "3.28.0",
16
- "@tiptap/extension-color": "3.28.0",
17
- "@tiptap/extension-horizontal-rule": "3.28.0",
18
- "@tiptap/extension-image": "3.28.0",
19
- "@tiptap/extension-link": "3.28.0",
20
- "@tiptap/extension-list": "3.28.0",
21
- "@tiptap/extension-placeholder": "3.28.0",
22
- "@tiptap/extension-table": "3.28.0",
23
- "@tiptap/extension-table-cell": "3.28.0",
24
- "@tiptap/extension-table-header": "3.28.0",
25
- "@tiptap/extension-table-row": "3.28.0",
26
- "@tiptap/extension-task-item": "3.28.0",
27
- "@tiptap/extension-task-list": "3.28.0",
28
- "@tiptap/extension-text-style": "3.28.0",
29
- "@tiptap/pm": "3.28.0",
30
- "@tiptap/react": "3.28.0",
31
- "@tiptap/starter-kit": "3.28.0",
10
+ "@tiptap/core": "3.30.1",
11
+ "@tiptap/extension-blockquote": "3.30.1",
12
+ "@tiptap/extension-bubble-menu": "3.30.1",
13
+ "@tiptap/extension-code-block-lowlight": "3.30.1",
14
+ "@tiptap/extension-collaboration": "3.30.1",
15
+ "@tiptap/extension-collaboration-caret": "3.30.1",
16
+ "@tiptap/extension-color": "3.30.1",
17
+ "@tiptap/extension-horizontal-rule": "3.30.1",
18
+ "@tiptap/extension-image": "3.30.1",
19
+ "@tiptap/extension-link": "3.30.1",
20
+ "@tiptap/extension-list": "3.30.1",
21
+ "@tiptap/extension-placeholder": "3.30.1",
22
+ "@tiptap/extension-table": "3.30.1",
23
+ "@tiptap/extension-table-cell": "3.30.1",
24
+ "@tiptap/extension-table-header": "3.30.1",
25
+ "@tiptap/extension-table-row": "3.30.1",
26
+ "@tiptap/extension-task-item": "3.30.1",
27
+ "@tiptap/extension-task-list": "3.30.1",
28
+ "@tiptap/extension-text-style": "3.30.1",
29
+ "@tiptap/pm": "3.30.1",
30
+ "@tiptap/react": "3.30.1",
31
+ "@tiptap/starter-kit": "3.30.1",
32
32
  "@tiptap/y-tiptap": "3.0.7",
33
33
  "@tabler/icons-react": "^3.41.1",
34
34
  "@tailwindcss/vite": "^4.2.4",
@@ -56,5 +56,5 @@
56
56
  "vite": "8.1.0",
57
57
  "vitest": "^4.1.5",
58
58
  "y-protocols": "^1.0.7",
59
- "yjs": "^13.6.31"
59
+ "yjs": "^13.6.32"
60
60
  }
@@ -18,6 +18,7 @@ declare global {
18
18
  appUrl?: string;
19
19
  workspaceGatewayUrl?: string;
20
20
  workspaceOAuthOrigin?: string;
21
+ workspaceRuntime?: boolean;
21
22
  sentryDsn?: string;
22
23
  sentryEnvironment?: string;
23
24
  /**
@@ -1,3 +1,4 @@
1
+ import { isTruthyRuntimeValue } from "../shared/runtime-config.js";
1
2
  import { initializeAgentNativeClient } from "./client-bootstrap.js";
2
3
  const FRAMEWORK_ROUTE_PREFIX = "/_agent-native";
3
4
  function normalizeBasePath(value) {
@@ -34,8 +35,11 @@ function pathMatchesBasePath(pathname, basePath) {
34
35
  }
35
36
  function isWorkspaceRuntime() {
36
37
  const env = clientEnv();
37
- return (env?.VITE_AGENT_NATIVE_WORKSPACE === "1" ||
38
- env?.AGENT_NATIVE_WORKSPACE === "1" ||
38
+ const projected = typeof window !== "undefined" &&
39
+ window.__AGENT_NATIVE_CONFIG__?.workspaceRuntime === true;
40
+ return (projected ||
41
+ isTruthyRuntimeValue(env?.VITE_AGENT_NATIVE_WORKSPACE) ||
42
+ isTruthyRuntimeValue(env?.AGENT_NATIVE_WORKSPACE) ||
39
43
  typeof env?.VITE_AGENT_NATIVE_WORKSPACE_APPS_JSON === "string");
40
44
  }
41
45
  function workspacePathBasePath() {
@@ -78,7 +82,7 @@ export function appBasePath() {
78
82
  const configured = configuredBasePath();
79
83
  const derived = pathDerivedBasePath();
80
84
  if (!configured)
81
- return derived;
85
+ return derived || workspacePathBasePath();
82
86
  if (typeof window === "undefined")
83
87
  return configured;
84
88
  const pathname = window.location.pathname;
@@ -158,7 +158,7 @@ export function BuilderSetupContent({ onConnected, layout = "default", }) {
158
158
  return (_jsxs("div", { className: cn("agent-builder-setup-content", sidebarLayout && "agent-builder-setup-card--sidebar"), children: [_jsxs("div", { className: cn("agent-builder-setup-card__content flex flex-col sm:flex-row sm:items-center sm:justify-between", sidebarLayout ? "gap-2" : "gap-3"), children: [_jsxs("div", { className: "agent-builder-setup-card__copy min-w-0", children: [_jsx("h3", { className: "text-[13px] font-medium text-foreground", children: t("agentPanel.connectAi", { defaultValue: "Connect AI" }) }), _jsx("p", { className: "mt-0.5 text-[11px] leading-relaxed text-muted-foreground", children: t("agentPanel.builderOrOwnKeys", {
159
159
  defaultValue: "Choose Builder.io or custom keys.",
160
160
  }) })] }), _jsxs("div", { className: cn("agent-builder-setup-card__actions flex shrink-0", sidebarLayout
161
- ? "flex-col items-start gap-1 sm:items-center"
161
+ ? "flex-row items-center gap-1"
162
162
  : "flex-nowrap items-center gap-2"), children: [_jsx(BuilderConnectCta, { variant: "compact", onConnected: onConnected }), _jsx("button", { type: "button", onClick: () => setKeyOpen((open) => !open), className: cn("agent-builder-setup-card__key-button inline-flex shrink-0 items-center whitespace-nowrap rounded-md text-[11px] font-medium", sidebarLayout
163
163
  ? "h-7 border-0 bg-transparent px-0 text-muted-foreground hover:bg-transparent hover:text-foreground"
164
164
  : "h-8 border border-border bg-background px-3 text-foreground hover:bg-accent"), "aria-expanded": keyOpen, children: t("agentPanel.addOwnKeys", {