@agent-native/core 0.161.16 → 0.161.20
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/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/analytics/AGENTS.md +1 -0
- package/corpus/templates/analytics/server/plugins/auth.ts +4 -0
- package/corpus/templates/assets/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/assets/AGENTS.md +1 -0
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/brain/AGENTS.md +1 -0
- package/corpus/templates/calendar/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/calendar/AGENTS.md +1 -0
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/chat/AGENTS.md +4 -0
- package/corpus/templates/chat/vitest.config.ts +12 -7
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/clips/AGENTS.md +1 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +4 -0
- package/corpus/templates/clips/app/hooks/use-playback-position.ts +10 -2
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +26 -25
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -0
- package/corpus/templates/clips/changelog/2026-08-18-clips-no-longer-opens-welcome-window-on-first-launch.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-18-clips-now-recovers-interrupted-uploads-and-reliably-restarts.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-18-meeting-notifications-no-longer-show-decorative-left-side-lines.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-18-pending-recording-files-now-use-a-clips-prefixed-name.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/updater.ts +21 -1
- package/corpus/templates/clips/desktop/src/main.tsx +0 -3
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +0 -4
- package/corpus/templates/clips/desktop/src/shared/config.ts +0 -1
- package/corpus/templates/clips/desktop/src/styles.css +0 -136
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +0 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +0 -45
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +1 -4
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +63 -8
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +98 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +54 -20
- package/corpus/templates/content/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/content/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/content/AGENTS.md +1 -0
- package/corpus/templates/crm/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/crm/AGENTS.md +1 -0
- package/corpus/templates/design/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/design/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/design/AGENTS.md +1 -0
- package/corpus/templates/design/app/global.css +6 -0
- package/corpus/templates/design/app/i18n-data.ts +11 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +9 -8
- package/corpus/templates/design/app/root.tsx +1 -1
- package/corpus/templates/design/changelog/2026-08-18-design-chat-context-stays-out-of-the-composer.md +6 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/dispatch/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/dispatch/AGENTS.md +5 -5
- package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/factory/AGENTS.md +1 -0
- package/corpus/templates/forms/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/forms/AGENTS.md +1 -0
- package/corpus/templates/macros/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/macros/AGENTS.md +1 -0
- package/corpus/templates/mail/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/mail/AGENTS.md +1 -0
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/plan/AGENTS.md +1 -0
- package/corpus/templates/slides/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/slides/AGENTS.md +2 -1
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +29 -2
- package/corpus/templates/tasks/AGENTS.md +1 -0
- package/dist/action.d.ts +1 -0
- package/dist/action.js +44 -2
- package/dist/agent/production-agent.js +28 -5
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/route-state.js +17 -13
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +6 -0
- package/dist/server/auth.js +23 -5
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
- package/dist/templates/chat/AGENTS.md +4 -0
- package/dist/templates/chat/vitest.config.ts +12 -7
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +29 -2
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +29 -2
- package/dist/templates/headless/AGENTS.md +4 -0
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -2
- package/dist/templates/workspace-core/AGENTS.md +4 -0
- package/dist/templates/workspace-root/AGENTS.md +9 -0
- package/docs/content/deployment.mdx +70 -0
- package/docs/content/faq.mdx +1 -1
- package/package.json +1 -1
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +29 -2
- package/src/templates/chat/AGENTS.md +4 -0
- package/src/templates/chat/vitest.config.ts +12 -7
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +29 -2
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +29 -2
- package/src/templates/headless/AGENTS.md +4 -0
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +10 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +24 -0
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +29 -2
- package/src/templates/workspace-core/AGENTS.md +4 -0
- package/src/templates/workspace-root/AGENTS.md +9 -0
- package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +0 -314
|
@@ -3,8 +3,8 @@ name: secrets
|
|
|
3
3
|
description: >-
|
|
4
4
|
Declaratively register API keys and service credentials a template needs so
|
|
5
5
|
they appear in the agent sidebar settings UI and the onboarding checklist.
|
|
6
|
-
Use
|
|
7
|
-
|
|
6
|
+
Use before adding any third-party credential or setup UI so API keys, OAuth
|
|
7
|
+
connections, and scoped configuration use the correct shared primitive.
|
|
8
8
|
scope: dev
|
|
9
9
|
metadata:
|
|
10
10
|
internal: true
|
|
@@ -24,6 +24,33 @@ encrypted `app_secrets` vault, `saveCredential` / `resolveCredential`, OAuth, or
|
|
|
24
24
|
`${keys.NAME}` substitution. Examples must use obvious placeholders such as
|
|
25
25
|
`<OPENAI_API_KEY>` or `${keys.SLACK_WEBHOOK}`, not real-looking copied values.
|
|
26
26
|
|
|
27
|
+
## Credential Modeling Preflight
|
|
28
|
+
|
|
29
|
+
Before registering a provider's fields, inspect the workspace/provider connection
|
|
30
|
+
catalog first. If a reusable connection exists, use its app grant and scoped
|
|
31
|
+
`resolveWorkspaceConnectionCredential(s)ForApp` path instead of registering a
|
|
32
|
+
parallel secret. Only classify fields for app-local setup when no reusable
|
|
33
|
+
connection exists:
|
|
34
|
+
|
|
35
|
+
- **API or service key** - register it as `kind: "api-key"` with the narrowest
|
|
36
|
+
correct `scope`, a human label, a description, a docs link, and a validator.
|
|
37
|
+
- **OAuth authorization or refresh token** - use the OAuth token store and
|
|
38
|
+
register a `kind: "oauth"` entry so the shared UI renders Connect and the
|
|
39
|
+
runtime owns status, refresh, and reauthorization.
|
|
40
|
+
- **Deploy- or app-level configuration** - use deployment/runtime
|
|
41
|
+
configuration, not a per-user secret row.
|
|
42
|
+
- **Account, customer, manager, or other non-secret identifier** - store it as
|
|
43
|
+
scoped connection metadata or app data, not as a masked secret field.
|
|
44
|
+
|
|
45
|
+
`required: true` is for a logical setup requirement. If a provider needs
|
|
46
|
+
several values, do not automatically create one required checklist item per
|
|
47
|
+
field; use one composite onboarding step or a registered connection readiness
|
|
48
|
+
check.
|
|
49
|
+
|
|
50
|
+
Custom setup UI is allowed for provider-specific prerequisites, ordering, or
|
|
51
|
+
health checks, but it must delegate credential storage and connection state to
|
|
52
|
+
the shared vault/OAuth/settings surfaces.
|
|
53
|
+
|
|
27
54
|
## When to use
|
|
28
55
|
|
|
29
56
|
Use this for any external credential your template needs: API keys, service
|
|
@@ -29,6 +29,7 @@ video sharing app. The agent and the UI share the same SQL data and actions.
|
|
|
29
29
|
- Never hardcode API keys, tokens, webhook URLs, signing secrets, private
|
|
30
30
|
Builder/internal data, customer data, or credential-looking literals. Use
|
|
31
31
|
secrets/OAuth/runtime config and obvious placeholders.
|
|
32
|
+
- For external integrations, inspect the workspace/provider connection catalog first; reuse its scoped resolver.
|
|
32
33
|
- Use actions for recording metadata, transcripts, cleanup, summaries, chapters,
|
|
33
34
|
comments, spaces/folders, meetings, and sharing. Never bypass access helpers.
|
|
34
35
|
- Comment text accepts inline Markdown for emphasis, inline code, links, and
|
|
@@ -183,6 +183,8 @@ export interface VideoPlayerProps {
|
|
|
183
183
|
defaultSpeed?: number;
|
|
184
184
|
/** Autoplay on mount. */
|
|
185
185
|
autoPlay?: boolean;
|
|
186
|
+
/** Persist resume position for an authenticated viewer. */
|
|
187
|
+
persistPlaybackPosition?: boolean;
|
|
186
188
|
/** Start time in ms. */
|
|
187
189
|
startMs?: number;
|
|
188
190
|
/** Comment + chapter overlays for the scrubber. */
|
|
@@ -247,6 +249,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
247
249
|
thumbnailUrl,
|
|
248
250
|
defaultSpeed = 1.2,
|
|
249
251
|
autoPlay,
|
|
252
|
+
persistPlaybackPosition = true,
|
|
250
253
|
startMs,
|
|
251
254
|
editsJson,
|
|
252
255
|
comments,
|
|
@@ -520,6 +523,7 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
520
523
|
recordingId,
|
|
521
524
|
videoEl: playbackVideoEl,
|
|
522
525
|
durationMs,
|
|
526
|
+
enabled: persistPlaybackPosition,
|
|
523
527
|
explicitStartMs: startMs,
|
|
524
528
|
allowRestoreWhilePlaying: autoPlay,
|
|
525
529
|
onRestore: restorePlaybackPosition,
|
|
@@ -13,6 +13,7 @@ export interface UsePlaybackPositionOptions {
|
|
|
13
13
|
recordingId: string;
|
|
14
14
|
videoEl: HTMLVideoElement | null;
|
|
15
15
|
durationMs: number;
|
|
16
|
+
enabled?: boolean;
|
|
16
17
|
explicitStartMs?: number;
|
|
17
18
|
allowRestoreWhilePlaying?: boolean;
|
|
18
19
|
onRestore?: (positionMs: number) => void;
|
|
@@ -27,6 +28,7 @@ export function usePlaybackPosition({
|
|
|
27
28
|
recordingId,
|
|
28
29
|
videoEl,
|
|
29
30
|
durationMs,
|
|
31
|
+
enabled = true,
|
|
30
32
|
explicitStartMs,
|
|
31
33
|
allowRestoreWhilePlaying = false,
|
|
32
34
|
onRestore,
|
|
@@ -38,7 +40,7 @@ export function usePlaybackPosition({
|
|
|
38
40
|
onRestoreRef.current = onRestore;
|
|
39
41
|
|
|
40
42
|
useEffect(() => {
|
|
41
|
-
if (!videoEl || !recordingId) return;
|
|
43
|
+
if (!enabled || !videoEl || !recordingId) return;
|
|
42
44
|
|
|
43
45
|
const controller = new AbortController();
|
|
44
46
|
let cancelled = false;
|
|
@@ -184,5 +186,11 @@ export function usePlaybackPosition({
|
|
|
184
186
|
window.removeEventListener("pagehide", onPageHide);
|
|
185
187
|
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
186
188
|
};
|
|
187
|
-
}, [
|
|
189
|
+
}, [
|
|
190
|
+
allowRestoreWhilePlaying,
|
|
191
|
+
enabled,
|
|
192
|
+
explicitStartMs,
|
|
193
|
+
recordingId,
|
|
194
|
+
videoEl,
|
|
195
|
+
]);
|
|
188
196
|
}
|
|
@@ -236,6 +236,7 @@ export default function EmbedRoute() {
|
|
|
236
236
|
videoFormat={recording.videoFormat}
|
|
237
237
|
embedProvider={isLoomEmbedBacked ? "loom" : null}
|
|
238
238
|
durationMs={recording.durationMs}
|
|
239
|
+
persistPlaybackPosition={false}
|
|
239
240
|
editsJson={recording.editsJson}
|
|
240
241
|
thumbnailUrl={recording.thumbnailUrl}
|
|
241
242
|
defaultSpeed={parsePlaybackSpeed(recording.defaultSpeed) ?? 1.2}
|
|
@@ -187,6 +187,30 @@ function nativeSaveFailureMessage(reason: string | null | undefined): string {
|
|
|
187
187
|
return "The desktop recorder finished and saved a local copy, but Clips could not upload it. You can retry from the Clips menu without recording again.";
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
export function BackToLibraryButton() {
|
|
191
|
+
const t = useT();
|
|
192
|
+
const navigate = useNavigate();
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<Tooltip>
|
|
196
|
+
<TooltipTrigger asChild>
|
|
197
|
+
<Button
|
|
198
|
+
variant="ghost"
|
|
199
|
+
size="icon"
|
|
200
|
+
className="shrink-0"
|
|
201
|
+
onClick={() => navigate("/library", { replace: true })}
|
|
202
|
+
aria-label={t("recordingPage.backToLibrary")}
|
|
203
|
+
>
|
|
204
|
+
<IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
|
|
205
|
+
</Button>
|
|
206
|
+
</TooltipTrigger>
|
|
207
|
+
<TooltipContent side="bottom" align="start">
|
|
208
|
+
{t("recordingPage.backToLibrary")}
|
|
209
|
+
</TooltipContent>
|
|
210
|
+
</Tooltip>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
190
214
|
function parseTimeParam(raw: string | null): number {
|
|
191
215
|
if (!raw) return 0;
|
|
192
216
|
const value = raw.trim();
|
|
@@ -965,17 +989,7 @@ export default function RecordingPage() {
|
|
|
965
989
|
return (
|
|
966
990
|
<div className="flex min-h-screen w-full flex-col bg-background">
|
|
967
991
|
<header className="flex min-w-0 shrink-0 items-center gap-3 border-b border-border px-3 py-2 sm:px-4 sm:py-3">
|
|
968
|
-
<
|
|
969
|
-
asChild
|
|
970
|
-
variant="ghost"
|
|
971
|
-
size="icon"
|
|
972
|
-
className="shrink-0"
|
|
973
|
-
aria-label={t("recordingPage.backToLibrary")}
|
|
974
|
-
>
|
|
975
|
-
<Link to="/library" replace>
|
|
976
|
-
<IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
|
|
977
|
-
</Link>
|
|
978
|
-
</Button>
|
|
992
|
+
<BackToLibraryButton />
|
|
979
993
|
<div className="min-w-0 flex-1">
|
|
980
994
|
<p className="truncate text-sm font-medium">{visibleTitle}</p>
|
|
981
995
|
<p className="truncate text-xs text-muted-foreground">
|
|
@@ -1294,20 +1308,7 @@ export default function RecordingPage() {
|
|
|
1294
1308
|
{/* Main video column */}
|
|
1295
1309
|
<div className="flex w-full min-w-0 flex-col xl:flex-1">
|
|
1296
1310
|
<header className="flex min-w-0 shrink-0 items-center gap-2 border-b border-border px-3 py-2 sm:gap-3 sm:px-4 sm:py-3">
|
|
1297
|
-
<
|
|
1298
|
-
asChild
|
|
1299
|
-
variant="ghost"
|
|
1300
|
-
size="icon"
|
|
1301
|
-
className="shrink-0 sm:w-auto sm:px-2"
|
|
1302
|
-
aria-label={t("recordingPage.backToLibrary")}
|
|
1303
|
-
>
|
|
1304
|
-
<Link to="/library" replace>
|
|
1305
|
-
<IconArrowLeft className="h-4 w-4 rtl:-scale-x-100" />
|
|
1306
|
-
<span className="hidden sm:inline">
|
|
1307
|
-
{t("recordingPage.backToLibrary")}
|
|
1308
|
-
</span>
|
|
1309
|
-
</Link>
|
|
1310
|
-
</Button>
|
|
1311
|
+
<BackToLibraryButton />
|
|
1311
1312
|
<div className="flex-1 min-w-0">
|
|
1312
1313
|
<EditableRecordingTitle
|
|
1313
1314
|
recordingId={recording.id}
|
|
@@ -1226,6 +1226,7 @@ export default function ShareRoute() {
|
|
|
1226
1226
|
videoFormat={recording.videoFormat}
|
|
1227
1227
|
embedProvider={isLoomEmbedBacked ? "loom" : null}
|
|
1228
1228
|
durationMs={recording.durationMs}
|
|
1229
|
+
persistPlaybackPosition={Boolean(session)}
|
|
1229
1230
|
editsJson={recording.editsJson}
|
|
1230
1231
|
thumbnailUrl={recording.thumbnailUrl}
|
|
1231
1232
|
role={viewerRole ?? (viewerCanEdit ? "owner" : "viewer")}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { invoke } from "@tauri-apps/api/core";
|
|
2
|
+
import { exit, relaunch } from "@tauri-apps/plugin-process";
|
|
2
3
|
import { check, Update } from "@tauri-apps/plugin-updater";
|
|
3
4
|
import { useEffect, useState } from "react";
|
|
4
5
|
|
|
6
|
+
import { isMacPlatform } from "./platform";
|
|
7
|
+
|
|
5
8
|
declare const __CLIPS_DESKTOP_LOCAL_BUILD__: boolean;
|
|
6
9
|
|
|
7
10
|
export type UpdateStatus =
|
|
@@ -166,9 +169,26 @@ export async function installAndRestart(): Promise<void> {
|
|
|
166
169
|
// bundle no longer matches the running process as short as possible — the
|
|
167
170
|
// process is torn down by `relaunch()` right after, so capture never runs
|
|
168
171
|
// against a swapped-out bundle.
|
|
172
|
+
const restartBundlePath = await invoke<string>("restart_bundle_path").catch(
|
|
173
|
+
(err) => {
|
|
174
|
+
console.error("[clips-updater] restart target lookup failed:", err);
|
|
175
|
+
return null;
|
|
176
|
+
},
|
|
177
|
+
);
|
|
169
178
|
if (pendingUpdate) {
|
|
170
179
|
await pendingUpdate.install();
|
|
171
180
|
}
|
|
181
|
+
if (isMacPlatform() && restartBundlePath) {
|
|
182
|
+
try {
|
|
183
|
+
await invoke("schedule_restart_after_exit", {
|
|
184
|
+
bundlePath: restartBundlePath,
|
|
185
|
+
});
|
|
186
|
+
await exit(0);
|
|
187
|
+
return;
|
|
188
|
+
} catch (err) {
|
|
189
|
+
console.error("[clips-updater] macOS restart handoff failed:", err);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
172
192
|
await relaunch();
|
|
173
193
|
}
|
|
174
194
|
|
|
@@ -11,7 +11,6 @@ import { FlowBar } from "./overlays/flow-bar";
|
|
|
11
11
|
import { MeetingNotification } from "./overlays/meeting-notification";
|
|
12
12
|
import { MeetingNub } from "./overlays/meeting-nub";
|
|
13
13
|
import { MonitorPicker } from "./overlays/monitor-picker";
|
|
14
|
-
import { Onboarding } from "./overlays/onboarding";
|
|
15
14
|
import { Preparing } from "./overlays/preparing";
|
|
16
15
|
import { RecordingPill } from "./overlays/recording-pill";
|
|
17
16
|
import { RegionGuideEditor, RegionGuides } from "./overlays/region-guides";
|
|
@@ -47,8 +46,6 @@ function pickRoute(route: string): React.ReactElement {
|
|
|
47
46
|
return <Finalizing />;
|
|
48
47
|
case "preparing":
|
|
49
48
|
return <Preparing />;
|
|
50
|
-
case "onboarding":
|
|
51
|
-
return <Onboarding />;
|
|
52
49
|
case "meeting-notif":
|
|
53
50
|
return <MeetingNotification />;
|
|
54
51
|
case "meeting-nub":
|
|
@@ -386,7 +386,6 @@ export function MeetingNotification() {
|
|
|
386
386
|
return <div className="meeting-notification-root" />;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
-
const isCalendar = data.type === "calendar";
|
|
390
389
|
const hasJoin = Boolean(data.joinUrl);
|
|
391
390
|
const provider = detectMeetingJoinProvider(data.joinUrl, data.platform);
|
|
392
391
|
const providerName = joinProviderLabel(provider);
|
|
@@ -404,9 +403,6 @@ export function MeetingNotification() {
|
|
|
404
403
|
onMouseEnter={() => setDomHovered(true)}
|
|
405
404
|
onMouseLeave={() => setDomHovered(false)}
|
|
406
405
|
>
|
|
407
|
-
<div
|
|
408
|
-
className={`meeting-notification-bar ${isCalendar ? "meeting-notification-bar-calendar" : "meeting-notification-bar-adhoc"}`}
|
|
409
|
-
/>
|
|
410
406
|
<div className="meeting-notification-content">
|
|
411
407
|
<div className="meeting-notification-title">{data.title}</div>
|
|
412
408
|
<div className="meeting-notification-subtitle">{data.subtitle}</div>
|
|
@@ -5263,124 +5263,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5263
5263
|
}
|
|
5264
5264
|
}
|
|
5265
5265
|
|
|
5266
|
-
/* ------------------------------------------------------------------------- */
|
|
5267
|
-
/* Overlay: onboarding */
|
|
5268
|
-
/* ------------------------------------------------------------------------- */
|
|
5269
|
-
|
|
5270
|
-
.onboarding-root {
|
|
5271
|
-
position: fixed;
|
|
5272
|
-
inset: 0;
|
|
5273
|
-
display: flex;
|
|
5274
|
-
align-items: center;
|
|
5275
|
-
justify-content: center;
|
|
5276
|
-
background: #212121;
|
|
5277
|
-
color: #f5f5f5;
|
|
5278
|
-
}
|
|
5279
|
-
|
|
5280
|
-
.onboarding-card {
|
|
5281
|
-
display: flex;
|
|
5282
|
-
flex-direction: column;
|
|
5283
|
-
align-items: center;
|
|
5284
|
-
gap: 20px;
|
|
5285
|
-
padding: 40px 36px;
|
|
5286
|
-
max-width: 380px;
|
|
5287
|
-
width: 100%;
|
|
5288
|
-
}
|
|
5289
|
-
|
|
5290
|
-
.onboarding-title {
|
|
5291
|
-
font-size: 22px;
|
|
5292
|
-
font-weight: 700;
|
|
5293
|
-
color: white;
|
|
5294
|
-
margin: 0;
|
|
5295
|
-
letter-spacing: -0.3px;
|
|
5296
|
-
}
|
|
5297
|
-
|
|
5298
|
-
.onboarding-subtitle {
|
|
5299
|
-
font-size: 14px;
|
|
5300
|
-
color: #a3a3a3;
|
|
5301
|
-
margin: -8px 0 0;
|
|
5302
|
-
}
|
|
5303
|
-
|
|
5304
|
-
.onboarding-features {
|
|
5305
|
-
display: flex;
|
|
5306
|
-
flex-direction: column;
|
|
5307
|
-
gap: 10px;
|
|
5308
|
-
width: 100%;
|
|
5309
|
-
}
|
|
5310
|
-
|
|
5311
|
-
.onboarding-feature {
|
|
5312
|
-
display: flex;
|
|
5313
|
-
align-items: flex-start;
|
|
5314
|
-
gap: 12px;
|
|
5315
|
-
padding: 14px 16px;
|
|
5316
|
-
background: rgba(255, 255, 255, 0.04);
|
|
5317
|
-
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
5318
|
-
border-radius: 12px;
|
|
5319
|
-
cursor: pointer;
|
|
5320
|
-
user-select: none;
|
|
5321
|
-
}
|
|
5322
|
-
|
|
5323
|
-
.onboarding-feature:hover {
|
|
5324
|
-
background: rgba(255, 255, 255, 0.06);
|
|
5325
|
-
}
|
|
5326
|
-
|
|
5327
|
-
.onboarding-checkbox {
|
|
5328
|
-
width: 18px;
|
|
5329
|
-
height: 18px;
|
|
5330
|
-
margin: 1px 0 0;
|
|
5331
|
-
accent-color: #16a34a;
|
|
5332
|
-
cursor: pointer;
|
|
5333
|
-
flex-shrink: 0;
|
|
5334
|
-
}
|
|
5335
|
-
|
|
5336
|
-
.onboarding-feature-text {
|
|
5337
|
-
display: flex;
|
|
5338
|
-
flex-direction: column;
|
|
5339
|
-
gap: 3px;
|
|
5340
|
-
}
|
|
5341
|
-
|
|
5342
|
-
.onboarding-feature-name {
|
|
5343
|
-
font-size: 14px;
|
|
5344
|
-
font-weight: 600;
|
|
5345
|
-
color: white;
|
|
5346
|
-
}
|
|
5347
|
-
|
|
5348
|
-
.onboarding-feature-desc {
|
|
5349
|
-
font-size: 12px;
|
|
5350
|
-
color: #a3a3a3;
|
|
5351
|
-
line-height: 1.4;
|
|
5352
|
-
}
|
|
5353
|
-
|
|
5354
|
-
.onboarding-cta {
|
|
5355
|
-
width: 100%;
|
|
5356
|
-
border: none;
|
|
5357
|
-
border-radius: 12px;
|
|
5358
|
-
padding: 12px 16px;
|
|
5359
|
-
background: #f5f5f5;
|
|
5360
|
-
color: #212121;
|
|
5361
|
-
font-size: 14px;
|
|
5362
|
-
font-weight: 600;
|
|
5363
|
-
cursor: pointer;
|
|
5364
|
-
height: 44px;
|
|
5365
|
-
display: inline-flex;
|
|
5366
|
-
align-items: center;
|
|
5367
|
-
justify-content: center;
|
|
5368
|
-
margin-top: 4px;
|
|
5369
|
-
}
|
|
5370
|
-
|
|
5371
|
-
.onboarding-cta:hover {
|
|
5372
|
-
background: #e5e5e5;
|
|
5373
|
-
}
|
|
5374
|
-
|
|
5375
|
-
.onboarding-cta:active {
|
|
5376
|
-
transform: translateY(1px);
|
|
5377
|
-
}
|
|
5378
|
-
|
|
5379
|
-
.onboarding-cta:disabled {
|
|
5380
|
-
opacity: 0.6;
|
|
5381
|
-
cursor: not-allowed;
|
|
5382
|
-
}
|
|
5383
|
-
|
|
5384
5266
|
/* ------------------------------------------------------------------------- */
|
|
5385
5267
|
/* Overlay: meeting notification */
|
|
5386
5268
|
/* ------------------------------------------------------------------------- */
|
|
@@ -5414,24 +5296,6 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5414
5296
|
max-width: 440px;
|
|
5415
5297
|
}
|
|
5416
5298
|
|
|
5417
|
-
.meeting-notification-bar {
|
|
5418
|
-
width: 3px;
|
|
5419
|
-
height: 36px;
|
|
5420
|
-
border-radius: 999px;
|
|
5421
|
-
flex-shrink: 0;
|
|
5422
|
-
}
|
|
5423
|
-
|
|
5424
|
-
.meeting-notification-bar-calendar {
|
|
5425
|
-
background: #7dd3fc;
|
|
5426
|
-
}
|
|
5427
|
-
|
|
5428
|
-
.meeting-notification-bar-adhoc {
|
|
5429
|
-
background: transparent;
|
|
5430
|
-
border-left: 3px dashed #a3a3a3;
|
|
5431
|
-
width: 3px;
|
|
5432
|
-
border-radius: 0;
|
|
5433
|
-
}
|
|
5434
|
-
|
|
5435
5299
|
.meeting-notification-content {
|
|
5436
5300
|
flex: 1;
|
|
5437
5301
|
min-width: 0;
|
|
@@ -48,7 +48,6 @@ const REGION_GUIDES_LABEL: &str = "region-guides";
|
|
|
48
48
|
const REGION_GUIDE_EDITOR_LABEL: &str = "region-guide-editor";
|
|
49
49
|
const REGION_RECORD_BORDER_LABEL: &str = "region-record-border";
|
|
50
50
|
const MONITOR_PICKER_LABEL_PREFIX: &str = "monitor-picker-";
|
|
51
|
-
const ONBOARDING_LABEL: &str = "onboarding";
|
|
52
51
|
const OVERLAY_LABELS: &[&str] = &[
|
|
53
52
|
COUNTDOWN_LABEL,
|
|
54
53
|
TOOLBAR_LABEL,
|
|
@@ -59,8 +58,6 @@ const OVERLAY_LABELS: &[&str] = &[
|
|
|
59
58
|
REGION_GUIDES_LABEL,
|
|
60
59
|
REGION_RECORD_BORDER_LABEL,
|
|
61
60
|
];
|
|
62
|
-
const ONBOARDING_WIDTH_LOGICAL: f64 = 560.0;
|
|
63
|
-
const ONBOARDING_HEIGHT_LOGICAL: f64 = 640.0;
|
|
64
61
|
|
|
65
62
|
/// Physical-pixel bubble sizes. Logical px on retina = physical / 2, so these
|
|
66
63
|
/// map to ~96 (small) and ~180 (medium) logical px — matching Loom's camera
|
|
@@ -599,48 +596,6 @@ pub async fn hide_finalizing(app: AppHandle) -> Result<(), String> {
|
|
|
599
596
|
Ok(())
|
|
600
597
|
}
|
|
601
598
|
|
|
602
|
-
/// First-run onboarding window (ONBOARD-WINDOW). Unlike the transparent,
|
|
603
|
-
/// click-through overlays above, this is a normal decorated, focused window
|
|
604
|
-
/// with its own solid dark background (`.onboarding-root` in styles.css) —
|
|
605
|
-
/// centered on the primary display so it reads as a real app window, not a
|
|
606
|
-
/// HUD. Called once from `lib.rs`'s `setup()` when `onboarding_complete` is
|
|
607
|
-
/// false. Reuses an existing window if one is somehow already open (e.g. a
|
|
608
|
-
/// hot-reload re-triggering setup in dev) instead of building a second one.
|
|
609
|
-
pub fn show_onboarding_window(app: &AppHandle) {
|
|
610
|
-
if let Some(existing) = app.get_webview_window(ONBOARDING_LABEL) {
|
|
611
|
-
let _ = existing.show();
|
|
612
|
-
let _ = existing.set_focus();
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
let win =
|
|
616
|
-
match WebviewWindowBuilder::new(app, ONBOARDING_LABEL, build_overlay_url("onboarding"))
|
|
617
|
-
.title("Welcome to Clips")
|
|
618
|
-
.inner_size(ONBOARDING_WIDTH_LOGICAL, ONBOARDING_HEIGHT_LOGICAL)
|
|
619
|
-
.resizable(false)
|
|
620
|
-
.center()
|
|
621
|
-
.focused(true)
|
|
622
|
-
.build()
|
|
623
|
-
{
|
|
624
|
-
Ok(w) => w,
|
|
625
|
-
Err(e) => {
|
|
626
|
-
eprintln!("[clips-tray] onboarding window build failed: {}", e);
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
};
|
|
630
|
-
let _ = win.show();
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/// Close the first-run onboarding window once the overlay's finish handler
|
|
634
|
-
/// has saved feature config + opened the popover. Idempotent — closing an
|
|
635
|
-
/// already-closed/never-built window is a no-op.
|
|
636
|
-
#[tauri::command]
|
|
637
|
-
pub async fn hide_onboarding_window(app: AppHandle) -> Result<(), String> {
|
|
638
|
-
if let Some(w) = app.get_webview_window(ONBOARDING_LABEL) {
|
|
639
|
-
let _ = w.close();
|
|
640
|
-
}
|
|
641
|
-
Ok(())
|
|
642
|
-
}
|
|
643
|
-
|
|
644
599
|
/// Full-screen, click-through recording guides. The React view renders the
|
|
645
600
|
/// saved translucent rectangles, while AppKit marks the whole overlay as
|
|
646
601
|
/// non-shareable so the guides stay private to the recorder.
|
|
@@ -134,7 +134,6 @@ pub struct FeatureConfig {
|
|
|
134
134
|
pub region_guides: RegionGuidesConfig,
|
|
135
135
|
#[serde(default)]
|
|
136
136
|
pub screen_memory: ScreenMemoryConfig,
|
|
137
|
-
pub onboarding_complete: bool,
|
|
138
137
|
#[serde(default = "default_whisper_model_enabled")]
|
|
139
138
|
pub whisper_model_enabled: bool,
|
|
140
139
|
#[serde(default = "default_whisper_model_id")]
|
|
@@ -238,7 +237,6 @@ impl Default for FeatureConfig {
|
|
|
238
237
|
show_in_screen_capture: false,
|
|
239
238
|
region_guides: RegionGuidesConfig::default(),
|
|
240
239
|
screen_memory: ScreenMemoryConfig::default(),
|
|
241
|
-
onboarding_complete: false,
|
|
242
240
|
whisper_model_enabled: default_whisper_model_enabled(),
|
|
243
241
|
whisper_model_id: default_whisper_model_id(),
|
|
244
242
|
}
|
|
@@ -437,8 +435,7 @@ mod tests {
|
|
|
437
435
|
let config: FeatureConfig = serde_json::from_value(serde_json::json!({
|
|
438
436
|
"clipsEnabled": true,
|
|
439
437
|
"meetingsEnabled": true,
|
|
440
|
-
"voiceEnabled": true
|
|
441
|
-
"onboardingComplete": true
|
|
438
|
+
"voiceEnabled": true
|
|
442
439
|
}))
|
|
443
440
|
.unwrap();
|
|
444
441
|
|
|
@@ -52,7 +52,7 @@ use state::{
|
|
|
52
52
|
};
|
|
53
53
|
use util::{
|
|
54
54
|
configure_overlay_behavior, is_recording_active, present_interactive_window,
|
|
55
|
-
set_capture_excluded,
|
|
55
|
+
restart_bundle_path, schedule_restart_after_exit, set_capture_excluded,
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
// Embedded fallback icon — a tiny 16x16 solid purple PNG so the binary always
|
|
@@ -116,7 +116,6 @@ pub fn run() {
|
|
|
116
116
|
clips::close_signin,
|
|
117
117
|
clips::show_flow_bar,
|
|
118
118
|
clips::hide_flow_bar,
|
|
119
|
-
clips::hide_onboarding_window,
|
|
120
119
|
clips::complete_voice_dictation,
|
|
121
120
|
clips::paste_last_dictation,
|
|
122
121
|
clips::set_recording_state,
|
|
@@ -248,6 +247,8 @@ pub fn run() {
|
|
|
248
247
|
// persistent log file (production debugging)
|
|
249
248
|
logfile::frontend_log,
|
|
250
249
|
logfile::open_logs,
|
|
250
|
+
restart_bundle_path,
|
|
251
|
+
schedule_restart_after_exit,
|
|
251
252
|
])
|
|
252
253
|
.plugin(tauri_plugin_shell::init())
|
|
253
254
|
.plugin(tauri_plugin_deep_link::init())
|
|
@@ -341,15 +342,6 @@ pub fn run() {
|
|
|
341
342
|
tray::build_tray(app)?;
|
|
342
343
|
config::sync_launch_at_login(app.handle());
|
|
343
344
|
let feature_config = config::feature_config(app.handle());
|
|
344
|
-
// ONBOARD-WINDOW: first-run onboarding never had a Rust-side
|
|
345
|
-
// window to appear in — the `#onboarding` hash route and overlay
|
|
346
|
-
// component existed, but nothing ever called
|
|
347
|
-
// WebviewWindowBuilder for it. Build it here, after the popover
|
|
348
|
-
// exists, gated on the persisted `onboarding_complete` flag so
|
|
349
|
-
// returning users never see it again.
|
|
350
|
-
if !feature_config.onboarding_complete {
|
|
351
|
-
clips::show_onboarding_window(app.handle());
|
|
352
|
-
}
|
|
353
345
|
screen_memory::sync_from_config(app.handle(), &feature_config);
|
|
354
346
|
// Re-show always-on region guides after relaunch/reboot when the
|
|
355
347
|
// setting is on (no-op if a recording owns the window or the
|