@agent-native/core 0.178.0 → 0.178.1-nightly-20260909221943
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/clips/.agents/skills/dictate/SKILL.md +1 -0
- package/corpus/templates/clips/DESIGN.md +10 -7
- package/corpus/templates/clips/actions/list-organization-state.ts +56 -3
- package/corpus/templates/clips/actions/list-recordings.ts +2 -0
- package/corpus/templates/clips/actions/search-dictations.ts +81 -0
- package/corpus/templates/clips/app/components/agent-destination-logos.tsx +50 -0
- package/corpus/templates/clips/app/components/bug-report/bug-report-dialog.tsx +60 -0
- package/corpus/templates/clips/app/components/bug-report/bug-report-form.tsx +206 -0
- package/corpus/templates/clips/app/components/clips-command-menu.tsx +653 -0
- package/corpus/templates/clips/app/components/library/empty-state.tsx +52 -17
- package/corpus/templates/clips/app/components/library/folder-card.tsx +34 -0
- package/corpus/templates/clips/app/components/library/folder-tree.tsx +109 -64
- package/corpus/templates/clips/app/components/library/library-action-hrefs.ts +27 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +295 -103
- package/corpus/templates/clips/app/components/library/library-layout.tsx +381 -203
- package/corpus/templates/clips/app/components/library/library-primary-actions.tsx +48 -0
- package/corpus/templates/clips/app/components/library/page-header.tsx +48 -8
- package/corpus/templates/clips/app/components/library/recording-card.tsx +58 -55
- package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -19
- package/corpus/templates/clips/app/components/library/sidebar-feedback-button.tsx +48 -0
- package/corpus/templates/clips/app/components/player/comments-panel.tsx +2 -2
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +344 -260
- package/corpus/templates/clips/app/components/player/viewer-controls.tsx +2 -2
- package/corpus/templates/clips/app/components/recorder/camera-visualizer.tsx +0 -33
- package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -1
- package/corpus/templates/clips/app/components/ui/tabs.tsx +1 -1
- package/corpus/templates/clips/app/hooks/use-command-search.ts +53 -0
- package/corpus/templates/clips/app/hooks/use-navigation-state.ts +32 -13
- package/corpus/templates/clips/app/hooks/use-upload-video-picker.tsx +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +7 -0
- package/corpus/templates/clips/app/lib/agent-share.ts +16 -0
- package/corpus/templates/clips/app/lib/command-events.ts +7 -0
- package/corpus/templates/clips/app/root.tsx +6 -82
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +25 -5
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +2 -30
- package/corpus/templates/clips/app/routes/_app.library.folder.$folderId.tsx +13 -2
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +4 -17
- package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +111 -114
- package/corpus/templates/clips/app/routes/_app.spaces.$spaceId.folder.$folderId.tsx +25 -2
- package/corpus/templates/clips/app/routes/_app.spaces.$spaceId.tsx +14 -61
- package/corpus/templates/clips/app/routes/_app.spaces._index.tsx +34 -24
- package/corpus/templates/clips/app/routes/_app.trash.tsx +1 -1
- package/corpus/templates/clips/app/routes/_app.tsx +2 -4
- package/corpus/templates/clips/app/routes/bug-report.tsx +11 -189
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +148 -123
- package/corpus/templates/clips/changelog/2026-09-08-comments-and-desktop-window-controls.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-08-global-command-search.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-09-agent-sidebar-fits-below-toolbar.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-09-desktop-switches-stay-clear-in-dark-mode.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-09-recording-agent-uses-global-panel.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +2 -2
- package/corpus/templates/clips/desktop/src/components/MediaDeviceRow.tsx +5 -3
- package/corpus/templates/clips/desktop/src/components/SourceRow.tsx +1 -0
- package/corpus/templates/clips/desktop/src/components/Switch.tsx +2 -5
- package/corpus/templates/clips/desktop/src/components/ui/switch.tsx +21 -3
- package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +72 -52
- package/corpus/templates/clips/desktop/src/styles.css +18 -19
- package/corpus/templates/clips/desktop/src/tailwind.css +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +18 -10
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +3 -5
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +14 -3
- package/corpus/templates/design/AGENTS.md +2 -1
- package/corpus/templates/design/actions/export-png.ts +119 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +47 -13
- package/corpus/templates/design/server/plugins/agent-chat.ts +3 -1
- package/corpus/templates/factory/actions/dispatch-factory-item.ts +51 -22
- package/corpus/templates/factory/actions/list-triage-items.ts +21 -11
- package/corpus/templates/factory/actions/poll-slack-channel.ts +7 -2
- package/corpus/templates/factory/changelog/2026-09-09-slack-feedback-keeps-claimed-markers-after-poll.md +6 -0
- package/corpus/templates/factory/changelog/2026-09-09-slack-feedback-preserves-started-claimed-threads.md +6 -0
- package/corpus/templates/factory/changelog/2026-09-09-slack-feedback-skips-claimed-parents.md +6 -0
- package/corpus/templates/factory/server/lib/factory-automation-config.ts +1 -1
- package/corpus/templates/factory/server/lib/slack-feedback-prompt.ts +47 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +5 -2
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +5 -4
- package/corpus/templates/factory/server/triage/review-skill-alignment.ts +12 -7
- package/corpus/templates/factory/server/triage/slack-review-window.ts +39 -0
- package/dist/client/CommandMenu.js +13 -1
- package/dist/client/analytics.js +10 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/vite/client.js +25 -7
- package/dist/vite/sentry-source-maps.d.ts +12 -0
- package/dist/vite/sentry-source-maps.js +105 -0
- package/package.json +2 -1
|
@@ -85,7 +85,7 @@ export const ViewerTabsList = React.forwardRef<
|
|
|
85
85
|
ref={ref}
|
|
86
86
|
variant="line"
|
|
87
87
|
className={cn(
|
|
88
|
-
"h-10 w-full shrink-0 justify-start overflow-x-auto rounded-none
|
|
88
|
+
"h-10 min-h-10 w-fit max-w-full shrink-0 justify-start overflow-x-auto rounded-none px-3 py-0",
|
|
89
89
|
className,
|
|
90
90
|
)}
|
|
91
91
|
{...props}
|
|
@@ -100,7 +100,7 @@ export const ViewerTabsTrigger = React.forwardRef<
|
|
|
100
100
|
<TabsTrigger
|
|
101
101
|
ref={ref}
|
|
102
102
|
className={cn(
|
|
103
|
-
"h-10 min-w-0 rounded-none px-2 py-0 text-
|
|
103
|
+
"h-10 min-w-0 flex-none rounded-none px-2 py-0 text-sm data-[state=active]:after:bottom-0 data-[state=active]:after:inset-x-2",
|
|
104
104
|
className,
|
|
105
105
|
)}
|
|
106
106
|
{...props}
|
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
} from "react";
|
|
15
15
|
|
|
16
16
|
import { Button } from "@/components/ui/button";
|
|
17
|
-
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
18
17
|
import {
|
|
19
18
|
createBackgroundBlurStream,
|
|
20
19
|
DEFAULT_BLUR_PX,
|
|
@@ -35,7 +34,6 @@ export interface CameraVisualizerProps {
|
|
|
35
34
|
/** Background blur radius (px) reflected live in the test preview. */
|
|
36
35
|
blurRadius?: number;
|
|
37
36
|
size?: CameraBubbleSize;
|
|
38
|
-
onSizeChange?: (size: CameraBubbleSize) => void;
|
|
39
37
|
onStatusChange?: (
|
|
40
38
|
status: CameraTestStatus,
|
|
41
39
|
detail?: { error?: string | null },
|
|
@@ -49,12 +47,6 @@ const CAMERA_BUBBLE_SIZE_PX: Record<CameraBubbleSize, number> = {
|
|
|
49
47
|
lg: 320,
|
|
50
48
|
};
|
|
51
49
|
|
|
52
|
-
const CAMERA_SIZE_OPTIONS: Array<{ value: CameraBubbleSize; label: string }> = [
|
|
53
|
-
{ value: "sm", label: "S" },
|
|
54
|
-
{ value: "md", label: "M" },
|
|
55
|
-
{ value: "lg", label: "L" },
|
|
56
|
-
];
|
|
57
|
-
|
|
58
50
|
const CAMERA_FRAME_TIMEOUT_MS = 5_000;
|
|
59
51
|
|
|
60
52
|
type CameraPermissionState = PermissionState | "unknown";
|
|
@@ -190,7 +182,6 @@ export function CameraVisualizer({
|
|
|
190
182
|
blur = false,
|
|
191
183
|
blurRadius = DEFAULT_BLUR_PX,
|
|
192
184
|
size = "md",
|
|
193
|
-
onSizeChange,
|
|
194
185
|
onStatusChange,
|
|
195
186
|
onPreviewChange,
|
|
196
187
|
}: CameraVisualizerProps) {
|
|
@@ -527,30 +518,6 @@ export function CameraVisualizer({
|
|
|
527
518
|
)}
|
|
528
519
|
<span className="truncate">{statusLabel}</span>
|
|
529
520
|
</div>
|
|
530
|
-
<ToggleGroup
|
|
531
|
-
type="single"
|
|
532
|
-
value={size}
|
|
533
|
-
onValueChange={(value) => {
|
|
534
|
-
if (value) onSizeChange?.(value as CameraBubbleSize);
|
|
535
|
-
}}
|
|
536
|
-
variant="outline"
|
|
537
|
-
aria-label={t("cameraVisualizer.bubble")}
|
|
538
|
-
className="grid shrink-0 grid-cols-3 gap-0.5 rounded-md bg-muted p-0.5"
|
|
539
|
-
>
|
|
540
|
-
{CAMERA_SIZE_OPTIONS.map((option) => (
|
|
541
|
-
<ToggleGroupItem
|
|
542
|
-
key={option.value}
|
|
543
|
-
value={option.value}
|
|
544
|
-
disabled={disabled}
|
|
545
|
-
aria-label={t("cameraVisualizer.setBubbleSize", {
|
|
546
|
-
size: option.label,
|
|
547
|
-
})}
|
|
548
|
-
className="h-6 min-w-6 rounded border-0 px-1.5 text-[11px] text-muted-foreground shadow-none data-[state=on]:bg-background data-[state=on]:text-foreground data-[state=on]:shadow-sm"
|
|
549
|
-
>
|
|
550
|
-
{option.label}
|
|
551
|
-
</ToggleGroupItem>
|
|
552
|
-
))}
|
|
553
|
-
</ToggleGroup>
|
|
554
521
|
<Button
|
|
555
522
|
type="button"
|
|
556
523
|
variant={live ? "outline" : "secondary"}
|
|
@@ -630,7 +630,11 @@ export function PeopleAccessSection({
|
|
|
630
630
|
? first
|
|
631
631
|
: t("shareUi.othersCount", { count: rest.length, email: first })
|
|
632
632
|
}
|
|
633
|
-
meta={
|
|
633
|
+
meta={
|
|
634
|
+
first && (open || rest.length === 0)
|
|
635
|
+
? firstRole
|
|
636
|
+
: t("shareUi.canAccess")
|
|
637
|
+
}
|
|
634
638
|
disabled={sharesQuery.isLoading}
|
|
635
639
|
open={open}
|
|
636
640
|
onOpenChange={setOpen}
|
|
@@ -62,7 +62,7 @@ function TabsTrigger({
|
|
|
62
62
|
<TabsPrimitive.Trigger
|
|
63
63
|
data-slot="tabs-trigger"
|
|
64
64
|
className={cn(
|
|
65
|
-
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-
|
|
65
|
+
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none dark:text-muted-foreground dark:hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
66
66
|
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
|
|
67
67
|
"data-[state=active]:bg-background data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 dark:data-[state=active]:text-foreground",
|
|
68
68
|
"after:absolute after:bg-foreground after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
2
|
+
|
|
3
|
+
export interface MeetingCommandSearchHit {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
recordingId?: string | null;
|
|
7
|
+
scheduledStart?: string | null;
|
|
8
|
+
actualStart?: string | null;
|
|
9
|
+
snippet?: string | null;
|
|
10
|
+
matchType?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface DictationCommandSearchHit {
|
|
14
|
+
id: string;
|
|
15
|
+
fullText: string;
|
|
16
|
+
cleanedText?: string | null;
|
|
17
|
+
snippet?: string | null;
|
|
18
|
+
durationMs: number;
|
|
19
|
+
source: string;
|
|
20
|
+
targetApp?: string | null;
|
|
21
|
+
startedAt: string;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useMeetingCommandSearch(query: string) {
|
|
26
|
+
const trimmedQuery = query.trim();
|
|
27
|
+
return useActionQuery<{
|
|
28
|
+
query: string;
|
|
29
|
+
meetings: MeetingCommandSearchHit[];
|
|
30
|
+
}>(
|
|
31
|
+
"search-meetings",
|
|
32
|
+
trimmedQuery ? { query: trimmedQuery, limit: 8 } : undefined,
|
|
33
|
+
{
|
|
34
|
+
enabled: trimmedQuery.length >= 2,
|
|
35
|
+
retry: false,
|
|
36
|
+
},
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function useDictationCommandSearch(query: string) {
|
|
41
|
+
const trimmedQuery = query.trim();
|
|
42
|
+
return useActionQuery<{
|
|
43
|
+
query: string;
|
|
44
|
+
dictations: DictationCommandSearchHit[];
|
|
45
|
+
}>(
|
|
46
|
+
"search-dictations",
|
|
47
|
+
trimmedQuery ? { query: trimmedQuery, limit: 8 } : undefined,
|
|
48
|
+
{
|
|
49
|
+
enabled: trimmedQuery.length >= 2,
|
|
50
|
+
retry: false,
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { getBrowserTabId } from "@agent-native/core/client/hooks";
|
|
2
2
|
import { useAgentRouteState } from "@agent-native/core/client/navigation";
|
|
3
|
+
import {
|
|
4
|
+
AGENT_SIDEBAR_QUERY_PARAM,
|
|
5
|
+
AGENT_SIDEBAR_QUERY_VALUE_OPEN,
|
|
6
|
+
} from "@agent-native/core/shared";
|
|
3
7
|
|
|
4
8
|
import { parseTimeParam } from "@/lib/time-param";
|
|
5
9
|
|
|
@@ -100,19 +104,23 @@ export function stateFromLocation(
|
|
|
100
104
|
const recordingId = decodePathSegment(recordingMatch[1]);
|
|
101
105
|
if (!recordingId) return { view: "library" };
|
|
102
106
|
const panel = params.get("panel");
|
|
107
|
+
const agentSidebarOpen =
|
|
108
|
+
params.get(AGENT_SIDEBAR_QUERY_PARAM) === AGENT_SIDEBAR_QUERY_VALUE_OPEN;
|
|
103
109
|
const atParam = params.get("at") ?? params.get("t");
|
|
104
110
|
const atMs = atParam == null ? undefined : parseTimeParam(atParam);
|
|
105
111
|
return {
|
|
106
112
|
view: panel === "insights" ? "insights" : "recording",
|
|
107
113
|
recordingId,
|
|
108
|
-
...(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
...(agentSidebarOpen
|
|
115
|
+
? { panel: "agent" as const }
|
|
116
|
+
: panel === "comments" ||
|
|
117
|
+
panel === "transcript" ||
|
|
118
|
+
panel === "agent" ||
|
|
119
|
+
panel === "debug" ||
|
|
120
|
+
panel === "insights" ||
|
|
121
|
+
panel === "settings"
|
|
122
|
+
? { panel }
|
|
123
|
+
: {}),
|
|
116
124
|
...(Number.isFinite(atMs) && atMs! >= 0 ? { atMs } : {}),
|
|
117
125
|
...(searchTerm ? { search: searchTerm } : {}),
|
|
118
126
|
};
|
|
@@ -164,11 +172,13 @@ export function stateFromLocation(
|
|
|
164
172
|
};
|
|
165
173
|
}
|
|
166
174
|
|
|
167
|
-
// /dictate (optionally /dictate/:dictationId in the future)
|
|
175
|
+
// /dictate?dictationId=:dictationId (optionally /dictate/:dictationId in the future)
|
|
168
176
|
const dictateMatch = p.match(/^\/dictate(?:\/([^/]+))?$/);
|
|
169
177
|
if (dictateMatch) {
|
|
170
|
-
const
|
|
171
|
-
if (dictateMatch[1] && !
|
|
178
|
+
const pathDictationId = decodePathSegment(dictateMatch[1]);
|
|
179
|
+
if (dictateMatch[1] && !pathDictationId) return { view: "library" };
|
|
180
|
+
const queryDictationId = params.get("dictationId")?.trim() || undefined;
|
|
181
|
+
const dictationId = pathDictationId ?? queryDictationId;
|
|
172
182
|
return {
|
|
173
183
|
view: "dictate",
|
|
174
184
|
...(dictationId ? { dictationId } : {}),
|
|
@@ -210,7 +220,14 @@ export function pathFromCommand(cmd: NavigateCommand): string {
|
|
|
210
220
|
case "recording":
|
|
211
221
|
if (!cmd.recordingId) return "/library";
|
|
212
222
|
const recordingParams = new URLSearchParams();
|
|
213
|
-
if (cmd.panel
|
|
223
|
+
if (cmd.panel === "agent") {
|
|
224
|
+
recordingParams.set(
|
|
225
|
+
AGENT_SIDEBAR_QUERY_PARAM,
|
|
226
|
+
AGENT_SIDEBAR_QUERY_VALUE_OPEN,
|
|
227
|
+
);
|
|
228
|
+
} else if (cmd.panel) {
|
|
229
|
+
recordingParams.set("panel", cmd.panel);
|
|
230
|
+
}
|
|
214
231
|
if (typeof cmd.atMs === "number" && Number.isFinite(cmd.atMs)) {
|
|
215
232
|
// Viewer routes use the public `at` query parameter in seconds while
|
|
216
233
|
// navigation commands expose timestamps in milliseconds.
|
|
@@ -265,7 +282,9 @@ export function pathFromCommand(cmd: NavigateCommand): string {
|
|
|
265
282
|
? `/meetings/${encodeURIComponent(cmd.meetingId)}`
|
|
266
283
|
: "/meetings";
|
|
267
284
|
case "dictate":
|
|
268
|
-
return
|
|
285
|
+
return cmd.dictationId
|
|
286
|
+
? `/dictate?dictationId=${encodeURIComponent(cmd.dictationId)}`
|
|
287
|
+
: "/dictate";
|
|
269
288
|
case "library":
|
|
270
289
|
default:
|
|
271
290
|
if (cmd.folderId) {
|
|
@@ -64,6 +64,7 @@ const messages = {
|
|
|
64
64
|
extensions: "Extensions",
|
|
65
65
|
newRecording: "New recording",
|
|
66
66
|
folders: "Folders",
|
|
67
|
+
recordings: "Recordings",
|
|
67
68
|
newFolder: "New folder",
|
|
68
69
|
noSpaces: "No spaces yet",
|
|
69
70
|
desktopCta: "Get desktop app",
|
|
@@ -502,6 +503,11 @@ const messages = {
|
|
|
502
503
|
shareLink: "Share link",
|
|
503
504
|
shareWithHumans: "Share with humans",
|
|
504
505
|
shareWithAgents: "Share with agents",
|
|
506
|
+
people: "People",
|
|
507
|
+
agents: "Agents",
|
|
508
|
+
openInClaude: "Open in Claude",
|
|
509
|
+
openInClaudeCode: "Open in Claude Code",
|
|
510
|
+
openInCodex: "Open in Codex",
|
|
505
511
|
copyAgentPrompt: "Copy agent prompt",
|
|
506
512
|
agentPrompt:
|
|
507
513
|
"Fetch this Clips agent context URL: {{agentContextUrl}}. Use transcript.segments for spoken context, fetch recommendedFrames or the frame API URLs to see the screen, and check browserDiagnostics if present for redacted console logs and fetch/XHR request metadata.",
|
|
@@ -1707,6 +1713,7 @@ const messages = {
|
|
|
1707
1713
|
donePageTitle: "Bug report submitted · Clips",
|
|
1708
1714
|
eyebrow: "Bug report",
|
|
1709
1715
|
title: "Record a bug report",
|
|
1716
|
+
sidebarCta: "Send feedback",
|
|
1710
1717
|
description:
|
|
1711
1718
|
"Capture a short repro with screen, voice, and redacted browser context for your team.",
|
|
1712
1719
|
issueTitleLabel: "Issue title",
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type AgentShareDestination = "claude" | "claude-code" | "codex";
|
|
2
|
+
|
|
3
|
+
const AGENT_SHARE_DESTINATION_URLS: Record<AgentShareDestination, string> = {
|
|
4
|
+
claude: "claude://claude.ai/new",
|
|
5
|
+
"claude-code": "claude://code/new",
|
|
6
|
+
codex: "codex://threads/new",
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function buildAgentShareDeepLink(
|
|
10
|
+
destination: AgentShareDestination,
|
|
11
|
+
prompt: string,
|
|
12
|
+
): string {
|
|
13
|
+
const url = new URL(AGENT_SHARE_DESTINATION_URLS[destination]);
|
|
14
|
+
url.searchParams.set("q", prompt);
|
|
15
|
+
return url.toString();
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const OPEN_CREATE_FOLDER_EVENT = "clips:open-create-folder";
|
|
2
|
+
export const OPEN_CREATE_SPACE_EVENT = "clips:open-create-space";
|
|
3
|
+
export const OPEN_BUG_REPORT_EVENT = "clips:open-bug-report";
|
|
4
|
+
|
|
5
|
+
export function openBugReportDialog() {
|
|
6
|
+
window.dispatchEvent(new Event(OPEN_BUG_REPORT_EVENT));
|
|
7
|
+
}
|
|
@@ -13,22 +13,11 @@ import {
|
|
|
13
13
|
type LocalizationPreference,
|
|
14
14
|
useT,
|
|
15
15
|
} from "@agent-native/core/client/i18n";
|
|
16
|
-
import {
|
|
17
|
-
CommandMenu,
|
|
18
|
-
useCommandMenuShortcut,
|
|
19
|
-
} from "@agent-native/core/client/navigation";
|
|
20
16
|
import { getThemeInitScript } from "@agent-native/core/client/ui";
|
|
21
17
|
import { resolveLocaleFromRequest } from "@agent-native/core/server";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
IconHierarchy2,
|
|
25
|
-
IconCheck,
|
|
26
|
-
IconSun,
|
|
27
|
-
IconMoon,
|
|
28
|
-
} from "@tabler/icons-react";
|
|
18
|
+
import { IconCheck } from "@tabler/icons-react";
|
|
29
19
|
import { useQueryClient } from "@tanstack/react-query";
|
|
30
|
-
import {
|
|
31
|
-
import { useCallback, useEffect, useState } from "react";
|
|
20
|
+
import { useEffect, useState } from "react";
|
|
32
21
|
import {
|
|
33
22
|
Links,
|
|
34
23
|
Meta,
|
|
@@ -37,11 +26,12 @@ import {
|
|
|
37
26
|
ScrollRestoration,
|
|
38
27
|
useLoaderData,
|
|
39
28
|
useLocation,
|
|
40
|
-
useNavigate,
|
|
41
29
|
useRouteLoaderData,
|
|
42
30
|
} from "react-router";
|
|
43
31
|
import type { LinksFunction, LoaderFunctionArgs } from "react-router";
|
|
44
32
|
|
|
33
|
+
import { BugReportDialog } from "@/components/bug-report/bug-report-dialog";
|
|
34
|
+
import { ClipsCommandMenu } from "@/components/clips-command-menu";
|
|
45
35
|
import { Button } from "@/components/ui/button";
|
|
46
36
|
import {
|
|
47
37
|
Dialog,
|
|
@@ -55,9 +45,7 @@ import { Toaster } from "@/components/ui/sonner";
|
|
|
55
45
|
import { AppToolkitProvider } from "@/components/ui/toolkit-provider";
|
|
56
46
|
import { useNavigationState } from "@/hooks/use-navigation-state";
|
|
57
47
|
import { isStandalonePublicPath } from "@/lib/public-ssr-paths";
|
|
58
|
-
import { SEARCH_FOCUS_PATH } from "@/lib/search-focus";
|
|
59
48
|
|
|
60
|
-
import changelog from "../CHANGELOG.md?raw";
|
|
61
49
|
import { i18nCatalog, loadI18nMessages } from "./i18n";
|
|
62
50
|
|
|
63
51
|
import stylesheet from "./global.css?url";
|
|
@@ -200,21 +188,6 @@ function DbSyncSetup() {
|
|
|
200
188
|
return null;
|
|
201
189
|
}
|
|
202
190
|
|
|
203
|
-
function ThemeToggleItem() {
|
|
204
|
-
const { resolvedTheme, setTheme } = useTheme();
|
|
205
|
-
const t = useT();
|
|
206
|
-
const isDark = resolvedTheme === "dark";
|
|
207
|
-
return (
|
|
208
|
-
<CommandMenu.Item
|
|
209
|
-
onSelect={() => setTheme(isDark ? "light" : "dark")}
|
|
210
|
-
keywords={["theme", "dark", "light", "mode"]}
|
|
211
|
-
>
|
|
212
|
-
{isDark ? <IconSun size={16} /> : <IconMoon size={16} />}
|
|
213
|
-
{t("root.toggleTheme")}
|
|
214
|
-
</CommandMenu.Item>
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
191
|
type ExternalChromeRuntime = {
|
|
219
192
|
lastError?: { message?: string };
|
|
220
193
|
sendMessage: (
|
|
@@ -224,29 +197,6 @@ type ExternalChromeRuntime = {
|
|
|
224
197
|
) => void;
|
|
225
198
|
};
|
|
226
199
|
|
|
227
|
-
const CLIPS_COMMAND_DOCS = [
|
|
228
|
-
{
|
|
229
|
-
title: "Use the Chrome extension for browser logs",
|
|
230
|
-
description:
|
|
231
|
-
"Record a browser tab with redacted console logs, JavaScript exceptions, and fetch/XHR diagnostics.",
|
|
232
|
-
href: docsUrl("template-clips-capture-everywhere", {
|
|
233
|
-
hash: "browser-logs-with-the-chrome-extension",
|
|
234
|
-
}),
|
|
235
|
-
keywords: [
|
|
236
|
-
"logs",
|
|
237
|
-
"browser logs",
|
|
238
|
-
"developer logs",
|
|
239
|
-
"console logs",
|
|
240
|
-
"network logs",
|
|
241
|
-
"fetch",
|
|
242
|
-
"xhr",
|
|
243
|
-
"diagnostics",
|
|
244
|
-
"chrome extension",
|
|
245
|
-
"recording",
|
|
246
|
-
],
|
|
247
|
-
},
|
|
248
|
-
] satisfies React.ComponentProps<typeof CommandMenu.DocsGroup>["docs"];
|
|
249
|
-
|
|
250
200
|
function ClipsExtensionAuthBridge() {
|
|
251
201
|
const location = useLocation();
|
|
252
202
|
const t = useT();
|
|
@@ -336,43 +286,17 @@ function AppContent() {
|
|
|
336
286
|
|
|
337
287
|
function PrivateAppContent() {
|
|
338
288
|
const location = useLocation();
|
|
339
|
-
const navigate = useNavigate();
|
|
340
|
-
const t = useT();
|
|
341
289
|
const standalonePublic = isStandalonePublicPath(location.pathname);
|
|
342
290
|
const [cmdkOpen, setCmdkOpen] = useState(false);
|
|
343
|
-
useCommandMenuShortcut(
|
|
344
|
-
useCallback(() => {
|
|
345
|
-
if (!standalonePublic) setCmdkOpen(true);
|
|
346
|
-
}, [standalonePublic]),
|
|
347
|
-
);
|
|
348
291
|
|
|
349
292
|
return (
|
|
350
293
|
<>
|
|
351
294
|
{standalonePublic ? null : <DbSyncSetup />}
|
|
352
295
|
{standalonePublic ? null : <ClipsExtensionAuthBridge />}
|
|
353
296
|
{standalonePublic ? null : (
|
|
354
|
-
<
|
|
355
|
-
open={cmdkOpen}
|
|
356
|
-
onOpenChange={setCmdkOpen}
|
|
357
|
-
changelog={changelog}
|
|
358
|
-
changelogLabel={t("settings.whatsNew")}
|
|
359
|
-
changelogKey="clips"
|
|
360
|
-
>
|
|
361
|
-
<CommandMenu.Group heading={t("root.commandActions")}>
|
|
362
|
-
<CommandMenu.Item onSelect={() => navigate("/settings/agent")}>
|
|
363
|
-
<IconHierarchy2 size={16} />
|
|
364
|
-
{t("root.openAgent")}
|
|
365
|
-
</CommandMenu.Item>
|
|
366
|
-
<CommandMenu.Item onSelect={() => navigate(SEARCH_FOCUS_PATH)}>
|
|
367
|
-
{t("root.commandSearch")}
|
|
368
|
-
</CommandMenu.Item>
|
|
369
|
-
</CommandMenu.Group>
|
|
370
|
-
<CommandMenu.DocsGroup docs={CLIPS_COMMAND_DOCS} />
|
|
371
|
-
<CommandMenu.Group heading={t("root.commandAppearance")}>
|
|
372
|
-
<ThemeToggleItem />
|
|
373
|
-
</CommandMenu.Group>
|
|
374
|
-
</CommandMenu>
|
|
297
|
+
<ClipsCommandMenu open={cmdkOpen} onOpenChange={setCmdkOpen} />
|
|
375
298
|
)}
|
|
299
|
+
{standalonePublic ? null : <BugReportDialog />}
|
|
376
300
|
{standalonePublic ? null : <DevOverlay />}
|
|
377
301
|
<Outlet />
|
|
378
302
|
</>
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
} from "@tabler/icons-react";
|
|
21
21
|
import { useQueryClient } from "@tanstack/react-query";
|
|
22
22
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
23
|
-
import { Navigate } from "react-router";
|
|
23
|
+
import { Navigate, useSearchParams } from "react-router";
|
|
24
24
|
import { toast } from "sonner";
|
|
25
25
|
|
|
26
26
|
import { CaptureInstallButton } from "@/components/capture-install-options";
|
|
@@ -393,9 +393,16 @@ function WebDictationPanel({
|
|
|
393
393
|
);
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
function DictationRow({
|
|
396
|
+
function DictationRow({
|
|
397
|
+
dictation,
|
|
398
|
+
initialExpanded = false,
|
|
399
|
+
}: {
|
|
400
|
+
dictation: Dictation;
|
|
401
|
+
initialExpanded?: boolean;
|
|
402
|
+
}) {
|
|
397
403
|
const t = useT();
|
|
398
|
-
const [expanded, setExpanded] = useState(
|
|
404
|
+
const [expanded, setExpanded] = useState(initialExpanded);
|
|
405
|
+
const rowRef = useRef<HTMLDivElement>(null);
|
|
399
406
|
const qc = useQueryClient();
|
|
400
407
|
const cleanup = useActionMutation<any, { id: string }>("cleanup-dictation");
|
|
401
408
|
const replaceOriginal = useActionMutation<
|
|
@@ -404,6 +411,12 @@ function DictationRow({ dictation }: { dictation: Dictation }) {
|
|
|
404
411
|
>("update-dictation");
|
|
405
412
|
const { label, icon } = sourceMeta(dictation.source, t);
|
|
406
413
|
|
|
414
|
+
useEffect(() => {
|
|
415
|
+
if (!initialExpanded) return;
|
|
416
|
+
setExpanded(true);
|
|
417
|
+
rowRef.current?.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
418
|
+
}, [initialExpanded]);
|
|
419
|
+
|
|
407
420
|
const preview = (dictation.cleanedText || dictation.fullText || "").slice(
|
|
408
421
|
0,
|
|
409
422
|
140,
|
|
@@ -458,6 +471,7 @@ function DictationRow({ dictation }: { dictation: Dictation }) {
|
|
|
458
471
|
|
|
459
472
|
return (
|
|
460
473
|
<div
|
|
474
|
+
ref={rowRef}
|
|
461
475
|
className={cn(
|
|
462
476
|
"border-b border-border last:border-b-0 cursor-pointer",
|
|
463
477
|
expanded ? "bg-accent/20" : "hover:bg-accent/10",
|
|
@@ -721,6 +735,8 @@ function DictateEmptyState({
|
|
|
721
735
|
export default function DictateRoute() {
|
|
722
736
|
const experiment = useExperimentState(CLIPS_WISPRFLOW.key);
|
|
723
737
|
const t = useT();
|
|
738
|
+
const [searchParams] = useSearchParams();
|
|
739
|
+
const selectedDictationId = searchParams.get("dictationId");
|
|
724
740
|
const { isDesktopApp } = useDesktopPromo();
|
|
725
741
|
const [filter, setFilter] = useState<SourceFilter>("all");
|
|
726
742
|
const [listening, setListening] = useState(false);
|
|
@@ -975,7 +991,7 @@ export default function DictateRoute() {
|
|
|
975
991
|
return (
|
|
976
992
|
<>
|
|
977
993
|
<PageHeader>
|
|
978
|
-
<PageBreadcrumb
|
|
994
|
+
<PageBreadcrumb items={[{ label: t("navigation.dictate") }]} />
|
|
979
995
|
<VocabularyManager />
|
|
980
996
|
</PageHeader>
|
|
981
997
|
<div className="mx-auto w-full max-w-4xl px-4 py-5 sm:px-6 sm:py-6">
|
|
@@ -1045,7 +1061,11 @@ export default function DictateRoute() {
|
|
|
1045
1061
|
</div>
|
|
1046
1062
|
<div>
|
|
1047
1063
|
{items.map((d) => (
|
|
1048
|
-
<DictationRow
|
|
1064
|
+
<DictationRow
|
|
1065
|
+
key={d.id}
|
|
1066
|
+
dictation={d}
|
|
1067
|
+
initialExpanded={d.id === selectedDictationId}
|
|
1068
|
+
/>
|
|
1049
1069
|
))}
|
|
1050
1070
|
</div>
|
|
1051
1071
|
</div>
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
-
import { IconVideoPlus } from "@tabler/icons-react";
|
|
3
|
-
import { NavLink } from "react-router";
|
|
4
2
|
|
|
5
|
-
import { ImportMenu } from "@/components/import-menu";
|
|
6
3
|
import { LibraryGrid } from "@/components/library/library-grid";
|
|
7
|
-
import {
|
|
8
|
-
PageHeaderActionGroup,
|
|
9
|
-
PageHeaderPrimaryAction,
|
|
10
|
-
} from "@/components/library/page-header";
|
|
4
|
+
import { LibraryPrimaryActions } from "@/components/library/library-primary-actions";
|
|
11
5
|
|
|
12
6
|
const SEO_TITLE = "Clips - Open Source screen recorder";
|
|
13
7
|
const SEO_DESCRIPTION =
|
|
@@ -33,29 +27,7 @@ export default function LibraryIndexRoute() {
|
|
|
33
27
|
view="library"
|
|
34
28
|
folderId={null}
|
|
35
29
|
title={t("navigation.library")}
|
|
36
|
-
extraActions={
|
|
37
|
-
<PageHeaderActionGroup>
|
|
38
|
-
<PageHeaderPrimaryAction asChild>
|
|
39
|
-
<NavLink to="/record" aria-label={t("navigation.newRecording")}>
|
|
40
|
-
<IconVideoPlus />
|
|
41
|
-
<span className="hidden sm:inline">
|
|
42
|
-
{t("navigation.newRecording")}
|
|
43
|
-
</span>
|
|
44
|
-
</NavLink>
|
|
45
|
-
</PageHeaderPrimaryAction>
|
|
46
|
-
<ImportMenu
|
|
47
|
-
uploadHref="/record?autoUpload=1"
|
|
48
|
-
importLoomHref="/import"
|
|
49
|
-
iconOnly
|
|
50
|
-
triggerIcon="chevron"
|
|
51
|
-
size="sm"
|
|
52
|
-
variant="default"
|
|
53
|
-
className="w-8 self-stretch border-s border-primary-foreground/20 px-0 shadow-none"
|
|
54
|
-
menuSide="bottom"
|
|
55
|
-
menuAlign="end"
|
|
56
|
-
/>
|
|
57
|
-
</PageHeaderActionGroup>
|
|
58
|
-
}
|
|
30
|
+
extraActions={<LibraryPrimaryActions />}
|
|
59
31
|
/>
|
|
60
32
|
);
|
|
61
33
|
}
|
|
@@ -3,7 +3,8 @@ import { useMemo } from "react";
|
|
|
3
3
|
import { useParams } from "react-router";
|
|
4
4
|
|
|
5
5
|
import { LibraryGrid } from "@/components/library/library-grid";
|
|
6
|
-
import {
|
|
6
|
+
import { LibraryPrimaryActions } from "@/components/library/library-primary-actions";
|
|
7
|
+
import { useFolders, useOrganizations } from "@/hooks/use-library";
|
|
7
8
|
import enMessages from "@/i18n/en-US";
|
|
8
9
|
|
|
9
10
|
export function meta() {
|
|
@@ -14,7 +15,12 @@ export default function LibraryFolderRoute() {
|
|
|
14
15
|
const t = useT();
|
|
15
16
|
const { folderId } = useParams<{ folderId: string }>();
|
|
16
17
|
|
|
17
|
-
const { data:
|
|
18
|
+
const { data: organizations } = useOrganizations();
|
|
19
|
+
const currentOrganizationId =
|
|
20
|
+
organizations?.currentId ?? organizations?.organizations?.[0]?.id;
|
|
21
|
+
const { data: folders } = useFolders({
|
|
22
|
+
organizationId: currentOrganizationId,
|
|
23
|
+
});
|
|
18
24
|
const folder = useMemo(
|
|
19
25
|
() =>
|
|
20
26
|
(folders?.folders ?? []).find((f: any) => f.id === folderId) as
|
|
@@ -29,6 +35,11 @@ export default function LibraryFolderRoute() {
|
|
|
29
35
|
folderId={folderId}
|
|
30
36
|
emptyKind="folder"
|
|
31
37
|
title={folder?.name ?? t("navigation.folder")}
|
|
38
|
+
breadcrumbItems={[
|
|
39
|
+
{ label: t("navigation.library"), to: "/library" },
|
|
40
|
+
{ label: folder?.name ?? t("navigation.folder") },
|
|
41
|
+
]}
|
|
42
|
+
extraActions={<LibraryPrimaryActions folderId={folderId} />}
|
|
32
43
|
/>
|
|
33
44
|
);
|
|
34
45
|
}
|
|
@@ -603,21 +603,8 @@ function MeetingsHeader({
|
|
|
603
603
|
|
|
604
604
|
useEffect(() => {
|
|
605
605
|
const onKeyDown = (event: KeyboardEvent) => {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if (
|
|
609
|
-
event.key === "/" &&
|
|
610
|
-
!event.metaKey &&
|
|
611
|
-
!event.ctrlKey &&
|
|
612
|
-
!event.altKey &&
|
|
613
|
-
tagName !== "input" &&
|
|
614
|
-
tagName !== "textarea" &&
|
|
615
|
-
!target?.isContentEditable
|
|
616
|
-
) {
|
|
617
|
-
event.preventDefault();
|
|
618
|
-
inputRef.current?.focus();
|
|
619
|
-
inputRef.current?.select();
|
|
620
|
-
}
|
|
606
|
+
if (event.key !== "Escape") return;
|
|
607
|
+
inputRef.current?.blur();
|
|
621
608
|
};
|
|
622
609
|
|
|
623
610
|
window.addEventListener("keydown", onKeyDown);
|
|
@@ -628,7 +615,7 @@ function MeetingsHeader({
|
|
|
628
615
|
<PageHeader>
|
|
629
616
|
<div className="flex min-w-0 flex-1 items-center gap-3 lg:grid lg:grid-cols-[minmax(0,1fr)_24rem_minmax(0,1fr)]">
|
|
630
617
|
<div className="hidden min-w-0 lg:block">
|
|
631
|
-
<PageBreadcrumb
|
|
618
|
+
<PageBreadcrumb items={[{ label: t("meetingsRoute.title") }]} />
|
|
632
619
|
</div>
|
|
633
620
|
<div className="relative min-w-0 flex-1 lg:w-full">
|
|
634
621
|
<IconSearch className="pointer-events-none absolute start-2.5 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground" />
|
|
@@ -660,7 +647,7 @@ function MeetingsHeader({
|
|
|
660
647
|
aria-hidden="true"
|
|
661
648
|
className="absolute end-1.5 top-1/2 h-5 -translate-y-1/2 px-1 font-mono text-[10px]"
|
|
662
649
|
>
|
|
663
|
-
{shortcutLabel("
|
|
650
|
+
{shortcutLabel("cmd+k")}
|
|
664
651
|
</Kbd>
|
|
665
652
|
)}
|
|
666
653
|
</div>
|