@agent-native/core 0.0.0-beta-20260820155159 → 0.0.0-beta-20260820171000
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/changelog/2026-08-20-staged-data-limit-recovery.md +5 -0
- package/corpus/templates/clips/changelog/2026-08-20-cross-tab-recording-controls.md +5 -0
- package/corpus/templates/clips/changelog/2026-08-20-overlay-follow-review-fixes.md +5 -0
- package/corpus/templates/clips/changelog/2026-08-20-provider-key-recovery.md +5 -0
- package/corpus/templates/clips/chrome-extension/PERMISSIONS.md +29 -46
- package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +1 -1
- package/corpus/templates/clips/chrome-extension/public/manifest.json +9 -2
- package/corpus/templates/clips/chrome-extension/src/background.ts +65 -46
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +25 -17
- package/corpus/templates/clips/chrome-extension/src/overlay-follow.ts +25 -0
- package/dist/client/chat/run-recovery.js +8 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/provider-api/actions/provider-api.js +16 -4
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -1,41 +1,45 @@
|
|
|
1
1
|
# Permissions model
|
|
2
2
|
|
|
3
|
-
This extension ships **
|
|
4
|
-
|
|
3
|
+
This extension ships **cross-tab follow for recording overlays**: it declares
|
|
4
|
+
the broad `<all_urls>` host permission and a matching declarative content script
|
|
5
|
+
so the camera bubble and controls can survive tab switches and navigations.
|
|
5
6
|
|
|
6
7
|
## Why
|
|
7
8
|
|
|
8
9
|
A declarative content script on `<all_urls>` (and the matching `<all_urls>` host
|
|
9
10
|
permission) triggers Chrome Web Store's **broad host permission in-depth review**,
|
|
10
|
-
which significantly delays publishing and updates. We
|
|
11
|
+
which significantly delays publishing and updates. We take that review path only
|
|
12
|
+
for the release that re-enables cross-tab follow.
|
|
11
13
|
|
|
12
|
-
The
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
The declarative content scripts are scoped to:
|
|
15
|
+
|
|
16
|
+
- `https://github.com/*` for Clips link previews in GitHub issue/PR markdown.
|
|
17
|
+
- `<all_urls>` for the recording overlay host that keeps the face bubble and
|
|
18
|
+
controls mounted across pages while a recording is active.
|
|
19
|
+
|
|
20
|
+
The GitHub preview script adds a narrow host disclosure, while the overlay host
|
|
21
|
+
is the broad review boundary.
|
|
16
22
|
|
|
17
23
|
## How the overlay gets on the page
|
|
18
24
|
|
|
19
25
|
When the user clicks the extension and starts a recording, the background service
|
|
20
|
-
worker
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
needed. The content script then mounts the overlay iframes (countdown, camera
|
|
25
|
-
bubble, controls). `web_accessible_resources` stays `<all_urls>` — that is **not**
|
|
26
|
-
a host permission and does not trigger the review.
|
|
26
|
+
worker mounts the overlay on the active tab and keeps rebroadcasting it as the
|
|
27
|
+
active tab changes. The content script then mounts the overlay iframes
|
|
28
|
+
(countdown, camera bubble, controls). `web_accessible_resources` stays
|
|
29
|
+
`<all_urls>` — that is **not** a host permission and does not trigger the review.
|
|
27
30
|
|
|
28
31
|
Declared permissions: `activeTab`, `debugger`, `offscreen`, `scripting`,
|
|
29
|
-
`storage`. Host permissions:
|
|
32
|
+
`storage`. Host permissions: the configured Clips app + `forms.agent-native.com`
|
|
30
33
|
|
|
31
34
|
- `localhost`/`127.0.0.1`.
|
|
32
|
-
- `https://github.com/*` is content-script scoped for link previews
|
|
35
|
+
- `https://github.com/*` is content-script scoped for link previews.
|
|
36
|
+
- `<all_urls>` is the overlay host required for cross-tab follow.
|
|
33
37
|
|
|
34
38
|
## What this costs
|
|
35
39
|
|
|
36
|
-
- The overlay (countdown, camera bubble, recording controls)
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
- The overlay (countdown, camera bubble, recording controls) follows the user
|
|
41
|
+
across tabs while a recording is active. Navigating to a new page or tab keeps
|
|
42
|
+
the face bubble and controls mounted once the page loads.
|
|
39
43
|
- **Recording itself is unaffected.** Capture runs in the offscreen document via
|
|
40
44
|
`getDisplayMedia`, independent of any tab's content script — full-screen,
|
|
41
45
|
window, and other-tab content are all still captured normally. Only the on-page
|
|
@@ -43,36 +47,15 @@ Declared permissions: `activeTab`, `debugger`, `offscreen`, `scripting`,
|
|
|
43
47
|
|
|
44
48
|
## Re-enabling cross-tab follow
|
|
45
49
|
|
|
46
|
-
The full cross-tab behavior is gated behind a single flag in
|
|
47
|
-
`src/background.ts`:
|
|
50
|
+
The full cross-tab behavior is gated behind a single flag in `src/background.ts`:
|
|
48
51
|
|
|
49
52
|
```ts
|
|
50
|
-
const CROSS_TAB_FOLLOW =
|
|
53
|
+
const CROSS_TAB_FOLLOW = true;
|
|
51
54
|
```
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
inject into arbitrary tabs.
|
|
57
|
-
|
|
58
|
-
1. **Static (simplest, but in-depth review):** re-add to `public/manifest.json`:
|
|
59
|
-
- `"<all_urls>"` in `host_permissions`, and
|
|
60
|
-
- the `content_scripts` block:
|
|
61
|
-
```json
|
|
62
|
-
"content_scripts": [
|
|
63
|
-
{
|
|
64
|
-
"matches": ["<all_urls>"],
|
|
65
|
-
"js": ["assets/content-script.js"],
|
|
66
|
-
"run_at": "document_idle",
|
|
67
|
-
"all_frames": false
|
|
68
|
-
}
|
|
69
|
-
],
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
2. **Optional (preferred — keeps the default install lean):** declare
|
|
73
|
-
`"optional_host_permissions": ["<all_urls>"]` in the manifest and call
|
|
74
|
-
`chrome.permissions.request({ origins: ["<all_urls>"] })` at runtime (e.g. from
|
|
75
|
-
a settings toggle) before enabling follow. The user grants the broad access
|
|
76
|
-
explicitly, only if they want cross-tab overlays.
|
|
56
|
+
That keeps the all-tabs broadcast in `broadcastMount()` / `broadcastUnmount()`
|
|
57
|
+
and the `chrome.tabs.onActivated` follow listener live. The manifest must keep
|
|
58
|
+
the broad host permission and the `<all_urls>` declarative content script in
|
|
59
|
+
place so the worker can inject into arbitrary tabs.
|
|
77
60
|
|
|
78
61
|
After any change: `pnpm build`, then re-zip `dist/`.
|
|
@@ -56,7 +56,7 @@ Upload the generated artifact (the version matches `public/manifest.json`; the
|
|
|
56
56
|
Chrome Web Store requires each upload to use a higher version than the last):
|
|
57
57
|
|
|
58
58
|
```txt
|
|
59
|
-
templates/clips/chrome-extension/releases/clips-chrome-extension-0.1.
|
|
59
|
+
templates/clips/chrome-extension/releases/clips-chrome-extension-0.1.19.zip
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
## Web App Rollout Gate
|
|
@@ -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.19",
|
|
6
6
|
"description": "Start Clips recordings from Chrome, capture optional diagnostics, and preview Clips links on GitHub and Jira.",
|
|
7
7
|
"minimum_chrome_version": "116",
|
|
8
8
|
"action": {
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"https://clips.agent-native.com/*",
|
|
32
32
|
"https://forms.agent-native.com/*",
|
|
33
33
|
"http://localhost/*",
|
|
34
|
-
"http://127.0.0.1/*"
|
|
34
|
+
"http://127.0.0.1/*",
|
|
35
|
+
"<all_urls>"
|
|
35
36
|
],
|
|
36
37
|
"content_scripts": [
|
|
37
38
|
{
|
|
@@ -43,6 +44,12 @@
|
|
|
43
44
|
"js": ["assets/github-preview-content.js"],
|
|
44
45
|
"run_at": "document_idle",
|
|
45
46
|
"all_frames": false
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"matches": ["<all_urls>"],
|
|
50
|
+
"js": ["assets/content-script.js"],
|
|
51
|
+
"run_at": "document_idle",
|
|
52
|
+
"all_frames": false
|
|
46
53
|
}
|
|
47
54
|
],
|
|
48
55
|
"web_accessible_resources": [
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
shouldReconcilePersistedRecording,
|
|
7
7
|
type OffscreenRecordingState,
|
|
8
8
|
} from "./native-recording-state";
|
|
9
|
+
import {
|
|
10
|
+
sendWithInjectionFallback,
|
|
11
|
+
shouldFollowOverlay,
|
|
12
|
+
} from "./overlay-follow";
|
|
9
13
|
import { captureExtensionError, initExtensionSentry } from "./sentry";
|
|
10
14
|
|
|
11
15
|
initExtensionSentry("background");
|
|
@@ -276,16 +280,11 @@ let overlayBaseEpochMs = 0;
|
|
|
276
280
|
// up, for both camera-only AND screen+camera recording (recordingShowsBubble).
|
|
277
281
|
let overlayShowsBubble = false;
|
|
278
282
|
let recordingShowsBubble = false;
|
|
279
|
-
// Cross-tab follow
|
|
280
|
-
//
|
|
281
|
-
//
|
|
282
|
-
|
|
283
|
-
//
|
|
284
|
-
// getDisplayMedia regardless. See PERMISSIONS.md to re-enable.
|
|
285
|
-
// Typed `boolean` (not inferred literal `false`) so the cross-tab branches below
|
|
286
|
-
// don't read as unreachable code; flip the value to re-enable. See PERMISSIONS.md.
|
|
287
|
-
const CROSS_TAB_FOLLOW: boolean = false;
|
|
288
|
-
// The tab the recording was launched from — the only tab activeTab lets us touch.
|
|
283
|
+
// Cross-tab follow stays enabled for the next release. It needs the manifest's
|
|
284
|
+
// broad-host review path (`<all_urls>` + declarative content script coverage) so
|
|
285
|
+
// the face bubble and controls keep following the user across tabs and reloads.
|
|
286
|
+
const CROSS_TAB_FOLLOW: boolean = true;
|
|
287
|
+
// The launch tab stays the anchor for the explicit reload recovery path.
|
|
289
288
|
let overlayTabId: number | null = null;
|
|
290
289
|
let countdownEndsAtMs = 0;
|
|
291
290
|
let armingNativeRecordingSessionId: string | null = null;
|
|
@@ -438,20 +437,19 @@ async function restoreRuntimeState(): Promise<void> {
|
|
|
438
437
|
function sendTabMessage(
|
|
439
438
|
tabId: number,
|
|
440
439
|
message: Record<string, unknown>,
|
|
441
|
-
): Promise<
|
|
440
|
+
): Promise<boolean> {
|
|
442
441
|
return new Promise((resolve) => {
|
|
443
442
|
try {
|
|
444
443
|
chrome.tabs.sendMessage(tabId, message, () => {
|
|
445
|
-
|
|
446
|
-
resolve();
|
|
444
|
+
resolve(!chrome.runtime.lastError);
|
|
447
445
|
});
|
|
448
446
|
} catch {
|
|
449
|
-
resolve();
|
|
447
|
+
resolve(false);
|
|
450
448
|
}
|
|
451
449
|
});
|
|
452
450
|
}
|
|
453
451
|
|
|
454
|
-
async function
|
|
452
|
+
async function injectContentScript(tabId: number): Promise<boolean> {
|
|
455
453
|
const scripting = (
|
|
456
454
|
chrome as typeof chrome & {
|
|
457
455
|
scripting?: {
|
|
@@ -462,18 +460,32 @@ async function ensureContentScript(tabId: number): Promise<void> {
|
|
|
462
460
|
};
|
|
463
461
|
}
|
|
464
462
|
).scripting;
|
|
465
|
-
if (!scripting) return;
|
|
466
|
-
|
|
467
|
-
.executeScript({
|
|
468
|
-
|
|
463
|
+
if (!scripting) return false;
|
|
464
|
+
try {
|
|
465
|
+
await scripting.executeScript({
|
|
466
|
+
target: { tabId },
|
|
467
|
+
files: ["assets/content-script.js"],
|
|
468
|
+
});
|
|
469
|
+
return true;
|
|
470
|
+
} catch {
|
|
471
|
+
// Unsupported pages (chrome://, the Chrome Web Store, and similar) reject
|
|
472
|
+
// injection. They still need to record without an in-page overlay.
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
469
475
|
}
|
|
470
476
|
|
|
471
|
-
async function mountOverlayOnTab(
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
+
async function mountOverlayOnTab(
|
|
478
|
+
tabId: number,
|
|
479
|
+
parts: OverlayPart[] = desiredParts(),
|
|
480
|
+
): Promise<boolean> {
|
|
481
|
+
return sendWithInjectionFallback(
|
|
482
|
+
() =>
|
|
483
|
+
sendTabMessage(tabId, {
|
|
484
|
+
type: "CLIPS_OVERLAY_MOUNT",
|
|
485
|
+
parts,
|
|
486
|
+
}),
|
|
487
|
+
() => injectContentScript(tabId),
|
|
488
|
+
);
|
|
477
489
|
}
|
|
478
490
|
|
|
479
491
|
function allTabs(): Promise<chrome.tabs.Tab[]> {
|
|
@@ -483,9 +495,8 @@ function allTabs(): Promise<chrome.tabs.Tab[]> {
|
|
|
483
495
|
}
|
|
484
496
|
|
|
485
497
|
async function broadcastMount(): Promise<void> {
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
// gated behind CROSS_TAB_FOLLOW because it needs broad host access.
|
|
498
|
+
// Cross-tab follow uses the declarative content script path, so every mounted
|
|
499
|
+
// tab can receive the current overlay parts and survive reloads.
|
|
489
500
|
if (!CROSS_TAB_FOLLOW) {
|
|
490
501
|
if (overlayTabId !== null) await mountOverlayOnTab(overlayTabId);
|
|
491
502
|
return;
|
|
@@ -548,12 +559,9 @@ async function startPreview(wantsCamera: boolean): Promise<void> {
|
|
|
548
559
|
if (!tab || typeof tab.id !== "number") return;
|
|
549
560
|
if (previewTabId !== null && previewTabId !== tab.id) await stopPreview();
|
|
550
561
|
previewTabId = tab.id;
|
|
551
|
-
|
|
552
|
-
//
|
|
553
|
-
await
|
|
554
|
-
type: "CLIPS_OVERLAY_MOUNT",
|
|
555
|
-
parts: ["bubble"],
|
|
556
|
-
});
|
|
562
|
+
// Message delivery reuses the declarative script; fallback injection fails
|
|
563
|
+
// silently on unsupported pages (chrome://, the Web Store, and similar).
|
|
564
|
+
await mountOverlayOnTab(tab.id, ["bubble"]);
|
|
557
565
|
}
|
|
558
566
|
|
|
559
567
|
async function stopPreview(): Promise<void> {
|
|
@@ -2560,29 +2568,40 @@ async function dispatchRuntimeMessage(message: unknown): Promise<unknown> {
|
|
|
2560
2568
|
}
|
|
2561
2569
|
}
|
|
2562
2570
|
|
|
2563
|
-
// While a recording is active, keep the overlay following the user as
|
|
2564
|
-
// switch tabs
|
|
2565
|
-
//
|
|
2571
|
+
// While a recording is active or arming, keep the overlay following the user as
|
|
2572
|
+
// they switch tabs. The message-first path reuses declarative scripts and only
|
|
2573
|
+
// injects for tabs that predate the extension or otherwise have no receiver.
|
|
2566
2574
|
chrome.tabs.onActivated.addListener((info) => {
|
|
2567
|
-
if (!CROSS_TAB_FOLLOW) return;
|
|
2575
|
+
if (!CROSS_TAB_FOLLOW) return;
|
|
2568
2576
|
void (async () => {
|
|
2569
2577
|
await ensureRestored();
|
|
2570
|
-
if (
|
|
2578
|
+
if (
|
|
2579
|
+
!shouldFollowOverlay(
|
|
2580
|
+
overlayPhase,
|
|
2581
|
+
Boolean(activeNativeRecording),
|
|
2582
|
+
Boolean(armingNativeRecordingSessionId),
|
|
2583
|
+
)
|
|
2584
|
+
)
|
|
2585
|
+
return;
|
|
2571
2586
|
await mountOverlayOnTab(info.tabId);
|
|
2572
2587
|
})();
|
|
2573
2588
|
});
|
|
2574
2589
|
|
|
2575
|
-
//
|
|
2576
|
-
//
|
|
2577
|
-
//
|
|
2578
|
-
// Re-inject and re-mount once the launch tab finishes reloading while a recording
|
|
2579
|
-
// is active. Scoped to the launch tab (the only tab activeTab lets us touch); a
|
|
2580
|
-
// same-URL reload keeps that grant.
|
|
2590
|
+
// Keep the launch tab in sync after a reload. Declarative follow covers the
|
|
2591
|
+
// other tabs; this is the explicit recovery path for the tab that originally
|
|
2592
|
+
// started the recording.
|
|
2581
2593
|
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
|
|
2582
2594
|
if (changeInfo.status !== "complete") return;
|
|
2583
2595
|
void (async () => {
|
|
2584
2596
|
await ensureRestored();
|
|
2585
|
-
if (
|
|
2597
|
+
if (
|
|
2598
|
+
!shouldFollowOverlay(
|
|
2599
|
+
overlayPhase,
|
|
2600
|
+
Boolean(activeNativeRecording),
|
|
2601
|
+
Boolean(armingNativeRecordingSessionId),
|
|
2602
|
+
)
|
|
2603
|
+
)
|
|
2604
|
+
return;
|
|
2586
2605
|
if (tabId !== overlayTabId) return;
|
|
2587
2606
|
await mountOverlayOnTab(tabId);
|
|
2588
2607
|
broadcastOverlayState();
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
// Loom-style in-page overlay host. The
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// emits a single self-contained classic script with no module imports/exports
|
|
9
|
-
// and leaks no names into the shared global scope. Its only job is to
|
|
1
|
+
// Loom-style in-page overlay host. The next release declares this on every page
|
|
2
|
+
// so the face bubble and controls can survive tab switches and navigations; the
|
|
3
|
+
// background worker can also inject it into the launch tab for immediate and
|
|
4
|
+
// reload recovery. That broad "<all_urls>" host access is the Chrome Web Store
|
|
5
|
+
// in-depth review boundary. Wrapped in an IIFE so it emits a single self-contained
|
|
6
|
+
// classic script with no module imports/exports and leaks no names into the shared
|
|
7
|
+
// global scope. Its only job is to
|
|
10
8
|
// mount/unmount the overlay iframes; all UI and control logic lives inside the
|
|
11
9
|
// extension-origin overlay pages (src/overlay.html). The worker is the source of
|
|
12
10
|
// truth for which "parts" are visible and pushes them here.
|
|
@@ -18,6 +16,12 @@
|
|
|
18
16
|
const ALL_PARTS: OverlayPart[] = ["bubble", "countdown", "toolbar", "saving"];
|
|
19
17
|
const flags = window as unknown as { __clipsOverlayHostReady?: boolean };
|
|
20
18
|
|
|
19
|
+
// Declarative and recovery injection can target the same document. Return
|
|
20
|
+
// before any side effects so global listeners remain one-per-page.
|
|
21
|
+
if (flags.__clipsOverlayHostReady) return;
|
|
22
|
+
flags.__clipsOverlayHostReady = true;
|
|
23
|
+
let recordingActive = false;
|
|
24
|
+
|
|
21
25
|
function errorPayload(error: unknown): {
|
|
22
26
|
name: string;
|
|
23
27
|
message: string;
|
|
@@ -40,6 +44,7 @@
|
|
|
40
44
|
error: unknown,
|
|
41
45
|
context: Record<string, unknown> = {},
|
|
42
46
|
): void {
|
|
47
|
+
if (!recordingActive) return;
|
|
43
48
|
try {
|
|
44
49
|
chrome.runtime.sendMessage(
|
|
45
50
|
{
|
|
@@ -73,6 +78,15 @@
|
|
|
73
78
|
});
|
|
74
79
|
});
|
|
75
80
|
|
|
81
|
+
try {
|
|
82
|
+
chrome.storage.onChanged.addListener((changes, areaName) => {
|
|
83
|
+
if (areaName !== "local" || !changes.clipsRecordingActive) return;
|
|
84
|
+
recordingActive = changes.clipsRecordingActive.newValue === true;
|
|
85
|
+
});
|
|
86
|
+
} catch {
|
|
87
|
+
/* storage unavailable */
|
|
88
|
+
}
|
|
89
|
+
|
|
76
90
|
// ----- Draggable, resizable camera bubble ---------------------------------
|
|
77
91
|
// Size + position persist in storage so the bubble stays where the user put it
|
|
78
92
|
// across pages and recordings (like the desktop app). The iframe can't move or
|
|
@@ -339,7 +353,8 @@
|
|
|
339
353
|
try {
|
|
340
354
|
chrome.storage.local.get("clipsRecordingActive", (value) => {
|
|
341
355
|
if (chrome.runtime.lastError) return;
|
|
342
|
-
|
|
356
|
+
recordingActive = value?.clipsRecordingActive === true;
|
|
357
|
+
if (recordingActive) requestState();
|
|
343
358
|
});
|
|
344
359
|
} catch {
|
|
345
360
|
/* ignore */
|
|
@@ -593,13 +608,6 @@
|
|
|
593
608
|
lastWantedParts = wanted;
|
|
594
609
|
}
|
|
595
610
|
|
|
596
|
-
// Guard against rare double-injection (SPA soft-reloads re-running the script).
|
|
597
|
-
if (flags.__clipsOverlayHostReady) {
|
|
598
|
-
syncIfRecording();
|
|
599
|
-
return;
|
|
600
|
-
}
|
|
601
|
-
flags.__clipsOverlayHostReady = true;
|
|
602
|
-
|
|
603
611
|
chrome.runtime.onMessage.addListener((message) => {
|
|
604
612
|
if (!message || typeof message !== "object") return;
|
|
605
613
|
const type = (message as { type?: unknown }).type;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type OverlayFollowPhase =
|
|
2
|
+
| "idle"
|
|
3
|
+
| "countdown"
|
|
4
|
+
| "recording"
|
|
5
|
+
| "paused"
|
|
6
|
+
| "saving";
|
|
7
|
+
|
|
8
|
+
export function shouldFollowOverlay(
|
|
9
|
+
phase: OverlayFollowPhase,
|
|
10
|
+
hasActiveNativeRecording: boolean,
|
|
11
|
+
hasArmingNativeRecording: boolean,
|
|
12
|
+
): boolean {
|
|
13
|
+
return (
|
|
14
|
+
phase !== "idle" && (hasActiveNativeRecording || hasArmingNativeRecording)
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function sendWithInjectionFallback(
|
|
19
|
+
sendMessage: () => Promise<boolean>,
|
|
20
|
+
injectContentScript: () => Promise<boolean>,
|
|
21
|
+
): Promise<boolean> {
|
|
22
|
+
if (await sendMessage()) return true;
|
|
23
|
+
if (!(await injectContentScript())) return false;
|
|
24
|
+
return sendMessage();
|
|
25
|
+
}
|
|
@@ -213,10 +213,15 @@ export function RunErrorRecoveryCard({ info, onContinue, onRetry, onFork, onDism
|
|
|
213
213
|
const shouldShowMissingProviderSetup = isMissingLlmProviderRunError(info);
|
|
214
214
|
const isProviderAuthError = isProviderAuthenticationError([info.message, info.details].filter(Boolean).join("\n"), info.errorCode);
|
|
215
215
|
// Blocked on something the reader goes and fixes elsewhere, then comes back
|
|
216
|
-
// to.
|
|
217
|
-
//
|
|
216
|
+
// to. Recoverable runs and email verification keep a retry path; rejected
|
|
217
|
+
// provider credentials use the setup flow below so the same bad key is not
|
|
218
|
+
// replayed.
|
|
218
219
|
const isUnblockableExternally = info.errorCode === "email_verification_required";
|
|
219
|
-
|
|
220
|
+
// Rejected provider keys already have a recovery path: update/connect the
|
|
221
|
+
// credential, then let the setup callback re-run the turn. Exposing a
|
|
222
|
+
// separate retry button here just replays the same rejected credential and
|
|
223
|
+
// turns a permanent auth failure into a loop.
|
|
224
|
+
const canRetry = canRecover || isUnblockableExternally;
|
|
220
225
|
const builderReconnectResolved = shouldShowBuilderReconnect &&
|
|
221
226
|
builderReconnect.hasFetchedStatus &&
|
|
222
227
|
builderReconnect.configured;
|
|
@@ -62,11 +62,11 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
62
62
|
error: string;
|
|
63
63
|
states?: undefined;
|
|
64
64
|
} | {
|
|
65
|
-
error?: undefined;
|
|
66
65
|
states: {
|
|
67
66
|
clientId: number;
|
|
68
67
|
state: string;
|
|
69
68
|
}[];
|
|
69
|
+
error?: undefined;
|
|
70
70
|
}>>;
|
|
71
71
|
/**
|
|
72
72
|
* GET /_agent-native/collab/:docId/users
|
|
@@ -77,9 +77,9 @@ export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("
|
|
|
77
77
|
error: string;
|
|
78
78
|
users?: undefined;
|
|
79
79
|
} | {
|
|
80
|
-
error?: undefined;
|
|
81
80
|
users: {
|
|
82
81
|
clientId: number;
|
|
83
82
|
lastSeen: number;
|
|
84
83
|
}[];
|
|
84
|
+
error?: undefined;
|
|
85
85
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -26,8 +26,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
26
26
|
* Body: { update: string (base64), requestSource?: string }
|
|
27
27
|
*/
|
|
28
28
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
29
|
-
ok?: undefined;
|
|
30
29
|
error: string;
|
|
30
|
+
ok?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
error?: undefined;
|
|
33
33
|
ok: boolean;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
|
|
14
14
|
*/
|
|
15
15
|
export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
16
|
-
ok?: undefined;
|
|
17
16
|
error: string;
|
|
17
|
+
ok?: undefined;
|
|
18
18
|
} | {
|
|
19
19
|
error?: undefined;
|
|
20
20
|
ok: boolean;
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* DELETE /_agent-native/notifications/:id — delete
|
|
12
12
|
*/
|
|
13
13
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
14
|
-
error?: undefined;
|
|
15
14
|
count: number;
|
|
16
15
|
updated?: undefined;
|
|
17
16
|
ok?: undefined;
|
|
18
|
-
} | {
|
|
19
17
|
error?: undefined;
|
|
18
|
+
} | {
|
|
20
19
|
updated: number;
|
|
21
20
|
ok?: undefined;
|
|
21
|
+
error?: undefined;
|
|
22
22
|
count?: undefined;
|
|
23
23
|
} | {
|
|
24
24
|
updated?: undefined;
|
|
@@ -26,8 +26,8 @@ export declare function createNotificationsHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
ok?: undefined;
|
|
27
27
|
count?: undefined;
|
|
28
28
|
} | {
|
|
29
|
-
error?: undefined;
|
|
30
29
|
updated?: undefined;
|
|
31
30
|
ok: boolean;
|
|
31
|
+
error?: undefined;
|
|
32
32
|
count?: undefined;
|
|
33
33
|
}>>;
|
|
@@ -193,6 +193,13 @@ export function createProviderApiDocsSchema(providerSchema = z.string().min(1))
|
|
|
193
193
|
search: WebContentSearchSchema.optional().describe("Optional post-fetch search over extracted content by default. Supports query, queries, terms, regex, source, maxMatches, and contextChars."),
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
|
+
const STAGED_DATASET_CAP_ERROR = /Staged dataset (?:byte )?cap exceeded/i;
|
|
197
|
+
function rethrowStagingError(error) {
|
|
198
|
+
if (error instanceof Error && STAGED_DATASET_CAP_ERROR.test(error.message)) {
|
|
199
|
+
throw new Error(`${error.message} Recover by deleting older staged datasets with list-staged-datasets/delete-staged-dataset, or switch this request to saveToFile / a smaller staged result before trying again.`, { cause: error });
|
|
200
|
+
}
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
196
203
|
export function createProviderApiRequestAction(runtime, options = {}) {
|
|
197
204
|
const schema = options.schema ?? createProviderApiRequestSchema();
|
|
198
205
|
return defineAction({
|
|
@@ -244,10 +251,15 @@ export function createProviderApiRequestAction(runtime, options = {}) {
|
|
|
244
251
|
if (!ownerEmail) {
|
|
245
252
|
throw new Error("No authenticated context for provider API staging.");
|
|
246
253
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
254
|
+
try {
|
|
255
|
+
return await stagingExecuteRequest(args, runtime.executeRequest, {
|
|
256
|
+
appId: options.appId,
|
|
257
|
+
ownerEmail,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
rethrowStagingError(error);
|
|
262
|
+
}
|
|
251
263
|
}
|
|
252
264
|
return runtime.executeRequest(args);
|
|
253
265
|
},
|
|
@@ -51,8 +51,8 @@ export declare function handleDeleteResource(event: any): Promise<{
|
|
|
51
51
|
error: string;
|
|
52
52
|
ok?: undefined;
|
|
53
53
|
} | {
|
|
54
|
-
error?: undefined;
|
|
55
54
|
ok: boolean;
|
|
55
|
+
error?: undefined;
|
|
56
56
|
}>;
|
|
57
57
|
/** POST /_agent-native/resources/upload — upload a file as a resource */
|
|
58
58
|
export declare function handleUploadResource(event: any): Promise<import("./store.js").Resource | {
|
|
@@ -73,10 +73,10 @@ export declare function handleUploadResource(event: any): Promise<import("./stor
|
|
|
73
73
|
runId: string | null;
|
|
74
74
|
expiresAt: number | null;
|
|
75
75
|
metadata: string | null;
|
|
76
|
-
error?: undefined;
|
|
77
76
|
url: string;
|
|
78
77
|
provider: string;
|
|
79
78
|
storageSetupRequired?: undefined;
|
|
79
|
+
error?: undefined;
|
|
80
80
|
} | {
|
|
81
81
|
error: string;
|
|
82
82
|
storageSetupRequired: boolean;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -34,16 +34,16 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
|
|
|
34
34
|
/** POST /_agent-native/secrets/:key — write a secret. */
|
|
35
35
|
export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
36
36
|
error: string;
|
|
37
|
-
ok?: undefined;
|
|
38
37
|
status?: undefined;
|
|
38
|
+
ok?: undefined;
|
|
39
39
|
} | {
|
|
40
40
|
ok: boolean;
|
|
41
41
|
status: string;
|
|
42
42
|
error?: undefined;
|
|
43
43
|
} | {
|
|
44
|
-
ok?: undefined;
|
|
45
44
|
error: string;
|
|
46
45
|
removed?: undefined;
|
|
46
|
+
ok?: undefined;
|
|
47
47
|
} | {
|
|
48
48
|
ok: boolean;
|
|
49
49
|
removed: boolean;
|
|
@@ -54,9 +54,9 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
|
|
|
54
54
|
* or the current stored value without changing anything.
|
|
55
55
|
*/
|
|
56
56
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
57
|
-
ok?: undefined;
|
|
58
57
|
error: string;
|
|
59
58
|
note?: undefined;
|
|
59
|
+
ok?: undefined;
|
|
60
60
|
} | {
|
|
61
61
|
ok: boolean;
|
|
62
62
|
note?: undefined;
|
|
@@ -26,8 +26,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
26
26
|
expiresAt?: undefined;
|
|
27
27
|
ttlSeconds?: undefined;
|
|
28
28
|
} | {
|
|
29
|
+
error?: undefined;
|
|
29
30
|
token: string;
|
|
30
31
|
expiresAt: string;
|
|
31
32
|
ttlSeconds: number;
|
|
32
|
-
error?: undefined;
|
|
33
33
|
}>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.0.0-beta-
|
|
3
|
+
"version": "0.0.0-beta-20260820171000",
|
|
4
4
|
"description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|