@agent-native/core 0.167.1 → 0.168.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/brain/actions/list-sources.ts +17 -7
- package/corpus/templates/brain/app/components/brain/Surface.tsx +4 -2
- package/corpus/templates/brain/app/lib/brain.ts +13 -3
- package/corpus/templates/brain/server/lib/brain-health.ts +5 -8
- package/corpus/templates/brain/server/lib/brain.ts +1 -0
- package/corpus/templates/brain/server/lib/capture-sanitization.ts +5 -0
- package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +3 -2
- package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/clips/app/routes/download.tsx +78 -131
- package/corpus/templates/clips/desktop/src/app.tsx +11 -10
- package/corpus/templates/clips/desktop/src/lib/desktop-oauth-window.ts +23 -0
- package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/dist/chat-threads/store.d.ts +7 -0
- package/dist/chat-threads/store.js +15 -0
- package/dist/client/AboutAgentNativeDialog.d.ts +5 -0
- package/dist/client/AboutAgentNativeDialog.js +56 -0
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +8 -8
- package/dist/client/AssistantChat.d.ts +3 -1
- package/dist/client/AssistantChat.js +22 -6
- package/dist/client/CommandMenu.d.ts +6 -1
- package/dist/client/CommandMenu.js +46 -3
- package/dist/client/EnvironmentBadge.js +4 -1
- package/dist/client/MultiTabAssistantChat.d.ts +3 -1
- package/dist/client/MultiTabAssistantChat.js +5 -4
- package/dist/client/agent-native-version.d.ts +12 -0
- package/dist/client/agent-native-version.js +36 -0
- package/dist/client/agent-page/AgentJobsTab.js +39 -6
- package/dist/client/agent-page/AutomationScheduleDialog.d.ts +10 -1
- package/dist/client/agent-page/AutomationScheduleDialog.js +3 -2
- package/dist/client/agent-page/ScheduledTriggerNotice.d.ts +22 -0
- package/dist/client/agent-page/ScheduledTriggerNotice.js +84 -0
- package/dist/client/agent-page/scheduled-trigger-state.d.ts +28 -0
- package/dist/client/agent-page/scheduled-trigger-state.js +10 -0
- package/dist/client/agent-page/use-jobs.d.ts +7 -0
- package/dist/client/agent-page/use-jobs.js +14 -0
- package/dist/client/blocks/library/diagram.config.d.ts +4 -1
- package/dist/client/blocks/library/diagram.js +1 -1
- package/dist/client/chat/run-recovery.js +15 -7
- package/dist/client/use-chat-threads.d.ts +7 -0
- package/dist/client/use-chat-threads.js +144 -40
- package/dist/collab/routes.d.ts +1 -1
- package/dist/config.d.ts +3 -1
- package/dist/config.js +14 -9
- package/dist/deploy/build.d.ts +5 -0
- package/dist/deploy/build.js +12 -1
- package/dist/framework-tools.js +1 -0
- package/dist/jobs/actions/get-scheduled-trigger-status.d.ts +13 -0
- package/dist/jobs/actions/get-scheduled-trigger-status.js +21 -0
- package/dist/localization/core-messages/ar-SA.js +6 -0
- package/dist/localization/core-messages/de-DE.js +6 -0
- package/dist/localization/core-messages/en-US.d.ts +6 -0
- package/dist/localization/core-messages/en-US.js +6 -0
- package/dist/localization/core-messages/es-ES.js +6 -0
- package/dist/localization/core-messages/fr-FR.js +6 -0
- package/dist/localization/core-messages/hi-IN.js +6 -0
- package/dist/localization/core-messages/ja-JP.js +6 -0
- package/dist/localization/core-messages/ko-KR.js +6 -0
- package/dist/localization/core-messages/pt-BR.js +6 -0
- package/dist/localization/core-messages/zh-CN.js +6 -0
- package/dist/localization/core-messages/zh-TW.js +6 -0
- package/dist/localization/core-messages.d.ts +6 -0
- package/dist/localization/default-messages.d.ts +14 -0
- package/dist/localization/default-messages.js +14 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/actions/custom-provider-registration.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/action-discovery.js +4 -0
- package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +42 -1
- package/dist/server/agent-chat/recurring-jobs-runtime.js +102 -9
- package/dist/server/agent-chat-plugin.d.ts +3 -1
- package/dist/server/agent-chat-plugin.js +115 -24
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/attribution.d.ts +29 -0
- package/dist/server/attribution.js +68 -0
- package/dist/server/auth.js +58 -15
- package/dist/server/better-auth-instance.js +16 -4
- package/dist/server/identity-sso.js +14 -2
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/request-context.d.ts +8 -0
- package/dist/server/request-context.js +4 -0
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/dist/vite/agent-native-config-loader.js +1 -1
- package/dist/vite/client.js +19 -8
- package/dist/vite/package-versions.d.ts +1 -0
- package/dist/vite/package-versions.js +97 -0
- package/docs/content/agent-native-config.mdx +55 -31
- package/docs/content/deployment.mdx +3 -1
- package/docs/content/environment-variables.mdx +51 -14
- package/docs/content/recurring-jobs.mdx +6 -0
- package/package.json +2 -2
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +11 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +11 -0
package/corpus/README.md
CHANGED
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|
|
@@ -6,6 +6,7 @@ import { z } from "zod";
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
7
|
import { nextBrainSourceSyncAt } from "../server/jobs/sync-sources.js";
|
|
8
8
|
import { listAccessibleAudienceIds } from "../server/lib/audiences.js";
|
|
9
|
+
import { sourceHealthState } from "../server/lib/brain-health.js";
|
|
9
10
|
import { parseJson, serializeSource } from "../server/lib/brain.js";
|
|
10
11
|
import { sourceProviderSchema } from "./_schemas.js";
|
|
11
12
|
|
|
@@ -71,14 +72,23 @@ export default defineAction({
|
|
|
71
72
|
.from(schema.brainSources)
|
|
72
73
|
.where(and(...clauses))
|
|
73
74
|
.orderBy(desc(schema.brainSources.updatedAt));
|
|
75
|
+
const nowMs = Date.now();
|
|
74
76
|
const sources = await Promise.all(
|
|
75
|
-
rows.map(async (row) =>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
rows.map(async (row) => {
|
|
78
|
+
const latest = await latestRun(row.id);
|
|
79
|
+
const nextSyncAt = nextBrainSourceSyncAt(row);
|
|
80
|
+
return {
|
|
81
|
+
...serializeSource(row),
|
|
82
|
+
recordCount: await sourceRecordCount(row.id),
|
|
83
|
+
latestRun: latest,
|
|
84
|
+
nextSyncAt,
|
|
85
|
+
health: sourceHealthState(row, latest, nextSyncAt, nowMs),
|
|
86
|
+
};
|
|
87
|
+
}),
|
|
81
88
|
);
|
|
82
|
-
return {
|
|
89
|
+
return {
|
|
90
|
+
count: rows.length,
|
|
91
|
+
sources,
|
|
92
|
+
};
|
|
83
93
|
},
|
|
84
94
|
});
|
|
@@ -117,7 +117,8 @@ export function StatusBadge({ status }: { status: string }) {
|
|
|
117
117
|
? IconCircleCheck
|
|
118
118
|
: normalized.includes("review") ||
|
|
119
119
|
normalized.includes("degraded") ||
|
|
120
|
-
normalized.includes("stale")
|
|
120
|
+
normalized.includes("stale") ||
|
|
121
|
+
normalized.includes("needs")
|
|
121
122
|
? IconClock
|
|
122
123
|
: normalized.includes("error")
|
|
123
124
|
? IconAlertTriangle
|
|
@@ -132,7 +133,8 @@ export function StatusBadge({ status }: { status: string }) {
|
|
|
132
133
|
"border-border bg-secondary text-secondary-foreground",
|
|
133
134
|
(normalized.includes("review") ||
|
|
134
135
|
normalized.includes("degraded") ||
|
|
135
|
-
normalized.includes("stale")
|
|
136
|
+
normalized.includes("stale") ||
|
|
137
|
+
normalized.includes("needs")) &&
|
|
136
138
|
"border-amber-500/35 bg-amber-500/10 text-amber-700 dark:text-amber-300",
|
|
137
139
|
normalized.includes("error") &&
|
|
138
140
|
"border-destructive/35 bg-destructive/10 text-destructive",
|
|
@@ -20,7 +20,14 @@ export type BrainView =
|
|
|
20
20
|
| "settings";
|
|
21
21
|
|
|
22
22
|
export type KnowledgeStatus = "approved" | "needs_review" | "draft" | "stale";
|
|
23
|
-
export type SourceHealth =
|
|
23
|
+
export type SourceHealth =
|
|
24
|
+
| "healthy"
|
|
25
|
+
| "needs_setup"
|
|
26
|
+
| "needs_sync"
|
|
27
|
+
| "stale"
|
|
28
|
+
| "degraded"
|
|
29
|
+
| "paused"
|
|
30
|
+
| "error";
|
|
24
31
|
export type ReviewPriority = "high" | "medium" | "low";
|
|
25
32
|
|
|
26
33
|
export interface Citation {
|
|
@@ -1144,8 +1151,11 @@ export function sourceDescription(source: BrainSource) {
|
|
|
1144
1151
|
export function sourceHealth(source: BrainSource): SourceHealth {
|
|
1145
1152
|
if (source.health) return source.health;
|
|
1146
1153
|
if (sourceRetryAfter(source)) return "degraded";
|
|
1147
|
-
if (source.status === "active")
|
|
1148
|
-
|
|
1154
|
+
if (source.status === "active") {
|
|
1155
|
+
if (source.lastError) return "degraded";
|
|
1156
|
+
if (sourceAutoSync(source) && !source.lastSyncedAt) return "needs_sync";
|
|
1157
|
+
return "healthy";
|
|
1158
|
+
}
|
|
1149
1159
|
if (source.status === "error") return "error";
|
|
1150
1160
|
if (source.status === "paused" || source.status === "archived")
|
|
1151
1161
|
return "paused";
|
|
@@ -189,9 +189,9 @@ function latestIso(values: Array<string | null | undefined>) {
|
|
|
189
189
|
return latest;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
function sourceHealthState(
|
|
192
|
+
export function sourceHealthState(
|
|
193
193
|
source: SourceRow,
|
|
194
|
-
latestRun: SyncRunRow | null,
|
|
194
|
+
latestRun: Pick<SyncRunRow, "status"> | null,
|
|
195
195
|
nextSyncAt: string | null,
|
|
196
196
|
nowMs: number,
|
|
197
197
|
): BrainSourceHealthState {
|
|
@@ -530,12 +530,9 @@ export async function readBrainHealth() {
|
|
|
530
530
|
};
|
|
531
531
|
});
|
|
532
532
|
|
|
533
|
-
const sourceHealthCounts = countStatuses<
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
...sourceSummaries.map((source) => ({ status: source.health })),
|
|
537
|
-
...sourceRows.map((source) => ({ status: source.status })),
|
|
538
|
-
]);
|
|
533
|
+
const sourceHealthCounts = countStatuses<BrainSourceHealthState>(
|
|
534
|
+
sourceSummaries.map((source) => ({ status: source.health })),
|
|
535
|
+
);
|
|
539
536
|
const captureCounts = countStatuses(captureRows);
|
|
540
537
|
const captureDispositionCounts = countStatuses(
|
|
541
538
|
captureRows.map((capture) => ({
|
|
@@ -755,6 +755,7 @@ export async function createCapture(values: {
|
|
|
755
755
|
title: source.title,
|
|
756
756
|
provider: source.provider as BrainSourceProvider,
|
|
757
757
|
ownerEmail: source.ownerEmail,
|
|
758
|
+
orgId: source.orgId,
|
|
758
759
|
},
|
|
759
760
|
sourceConfig: parseJson<Record<string, unknown>>(source.configJson, {}),
|
|
760
761
|
settings,
|
|
@@ -71,6 +71,7 @@ export interface CaptureSanitizationInput {
|
|
|
71
71
|
title: string;
|
|
72
72
|
provider: BrainSourceProvider;
|
|
73
73
|
ownerEmail: string;
|
|
74
|
+
orgId?: string | null;
|
|
74
75
|
};
|
|
75
76
|
sourceConfig?: Record<string, unknown>;
|
|
76
77
|
settings: BrainSettings;
|
|
@@ -440,6 +441,10 @@ async function classifyWithApprovedModel(
|
|
|
440
441
|
apiKeyEnvVar: userApiKey.apiKeyEnvVar,
|
|
441
442
|
appId: "brain",
|
|
442
443
|
engineOption: engineName,
|
|
444
|
+
credentialIdentity: {
|
|
445
|
+
userEmail: input.source.ownerEmail,
|
|
446
|
+
orgId: input.source.orgId ?? undefined,
|
|
447
|
+
},
|
|
443
448
|
});
|
|
444
449
|
|
|
445
450
|
const maxChars = Math.min(
|
|
@@ -10,7 +10,8 @@ declare global {
|
|
|
10
10
|
var __AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__: boolean | undefined;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const BRAIN_QUEUE_SWEEP_LIMIT =
|
|
13
|
+
export const BRAIN_QUEUE_SWEEP_LIMIT = 25;
|
|
14
|
+
export const BRAIN_MAX_DISTILLATIONS_PER_SWEEP = 2;
|
|
14
15
|
|
|
15
16
|
function productionLike() {
|
|
16
17
|
return (
|
|
@@ -53,7 +54,7 @@ export default defineEventHandler(async (event) => {
|
|
|
53
54
|
processBrainIngestQueueOnce({
|
|
54
55
|
limit: BRAIN_QUEUE_SWEEP_LIMIT,
|
|
55
56
|
runDistillation: true,
|
|
56
|
-
maxDistillations:
|
|
57
|
+
maxDistillations: BRAIN_MAX_DISTILLATIONS_PER_SWEEP,
|
|
57
58
|
}),
|
|
58
59
|
expireSensitivityQuarantines(),
|
|
59
60
|
]);
|
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|
|
@@ -4,20 +4,12 @@ import {
|
|
|
4
4
|
IconBrandChrome,
|
|
5
5
|
IconBrandApple,
|
|
6
6
|
IconBrandWindows,
|
|
7
|
-
IconChevronDown,
|
|
8
|
-
IconDeviceDesktop,
|
|
9
7
|
IconExternalLink,
|
|
8
|
+
IconTerminal2,
|
|
10
9
|
} from "@tabler/icons-react";
|
|
11
10
|
import { useEffect, useState } from "react";
|
|
12
11
|
|
|
13
12
|
import { Button } from "@/components/ui/button";
|
|
14
|
-
import {
|
|
15
|
-
DropdownMenu,
|
|
16
|
-
DropdownMenuContent,
|
|
17
|
-
DropdownMenuRadioGroup,
|
|
18
|
-
DropdownMenuRadioItem,
|
|
19
|
-
DropdownMenuTrigger,
|
|
20
|
-
} from "@/components/ui/dropdown-menu";
|
|
21
13
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
22
14
|
import enMessages from "@/i18n/en-US";
|
|
23
15
|
import {
|
|
@@ -45,7 +37,6 @@ type PlatformId = "mac" | "windows" | "linux";
|
|
|
45
37
|
interface PlatformVariant {
|
|
46
38
|
id: PlatformId;
|
|
47
39
|
label: string;
|
|
48
|
-
sublabel: string;
|
|
49
40
|
assetKinds: readonly (
|
|
50
41
|
| "mac-universal"
|
|
51
42
|
| "mac-arm64"
|
|
@@ -64,23 +55,20 @@ const VARIANTS: PlatformVariant[] = [
|
|
|
64
55
|
{
|
|
65
56
|
id: "mac",
|
|
66
57
|
label: "macOS",
|
|
67
|
-
sublabel: "Universal (Apple Silicon + Intel)",
|
|
68
58
|
assetKinds: ["mac-universal", "mac-arm64", "mac-x64"],
|
|
69
59
|
icon: IconBrandApple,
|
|
70
60
|
},
|
|
71
61
|
{
|
|
72
62
|
id: "windows",
|
|
73
63
|
label: "Windows",
|
|
74
|
-
sublabel: "64-bit MSI installer",
|
|
75
64
|
assetKinds: ["windows-msi"],
|
|
76
65
|
icon: IconBrandWindows,
|
|
77
66
|
},
|
|
78
67
|
{
|
|
79
68
|
id: "linux",
|
|
80
69
|
label: "Linux",
|
|
81
|
-
sublabel: "AppImage, Debian, and RPM packages",
|
|
82
70
|
assetKinds: ["linux-appimage", "linux-deb", "linux-rpm"],
|
|
83
|
-
icon:
|
|
71
|
+
icon: IconTerminal2,
|
|
84
72
|
},
|
|
85
73
|
];
|
|
86
74
|
|
|
@@ -171,47 +159,6 @@ function primaryDownloadButton(
|
|
|
171
159
|
);
|
|
172
160
|
}
|
|
173
161
|
|
|
174
|
-
function secondaryDownloadButton(
|
|
175
|
-
variant: PlatformVariant,
|
|
176
|
-
manifest: Manifest | null,
|
|
177
|
-
manifestError: boolean,
|
|
178
|
-
downloadLabel: string,
|
|
179
|
-
retryLabel: string,
|
|
180
|
-
onRetry: () => void,
|
|
181
|
-
) {
|
|
182
|
-
const asset = pickAsset(manifest, variant);
|
|
183
|
-
const Icon = variant.icon;
|
|
184
|
-
const className =
|
|
185
|
-
"h-auto gap-1.5 px-2 py-1 text-sm font-normal text-muted-foreground hover:bg-transparent hover:text-foreground";
|
|
186
|
-
if (asset) {
|
|
187
|
-
return (
|
|
188
|
-
<Button asChild variant="ghost" className={className}>
|
|
189
|
-
<a href={asset.url} download onClick={markDesktopAppDownloaded}>
|
|
190
|
-
<Icon className="h-4 w-4" />
|
|
191
|
-
{downloadLabel}
|
|
192
|
-
</a>
|
|
193
|
-
</Button>
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
if (manifest === null && !manifestError) {
|
|
197
|
-
return <Skeleton className="h-7 w-[208px] rounded-md" />;
|
|
198
|
-
}
|
|
199
|
-
if (manifestError) {
|
|
200
|
-
return (
|
|
201
|
-
<Button variant="ghost" className={className} onClick={onRetry}>
|
|
202
|
-
<Icon className="h-4 w-4" />
|
|
203
|
-
{retryLabel}
|
|
204
|
-
</Button>
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
return (
|
|
208
|
-
<Button variant="ghost" className={className} disabled>
|
|
209
|
-
<Icon className="h-4 w-4" />
|
|
210
|
-
{downloadLabel}
|
|
211
|
-
</Button>
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
162
|
export default function DownloadPage() {
|
|
216
163
|
const chromeExtensionEnabled = useClipsChromeExtensionEnabled();
|
|
217
164
|
const t = useT();
|
|
@@ -267,7 +214,11 @@ export default function DownloadPage() {
|
|
|
267
214
|
};
|
|
268
215
|
|
|
269
216
|
const primary = VARIANTS.find((v) => v.id === detected) ?? VARIANTS[0];
|
|
270
|
-
|
|
217
|
+
|
|
218
|
+
const handlePlatformChange = (nextPlatform: PlatformId) => {
|
|
219
|
+
if (nextPlatform === detected) return;
|
|
220
|
+
setDetected(nextPlatform);
|
|
221
|
+
};
|
|
271
222
|
|
|
272
223
|
return (
|
|
273
224
|
<div className="min-h-screen bg-background text-foreground">
|
|
@@ -317,87 +268,83 @@ export default function DownloadPage() {
|
|
|
317
268
|
{t("downloadRoute.heroDescription")}
|
|
318
269
|
</p>
|
|
319
270
|
|
|
320
|
-
<div className="mt-10 flex flex-col items-center
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
{manifest ? (
|
|
343
|
-
<>
|
|
344
|
-
{manifest.pub_date
|
|
345
|
-
? t("downloadRoute.versionReleased", {
|
|
346
|
-
version: manifest.version,
|
|
347
|
-
date: new Date(manifest.pub_date).toLocaleDateString(),
|
|
348
|
-
})
|
|
349
|
-
: t("downloadRoute.version", {
|
|
350
|
-
version: manifest.version,
|
|
351
|
-
})}
|
|
352
|
-
</>
|
|
353
|
-
) : manifestError ? (
|
|
354
|
-
<>{t("downloadRoute.manifestError")}</>
|
|
355
|
-
) : (
|
|
356
|
-
<>{t("downloadRoute.loadingRelease")}</>
|
|
357
|
-
)}
|
|
271
|
+
<div className="mt-10 flex flex-col items-center">
|
|
272
|
+
<div className="mb-2 flex justify-center gap-2">
|
|
273
|
+
{VARIANTS.map((variant) => {
|
|
274
|
+
const Icon = variant.icon;
|
|
275
|
+
const active = primary.id === variant.id;
|
|
276
|
+
return (
|
|
277
|
+
<button
|
|
278
|
+
key={variant.id}
|
|
279
|
+
type="button"
|
|
280
|
+
aria-label={variant.label}
|
|
281
|
+
aria-pressed={active}
|
|
282
|
+
onClick={() => handlePlatformChange(variant.id)}
|
|
283
|
+
className={`group flex items-center justify-center rounded-lg p-4 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ${
|
|
284
|
+
active
|
|
285
|
+
? "text-foreground"
|
|
286
|
+
: "text-muted-foreground opacity-40 hover:opacity-65"
|
|
287
|
+
}`}
|
|
288
|
+
>
|
|
289
|
+
<Icon className="size-6" aria-hidden="true" />
|
|
290
|
+
</button>
|
|
291
|
+
);
|
|
292
|
+
})}
|
|
358
293
|
</div>
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
294
|
+
|
|
295
|
+
<div className="mx-auto mt-8 max-w-2xl text-center">
|
|
296
|
+
{primaryDownloadButton(
|
|
297
|
+
primary,
|
|
298
|
+
manifest,
|
|
299
|
+
manifestError,
|
|
300
|
+
t("downloadRoute.downloadFor", { platform: primary.label }),
|
|
301
|
+
t("downloadRoute.retry"),
|
|
302
|
+
retryManifest,
|
|
303
|
+
)}
|
|
304
|
+
|
|
305
|
+
<div className="mt-5 flex justify-center">
|
|
306
|
+
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
307
|
+
<span>{t("downloadRoute.stable")}</span>
|
|
308
|
+
<button
|
|
363
309
|
type="button"
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
310
|
+
role="switch"
|
|
311
|
+
aria-checked={channel === "nightly"}
|
|
312
|
+
aria-label={t(
|
|
313
|
+
channel === "nightly"
|
|
314
|
+
? "downloadRoute.switchToStable"
|
|
315
|
+
: "downloadRoute.switchToNightly",
|
|
316
|
+
)}
|
|
317
|
+
onClick={() =>
|
|
318
|
+
handleChannelChange(
|
|
319
|
+
channel === "nightly" ? "production" : "nightly",
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
className={`relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ${
|
|
323
|
+
channel === "nightly"
|
|
324
|
+
? "bg-foreground"
|
|
325
|
+
: "bg-muted-foreground/20"
|
|
326
|
+
}`}
|
|
368
327
|
>
|
|
369
328
|
<span
|
|
370
|
-
|
|
329
|
+
aria-hidden="true"
|
|
330
|
+
className={`block size-3.5 rounded-full bg-primary-foreground shadow-sm transition-transform ${
|
|
371
331
|
channel === "nightly"
|
|
372
|
-
? "
|
|
373
|
-
:
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
<DropdownMenuContent align="center" className="w-44">
|
|
384
|
-
<DropdownMenuRadioGroup
|
|
385
|
-
value={channel}
|
|
386
|
-
onValueChange={(value) => {
|
|
387
|
-
if (value === "production" || value === "nightly") {
|
|
388
|
-
handleChannelChange(value);
|
|
389
|
-
}
|
|
390
|
-
}}
|
|
332
|
+
? "translate-x-[18px]"
|
|
333
|
+
: "translate-x-[2px]"
|
|
334
|
+
}`}
|
|
335
|
+
/>
|
|
336
|
+
</button>
|
|
337
|
+
<span
|
|
338
|
+
className={
|
|
339
|
+
channel === "nightly"
|
|
340
|
+
? "font-medium text-foreground"
|
|
341
|
+
: "text-muted-foreground"
|
|
342
|
+
}
|
|
391
343
|
>
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
{t("downloadRoute.nightly")}
|
|
397
|
-
</DropdownMenuRadioItem>
|
|
398
|
-
</DropdownMenuRadioGroup>
|
|
399
|
-
</DropdownMenuContent>
|
|
400
|
-
</DropdownMenu>
|
|
344
|
+
{t("downloadRoute.nightly")}
|
|
345
|
+
</span>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
401
348
|
</div>
|
|
402
349
|
</div>
|
|
403
350
|
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
startBubbleWebrtc,
|
|
68
68
|
type BubbleWebrtcHandle,
|
|
69
69
|
} from "./lib/bubble-webrtc";
|
|
70
|
+
import { openBoundOAuthWindow } from "./lib/desktop-oauth-window";
|
|
70
71
|
import {
|
|
71
72
|
getCameraStreamWithFallback,
|
|
72
73
|
isMediaConstraintFailure,
|
|
@@ -2126,15 +2127,17 @@ export function App() {
|
|
|
2126
2127
|
void tick();
|
|
2127
2128
|
}
|
|
2128
2129
|
|
|
2129
|
-
// Google verification stays in the bound Tauri WebView so the
|
|
2130
|
-
// the same browser-binding cookie. Magic-link verification
|
|
2131
|
-
// in the system browser through its own exchange flow.
|
|
2130
|
+
// Google verification stays in a child of the bound Tauri WebView so the
|
|
2131
|
+
// callback sees the same browser-binding cookie. Magic-link verification
|
|
2132
|
+
// still completes in the system browser through its own exchange flow.
|
|
2132
2133
|
async function signInExternal() {
|
|
2133
2134
|
if (signInInflightRef.current) return;
|
|
2134
2135
|
signInInflightRef.current = true;
|
|
2136
|
+
let oauthWindow: ReturnType<typeof openBoundOAuthWindow> | null = null;
|
|
2135
2137
|
|
|
2136
2138
|
try {
|
|
2137
2139
|
setSignInError(null);
|
|
2140
|
+
oauthWindow = openBoundOAuthWindow();
|
|
2138
2141
|
const flowId = crypto.randomUUID?.() ?? null;
|
|
2139
2142
|
const verifier = (() => {
|
|
2140
2143
|
const randomUuid = crypto.randomUUID;
|
|
@@ -2163,7 +2166,6 @@ export function App() {
|
|
|
2163
2166
|
const authParams = new URLSearchParams({
|
|
2164
2167
|
desktop: "1",
|
|
2165
2168
|
flow_id: flowId,
|
|
2166
|
-
webview: "1",
|
|
2167
2169
|
});
|
|
2168
2170
|
const authResponse = await fetch(
|
|
2169
2171
|
`${base}/_agent-native/google/auth-url?${authParams.toString()}`,
|
|
@@ -2194,13 +2196,12 @@ export function App() {
|
|
|
2194
2196
|
: "Could not start Google sign-in.";
|
|
2195
2197
|
throw new Error(message);
|
|
2196
2198
|
}
|
|
2199
|
+
oauthWindow.location.href = authPayload.url;
|
|
2197
2200
|
setSignInPending("google");
|
|
2198
|
-
|
|
2199
|
-
// browser-binding cookie here, and the callback returns this page with
|
|
2200
|
-
// the staged session cookie after Google completes.
|
|
2201
|
-
window.location.href = authPayload.url;
|
|
2201
|
+
startDesktopAuthExchange(flowId, "google", verifier);
|
|
2202
2202
|
} catch (err) {
|
|
2203
2203
|
console.error("[clips-tray] signInExternal failed:", err);
|
|
2204
|
+
oauthWindow?.close();
|
|
2204
2205
|
signInInflightRef.current = false;
|
|
2205
2206
|
setSignInPending(null);
|
|
2206
2207
|
setSignInError(
|
|
@@ -3962,8 +3963,8 @@ export function App() {
|
|
|
3962
3963
|
// (not a separate Tauri window). This avoids Tauri 2's separate-WebKit-
|
|
3963
3964
|
// data-store-per-WebviewWindow cookie-jar issue — the cookie is set in
|
|
3964
3965
|
// the same webview that reads it on the next /auth/session poll.
|
|
3965
|
-
// Google verification uses the bound WebView, while magic-link
|
|
3966
|
-
// uses the system browser and password stays inline here.
|
|
3966
|
+
// Google verification uses a popup in the bound WebView, while magic-link
|
|
3967
|
+
// verification uses the system browser and password stays inline here.
|
|
3967
3968
|
if (authStatus === "anon") {
|
|
3968
3969
|
return (
|
|
3969
3970
|
<div className="app" ref={appRef}>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type OAuthWindow = Pick<Window, "close"> & {
|
|
2
|
+
location: Pick<Location, "href">;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
type OpenOAuthWindow = (url: string, target: string) => OAuthWindow | null;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Open a same-WebView OAuth child before awaiting the auth URL.
|
|
9
|
+
*
|
|
10
|
+
* The parent keeps polling the exchange while the child completes Google
|
|
11
|
+
* OAuth. Using window.open keeps both pages in the Tauri WebView cookie
|
|
12
|
+
* partition; the system-browser shell opener would lose the binding cookie.
|
|
13
|
+
*/
|
|
14
|
+
export function openBoundOAuthWindow(
|
|
15
|
+
openWindow: OpenOAuthWindow = (url, target) =>
|
|
16
|
+
window.open(url, target) as OAuthWindow | null,
|
|
17
|
+
): OAuthWindow {
|
|
18
|
+
const oauthWindow = openWindow("about:blank", "_blank");
|
|
19
|
+
if (!oauthWindow) {
|
|
20
|
+
throw new Error("Could not open the Google sign-in window.");
|
|
21
|
+
}
|
|
22
|
+
return oauthWindow;
|
|
23
|
+
}
|
|
@@ -134,3 +134,14 @@ hand-duplicating framework logic.
|
|
|
134
134
|
`agent-surfaces`.
|
|
135
135
|
- Do not copy framework runtime internals when a public API or narrow UI copy
|
|
136
136
|
will do; read `customizing-agent-native` for the supported override ladder.
|
|
137
|
+
|
|
138
|
+
## Authoring visual docs blocks
|
|
139
|
+
|
|
140
|
+
Treat the shared `Diagram` block as a renderer, not as a reason to style every
|
|
141
|
+
docs UI as a sketch. Use the hand-drawn font and Rough.js only for actual
|
|
142
|
+
diagrams or wireframes that communicate structure, flow, or a design draft.
|
|
143
|
+
For polished UI-like content - cards, logo walls, tables, controls, or product
|
|
144
|
+
shells — set `renderMode="design"` (and usually `frame="hide"` when the block
|
|
145
|
+
is the content itself). Design mode preserves normal docs typography and
|
|
146
|
+
disables the Rough.js overlay. Keep `data-rough` only on elements intentionally
|
|
147
|
+
sketched inside a real diagram.
|