@agent-native/core 0.119.6 → 0.120.1
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/core/CHANGELOG.md +19 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/index.ts +64 -3
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +45 -0
- package/corpus/core/src/client/use-chat-models.ts +45 -0
- package/corpus/core/src/server/analytics.ts +15 -0
- package/corpus/core/src/server/auth.ts +17 -13
- package/corpus/core/src/server/better-auth-instance.ts +13 -1
- package/corpus/core/src/templates/default/package.json +1 -1
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/assets/changelog/2026-07-23-new-chat-aligns-with-sidebar-controls.md +6 -0
- package/corpus/templates/assets/package.json +1 -1
- package/corpus/templates/brain/package.json +1 -1
- package/corpus/templates/calendar/package.json +1 -1
- package/corpus/templates/clips/package.json +1 -1
- package/corpus/templates/content/actions/add-database-item.ts +1 -0
- package/corpus/templates/content/actions/set-document-property.ts +0 -4
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +10 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +10 -4
- package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +5 -1
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +6 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +52 -33
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +16 -4
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +16 -7
- package/corpus/templates/content/app/hooks/use-create-page.ts +8 -3
- package/corpus/templates/content/app/hooks/use-document-properties.ts +1 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +3 -1
- package/corpus/templates/content/app/lib/optimistic-document.ts +29 -0
- package/corpus/templates/content/changelog/2026-07-21-editing-a-database-property-no-longer-refreshes-unrelated-co.md +6 -0
- package/corpus/templates/content/changelog/2026-07-23-new-database-ready.md +6 -0
- package/corpus/templates/content/package.json +1 -1
- package/corpus/templates/content/shared/api.ts +1 -0
- package/corpus/templates/design/package.json +1 -1
- package/corpus/templates/dispatch/package.json +1 -1
- package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +9 -3
- package/corpus/templates/forms/AGENTS.md +11 -1
- package/corpus/templates/forms/README.md +24 -1
- package/corpus/templates/forms/actions/update-form.ts +12 -5
- package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +199 -1
- package/corpus/templates/forms/app/i18n/en-US.ts +13 -1
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +35 -4
- package/corpus/templates/forms/app/pages/FormFillPage.tsx +7 -16
- package/corpus/templates/forms/changelog/2026-07-23-forms-can-branch-into-follow-up-questions-and-route-response.md +6 -0
- package/corpus/templates/forms/package.json +1 -1
- package/corpus/templates/forms/server/handlers/submissions.ts +22 -31
- package/corpus/templates/forms/server/lib/integrations.ts +11 -2
- package/corpus/templates/forms/server/lib/public-form-ssr.ts +26 -5
- package/corpus/templates/forms/server/lib/validate-fields.ts +48 -11
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/forms/shared/conditional.ts +67 -0
- package/corpus/templates/macros/package.json +1 -1
- package/corpus/templates/mail/package.json +1 -1
- package/corpus/templates/slides/package.json +1 -1
- package/dist/cli/index.js +53 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +35 -0
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/use-chat-models.d.ts +1 -0
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +33 -0
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
- package/dist/provider-api/actions/provider-api.d.ts +9 -9
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/analytics.d.ts +8 -0
- package/dist/server/analytics.d.ts.map +1 -1
- package/dist/server/analytics.js +16 -0
- package/dist/server/analytics.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +5 -4
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +8 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +10 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/default/package.json +1 -1
- package/package.json +1 -1
- package/src/cli/index.ts +64 -3
- package/src/client/MultiTabAssistantChat.tsx +45 -0
- package/src/client/use-chat-models.ts +45 -0
- package/src/server/analytics.ts +15 -0
- package/src/server/auth.ts +17 -13
- package/src/server/better-auth-instance.ts +13 -1
- package/src/templates/default/package.json +1 -1
|
@@ -56,6 +56,7 @@ import { isTrustedFrameMessage } from "./frame.js";
|
|
|
56
56
|
import { RunStuckBanner } from "./RunStuckBanner.js";
|
|
57
57
|
import { callAction } from "./use-action.js";
|
|
58
58
|
import { useChangeVersion } from "./use-change-version.js";
|
|
59
|
+
import { CHAT_MODEL_SELECTION_CHANGED_EVENT } from "./use-chat-models.js";
|
|
59
60
|
import {
|
|
60
61
|
useChatThreads,
|
|
61
62
|
type ChatThreadScope,
|
|
@@ -138,6 +139,13 @@ function writeStoredModelSelection(key: string, selection: ModelSelection) {
|
|
|
138
139
|
if (typeof window === "undefined") return;
|
|
139
140
|
try {
|
|
140
141
|
window.localStorage.setItem(key, JSON.stringify(selection));
|
|
142
|
+
queueMicrotask(() => {
|
|
143
|
+
window.dispatchEvent(
|
|
144
|
+
new CustomEvent(CHAT_MODEL_SELECTION_CHANGED_EVENT, {
|
|
145
|
+
detail: { key },
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
148
|
+
});
|
|
141
149
|
} catch {}
|
|
142
150
|
}
|
|
143
151
|
|
|
@@ -954,6 +962,43 @@ export function MultiTabAssistantChat({
|
|
|
954
962
|
const bumpModelSelectionVersion = useCallback(() => {
|
|
955
963
|
setModelSelectionVersion((version) => version + 1);
|
|
956
964
|
}, []);
|
|
965
|
+
|
|
966
|
+
useEffect(() => {
|
|
967
|
+
if (typeof window === "undefined") return;
|
|
968
|
+
|
|
969
|
+
const syncPersistedSelection = (event?: Event) => {
|
|
970
|
+
const detail = (event as CustomEvent<{ key?: string }> | undefined)
|
|
971
|
+
?.detail;
|
|
972
|
+
if (detail?.key && detail.key !== modelSelectionKey) return;
|
|
973
|
+
|
|
974
|
+
const next = readStoredModelSelection(modelSelectionKey);
|
|
975
|
+
if (!next) return;
|
|
976
|
+
|
|
977
|
+
const activeThreadId = activeThreadIdRef.current;
|
|
978
|
+
if (activeThreadId) {
|
|
979
|
+
threadModelRef.current.set(activeThreadId, next);
|
|
980
|
+
}
|
|
981
|
+
setPersistedModelSelection(next);
|
|
982
|
+
bumpModelSelectionVersion();
|
|
983
|
+
};
|
|
984
|
+
const handleStorage = (event: StorageEvent) => {
|
|
985
|
+
if (event.key === modelSelectionKey) syncPersistedSelection();
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
window.addEventListener(
|
|
989
|
+
CHAT_MODEL_SELECTION_CHANGED_EVENT,
|
|
990
|
+
syncPersistedSelection,
|
|
991
|
+
);
|
|
992
|
+
window.addEventListener("storage", handleStorage);
|
|
993
|
+
return () => {
|
|
994
|
+
window.removeEventListener(
|
|
995
|
+
CHAT_MODEL_SELECTION_CHANGED_EVENT,
|
|
996
|
+
syncPersistedSelection,
|
|
997
|
+
);
|
|
998
|
+
window.removeEventListener("storage", handleStorage);
|
|
999
|
+
};
|
|
1000
|
+
}, [bumpModelSelectionVersion, modelSelectionKey]);
|
|
1001
|
+
|
|
957
1002
|
const postMessageSubmissionsDisabled = props.composerDisabled === true;
|
|
958
1003
|
|
|
959
1004
|
const setContextInTab = useCallback(
|
|
@@ -42,6 +42,8 @@ interface Options {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const DEFAULT_STORAGE_KEY = "agent-native:chat-models:selection";
|
|
45
|
+
export const CHAT_MODEL_SELECTION_CHANGED_EVENT =
|
|
46
|
+
"agent-native:chat-model-selection-changed";
|
|
45
47
|
|
|
46
48
|
interface PersistedSelection {
|
|
47
49
|
model?: string;
|
|
@@ -63,6 +65,13 @@ function writePersisted(key: string | null, value: PersistedSelection) {
|
|
|
63
65
|
if (!key || typeof window === "undefined") return;
|
|
64
66
|
try {
|
|
65
67
|
window.localStorage.setItem(key, JSON.stringify(value));
|
|
68
|
+
queueMicrotask(() => {
|
|
69
|
+
window.dispatchEvent(
|
|
70
|
+
new CustomEvent(CHAT_MODEL_SELECTION_CHANGED_EVENT, {
|
|
71
|
+
detail: { key },
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
});
|
|
66
75
|
} catch {}
|
|
67
76
|
}
|
|
68
77
|
|
|
@@ -110,6 +119,42 @@ export function useChatModels({
|
|
|
110
119
|
};
|
|
111
120
|
}, [selectedEffort, selectedEngine, selectedModel]);
|
|
112
121
|
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (!storageKey || typeof window === "undefined") return;
|
|
124
|
+
|
|
125
|
+
const syncPersistedSelection = (event?: Event) => {
|
|
126
|
+
const detail = (event as CustomEvent<{ key?: string }> | undefined)
|
|
127
|
+
?.detail;
|
|
128
|
+
if (detail?.key && detail.key !== storageKey) return;
|
|
129
|
+
|
|
130
|
+
const next = readPersisted(storageKey);
|
|
131
|
+
if (!next.model) return;
|
|
132
|
+
|
|
133
|
+
hasExplicitSelectionRef.current = true;
|
|
134
|
+
setSelectedModel(next.model);
|
|
135
|
+
setSelectedEngine(next.engine ?? "");
|
|
136
|
+
setSelectedEffort(
|
|
137
|
+
resolveReasoningEffortSelection(next.model, next.effort),
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
const handleStorage = (event: StorageEvent) => {
|
|
141
|
+
if (event.key === storageKey) syncPersistedSelection();
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
window.addEventListener(
|
|
145
|
+
CHAT_MODEL_SELECTION_CHANGED_EVENT,
|
|
146
|
+
syncPersistedSelection,
|
|
147
|
+
);
|
|
148
|
+
window.addEventListener("storage", handleStorage);
|
|
149
|
+
return () => {
|
|
150
|
+
window.removeEventListener(
|
|
151
|
+
CHAT_MODEL_SELECTION_CHANGED_EVENT,
|
|
152
|
+
syncPersistedSelection,
|
|
153
|
+
);
|
|
154
|
+
window.removeEventListener("storage", handleStorage);
|
|
155
|
+
};
|
|
156
|
+
}, [storageKey]);
|
|
157
|
+
|
|
113
158
|
const onModelChange = useCallback(
|
|
114
159
|
(model: string, engine: string) => {
|
|
115
160
|
hasExplicitSelectionRef.current = true;
|
package/src/server/analytics.ts
CHANGED
|
@@ -74,6 +74,21 @@ function getGaScript(): string | null {
|
|
|
74
74
|
);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Add the configured analytics scripts to a complete HTML document.
|
|
79
|
+
*
|
|
80
|
+
* The normal app document is streamed through `wrapWithAnalytics`, but
|
|
81
|
+
* framework-owned documents such as `/signup` are returned as strings by the
|
|
82
|
+
* auth guard and need the same injection path.
|
|
83
|
+
*/
|
|
84
|
+
export function injectAnalyticsIntoHtml(html: string): string {
|
|
85
|
+
const script = getGaScript();
|
|
86
|
+
if (!script) return html;
|
|
87
|
+
const headCloseIdx = html.indexOf("</head>");
|
|
88
|
+
if (headCloseIdx === -1) return html;
|
|
89
|
+
return html.slice(0, headCloseIdx) + script + html.slice(headCloseIdx);
|
|
90
|
+
}
|
|
91
|
+
|
|
77
92
|
export function wrapWithAnalytics(body: ReadableStream): ReadableStream {
|
|
78
93
|
const scripts = [getGaScript()].filter(Boolean).join("");
|
|
79
94
|
if (!scripts) return body;
|
package/src/server/auth.ts
CHANGED
|
@@ -98,6 +98,7 @@ import {
|
|
|
98
98
|
type WorkspaceAppAudience,
|
|
99
99
|
} from "../shared/workspace-app-audience.js";
|
|
100
100
|
import { isValidWorkspaceAppIdFormat } from "../shared/workspace-app-id.js";
|
|
101
|
+
import { injectAnalyticsIntoHtml } from "./analytics.js";
|
|
101
102
|
import { signupAttributionFromCookieHeader } from "./attribution.js";
|
|
102
103
|
import { getBetterAuth, getBetterAuthSync } from "./better-auth-instance.js";
|
|
103
104
|
import type { BetterAuthConfig } from "./better-auth-instance.js";
|
|
@@ -1646,20 +1647,23 @@ function injectLoginSocialImageMeta(loginHtml: string, event: H3Event): string {
|
|
|
1646
1647
|
}
|
|
1647
1648
|
|
|
1648
1649
|
function loginHtmlResponse(loginHtml: string, event: H3Event): Response {
|
|
1649
|
-
return new Response(
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1650
|
+
return new Response(
|
|
1651
|
+
injectAnalyticsIntoHtml(injectLoginSocialImageMeta(loginHtml, event)),
|
|
1652
|
+
{
|
|
1653
|
+
status: 200,
|
|
1654
|
+
headers: {
|
|
1655
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
1656
|
+
// The sign-in document is part of the public server shell. Keep it on the
|
|
1657
|
+
// same long-fresh/long-SWR CDN policy as React Router SSR so hosted
|
|
1658
|
+
// template roots do not invoke origin just to render anonymous login UI.
|
|
1659
|
+
// The login markup is env-INDEPENDENT (a Google-only app always renders
|
|
1660
|
+
// a working button); the analytics script is public build configuration,
|
|
1661
|
+
// not user/session state. Never downgrade this to private/no-store.
|
|
1662
|
+
...DEFAULT_SSR_CACHE_HEADERS,
|
|
1663
|
+
"X-Robots-Tag": "noindex, nofollow",
|
|
1664
|
+
},
|
|
1661
1665
|
},
|
|
1662
|
-
|
|
1666
|
+
);
|
|
1663
1667
|
}
|
|
1664
1668
|
|
|
1665
1669
|
function isHtmlDocumentRequest(event: H3Event, pathname: string): boolean {
|
|
@@ -1109,6 +1109,18 @@ async function createBetterAuthInstance(
|
|
|
1109
1109
|
return auth as unknown as BetterAuthInstance;
|
|
1110
1110
|
}
|
|
1111
1111
|
|
|
1112
|
+
/**
|
|
1113
|
+
* Configure the local auth connection with the same write contention settings
|
|
1114
|
+
* as the shared app connection. Better Auth uses its own SQLite handle, so the
|
|
1115
|
+
* app connection's busy timeout does not protect first-run account creation.
|
|
1116
|
+
*/
|
|
1117
|
+
export function configureLocalSqlite(sqlite: {
|
|
1118
|
+
pragma(statement: string): unknown;
|
|
1119
|
+
}): void {
|
|
1120
|
+
sqlite.pragma("busy_timeout = 10000");
|
|
1121
|
+
sqlite.pragma("journal_mode = WAL");
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1112
1124
|
async function buildDatabaseConfig(
|
|
1113
1125
|
dialect: string,
|
|
1114
1126
|
): Promise<BetterAuthOptions["database"]> {
|
|
@@ -1182,7 +1194,7 @@ async function buildDatabaseConfig(
|
|
|
1182
1194
|
const { default: Database } = await import("better-sqlite3");
|
|
1183
1195
|
const filePath = url.replace(/^file:/, "");
|
|
1184
1196
|
const sqlite = new Database(filePath);
|
|
1185
|
-
sqlite
|
|
1197
|
+
configureLocalSqlite(sqlite);
|
|
1186
1198
|
const { drizzle } = await import("drizzle-orm/better-sqlite3");
|
|
1187
1199
|
const db = drizzle(sqlite, { schema: sqliteAuthSchema });
|
|
1188
1200
|
const { drizzleAdapter } = await import("better-auth/adapters/drizzle");
|