@agent-native/core 0.114.6 → 0.114.8
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 +15 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/cli/mcp-config-writers.ts +6 -4
- package/corpus/core/src/cli/mcp.ts +124 -0
- package/corpus/core/src/cli/skills-content/help.ts +4 -3
- package/corpus/core/src/cli/skills-content/index.ts +1 -0
- package/corpus/core/src/cli/skills-content/rewind-skill.ts +52 -0
- package/corpus/core/src/cli/skills.ts +115 -13
- package/corpus/core/src/mcp/screen-memory-stdio.ts +1360 -104
- package/corpus/core/src/mcp-client/index.ts +9 -0
- package/corpus/core/src/mcp-client/screen-memory-local.ts +847 -13
- package/corpus/core/src/server/agent-chat-plugin.ts +16 -9
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +19 -7
- package/corpus/templates/analytics/app/hooks/use-chart-tooltip-portal.ts +60 -0
- package/corpus/templates/analytics/app/routes/chart.tsx +1 -1
- package/corpus/templates/analytics/changelog/2026-07-20-dashboard-requests-no-longer-stall-without-progress.md +6 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -0
- package/corpus/templates/clips/actions/apply-rewind-extension.ts +195 -0
- package/corpus/templates/clips/actions/delete-agent-recording-if-unpromoted.ts +64 -0
- package/corpus/templates/clips/actions/get-rewind-extension-request.ts +22 -0
- package/corpus/templates/clips/actions/get-screen-memory-status.ts +18 -2
- package/corpus/templates/clips/actions/list-rewind-extension-requests.ts +52 -0
- package/corpus/templates/clips/actions/make-recording-private-for-rewind.ts +55 -0
- package/corpus/templates/clips/actions/query-screen-memory-context.ts +4 -4
- package/corpus/templates/clips/actions/request-rewind-extension.ts +81 -0
- package/corpus/templates/clips/actions/update-rewind-extension-request.ts +47 -0
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +25 -0
- package/corpus/templates/clips/app/components/editor/editor-toolbar.tsx +36 -0
- package/corpus/templates/clips/app/components/editor/rewind-extension-dialog.tsx +338 -0
- package/corpus/templates/clips/app/components/editor/stitch-manager.tsx +1 -16
- package/corpus/templates/clips/app/components/editor/timeline.tsx +26 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +18 -0
- package/corpus/templates/clips/app/lib/ffmpeg-export.ts +19 -12
- package/corpus/templates/clips/app/lib/rewind-visibility.ts +31 -0
- package/corpus/templates/clips/app/lib/timestamp-mapping.ts +7 -0
- package/corpus/templates/clips/app/lib/upload-file-client.ts +17 -0
- package/corpus/templates/clips/changelog/2026-07-14-rewind-keeps-recent-screen-context-local-and-turns-it-into-clips.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-active-clips-keep-rewind-stable-and-settings-clear.md +12 -0
- package/corpus/templates/clips/changelog/2026-07-17-clicking-the-clips-icon-during-a-recording-now-opens-the-app.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-default-mic-now-uses-the-mac-default-and-transcription-shares-one-capture.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-full-screen-clips-finalize-even-when-screencapturekit-stop-hangs.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-normal-full-screen-clips-no-longer-stop-immediately-after-th.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-can-hand-one-bounded-private-clip-to-your-agent.md +12 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-home-can-copy-a-local-agent-prompt.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-now-has-a-calm-home-status-focused-first-run-consent-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-rewind-settings-are-smaller-clearer-and-agent-first.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-17-the-full-clips-interface-stays-available-while-recording.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-18-rewind-organizes-recent-work-into-local-searchable-chapters.md +8 -0
- package/corpus/templates/clips/changelog/2026-07-18-searchable-rewind-chapters.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-19-rewind-backed-recordings-now-start-immediately-after-the-cou.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-20-rewind-can-set-up-your-local-agent-once-so-future-requests-w.md +6 -0
- package/corpus/templates/clips/desktop/package.json +1 -0
- package/corpus/templates/clips/desktop/scripts/sign-macos-local.ts +12 -1
- package/corpus/templates/clips/desktop/src/app.tsx +2498 -239
- package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +21 -1
- package/corpus/templates/clips/desktop/src/components/Switch.tsx +3 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +156 -24
- package/corpus/templates/clips/desktop/src/lib/native-recording-warm.ts +6 -7
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +1763 -1160
- package/corpus/templates/clips/desktop/src/lib/rewind-agent-prompt.ts +9 -0
- package/corpus/templates/clips/desktop/src/lib/rewind-recording-start.ts +20 -0
- package/corpus/templates/clips/desktop/src/main.tsx +3 -0
- package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +14 -14
- package/corpus/templates/clips/desktop/src/overlays/onboarding.tsx +4 -4
- package/corpus/templates/clips/desktop/src/overlays/preparing.tsx +13 -0
- package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +27 -2
- package/corpus/templates/clips/desktop/src/shared/config.ts +16 -0
- package/corpus/templates/clips/desktop/src/styles.css +956 -134
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +5 -0
- package/corpus/templates/clips/desktop/src-tauri/build.rs +69 -1
- package/corpus/templates/clips/desktop/src-tauri/src/accessibility.rs +386 -12
- package/corpus/templates/clips/desktop/src-tauri/src/capture_audio_bus.rs +382 -0
- package/corpus/templates/clips/desktop/src-tauri/src/capture_graph.rs +777 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +249 -22
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +148 -1
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +58 -4
- package/corpus/templates/clips/desktop/src-tauri/src/logfile.rs +13 -1
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +1505 -51
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/live_upload.rs +124 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1006 -95
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_capture_suspension.rs +165 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_chapters.rs +2434 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_clip.rs +1650 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_egress.rs +643 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_local_ask.rs +803 -0
- package/corpus/templates/clips/desktop/src-tauri/src/rewind_meeting_history.rs +595 -0
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory.rs +2900 -91
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory_ocr.rs +360 -0
- package/corpus/templates/clips/desktop/src-tauri/src/screen_memory_transcript.rs +408 -0
- package/corpus/templates/clips/desktop/src-tauri/src/shortcuts.rs +114 -33
- package/corpus/templates/clips/desktop/src-tauri/src/state.rs +2 -2
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +13 -3
- package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +4 -1
- package/corpus/templates/clips/desktop/src-tauri/src/util.rs +7 -13
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +198 -11
- package/corpus/templates/clips/desktop/src-tauri/tauri.alpha.conf.json +17 -0
- package/corpus/toolkit/CHANGELOG.md +6 -0
- package/corpus/toolkit/package.json +1 -1
- package/dist/cli/mcp-config-writers.d.ts +2 -2
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +6 -6
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.d.ts +14 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +79 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/skills-content/help.d.ts +1 -1
- package/dist/cli/skills-content/help.d.ts.map +1 -1
- package/dist/cli/skills-content/help.js +4 -3
- package/dist/cli/skills-content/help.js.map +1 -1
- package/dist/cli/skills-content/index.d.ts +1 -0
- package/dist/cli/skills-content/index.d.ts.map +1 -1
- package/dist/cli/skills-content/index.js +1 -0
- package/dist/cli/skills-content/index.js.map +1 -1
- package/dist/cli/skills-content/rewind-skill.d.ts +2 -0
- package/dist/cli/skills-content/rewind-skill.d.ts.map +1 -0
- package/dist/cli/skills-content/rewind-skill.js +53 -0
- package/dist/cli/skills-content/rewind-skill.js.map +1 -0
- package/dist/cli/skills.d.ts +6 -0
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +90 -14
- package/dist/cli/skills.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +365 -0
- package/dist/mcp/screen-memory-stdio.d.ts.map +1 -1
- package/dist/mcp/screen-memory-stdio.js +1014 -91
- package/dist/mcp/screen-memory-stdio.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/screen-memory-local.d.ts +90 -0
- package/dist/mcp-client/screen-memory-local.d.ts.map +1 -1
- package/dist/mcp-client/screen-memory-local.js +590 -12
- package/dist/mcp-client/screen-memory-local.js.map +1 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/agent-chat-plugin.d.ts +5 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +10 -9
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/package.json +2 -2
- package/src/cli/mcp-config-writers.ts +6 -4
- package/src/cli/mcp.ts +124 -0
- package/src/cli/skills-content/help.ts +4 -3
- package/src/cli/skills-content/index.ts +1 -0
- package/src/cli/skills-content/rewind-skill.ts +52 -0
- package/src/cli/skills.ts +115 -13
- package/src/mcp/screen-memory-stdio.ts +1360 -104
- package/src/mcp-client/index.ts +9 -0
- package/src/mcp-client/screen-memory-local.ts +847 -13
- package/src/server/agent-chat-plugin.ts +16 -9
|
@@ -332,6 +332,19 @@ export { loadRunCodeToolEntries };
|
|
|
332
332
|
export { shouldDisableRecurringJobsRuntime };
|
|
333
333
|
export { finalizeClaimedAgentChatProcessRunFailure };
|
|
334
334
|
|
|
335
|
+
export function resolveInteractiveAgentRunOptions(
|
|
336
|
+
options?: Pick<
|
|
337
|
+
AgentChatPluginOptions,
|
|
338
|
+
"runSoftTimeoutMs" | "runNoProgressTimeoutMs" | "durableBackgroundRuns"
|
|
339
|
+
>,
|
|
340
|
+
) {
|
|
341
|
+
return {
|
|
342
|
+
runSoftTimeoutMs: options?.runSoftTimeoutMs,
|
|
343
|
+
runNoProgressTimeoutMs: options?.runNoProgressTimeoutMs,
|
|
344
|
+
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
335
348
|
export function createSerializedA2ATaskStatusWriter(
|
|
336
349
|
taskId: string,
|
|
337
350
|
writeStatus: (
|
|
@@ -2909,9 +2922,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2909
2922
|
model: options?.model,
|
|
2910
2923
|
appId: options?.appId,
|
|
2911
2924
|
apiKey: options?.apiKey,
|
|
2912
|
-
|
|
2913
|
-
runNoProgressTimeoutMs: options?.runNoProgressTimeoutMs,
|
|
2914
|
-
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
2925
|
+
...resolveInteractiveAgentRunOptions(options),
|
|
2915
2926
|
finalResponseGuard: options?.finalResponseGuard,
|
|
2916
2927
|
prepareRequest: async (details) => {
|
|
2917
2928
|
if (details.threadId && details.ownerEmail) {
|
|
@@ -3017,9 +3028,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3017
3028
|
model: options?.model,
|
|
3018
3029
|
appId: options?.appId,
|
|
3019
3030
|
apiKey: options?.apiKey,
|
|
3020
|
-
|
|
3021
|
-
runNoProgressTimeoutMs: options?.runNoProgressTimeoutMs,
|
|
3022
|
-
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
3031
|
+
...resolveInteractiveAgentRunOptions(options),
|
|
3023
3032
|
finalResponseGuard: options?.finalResponseGuard,
|
|
3024
3033
|
prepareRequest: options?.prepareRequest,
|
|
3025
3034
|
skipFilesContext: true,
|
|
@@ -3176,9 +3185,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3176
3185
|
model: options?.model,
|
|
3177
3186
|
appId: options?.appId,
|
|
3178
3187
|
apiKey: options?.apiKey,
|
|
3179
|
-
|
|
3180
|
-
runNoProgressTimeoutMs: options?.runNoProgressTimeoutMs,
|
|
3181
|
-
durableBackgroundRuns: options?.durableBackgroundRuns,
|
|
3188
|
+
...resolveInteractiveAgentRunOptions(options),
|
|
3182
3189
|
finalResponseGuard: options?.finalResponseGuard,
|
|
3183
3190
|
prepareRequest: async (details) => {
|
|
3184
3191
|
if (details.threadId && details.ownerEmail) {
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
type CSSProperties,
|
|
27
27
|
type ReactNode,
|
|
28
28
|
} from "react";
|
|
29
|
+
import { createPortal } from "react-dom";
|
|
29
30
|
import { Link } from "react-router";
|
|
30
31
|
import {
|
|
31
32
|
Area,
|
|
@@ -60,7 +61,7 @@ import {
|
|
|
60
61
|
SelectValue,
|
|
61
62
|
} from "@/components/ui/select";
|
|
62
63
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
63
|
-
import {
|
|
64
|
+
import { useChartTooltipPortalPosition } from "@/hooks/use-chart-tooltip-portal";
|
|
64
65
|
|
|
65
66
|
const PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
|
|
66
67
|
import { createDemoChartTrendRows } from "@/lib/demo-chart-trend";
|
|
@@ -86,7 +87,7 @@ const DEFAULT_COLORS = [
|
|
|
86
87
|
];
|
|
87
88
|
|
|
88
89
|
const CHART_TOOLTIP_WRAPPER_STYLE: CSSProperties = {
|
|
89
|
-
zIndex:
|
|
90
|
+
zIndex: 9999,
|
|
90
91
|
pointerEvents: "none",
|
|
91
92
|
};
|
|
92
93
|
|
|
@@ -897,6 +898,7 @@ export function ChartTooltip({
|
|
|
897
898
|
active,
|
|
898
899
|
payload,
|
|
899
900
|
label,
|
|
901
|
+
coordinate,
|
|
900
902
|
labelFormatter,
|
|
901
903
|
seriesNameFormatter,
|
|
902
904
|
valueFormatter,
|
|
@@ -909,11 +911,11 @@ export function ChartTooltip({
|
|
|
909
911
|
value?: unknown;
|
|
910
912
|
}>;
|
|
911
913
|
label?: unknown;
|
|
914
|
+
coordinate?: { x?: number; y?: number };
|
|
912
915
|
labelFormatter?: (value: string) => string;
|
|
913
916
|
seriesNameFormatter?: (value: string) => string;
|
|
914
917
|
valueFormatter?: (value: number) => string;
|
|
915
918
|
}) {
|
|
916
|
-
const tooltipRef = useChartTooltipFlip<HTMLDivElement>(active);
|
|
917
919
|
const items = useMemo(
|
|
918
920
|
() =>
|
|
919
921
|
sortTooltipPayloadItems(
|
|
@@ -922,6 +924,11 @@ export function ChartTooltip({
|
|
|
922
924
|
),
|
|
923
925
|
[payload],
|
|
924
926
|
);
|
|
927
|
+
const isVisible = Boolean(active) && items.length > 0;
|
|
928
|
+
const { anchorRef, boxRef } = useChartTooltipPortalPosition(
|
|
929
|
+
isVisible,
|
|
930
|
+
coordinate,
|
|
931
|
+
);
|
|
925
932
|
|
|
926
933
|
const labelText =
|
|
927
934
|
label == null
|
|
@@ -930,13 +937,13 @@ export function ChartTooltip({
|
|
|
930
937
|
? labelFormatter(String(label))
|
|
931
938
|
: String(label);
|
|
932
939
|
|
|
933
|
-
if (!
|
|
940
|
+
if (!isVisible) return null;
|
|
934
941
|
|
|
935
942
|
const tooltip = (
|
|
936
943
|
<div
|
|
937
|
-
ref={
|
|
944
|
+
ref={boxRef}
|
|
938
945
|
role="tooltip"
|
|
939
|
-
className="min-w-40 max-w-[280px] rounded-md border border-border bg-card px-3 py-2 text-xs text-foreground shadow-lg"
|
|
946
|
+
className="fixed z-[9999] min-w-40 max-w-[280px] rounded-md border border-border bg-card px-3 py-2 text-xs text-foreground shadow-lg pointer-events-none"
|
|
940
947
|
>
|
|
941
948
|
{labelText && (
|
|
942
949
|
<div className="mb-1.5 truncate font-medium text-foreground">
|
|
@@ -971,7 +978,12 @@ export function ChartTooltip({
|
|
|
971
978
|
</div>
|
|
972
979
|
);
|
|
973
980
|
|
|
974
|
-
return
|
|
981
|
+
return (
|
|
982
|
+
<>
|
|
983
|
+
<span ref={anchorRef} aria-hidden="true" />
|
|
984
|
+
{createPortal(tooltip, document.body)}
|
|
985
|
+
</>
|
|
986
|
+
);
|
|
975
987
|
}
|
|
976
988
|
|
|
977
989
|
function detectKeys(
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
const CHART_EDGE_PADDING = 8;
|
|
4
|
+
const CURSOR_OFFSET = 14;
|
|
5
|
+
|
|
6
|
+
type TooltipCoordinate = { x?: number; y?: number } | undefined;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ancestors of a dashboard chart (the scrollable app shell, the dashboard
|
|
10
|
+
* grid's inline-size container) clip any content that overflows their box,
|
|
11
|
+
* so the tooltip content is rendered through a portal to `document.body`.
|
|
12
|
+
* Recharts positions its own tooltip wrapper by measuring that wrapper's
|
|
13
|
+
* child content size — with the real content portaled away the wrapper has
|
|
14
|
+
* no size to measure and never gets a transform, so we can't read a live
|
|
15
|
+
* position off it. Instead, position the portaled box ourselves from the
|
|
16
|
+
* `coordinate` Recharts already passes to custom tooltip content (the exact
|
|
17
|
+
* pixel the cursor is over, relative to the chart) plus the chart's own
|
|
18
|
+
* `.recharts-wrapper` rect, and clamp against that same rect so the tooltip
|
|
19
|
+
* tracks the cursor but never crosses the chart's own edges.
|
|
20
|
+
*/
|
|
21
|
+
export function useChartTooltipPortalPosition(
|
|
22
|
+
isVisible: boolean,
|
|
23
|
+
coordinate: TooltipCoordinate,
|
|
24
|
+
) {
|
|
25
|
+
const anchorRef = useRef<HTMLSpanElement | null>(null);
|
|
26
|
+
const boxRef = useRef<HTMLDivElement | null>(null);
|
|
27
|
+
|
|
28
|
+
useLayoutEffect(() => {
|
|
29
|
+
if (!isVisible) return;
|
|
30
|
+
const anchor = anchorRef.current;
|
|
31
|
+
const box = boxRef.current;
|
|
32
|
+
if (!anchor || !box) return;
|
|
33
|
+
const chartEl = anchor.closest(".recharts-wrapper");
|
|
34
|
+
if (!chartEl) return;
|
|
35
|
+
|
|
36
|
+
const chartRect = chartEl.getBoundingClientRect();
|
|
37
|
+
const boxRect = box.getBoundingClientRect();
|
|
38
|
+
|
|
39
|
+
const pointX = chartRect.left + (coordinate?.x ?? 0);
|
|
40
|
+
const pointY = chartRect.top + (coordinate?.y ?? 0);
|
|
41
|
+
|
|
42
|
+
const minLeft = chartRect.left + CHART_EDGE_PADDING;
|
|
43
|
+
const maxLeft = chartRect.right - CHART_EDGE_PADDING - boxRect.width;
|
|
44
|
+
let left = pointX + CURSOR_OFFSET;
|
|
45
|
+
if (left > maxLeft) left = pointX - CURSOR_OFFSET - boxRect.width;
|
|
46
|
+
left = Math.min(Math.max(left, minLeft), Math.max(minLeft, maxLeft));
|
|
47
|
+
|
|
48
|
+
const minTop = chartRect.top + CHART_EDGE_PADDING;
|
|
49
|
+
const maxTop = chartRect.bottom - CHART_EDGE_PADDING - boxRect.height;
|
|
50
|
+
const top = Math.min(
|
|
51
|
+
Math.max(pointY - boxRect.height / 2, minTop),
|
|
52
|
+
Math.max(minTop, maxTop),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
box.style.left = `${left}px`;
|
|
56
|
+
box.style.top = `${top}px`;
|
|
57
|
+
}, [isVisible, coordinate?.x, coordinate?.y]);
|
|
58
|
+
|
|
59
|
+
return { anchorRef, boxRef };
|
|
60
|
+
}
|
|
@@ -105,7 +105,7 @@ export default function ChartRoute() {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
return (
|
|
108
|
-
<div className="flex h-screen w-screen flex-col overflow-
|
|
108
|
+
<div className="flex h-screen w-screen flex-col overflow-visible bg-transparent p-2">
|
|
109
109
|
{result.title && (
|
|
110
110
|
<div className="mb-1 px-1 text-xs font-medium text-muted-foreground">
|
|
111
111
|
{result.title}
|
|
@@ -34,6 +34,11 @@ import {
|
|
|
34
34
|
} from "../lib/real-data-actions";
|
|
35
35
|
|
|
36
36
|
const ANALYTICS_BACKGROUND_RUN_SOFT_TIMEOUT_MS = 13 * 60_000;
|
|
37
|
+
// A background job may legitimately spend minutes inside a provider/tool call,
|
|
38
|
+
// which the shared watchdog already excludes. Outside a tool call, however,
|
|
39
|
+
// silence means the model transport or worker has wedged; recover the chunk
|
|
40
|
+
// promptly instead of holding the dashboard composer for the 12-minute default.
|
|
41
|
+
export const ANALYTICS_BACKGROUND_RUN_NO_PROGRESS_TIMEOUT_MS = 3 * 60_000;
|
|
37
42
|
|
|
38
43
|
const ANALYTICS_DATA_SOURCES_LINK = buildDeepLink({
|
|
39
44
|
app: "analytics",
|
|
@@ -684,6 +689,7 @@ export default createAgentChatPlugin({
|
|
|
684
689
|
// standard serverless request budget without orphaning the task.
|
|
685
690
|
durableBackgroundRuns: true,
|
|
686
691
|
runSoftTimeoutMs: ANALYTICS_BACKGROUND_RUN_SOFT_TIMEOUT_MS,
|
|
692
|
+
runNoProgressTimeoutMs: ANALYTICS_BACKGROUND_RUN_NO_PROGRESS_TIMEOUT_MS,
|
|
687
693
|
connectorCatalog: [...ANALYTICS_CONNECTOR_CATALOG],
|
|
688
694
|
externalAgents: {
|
|
689
695
|
// Keep the direct MCP surface deliberately curated. External agents
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import {
|
|
3
|
+
readAppState,
|
|
4
|
+
writeAppState,
|
|
5
|
+
} from "@agent-native/core/application-state";
|
|
6
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
import { isPrivateClip } from "../app/lib/rewind-visibility.js";
|
|
10
|
+
import { parseEdits, serializeEdits } from "../app/lib/timestamp-mapping.js";
|
|
11
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
12
|
+
import {
|
|
13
|
+
getCurrentOwnerEmail,
|
|
14
|
+
ownerEmailMatches,
|
|
15
|
+
} from "../server/lib/recordings.js";
|
|
16
|
+
import { parseTranscriptSegments } from "../shared/transcript-segments.js";
|
|
17
|
+
import { assertNoDirectRecordingShares } from "./make-recording-private-for-rewind.js";
|
|
18
|
+
import {
|
|
19
|
+
rewindExtensionKey,
|
|
20
|
+
type RewindExtensionRequest,
|
|
21
|
+
} from "./request-rewind-extension.js";
|
|
22
|
+
|
|
23
|
+
function shiftedJsonArray(
|
|
24
|
+
raw: string | null | undefined,
|
|
25
|
+
addedMs: number,
|
|
26
|
+
fields: string[],
|
|
27
|
+
): string {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(raw || "[]");
|
|
30
|
+
if (!Array.isArray(parsed)) return raw || "[]";
|
|
31
|
+
return JSON.stringify(
|
|
32
|
+
parsed.map((item) => {
|
|
33
|
+
if (!item || typeof item !== "object") return item;
|
|
34
|
+
const next = { ...item } as Record<string, unknown>;
|
|
35
|
+
for (const field of fields) {
|
|
36
|
+
if (typeof next[field] === "number") {
|
|
37
|
+
next[field] = Math.max(0, Math.round(next[field] + addedMs));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return next;
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
} catch {
|
|
44
|
+
return raw || "[]";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default defineAction({
|
|
49
|
+
description:
|
|
50
|
+
"Replace an owned Clip with an explicitly prepended local Rewind range while shifting its timestamped editor data and preserving the original-start marker.",
|
|
51
|
+
schema: z.object({
|
|
52
|
+
recordingId: z.string(),
|
|
53
|
+
requestId: z.string(),
|
|
54
|
+
preRollRecordingId: z.string(),
|
|
55
|
+
videoUrl: z.string().min(1),
|
|
56
|
+
durationMs: z.number().int().positive(),
|
|
57
|
+
addedMs: z
|
|
58
|
+
.number()
|
|
59
|
+
.int()
|
|
60
|
+
.positive()
|
|
61
|
+
.max(5 * 60_000),
|
|
62
|
+
}),
|
|
63
|
+
run: async (args) => {
|
|
64
|
+
if (args.videoUrl.startsWith("data:")) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"The combined Clip must be uploaded before it is applied.",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const db = getDb();
|
|
70
|
+
const ownerEmail = getCurrentOwnerEmail();
|
|
71
|
+
const [recording] = await db
|
|
72
|
+
.select()
|
|
73
|
+
.from(schema.recordings)
|
|
74
|
+
.where(
|
|
75
|
+
and(
|
|
76
|
+
eq(schema.recordings.id, args.recordingId),
|
|
77
|
+
ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
const [preRoll] = await db
|
|
81
|
+
.select()
|
|
82
|
+
.from(schema.recordings)
|
|
83
|
+
.where(
|
|
84
|
+
and(
|
|
85
|
+
eq(schema.recordings.id, args.preRollRecordingId),
|
|
86
|
+
ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
|
|
87
|
+
),
|
|
88
|
+
);
|
|
89
|
+
if (!recording || !preRoll) {
|
|
90
|
+
throw new Error("The Clip or its local Rewind pre-roll is unavailable.");
|
|
91
|
+
}
|
|
92
|
+
if (
|
|
93
|
+
!isPrivateClip(recording.visibility) ||
|
|
94
|
+
!isPrivateClip(preRoll.visibility)
|
|
95
|
+
) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"Rewind history can only be added to a private Clip from a private pre-roll.",
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
await assertNoDirectRecordingShares(args.recordingId);
|
|
101
|
+
const key = rewindExtensionKey(args.recordingId);
|
|
102
|
+
const request = (await readAppState(key)) as RewindExtensionRequest | null;
|
|
103
|
+
if (
|
|
104
|
+
!request ||
|
|
105
|
+
request.requestId !== args.requestId ||
|
|
106
|
+
request.status !== "ready" ||
|
|
107
|
+
request.preRollRecordingId !== args.preRollRecordingId
|
|
108
|
+
) {
|
|
109
|
+
throw new Error("The Rewind pre-roll request is not ready to apply.");
|
|
110
|
+
}
|
|
111
|
+
const expectedDuration = recording.durationMs + args.addedMs;
|
|
112
|
+
if (Math.abs(args.durationMs - expectedDuration) > 2_000) {
|
|
113
|
+
throw new Error("The combined Clip duration does not match its sources.");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const edits = parseEdits(recording.editsJson);
|
|
117
|
+
edits.trims = edits.trims.map((trim) => ({
|
|
118
|
+
...trim,
|
|
119
|
+
startMs: trim.startMs + args.addedMs,
|
|
120
|
+
endMs: trim.endMs + args.addedMs,
|
|
121
|
+
}));
|
|
122
|
+
edits.blurs = edits.blurs.map((blur) => ({
|
|
123
|
+
...blur,
|
|
124
|
+
startMs: blur.startMs + args.addedMs,
|
|
125
|
+
endMs: blur.endMs + args.addedMs,
|
|
126
|
+
}));
|
|
127
|
+
edits.rewindOriginalStartMs = args.addedMs;
|
|
128
|
+
|
|
129
|
+
const [transcript] = await db
|
|
130
|
+
.select()
|
|
131
|
+
.from(schema.recordingTranscripts)
|
|
132
|
+
.where(eq(schema.recordingTranscripts.recordingId, args.recordingId));
|
|
133
|
+
const shiftedTranscript = transcript
|
|
134
|
+
? JSON.stringify(
|
|
135
|
+
parseTranscriptSegments(transcript.segmentsJson).map((segment) => ({
|
|
136
|
+
...segment,
|
|
137
|
+
startMs: segment.startMs + args.addedMs,
|
|
138
|
+
endMs: segment.endMs + args.addedMs,
|
|
139
|
+
})),
|
|
140
|
+
)
|
|
141
|
+
: null;
|
|
142
|
+
const now = new Date().toISOString();
|
|
143
|
+
|
|
144
|
+
await db.transaction(async (tx) => {
|
|
145
|
+
await tx
|
|
146
|
+
.update(schema.recordings)
|
|
147
|
+
.set({
|
|
148
|
+
videoUrl: args.videoUrl,
|
|
149
|
+
videoFormat: "mp4",
|
|
150
|
+
durationMs: args.durationMs,
|
|
151
|
+
editsJson: serializeEdits(edits),
|
|
152
|
+
chaptersJson: shiftedJsonArray(recording.chaptersJson, args.addedMs, [
|
|
153
|
+
"startMs",
|
|
154
|
+
]),
|
|
155
|
+
thumbnailUrl: null,
|
|
156
|
+
animatedThumbnailUrl: null,
|
|
157
|
+
updatedAt: now,
|
|
158
|
+
})
|
|
159
|
+
.where(eq(schema.recordings.id, args.recordingId));
|
|
160
|
+
if (transcript && shiftedTranscript) {
|
|
161
|
+
await tx
|
|
162
|
+
.update(schema.recordingTranscripts)
|
|
163
|
+
.set({ segmentsJson: shiftedTranscript, updatedAt: now })
|
|
164
|
+
.where(eq(schema.recordingTranscripts.recordingId, args.recordingId));
|
|
165
|
+
}
|
|
166
|
+
await tx
|
|
167
|
+
.update(schema.recordingComments)
|
|
168
|
+
.set({
|
|
169
|
+
videoTimestampMs: sql`${schema.recordingComments.videoTimestampMs} + ${args.addedMs}`,
|
|
170
|
+
updatedAt: now,
|
|
171
|
+
})
|
|
172
|
+
.where(eq(schema.recordingComments.recordingId, args.recordingId));
|
|
173
|
+
await tx
|
|
174
|
+
.update(schema.recordingReactions)
|
|
175
|
+
.set({
|
|
176
|
+
videoTimestampMs: sql`${schema.recordingReactions.videoTimestampMs} + ${args.addedMs}`,
|
|
177
|
+
})
|
|
178
|
+
.where(eq(schema.recordingReactions.recordingId, args.recordingId));
|
|
179
|
+
await tx
|
|
180
|
+
.update(schema.recordings)
|
|
181
|
+
.set({ trashedAt: now, expiresAt: now, updatedAt: now })
|
|
182
|
+
.where(eq(schema.recordings.id, args.preRollRecordingId));
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const applied: RewindExtensionRequest = {
|
|
186
|
+
...request,
|
|
187
|
+
status: "applied",
|
|
188
|
+
actualDurationMs: args.addedMs,
|
|
189
|
+
updatedAt: now,
|
|
190
|
+
};
|
|
191
|
+
await writeAppState(key, applied);
|
|
192
|
+
await writeAppState("refresh-signal", { ts: Date.now() });
|
|
193
|
+
return { recordingId: args.recordingId, request: applied };
|
|
194
|
+
},
|
|
195
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { eq } from "drizzle-orm";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
import deleteRecordingPermanent from "./delete-recording-permanent.js";
|
|
8
|
+
|
|
9
|
+
export default defineAction({
|
|
10
|
+
description:
|
|
11
|
+
"Delete an expired agent-created Clip only if it is still private and has not been renamed, shared, commented on, reacted to, tagged, archived, or trashed.",
|
|
12
|
+
schema: z.object({ id: z.string() }),
|
|
13
|
+
run: async ({ id }) => {
|
|
14
|
+
await assertAccess("recording", id, "editor");
|
|
15
|
+
const db = getDb();
|
|
16
|
+
const [recording] = await db
|
|
17
|
+
.select()
|
|
18
|
+
.from(schema.recordings)
|
|
19
|
+
.where(eq(schema.recordings.id, id));
|
|
20
|
+
if (!recording) return { id, deleted: true, reason: "already-missing" };
|
|
21
|
+
|
|
22
|
+
const [share, comment, reaction, tag] = await Promise.all([
|
|
23
|
+
db
|
|
24
|
+
.select({ id: schema.recordingShares.id })
|
|
25
|
+
.from(schema.recordingShares)
|
|
26
|
+
.where(eq(schema.recordingShares.resourceId, id))
|
|
27
|
+
.limit(1),
|
|
28
|
+
db
|
|
29
|
+
.select({ id: schema.recordingComments.id })
|
|
30
|
+
.from(schema.recordingComments)
|
|
31
|
+
.where(eq(schema.recordingComments.recordingId, id))
|
|
32
|
+
.limit(1),
|
|
33
|
+
db
|
|
34
|
+
.select({ id: schema.recordingReactions.id })
|
|
35
|
+
.from(schema.recordingReactions)
|
|
36
|
+
.where(eq(schema.recordingReactions.recordingId, id))
|
|
37
|
+
.limit(1),
|
|
38
|
+
db
|
|
39
|
+
.select({ id: schema.recordingTags.id })
|
|
40
|
+
.from(schema.recordingTags)
|
|
41
|
+
.where(eq(schema.recordingTags.recordingId, id))
|
|
42
|
+
.limit(1),
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const promoted =
|
|
46
|
+
recording.visibility !== "private" ||
|
|
47
|
+
recording.titleSource === "manual" ||
|
|
48
|
+
Boolean(recording.archivedAt || recording.trashedAt) ||
|
|
49
|
+
share.length > 0 ||
|
|
50
|
+
comment.length > 0 ||
|
|
51
|
+
reaction.length > 0 ||
|
|
52
|
+
tag.length > 0;
|
|
53
|
+
if (promoted) {
|
|
54
|
+
await db
|
|
55
|
+
.update(schema.recordings)
|
|
56
|
+
.set({ expiresAt: null, updatedAt: new Date().toISOString() })
|
|
57
|
+
.where(eq(schema.recordings.id, id));
|
|
58
|
+
return { id, deleted: false, reason: "promoted" };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await deleteRecordingPermanent.run({ id });
|
|
62
|
+
return { id, deleted: true, reason: "retention-expired" };
|
|
63
|
+
},
|
|
64
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { readAppState } from "@agent-native/core/application-state";
|
|
3
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
rewindExtensionKey,
|
|
8
|
+
type RewindExtensionRequest,
|
|
9
|
+
} from "./request-rewind-extension.js";
|
|
10
|
+
|
|
11
|
+
export default defineAction({
|
|
12
|
+
description: "Read the current explicit Rewind pre-roll request for a Clip.",
|
|
13
|
+
schema: z.object({ recordingId: z.string() }),
|
|
14
|
+
http: { method: "GET" },
|
|
15
|
+
run: async ({ recordingId }) => {
|
|
16
|
+
await assertAccess("recording", recordingId, "owner");
|
|
17
|
+
const request = (await readAppState(
|
|
18
|
+
rewindExtensionKey(recordingId),
|
|
19
|
+
)) as RewindExtensionRequest | null;
|
|
20
|
+
return { request };
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -4,9 +4,25 @@ import { z } from "zod";
|
|
|
4
4
|
|
|
5
5
|
export default defineAction({
|
|
6
6
|
description:
|
|
7
|
-
"Check local Clips Screen Memory status for this machine: enabled/paused state, local
|
|
7
|
+
"Check local Clips Screen Memory status for this machine: enabled/paused state, local metadata files, and capture recency. Screen Memory is disabled by default, local-only, and does not expose media bytes or images.",
|
|
8
8
|
schema: z.object({}),
|
|
9
9
|
http: { method: "GET" },
|
|
10
10
|
readOnly: true,
|
|
11
|
-
run: async () =>
|
|
11
|
+
run: async () => {
|
|
12
|
+
const status = await readScreenMemoryStatus();
|
|
13
|
+
return {
|
|
14
|
+
feature: status.feature,
|
|
15
|
+
localOnly: status.localOnly,
|
|
16
|
+
enabled: status.enabled,
|
|
17
|
+
paused: status.paused,
|
|
18
|
+
state: status.state,
|
|
19
|
+
captureMode: status.config.captureMode,
|
|
20
|
+
retentionHours: status.config.retentionHours,
|
|
21
|
+
captureCount: status.captureCount,
|
|
22
|
+
storageBytes: status.storageBytes,
|
|
23
|
+
oldestCaptureAt: status.oldestCaptureAt,
|
|
24
|
+
newestCaptureAt: status.newestCaptureAt,
|
|
25
|
+
note: status.note,
|
|
26
|
+
};
|
|
27
|
+
},
|
|
12
28
|
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { listAppState } from "@agent-native/core/application-state";
|
|
3
|
+
import { and, eq, inArray } from "drizzle-orm";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
import {
|
|
8
|
+
getCurrentOwnerEmail,
|
|
9
|
+
ownerEmailMatches,
|
|
10
|
+
} from "../server/lib/recordings.js";
|
|
11
|
+
import {
|
|
12
|
+
REWIND_EXTENSION_PREFIX,
|
|
13
|
+
type RewindExtensionRequest,
|
|
14
|
+
} from "./request-rewind-extension.js";
|
|
15
|
+
|
|
16
|
+
export default defineAction({
|
|
17
|
+
description:
|
|
18
|
+
"List pending local Rewind pre-roll requests for the signed-in Clips Alpha app.",
|
|
19
|
+
schema: z.object({}),
|
|
20
|
+
http: { method: "GET" },
|
|
21
|
+
run: async () => {
|
|
22
|
+
const entries = await listAppState(REWIND_EXTENSION_PREFIX);
|
|
23
|
+
const staleProcessingCutoff = Date.now() - 2 * 60_000;
|
|
24
|
+
const requests = entries
|
|
25
|
+
.map((entry) => entry.value as unknown as RewindExtensionRequest)
|
|
26
|
+
.filter(
|
|
27
|
+
(request) =>
|
|
28
|
+
request &&
|
|
29
|
+
typeof request.recordingId === "string" &&
|
|
30
|
+
(request.status === "pending" ||
|
|
31
|
+
(request.status === "processing" &&
|
|
32
|
+
Date.parse(request.updatedAt) < staleProcessingCutoff)),
|
|
33
|
+
);
|
|
34
|
+
if (!requests.length) return { requests: [] };
|
|
35
|
+
const ids = [...new Set(requests.map((request) => request.recordingId))];
|
|
36
|
+
const ownerEmail = getCurrentOwnerEmail();
|
|
37
|
+
const accessible = await getDb()
|
|
38
|
+
.select({ id: schema.recordings.id })
|
|
39
|
+
.from(schema.recordings)
|
|
40
|
+
.where(
|
|
41
|
+
and(
|
|
42
|
+
ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
|
|
43
|
+
inArray(schema.recordings.id, ids),
|
|
44
|
+
eq(schema.recordings.status, "ready"),
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
const allowed = new Set(accessible.map((row) => row.id));
|
|
48
|
+
return {
|
|
49
|
+
requests: requests.filter((request) => allowed.has(request.recordingId)),
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
3
|
+
import { and, eq, notExists } from "drizzle-orm";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
+
|
|
8
|
+
export const DIRECT_SHARE_REWIND_ERROR =
|
|
9
|
+
"This Clip is still shared directly with other people. Remove their access in Share before adding local Rewind history.";
|
|
10
|
+
|
|
11
|
+
export async function assertNoDirectRecordingShares(
|
|
12
|
+
recordingId: string,
|
|
13
|
+
): Promise<void> {
|
|
14
|
+
const [share] = await getDb()
|
|
15
|
+
.select({ id: schema.recordingShares.id })
|
|
16
|
+
.from(schema.recordingShares)
|
|
17
|
+
.where(eq(schema.recordingShares.resourceId, recordingId))
|
|
18
|
+
.limit(1);
|
|
19
|
+
if (share) throw new Error(DIRECT_SHARE_REWIND_ERROR);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default defineAction({
|
|
23
|
+
description:
|
|
24
|
+
"Make an owned recording private for a Rewind extension, refusing to continue while anyone still has direct access.",
|
|
25
|
+
schema: z.object({ recordingId: z.string() }),
|
|
26
|
+
run: async ({ recordingId }) => {
|
|
27
|
+
await assertAccess("recording", recordingId, "owner");
|
|
28
|
+
|
|
29
|
+
const now = new Date().toISOString();
|
|
30
|
+
const db = getDb();
|
|
31
|
+
const [recording] = await db
|
|
32
|
+
.update(schema.recordings)
|
|
33
|
+
.set({ visibility: "private", updatedAt: now })
|
|
34
|
+
.where(
|
|
35
|
+
and(
|
|
36
|
+
eq(schema.recordings.id, recordingId),
|
|
37
|
+
notExists(
|
|
38
|
+
db
|
|
39
|
+
.select({ id: schema.recordingShares.id })
|
|
40
|
+
.from(schema.recordingShares)
|
|
41
|
+
.where(eq(schema.recordingShares.resourceId, recordingId)),
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
|
+
)
|
|
45
|
+
.returning({ id: schema.recordings.id });
|
|
46
|
+
if (!recording) {
|
|
47
|
+
// The conditional UPDATE is the invariant. This follow-up read only
|
|
48
|
+
// chooses the useful error message after the atomic mutation declined.
|
|
49
|
+
await assertNoDirectRecordingShares(recordingId);
|
|
50
|
+
throw new Error("This Clip is unavailable.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { recordingId, visibility: "private" as const };
|
|
54
|
+
},
|
|
55
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
|
-
import {
|
|
2
|
+
import { queryScreenMemoryForAgent } from "@agent-native/core/mcp-client";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
export default defineAction({
|
|
6
6
|
description:
|
|
7
|
-
"Search
|
|
7
|
+
"Search bounded local Clips Screen Memory evidence from this machine. Returns typed app-context, OCR, or transcript excerpts only when present in local files, plus coverage, gaps, segment references, jump targets, and truncation; never media bytes or images. Use get-screen-memory-status first if availability is unclear.",
|
|
8
8
|
schema: z.object({
|
|
9
9
|
query: z
|
|
10
10
|
.string()
|
|
@@ -21,9 +21,9 @@ export default defineAction({
|
|
|
21
21
|
.min(1)
|
|
22
22
|
.max(50)
|
|
23
23
|
.default(10)
|
|
24
|
-
.describe("Maximum number of
|
|
24
|
+
.describe("Maximum number of bounded local evidence items to return"),
|
|
25
25
|
}),
|
|
26
26
|
http: { method: "GET" },
|
|
27
27
|
readOnly: true,
|
|
28
|
-
run: async (args) =>
|
|
28
|
+
run: async (args) => queryScreenMemoryForAgent(args),
|
|
29
29
|
});
|