@agent-native/core 0.114.0 → 0.114.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +15 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/create.ts +23 -0
- package/corpus/core/src/cli/skills.ts +24 -0
- package/corpus/core/src/client/build-compatibility.ts +77 -0
- package/corpus/core/src/client/route-chunk-recovery/index.ts +1 -0
- package/corpus/core/src/client/use-action.ts +32 -1
- package/corpus/core/src/deploy/build.ts +4 -1
- package/corpus/core/src/org/context.ts +56 -30
- package/corpus/core/src/server/action-routes.ts +52 -2
- package/corpus/core/src/server/auth-plugin.ts +9 -4
- package/corpus/core/src/server/better-auth-instance.ts +5 -1
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/core/src/templates/default/AGENTS.md +4 -1
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/core/src/templates/headless/AGENTS.md +5 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -1
- package/corpus/core/src/templates/workspace-root/AGENTS.md +3 -1
- package/corpus/core/src/vite/client.ts +17 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/analytics/AGENTS.md +5 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/assets/AGENTS.md +5 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/brain/AGENTS.md +5 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/calendar/AGENTS.md +5 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/chat/AGENTS.md +4 -1
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/clips/AGENTS.md +5 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/content/AGENTS.md +7 -0
- package/corpus/templates/content/actions/_content-database-personal-view.ts +49 -5
- package/corpus/templates/content/actions/_content-document-access.ts +21 -0
- package/corpus/templates/content/actions/_content-favorites.ts +91 -0
- package/corpus/templates/content/actions/_content-files.ts +79 -23
- package/corpus/templates/content/actions/_content-sidebar-state.ts +24 -0
- package/corpus/templates/content/actions/_content-space-access.ts +15 -17
- package/corpus/templates/content/actions/_content-space-catalog-guards.ts +20 -0
- package/corpus/templates/content/actions/_content-spaces.ts +364 -167
- package/corpus/templates/content/actions/_database-source-utils.ts +8 -0
- package/corpus/templates/content/actions/_database-utils.ts +249 -15
- package/corpus/templates/content/actions/_delete-content-space.ts +84 -0
- package/corpus/templates/content/actions/_files-system-properties.ts +499 -0
- package/corpus/templates/content/actions/_local-file-documents.ts +0 -1
- package/corpus/templates/content/actions/_property-utils.ts +18 -9
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +3 -0
- package/corpus/templates/content/actions/configure-document-property.ts +3 -0
- package/corpus/templates/content/actions/create-content-database.ts +2 -2
- package/corpus/templates/content/actions/create-content-space.ts +34 -0
- package/corpus/templates/content/actions/create-document.ts +4 -1
- package/corpus/templates/content/actions/delete-content-space.ts +19 -0
- package/corpus/templates/content/actions/delete-database-items.ts +28 -1
- package/corpus/templates/content/actions/delete-document-property.ts +3 -0
- package/corpus/templates/content/actions/delete-document.ts +39 -2
- package/corpus/templates/content/actions/duplicate-database-item.ts +6 -0
- package/corpus/templates/content/actions/duplicate-database-items.ts +6 -0
- package/corpus/templates/content/actions/duplicate-document-property.ts +3 -0
- package/corpus/templates/content/actions/get-content-database.ts +11 -2
- package/corpus/templates/content/actions/get-content-sidebar-state.ts +23 -0
- package/corpus/templates/content/actions/get-document.ts +32 -7
- package/corpus/templates/content/actions/import-content-source.ts +33 -1
- package/corpus/templates/content/actions/list-content-spaces.ts +34 -2
- package/corpus/templates/content/actions/list-documents.ts +39 -7
- package/corpus/templates/content/actions/reorder-document-property.ts +9 -0
- package/corpus/templates/content/actions/set-document-property.ts +41 -23
- package/corpus/templates/content/actions/share-local-file-document.ts +15 -0
- package/corpus/templates/content/actions/submit-content-database-form.ts +7 -0
- package/corpus/templates/content/actions/sync-local-folder-source.ts +14 -0
- package/corpus/templates/content/actions/update-content-database-view.ts +1 -0
- package/corpus/templates/content/actions/update-content-sidebar-state.ts +27 -0
- package/corpus/templates/content/actions/update-document.ts +158 -66
- package/corpus/templates/content/app/components/EmptyState.tsx +4 -57
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +8 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +519 -178
- package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +39 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +1 -1
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +266 -7
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +430 -152
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +467 -66
- package/corpus/templates/content/app/components/editor/database/view-config.ts +9 -3
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +720 -196
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +173 -1
- package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +1 -1
- package/corpus/templates/content/app/components/sidebar/select-content-space.ts +91 -16
- package/corpus/templates/content/app/entry.client.tsx +5 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +84 -3
- package/corpus/templates/content/app/hooks/use-content-spaces.ts +60 -2
- package/corpus/templates/content/app/hooks/use-create-page.ts +30 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +270 -19
- package/corpus/templates/content/app/i18n-data.ts +243 -20
- package/corpus/templates/content/app/lib/local-folder-picker-safety.ts +54 -0
- package/corpus/templates/content/app/lib/local-folder-picker-support.ts +18 -0
- package/corpus/templates/content/app/routes/_app.favorites.tsx +30 -0
- package/corpus/templates/content/app/routes/_app.local-files.tsx +18 -6
- package/corpus/templates/content/changelog/2026-07-17-workspace-files-now-stay-in-a-loading-state-until-automatic-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-workspace-switching-now-opens-the-selected-files-database-pr.md +6 -0
- package/corpus/templates/content/changelog/2026-07-17-workspaces-now-expand-above-their-own-files-list-without-dup.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-create-named-workspaces-each-with-its-own-private-files-data.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-favorites-align-with-workspace-and-file-rows-in-the-sidebar.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-local-folder-selection-no-longer-invokes-the-unsafe-native-p.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-made-content-workspaces-independently-expandable-restored-or.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-page-details-now-live-in-a-shared-info-and-comments-rail-dat.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-workspace-database-views-now-control-sidebar-workspace-navig.md +6 -0
- package/corpus/templates/content/changelog/2026-07-18-workspace-navigation-now-aligns-favorites-with-workspace-pag.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-favorites-now-open-as-a-table-and-compact-breadcrumbs-make-w.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-files-databases-now-start-unfiltered-sidebar-rows-exactly-fo.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-sidebar-page-trees-now-open-only-when-expanded-remember-thei.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-file-databases-now-use-the-workspace-name-open-as-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-navigation-now-stays-stable-on-hover-uses-folder-i.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspace-rows-now-use-folder-icons-and-deleting-a-user-crea.md +6 -0
- package/corpus/templates/content/changelog/2026-07-19-workspaces-can-be-created-without-leaving-the-workspaces-dat.md +6 -0
- package/corpus/templates/content/e2e/global-setup.ts +3 -2
- package/corpus/templates/content/parity/matrix.md +28 -28
- package/corpus/templates/content/parity/matrix.ts +8 -2
- package/corpus/templates/content/server/db/index.ts +1 -0
- package/corpus/templates/content/server/db/schema.ts +10 -0
- package/corpus/templates/content/server/lib/documents.ts +12 -7
- package/corpus/templates/content/server/plugins/db.ts +17 -0
- package/corpus/templates/content/shared/api.ts +9 -0
- package/corpus/templates/content/shared/database-form.ts +11 -2
- package/corpus/templates/content/vite.config.ts +1 -0
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/design/AGENTS.md +5 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/dispatch/AGENTS.md +5 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/forms/AGENTS.md +5 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/macros/AGENTS.md +5 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/mail/AGENTS.md +5 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/plan/AGENTS.md +5 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/slides/AGENTS.md +5 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/corpus/templates/tasks/AGENTS.md +5 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +21 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +19 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/build-compatibility.d.ts +11 -0
- package/dist/client/build-compatibility.d.ts.map +1 -0
- package/dist/client/build-compatibility.js +56 -0
- package/dist/client/build-compatibility.js.map +1 -0
- package/dist/client/route-chunk-recovery/index.d.ts +1 -0
- package/dist/client/route-chunk-recovery/index.d.ts.map +1 -1
- package/dist/client/route-chunk-recovery/index.js +1 -0
- package/dist/client/route-chunk-recovery/index.js.map +1 -1
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +19 -1
- package/dist/client/use-action.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/deploy/build.js +2 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/org/context.d.ts +4 -2
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +44 -22
- package/dist/org/context.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +32 -2
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth-plugin.d.ts.map +1 -1
- package/dist/server/auth-plugin.js +9 -5
- package/dist/server/auth-plugin.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +4 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +1 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/chat/AGENTS.md +4 -1
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/default/AGENTS.md +4 -1
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/dist/templates/headless/AGENTS.md +5 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -1
- package/dist/templates/workspace-root/AGENTS.md +3 -1
- package/dist/vite/client.d.ts +6 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +8 -0
- package/dist/vite/client.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/create.ts +23 -0
- package/src/cli/skills.ts +24 -0
- package/src/client/build-compatibility.ts +77 -0
- package/src/client/route-chunk-recovery/index.ts +1 -0
- package/src/client/use-action.ts +32 -1
- package/src/deploy/build.ts +4 -1
- package/src/org/context.ts +56 -30
- package/src/server/action-routes.ts +52 -2
- package/src/server/auth-plugin.ts +9 -4
- package/src/server/better-auth-instance.ts +5 -1
- package/src/shared/mcp-embed-headers.ts +1 -1
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/chat/AGENTS.md +4 -1
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/default/AGENTS.md +4 -1
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +133 -0
- package/src/templates/headless/AGENTS.md +5 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +26 -0
- package/src/templates/workspace-core/AGENTS.md +3 -1
- package/src/templates/workspace-root/AGENTS.md +3 -1
- package/src/vite/client.ts +17 -0
package/corpus/README.md
CHANGED
package/corpus/core/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @agent-native/core
|
|
2
2
|
|
|
3
|
+
## 0.114.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3253e1d: Teach generated agents to discover Toolkit capabilities before composing or ejecting shared features.
|
|
8
|
+
|
|
9
|
+
## 0.114.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- c913280: Keep action mutations pending until asynchronous success callbacks finish.
|
|
14
|
+
- c913280: Allow email-password signup without email verification on Netlify deploy previews while preserving explicit verification overrides, and hold auth requests until their serverless routes finish mounting.
|
|
15
|
+
- c913280: Fence incompatible cached browser clients from newer action backends and reload version-aware tabs with a cache-busted build.
|
|
16
|
+
- c913280: Honor an explicit Personal context for users who also belong to organizations.
|
|
17
|
+
|
|
3
18
|
## 0.114.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
package/corpus/core/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.114.
|
|
3
|
+
"version": "0.114.2",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -1697,10 +1697,33 @@ function fixPackageJsonName(
|
|
|
1697
1697
|
) {
|
|
1698
1698
|
pkg.description = defaultPackageDescriptionForScaffold(name);
|
|
1699
1699
|
}
|
|
1700
|
+
const scaffoldGuidance = scaffoldGuidanceForTemplate(templateName);
|
|
1701
|
+
if (scaffoldGuidance) {
|
|
1702
|
+
const agentNative =
|
|
1703
|
+
pkg["agent-native"] &&
|
|
1704
|
+
typeof pkg["agent-native"] === "object" &&
|
|
1705
|
+
!Array.isArray(pkg["agent-native"])
|
|
1706
|
+
? pkg["agent-native"]
|
|
1707
|
+
: {};
|
|
1708
|
+
agentNative.scaffold = {
|
|
1709
|
+
template: trackingTemplateName(templateName),
|
|
1710
|
+
frameworkSkills: scaffoldGuidance,
|
|
1711
|
+
};
|
|
1712
|
+
pkg["agent-native"] = agentNative;
|
|
1713
|
+
}
|
|
1700
1714
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1701
1715
|
} catch {}
|
|
1702
1716
|
}
|
|
1703
1717
|
|
|
1718
|
+
function scaffoldGuidanceForTemplate(
|
|
1719
|
+
templateName: string | undefined,
|
|
1720
|
+
): "default" | "headless" | undefined {
|
|
1721
|
+
if (!templateName || templateName.startsWith("github:")) return undefined;
|
|
1722
|
+
const normalized = normalizeTemplateName(templateName);
|
|
1723
|
+
if (normalized === "headless") return "headless";
|
|
1724
|
+
return getTemplate(normalized) ? "default" : undefined;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1704
1727
|
function fixWebManifestName(
|
|
1705
1728
|
appDir: string,
|
|
1706
1729
|
name: string,
|
|
@@ -1580,6 +1580,27 @@ function hasAgentNativeCoreDependency(
|
|
|
1580
1580
|
return false;
|
|
1581
1581
|
}
|
|
1582
1582
|
|
|
1583
|
+
function markedScaffoldGuidanceTemplate(
|
|
1584
|
+
pkg: Record<string, unknown> | undefined,
|
|
1585
|
+
): "headless" | "default" | undefined {
|
|
1586
|
+
const agentNative = pkg?.["agent-native"];
|
|
1587
|
+
if (
|
|
1588
|
+
!agentNative ||
|
|
1589
|
+
typeof agentNative !== "object" ||
|
|
1590
|
+
Array.isArray(agentNative)
|
|
1591
|
+
) {
|
|
1592
|
+
return undefined;
|
|
1593
|
+
}
|
|
1594
|
+
const scaffold = (agentNative as Record<string, unknown>).scaffold;
|
|
1595
|
+
if (!scaffold || typeof scaffold !== "object" || Array.isArray(scaffold)) {
|
|
1596
|
+
return undefined;
|
|
1597
|
+
}
|
|
1598
|
+
const frameworkSkills = (scaffold as Record<string, unknown>).frameworkSkills;
|
|
1599
|
+
return frameworkSkills === "headless" || frameworkSkills === "default"
|
|
1600
|
+
? frameworkSkills
|
|
1601
|
+
: undefined;
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1583
1604
|
function findWorkspaceCorePackageDir(
|
|
1584
1605
|
workspaceRoot: string,
|
|
1585
1606
|
workspaceCoreName: string,
|
|
@@ -1634,6 +1655,9 @@ function detectStandaloneScaffoldTemplate(
|
|
|
1634
1655
|
return undefined;
|
|
1635
1656
|
}
|
|
1636
1657
|
|
|
1658
|
+
const markedTemplate = markedScaffoldGuidanceTemplate(pkg);
|
|
1659
|
+
if (markedTemplate) return markedTemplate;
|
|
1660
|
+
|
|
1637
1661
|
const hasAppDir = fs.existsSync(path.join(projectRoot, "app"));
|
|
1638
1662
|
const hasHeadlessHello = fs.existsSync(
|
|
1639
1663
|
path.join(projectRoot, "actions", "hello.ts"),
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
declare const __AGENT_NATIVE_BUILD_ID__: string | undefined;
|
|
2
|
+
declare const __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__: string | undefined;
|
|
3
|
+
|
|
4
|
+
const RELOAD_MARKER_KEY = "__agentNativeClientCompatibilityReload";
|
|
5
|
+
export const BUILD_CACHE_BUSTER_PARAM = "__an_build";
|
|
6
|
+
|
|
7
|
+
type CompatibilityWindow = Pick<Window, "location" | "history"> & {
|
|
8
|
+
sessionStorage?: Storage;
|
|
9
|
+
__agentNativeClientCompatibilityReload?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function clientBuildId(): string {
|
|
13
|
+
if (typeof __AGENT_NATIVE_BUILD_ID__ === "string") {
|
|
14
|
+
return __AGENT_NATIVE_BUILD_ID__;
|
|
15
|
+
}
|
|
16
|
+
return (
|
|
17
|
+
(globalThis as typeof globalThis & { __AGENT_NATIVE_BUILD_ID__?: string })
|
|
18
|
+
.__AGENT_NATIVE_BUILD_ID__ ?? ""
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function clientCompatibilityVersion(): string {
|
|
23
|
+
if (typeof __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ === "string") {
|
|
24
|
+
return __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__;
|
|
25
|
+
}
|
|
26
|
+
return (
|
|
27
|
+
(
|
|
28
|
+
globalThis as typeof globalThis & {
|
|
29
|
+
__AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__?: string;
|
|
30
|
+
}
|
|
31
|
+
).__AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ ?? ""
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readReloadMarker(win: CompatibilityWindow): string {
|
|
36
|
+
try {
|
|
37
|
+
return win.sessionStorage?.getItem(RELOAD_MARKER_KEY) ?? "";
|
|
38
|
+
} catch {
|
|
39
|
+
return win.__agentNativeClientCompatibilityReload ?? "";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function writeReloadMarker(win: CompatibilityWindow, marker: string): void {
|
|
44
|
+
win.__agentNativeClientCompatibilityReload = marker;
|
|
45
|
+
try {
|
|
46
|
+
win.sessionStorage?.setItem(RELOAD_MARKER_KEY, marker);
|
|
47
|
+
} catch {}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function reloadForClientCompatibilityMismatch(
|
|
51
|
+
serverBuildId: string,
|
|
52
|
+
requiredCompatibility: string,
|
|
53
|
+
win: CompatibilityWindow | undefined = typeof window === "undefined"
|
|
54
|
+
? undefined
|
|
55
|
+
: window,
|
|
56
|
+
): boolean {
|
|
57
|
+
if (!win?.location) return false;
|
|
58
|
+
const marker = `${requiredCompatibility}:${serverBuildId}`;
|
|
59
|
+
if (readReloadMarker(win) === marker) return false;
|
|
60
|
+
writeReloadMarker(win, marker);
|
|
61
|
+
const target = new URL(win.location.href);
|
|
62
|
+
target.searchParams.set(BUILD_CACHE_BUSTER_PARAM, serverBuildId || "latest");
|
|
63
|
+
win.location.replace(target.href);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function stripBuildCompatibilityCacheBuster(
|
|
68
|
+
win: CompatibilityWindow | undefined = typeof window === "undefined"
|
|
69
|
+
? undefined
|
|
70
|
+
: window,
|
|
71
|
+
): void {
|
|
72
|
+
if (!win?.location || !win.history) return;
|
|
73
|
+
const target = new URL(win.location.href);
|
|
74
|
+
if (!target.searchParams.has(BUILD_CACHE_BUSTER_PARAM)) return;
|
|
75
|
+
target.searchParams.delete(BUILD_CACHE_BUSTER_PARAM);
|
|
76
|
+
win.history.replaceState(win.history.state, "", target.href);
|
|
77
|
+
}
|
|
@@ -30,6 +30,11 @@ import type {
|
|
|
30
30
|
import { trackEvent } from "./analytics.js";
|
|
31
31
|
import { agentNativePath } from "./api-path.js";
|
|
32
32
|
import { getBrowserTabId } from "./browser-tab-id.js";
|
|
33
|
+
import {
|
|
34
|
+
clientBuildId,
|
|
35
|
+
clientCompatibilityVersion,
|
|
36
|
+
reloadForClientCompatibilityMismatch,
|
|
37
|
+
} from "./build-compatibility.js";
|
|
33
38
|
import { ensureEmbedAuthFetchInterceptor } from "./embed-auth.js";
|
|
34
39
|
|
|
35
40
|
const ACTION_PREFIX = agentNativePath("/_agent-native/actions");
|
|
@@ -281,6 +286,12 @@ async function performActionFetch<T>(
|
|
|
281
286
|
}
|
|
282
287
|
: {}),
|
|
283
288
|
};
|
|
289
|
+
const compatibilityVersion = clientCompatibilityVersion();
|
|
290
|
+
if (compatibilityVersion) {
|
|
291
|
+
headers["X-Agent-Native-Client-Compatibility"] = compatibilityVersion;
|
|
292
|
+
}
|
|
293
|
+
const buildId = clientBuildId();
|
|
294
|
+
if (buildId) headers["X-Agent-Native-Build-Id"] = buildId;
|
|
284
295
|
const tz = resolveUserTimezone();
|
|
285
296
|
if (tz) headers["x-user-timezone"] = tz;
|
|
286
297
|
const init: RequestInit = {
|
|
@@ -349,6 +360,26 @@ async function performActionFetch<T>(
|
|
|
349
360
|
throw new Error(`Action ${name} failed: ${cause}`);
|
|
350
361
|
}
|
|
351
362
|
|
|
363
|
+
if (
|
|
364
|
+
res.status === 409 &&
|
|
365
|
+
res.headers.get("X-Agent-Native-Client-Mismatch") === "1"
|
|
366
|
+
) {
|
|
367
|
+
const serverBuildId =
|
|
368
|
+
res.headers.get("X-Agent-Native-Build-Id") ?? "latest";
|
|
369
|
+
const requiredCompatibility =
|
|
370
|
+
res.headers.get("X-Agent-Native-Client-Compatibility") ?? "unknown";
|
|
371
|
+
reloadForClientCompatibilityMismatch(
|
|
372
|
+
serverBuildId,
|
|
373
|
+
requiredCompatibility,
|
|
374
|
+
);
|
|
375
|
+
const error = new Error(
|
|
376
|
+
`Action ${name} requires a refreshed browser client`,
|
|
377
|
+
);
|
|
378
|
+
(error as any).status = 409;
|
|
379
|
+
(error as any).code = "client_build_mismatch";
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
|
|
352
383
|
// 204 No Content — nothing to parse.
|
|
353
384
|
if (res.status === 204) return null as T;
|
|
354
385
|
|
|
@@ -760,7 +791,7 @@ export function useActionMutation<
|
|
|
760
791
|
if (!skipActionQueryInvalidation) {
|
|
761
792
|
queryClient.invalidateQueries({ queryKey: ["action"] });
|
|
762
793
|
}
|
|
763
|
-
(onSuccess as Function)?.(...args);
|
|
794
|
+
return (onSuccess as Function)?.(...args);
|
|
764
795
|
},
|
|
765
796
|
});
|
|
766
797
|
}
|
|
@@ -1240,7 +1240,7 @@ async function getHandler() {
|
|
|
1240
1240
|
headers: {
|
|
1241
1241
|
"Access-Control-Allow-Origin": "*",
|
|
1242
1242
|
"Access-Control-Allow-Methods": "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS",
|
|
1243
|
-
"Access-Control-Allow-Headers": "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Embed-Target",
|
|
1243
|
+
"Access-Control-Allow-Headers": "Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,X-Agent-Native-Embed-Target",
|
|
1244
1244
|
},
|
|
1245
1245
|
});
|
|
1246
1246
|
}
|
|
@@ -3479,6 +3479,9 @@ export default bundle;
|
|
|
3479
3479
|
"process.env.AGENT_NATIVE_BUILD_GA_MEASUREMENT_ID": JSON.stringify(
|
|
3480
3480
|
process.env.GA_MEASUREMENT_ID?.trim() || "",
|
|
3481
3481
|
),
|
|
3482
|
+
"process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT": JSON.stringify(
|
|
3483
|
+
process.env.CONTEXT?.trim() || "",
|
|
3484
|
+
),
|
|
3482
3485
|
},
|
|
3483
3486
|
// Replace browser-only renderers (Excalidraw/Mermaid) with an inert proxy in
|
|
3484
3487
|
// the server bundle. Without this, Nitro's Rolldown build pulls the real
|
|
@@ -41,7 +41,8 @@ const nanoid = (): string =>
|
|
|
41
41
|
/**
|
|
42
42
|
* Resolve the current user's organization context from their session.
|
|
43
43
|
*
|
|
44
|
-
* -
|
|
44
|
+
* - Honors the user's `active-org-id` setting, including an explicit Personal
|
|
45
|
+
* context represented by `{ orgId: null }`.
|
|
45
46
|
* - Falls back to the user's first membership.
|
|
46
47
|
* - When the authenticated user has zero memberships, provisions a default org
|
|
47
48
|
* named after the user ({name}'s workspace, falling back to the email
|
|
@@ -63,6 +64,34 @@ export async function getOrgContext(event: H3Event): Promise<OrgContext> {
|
|
|
63
64
|
type MembershipRow = { orgId: string; role: OrgRole; orgName: string };
|
|
64
65
|
|
|
65
66
|
const MEMBERSHIPS_CACHE_KEY = "__anOrgMembershipsCache";
|
|
67
|
+
const ACTIVE_ORG_SETTING_CACHE_KEY = "__anActiveOrgSettingCache";
|
|
68
|
+
|
|
69
|
+
type ActiveOrgSetting = { orgId: string | null } | null;
|
|
70
|
+
|
|
71
|
+
function loadActiveOrgSettingForEvent(
|
|
72
|
+
event: H3Event,
|
|
73
|
+
email: string,
|
|
74
|
+
): Promise<ActiveOrgSetting> {
|
|
75
|
+
const ctx = event.context as Record<string, unknown>;
|
|
76
|
+
const cache = ((ctx[ACTIVE_ORG_SETTING_CACHE_KEY] as
|
|
77
|
+
| Map<string, Promise<ActiveOrgSetting>>
|
|
78
|
+
| undefined) ??
|
|
79
|
+
(ctx[ACTIVE_ORG_SETTING_CACHE_KEY] = new Map<
|
|
80
|
+
string,
|
|
81
|
+
Promise<ActiveOrgSetting>
|
|
82
|
+
>())) as Map<string, Promise<ActiveOrgSetting>>;
|
|
83
|
+
const normalizedEmail = email.toLowerCase();
|
|
84
|
+
let promise = cache.get(normalizedEmail);
|
|
85
|
+
if (!promise) {
|
|
86
|
+
promise = getUserSetting(email, "active-org-id").then((value) => {
|
|
87
|
+
if (!value || !("orgId" in value)) return null;
|
|
88
|
+
if (value.orgId === null) return { orgId: null };
|
|
89
|
+
return typeof value.orgId === "string" ? { orgId: value.orgId } : null;
|
|
90
|
+
});
|
|
91
|
+
cache.set(normalizedEmail, promise);
|
|
92
|
+
}
|
|
93
|
+
return promise;
|
|
94
|
+
}
|
|
66
95
|
|
|
67
96
|
/**
|
|
68
97
|
* Per-request memoization of the org_members lookup, keyed by email on
|
|
@@ -128,32 +157,29 @@ async function resolveOrgContextUncached(event: H3Event): Promise<OrgContext> {
|
|
|
128
157
|
return { email, orgId: null, orgName: null, role: null };
|
|
129
158
|
}
|
|
130
159
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
const shouldTryDomainAutoJoin =
|
|
161
|
+
memberships.length === 0 ||
|
|
162
|
+
(memberships.length === 1 &&
|
|
163
|
+
isLikelyPersonalWorkspace(memberships[0], email, session));
|
|
164
|
+
const activeOrgSetting = await loadActiveOrgSettingForEvent(event, email);
|
|
165
|
+
if (activeOrgSetting?.orgId === null) {
|
|
166
|
+
return { email, orgId: null, orgName: null, role: null };
|
|
167
|
+
}
|
|
168
|
+
if (activeOrgSetting?.orgId) {
|
|
169
|
+
const active = memberships.find((m) => m.orgId === activeOrgSetting.orgId);
|
|
170
|
+
if (active && !shouldTryDomainAutoJoin) {
|
|
171
|
+
return {
|
|
172
|
+
email,
|
|
173
|
+
orgId: active.orgId,
|
|
174
|
+
orgName: active.orgName,
|
|
175
|
+
role: active.role,
|
|
176
|
+
};
|
|
147
177
|
}
|
|
148
178
|
}
|
|
149
179
|
|
|
150
180
|
const sessionMembership = sessionOrgId
|
|
151
181
|
? memberships.find((m) => m.orgId === sessionOrgId)
|
|
152
182
|
: null;
|
|
153
|
-
const shouldTryDomainAutoJoin =
|
|
154
|
-
memberships.length === 0 ||
|
|
155
|
-
(memberships.length === 1 &&
|
|
156
|
-
isLikelyPersonalWorkspace(memberships[0], email, session));
|
|
157
183
|
|
|
158
184
|
if (shouldTryDomainAutoJoin) {
|
|
159
185
|
const joined = await autoJoinDomainMatchingOrgs(email, {
|
|
@@ -248,7 +274,8 @@ async function loadMemberships(
|
|
|
248
274
|
/**
|
|
249
275
|
* Resolve the active org ID for a given email — for non-HTTP contexts like
|
|
250
276
|
* the integration webhook handler where we have an email but no event/session.
|
|
251
|
-
* Picks the user's active-org-id setting if set,
|
|
277
|
+
* Picks the user's active-org-id setting if set, including explicit Personal,
|
|
278
|
+
* otherwise the first membership.
|
|
252
279
|
* Returns null if the user has no memberships.
|
|
253
280
|
*/
|
|
254
281
|
export async function resolveOrgIdForEmail(
|
|
@@ -263,10 +290,11 @@ export async function resolveOrgIdForEmail(
|
|
|
263
290
|
});
|
|
264
291
|
if (rows.length === 0) return null;
|
|
265
292
|
const ids = rows.map((r: any) => String(r.org_id));
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
293
|
+
const activeOrgSetting = (await getUserSetting(
|
|
294
|
+
email,
|
|
295
|
+
"active-org-id",
|
|
296
|
+
)) as ActiveOrgSetting;
|
|
297
|
+
if (activeOrgSetting?.orgId === null) return null;
|
|
270
298
|
if (activeOrgSetting?.orgId && ids.includes(activeOrgSetting.orgId)) {
|
|
271
299
|
return activeOrgSetting.orgId;
|
|
272
300
|
}
|
|
@@ -291,10 +319,8 @@ export async function resolveOrgIdForEmailViaEvent(
|
|
|
291
319
|
if (!exec) return null;
|
|
292
320
|
const memberships = await loadMembershipsForEvent(event, exec, email);
|
|
293
321
|
if (!memberships || memberships.length === 0) return null;
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
orgId: string;
|
|
297
|
-
} | null;
|
|
322
|
+
const activeOrgSetting = await loadActiveOrgSettingForEvent(event, email);
|
|
323
|
+
if (activeOrgSetting?.orgId === null) return null;
|
|
298
324
|
if (
|
|
299
325
|
activeOrgSetting?.orgId &&
|
|
300
326
|
memberships.some((m) => m.orgId === activeOrgSetting.orgId)
|
|
@@ -30,6 +30,26 @@ import {
|
|
|
30
30
|
getAllowedCorsOrigin as resolveAllowedCorsOrigin,
|
|
31
31
|
readCorsAllowedOrigins,
|
|
32
32
|
} from "./cors-origins.js";
|
|
33
|
+
|
|
34
|
+
declare const __AGENT_NATIVE_BUILD_ID__: string | undefined;
|
|
35
|
+
declare const __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__: string | undefined;
|
|
36
|
+
|
|
37
|
+
function requiredClientCompatibilityVersion(): string {
|
|
38
|
+
const configured =
|
|
39
|
+
typeof __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__ === "string"
|
|
40
|
+
? __AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION__
|
|
41
|
+
: process.env.AGENT_NATIVE_CLIENT_COMPATIBILITY_VERSION;
|
|
42
|
+
return configured?.trim() ?? "";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function currentBuildId(): string {
|
|
46
|
+
const configured =
|
|
47
|
+
typeof __AGENT_NATIVE_BUILD_ID__ === "string"
|
|
48
|
+
? __AGENT_NATIVE_BUILD_ID__
|
|
49
|
+
: process.env.AGENT_NATIVE_BUILD_ID;
|
|
50
|
+
return configured?.trim() || "unknown";
|
|
51
|
+
}
|
|
52
|
+
|
|
33
53
|
/**
|
|
34
54
|
* Auto-mount actions as HTTP endpoints under /_agent-native/actions/:name.
|
|
35
55
|
*
|
|
@@ -187,8 +207,8 @@ function handleOptionsRequest(event: any): string {
|
|
|
187
207
|
event,
|
|
188
208
|
"Access-Control-Allow-Headers",
|
|
189
209
|
cors.credentials
|
|
190
|
-
? `Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,${EMBED_TARGET_HEADER}`
|
|
191
|
-
: `${MCP_EMBED_CORS_ALLOW_HEADERS},X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend`,
|
|
210
|
+
? `Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-User-Timezone,X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,${EMBED_TARGET_HEADER}`
|
|
211
|
+
: `${MCP_EMBED_CORS_ALLOW_HEADERS},X-Agent-Native-Tool-Bridge,X-Agent-Native-Tool-Id,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id`,
|
|
192
212
|
);
|
|
193
213
|
}
|
|
194
214
|
|
|
@@ -320,6 +340,11 @@ export function mountActionRoutes(
|
|
|
320
340
|
}
|
|
321
341
|
|
|
322
342
|
setResponseHeader(event, "Cache-Control", "no-store");
|
|
343
|
+
setResponseHeader(
|
|
344
|
+
event,
|
|
345
|
+
"Access-Control-Expose-Headers",
|
|
346
|
+
"X-Agent-Native-Client-Mismatch,X-Agent-Native-Build-Id,X-Agent-Native-Client-Compatibility",
|
|
347
|
+
);
|
|
323
348
|
|
|
324
349
|
// Allow the declared method
|
|
325
350
|
if (effectiveMethod !== method) {
|
|
@@ -327,6 +352,31 @@ export function mountActionRoutes(
|
|
|
327
352
|
return { error: `Method not allowed. Use ${method}.` };
|
|
328
353
|
}
|
|
329
354
|
|
|
355
|
+
const requiredCompatibility = requiredClientCompatibilityVersion();
|
|
356
|
+
if (isFrontendActionRequest(event) && requiredCompatibility) {
|
|
357
|
+
const receivedCompatibility = getHeader(
|
|
358
|
+
event,
|
|
359
|
+
"x-agent-native-client-compatibility",
|
|
360
|
+
);
|
|
361
|
+
if (receivedCompatibility !== requiredCompatibility) {
|
|
362
|
+
const serverBuildId = currentBuildId();
|
|
363
|
+
setResponseStatus(event, 409);
|
|
364
|
+
setResponseHeader(event, "X-Agent-Native-Client-Mismatch", "1");
|
|
365
|
+
setResponseHeader(event, "X-Agent-Native-Build-Id", serverBuildId);
|
|
366
|
+
setResponseHeader(
|
|
367
|
+
event,
|
|
368
|
+
"X-Agent-Native-Client-Compatibility",
|
|
369
|
+
requiredCompatibility,
|
|
370
|
+
);
|
|
371
|
+
return {
|
|
372
|
+
error: "This browser tab must reload before it can use this app.",
|
|
373
|
+
code: "client_build_mismatch",
|
|
374
|
+
serverBuildId,
|
|
375
|
+
requiredCompatibility,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
330
380
|
// (audit H5) Per-action `toolCallable` opt-out for the tools-iframe
|
|
331
381
|
// bridge. The bridge tags every outbound action call with
|
|
332
382
|
// X-Agent-Native-Tool-Bridge: 1. When that header is present and the
|
|
@@ -4,16 +4,21 @@ import {
|
|
|
4
4
|
getH3App,
|
|
5
5
|
awaitBootstrap,
|
|
6
6
|
markDefaultPluginProvided,
|
|
7
|
+
trackPluginInit,
|
|
7
8
|
} from "./framework-request-handler.js";
|
|
8
9
|
|
|
9
10
|
type NitroPluginDef = (nitroApp: any) => void | Promise<void>;
|
|
10
11
|
|
|
11
12
|
export function createAuthPlugin(options?: AuthOptions): NitroPluginDef {
|
|
12
|
-
return
|
|
13
|
+
return (nitroApp: any) => {
|
|
13
14
|
markDefaultPluginProvided(nitroApp, "auth");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const initPromise = (async () => {
|
|
16
|
+
await awaitBootstrap(nitroApp);
|
|
17
|
+
await autoMountAuth(getH3App(nitroApp), options);
|
|
18
|
+
})();
|
|
19
|
+
trackPluginInit(nitroApp, initPromise, {
|
|
20
|
+
paths: ["/_agent-native/auth"],
|
|
21
|
+
});
|
|
17
22
|
};
|
|
18
23
|
}
|
|
19
24
|
|
|
@@ -317,8 +317,12 @@ export function resolveSignupTrackingProperties(): Record<string, string> {
|
|
|
317
317
|
export function shouldSkipEmailVerification(): boolean {
|
|
318
318
|
const value = process.env.AUTH_SKIP_EMAIL_VERIFICATION;
|
|
319
319
|
if (value == null) {
|
|
320
|
+
const deployContext =
|
|
321
|
+
process.env.AGENT_NATIVE_BUILD_DEPLOY_CONTEXT || process.env.CONTEXT;
|
|
320
322
|
return (
|
|
321
|
-
process.env.NODE_ENV === "development" ||
|
|
323
|
+
process.env.NODE_ENV === "development" ||
|
|
324
|
+
process.env.NODE_ENV === "test" ||
|
|
325
|
+
deployContext === "deploy-preview"
|
|
322
326
|
);
|
|
323
327
|
}
|
|
324
328
|
const normalized = value.trim().toLowerCase();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const MCP_EMBED_CORS_ALLOW_HEADERS =
|
|
2
|
-
"Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-Agent-Native-Frontend,X-User-Timezone,X-Agent-Native-Embed-Target,X-Agent-Native-Embed-Transplant";
|
|
2
|
+
"Content-Type,Authorization,X-Requested-With,X-Request-Source,X-Agent-Native-CSRF,X-Agent-Native-Frontend,X-Agent-Native-Client-Compatibility,X-Agent-Native-Build-Id,X-User-Timezone,X-Agent-Native-Embed-Target,X-Agent-Native-Embed-Transplant";
|
|
3
3
|
export const EMBED_TRANSPLANT_HEADER = "x-agent-native-embed-transplant";
|
|
4
4
|
|
|
5
5
|
const CLAUDE_MCP_CONTENT_HOST_RE = /^[a-f0-9]{32}\.claudemcpcontent\.com$/i;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-native-toolkit
|
|
3
|
+
description: >-
|
|
4
|
+
Inventory and ownership rules for shared Agent Native workspace UI. Use
|
|
5
|
+
before building app chrome, settings, navigation, sharing, collaboration,
|
|
6
|
+
setup, history, comments, chat rails, agent UX, or repeated workspace behavior.
|
|
7
|
+
scope: dev
|
|
8
|
+
metadata:
|
|
9
|
+
internal: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Agent-Native Toolkit
|
|
13
|
+
|
|
14
|
+
Use this skill when deciding whether app chrome, settings, collaboration,
|
|
15
|
+
sharing, navigation, organization, setup, history, comments, or agent UX should
|
|
16
|
+
be built app-locally or moved into reusable framework/toolkit pieces.
|
|
17
|
+
|
|
18
|
+
## Core Rule
|
|
19
|
+
|
|
20
|
+
Apps own domain models, domain actions, and product-specific workflows. The
|
|
21
|
+
framework and `@agent-native/toolkit` own repeated workspace behavior users
|
|
22
|
+
expect to work the same everywhere.
|
|
23
|
+
|
|
24
|
+
Move behavior into shared toolkit primitives when it is:
|
|
25
|
+
|
|
26
|
+
- workspace-wide, such as settings, nav, search, org membership, or setup
|
|
27
|
+
- agent-visible, such as context, actions, run progress, or proof-of-done
|
|
28
|
+
- governed, such as secrets, permissions, sharing, audit, or billing
|
|
29
|
+
- repeated by two or more apps
|
|
30
|
+
- not tied to one domain model
|
|
31
|
+
|
|
32
|
+
Keep behavior app-local when the abstraction would hide important domain
|
|
33
|
+
language or make a simple app-specific workflow harder to understand.
|
|
34
|
+
|
|
35
|
+
## Discover Before Building
|
|
36
|
+
|
|
37
|
+
Before creating an app-local version of repeated workspace or agent UI:
|
|
38
|
+
|
|
39
|
+
1. Check the reusable kits below and the installed package documentation.
|
|
40
|
+
2. Search installed public components and source with `docs-search` and
|
|
41
|
+
`source-search`.
|
|
42
|
+
3. Run `agent-native eject --list` to see the version-matched units published
|
|
43
|
+
by the packages installed in this app.
|
|
44
|
+
4. Read `customizing-agent-native` and configure, compose, or eject the
|
|
45
|
+
smallest unit instead of recreating shared behavior from memory.
|
|
46
|
+
|
|
47
|
+
Use public package exports at runtime. Published source and ejection manifests
|
|
48
|
+
are discovery and ownership-transfer mechanisms, not private runtime APIs.
|
|
49
|
+
|
|
50
|
+
## Settings Direction
|
|
51
|
+
|
|
52
|
+
Durable settings belong in the Settings app or a registered settings route. The
|
|
53
|
+
agent sidebar should not become a second settings app. It can show contextual
|
|
54
|
+
quick controls and deep links such as:
|
|
55
|
+
|
|
56
|
+
- `/settings/ai`
|
|
57
|
+
- `/settings/connections`
|
|
58
|
+
- `/settings/secrets`
|
|
59
|
+
- `/settings/usage`
|
|
60
|
+
- `/settings/apps/:appId`
|
|
61
|
+
|
|
62
|
+
When adding a new API key, OAuth grant, provider connection, model selector, app
|
|
63
|
+
preference, notification preference, or usage/billing surface, register it as a
|
|
64
|
+
settings tab or app settings panel first. Only add sidebar UI when it is needed
|
|
65
|
+
in the moment of agent use.
|
|
66
|
+
|
|
67
|
+
## Reusable Kits
|
|
68
|
+
|
|
69
|
+
- **Settings kit**: a searchable settings page with account, workspace, AI
|
|
70
|
+
models, LLM keys, connections, secrets, usage, notifications, changelog, and
|
|
71
|
+
app-specific panels. Search is on by default; register a `SettingsSearchEntry`
|
|
72
|
+
per control so users find settings by name across tabs.
|
|
73
|
+
- **Collaboration kit**: Yjs docs, presence, agent presence, live cursors,
|
|
74
|
+
remote selections, recent edit highlights, real-time sync indicators, and
|
|
75
|
+
undo/redo grouping.
|
|
76
|
+
- **Sharing kit**: private/workspace/org/public-link access, invites, roles,
|
|
77
|
+
expirations, agent-readable links, and resource registration.
|
|
78
|
+
- **Navigation and command kit**: app shell, side nav, breadcrumbs, app switcher,
|
|
79
|
+
command palette entries, recent resources, pinned resources, and global search.
|
|
80
|
+
- **Organization kit**: folders, tags, favorites, archive, trash, ownership,
|
|
81
|
+
membership, and common resource metadata.
|
|
82
|
+
- **Setup and connections kit**: declarative setup requirements, model readiness,
|
|
83
|
+
missing-secret states, OAuth grants, and provider connection health.
|
|
84
|
+
- **Agent UX kit**: sidebar, composer, staged context, mentions, voice, human
|
|
85
|
+
approval, generative UI, progress, and screen-state exposure.
|
|
86
|
+
- **Chat history kit**: presentational chat lists and recent-chat rails belong
|
|
87
|
+
in Toolkit; Core keeps thread persistence, agent execution, transport, and
|
|
88
|
+
page-to-sidebar handoff. Apps inject routing, labels, and domain actions.
|
|
89
|
+
- **Agent page kit**: the full-page `/agent` surface (`AgentTabsPage` from
|
|
90
|
+
`@agent-native/core/client`) with Context, Files, Connections, Jobs, and
|
|
91
|
+
Access tabs plus a Personal/Organization scope toggle. The canonical home
|
|
92
|
+
for context transparency, MCP servers, A2A remote agents, recurring
|
|
93
|
+
jobs/automations, and external-client connect flows. See the `agent-page`
|
|
94
|
+
skill.
|
|
95
|
+
- **History and recovery kit**: audit log, activity feed, version history,
|
|
96
|
+
checkpoints, undo, redo, restore, and proof-of-done.
|
|
97
|
+
- **Comments and review kit**: anchored comments, pins, mentions, review
|
|
98
|
+
requests, resolved threads, agent follow-up tasks, and notifications.
|
|
99
|
+
- **Workflow and observability kit**: notifications, approvals, scheduled work,
|
|
100
|
+
background runs, recurring jobs, traces, evals, feedback, and run timelines.
|
|
101
|
+
|
|
102
|
+
## Implementation Checklist
|
|
103
|
+
|
|
104
|
+
When adding or refactoring one of these areas:
|
|
105
|
+
|
|
106
|
+
1. Search existing framework and template code for duplicated UI or actions.
|
|
107
|
+
2. Decide the shared contract: data shape, action API, React component/hook, and
|
|
108
|
+
app adapter points.
|
|
109
|
+
3. Keep shared data provider-agnostic and scoped by auth/sharing rules.
|
|
110
|
+
4. Expose the same capability to the UI and agent through actions or documented
|
|
111
|
+
client helpers.
|
|
112
|
+
5. Register app-specific labels, routes, resource adapters, and settings panels
|
|
113
|
+
instead of hardcoding app names in core UI.
|
|
114
|
+
6. Update docs and relevant skills so future apps discover the shared path.
|
|
115
|
+
7. Keep the component easy to adopt piecemeal: expose props/slots first and
|
|
116
|
+
ship readable source plus a complete ejection unit so apps can take ownership
|
|
117
|
+
of the smallest feature when needed. See `customizing-agent-native` for the
|
|
118
|
+
configure → compose → eject → propose seam ladder.
|
|
119
|
+
|
|
120
|
+
## Related Skills
|
|
121
|
+
|
|
122
|
+
Read these alongside this skill when the work touches the specific area:
|
|
123
|
+
|
|
124
|
+
- `sharing`
|
|
125
|
+
- `real-time-collab`
|
|
126
|
+
- `real-time-sync`
|
|
127
|
+
- `client-side-routing`
|
|
128
|
+
- `context-awareness`
|
|
129
|
+
- `onboarding`
|
|
130
|
+
- `secrets`
|
|
131
|
+
- `audit-log`
|
|
132
|
+
- `observability`
|
|
133
|
+
- `frontend-design`
|