@agent-native/core 0.68.3 → 0.70.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 +2 -2
- package/corpus/core/CHANGELOG.md +54 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/changelog/parse.ts +245 -0
- package/corpus/core/src/cli/changelog.ts +199 -0
- package/corpus/core/src/cli/index.ts +19 -0
- package/corpus/core/src/cli/recap.ts +24 -1
- package/corpus/core/src/cli/skills.ts +72 -45
- package/corpus/core/src/client/CommandMenu.tsx +183 -75
- package/corpus/core/src/client/agent-chat-adapter.ts +44 -7
- package/corpus/core/src/client/analytics.ts +181 -0
- package/corpus/core/src/client/changelog/Changelog.tsx +321 -0
- package/corpus/core/src/client/index.ts +11 -0
- package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +54 -0
- package/corpus/core/src/client/settings/useBuilderStatus.ts +82 -20
- package/corpus/core/src/extensions/web-search-tool.ts +45 -4
- package/corpus/core/src/mcp/build-server.ts +1 -1
- package/corpus/core/src/mcp/embed-app.ts +112 -6
- package/corpus/core/src/secrets/register-framework-secrets.ts +7 -0
- package/corpus/core/src/server/attribution.ts +211 -0
- package/corpus/core/src/server/auth.ts +6 -0
- package/corpus/core/src/server/better-auth-instance.ts +49 -5
- package/corpus/core/src/server/builder-browser.ts +27 -1
- package/corpus/core/src/server/core-routes-plugin.ts +58 -0
- package/corpus/core/src/server/google-oauth.ts +19 -6
- package/corpus/core/src/shared/mcp-embed-headers.ts +1 -1
- package/corpus/core/src/styles/agent-conversation.css +21 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/corpus/templates/analytics/CHANGELOG.md +10 -0
- package/corpus/templates/analytics/actions/install-dashboard-template.ts +2 -2
- package/corpus/templates/analytics/actions/open-traffic-dashboard.ts +1 -1
- package/corpus/templates/analytics/actions/update-dashboard.ts +5 -3
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +180 -144
- package/corpus/templates/analytics/app/components/layout/Header.tsx +2 -2
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -5
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +221 -213
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +6 -3
- package/corpus/templates/analytics/app/lib/demo-dashboard-path.ts +1 -1
- package/corpus/templates/analytics/app/lib/last-opened.ts +2 -1
- package/corpus/templates/analytics/app/pages/Settings.tsx +4 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/DashboardFilterBar.tsx +2 -2
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +101 -99
- package/corpus/templates/analytics/app/pages/overview/OverviewPage.tsx +1 -1
- package/corpus/templates/analytics/app/routes/adhoc.$id.tsx +18 -5
- package/corpus/templates/analytics/app/routes/catalog.tsx +1 -1
- package/corpus/templates/analytics/app/routes/dashboards.$id.tsx +9 -0
- package/corpus/templates/analytics/app/routes/traffic.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-06-23-the-dashboards-and-analyses-sidebar-settings-buttons-now-sta.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +145 -0
- package/corpus/templates/analytics/server/db/index.ts +1 -1
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +9 -2
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +2 -2
- package/corpus/templates/analytics/server/plugins/core-routes.ts +6 -6
- package/corpus/templates/assets/CHANGELOG.md +10 -0
- package/corpus/templates/assets/app/root.tsx +7 -1
- package/corpus/templates/assets/app/routes/settings.tsx +6 -0
- package/corpus/templates/brain/CHANGELOG.md +10 -0
- package/corpus/templates/brain/app/root.tsx +7 -1
- package/corpus/templates/brain/app/routes/settings.tsx +8 -1
- package/corpus/templates/calendar/CHANGELOG.md +10 -0
- package/corpus/templates/calendar/app/pages/Settings.tsx +4 -0
- package/corpus/templates/calendar/app/root.tsx +7 -1
- package/corpus/templates/chat/CHANGELOG.md +10 -0
- package/corpus/templates/chat/app/root.tsx +7 -1
- package/corpus/templates/clips/CHANGELOG.md +10 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +33 -7
- package/corpus/templates/clips/app/components/player/sign-in-prompt-dialog.tsx +8 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +150 -20
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +72 -20
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +69 -2
- package/corpus/templates/clips/app/components/sharing/slack-share-hint.tsx +71 -0
- package/corpus/templates/clips/app/lib/recorder-preferences.ts +67 -0
- package/corpus/templates/clips/app/root.tsx +7 -1
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +15 -1
- package/corpus/templates/clips/app/routes/_app.trash.tsx +21 -0
- package/corpus/templates/clips/app/routes/record.tsx +92 -8
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +86 -5
- package/corpus/templates/clips/changelog/2026-06-23-clips-shared-in-slack-no-longer-show-a-could-not-start-playb.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-made-the-play-button-on-shared-and-embedded-clips-scale-with.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-public-clip-share-links-now-show-whether-they-ll-play-inline.md +6 -0
- package/corpus/templates/clips/changelog/2026-06-23-screen-camera-recordings-now-keep-the-presenter-s-face-in-th.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +20 -0
- package/corpus/templates/clips/desktop/src/main.tsx +3 -0
- package/corpus/templates/clips/desktop/src/overlays/region-record-border.tsx +76 -0
- package/corpus/templates/clips/desktop/src/styles.css +49 -0
- package/corpus/templates/clips/desktop/src-tauri/capabilities/default.json +2 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +67 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +2 -0
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +4 -1
- package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +51 -1
- package/corpus/templates/clips/shared/share-attribution.ts +79 -0
- package/corpus/templates/content/CHANGELOG.md +10 -0
- package/corpus/templates/content/app/root.tsx +7 -1
- package/corpus/templates/content/vitest.config.ts +3 -0
- package/corpus/templates/design/CHANGELOG.md +10 -0
- package/corpus/templates/design/actions/generate-design.ts +4 -0
- package/corpus/templates/design/app/root.tsx +7 -1
- package/corpus/templates/design/app/routes/settings.tsx +10 -2
- package/corpus/templates/dispatch/CHANGELOG.md +10 -0
- package/corpus/templates/dispatch/app/root.tsx +7 -1
- package/corpus/templates/forms/CHANGELOG.md +10 -0
- package/corpus/templates/forms/app/root.tsx +7 -1
- package/corpus/templates/macros/CHANGELOG.md +10 -0
- package/corpus/templates/macros/app/root.tsx +7 -1
- package/corpus/templates/mail/CHANGELOG.md +10 -0
- package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +3 -0
- package/corpus/templates/mail/app/pages/SettingsPage.tsx +27 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +31 -17
- package/corpus/templates/plan/.agents/skills/visual-plan/references/wireframe.md +7 -4
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +34 -24
- package/corpus/templates/plan/.agents/skills/visual-recap/references/wireframe.md +7 -4
- package/corpus/templates/plan/AGENTS.md +4 -0
- package/corpus/templates/plan/CHANGELOG.md +10 -0
- package/corpus/templates/plan/actions/view-screen.ts +5 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +98 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +107 -7
- package/corpus/templates/plan/app/root.tsx +7 -1
- package/corpus/templates/plan/shared/share-attribution.ts +72 -0
- package/corpus/templates/slides/CHANGELOG.md +10 -0
- package/corpus/templates/slides/app/root.tsx +7 -1
- package/corpus/templates/videos/CHANGELOG.md +4 -151
- package/corpus/templates/videos/app/root.tsx +7 -1
- package/dist/changelog/parse.d.ts +70 -0
- package/dist/changelog/parse.d.ts.map +1 -0
- package/dist/changelog/parse.js +200 -0
- package/dist/changelog/parse.js.map +1 -0
- package/dist/cli/changelog.d.ts +4 -0
- package/dist/cli/changelog.d.ts.map +1 -0
- package/dist/cli/changelog.js +166 -0
- package/dist/cli/changelog.js.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +22 -1
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -3
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +72 -45
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/CommandMenu.d.ts +17 -1
- package/dist/client/CommandMenu.d.ts.map +1 -1
- package/dist/client/CommandMenu.js +49 -13
- package/dist/client/CommandMenu.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +43 -6
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +18 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +177 -0
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/changelog/Changelog.d.ts +47 -0
- package/dist/client/changelog/Changelog.d.ts.map +1 -0
- package/dist/client/changelog/Changelog.js +138 -0
- package/dist/client/changelog/Changelog.js.map +1 -0
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -1
- package/dist/client/index.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 +42 -1
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +2 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +58 -10
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/extensions/web-search-tool.d.ts +5 -3
- package/dist/extensions/web-search-tool.d.ts.map +1 -1
- package/dist/extensions/web-search-tool.js +36 -4
- package/dist/extensions/web-search-tool.js.map +1 -1
- package/dist/mcp/build-server.js +1 -1
- 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 +112 -6
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
- package/dist/secrets/register-framework-secrets.js +6 -0
- package/dist/secrets/register-framework-secrets.js.map +1 -1
- package/dist/server/attribution.d.ts +83 -0
- package/dist/server/attribution.d.ts.map +1 -0
- package/dist/server/attribution.js +178 -0
- package/dist/server/attribution.js.map +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +7 -0
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +9 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +32 -2
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +4 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +20 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +25 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +38 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +16 -2
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/shared/mcp-embed-headers.js +1 -1
- package/dist/shared/mcp-embed-headers.js.map +1 -1
- package/dist/styles/agent-conversation.css +21 -0
- package/dist/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/changelog/SKILL.md +111 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +46 -14
- /package/corpus/templates/analytics/app/routes/{dashboards.tsx → dashboards._index.tsx} +0 -0
|
@@ -1473,6 +1473,22 @@ async function showRegionGuidesForRecording(wantsScreen: boolean) {
|
|
|
1473
1473
|
});
|
|
1474
1474
|
}
|
|
1475
1475
|
|
|
1476
|
+
// Frame the chosen screen region with a live border so the user can see exactly
|
|
1477
|
+
// what's being captured throughout the countdown and recording. The overlay is
|
|
1478
|
+
// capture-excluded and draws its stroke outside the captured pixels, so it never
|
|
1479
|
+
// lands in the video. Torn down with the rest of the recording chrome on stop.
|
|
1480
|
+
async function showRegionRecordBorder(region: RegionCaptureRect | null) {
|
|
1481
|
+
if (!region) return;
|
|
1482
|
+
await invoke("show_region_record_border", {
|
|
1483
|
+
x: region.x,
|
|
1484
|
+
y: region.y,
|
|
1485
|
+
width: region.width,
|
|
1486
|
+
height: region.height,
|
|
1487
|
+
}).catch((err) => {
|
|
1488
|
+
console.warn("[clips-recorder] show_region_record_border failed:", err);
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1476
1492
|
async function runRecordingCountdown(wantsScreen: boolean, audioCue: AudioCue) {
|
|
1477
1493
|
const countdownEvent = waitForCountdownEvent(
|
|
1478
1494
|
COUNTDOWN_EVENT_TIMEOUT_MS,
|
|
@@ -1566,6 +1582,10 @@ async function startNativeFullscreenRecording(
|
|
|
1566
1582
|
|
|
1567
1583
|
if (params.source === "region") {
|
|
1568
1584
|
captureRegion = await selectRegionForRecording();
|
|
1585
|
+
// Frame the selected area now so it stays visible through the countdown
|
|
1586
|
+
// and the whole recording. hide_recording_chrome / hide_overlays tear it
|
|
1587
|
+
// down on stop, cancel, and the error paths below.
|
|
1588
|
+
await showRegionRecordBorder(captureRegion);
|
|
1569
1589
|
}
|
|
1570
1590
|
|
|
1571
1591
|
if (localOnly && localRecordingMode === "separate" && wantsCamera) {
|
|
@@ -12,6 +12,7 @@ import { MeetingNub } from "./overlays/meeting-nub";
|
|
|
12
12
|
import { FlowBar } from "./overlays/flow-bar";
|
|
13
13
|
import { RecordingPill } from "./overlays/recording-pill";
|
|
14
14
|
import { RegionGuideEditor, RegionGuides } from "./overlays/region-guides";
|
|
15
|
+
import { RegionRecordBorder } from "./overlays/region-record-border";
|
|
15
16
|
import "./styles.css";
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -55,6 +56,8 @@ function pickRoute(route: string): React.ReactElement {
|
|
|
55
56
|
return <RegionGuideEditor />;
|
|
56
57
|
case "region-capture-selector":
|
|
57
58
|
return <RegionGuideEditor mode="capture" />;
|
|
59
|
+
case "region-record-border":
|
|
60
|
+
return <RegionRecordBorder />;
|
|
58
61
|
default:
|
|
59
62
|
return <App />;
|
|
60
63
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { getCurrentWindow } from "@tauri-apps/api/window";
|
|
3
|
+
|
|
4
|
+
interface BorderRect {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function clamp01(value: number): number {
|
|
12
|
+
if (!Number.isFinite(value)) return 0;
|
|
13
|
+
return Math.min(1, Math.max(0, value));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The live recording region is handed to this overlay window as a normalized
|
|
18
|
+
* rect in the URL query (`?region=x,y,width,height`) so it never has to wait
|
|
19
|
+
* on a Tauri event (which could race the webview load). All four values are
|
|
20
|
+
* fractions [0,1] of the recording monitor — the same space the region-capture
|
|
21
|
+
* selector emitted them in.
|
|
22
|
+
*/
|
|
23
|
+
function parseRect(search: string): BorderRect | null {
|
|
24
|
+
const raw = new URLSearchParams(search).get("region");
|
|
25
|
+
if (!raw) return null;
|
|
26
|
+
const parts = raw.split(",").map((value) => Number.parseFloat(value));
|
|
27
|
+
if (parts.length !== 4 || parts.some((value) => !Number.isFinite(value))) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const [x, y, width, height] = parts;
|
|
31
|
+
if (width <= 0 || height <= 0) return null;
|
|
32
|
+
return {
|
|
33
|
+
x: clamp01(x),
|
|
34
|
+
y: clamp01(y),
|
|
35
|
+
width: clamp01(width),
|
|
36
|
+
height: clamp01(height),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A thin frame painted around the screen region currently being recorded. The
|
|
42
|
+
* window itself is full-screen, click-through, and capture-excluded (see
|
|
43
|
+
* `show_region_record_border` on the Rust side). The frame is drawn entirely
|
|
44
|
+
* OUTWARD via an outset box-shadow with no fill, so its pixels sit just outside
|
|
45
|
+
* the captured rect and never leak into the recording even on the macOS 15.4+
|
|
46
|
+
* builds where `NSWindowSharingNone` is occasionally bypassed.
|
|
47
|
+
*/
|
|
48
|
+
export function RegionRecordBorder() {
|
|
49
|
+
const [rect] = useState<BorderRect | null>(() =>
|
|
50
|
+
typeof window === "undefined" ? null : parseRect(window.location.search),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (rect) return;
|
|
55
|
+
// No usable region — close the overlay so an empty window never lingers.
|
|
56
|
+
getCurrentWindow()
|
|
57
|
+
.close()
|
|
58
|
+
.catch(() => {});
|
|
59
|
+
}, [rect]);
|
|
60
|
+
|
|
61
|
+
if (!rect) return null;
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="region-record-border-layer" aria-hidden>
|
|
65
|
+
<div
|
|
66
|
+
className="region-record-border-frame"
|
|
67
|
+
style={{
|
|
68
|
+
left: `${rect.x * 100}%`,
|
|
69
|
+
top: `${rect.y * 100}%`,
|
|
70
|
+
width: `${rect.width * 100}%`,
|
|
71
|
+
height: `${rect.height * 100}%`,
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
@@ -3749,6 +3749,55 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
3749
3749
|
backdrop-filter: blur(14px);
|
|
3750
3750
|
}
|
|
3751
3751
|
|
|
3752
|
+
/* ------------------------------------------------------------------------- */
|
|
3753
|
+
/* Overlay: live recording-region border */
|
|
3754
|
+
/* ------------------------------------------------------------------------- */
|
|
3755
|
+
|
|
3756
|
+
.region-record-border-layer {
|
|
3757
|
+
position: fixed;
|
|
3758
|
+
inset: 0;
|
|
3759
|
+
width: 100vw;
|
|
3760
|
+
height: 100vh;
|
|
3761
|
+
overflow: hidden;
|
|
3762
|
+
pointer-events: none;
|
|
3763
|
+
}
|
|
3764
|
+
|
|
3765
|
+
.region-record-border-frame {
|
|
3766
|
+
position: absolute;
|
|
3767
|
+
border-radius: 5px;
|
|
3768
|
+
/* No fill, and the stroke is painted OUTWARD with an outset box-shadow so it
|
|
3769
|
+
lands just outside the captured rect — never inside the recorded video. */
|
|
3770
|
+
box-shadow:
|
|
3771
|
+
0 0 0 2px rgba(239, 68, 68, 0.95),
|
|
3772
|
+
0 0 0 4px rgba(239, 68, 68, 0.32),
|
|
3773
|
+
0 0 26px 6px rgba(239, 68, 68, 0.26);
|
|
3774
|
+
animation: region-record-border-pulse 1.8s ease-in-out infinite;
|
|
3775
|
+
}
|
|
3776
|
+
|
|
3777
|
+
/* Gentle pulse that mirrors the live recording dot, signalling "recording
|
|
3778
|
+
now". Honour reduced-motion by holding the frame steady. */
|
|
3779
|
+
@keyframes region-record-border-pulse {
|
|
3780
|
+
0%,
|
|
3781
|
+
100% {
|
|
3782
|
+
box-shadow:
|
|
3783
|
+
0 0 0 2px rgba(239, 68, 68, 0.9),
|
|
3784
|
+
0 0 0 4px rgba(239, 68, 68, 0.28),
|
|
3785
|
+
0 0 22px 5px rgba(239, 68, 68, 0.2);
|
|
3786
|
+
}
|
|
3787
|
+
50% {
|
|
3788
|
+
box-shadow:
|
|
3789
|
+
0 0 0 2px rgba(239, 68, 68, 1),
|
|
3790
|
+
0 0 0 4px rgba(239, 68, 68, 0.44),
|
|
3791
|
+
0 0 30px 8px rgba(239, 68, 68, 0.34);
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
|
|
3795
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3796
|
+
.region-record-border-frame {
|
|
3797
|
+
animation: none;
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3752
3801
|
@keyframes flow-bar-in {
|
|
3753
3802
|
from {
|
|
3754
3803
|
opacity: 0;
|
|
@@ -31,6 +31,7 @@ const FINALIZING_LABEL: &str = "finalizing";
|
|
|
31
31
|
const FLOW_BAR_LABEL: &str = "flow-bar";
|
|
32
32
|
const REGION_GUIDES_LABEL: &str = "region-guides";
|
|
33
33
|
const REGION_GUIDE_EDITOR_LABEL: &str = "region-guide-editor";
|
|
34
|
+
const REGION_RECORD_BORDER_LABEL: &str = "region-record-border";
|
|
34
35
|
|
|
35
36
|
/// Physical-pixel bubble sizes. Logical px on retina = physical / 2, so these
|
|
36
37
|
/// map to ~96 (small) and ~180 (medium) logical px — matching Loom's camera
|
|
@@ -448,6 +449,65 @@ pub async fn hide_region_guides(app: AppHandle) -> Result<(), String> {
|
|
|
448
449
|
Ok(())
|
|
449
450
|
}
|
|
450
451
|
|
|
452
|
+
/// Live border framing the region currently being recorded. Like the region
|
|
453
|
+
/// guides this is a full-screen, click-through, capture-excluded overlay — but
|
|
454
|
+
/// the rect is ephemeral (it belongs to one recording, not the saved preset),
|
|
455
|
+
/// so it's handed in via the URL query rather than read from config. The React
|
|
456
|
+
/// view paints only an OUTWARD frame so the stroke stays out of the captured
|
|
457
|
+
/// pixels. The recording flow owns this window; it's torn down by
|
|
458
|
+
/// `hide_recording_chrome` / `hide_overlays` when capture stops.
|
|
459
|
+
#[tauri::command]
|
|
460
|
+
pub async fn show_region_record_border(
|
|
461
|
+
app: AppHandle,
|
|
462
|
+
x: f64,
|
|
463
|
+
y: f64,
|
|
464
|
+
width: f64,
|
|
465
|
+
height: f64,
|
|
466
|
+
) -> Result<(), String> {
|
|
467
|
+
if !(width > 0.0 && height > 0.0) {
|
|
468
|
+
return Ok(());
|
|
469
|
+
}
|
|
470
|
+
if let Some(existing) = app.get_webview_window(REGION_RECORD_BORDER_LABEL) {
|
|
471
|
+
let _ = existing.close();
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
let (mx, my, mw, mh) = tray_monitor_physical_rect(&app);
|
|
475
|
+
let url = WebviewUrl::App(
|
|
476
|
+
format!("index.html?region={x:.6},{y:.6},{width:.6},{height:.6}#region-record-border")
|
|
477
|
+
.into(),
|
|
478
|
+
);
|
|
479
|
+
let win = WebviewWindowBuilder::new(&app, REGION_RECORD_BORDER_LABEL, url)
|
|
480
|
+
.title("Clips Recording Region")
|
|
481
|
+
.decorations(false)
|
|
482
|
+
.transparent(true)
|
|
483
|
+
.always_on_top(true)
|
|
484
|
+
.skip_taskbar(true)
|
|
485
|
+
.resizable(false)
|
|
486
|
+
.shadow(false)
|
|
487
|
+
.visible(false)
|
|
488
|
+
.focused(false)
|
|
489
|
+
.build()
|
|
490
|
+
.map_err(|e| {
|
|
491
|
+
eprintln!("[clips-tray] region record border build failed: {}", e);
|
|
492
|
+
e.to_string()
|
|
493
|
+
})?;
|
|
494
|
+
let _ = win.set_size(tauri::Size::Physical(PhysicalSize::new(mw, mh)));
|
|
495
|
+
let _ = win.set_position(PhysicalPosition::new(mx, my));
|
|
496
|
+
let _ = win.set_ignore_cursor_events(true);
|
|
497
|
+
set_capture_excluded_always(&win);
|
|
498
|
+
configure_overlay_behavior(&win);
|
|
499
|
+
crate::util::show_without_activation(&win);
|
|
500
|
+
Ok(())
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
#[tauri::command]
|
|
504
|
+
pub async fn hide_region_record_border(app: AppHandle) -> Result<(), String> {
|
|
505
|
+
if let Some(w) = app.get_webview_window(REGION_RECORD_BORDER_LABEL) {
|
|
506
|
+
let _ = w.close();
|
|
507
|
+
}
|
|
508
|
+
Ok(())
|
|
509
|
+
}
|
|
510
|
+
|
|
451
511
|
/// Reconcile the always-on region-guides overlay with the current config.
|
|
452
512
|
/// Called from config saves and on startup so the guides window matches the
|
|
453
513
|
/// `always_visible` toggle without needing a recording-flow round trip. When a
|
|
@@ -748,6 +808,7 @@ pub async fn hide_overlays(app: AppHandle) -> Result<(), String> {
|
|
|
748
808
|
FINALIZING_LABEL,
|
|
749
809
|
FLOW_BAR_LABEL,
|
|
750
810
|
REGION_GUIDES_LABEL,
|
|
811
|
+
REGION_RECORD_BORDER_LABEL,
|
|
751
812
|
] {
|
|
752
813
|
if let Some(w) = app.get_webview_window(label) {
|
|
753
814
|
let _ = w.close();
|
|
@@ -772,7 +833,9 @@ pub async fn hide_recording_chrome(app: AppHandle) -> Result<(), String> {
|
|
|
772
833
|
// toggle — otherwise we'd flicker close→reopen right after stop.
|
|
773
834
|
let g = crate::config::feature_config(&app).region_guides;
|
|
774
835
|
let keep_region_guides = g.always_visible && g.enabled && !g.rects.is_empty();
|
|
775
|
-
|
|
836
|
+
// The recording-region border belongs to a single recording (never pinned),
|
|
837
|
+
// so it always tears down here alongside the countdown + toolbar.
|
|
838
|
+
let mut labels: Vec<&str> = vec![COUNTDOWN_LABEL, TOOLBAR_LABEL, REGION_RECORD_BORDER_LABEL];
|
|
776
839
|
if !keep_region_guides {
|
|
777
840
|
labels.push(REGION_GUIDES_LABEL);
|
|
778
841
|
}
|
|
@@ -1438,6 +1501,9 @@ pub async fn reset_state(app: AppHandle) -> Result<(), String> {
|
|
|
1438
1501
|
if let Some(w) = app.get_webview_window(REGION_GUIDES_LABEL) {
|
|
1439
1502
|
let _ = w.close();
|
|
1440
1503
|
}
|
|
1504
|
+
if let Some(w) = app.get_webview_window(REGION_RECORD_BORDER_LABEL) {
|
|
1505
|
+
let _ = w.close();
|
|
1506
|
+
}
|
|
1441
1507
|
if let Some(window) = app.get_webview_window("popover") {
|
|
1442
1508
|
// Restore normal size in case the window was shrunk to a pinhole
|
|
1443
1509
|
// during recording — otherwise it would reappear as a 2×2 dot.
|
|
@@ -68,6 +68,8 @@ pub fn run() {
|
|
|
68
68
|
clips::hide_recording_chrome,
|
|
69
69
|
clips::show_region_guides,
|
|
70
70
|
clips::hide_region_guides,
|
|
71
|
+
clips::show_region_record_border,
|
|
72
|
+
clips::hide_region_record_border,
|
|
71
73
|
clips::show_region_guide_editor,
|
|
72
74
|
clips::show_region_capture_selector,
|
|
73
75
|
clips::close_bubble,
|
|
@@ -208,7 +208,10 @@ pub fn reapply_capture_exclusion_to_overlays(app: &tauri::AppHandle) {
|
|
|
208
208
|
set_window_capture_excluded(window, false);
|
|
209
209
|
continue;
|
|
210
210
|
}
|
|
211
|
-
let private_guide = matches!(
|
|
211
|
+
let private_guide = matches!(
|
|
212
|
+
label.as_str(),
|
|
213
|
+
"region-guides" | "region-guide-editor" | "region-record-border"
|
|
214
|
+
);
|
|
212
215
|
set_window_capture_excluded(window, private_guide || !visible);
|
|
213
216
|
}
|
|
214
217
|
}
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
import { getOrgContext } from "@agent-native/core/org";
|
|
50
50
|
import { resolveAccess } from "@agent-native/core/sharing";
|
|
51
51
|
import {
|
|
52
|
+
captureRouteError,
|
|
52
53
|
getSession,
|
|
53
54
|
runWithRequestContext,
|
|
54
55
|
signShortLivedToken,
|
|
@@ -404,7 +405,56 @@ export default defineEventHandler(async (event: H3Event) => {
|
|
|
404
405
|
setResponseStatus(event, upstream.status);
|
|
405
406
|
return { error: upstream.error };
|
|
406
407
|
}
|
|
407
|
-
|
|
408
|
+
// The provider answered, but with a server error (e.g. the CDN asset is
|
|
409
|
+
// broken and returns 5xx). Don't proxy an opaque upstream error — and
|
|
410
|
+
// don't risk reconstructing a Response from it, which previously threw
|
|
411
|
+
// and surfaced as an unhandled 500 on every request. Capture it so the
|
|
412
|
+
// broken asset is diagnosable, and return a clean 502.
|
|
413
|
+
if (upstream.status >= 500) {
|
|
414
|
+
captureRouteError(
|
|
415
|
+
new Error(
|
|
416
|
+
`Storage provider returned ${upstream.status} for recording media`,
|
|
417
|
+
),
|
|
418
|
+
{
|
|
419
|
+
route: "api/video",
|
|
420
|
+
tags: {
|
|
421
|
+
mediaPath: "provider-proxy",
|
|
422
|
+
upstreamStatus: String(upstream.status),
|
|
423
|
+
},
|
|
424
|
+
extra: { recordingId },
|
|
425
|
+
},
|
|
426
|
+
);
|
|
427
|
+
setResponseStatus(event, 502);
|
|
428
|
+
setResponseHeader(
|
|
429
|
+
event,
|
|
430
|
+
"Cache-Control",
|
|
431
|
+
"private, max-age=0, no-store",
|
|
432
|
+
);
|
|
433
|
+
return {
|
|
434
|
+
error: "The recording's media could not be loaded from storage.",
|
|
435
|
+
upstreamStatus: upstream.status,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
return providerResponse(upstream);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
// Reconstructing the proxied Response should not happen, but if it
|
|
442
|
+
// does, fail cleanly instead of as an unhandled 500.
|
|
443
|
+
captureRouteError(err, {
|
|
444
|
+
route: "api/video",
|
|
445
|
+
tags: { mediaPath: "provider-proxy-response" },
|
|
446
|
+
extra: { recordingId, upstreamStatus: String(upstream.status) },
|
|
447
|
+
});
|
|
448
|
+
setResponseStatus(event, 502);
|
|
449
|
+
setResponseHeader(
|
|
450
|
+
event,
|
|
451
|
+
"Cache-Control",
|
|
452
|
+
"private, max-age=0, no-store",
|
|
453
|
+
);
|
|
454
|
+
return {
|
|
455
|
+
error: "The recording's media could not be loaded from storage.",
|
|
456
|
+
};
|
|
457
|
+
}
|
|
408
458
|
}
|
|
409
459
|
const mimeType =
|
|
410
460
|
typeof blob?.mimeType === "string" ? blob.mimeType : "video/webm";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Viral attribution contract for shared Clips links.
|
|
3
|
+
*
|
|
4
|
+
* Shared clip URLs self-attribute so the signup funnel can be measured even
|
|
5
|
+
* when `document.referrer` is empty (desktop app, Slack, native clients, etc.).
|
|
6
|
+
* The framework captures first-touch from these params into a cookie and
|
|
7
|
+
* enriches the `signup` event; Clips' job is to (a) tag share/embed URLs and
|
|
8
|
+
* (b) emit funnel events from the public share page.
|
|
9
|
+
*
|
|
10
|
+
* Contract strings are centralized here so the minting side (share dialog) and
|
|
11
|
+
* the measuring side (public share page) cannot drift apart.
|
|
12
|
+
*
|
|
13
|
+
* Privacy: `via` must be a non-PII stable id (e.g. the owner's user id), never
|
|
14
|
+
* an email. Omit `via` rather than leak PII into a public URL or event.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Fixed referral source for clip shares. */
|
|
18
|
+
export const CLIP_SHARE_REF = "clip_share";
|
|
19
|
+
|
|
20
|
+
/** Query param names that carry attribution. */
|
|
21
|
+
export const REF_PARAM = "ref";
|
|
22
|
+
export const VIA_PARAM = "via";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Append `ref=clip_share` (and `via=<ownerId>` when a non-PII owner id is
|
|
26
|
+
* known) to an absolute share/embed URL, preserving any existing query params.
|
|
27
|
+
* Returns the input unchanged when it isn't a parseable absolute URL.
|
|
28
|
+
*/
|
|
29
|
+
export function withShareAttribution(
|
|
30
|
+
url: string,
|
|
31
|
+
ownerId?: string | null,
|
|
32
|
+
): string {
|
|
33
|
+
if (!url) return url;
|
|
34
|
+
try {
|
|
35
|
+
const parsed = new URL(url);
|
|
36
|
+
parsed.searchParams.set(REF_PARAM, CLIP_SHARE_REF);
|
|
37
|
+
const owner = (ownerId ?? "").trim();
|
|
38
|
+
if (owner) parsed.searchParams.set(VIA_PARAM, owner);
|
|
39
|
+
return parsed.toString();
|
|
40
|
+
} catch {
|
|
41
|
+
return url;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type ShareAttribution = {
|
|
46
|
+
ref: string | undefined;
|
|
47
|
+
via: string | undefined;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Read `ref`/`via` from a query string (e.g. `window.location.search`). Falls
|
|
52
|
+
* back to `ref=clip_share` so downstream attribution stays meaningful even when
|
|
53
|
+
* the visitor arrived via a link that lost the param.
|
|
54
|
+
*/
|
|
55
|
+
export function readShareAttribution(search: string): ShareAttribution {
|
|
56
|
+
let ref: string | undefined;
|
|
57
|
+
let via: string | undefined;
|
|
58
|
+
try {
|
|
59
|
+
const params = new URLSearchParams(search ?? "");
|
|
60
|
+
ref = params.get(REF_PARAM) ?? undefined;
|
|
61
|
+
via = params.get(VIA_PARAM) ?? undefined;
|
|
62
|
+
} catch {
|
|
63
|
+
// Ignore malformed query strings — fall through to the default below.
|
|
64
|
+
}
|
|
65
|
+
return { ref: ref || CLIP_SHARE_REF, via: via || undefined };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Build the attribution-forwarding signup path so attribution survives even if
|
|
70
|
+
* cookies are blocked. The framework also captures these params on the
|
|
71
|
+
* `/signup` page load.
|
|
72
|
+
*/
|
|
73
|
+
export function buildSignupAttributionQuery(via?: string | null): string {
|
|
74
|
+
const params = new URLSearchParams();
|
|
75
|
+
params.set(REF_PARAM, CLIP_SHARE_REF);
|
|
76
|
+
const owner = (via ?? "").trim();
|
|
77
|
+
if (owner) params.set(VIA_PARAM, owner);
|
|
78
|
+
return params.toString();
|
|
79
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Agent-Native Content are documented here. Open it any
|
|
4
|
+
time from the command menu (Cmd+K → "What's new").
|
|
5
|
+
|
|
6
|
+
## 2026-06-23
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- See what's new right inside Agent-Native Content — a changelog now lives in the command menu (Cmd+K).
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from "@agent-native/core/client";
|
|
27
27
|
import { useDbSync } from "./hooks/use-db-sync";
|
|
28
28
|
import { useNavigationState } from "./hooks/use-navigation-state";
|
|
29
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
29
30
|
import type { LinksFunction } from "react-router";
|
|
30
31
|
import stylesheet from "./global.css?url";
|
|
31
32
|
import { configureTracking } from "@agent-native/core/client";
|
|
@@ -247,7 +248,12 @@ export default function Root() {
|
|
|
247
248
|
>
|
|
248
249
|
<AppSetup />
|
|
249
250
|
<Toaster />
|
|
250
|
-
<CommandMenu
|
|
251
|
+
<CommandMenu
|
|
252
|
+
open={cmdkOpen}
|
|
253
|
+
onOpenChange={setCmdkOpen}
|
|
254
|
+
changelog={changelog}
|
|
255
|
+
changelogKey="content"
|
|
256
|
+
>
|
|
251
257
|
<CommandMenu.Group heading="Content">
|
|
252
258
|
<CommandMenu.Item onSelect={() => {}}>
|
|
253
259
|
Search documents
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Design are documented here. Open it any time
|
|
4
|
+
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
|
+
|
|
6
|
+
## 2026-06-23
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- See what's new right inside Design — a changelog now lives in the command menu (Cmd+K) and in Settings.
|
|
@@ -29,6 +29,10 @@ export default defineAction({
|
|
|
29
29
|
"The agent calls this after generating HTML/CSS/JSX content to persist it " +
|
|
30
30
|
"as files in the design project. Creates or updates files as needed. " +
|
|
31
31
|
"Returns the saved files and design URL path for iframe rendering. " +
|
|
32
|
+
"Keep the first save compact and working; for large designs, persist a minimal " +
|
|
33
|
+
"version then refine individual files with `edit-design` (search/replace) rather " +
|
|
34
|
+
"than resending a big multi-file payload — a single oversized payload can get cut " +
|
|
35
|
+
"off mid-stream and stall the turn. " +
|
|
32
36
|
"Do not report a design as ready until this action succeeds.",
|
|
33
37
|
schema: z.object({
|
|
34
38
|
designId: z.string().describe("Design project ID to save content to"),
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
configureTracking,
|
|
15
15
|
} from "@agent-native/core/client";
|
|
16
16
|
import { IconSun, IconMoon } from "@tabler/icons-react";
|
|
17
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
17
18
|
import { Toaster } from "@/components/ui/sonner";
|
|
18
19
|
import { Layout as AppLayout } from "@/components/layout/Layout";
|
|
19
20
|
import type { LinksFunction } from "react-router";
|
|
@@ -99,7 +100,12 @@ export default function Root() {
|
|
|
99
100
|
<AppProviders queryClient={queryClient}>
|
|
100
101
|
<DbSyncSetup />
|
|
101
102
|
<Toaster richColors position="bottom-left" />
|
|
102
|
-
<CommandMenu
|
|
103
|
+
<CommandMenu
|
|
104
|
+
open={cmdkOpen}
|
|
105
|
+
onOpenChange={setCmdkOpen}
|
|
106
|
+
changelog={changelog}
|
|
107
|
+
changelogKey="design"
|
|
108
|
+
>
|
|
103
109
|
<CommandMenu.Group heading="Actions">
|
|
104
110
|
<CommandMenu.Item onSelect={() => {}}>Search</CommandMenu.Item>
|
|
105
111
|
</CommandMenu.Group>
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
SettingsPanel,
|
|
3
|
+
useDevMode,
|
|
4
|
+
ChangelogSettingsCard,
|
|
5
|
+
} from "@agent-native/core/client";
|
|
6
|
+
import changelog from "../../CHANGELOG.md?raw";
|
|
2
7
|
|
|
3
8
|
export function meta() {
|
|
4
9
|
return [{ title: "Settings — Design" }];
|
|
@@ -8,12 +13,15 @@ export default function SettingsRoute() {
|
|
|
8
13
|
const { isDevMode, canToggle, setDevMode } = useDevMode();
|
|
9
14
|
|
|
10
15
|
return (
|
|
11
|
-
<div className="flex h-full min-h-0 flex-col bg-background">
|
|
16
|
+
<div className="flex h-full min-h-0 flex-col overflow-y-auto bg-background">
|
|
12
17
|
<SettingsPanel
|
|
13
18
|
isDevMode={isDevMode}
|
|
14
19
|
onToggleDevMode={() => setDevMode(!isDevMode)}
|
|
15
20
|
showDevToggle={canToggle}
|
|
16
21
|
/>
|
|
22
|
+
<div className="mx-auto w-full max-w-2xl px-4 pb-8">
|
|
23
|
+
<ChangelogSettingsCard markdown={changelog} />
|
|
24
|
+
</div>
|
|
17
25
|
</div>
|
|
18
26
|
);
|
|
19
27
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Agent-Native Dispatch are documented here. Open it any
|
|
4
|
+
time from the command menu (Cmd+K → "What's new").
|
|
5
|
+
|
|
6
|
+
## 2026-06-23
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- See what's new right inside Agent-Native Dispatch — a changelog now lives in the command menu (Cmd+K).
|
|
@@ -25,6 +25,7 @@ import { useTheme } from "next-themes";
|
|
|
25
25
|
import { Layout as AppLayout } from "@agent-native/dispatch/components";
|
|
26
26
|
import type { LinksFunction } from "react-router";
|
|
27
27
|
import { dispatchExtensions } from "./dispatch-extensions";
|
|
28
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
28
29
|
import stylesheet from "./global.css?url";
|
|
29
30
|
|
|
30
31
|
configureTracking({
|
|
@@ -166,7 +167,12 @@ function AppContent() {
|
|
|
166
167
|
return (
|
|
167
168
|
<>
|
|
168
169
|
<DbSyncSetup />
|
|
169
|
-
<CommandMenu
|
|
170
|
+
<CommandMenu
|
|
171
|
+
open={cmdkOpen}
|
|
172
|
+
onOpenChange={setCmdkOpen}
|
|
173
|
+
changelog={changelog}
|
|
174
|
+
changelogKey="dispatch"
|
|
175
|
+
>
|
|
170
176
|
<CommandMenu.Group heading="Actions">
|
|
171
177
|
<CommandMenu.Item onSelect={() => {}}>Search</CommandMenu.Item>
|
|
172
178
|
</CommandMenu.Group>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable user-facing changes to Agent-Native Forms are documented here. Open it any
|
|
4
|
+
time from the command menu (Cmd+K → "What's new").
|
|
5
|
+
|
|
6
|
+
## 2026-06-23
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- See what's new right inside Agent-Native Forms — a changelog now lives in the command menu (Cmd+K).
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
setClientAppState,
|
|
28
28
|
} from "@agent-native/core/client";
|
|
29
29
|
import type { LinksFunction } from "react-router";
|
|
30
|
+
import changelog from "../CHANGELOG.md?raw";
|
|
30
31
|
import stylesheet from "./global.css?url";
|
|
31
32
|
import { TAB_ID } from "@/lib/tab-id";
|
|
32
33
|
|
|
@@ -198,7 +199,12 @@ export default function Root() {
|
|
|
198
199
|
<NavigationStateSync />
|
|
199
200
|
<UrlStateSync />
|
|
200
201
|
<OpenLinkInterceptor />
|
|
201
|
-
<CommandMenu
|
|
202
|
+
<CommandMenu
|
|
203
|
+
open={cmdkOpen}
|
|
204
|
+
onOpenChange={setCmdkOpen}
|
|
205
|
+
changelog={changelog}
|
|
206
|
+
changelogKey="forms"
|
|
207
|
+
>
|
|
202
208
|
<CommandMenu.Group heading="Forms">
|
|
203
209
|
<CommandMenu.Item onSelect={() => {}}>Search forms</CommandMenu.Item>
|
|
204
210
|
</CommandMenu.Group>
|