@agent-native/core 0.178.1-nightly-20260910175201 → 0.178.1

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.
Files changed (37) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/CHANGELOG.md +1 -0
  3. package/corpus/templates/calendar/CHANGELOG.md +7 -0
  4. package/corpus/templates/clips/CHANGELOG.md +22 -0
  5. package/corpus/templates/clips/actions/create-intake-agent-link.ts +114 -0
  6. package/corpus/templates/clips/actions/create-intake-recording.ts +208 -0
  7. package/corpus/templates/clips/actions/create-recording-intake-link.ts +85 -0
  8. package/corpus/templates/clips/app/components/bug-report/bug-report-form.tsx +7 -0
  9. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +22 -5
  10. package/corpus/templates/clips/app/hooks/use-video-storage-status.ts +2 -1
  11. package/corpus/templates/clips/app/routes/bug-report.done.tsx +12 -10
  12. package/corpus/templates/clips/app/routes/bug-report.tsx +6 -0
  13. package/corpus/templates/clips/app/routes/record.tsx +269 -100
  14. package/corpus/templates/clips/server/db/schema.ts +24 -0
  15. package/corpus/templates/clips/server/lib/clip-intake.ts +247 -0
  16. package/corpus/templates/clips/server/plugins/auth.ts +8 -0
  17. package/corpus/templates/clips/server/plugins/db.ts +16 -0
  18. package/corpus/templates/clips/server/routes/api/clip-intake.get.ts +61 -0
  19. package/corpus/templates/clips/server/routes/api/clip-intake.post.ts +90 -0
  20. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +19 -4
  21. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +25 -10
  22. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +21 -4
  23. package/corpus/templates/clips/shared/clip-intake.ts +41 -0
  24. package/corpus/templates/clips/shared/finalize-recovery.ts +27 -5
  25. package/corpus/templates/clips/shared/recording-core.ts +4 -4
  26. package/corpus/templates/content/CHANGELOG.md +1 -0
  27. package/corpus/templates/design/CHANGELOG.md +9 -4
  28. package/corpus/templates/factory/CHANGELOG.md +11 -0
  29. package/dist/collab/struct-routes.d.ts +1 -1
  30. package/dist/observability/routes.d.ts +3 -3
  31. package/dist/progress/routes.d.ts +1 -1
  32. package/dist/resources/handlers.d.ts +1 -1
  33. package/dist/secrets/routes.d.ts +3 -3
  34. package/docs/content/template-clips-anonymous-intake.mdx +148 -0
  35. package/docs/content/template-clips-developers.mdx +4 -3
  36. package/docs/content/template-clips.mdx +1 -0
  37. package/package.json +3 -3
@@ -10,7 +10,7 @@ export type RecoveredReadyRecording = {
10
10
  id: string;
11
11
  recordingId: string;
12
12
  status: "ready";
13
- videoUrl: string;
13
+ videoUrl?: string;
14
14
  durationMs?: number;
15
15
  width?: number;
16
16
  height?: number;
@@ -97,6 +97,11 @@ export function publicRecordingStatusUrl(
97
97
  recordingId: string,
98
98
  ): string {
99
99
  const url = absoluteUploadUrl(uploadUrl);
100
+ if (url.pathname.endsWith("/api/clip-intake")) {
101
+ url.searchParams.set("recordingId", recordingId);
102
+ url.searchParams.set("operation", "status");
103
+ return maybeRelativeUrl(url, uploadUrl);
104
+ }
100
105
  const match = url.pathname.match(/^(.*)\/api\/uploads\/[^/]+\/chunk$/);
101
106
  const basePath = match?.[1] ?? "";
102
107
  url.pathname = `${basePath}/api/public-recording`;
@@ -132,7 +137,10 @@ function optionalBoolean(value: unknown): boolean | undefined {
132
137
  export function readyRecordingFromPublicPayload(
133
138
  payload: unknown,
134
139
  fallbackRecordingId: string,
135
- options: { acceptPendingVerification?: boolean } = {},
140
+ options: {
141
+ acceptPendingVerification?: boolean;
142
+ acceptReadyWithoutVideoUrl?: boolean;
143
+ } = {},
136
144
  ): ProbeResult {
137
145
  const root =
138
146
  payload && typeof payload === "object"
@@ -178,7 +186,10 @@ export function readyRecordingFromPublicPayload(
178
186
 
179
187
  const videoUrl =
180
188
  typeof recording.videoUrl === "string" ? recording.videoUrl : "";
181
- if (status !== "ready" || !videoUrl) {
189
+ if (
190
+ status !== "ready" ||
191
+ (!videoUrl && !options.acceptReadyWithoutVideoUrl)
192
+ ) {
182
193
  return { ready: false, terminal: false, status };
183
194
  }
184
195
 
@@ -195,7 +206,7 @@ export function readyRecordingFromPublicPayload(
195
206
  id,
196
207
  recordingId: id,
197
208
  status: "ready",
198
- videoUrl,
209
+ ...(videoUrl ? { videoUrl } : {}),
199
210
  durationMs: optionalNumber(recording.durationMs),
200
211
  width: optionalNumber(recording.width),
201
212
  height: optionalNumber(recording.height),
@@ -235,6 +246,7 @@ export async function waitForReadyRecordingAfterFinalizeError(args: {
235
246
  intervalMs?: number;
236
247
  fetchTimeoutMs?: number;
237
248
  acceptPendingVerification?: boolean;
249
+ acceptReadyWithoutVideoUrl?: boolean;
238
250
  signal?: AbortSignal;
239
251
  }): Promise<RecoveredFinalizeRecording | null> {
240
252
  const fetchImpl = args.fetchImpl ?? fetch;
@@ -250,10 +262,19 @@ export async function waitForReadyRecordingAfterFinalizeError(args: {
250
262
  const attempts = Math.max(1, Math.ceil(timeoutMs / intervalMs));
251
263
  let url: string;
252
264
  let authenticatedUrl: string | null = null;
265
+ let acceptReadyWithoutVideoUrl = false;
253
266
  try {
254
267
  url = publicRecordingStatusUrl(args.uploadUrl, args.recordingId);
268
+ const isClipIntake = new URL(
269
+ args.uploadUrl,
270
+ typeof globalThis.location?.origin === "string"
271
+ ? globalThis.location.origin
272
+ : "http://localhost",
273
+ ).pathname.endsWith("/api/clip-intake");
274
+ acceptReadyWithoutVideoUrl =
275
+ args.acceptReadyWithoutVideoUrl ?? isClipIntake;
255
276
  authenticatedUrl =
256
- args.authToken || args.preferAuthenticated
277
+ !isClipIntake && (args.authToken || args.preferAuthenticated)
257
278
  ? authenticatedRecordingStatusUrl(args.uploadUrl, args.recordingId)
258
279
  : null;
259
280
  } catch {
@@ -298,6 +319,7 @@ export async function waitForReadyRecordingAfterFinalizeError(args: {
298
319
  args.recordingId,
299
320
  {
300
321
  acceptPendingVerification: args.acceptPendingVerification,
322
+ acceptReadyWithoutVideoUrl,
301
323
  },
302
324
  );
303
325
  if (probe.ready) return probe.result;
@@ -127,12 +127,12 @@ export function chunkUploadQuery(params: ChunkUploadParams): string {
127
127
  return q.toString();
128
128
  }
129
129
 
130
- /** Full chunk-upload URL: `<chunkBaseUrl>?<encoded params>`. `chunkBaseUrl` is
131
- * the per-recording endpoint (e.g. `/api/uploads/<id>/chunk` or its absolute
132
- * form) with no existing query string. */
130
+ /** Full chunk-upload URL: append the encoded chunk params to the per-recording
131
+ * endpoint, preserving any capability query already present on the URL. */
133
132
  export function chunkUploadUrl(
134
133
  chunkBaseUrl: string,
135
134
  params: ChunkUploadParams,
136
135
  ): string {
137
- return `${chunkBaseUrl}?${chunkUploadQuery(params)}`;
136
+ const separator = chunkBaseUrl.includes("?") ? "&" : "?";
137
+ return `${chunkBaseUrl}${separator}${chunkUploadQuery(params)}`;
138
138
  }
@@ -11,6 +11,7 @@ time from the command menu (Cmd+K → "What's new").
11
11
 
12
12
  ### Fixed
13
13
 
14
+ - Sidebar Search opens the command picker, icon controls have accessible names, and the sidebar can be resized with the keyboard.
14
15
  - First title edits no longer hit a stale-version conflict, open databases recover after agent Trash and restore actions, and database settings preserve keyboard focus when closing or returning to Add property. Source-managed database fields stay read-only in tables, page property editors, and agent actions, while local fields remain editable. Property editors stay inside mobile Info so edits can be saved without closing the panel.
15
16
  - Remote collaborator cursors in the document editor now stay compact above the text instead of expanding into full-width color bars.
16
17
 
@@ -9,15 +9,20 @@ from the command menu (Cmd+K → "What's new") or from Settings.
9
9
 
10
10
  - Design editor version history: browse and restore saved checkpoints from the top-left menu or Cmd+K.
11
11
 
12
- ### Removed
13
-
14
- - Removed the always-visible design system picker above the design editor chat.
15
-
16
12
  ### Improved
17
13
 
14
+ - The Layers panel is denser with smaller text, icons, and row height.
18
15
  - Opening or closing the left sidebar (or toggling minimal mode) no longer shifts designs on the canvas.
19
16
  - Breakpoint add control keeps a clear gap from the screen edge and shows immediate feedback while adding.
20
17
 
18
+ ### Changed
19
+
20
+ - Design canvas chrome now overlays instead of resizing the board, so opening or closing the left panel and minimal mode no longer shifts screens on the canvas.
21
+
22
+ ### Removed
23
+
24
+ - Removed the always-visible design system picker above the design editor chat.
25
+
21
26
  ## 2026-09-09
22
27
 
23
28
  ### Improved
@@ -3,6 +3,17 @@
3
3
  All notable user-facing changes to Chat are documented here. Open it any
4
4
  time from the command menu (Cmd+K → "What's new").
5
5
 
6
+ ## 2026-09-09
7
+
8
+ ### Improved
9
+
10
+ - Slack feedback jobs skip threads whose parent already has 👀 or 🤖, instead of tagging Builder again.
11
+
12
+ ### Fixed
13
+
14
+ - Slack feedback keeps a claimed 👀/🤖 marker after polling, so those threads stay out of the review queue.
15
+ - Slack feedback no longer moves an already-started thread to needs-manual just because the parent already has 👀 or 🤖.
16
+
6
17
  ## 2026-09-08
7
18
 
8
19
  ### Fixed
@@ -13,8 +13,8 @@
13
13
  * Body: { json: any, fieldName?: string, type?: "map"|"array", requestSource?: string }
14
14
  */
15
15
  export declare const postCollabJson: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
16
- error: string;
17
16
  ok?: undefined;
17
+ error: string;
18
18
  } | {
19
19
  error?: undefined;
20
20
  ok: boolean;
@@ -41,22 +41,22 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
41
41
  thumbsUpRate: number;
42
42
  avgEvalScore: number;
43
43
  } | {
44
- ok?: undefined;
45
44
  summary: import("./types.js").TraceSummary;
46
45
  spans: import("./types.js").TraceSpan[];
46
+ ok?: undefined;
47
47
  error?: undefined;
48
48
  id?: undefined;
49
49
  } | {
50
- ok?: undefined;
51
50
  summary?: undefined;
52
51
  spans?: undefined;
53
52
  id: string;
53
+ ok?: undefined;
54
54
  error?: undefined;
55
55
  } | {
56
- ok?: undefined;
57
56
  summary?: undefined;
58
57
  spans?: undefined;
59
58
  error: any;
59
+ ok?: undefined;
60
60
  id?: undefined;
61
61
  } | {
62
62
  summary?: undefined;
@@ -15,6 +15,6 @@ export declare function createProgressHandler(): import("h3").EventHandlerWithFe
15
15
  error: string;
16
16
  ok?: undefined;
17
17
  } | {
18
- ok: boolean;
19
18
  error?: undefined;
19
+ ok: boolean;
20
20
  }>>;
@@ -48,8 +48,8 @@ export declare function handleUpdateResource(event: any): Promise<import("./stor
48
48
  }>;
49
49
  /** DELETE /_agent-native/resources/:id — delete a resource */
50
50
  export declare function handleDeleteResource(event: any): Promise<{
51
- ok?: undefined;
52
51
  error: string;
52
+ ok?: undefined;
53
53
  } | {
54
54
  error?: undefined;
55
55
  ok: boolean;
@@ -53,16 +53,16 @@ export declare function createListSecretsHandler(): import("h3").EventHandlerWit
53
53
  /** POST /_agent-native/secrets/:key — write a secret. */
54
54
  export declare function createWriteSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
55
55
  error: string;
56
- ok?: undefined;
57
56
  status?: undefined;
57
+ ok?: undefined;
58
58
  } | {
59
59
  error?: undefined;
60
60
  ok: boolean;
61
61
  status: string;
62
62
  } | {
63
- ok?: undefined;
64
63
  error: string;
65
64
  removed?: undefined;
65
+ ok?: undefined;
66
66
  } | {
67
67
  error?: undefined;
68
68
  ok: boolean;
@@ -73,9 +73,9 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
73
73
  * or the current stored value without changing anything.
74
74
  */
75
75
  export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
76
- ok?: undefined;
77
76
  error: string;
78
77
  note?: undefined;
78
+ ok?: undefined;
79
79
  } | {
80
80
  error?: undefined;
81
81
  ok: boolean;
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: "Clips anonymous intake"
3
+ description: "Collect one private Clips recording from an unsigned visitor with a short-lived signed intake URL."
4
+ search: "Clips anonymous intake bug report signed upload token no login"
5
+ ---
6
+
7
+ # Anonymous Clips intake
8
+
9
+ Anonymous intake lets a customer submit one private Clips recording without signing in to Clips. The product that creates the intake URL still needs an authenticated Clips session or an authenticated backend action caller.
10
+
11
+ The intake URL is a narrow upload capability. It is not a share link, a library session, or an agent access token.
12
+
13
+ ## Capability boundaries
14
+
15
+ | Capability | Allows | Does not allow | Lifetime |
16
+ | --- | --- | --- | --- |
17
+ | Intake URL | Create one private recording, upload its chunks, finalize it, or abort it | List recordings, read media, open the library, or use normal agent APIs | One hour by default. Four hours maximum |
18
+ | Agent context link | Read the completed recording through the normal scoped Clips agent surface after an authenticated host-side exchange | Be minted by the anonymous intake bearer, read any other recording, or act as the recording owner | Seven days for bug-report completions |
19
+ | Clips session | Mint intake URLs and use the normal authenticated Clips UI | Nothing is added to the anonymous visitor's browser | Controlled by normal Clips auth |
20
+
21
+ The intake token is signed with the existing scoped-token mechanism. The token is never stored in SQL. The database stores only the intake id, owner and organization binding, recording id, status, and expiry.
22
+
23
+ ## End-to-end flow
24
+
25
+ 1. Your authenticated product backend calls `create-recording-intake-link`.
26
+ 2. Clips returns a short-lived `/bug-report` URL.
27
+ 3. Your product opens that URL in an iframe or popup.
28
+ 4. The unsigned visitor fills in the report and records the screen.
29
+ 5. Clips creates one private recording and sends the media through its existing chunk and finalize pipeline.
30
+ 6. The completion page posts the recording id to the host window. It does not mint read access with the anonymous bearer.
31
+ 7. Your authenticated host backend exchanges the completed intake for a separate read-only agent context link.
32
+
33
+ The browser never receives the Clips workspace session. If the create response is lost after Clips attaches the recording, retrying the same signed create request returns that recording's upload URLs instead of creating a second row. Expired or terminal intake URLs remain unusable.
34
+
35
+ ## Mint an intake URL
36
+
37
+ `create-recording-intake-link` is a UI and HTTP action. It is not exposed as an agent tool because minting a bearer upload capability is an explicit integration operation.
38
+
39
+ Call it from an authenticated same-origin browser or from an authenticated backend caller:
40
+
41
+ ```ts
42
+ const response = await fetch(
43
+ "https://clips.example.com/_agent-native/actions/create-recording-intake-link",
44
+ {
45
+ method: "POST",
46
+ headers: { "Content-Type": "application/json" },
47
+ credentials: "include",
48
+ body: JSON.stringify({ ttlSeconds: 3600 }),
49
+ },
50
+ );
51
+
52
+ if (!response.ok) throw new Error("Could not create the Clips intake URL");
53
+
54
+ const { result } = await response.json();
55
+ // result.url is safe to give to the unsigned visitor.
56
+ ```
57
+
58
+ `ttlSeconds` is optional. It must be between 60 seconds and four hours. The default is one hour. The response also includes `intakeId`, `expiresAt`, and `ttlSeconds`.
59
+
60
+ The create request is safe to retry with the same `intakeId` and `intakeToken` if its response is lost. Clips returns the existing recording after attachment; it never creates a second recording for the same intake. Do not retry with a different intake token or reuse the upload URLs after an abort.
61
+
62
+ Do not mint this URL in an anonymous browser. Do not put a long-lived Clips session or a service credential into the customer-facing page.
63
+
64
+ ## Embed the intake page
65
+
66
+ Pass the returned URL directly to an iframe. The URL already contains the signed `clip_intake_id` and `clip_intake` query parameters.
67
+
68
+ ```tsx
69
+ <iframe
70
+ src={result.url}
71
+ allow="display-capture; camera; microphone"
72
+ title="Report a problem"
73
+ style={{ width: 420, height: 560, border: 0 }}
74
+ />
75
+ ```
76
+
77
+ The recorder opens a top-level popup when the visitor starts capture. Browser media permissions and screen capture require a user gesture in a top-level browsing context. If popups are blocked, the page falls back to navigating the current window.
78
+
79
+ ## Receive the completed recording
80
+
81
+ The done page posts `agent-native.clips.bug-report.submitted` to the opener and the embedding parent. For anonymous intake, the message intentionally contains `agentAccessStatus: "unavailable"` and no agent link. Retain the `intakeId` from the mint response on the trusted host, then exchange it server-side after receiving the `recordingId`. Validate both the Clips origin and the message source before using the payload.
82
+
83
+ ```ts
84
+ const clipsOrigin = "https://clips.example.com";
85
+ let recorderWindow: Window | null = null;
86
+
87
+ window.addEventListener("message", (event) => {
88
+ if (event.origin !== clipsOrigin) return;
89
+ if (recorderWindow && event.source !== recorderWindow) return;
90
+ if (event.data?.type !== "agent-native.clips.bug-report.submitted") return;
91
+
92
+ if (event.data.agentAccessStatus !== "unavailable") return;
93
+ // Send event.data.recordingId and the retained intakeId to your trusted
94
+ // backend. Do not send the anonymous clip_intake token from this page.
95
+ });
96
+ ```
97
+
98
+ The payload includes `recordingId`, `recordingUrl`, `embedUrl`, `agentShareUrl`, `agentContextUrl`, `agentAccessExpiresAt`, and `agentAccessStatus`. For anonymous intake, `agentAccessStatus: "unavailable"` is expected until the trusted host performs the exchange. Do not treat it as an empty recording result or let the visitor call the exchange action.
99
+
100
+ Use the authenticated `create-intake-agent-link` action from the trusted host backend. Keep the `intakeId` returned by `create-recording-intake-link` with the host's authenticated Clips session, and pass the completed `recordingId` from the message:
101
+
102
+ ```ts
103
+ const response = await fetch(
104
+ "https://clips.example.com/_agent-native/actions/create-intake-agent-link",
105
+ {
106
+ method: "POST",
107
+ headers: { "Content-Type": "application/json" },
108
+ credentials: "include",
109
+ body: JSON.stringify({ intakeId, recordingId }),
110
+ },
111
+ );
112
+
113
+ if (!response.ok) throw new Error("Could not create the Clips agent link");
114
+ const { result } = await response.json();
115
+ // Send result.contextUrl to the support agent or backend here.
116
+ ```
117
+
118
+ The exchange verifies the authenticated owner, organization, intake expiry, completed state, and recording binding before delegating to the normal scoped agent-link implementation. If the host already has an authenticated Clips session with access to the recording, it can also call `create-recording-agent-link` with the `recordingId`.
119
+
120
+ ## Self-hosting requirements
121
+
122
+ Anonymous intake uses the same storage and database prerequisites as an authenticated recording:
123
+
124
+ - A persistent `DATABASE_URL`.
125
+ - A configured Builder.io or S3-compatible video storage provider.
126
+ - The normal production auth and scoped-token configuration from [Deployment](/docs/deployment).
127
+ - A public `BETTER_AUTH_URL`, such as `https://clips.example.com`, when the intake URL is minted outside a browser request.
128
+
129
+ The intake action creates the recording with private visibility regardless of the organization's default recording visibility. The normal Clips access checks still protect the recording after intake completes.
130
+
131
+ ## Security checklist
132
+
133
+ - Use HTTPS for the Clips app and the host product.
134
+ - Treat the intake URL as a bearer credential. Keep it out of logs, analytics events, referrer data, screenshots, and support tickets.
135
+ - Use the shortest useful TTL. One hour is the default.
136
+ - Validate `event.origin` and `event.source` in the completion listener.
137
+ - Keep the intake id and the authenticated exchange on the trusted host. Store the resulting `agentContextUrl` only where the support agent or backend needs it. It is also a bearer credential.
138
+ - Never expose `/api/uploads/:recordingId/chunk` or `/api/uploads/:recordingId/abort` directly to anonymous users. Intake traffic goes through the signed `/api/clip-intake` transport, which checks the intake id, token, recording binding, owner binding, status, and expiry on every request.
139
+
140
+ ## Troubleshooting
141
+
142
+ **The recorder opens a sign-in page.** Make sure the intake URL includes both `clip_intake_id` and `clip_intake`. The `/record` route is public for the intake handoff, while normal recording creation remains session protected.
143
+
144
+ **The recording says the intake URL is unavailable.** The URL may have expired, been aborted, or be mid-creation. Retry the original create request once if its response was lost; otherwise mint a new intake URL. Each intake URL still creates at most one recording.
145
+
146
+ **The completion has no agent link.** That is expected for anonymous intake: the visitor's bearer is write-only. Have the authenticated host exchange the retained `intakeId` and completed `recordingId` with `create-intake-agent-link`. A 409 means the recording is still being verified; retry from the trusted host after it becomes ready.
147
+
148
+ **The page has no storage setup control.** Anonymous visitors cannot configure a Clips storage provider. Configure storage before minting intake URLs.
@@ -94,11 +94,11 @@ window.addEventListener("message", (event) => {
94
94
  });
95
95
  ```
96
96
 
97
- Always validate both `event.origin` and `event.source` in the host. The completion payload includes `recordingId`, `recordingUrl`, `embedUrl`, `agentShareUrl`, `agentContextUrl`, `agentAccessExpiresAt`, and an explicit `agentAccessStatus` of `ready` or `unavailable`. When access is ready, `agentContextUrl` is a temporary, scoped URL that lets an agent read recording metadata, timestamped transcript segments, recommended frames and frame URLs, and browser diagnostics without receiving the user's workspace session. Normal agent links expire after two hours; embedded bug-report completions use a seven-day scoped link so asynchronous support tickets can be triaged. Treat an unavailable or expired link as an access failure, not an empty recording. `embedUrl` remains subject to the recording's normal viewer access.
97
+ Always validate both `event.origin` and `event.source` in the host. The completion payload includes `recordingId`, `recordingUrl`, `embedUrl`, `agentShareUrl`, `agentContextUrl`, `agentAccessExpiresAt`, and an explicit `agentAccessStatus` of `ready` or `unavailable`. When access is ready, `agentContextUrl` is a temporary, scoped URL that lets an agent read recording metadata, timestamped transcript segments, recommended frames and frame URLs, and browser diagnostics without receiving the user's workspace session. Normal agent links expire after two hours; authenticated embedded bug-report completions use a seven-day scoped link so asynchronous support tickets can be triaged. Anonymous intake completions intentionally report `agentAccessStatus: "unavailable"` until the trusted host exchanges the retained intake id and completed recording id through the authenticated `create-intake-agent-link` action. Treat an unavailable or expired link as an access failure, not an empty recording. `embedUrl` remains subject to the recording's normal viewer access.
98
98
 
99
99
  Bug-report recordings default to workspace visibility instead of public visibility. The saved `recording_bug_reports` sidecar includes the redacted host metadata, while the recording itself remains the canonical media/transcript resource. URLs have credentials, fragments, and query values removed before storage, and the browser-diagnostics pipeline still omits request/response bodies, headers, and cookies. A popup recording only sees diagnostics emitted inside the Clips window. Use the Chrome extension or attach diagnostics from the host product separately when the agent needs console and network context from the source tab.
100
100
 
101
- This pilot requires the reporter to already have an active session in the Clips workspace that owns the recording. The current cross-origin popup cannot preserve its completion channel through a first-time sign-in redirect, so users should sign in to Clips in a separate tab before launching it. A fully anonymous customer-support intake should add a signed intake token that can create, upload, and finalize a recording without granting broad recording access; do not expose the existing owner-scoped upload endpoints directly to anonymous users.
101
+ This embedded flow requires the reporter to already have an active session in the Clips workspace that owns the recording. The current cross-origin popup cannot preserve its completion channel through a first-time sign-in redirect, so users should sign in to Clips in a separate tab before launching it. For a no-login customer-support flow, use [Anonymous Clips intake](/docs/template-clips-anonymous-intake). It creates a one-recording, write-only capability and keeps the normal owner-scoped upload endpoints protected.
102
102
 
103
103
  ## Data model
104
104
 
@@ -273,6 +273,7 @@ Two things live outside this schema on purpose: organization/member/invitation r
273
273
  | `recording_ctas` | Call-to-action buttons (label, url, color, placement) overlaid on a recording |
274
274
  | `recording_comments` | Threaded, timestamped comments with emoji-reaction map and resolved flag |
275
275
  | `recording_bug_reports` | Redacted host-product bug report metadata keyed by `recording_id` |
276
+ | `clips_intake_sessions` | One-use anonymous intake capabilities bound to an owner, organization, and recording |
276
277
  | `recording_reactions` | Emoji reactions pinned to a video timestamp (anonymous viewers allowed) |
277
278
  | `recording_viewers` / `recording_events` | View analytics: per-viewer watch time and completion, plus granular events (view-start, watch-progress, seek, pause, cta-click, reaction) |
278
279
  | `recording_views` | Append-only per-view log (who viewed, when) — backs the owner-facing "Viewed by" popover, kept separate from the aggregate counters above |
@@ -344,7 +345,7 @@ Recordings and transcripts are intentionally separate tables so the library and
344
345
  Every agent-callable operation is a TypeScript file in `templates/clips/actions/`, auto-mounted at `POST /_agent-native/actions/:name` and runnable from the CLI as `pnpm action <name>`. There are roughly 110 actions, grouped here by purpose:
345
346
 
346
347
  - **Recording lifecycle** — `create-recording`, `finalize-recording`, `update-recording`, `set-thumbnail`, `archive-recording` / `restore-recording` / `trash-recording` / `delete-recording-permanent`, `move-recording`, `tag-recording`, `reprocess-recording`, `import-loom-recording`.
347
- - **Bug reports** — `save-bug-report-context` stores redacted host-product context for recordings launched from `/bug-report`; `get-recording-player-data` returns the sidecar to editors.
348
+ - **Bug reports** — `save-bug-report-context` stores redacted host-product context for recordings launched from `/bug-report`; `create-recording-intake-link` mints a one-use anonymous intake URL; `create-intake-recording` is the anonymous write step and `create-intake-agent-link` is the authenticated host-side exchange; `get-recording-player-data` returns the sidecar to editors. See [Anonymous Clips intake](/docs/template-clips-anonymous-intake) for the complete flow.
348
349
  - **Transcript & AI** — `request-transcript`, `cleanup-transcript`, `save-browser-transcript`, `regenerate-title` / `regenerate-summary` / `regenerate-chapters`, `set-chapters`, `generate-workflow`, `get-clips-ai-prefs` / `update-clips-ai-prefs`, `get-builder-credit-status`. (`cleanup-transcript` and `finalize-meeting` are server-side media-pipeline calls; most other AI features delegate to the agent chat.)
349
350
  - **Editing** — non-destructive `trim-recording`, `split-recording`, `remove-filler-words`, `remove-silences`, plus `stitch-recordings`, `undo-edit`, `clear-edits`. Edits accumulate in `edits_json`; the client concatenates/exports via ffmpeg.wasm.
350
351
  - **Meetings** — `create-meeting`, `start-meeting-recording` / `stop-meeting-recording`, `finalize-meeting`, `update-meeting`, `get-meeting`, `list-meetings`, `delete-meeting`, plus calendar wiring `connect-calendar` / `disconnect-calendar` / `sync-calendars` / `list-calendar-accounts`.
@@ -116,6 +116,7 @@ Live demo: [clips.agent-native.com](https://clips.agent-native.com).
116
116
  - [**Sharing, Teams, and Agent-Readable Clips**](/docs/template-clips-sharing-and-teams) — visibility, passwords, organizations, and pasting a clip link into an agent.
117
117
  - [**AI Pipeline, Editing, and Insights**](/docs/template-clips-ai-and-editing) — transcription, non-destructive editing, and view analytics.
118
118
  - [**Extending Clips**](/docs/template-clips-developers) — for anyone customizing or extending the template.
119
+ - [**Anonymous Clips intake**](/docs/template-clips-anonymous-intake) — collect one private recording from an unsigned visitor with a short-lived signed URL.
119
120
  - [**Templates**](/docs/cloneable-saas) — the Cloneable SaaS model
120
121
  - [**Context Awareness**](/docs/context-awareness) — how the agent knows the current clip and playhead
121
122
  - [**Agent Teams**](/docs/agent-teams) — delegate transcript cleanup to a specialist sub-agent
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.178.1-nightly-20260910175201",
3
+ "version": "0.178.1",
4
4
  "description": "The agentic application framework for building autonomous agents with intuitive UIs",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -446,8 +446,8 @@
446
446
  "y-protocols": "^1.0.7",
447
447
  "yjs": "^13.6.32",
448
448
  "zod": "^4.3.6",
449
- "@agent-native/toolkit": "^0.19.7-nightly-20260910175201",
450
- "@agent-native/recap-cli": "0.5.28"
449
+ "@agent-native/recap-cli": "0.5.29",
450
+ "@agent-native/toolkit": "^0.19.7"
451
451
  },
452
452
  "devDependencies": {
453
453
  "@ai-sdk/anthropic": "^3.0.71",