@agent-native/core 0.72.3 → 0.73.0
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 +38 -0
- package/corpus/core/docs/content/skills-guide.md +14 -0
- package/corpus/core/docs/content/template-clips.md +7 -1
- package/corpus/core/package.json +6 -6
- package/corpus/core/src/a2a/client.ts +7 -3
- package/corpus/core/src/agent/durable-background.ts +25 -12
- package/corpus/core/src/cli/create.ts +1 -1
- package/corpus/core/src/cli/skills.ts +450 -19
- package/corpus/core/src/client/api-path.ts +28 -0
- package/corpus/core/src/client/embed-auth.ts +26 -0
- package/corpus/core/src/client/mcp-app-host.ts +6 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +227 -33
- package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -1
- package/corpus/core/src/demo/fetch-interceptor.ts +1 -1
- package/corpus/core/src/embedding/agent.ts +6 -1
- package/corpus/core/src/embedding/bridge.ts +34 -1
- package/corpus/core/src/mcp/build-server.ts +38 -10
- package/corpus/core/src/mcp/embed-app.ts +120 -45
- package/corpus/core/src/mcp/index.ts +5 -0
- package/corpus/core/src/mcp/org-directory.ts +70 -11
- package/corpus/core/src/mcp/server.ts +14 -0
- package/corpus/core/src/mcp-client/config.ts +12 -0
- package/corpus/core/src/mcp-client/index.ts +2 -0
- package/corpus/core/src/mcp-client/manager.ts +268 -9
- package/corpus/core/src/mcp-client/remote-store.ts +154 -0
- package/corpus/core/src/mcp-client/routes.ts +2 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +8 -0
- package/corpus/core/src/server/auth.ts +7 -0
- package/corpus/core/src/server/index.ts +1 -0
- package/corpus/core/src/server/onboarding-html.ts +95 -9
- package/corpus/core/src/shared/mcp-embed-headers.ts +44 -3
- package/corpus/core/src/templates/default/AGENTS.md +4 -0
- package/corpus/core/src/templates/default/package.json +2 -1
- package/corpus/core/src/templates/headless/AGENTS.md +4 -0
- package/corpus/core/src/templates/headless/package.json +1 -0
- package/corpus/core/src/templates/workspace-root/AGENTS.md +4 -0
- package/corpus/core/src/templates/workspace-root/README.md +4 -0
- package/corpus/core/src/templates/workspace-root/package.json +1 -0
- package/corpus/core/src/vite/client.ts +53 -0
- package/corpus/templates/analytics/actions/update-dashboard.ts +3 -4
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +144 -40
- package/corpus/templates/analytics/app/global.css +15 -13
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +9 -32
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +0 -26
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +0 -23
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/pivot.ts +65 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +3 -4
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-charts-now-fill-sparse-template-time-series-suppor.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-rows-now-auto-fit-panels-so-one-two-or-three-chart.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-traffic-tables-now-show-top-urls-and-shared-clips-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +5 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-template-dashboards-now-include-repeat-users-ret.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-retention-charts-now-break-out-1-day-and-7-day-return-rates-.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +256 -44
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +7 -2
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +35 -8
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +287 -42
- package/corpus/templates/assets/.agents/skills/a2a-assets/SKILL.md +17 -10
- package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +15 -6
- package/corpus/templates/assets/AGENTS.md +7 -5
- package/corpus/templates/assets/actions/generate-asset.ts +161 -0
- package/corpus/templates/assets/actions/list-assets.ts +4 -2
- package/corpus/templates/assets/actions/open-asset-picker.ts +84 -3
- package/corpus/templates/assets/app/routes/library.tsx +243 -40
- package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +1 -1
- package/corpus/templates/calendar/server/plugins/auth.ts +12 -0
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +7 -7
- package/corpus/templates/clips/AGENTS.md +6 -2
- package/corpus/templates/clips/app/components/capture-install-options.tsx +20 -4
- package/corpus/templates/clips/app/components/player/player-controls.tsx +62 -32
- package/corpus/templates/clips/app/lib/capture-install-options.ts +39 -5
- package/corpus/templates/clips/app/routes/download.tsx +2 -2
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +1 -1
- package/corpus/templates/clips/changelog/2026-06-24-inline-slack-playback-controls-no-longer-shift-when-adjustin.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-console-log-stream-all-le.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-shared-clips-now-expose-their-full-fetch-xhr-network-request.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-24-the-chrome-extension-option-now-only-appears-on-supported-hosts.md +5 -0
- package/corpus/templates/clips/chrome-extension/STORE_DRAFT.md +13 -8
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/scripts/package.ts +15 -2
- package/corpus/templates/clips/chrome-extension/src/overlay.css +4 -25
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +1 -3
- package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +9 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +67 -24
- package/corpus/templates/design/AGENTS.md +10 -5
- package/corpus/templates/design/actions/connect-assets-mcp.ts +131 -0
- package/corpus/templates/design/actions/insert-asset.ts +219 -0
- package/corpus/templates/design/actions/view-screen.ts +3 -1
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignEditor.tsx +53 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +5 -1
- package/corpus/templates/design/server/plugins/assets-mcp.ts +60 -0
- package/corpus/templates/mail/server/plugins/auth.ts +4 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +271 -197
- package/corpus/templates/plan/server/plan-content.ts +45 -2
- package/dist/a2a/client.d.ts +1 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +5 -3
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/durable-background.d.ts +9 -4
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +24 -11
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/cli/create.js +1 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +361 -19
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/api-path.d.ts.map +1 -1
- package/dist/client/api-path.js +27 -0
- package/dist/client/api-path.js.map +1 -1
- package/dist/client/embed-auth.d.ts.map +1 -1
- package/dist/client/embed-auth.js +27 -0
- package/dist/client/embed-auth.js.map +1 -1
- package/dist/client/mcp-app-host.d.ts.map +1 -1
- package/dist/client/mcp-app-host.js +5 -0
- package/dist/client/mcp-app-host.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.js +179 -33
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/resources/use-mcp-servers.d.ts +1 -0
- package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
- package/dist/client/resources/use-mcp-servers.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +3 -1
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/demo/fetch-interceptor.js +1 -1
- package/dist/demo/fetch-interceptor.js.map +1 -1
- package/dist/embedding/agent.d.ts +1 -1
- package/dist/embedding/agent.d.ts.map +1 -1
- package/dist/embedding/agent.js +1 -1
- package/dist/embedding/agent.js.map +1 -1
- package/dist/embedding/bridge.d.ts.map +1 -1
- package/dist/embedding/bridge.js +27 -1
- package/dist/embedding/bridge.js.map +1 -1
- package/dist/extensions/schema.d.ts +2 -2
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +32 -9
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +120 -45
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/org-directory.d.ts +1 -0
- package/dist/mcp/org-directory.d.ts.map +1 -1
- package/dist/mcp/org-directory.js +59 -11
- package/dist/mcp/org-directory.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +9 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp-client/config.d.ts +12 -0
- package/dist/mcp-client/config.d.ts.map +1 -1
- package/dist/mcp-client/config.js.map +1 -1
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +1 -1
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/manager.d.ts +2 -0
- package/dist/mcp-client/manager.d.ts.map +1 -1
- package/dist/mcp-client/manager.js +201 -9
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/remote-store.d.ts +27 -0
- package/dist/mcp-client/remote-store.d.ts.map +1 -1
- package/dist/mcp-client/remote-store.js +105 -0
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/mcp-client/routes.d.ts +1 -0
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +1 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/provider-api/actions/github-repo-files.d.ts +2 -2
- package/dist/provider-api/actions/query-staged-dataset.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +8 -8
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +8 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts +7 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +1 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts +15 -0
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +73 -9
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/shared/mcp-embed-headers.d.ts +3 -1
- package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
- package/dist/shared/mcp-embed-headers.js +40 -3
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
- package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
- package/dist/sharing/actions/share-resource.d.ts +1 -1
- package/dist/sharing/schema.d.ts +1 -1
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/default/package.json +2 -1
- package/dist/templates/headless/AGENTS.md +4 -0
- package/dist/templates/headless/package.json +1 -0
- package/dist/templates/workspace-root/AGENTS.md +4 -0
- package/dist/templates/workspace-root/README.md +4 -0
- package/dist/templates/workspace-root/package.json +1 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +44 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/skills-guide.md +14 -0
- package/docs/content/template-clips.md +7 -1
- package/package.json +6 -6
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/default/package.json +2 -1
- package/src/templates/headless/AGENTS.md +4 -0
- package/src/templates/headless/package.json +1 -0
- package/src/templates/workspace-root/AGENTS.md +4 -0
- package/src/templates/workspace-root/README.md +4 -0
- package/src/templates/workspace-root/package.json +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
1
|
+
import { useState, type FocusEvent } from "react";
|
|
2
2
|
import {
|
|
3
3
|
IconPlayerPlay,
|
|
4
4
|
IconPlayerPause,
|
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
TooltipContent,
|
|
25
25
|
TooltipTrigger,
|
|
26
26
|
} from "@/components/ui/tooltip";
|
|
27
|
+
import {
|
|
28
|
+
Popover,
|
|
29
|
+
PopoverContent,
|
|
30
|
+
PopoverTrigger,
|
|
31
|
+
} from "@/components/ui/popover";
|
|
27
32
|
import { PLAYBACK_SPEED_OPTIONS } from "@/lib/playback-speed";
|
|
28
33
|
|
|
29
34
|
export const SPEED_OPTIONS = PLAYBACK_SPEED_OPTIONS;
|
|
@@ -85,7 +90,14 @@ export function PlayerControls(props: PlayerControlsProps) {
|
|
|
85
90
|
menuPortalContainer,
|
|
86
91
|
} = props;
|
|
87
92
|
|
|
88
|
-
const [
|
|
93
|
+
const [volumePopoverOpen, setVolumePopoverOpen] = useState(false);
|
|
94
|
+
|
|
95
|
+
const handleVolumeBlur = (event: FocusEvent<HTMLDivElement>) => {
|
|
96
|
+
const nextFocusedElement = event.relatedTarget as Node | null;
|
|
97
|
+
if (!event.currentTarget.contains(nextFocusedElement)) {
|
|
98
|
+
setVolumePopoverOpen(false);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
89
101
|
|
|
90
102
|
return (
|
|
91
103
|
<div className="px-3 pb-2 pt-10 bg-gradient-to-t from-black/80 via-black/50 to-transparent">
|
|
@@ -112,38 +124,56 @@ export function PlayerControls(props: PlayerControlsProps) {
|
|
|
112
124
|
</IconBtn>
|
|
113
125
|
|
|
114
126
|
<div
|
|
115
|
-
className="flex items-center
|
|
116
|
-
onMouseEnter={() =>
|
|
117
|
-
onMouseLeave={() =>
|
|
127
|
+
className="relative flex shrink-0 items-center"
|
|
128
|
+
onMouseEnter={() => setVolumePopoverOpen(true)}
|
|
129
|
+
onMouseLeave={() => setVolumePopoverOpen(false)}
|
|
130
|
+
onFocus={() => setVolumePopoverOpen(true)}
|
|
131
|
+
onBlur={handleVolumeBlur}
|
|
118
132
|
>
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
className="w-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
<Popover open={volumePopoverOpen} onOpenChange={setVolumePopoverOpen}>
|
|
134
|
+
<PopoverTrigger asChild>
|
|
135
|
+
<button
|
|
136
|
+
type="button"
|
|
137
|
+
onClick={onToggleMute}
|
|
138
|
+
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-white hover:bg-white/10"
|
|
139
|
+
aria-label={muted || volume === 0 ? "Unmute" : "Mute"}
|
|
140
|
+
>
|
|
141
|
+
{muted || volume === 0 ? (
|
|
142
|
+
<IconVolumeOff className="h-5 w-5" />
|
|
143
|
+
) : (
|
|
144
|
+
<IconVolume className="h-5 w-5" />
|
|
145
|
+
)}
|
|
146
|
+
</button>
|
|
147
|
+
</PopoverTrigger>
|
|
148
|
+
<PopoverContent
|
|
149
|
+
side="top"
|
|
150
|
+
align="center"
|
|
151
|
+
sideOffset={8}
|
|
152
|
+
portalled={false}
|
|
153
|
+
className="w-auto border-white/10 bg-black/90 p-2 text-white shadow-2xl backdrop-blur-md"
|
|
154
|
+
onOpenAutoFocus={(event) => event.preventDefault()}
|
|
155
|
+
onCloseAutoFocus={(event) => event.preventDefault()}
|
|
156
|
+
>
|
|
157
|
+
<div className="flex h-24 w-8 items-center justify-center">
|
|
158
|
+
<input
|
|
159
|
+
aria-label="Volume"
|
|
160
|
+
aria-orientation="vertical"
|
|
161
|
+
type="range"
|
|
162
|
+
min={0}
|
|
163
|
+
max={1}
|
|
164
|
+
step={0.05}
|
|
165
|
+
value={muted ? 0 : volume}
|
|
166
|
+
onChange={(e) => onVolumeChange(parseFloat(e.target.value))}
|
|
167
|
+
className="h-2 w-24 -rotate-90 cursor-pointer accent-white"
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
</PopoverContent>
|
|
171
|
+
</Popover>
|
|
142
172
|
</div>
|
|
143
173
|
|
|
144
|
-
<span className="
|
|
174
|
+
<span className="shrink-0 whitespace-nowrap px-1 font-mono text-[10px] leading-none tabular-nums text-white/85 sm:text-[11px]">
|
|
145
175
|
{msToClock(currentMs)}
|
|
146
|
-
<span className="text-white/50"
|
|
176
|
+
<span className="text-white/50">/{msToClock(durationMs)}</span>
|
|
147
177
|
</span>
|
|
148
178
|
|
|
149
179
|
<div className="flex-1" />
|
|
@@ -162,7 +192,7 @@ export function PlayerControls(props: PlayerControlsProps) {
|
|
|
162
192
|
<Tooltip>
|
|
163
193
|
<TooltipTrigger asChild>
|
|
164
194
|
<DropdownMenuTrigger asChild>
|
|
165
|
-
<button className="h-8
|
|
195
|
+
<button className="h-8 shrink-0 rounded-md px-2 text-xs font-medium tabular-nums hover:bg-white/10">
|
|
166
196
|
{speed}x
|
|
167
197
|
</button>
|
|
168
198
|
</DropdownMenuTrigger>
|
|
@@ -237,7 +267,7 @@ function IconBtn({
|
|
|
237
267
|
<button
|
|
238
268
|
onClick={onClick}
|
|
239
269
|
className={cn(
|
|
240
|
-
"h-8 w-8
|
|
270
|
+
"flex h-8 w-8 shrink-0 items-center justify-center rounded-md",
|
|
241
271
|
active ? "bg-white/20 text-white" : "text-white hover:bg-white/10",
|
|
242
272
|
)}
|
|
243
273
|
>
|
|
@@ -1,14 +1,48 @@
|
|
|
1
|
-
function
|
|
1
|
+
function isFalsy(value: unknown): boolean {
|
|
2
2
|
if (typeof value !== "string") return false;
|
|
3
|
-
return ["
|
|
3
|
+
return ["0", "false", "no", "off"].includes(value.trim().toLowerCase());
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function normalizeHostname(hostname: string | undefined): string {
|
|
7
|
+
return (hostname ?? "").trim().toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function supportsPublishedClipsChromeExtensionHost(
|
|
11
|
+
hostname: string | undefined,
|
|
12
|
+
): boolean {
|
|
13
|
+
const normalized = normalizeHostname(hostname);
|
|
14
|
+
return (
|
|
15
|
+
normalized === "clips.agent-native.com" ||
|
|
16
|
+
normalized === "localhost" ||
|
|
17
|
+
normalized === "127.0.0.1"
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resolveClipsChromeExtensionEnabled({
|
|
22
|
+
enabledSetting,
|
|
23
|
+
hostname,
|
|
24
|
+
}: {
|
|
25
|
+
enabledSetting?: string;
|
|
26
|
+
hostname?: string;
|
|
27
|
+
}): boolean {
|
|
28
|
+
const normalizedSetting = enabledSetting?.trim();
|
|
29
|
+
if (normalizedSetting) return !isFalsy(normalizedSetting);
|
|
30
|
+
return supportsPublishedClipsChromeExtensionHost(hostname);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getCurrentHostname(): string | undefined {
|
|
34
|
+
return typeof window === "undefined" ? undefined : window.location.hostname;
|
|
4
35
|
}
|
|
5
36
|
|
|
6
37
|
const chromeExtensionUrl =
|
|
7
38
|
import.meta.env.VITE_CLIPS_CHROME_EXTENSION_URL?.trim() ??
|
|
8
39
|
"https://chromewebstore.google.com/detail/baoipacpchggcdigagnajakiidcgcffn";
|
|
9
40
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
41
|
+
// The published extension manifest only trusts first-party Clips/local origins.
|
|
42
|
+
// Custom deployments can opt in after publishing a matching extension/listing.
|
|
43
|
+
export const clipsChromeExtensionEnabled = resolveClipsChromeExtensionEnabled({
|
|
44
|
+
enabledSetting: import.meta.env.VITE_CLIPS_CHROME_EXTENSION_ENABLED,
|
|
45
|
+
hostname: getCurrentHostname(),
|
|
46
|
+
});
|
|
13
47
|
|
|
14
48
|
export const clipsChromeExtensionUrl = chromeExtensionUrl || null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
IconBrandChrome,
|
|
4
4
|
IconBrandApple,
|
|
5
5
|
IconBrandWindows,
|
|
6
6
|
IconExternalLink,
|
|
@@ -248,7 +248,7 @@ export default function DownloadPage() {
|
|
|
248
248
|
<section className="mt-10 w-full max-w-xl rounded-2xl border border-border bg-card p-4 text-left shadow-sm">
|
|
249
249
|
<div className="flex items-start gap-3">
|
|
250
250
|
<div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary">
|
|
251
|
-
<
|
|
251
|
+
<IconBrandChrome className="h-4 w-4" />
|
|
252
252
|
</div>
|
|
253
253
|
<div className="min-w-0 flex-1">
|
|
254
254
|
<h2 className="text-sm font-semibold text-foreground">
|
|
@@ -253,7 +253,7 @@ function AgentDiscovery({
|
|
|
253
253
|
title: recording.title,
|
|
254
254
|
agentContextUrl,
|
|
255
255
|
instructions:
|
|
256
|
-
"Fetch agentContextUrl for
|
|
256
|
+
"Fetch agentContextUrl for the transcript and JPEG frame URLs. Fetch the frame URLs to SEE the screen, not just read the transcript.",
|
|
257
257
|
};
|
|
258
258
|
|
|
259
259
|
return (
|
|
@@ -28,6 +28,8 @@ Diagnostics are bounded and redacted before they are saved. Clips does not colle
|
|
|
28
28
|
## Permission Justification
|
|
29
29
|
|
|
30
30
|
- `activeTab`: lets the toolbar action identify the user-selected active tab after the user clicks the extension.
|
|
31
|
+
- `scripting`: injects the on-page recording overlay (countdown, camera bubble, recording controls) into the active tab the user starts recording from, and removes it when the recording ends — via `chrome.scripting.executeScript` authorized by `activeTab`. Used only after the user starts a recording; never injected into background or arbitrary tabs, and no broad host permission is requested.
|
|
32
|
+
- `offscreen`: runs an offscreen document that performs the actual screen and camera capture via `getDisplayMedia`/`getUserMedia`, which a service worker cannot call directly.
|
|
31
33
|
- `debugger`: attaches to only the user-selected tab while a Clips recording is active, then detaches on stop/cancel. It is used to collect console messages, JavaScript exceptions, and fetch/XHR method, URL, status, timing, and failure metadata. It does not read request or response bodies.
|
|
32
34
|
- `storage`: remembers the user's default Clips app URL, capture source, camera toggle, and developer-log preference.
|
|
33
35
|
|
|
@@ -50,21 +52,24 @@ Build the latest Chrome Web Store ZIP from the repo root:
|
|
|
50
52
|
pnpm --filter clips-chrome-extension package
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
Upload the generated artifact
|
|
55
|
+
Upload the generated artifact (the version matches `public/manifest.json`; the
|
|
56
|
+
Chrome Web Store requires each upload to use a higher version than the last):
|
|
54
57
|
|
|
55
58
|
```txt
|
|
56
|
-
templates/clips/chrome-extension/releases/clips-chrome-extension-0.1.
|
|
59
|
+
templates/clips/chrome-extension/releases/clips-chrome-extension-0.1.2.zip
|
|
57
60
|
```
|
|
58
61
|
|
|
59
62
|
## Web App Rollout Gate
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
The Web Store listing is live, and the web app shows the Chrome extension
|
|
65
|
+
option by default on hosts supported by the published manifest
|
|
66
|
+
(`clips.agent-native.com`, `localhost`, and `127.0.0.1`). Other deployments hide
|
|
67
|
+
the option unless they explicitly opt in with a matching extension/listing.
|
|
63
68
|
|
|
64
|
-
- `VITE_CLIPS_CHROME_EXTENSION_ENABLED=1`
|
|
65
|
-
|
|
69
|
+
- `VITE_CLIPS_CHROME_EXTENSION_ENABLED=1` shows the Chrome option on custom
|
|
70
|
+
deployments that have a compatible extension.
|
|
71
|
+
- `VITE_CLIPS_CHROME_EXTENSION_ENABLED=0` (or `false`/`no`/`off`) hides the
|
|
72
|
+
Chrome option even on supported first-party/local hosts.
|
|
66
73
|
- `VITE_CLIPS_CHROME_EXTENSION_URL` overrides the default install URL
|
|
67
74
|
(`https://chromewebstore.google.com/detail/baoipacpchggcdigagnajakiidcgcffn`)
|
|
68
75
|
if a deployment uses a different listing.
|
|
69
|
-
- Leave both unset while submitting the draft so production continues to send
|
|
70
|
-
users directly to the desktop app.
|
|
@@ -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.2",
|
|
6
6
|
"description": "Start Clips recordings from Chrome with optional redacted console and network diagnostics.",
|
|
7
7
|
"minimum_chrome_version": "116",
|
|
8
8
|
"action": {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, rm } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, rm } from "node:fs/promises";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
@@ -8,7 +8,20 @@ const execFileAsync = promisify(execFile);
|
|
|
8
8
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
9
|
const distDir = resolve(root, "dist");
|
|
10
10
|
const releaseDir = resolve(root, "releases");
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
// Derive the artifact name from the built manifest so the zip version never
|
|
13
|
+
// drifts from the source of truth. The Chrome Web Store rejects an upload whose
|
|
14
|
+
// version is not higher than the currently published one.
|
|
15
|
+
const manifest = JSON.parse(
|
|
16
|
+
await readFile(resolve(distDir, "manifest.json"), "utf8"),
|
|
17
|
+
) as { version?: string };
|
|
18
|
+
const version = manifest.version;
|
|
19
|
+
if (!version) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
"dist/manifest.json is missing a version; run the build first",
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
const zipPath = resolve(releaseDir, `clips-chrome-extension-${version}.zip`);
|
|
12
25
|
|
|
13
26
|
await mkdir(releaseDir, { recursive: true });
|
|
14
27
|
await rm(zipPath, { force: true });
|
|
@@ -167,16 +167,6 @@ body {
|
|
|
167
167
|
|
|
168
168
|
/* ---------- Toolbar (vertical left pill, desktop layout) ---------- */
|
|
169
169
|
|
|
170
|
-
@keyframes rec-pulse {
|
|
171
|
-
0%,
|
|
172
|
-
100% {
|
|
173
|
-
opacity: 1;
|
|
174
|
-
}
|
|
175
|
-
50% {
|
|
176
|
-
opacity: 0.3;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
170
|
.toolbar-v {
|
|
181
171
|
/* Fill the iframe so the (opaque) iframe canvas is fully covered by the pill —
|
|
182
172
|
the iframe is clipped to this same 20px radius in styleFrame, so no canvas
|
|
@@ -235,28 +225,17 @@ body {
|
|
|
235
225
|
}
|
|
236
226
|
|
|
237
227
|
.toolbar-v-time {
|
|
238
|
-
display: flex;
|
|
228
|
+
display: inline-flex;
|
|
239
229
|
align-items: center;
|
|
240
|
-
|
|
230
|
+
justify-content: center;
|
|
231
|
+
width: 40px;
|
|
232
|
+
line-height: 1;
|
|
241
233
|
font-variant-numeric: tabular-nums;
|
|
242
234
|
font-size: 13px;
|
|
243
235
|
font-weight: 600;
|
|
244
236
|
color: rgba(255, 255, 255, 0.94);
|
|
245
237
|
}
|
|
246
238
|
|
|
247
|
-
.toolbar-v-dot {
|
|
248
|
-
width: 8px;
|
|
249
|
-
height: 8px;
|
|
250
|
-
border-radius: 50%;
|
|
251
|
-
background: #ef4444;
|
|
252
|
-
animation: rec-pulse 1.4s ease-in-out infinite;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.toolbar-v-paused .toolbar-v-dot {
|
|
256
|
-
background: #f59e0b;
|
|
257
|
-
animation: none;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
239
|
.toolbar-v-pause {
|
|
261
240
|
width: 40px;
|
|
262
241
|
height: 40px;
|
|
@@ -281,11 +281,9 @@ function initToolbar(): void {
|
|
|
281
281
|
|
|
282
282
|
const time = document.createElement("div");
|
|
283
283
|
time.className = "toolbar-v-time";
|
|
284
|
-
const dot = document.createElement("span");
|
|
285
|
-
dot.className = "toolbar-v-dot";
|
|
286
284
|
const clock = document.createElement("span");
|
|
287
285
|
clock.textContent = "0:00";
|
|
288
|
-
time.append(
|
|
286
|
+
time.append(clock);
|
|
289
287
|
|
|
290
288
|
const pauseBtn = makeBtn("toolbar-v-pause", "Pause", ICONS.pause, () => {
|
|
291
289
|
if (state.phase === "paused") send("CLIPS_OVERLAY_RESUME");
|
|
@@ -597,6 +597,15 @@ pub(crate) mod macos {
|
|
|
597
597
|
mic_device_label.as_deref(),
|
|
598
598
|
)?;
|
|
599
599
|
let input_node = unsafe { engine.inputNode() };
|
|
600
|
+
// Finalize input-device format negotiation before reading the format.
|
|
601
|
+
// When `configure_engine_input_device` pins a specific mic, the AUHAL's
|
|
602
|
+
// current device is switched; the input node's `outputFormatForBus(0)`
|
|
603
|
+
// only reflects the new device after `prepare()` runs. Reading it first
|
|
604
|
+
// returns a stale format, so the tap gets installed with a mismatched
|
|
605
|
+
// format and forwards no usable audio to the recognizer — the user
|
|
606
|
+
// speaks but SFSpeechRecognizer reports "No speech detected". Mirrors
|
|
607
|
+
// the working `start_raw_mic_capture` ordering.
|
|
608
|
+
unsafe { engine.prepare() };
|
|
600
609
|
let format = unsafe { input_node.outputFormatForBus(0) };
|
|
601
610
|
|
|
602
611
|
// Install a tap that forwards every PCM buffer into the recognition
|
|
@@ -329,36 +329,78 @@ export async function loadAgentBrowserDiagnostics(recordingId: string) {
|
|
|
329
329
|
return parseBrowserDiagnosticsRow(row);
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
// Most-recent console logs / network requests surfaced in the public agent
|
|
333
|
+
// context. Bounded to keep the agent payload small; the summary still reports
|
|
334
|
+
// the true total counts.
|
|
335
|
+
const MAX_PUBLIC_AGENT_CONSOLE_LOGS = 100;
|
|
336
|
+
const MAX_PUBLIC_AGENT_NETWORK_REQUESTS = 100;
|
|
337
|
+
// Curated warn/error highlights and failed-request highlights.
|
|
338
|
+
const MAX_PUBLIC_AGENT_DIAGNOSTIC_ISSUES = 20;
|
|
339
|
+
|
|
340
|
+
function toPublicConsoleEntry(
|
|
341
|
+
entry: BrowserDiagnosticsData["consoleLogs"][number],
|
|
342
|
+
) {
|
|
343
|
+
return {
|
|
344
|
+
timestampMs: entry.elapsedMs,
|
|
345
|
+
level: entry.level,
|
|
346
|
+
message: entry.message,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function toPublicNetworkEntry(
|
|
351
|
+
entry: BrowserDiagnosticsData["networkRequests"][number],
|
|
352
|
+
) {
|
|
353
|
+
return {
|
|
354
|
+
timestampMs: entry.elapsedMs,
|
|
355
|
+
type: entry.type,
|
|
356
|
+
method: entry.method,
|
|
357
|
+
// Already sanitized at capture time: path is kept, query values are
|
|
358
|
+
// redacted, and auth/hash are stripped.
|
|
359
|
+
url: entry.url,
|
|
360
|
+
status: entry.status ?? null,
|
|
361
|
+
error: entry.error ?? null,
|
|
362
|
+
durationMs: entry.durationMs,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function isFailedNetworkRequest(
|
|
367
|
+
entry: BrowserDiagnosticsData["networkRequests"][number],
|
|
368
|
+
): boolean {
|
|
369
|
+
return (
|
|
370
|
+
Boolean(entry.error) ||
|
|
371
|
+
(typeof entry.status === "number" && entry.status >= 400)
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
332
375
|
function compactBrowserDiagnostics(diagnostics: BrowserDiagnosticsData | null) {
|
|
333
376
|
if (!diagnostics) return null;
|
|
377
|
+
// Full console stream (all levels: debug/log/info/warn/error), redacted at
|
|
378
|
+
// capture time and bounded to the most-recent entries.
|
|
379
|
+
const consoleLogs = diagnostics.consoleLogs
|
|
380
|
+
.slice(-MAX_PUBLIC_AGENT_CONSOLE_LOGS)
|
|
381
|
+
.map(toPublicConsoleEntry);
|
|
382
|
+
// Warn/error highlights kept as a separate convenience list so agents can
|
|
383
|
+
// jump straight to problems without scanning the full stream.
|
|
334
384
|
const consoleIssues = diagnostics.consoleLogs
|
|
335
385
|
.filter((entry) => entry.level === "warn" || entry.level === "error")
|
|
336
|
-
.slice(-
|
|
337
|
-
.map(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
386
|
+
.slice(-MAX_PUBLIC_AGENT_DIAGNOSTIC_ISSUES)
|
|
387
|
+
.map(toPublicConsoleEntry);
|
|
388
|
+
// Full network stream (fetch + XHR), redacted at capture time and bounded.
|
|
389
|
+
const networkRequests = diagnostics.networkRequests
|
|
390
|
+
.slice(-MAX_PUBLIC_AGENT_NETWORK_REQUESTS)
|
|
391
|
+
.map(toPublicNetworkEntry);
|
|
392
|
+
// Failed-request highlights so agents can jump straight to problems.
|
|
342
393
|
const failedNetworkRequests = diagnostics.networkRequests
|
|
343
|
-
.filter(
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
(typeof entry.status === "number" && entry.status >= 400),
|
|
347
|
-
)
|
|
348
|
-
.slice(-20)
|
|
349
|
-
.map((entry) => ({
|
|
350
|
-
timestampMs: entry.elapsedMs,
|
|
351
|
-
type: entry.type,
|
|
352
|
-
method: entry.method,
|
|
353
|
-
status: entry.status ?? null,
|
|
354
|
-
error: entry.error ?? null,
|
|
355
|
-
durationMs: entry.durationMs,
|
|
356
|
-
}));
|
|
394
|
+
.filter(isFailedNetworkRequest)
|
|
395
|
+
.slice(-MAX_PUBLIC_AGENT_DIAGNOSTIC_ISSUES)
|
|
396
|
+
.map(toPublicNetworkEntry);
|
|
357
397
|
return {
|
|
358
398
|
summary: diagnostics.summary,
|
|
399
|
+
consoleLogs,
|
|
359
400
|
consoleIssues,
|
|
401
|
+
networkRequests,
|
|
360
402
|
failedNetworkRequests,
|
|
361
|
-
note: "
|
|
403
|
+
note: "Console logs include all levels (debug/log/info/warn/error). Network requests include method, sanitized URL (path kept, query values redacted), status, and duration. Diagnostics are bounded; the recording's own page URL, request headers, request/response bodies, and cookies are omitted.",
|
|
362
404
|
};
|
|
363
405
|
}
|
|
364
406
|
|
|
@@ -403,7 +445,7 @@ export function buildPublicAgentContext({
|
|
|
403
445
|
"Use transcript.segments for timestamped spoken context.",
|
|
404
446
|
...(browserDiagnostics
|
|
405
447
|
? [
|
|
406
|
-
"Use browserDiagnostics for redacted console
|
|
448
|
+
"Use browserDiagnostics.consoleLogs for the redacted console stream (all levels: debug/log/info/warn/error) and browserDiagnostics.networkRequests for the fetch/XHR requests (method, sanitized URL, status, duration) captured during the recording. browserDiagnostics.consoleIssues highlights just the warnings/errors, and browserDiagnostics.failedNetworkRequests highlights failed requests.",
|
|
407
449
|
]
|
|
408
450
|
: []),
|
|
409
451
|
...(isLoomEmbedBacked
|
|
@@ -411,8 +453,9 @@ export function buildPublicAgentContext({
|
|
|
411
453
|
"This clip is a legacy Loom embed import; frame extraction is not available through Clips until it is reimported as a Clips-hosted video.",
|
|
412
454
|
]
|
|
413
455
|
: [
|
|
414
|
-
"
|
|
415
|
-
"
|
|
456
|
+
"This clip is readable as both text (transcript) and images (JPEG frames) — you can hear AND see it.",
|
|
457
|
+
"To SEE the screen, GET apis.frame.urlTemplate with atMs (returns image/jpeg). Start with recommendedFrames, then fetch additional frames around transcript timestamps that matter for the task.",
|
|
458
|
+
"If you cannot load an image from a URL, you will only have the transcript — tell the user to open the clip in an image-capable agent (ChatGPT, Claude Code, Cursor, Codex) or to upload a frame image directly so you can see it.",
|
|
416
459
|
]),
|
|
417
460
|
];
|
|
418
461
|
|
|
@@ -26,11 +26,16 @@ patterns live in `.agents/skills/`.
|
|
|
26
26
|
- Generated files must be complete, standalone HTML unless the user asks for a
|
|
27
27
|
different export format. They should render in the iframe without a build step.
|
|
28
28
|
- For raster image generation, restyling, or editing existing screenshots/photos,
|
|
29
|
-
use the first-party Assets
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
use the available first-party Assets MCP tool such as `generate-asset` instead
|
|
30
|
+
of placeholders or generic stock imagery. When the Assets picker returns a
|
|
31
|
+
selected asset, preserve `assetId`, `runId`, and URLs verbatim; if a design is
|
|
32
|
+
open, call `insert-asset` with the chosen URL/id, then refine placement with
|
|
33
|
+
`get-design-snapshot` and `edit-design` as needed. If no Assets MCP tool is
|
|
34
|
+
available, use the first-party Assets app via `call-agent` with agent
|
|
35
|
+
`"assets"` when available. If the user attached an image, use its hosted
|
|
36
|
+
chat-attachment URL or call `upload-image` to create one before delegating. If
|
|
37
|
+
no image/upload provider is configured, say that specific setup is needed and
|
|
38
|
+
continue any non-image Design work separately.
|
|
34
39
|
- Use Alpine.js and Tailwind CDN for interactive prototypes. Prefer Alpine
|
|
35
40
|
directives over raw inline event handlers.
|
|
36
41
|
- Navigate between prototype screens with Alpine state (`x-show`), a
|