@agent-native/core 0.84.18 → 0.84.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/core/CHANGELOG.md +13 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/run-store.ts +180 -13
- package/corpus/core/src/client/AssistantChat.tsx +49 -0
- package/corpus/core/src/client/active-run-state.ts +30 -0
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +41 -3
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +133 -0
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +2 -2
- package/corpus/core/src/extensions/html-shell.ts +17 -3
- package/corpus/core/src/extensions/theme.ts +39 -0
- package/corpus/templates/analytics/actions/provider-api-request.ts +8 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +91 -33
- package/corpus/templates/clips/changelog/2026-07-01-chrome-recording-uploads-now-serialize-chunks-to-avoid-resum.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +30 -23
- package/dist/agent/run-store.d.ts +19 -6
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +163 -13
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +36 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/active-run-state.d.ts +3 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +24 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +32 -3
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +59 -2
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +2 -2
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +17 -3
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/theme.d.ts +9 -0
- package/dist/extensions/theme.d.ts.map +1 -1
- package/dist/extensions/theme.js +38 -0
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
IconArrowLeft,
|
|
3
3
|
IconArrowBackUp,
|
|
4
4
|
IconChevronRight,
|
|
5
|
+
IconCode,
|
|
5
6
|
IconDotsVertical,
|
|
6
7
|
IconHistory,
|
|
7
8
|
IconLoader2,
|
|
@@ -20,6 +21,7 @@ import { getThemeVars } from "../../extensions/theme.js";
|
|
|
20
21
|
import { sendToAgentChat } from "../agent-chat.js";
|
|
21
22
|
import { AgentToggleButton } from "../AgentPanel.js";
|
|
22
23
|
import { agentNativePath, appPath } from "../api-path.js";
|
|
24
|
+
import { Dialog, DialogContent, DialogTitle } from "../components/ui/dialog.js";
|
|
23
25
|
import {
|
|
24
26
|
Popover,
|
|
25
27
|
PopoverContent,
|
|
@@ -324,6 +326,131 @@ function applyCanonicalLink(path: string): () => void {
|
|
|
324
326
|
};
|
|
325
327
|
}
|
|
326
328
|
|
|
329
|
+
function SourceCodeDialog({
|
|
330
|
+
extension,
|
|
331
|
+
onSaved,
|
|
332
|
+
}: {
|
|
333
|
+
extension: Extension;
|
|
334
|
+
onSaved?: () => void;
|
|
335
|
+
}) {
|
|
336
|
+
const queryClient = useQueryClient();
|
|
337
|
+
const [open, setOpen] = useState(false);
|
|
338
|
+
const [code, setCode] = useState(extension.content ?? "");
|
|
339
|
+
const [saving, setSaving] = useState(false);
|
|
340
|
+
const [error, setError] = useState<string | null>(null);
|
|
341
|
+
|
|
342
|
+
// Sync in when the dialog opens, or when the viewed extension changes
|
|
343
|
+
// while the dialog stays mounted (e.g. re-parented to a different id).
|
|
344
|
+
useEffect(() => {
|
|
345
|
+
if (open) setCode(extension.content ?? "");
|
|
346
|
+
}, [open, extension.id]);
|
|
347
|
+
|
|
348
|
+
const isDirty = code !== (extension.content ?? "");
|
|
349
|
+
|
|
350
|
+
// Block Escape / outside-click from closing while there are unsaved edits.
|
|
351
|
+
const handleOpenChange = (next: boolean) => {
|
|
352
|
+
if (!next && isDirty) return;
|
|
353
|
+
setOpen(next);
|
|
354
|
+
if (!next) setError(null);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const handleCancel = () => {
|
|
358
|
+
setCode(extension.content ?? "");
|
|
359
|
+
setOpen(false);
|
|
360
|
+
setError(null);
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const handleSave = async () => {
|
|
364
|
+
setSaving(true);
|
|
365
|
+
setError(null);
|
|
366
|
+
try {
|
|
367
|
+
const res = await fetch(
|
|
368
|
+
agentNativePath(`/_agent-native/extensions/${extension.id}`),
|
|
369
|
+
{
|
|
370
|
+
method: "PUT",
|
|
371
|
+
headers: { "Content-Type": "application/json" },
|
|
372
|
+
body: JSON.stringify({ content: code }),
|
|
373
|
+
},
|
|
374
|
+
);
|
|
375
|
+
if (!res.ok) {
|
|
376
|
+
const body = await res.json().catch(() => ({}));
|
|
377
|
+
throw new Error(body?.error ?? `Save failed (${res.status})`);
|
|
378
|
+
}
|
|
379
|
+
setOpen(false);
|
|
380
|
+
queryClient.setQueryData<Extension>(["extension", extension.id], (old) =>
|
|
381
|
+
old ? { ...old, content: code } : old,
|
|
382
|
+
);
|
|
383
|
+
queryClient.invalidateQueries({
|
|
384
|
+
queryKey: ["extension", extension.id],
|
|
385
|
+
});
|
|
386
|
+
queryClient.invalidateQueries({ queryKey: ["extensions"] });
|
|
387
|
+
onSaved?.();
|
|
388
|
+
} catch (err: any) {
|
|
389
|
+
setError(err?.message ?? "Save failed");
|
|
390
|
+
} finally {
|
|
391
|
+
setSaving(false);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
return (
|
|
396
|
+
<>
|
|
397
|
+
<Tooltip>
|
|
398
|
+
<TooltipTrigger asChild>
|
|
399
|
+
<button
|
|
400
|
+
type="button"
|
|
401
|
+
onClick={() => setOpen(true)}
|
|
402
|
+
className="inline-flex items-center justify-center rounded-md h-8 w-8 text-muted-foreground hover:bg-accent hover:text-accent-foreground cursor-pointer"
|
|
403
|
+
>
|
|
404
|
+
<IconCode className="h-4 w-4" />
|
|
405
|
+
</button>
|
|
406
|
+
</TooltipTrigger>
|
|
407
|
+
<TooltipContent>View / edit source</TooltipContent>
|
|
408
|
+
</Tooltip>
|
|
409
|
+
<Dialog open={open} onOpenChange={handleOpenChange}>
|
|
410
|
+
<DialogContent className="flex h-[85vh] w-[90vw] max-w-[900px] flex-col gap-0 overflow-hidden p-0">
|
|
411
|
+
<div className="flex shrink-0 items-center border-b border-border px-5 py-3 pr-12">
|
|
412
|
+
<DialogTitle className="truncate text-sm font-medium">
|
|
413
|
+
{extension.name} — source
|
|
414
|
+
</DialogTitle>
|
|
415
|
+
</div>
|
|
416
|
+
<textarea
|
|
417
|
+
className="flex-1 resize-none bg-muted/40 px-5 py-4 font-mono text-xs leading-relaxed text-foreground focus:outline-none"
|
|
418
|
+
value={code}
|
|
419
|
+
onChange={(e) => setCode(e.target.value)}
|
|
420
|
+
spellCheck={false}
|
|
421
|
+
/>
|
|
422
|
+
<div className="flex shrink-0 items-center justify-between border-t border-border px-5 py-3">
|
|
423
|
+
{error ? (
|
|
424
|
+
<p className="text-xs text-destructive">{error}</p>
|
|
425
|
+
) : (
|
|
426
|
+
<span className="text-xs text-muted-foreground">
|
|
427
|
+
Alpine.js / HTML · {code.length.toLocaleString()} chars
|
|
428
|
+
</span>
|
|
429
|
+
)}
|
|
430
|
+
<div className="flex items-center gap-2">
|
|
431
|
+
<button
|
|
432
|
+
type="button"
|
|
433
|
+
onClick={handleCancel}
|
|
434
|
+
className="inline-flex h-8 cursor-pointer items-center rounded-md border border-input px-3 text-xs hover:bg-accent"
|
|
435
|
+
>
|
|
436
|
+
Cancel
|
|
437
|
+
</button>
|
|
438
|
+
<button
|
|
439
|
+
type="button"
|
|
440
|
+
onClick={handleSave}
|
|
441
|
+
disabled={saving}
|
|
442
|
+
className="inline-flex h-8 cursor-pointer items-center rounded-md bg-primary px-4 text-xs font-medium text-primary-foreground hover:opacity-90 disabled:opacity-50"
|
|
443
|
+
>
|
|
444
|
+
{saving ? "Saving…" : "Save"}
|
|
445
|
+
</button>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
</DialogContent>
|
|
449
|
+
</Dialog>
|
|
450
|
+
</>
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
327
454
|
function EditToolPopover({
|
|
328
455
|
extension,
|
|
329
456
|
onOpenChange,
|
|
@@ -1157,6 +1284,12 @@ export function ExtensionViewer({ extensionId }: ExtensionViewerProps) {
|
|
|
1157
1284
|
onRestored={() => setRefreshKey((k) => k + 1)}
|
|
1158
1285
|
onOpenChange={onPopoverOpenChange}
|
|
1159
1286
|
/>
|
|
1287
|
+
{extension.canEdit && (
|
|
1288
|
+
<SourceCodeDialog
|
|
1289
|
+
extension={extension}
|
|
1290
|
+
onSaved={() => setRefreshKey((k) => k + 1)}
|
|
1291
|
+
/>
|
|
1292
|
+
)}
|
|
1160
1293
|
<EditToolPopover
|
|
1161
1294
|
extension={extension}
|
|
1162
1295
|
onOpenChange={onPopoverOpenChange}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
IconChevronDown,
|
|
3
3
|
IconPlus,
|
|
4
|
-
|
|
4
|
+
IconFilter,
|
|
5
5
|
IconStar,
|
|
6
6
|
IconStarFilled,
|
|
7
7
|
IconTrash,
|
|
@@ -570,7 +570,7 @@ function ExtensionSortMenu({
|
|
|
570
570
|
className="inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground/45 opacity-0 transition-all hover:bg-accent hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring group-hover/extensions-section:opacity-100"
|
|
571
571
|
aria-label={copy.sortOptions}
|
|
572
572
|
>
|
|
573
|
-
<
|
|
573
|
+
<IconFilter className="h-3.5 w-3.5" />
|
|
574
574
|
</button>
|
|
575
575
|
</DropdownMenuTrigger>
|
|
576
576
|
</TooltipTrigger>
|
|
@@ -226,11 +226,19 @@ export function buildExtensionHtml(
|
|
|
226
226
|
</style>
|
|
227
227
|
<style>
|
|
228
228
|
*, *::before, *::after { border-color: hsl(var(--border)); }
|
|
229
|
+
html, body {
|
|
230
|
+
/* Transparent so the iframe inherits the host surface (dashboard panel,
|
|
231
|
+
sidebar, chat) instead of painting the browser's default white canvas.
|
|
232
|
+
The dark class still flips the theme vars; content paints its own
|
|
233
|
+
bg-background / bg-card surfaces. */
|
|
234
|
+
background: transparent;
|
|
235
|
+
}
|
|
229
236
|
body {
|
|
230
237
|
--agent-native-extension-padding: clamp(16px, 2vw, 24px);
|
|
231
238
|
/* Legacy alias for pre-rename extension content (do not remove). */
|
|
232
239
|
--agent-native-tool-padding: var(--agent-native-extension-padding);
|
|
233
240
|
box-sizing: border-box;
|
|
241
|
+
color: hsl(var(--foreground));
|
|
234
242
|
font-family: 'Inter', sans-serif;
|
|
235
243
|
margin: 0;
|
|
236
244
|
min-height: 100vh;
|
|
@@ -403,8 +411,14 @@ export function buildExtensionHtml(
|
|
|
403
411
|
}
|
|
404
412
|
|
|
405
413
|
if (!res.ok) {
|
|
406
|
-
var err = res.body || {
|
|
407
|
-
|
|
414
|
+
var err = res.body || {};
|
|
415
|
+
var rawError = typeof err === 'string' ? err : err.error;
|
|
416
|
+
var message = (typeof rawError === 'string' && rawError.trim())
|
|
417
|
+
? rawError
|
|
418
|
+
: (res.status === 404
|
|
419
|
+
? "Action '" + name + "' is not available over HTTP (404). It may be agent-only (http: false); expose it with an HTTP-mounted action to call it from an extension."
|
|
420
|
+
: "Action '" + name + "' failed (" + (res.status || 'network error') + ")");
|
|
421
|
+
throw new Error(message);
|
|
408
422
|
}
|
|
409
423
|
return res.body;
|
|
410
424
|
}
|
|
@@ -730,7 +744,7 @@ export function buildExtensionHtml(
|
|
|
730
744
|
});
|
|
731
745
|
</script>
|
|
732
746
|
</head>
|
|
733
|
-
<body${extensionId ? ` data-extension-id="${extensionIdAttr}" data-tool-id="${extensionIdAttr}"` : ""} class="
|
|
747
|
+
<body${extensionId ? ` data-extension-id="${extensionIdAttr}" data-tool-id="${extensionIdAttr}"` : ""} class="text-foreground">
|
|
734
748
|
${content}
|
|
735
749
|
<div id="__extension-error-toast">
|
|
736
750
|
<div style="display:flex;align-items:flex-start;gap:8px;">
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical set of semantic theme token names shared by the app and extension
|
|
3
|
+
* iframes. This is the single source of truth: `getThemeVars` bakes default
|
|
4
|
+
* values for these into every iframe, and the host reads the *actual* computed
|
|
5
|
+
* values for the same names to sync its live palette into embedded extensions
|
|
6
|
+
* (see EmbeddedExtension). Custom properties can't be enumerated portably from
|
|
7
|
+
* a computed style, so the names must be listed explicitly.
|
|
8
|
+
*/
|
|
9
|
+
export const THEME_VAR_NAMES = [
|
|
10
|
+
"--background",
|
|
11
|
+
"--foreground",
|
|
12
|
+
"--card",
|
|
13
|
+
"--card-foreground",
|
|
14
|
+
"--popover",
|
|
15
|
+
"--popover-foreground",
|
|
16
|
+
"--primary",
|
|
17
|
+
"--primary-foreground",
|
|
18
|
+
"--secondary",
|
|
19
|
+
"--secondary-foreground",
|
|
20
|
+
"--muted",
|
|
21
|
+
"--muted-foreground",
|
|
22
|
+
"--accent",
|
|
23
|
+
"--accent-foreground",
|
|
24
|
+
"--destructive",
|
|
25
|
+
"--destructive-foreground",
|
|
26
|
+
"--border",
|
|
27
|
+
"--input",
|
|
28
|
+
"--ring",
|
|
29
|
+
"--radius",
|
|
30
|
+
"--sidebar-background",
|
|
31
|
+
"--sidebar-foreground",
|
|
32
|
+
"--sidebar-primary",
|
|
33
|
+
"--sidebar-primary-foreground",
|
|
34
|
+
"--sidebar-accent",
|
|
35
|
+
"--sidebar-accent-foreground",
|
|
36
|
+
"--sidebar-border",
|
|
37
|
+
"--sidebar-ring",
|
|
38
|
+
] as const;
|
|
39
|
+
|
|
1
40
|
/**
|
|
2
41
|
* CSS variables baked into every extension iframe. Both light and dark are
|
|
3
42
|
* always emitted — the `.dark` class on the iframe's `<html>` toggles between
|
|
@@ -213,7 +213,14 @@ export default defineAction({
|
|
|
213
213
|
"Enable cursor-based pagination. After each response, reads cursorPath from the JSON body and re-issues the request with cursorParam or cursorBodyPath set, accumulating items from itemsPath (or whole bodies) until cursor is empty or maxPages is reached. Combine with saveToFile to write the full dataset to a workspace file; use scratch/... for temporary staging.",
|
|
214
214
|
),
|
|
215
215
|
}),
|
|
216
|
-
|
|
216
|
+
// Mounted over HTTP (POST) so the agent and frontend (`useActionMutation`)
|
|
217
|
+
// can reach it, consistent with provider-api-catalog / provider-api-docs.
|
|
218
|
+
// toolCallable: false blocks the extension iframe bridge — this action
|
|
219
|
+
// accepts arbitrary methods (PUT/DELETE/etc.) against provider APIs, so
|
|
220
|
+
// allowing shared extensions to call it would let malicious extension authors
|
|
221
|
+
// mutate provider data under the opener's credentials.
|
|
222
|
+
http: { method: "POST" },
|
|
223
|
+
toolCallable: false,
|
|
217
224
|
run: async (args) => {
|
|
218
225
|
if (args.stageAs) {
|
|
219
226
|
const ctx = requireRequestCredentialContext("provider-api staging");
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
IconStar,
|
|
8
8
|
IconPencil,
|
|
9
9
|
IconSettings,
|
|
10
|
+
IconFilter,
|
|
10
11
|
IconGripVertical,
|
|
11
12
|
IconBook2,
|
|
12
13
|
IconDatabase,
|
|
@@ -251,7 +252,7 @@ function SidebarSectionSettingsPopover({
|
|
|
251
252
|
className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground/65 opacity-0 transition-all hover:bg-sidebar-accent hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring group-hover/section:opacity-100 data-[state=open]:opacity-100"
|
|
252
253
|
aria-label={settingsLabel}
|
|
253
254
|
>
|
|
254
|
-
<
|
|
255
|
+
<IconFilter className="h-3.5 w-3.5" />
|
|
255
256
|
</button>
|
|
256
257
|
</PopoverTrigger>
|
|
257
258
|
</TooltipTrigger>
|
|
@@ -3,6 +3,7 @@ import { useDraggable } from "@dnd-kit/core";
|
|
|
3
3
|
import {
|
|
4
4
|
IconGripVertical,
|
|
5
5
|
IconDotsVertical,
|
|
6
|
+
IconExternalLink,
|
|
6
7
|
IconMaximize,
|
|
7
8
|
IconPencil,
|
|
8
9
|
IconRefresh,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
} from "@tabler/icons-react";
|
|
13
14
|
import { useIsFetching, useQueryClient } from "@tanstack/react-query";
|
|
14
15
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
16
|
+
import { useNavigate } from "react-router";
|
|
15
17
|
|
|
16
18
|
import { ChartFillHeight, SqlChart } from "@/components/dashboard/SqlChart";
|
|
17
19
|
import {
|
|
@@ -119,6 +121,8 @@ export function SqlChartCard({
|
|
|
119
121
|
|
|
120
122
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
121
123
|
const [expanded, setExpanded] = useState(false);
|
|
124
|
+
const [extRefreshKey, setExtRefreshKey] = useState(0);
|
|
125
|
+
const navigate = useNavigate();
|
|
122
126
|
const [exportCsv, setExportCsv] = useState<(() => void) | null>(null);
|
|
123
127
|
const [shouldLoadData, setShouldLoadData] = useState(
|
|
124
128
|
eagerLoad ||
|
|
@@ -291,10 +295,12 @@ export function SqlChartCard({
|
|
|
291
295
|
}
|
|
292
296
|
|
|
293
297
|
// Extension panels render their sandboxed iframe full-bleed with no card chrome
|
|
294
|
-
// or title — the extension owns its own UI.
|
|
295
|
-
//
|
|
296
|
-
//
|
|
298
|
+
// or title — the extension owns its own UI. All viewers get the read-only
|
|
299
|
+
// actions (full screen, refresh, open extension); editable dashboards also get
|
|
300
|
+
// delete and drag.
|
|
297
301
|
if (panel.chartType === "extension") {
|
|
302
|
+
const extensionId = (panel.config as Record<string, unknown> | undefined)
|
|
303
|
+
?.extensionId as string | undefined;
|
|
298
304
|
return (
|
|
299
305
|
<div
|
|
300
306
|
ref={setCardNodeRef}
|
|
@@ -302,45 +308,97 @@ export function SqlChartCard({
|
|
|
302
308
|
data-dragging={isDragSource ? "true" : undefined}
|
|
303
309
|
className="dashboard-extension-card group relative h-full"
|
|
304
310
|
>
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
311
|
+
{!expanded && (
|
|
312
|
+
<SqlChart
|
|
313
|
+
key={extRefreshKey}
|
|
314
|
+
panel={panel}
|
|
315
|
+
resolvedSql={resolvedSql}
|
|
316
|
+
loadData
|
|
317
|
+
/>
|
|
318
|
+
)}
|
|
319
|
+
<div className="absolute right-1 top-1 flex items-center gap-1 opacity-0 group-hover:opacity-100">
|
|
320
|
+
<DropdownMenu>
|
|
321
|
+
<Tooltip>
|
|
322
|
+
<TooltipTrigger asChild>
|
|
323
|
+
<DropdownMenuTrigger asChild>
|
|
324
|
+
<button
|
|
325
|
+
className="p-1 rounded bg-background/80 text-muted-foreground hover:text-foreground"
|
|
326
|
+
aria-label={t("sqlDashboard.panelOptions")}
|
|
327
|
+
>
|
|
328
|
+
<IconDotsVertical className="h-3.5 w-3.5" />
|
|
329
|
+
</button>
|
|
330
|
+
</DropdownMenuTrigger>
|
|
331
|
+
</TooltipTrigger>
|
|
332
|
+
<TooltipContent>{t("sqlDashboard.panelOptions")}</TooltipContent>
|
|
333
|
+
</Tooltip>
|
|
334
|
+
<DropdownMenuContent align="end" className="w-44">
|
|
335
|
+
<DropdownMenuItem onSelect={() => setExpanded(true)}>
|
|
336
|
+
<IconMaximize className="h-4 w-4 mr-2" />
|
|
337
|
+
{t("sqlDashboard.fullScreen")}
|
|
338
|
+
</DropdownMenuItem>
|
|
339
|
+
{extensionId ? (
|
|
325
340
|
<DropdownMenuItem
|
|
326
|
-
onSelect={(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
341
|
+
onSelect={() =>
|
|
342
|
+
navigate(
|
|
343
|
+
`/extensions/${extensionId}/${encodeURIComponent(
|
|
344
|
+
(panel.title ?? "extension")
|
|
345
|
+
.toLowerCase()
|
|
346
|
+
.replace(/[^a-z0-9]+/g, "-"),
|
|
347
|
+
)}`,
|
|
348
|
+
)
|
|
349
|
+
}
|
|
330
350
|
>
|
|
331
|
-
<
|
|
332
|
-
{
|
|
351
|
+
<IconExternalLink className="h-4 w-4 mr-2" />
|
|
352
|
+
Open extension {/* i18n-ignore */}
|
|
333
353
|
</DropdownMenuItem>
|
|
334
|
-
|
|
335
|
-
|
|
354
|
+
) : null}
|
|
355
|
+
<DropdownMenuSeparator />
|
|
356
|
+
<DropdownMenuItem onSelect={() => setExtRefreshKey((k) => k + 1)}>
|
|
357
|
+
<IconRefresh className="h-4 w-4 mr-2" />
|
|
358
|
+
{t("sqlDashboard.refresh")}
|
|
359
|
+
</DropdownMenuItem>
|
|
360
|
+
{editable ? (
|
|
361
|
+
<>
|
|
362
|
+
<DropdownMenuSeparator />
|
|
363
|
+
<DropdownMenuItem
|
|
364
|
+
onSelect={(e) => {
|
|
365
|
+
e.preventDefault();
|
|
366
|
+
setConfirmOpen(true);
|
|
367
|
+
}}
|
|
368
|
+
>
|
|
369
|
+
<IconTrash className="h-4 w-4 mr-2" />
|
|
370
|
+
{t("sidebar.delete")}
|
|
371
|
+
</DropdownMenuItem>
|
|
372
|
+
</>
|
|
373
|
+
) : null}
|
|
374
|
+
</DropdownMenuContent>
|
|
375
|
+
</DropdownMenu>
|
|
376
|
+
{editable ? (
|
|
336
377
|
<PanelDragHandle
|
|
337
378
|
panelId={panel.id}
|
|
338
379
|
label={t("sqlDashboard.dragToReorder")}
|
|
339
380
|
className="p-1 rounded bg-background/80 cursor-grab active:cursor-grabbing text-muted-foreground/50 hover:text-muted-foreground"
|
|
340
381
|
iconClassName="h-3.5 w-3.5"
|
|
341
382
|
/>
|
|
342
|
-
|
|
343
|
-
|
|
383
|
+
) : null}
|
|
384
|
+
</div>
|
|
385
|
+
<Dialog open={expanded} onOpenChange={setExpanded}>
|
|
386
|
+
<DialogContent className="flex h-[90vh] w-[95vw] max-w-[1400px] flex-col gap-4">
|
|
387
|
+
<DialogHeader className="shrink-0 pr-8 text-left">
|
|
388
|
+
<DialogTitle className="truncate">{panel.title}</DialogTitle>
|
|
389
|
+
</DialogHeader>
|
|
390
|
+
<div className="flex min-h-0 flex-1 flex-col overflow-auto">
|
|
391
|
+
<ChartFillHeight>
|
|
392
|
+
<SqlChart
|
|
393
|
+
key={extRefreshKey}
|
|
394
|
+
panel={panel}
|
|
395
|
+
resolvedSql={resolvedSql}
|
|
396
|
+
loadData
|
|
397
|
+
/>
|
|
398
|
+
</ChartFillHeight>
|
|
399
|
+
</div>
|
|
400
|
+
</DialogContent>
|
|
401
|
+
</Dialog>
|
|
344
402
|
{editable ? (
|
|
345
403
|
<AlertDialog open={confirmOpen} onOpenChange={setConfirmOpen}>
|
|
346
404
|
<AlertDialogContent>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Agent-Native Clips",
|
|
4
4
|
"short_name": "Clips",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.9",
|
|
6
6
|
"description": "Start Clips recordings from Chrome, capture optional diagnostics, and preview Clips links on GitHub.",
|
|
7
7
|
"minimum_chrome_version": "116",
|
|
8
8
|
"action": {
|
|
@@ -129,6 +129,7 @@ type ActiveRecording = {
|
|
|
129
129
|
sourceStreams: MediaStream[];
|
|
130
130
|
audioContext: AudioContext | null;
|
|
131
131
|
chunkIndex: number;
|
|
132
|
+
uploadChain: Promise<void>;
|
|
132
133
|
uploadPromises: Promise<unknown>[];
|
|
133
134
|
uploadFailure: Error | null;
|
|
134
135
|
// Local safety buffer: every recorded blob is kept here (browser-managed,
|
|
@@ -795,6 +796,7 @@ async function begin(message: BeginMessage): Promise<{
|
|
|
795
796
|
],
|
|
796
797
|
audioContext: mixedAudio.audioContext,
|
|
797
798
|
chunkIndex: 0,
|
|
799
|
+
uploadChain: Promise.resolve(),
|
|
798
800
|
uploadPromises: [],
|
|
799
801
|
uploadFailure: null,
|
|
800
802
|
recordedBlobs: [],
|
|
@@ -837,30 +839,35 @@ async function begin(message: BeginMessage): Promise<{
|
|
|
837
839
|
// rejected promise that surfaces as an "Uncaught (in promise)" error (bad
|
|
838
840
|
// look in a Chrome Web Store review). finalizeStop reads recording.upload-
|
|
839
841
|
// Failure and surfaces it through the normal error path instead.
|
|
840
|
-
const upload =
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
842
|
+
const upload = recording.uploadChain
|
|
843
|
+
.then(() =>
|
|
844
|
+
recording.cancelled || recording.uploadFailure
|
|
845
|
+
? undefined
|
|
846
|
+
: recording.uploadMode === "streaming"
|
|
847
|
+
? uploadStreamingBlob(recording, event.data)
|
|
848
|
+
: uploadBlobInSlices(recording, event.data),
|
|
849
|
+
)
|
|
850
|
+
.catch((err) => {
|
|
851
|
+
recording.uploadFailure =
|
|
852
|
+
err instanceof Error ? err : new Error(String(err));
|
|
853
|
+
captureExtensionError(recording.uploadFailure, {
|
|
854
|
+
tags: {
|
|
855
|
+
surface: "offscreen",
|
|
856
|
+
recordingStep: "dataavailable-upload",
|
|
857
|
+
},
|
|
858
|
+
extra: {
|
|
859
|
+
recordingId: recording.recordingId,
|
|
860
|
+
blobBytes: event.data.size,
|
|
861
|
+
chunkIndex: recording.chunkIndex,
|
|
862
|
+
mimeType: event.data.type || recording.mimeType,
|
|
863
|
+
},
|
|
864
|
+
});
|
|
865
|
+
reportStatus(recording.sessionId, "error", {
|
|
866
|
+
error: recording.uploadFailure.message,
|
|
867
|
+
});
|
|
868
|
+
if (recorder.state !== "inactive") recorder.stop();
|
|
861
869
|
});
|
|
862
|
-
|
|
863
|
-
});
|
|
870
|
+
recording.uploadChain = upload.then(() => undefined);
|
|
864
871
|
recording.uploadPromises.push(upload);
|
|
865
872
|
});
|
|
866
873
|
|
|
@@ -16,6 +16,8 @@ export declare const RUN_STALE_MS = 15000;
|
|
|
16
16
|
* With the normal 15s window the reaper would falsely kill that freshly-
|
|
17
17
|
* inserted-but-not-yet-heartbeaten row. 90s tolerates a slow background
|
|
18
18
|
* cold-start while still reaping a genuinely dead background worker promptly.
|
|
19
|
+
* Claimed background workers heartbeat during long work; the stale watchdog is a
|
|
20
|
+
* liveness timeout, not the Netlify background-function execution budget.
|
|
19
21
|
*
|
|
20
22
|
* Only applied to rows explicitly marked background-dispatched; ordinary
|
|
21
23
|
* foreground runs keep the tight 15s window unchanged.
|
|
@@ -62,13 +64,14 @@ export declare const CLAIMED_BACKGROUND_WORKER_FAILED_ERROR_EVENT: {
|
|
|
62
64
|
* Grace period before a never-claimed background run (dispatch_mode still
|
|
63
65
|
* 'background', no worker claim) is treated as a dead handoff and reaped.
|
|
64
66
|
*
|
|
65
|
-
* This is intentionally
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* has, by definition, NO worker — nothing
|
|
67
|
+
* This is intentionally tighter than `BACKGROUND_RUN_STALE_MS`. That wider
|
|
68
|
+
* window protects cold-starting or temporarily delayed background dispatches,
|
|
69
|
+
* while claimed workers stay alive by heartbeat/progress updates. A run that is
|
|
70
|
+
* still `dispatch_mode = 'background'` has, by definition, NO worker — nothing
|
|
71
|
+
* to protect — so once a Netlify
|
|
69
72
|
* background function has had a reasonable cold-start window to claim it and
|
|
70
73
|
* hasn't, the handoff is dead and should surface promptly instead of leaving
|
|
71
|
-
* the user staring at a spinner for
|
|
74
|
+
* the user staring at a spinner for the durable-worker window. 25s comfortably exceeds a normal
|
|
72
75
|
* Netlify Lambda cold start while still failing fast on a silent worker death.
|
|
73
76
|
*/
|
|
74
77
|
export declare const UNCLAIMED_BACKGROUND_RUN_GRACE_MS = 25000;
|
|
@@ -159,6 +162,16 @@ export declare function setRunError(runId: string, errorCode: string | undefined
|
|
|
159
162
|
* status='completed' + terminal_reason='run_timeout').
|
|
160
163
|
*/
|
|
161
164
|
export declare function setRunTerminalReason(runId: string, terminalReason: string | undefined): Promise<void>;
|
|
165
|
+
/**
|
|
166
|
+
* Repair a run whose terminal event was durably appended but whose final
|
|
167
|
+
* `agent_runs.status` write lost a race with reconnect/reaper code.
|
|
168
|
+
*
|
|
169
|
+
* The event ledger is the durable transcript users see. If its latest event is
|
|
170
|
+
* terminal, the run is no longer alive and must not be converted into a stale
|
|
171
|
+
* error later. This keeps `agent_runs` and `agent_run_events` from telling two
|
|
172
|
+
* different stories after delayed DB writes or background function teardown.
|
|
173
|
+
*/
|
|
174
|
+
export declare function reconcileTerminalRunFromEvents(runId: string): Promise<boolean>;
|
|
162
175
|
/**
|
|
163
176
|
* Diagnostic stage names recorded onto a background run as it moves through the
|
|
164
177
|
* `_process-run` worker pipeline. Each value is the LAST stage successfully
|
|
@@ -235,7 +248,7 @@ export declare function reapIfStale(runId: string, maxStaleMs?: number): Promise
|
|
|
235
248
|
* before it can claim), the row stays `background`, never heartbeats again, and
|
|
236
249
|
* — because dispatch returned 202 — the foreground already returned the SSE
|
|
237
250
|
* stream, so the existing fast-fail inline fallback never engaged. The run would
|
|
238
|
-
* otherwise hang for the full
|
|
251
|
+
* otherwise hang for the full durable background window and then error opaquely.
|
|
239
252
|
*
|
|
240
253
|
* This reaps such a run EARLY and DISTINCTLY: a row that is still unclaimed
|
|
241
254
|
* (`dispatch_mode = 'background'`) past the tight `UNCLAIMED_BACKGROUND_RUN_GRACE_MS`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/agent/run-store.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,QAAS,CAAC;AAEnC
|
|
1
|
+
{"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/agent/run-store.ts"],"names":[],"mappings":"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"}
|