@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.
Files changed (88) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/clips/.agents/skills/dictate/SKILL.md +1 -0
  3. package/corpus/templates/clips/DESIGN.md +10 -7
  4. package/corpus/templates/clips/actions/list-organization-state.ts +56 -3
  5. package/corpus/templates/clips/actions/list-recordings.ts +2 -0
  6. package/corpus/templates/clips/actions/search-dictations.ts +81 -0
  7. package/corpus/templates/clips/app/components/agent-destination-logos.tsx +50 -0
  8. package/corpus/templates/clips/app/components/bug-report/bug-report-dialog.tsx +60 -0
  9. package/corpus/templates/clips/app/components/bug-report/bug-report-form.tsx +206 -0
  10. package/corpus/templates/clips/app/components/clips-command-menu.tsx +653 -0
  11. package/corpus/templates/clips/app/components/library/empty-state.tsx +52 -17
  12. package/corpus/templates/clips/app/components/library/folder-card.tsx +34 -0
  13. package/corpus/templates/clips/app/components/library/folder-tree.tsx +109 -64
  14. package/corpus/templates/clips/app/components/library/library-action-hrefs.ts +27 -0
  15. package/corpus/templates/clips/app/components/library/library-grid.tsx +295 -103
  16. package/corpus/templates/clips/app/components/library/library-layout.tsx +381 -203
  17. package/corpus/templates/clips/app/components/library/library-primary-actions.tsx +48 -0
  18. package/corpus/templates/clips/app/components/library/page-header.tsx +48 -8
  19. package/corpus/templates/clips/app/components/library/recording-card.tsx +58 -55
  20. package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -19
  21. package/corpus/templates/clips/app/components/library/sidebar-feedback-button.tsx +48 -0
  22. package/corpus/templates/clips/app/components/player/comments-panel.tsx +2 -2
  23. package/corpus/templates/clips/app/components/player/share-dialog.tsx +344 -260
  24. package/corpus/templates/clips/app/components/player/viewer-controls.tsx +2 -2
  25. package/corpus/templates/clips/app/components/recorder/camera-visualizer.tsx +0 -33
  26. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +5 -1
  27. package/corpus/templates/clips/app/components/ui/tabs.tsx +1 -1
  28. package/corpus/templates/clips/app/hooks/use-command-search.ts +53 -0
  29. package/corpus/templates/clips/app/hooks/use-navigation-state.ts +32 -13
  30. package/corpus/templates/clips/app/hooks/use-upload-video-picker.tsx +1 -0
  31. package/corpus/templates/clips/app/i18n/en-US.ts +7 -0
  32. package/corpus/templates/clips/app/lib/agent-share.ts +16 -0
  33. package/corpus/templates/clips/app/lib/command-events.ts +7 -0
  34. package/corpus/templates/clips/app/root.tsx +6 -82
  35. package/corpus/templates/clips/app/routes/_app.dictate.tsx +25 -5
  36. package/corpus/templates/clips/app/routes/_app.library._index.tsx +2 -30
  37. package/corpus/templates/clips/app/routes/_app.library.folder.$folderId.tsx +13 -2
  38. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +4 -17
  39. package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +111 -114
  40. package/corpus/templates/clips/app/routes/_app.spaces.$spaceId.folder.$folderId.tsx +25 -2
  41. package/corpus/templates/clips/app/routes/_app.spaces.$spaceId.tsx +14 -61
  42. package/corpus/templates/clips/app/routes/_app.spaces._index.tsx +34 -24
  43. package/corpus/templates/clips/app/routes/_app.trash.tsx +1 -1
  44. package/corpus/templates/clips/app/routes/_app.tsx +2 -4
  45. package/corpus/templates/clips/app/routes/bug-report.tsx +11 -189
  46. package/corpus/templates/clips/app/routes/share.$shareId.tsx +148 -123
  47. package/corpus/templates/clips/changelog/2026-09-08-comments-and-desktop-window-controls.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-09-08-global-command-search.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-09-09-agent-sidebar-fits-below-toolbar.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-09-09-desktop-switches-stay-clear-in-dark-mode.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-09-09-recording-agent-uses-global-panel.md +6 -0
  52. package/corpus/templates/clips/desktop/src/app.tsx +2 -2
  53. package/corpus/templates/clips/desktop/src/components/MediaDeviceRow.tsx +5 -3
  54. package/corpus/templates/clips/desktop/src/components/SourceRow.tsx +1 -0
  55. package/corpus/templates/clips/desktop/src/components/Switch.tsx +2 -5
  56. package/corpus/templates/clips/desktop/src/components/ui/switch.tsx +21 -3
  57. package/corpus/templates/clips/desktop/src/hooks/useMediaDevices.ts +72 -52
  58. package/corpus/templates/clips/desktop/src/styles.css +18 -19
  59. package/corpus/templates/clips/desktop/src/tailwind.css +3 -0
  60. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +18 -10
  61. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +3 -5
  62. package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +14 -3
  63. package/corpus/templates/design/AGENTS.md +2 -1
  64. package/corpus/templates/design/actions/export-png.ts +119 -0
  65. package/corpus/templates/design/actions/take-design-screenshot.ts +47 -13
  66. package/corpus/templates/design/server/plugins/agent-chat.ts +3 -1
  67. package/corpus/templates/factory/actions/dispatch-factory-item.ts +51 -22
  68. package/corpus/templates/factory/actions/list-triage-items.ts +21 -11
  69. package/corpus/templates/factory/actions/poll-slack-channel.ts +7 -2
  70. package/corpus/templates/factory/changelog/2026-09-09-slack-feedback-keeps-claimed-markers-after-poll.md +6 -0
  71. package/corpus/templates/factory/changelog/2026-09-09-slack-feedback-preserves-started-claimed-threads.md +6 -0
  72. package/corpus/templates/factory/changelog/2026-09-09-slack-feedback-skips-claimed-parents.md +6 -0
  73. package/corpus/templates/factory/server/lib/factory-automation-config.ts +1 -1
  74. package/corpus/templates/factory/server/lib/slack-feedback-prompt.ts +47 -0
  75. package/corpus/templates/factory/server/plugins/agent-chat.ts +5 -2
  76. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +5 -4
  77. package/corpus/templates/factory/server/triage/review-skill-alignment.ts +12 -7
  78. package/corpus/templates/factory/server/triage/slack-review-window.ts +39 -0
  79. package/dist/client/CommandMenu.js +13 -1
  80. package/dist/client/analytics.js +10 -0
  81. package/dist/collab/routes.d.ts +1 -1
  82. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  83. package/dist/notifications/routes.d.ts +2 -2
  84. package/dist/observability/routes.d.ts +5 -5
  85. package/dist/vite/client.js +25 -7
  86. package/dist/vite/sentry-source-maps.d.ts +12 -0
  87. package/dist/vite/sentry-source-maps.js +105 -0
  88. package/package.json +2 -1
@@ -6,7 +6,8 @@ import {
6
6
  IconArchive,
7
7
  IconTrash,
8
8
  } from "@tabler/icons-react";
9
- import { useNavigate } from "react-router";
9
+ import type { ComponentType, ReactNode } from "react";
10
+ import { Link, useNavigate } from "react-router";
10
11
 
11
12
  import { Button } from "@/components/ui/button";
12
13
  import {
@@ -38,6 +39,40 @@ const ICONS: Record<EmptyKind, React.ComponentType<{ className?: string }>> = {
38
39
  };
39
40
 
40
41
  const CTA_KINDS = new Set<EmptyKind>(["library", "folder", "space"]);
42
+ const BACK_TO_LIBRARY_KINDS = new Set<EmptyKind>([
43
+ "shared",
44
+ "archive",
45
+ "trash",
46
+ ]);
47
+
48
+ interface AppEmptyStateProps {
49
+ icon: ComponentType<{ className?: string }>;
50
+ title: ReactNode;
51
+ description?: ReactNode;
52
+ content?: ReactNode;
53
+ }
54
+
55
+ export function AppEmptyState({
56
+ icon: Icon,
57
+ title,
58
+ description,
59
+ content,
60
+ }: AppEmptyStateProps) {
61
+ return (
62
+ <Empty className="min-h-64 px-6 py-12 md:p-12">
63
+ <EmptyHeader>
64
+ <EmptyMedia variant="icon">
65
+ <Icon />
66
+ </EmptyMedia>
67
+ <EmptyTitle>{title}</EmptyTitle>
68
+ {description ? (
69
+ <EmptyDescription>{description}</EmptyDescription>
70
+ ) : null}
71
+ </EmptyHeader>
72
+ {content ? <EmptyContent>{content}</EmptyContent> : null}
73
+ </Empty>
74
+ );
75
+ }
41
76
 
42
77
  interface EmptyStateProps {
43
78
  kind: EmptyKind;
@@ -69,22 +104,22 @@ export function EmptyState({
69
104
  }
70
105
  };
71
106
 
107
+ const content = hasCta ? (
108
+ <Button onClick={handleCta} size="sm">
109
+ {t(`empty.${kind}.cta`)}
110
+ </Button>
111
+ ) : BACK_TO_LIBRARY_KINDS.has(kind) ? (
112
+ <Button asChild size="sm" variant="outline">
113
+ <Link to="/library">{t("recordingPage.backToLibrary")}</Link>
114
+ </Button>
115
+ ) : null;
116
+
72
117
  return (
73
- <Empty className="min-h-full rounded-none py-20">
74
- <EmptyHeader>
75
- <EmptyMedia variant="icon">
76
- <Icon />
77
- </EmptyMedia>
78
- <EmptyTitle>{t(`empty.${kind}.title`)}</EmptyTitle>
79
- <EmptyDescription>{t(`empty.${kind}.body`)}</EmptyDescription>
80
- </EmptyHeader>
81
- {hasCta ? (
82
- <EmptyContent>
83
- <Button onClick={handleCta} size="sm">
84
- {t(`empty.${kind}.cta`)}
85
- </Button>
86
- </EmptyContent>
87
- ) : null}
88
- </Empty>
118
+ <AppEmptyState
119
+ icon={Icon}
120
+ title={t(`empty.${kind}.title`)}
121
+ description={t(`empty.${kind}.body`)}
122
+ content={content}
123
+ />
89
124
  );
90
125
  }
@@ -0,0 +1,34 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import { IconFolderOpen } from "@tabler/icons-react";
3
+ import { Link } from "react-router";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ interface FolderCardProps {
8
+ folder: {
9
+ id: string;
10
+ name: string;
11
+ };
12
+ href: string;
13
+ }
14
+
15
+ export function FolderCard({ folder, href }: FolderCardProps) {
16
+ const t = useT();
17
+
18
+ return (
19
+ <Link
20
+ to={href}
21
+ aria-label={`${folder.name} — ${t("navigation.folder")}`}
22
+ className={cn(
23
+ "group flex h-14 min-w-0 items-center gap-3 rounded-lg border border-border bg-card px-3.5 py-2.5 text-start",
24
+ "shadow-[0_1px_2px_rgba(15,23,42,0.04)] transition-colors hover:border-primary/40 hover:bg-accent/20",
25
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
26
+ )}
27
+ >
28
+ <IconFolderOpen className="size-5 shrink-0 text-muted-foreground transition-transform group-hover:scale-105 motion-reduce:transition-none" />
29
+ <span className="min-w-0 truncate text-sm font-medium text-foreground">
30
+ {folder.name}
31
+ </span>
32
+ </Link>
33
+ );
34
+ }
@@ -53,6 +53,7 @@ export interface FolderNode {
53
53
  parentId: string | null;
54
54
  spaceId: string | null;
55
55
  name: string;
56
+ recordingCount?: number;
56
57
  children?: FolderNode[];
57
58
  }
58
59
 
@@ -80,6 +81,8 @@ interface FolderTreeProps {
80
81
  /** Build the URL for a folder — allows library or space-scoped trees. */
81
82
  buildPath: (folderId: string) => string;
82
83
  activeFolderId?: string | null;
84
+ /** Use the single-indent spacing expected by a sidebar submenu. */
85
+ compact?: boolean;
83
86
  }
84
87
 
85
88
  export function FolderTree({
@@ -88,6 +91,7 @@ export function FolderTree({
88
91
  spaceId = null,
89
92
  buildPath,
90
93
  activeFolderId,
94
+ compact = false,
91
95
  }: FolderTreeProps) {
92
96
  const t = useT();
93
97
  const tree = useMemo(() => buildTree(folders), [folders]);
@@ -111,6 +115,7 @@ export function FolderTree({
111
115
  activeFolderId={activeFolderId}
112
116
  organizationId={organizationId}
113
117
  spaceId={spaceId}
118
+ compact={compact}
114
119
  />
115
120
  ))}
116
121
  </ul>
@@ -124,6 +129,7 @@ interface FolderItemProps {
124
129
  activeFolderId?: string | null;
125
130
  organizationId?: string;
126
131
  spaceId?: string | null;
132
+ compact: boolean;
127
133
  }
128
134
 
129
135
  function FolderItem({
@@ -133,6 +139,7 @@ function FolderItem({
133
139
  activeFolderId,
134
140
  organizationId,
135
141
  spaceId,
142
+ compact,
136
143
  }: FolderItemProps) {
137
144
  const t = useT();
138
145
  const [open, setOpen] = useState(true);
@@ -159,85 +166,122 @@ function FolderItem({
159
166
  "group flex items-center gap-1 rounded px-1.5 py-1 text-xs",
160
167
  isActive
161
168
  ? "bg-primary/10 text-primary"
162
- : "text-foreground hover:bg-accent/60",
169
+ : "text-primary hover:bg-accent/60",
163
170
  )}
164
- style={{ paddingInlineStart: 6 + depth * 12 }}
171
+ style={{
172
+ paddingInlineStart: compact ? 8 + depth * 12 : 6 + depth * 12,
173
+ }}
165
174
  >
166
- <CollapsibleTrigger asChild disabled={!hasChildren}>
167
- <button
168
- type="button"
169
- className={cn(
170
- "rounded p-0.5 text-muted-foreground",
171
- !hasChildren && "invisible",
172
- )}
173
- onClick={(e) => e.stopPropagation()}
174
- aria-label={`${t(open ? "settings.collapse" : "settings.expand")}: ${node.name}`}
175
- >
176
- <IconChevronRight
175
+ {!compact && (
176
+ <CollapsibleTrigger asChild disabled={!hasChildren}>
177
+ <button
178
+ type="button"
177
179
  className={cn(
178
- "h-3 w-3 transition-transform motion-reduce:transition-none rtl:-scale-x-100",
179
- open && "rotate-90",
180
+ "rounded p-0.5 text-primary",
181
+ !hasChildren && "invisible",
180
182
  )}
181
- />
182
- </button>
183
- </CollapsibleTrigger>
183
+ onClick={(e) => e.stopPropagation()}
184
+ aria-label={`${t(open ? "settings.collapse" : "settings.expand")}: ${node.name}`}
185
+ >
186
+ <IconChevronRight
187
+ className={cn(
188
+ "h-3 w-3 transition-transform motion-reduce:transition-none rtl:-scale-x-100",
189
+ open && "rotate-90",
190
+ )}
191
+ />
192
+ </button>
193
+ </CollapsibleTrigger>
194
+ )}
184
195
  <NavLink
185
196
  to={buildPath(node.id)}
186
- className="flex min-w-0 flex-1 items-center gap-1.5"
187
- >
188
- {open && hasChildren ? (
189
- <IconFolderOpen className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
190
- ) : (
191
- <IconFolder className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
197
+ className={cn(
198
+ "flex min-w-0 flex-1 items-center",
199
+ compact ? "gap-0" : "gap-1.5",
192
200
  )}
201
+ >
202
+ {!compact &&
203
+ (open && hasChildren ? (
204
+ <IconFolderOpen className="h-3.5 w-3.5 shrink-0 text-primary" />
205
+ ) : (
206
+ <IconFolder className="h-3.5 w-3.5 shrink-0 text-primary" />
207
+ ))}
193
208
  <span className="truncate" title={node.name}>
194
209
  {node.name}
195
210
  </span>
196
211
  </NavLink>
197
- <DropdownMenu>
198
- <DropdownMenuTrigger asChild>
212
+ {compact && hasChildren && (
213
+ <CollapsibleTrigger asChild>
199
214
  <button
200
215
  type="button"
201
- aria-label={`${node.name}: ${t("root.commandActions")}`}
202
- title={`${node.name}: ${t("root.commandActions")}`}
203
- className="rounded p-0.5 text-muted-foreground opacity-0 transition-opacity hover:bg-accent hover:text-foreground focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100"
216
+ className="rounded p-0.5 text-primary hover:bg-accent focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
217
+ onClick={(e) => e.stopPropagation()}
218
+ aria-label={`${t(open ? "settings.collapse" : "settings.expand")}: ${node.name}`}
204
219
  >
205
- <IconDots className="h-3.5 w-3.5" />
220
+ <IconChevronRight
221
+ className={cn(
222
+ "h-3 w-3 transition-transform motion-reduce:transition-none rtl:-scale-x-100",
223
+ open && "rotate-90",
224
+ )}
225
+ />
206
226
  </button>
207
- </DropdownMenuTrigger>
208
- <DropdownMenuContent align="start" side="right">
209
- <DropdownMenuItem
210
- onSelect={() => {
211
- setTimeout(() => {
212
- setRenameValue(node.name);
213
- setRenameOpen(true);
214
- }, 0);
215
- }}
216
- >
217
- <IconEdit className="h-3.5 w-3.5 me-2" />{" "}
218
- {t("folderTree.rename")}
219
- </DropdownMenuItem>
220
- <DropdownMenuItem
221
- onSelect={() => {
222
- setTimeout(() => {
223
- setNewValue("");
224
- setNewOpen(true);
225
- }, 0);
226
- }}
227
- >
228
- <IconFolderPlus className="h-3.5 w-3.5 me-2" />{" "}
229
- {t("folderTree.newSubfolder")}
230
- </DropdownMenuItem>
231
- <DropdownMenuSeparator />
232
- <DropdownMenuItem
233
- onSelect={() => setTimeout(() => setConfirmDelete(true), 0)}
234
- className="text-destructive"
235
- >
236
- <IconTrash className="h-3.5 w-3.5 me-2" />{" "}
237
- {t("folderTree.delete")}
238
- </DropdownMenuItem>
239
- </DropdownMenuContent>
240
- </DropdownMenu>
227
+ </CollapsibleTrigger>
228
+ )}
229
+ <div className="relative size-5 shrink-0">
230
+ <DropdownMenu>
231
+ <DropdownMenuTrigger asChild>
232
+ <button
233
+ type="button"
234
+ aria-label={`${node.name}: ${t("root.commandActions")}`}
235
+ title={`${node.name}: ${t("root.commandActions")}`}
236
+ className="peer absolute inset-0 flex items-center justify-center rounded text-primary opacity-0 transition-opacity hover:bg-accent hover:text-primary focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring group-hover:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100"
237
+ >
238
+ <IconDots className="h-3.5 w-3.5" />
239
+ </button>
240
+ </DropdownMenuTrigger>
241
+ <DropdownMenuContent align="start" side="right">
242
+ <DropdownMenuItem
243
+ onSelect={() => {
244
+ setTimeout(() => {
245
+ setRenameValue(node.name);
246
+ setRenameOpen(true);
247
+ }, 0);
248
+ }}
249
+ >
250
+ <IconEdit className="h-3.5 w-3.5 me-2" />{" "}
251
+ {t("folderTree.rename")}
252
+ </DropdownMenuItem>
253
+ <DropdownMenuItem
254
+ onSelect={() => {
255
+ setTimeout(() => {
256
+ setNewValue("");
257
+ setNewOpen(true);
258
+ }, 0);
259
+ }}
260
+ >
261
+ <IconFolderPlus className="h-3.5 w-3.5 me-2" />{" "}
262
+ {t("folderTree.newSubfolder")}
263
+ </DropdownMenuItem>
264
+ <DropdownMenuSeparator />
265
+ <DropdownMenuItem
266
+ onSelect={() =>
267
+ setTimeout(() => setConfirmDelete(true), 0)
268
+ }
269
+ className="text-destructive"
270
+ >
271
+ <IconTrash className="h-3.5 w-3.5 me-2" />{" "}
272
+ {t("folderTree.delete")}
273
+ </DropdownMenuItem>
274
+ </DropdownMenuContent>
275
+ </DropdownMenu>
276
+ {(node.recordingCount ?? 0) > 0 && (
277
+ <span className="pointer-events-none absolute inset-0 flex items-center justify-end tabular-nums text-[11px] text-primary/80 transition-opacity group-hover:opacity-0 group-focus-within:opacity-0 peer-data-[state=open]:opacity-0">
278
+ {node.recordingCount}
279
+ <span className="sr-only">
280
+ {t("navigation.recordings")}
281
+ </span>
282
+ </span>
283
+ )}
284
+ </div>
241
285
  </div>
242
286
  </ContextMenuTrigger>
243
287
  <ContextMenuContent>
@@ -292,6 +336,7 @@ function FolderItem({
292
336
  activeFolderId={activeFolderId}
293
337
  organizationId={organizationId}
294
338
  spaceId={spaceId}
339
+ compact={compact}
295
340
  />
296
341
  ))}
297
342
  </ul>
@@ -0,0 +1,27 @@
1
+ export interface LibraryActionScope {
2
+ folderId?: string | null;
3
+ spaceId?: string | null;
4
+ }
5
+
6
+ function scopedPath(pathname: string, params: URLSearchParams) {
7
+ const query = params.toString();
8
+ return query ? `${pathname}?${query}` : pathname;
9
+ }
10
+
11
+ export function buildLibraryActionHrefs({
12
+ folderId,
13
+ spaceId,
14
+ }: LibraryActionScope) {
15
+ const scope = new URLSearchParams();
16
+ if (spaceId) scope.set("spaceId", spaceId);
17
+ if (folderId) scope.set("folderId", folderId);
18
+
19
+ const uploadParams = new URLSearchParams(scope);
20
+ uploadParams.set("autoUpload", "1");
21
+
22
+ return {
23
+ recordHref: scopedPath("/record", scope),
24
+ uploadHref: scopedPath("/record", uploadParams),
25
+ importLoomHref: scopedPath("/import", scope),
26
+ };
27
+ }