@agent-native/core 0.102.1 → 0.102.2
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 +9 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/AgentPanel.tsx +7 -0
- package/corpus/core/src/client/AssistantChat.tsx +7 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +7 -1
- package/corpus/core/src/client/chat/message-components.tsx +17 -3
- package/corpus/core/src/client/composer/ComposerPlusMenu.tsx +96 -6
- package/corpus/core/src/client/composer/asset-picker-url.ts +80 -0
- package/corpus/core/src/client/error-format.ts +24 -0
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +8 -1
- package/corpus/templates/assets/app/routes/library.tsx +69 -0
- package/corpus/templates/assets/changelog/2026-07-15-fixed-top-level-image-picker-selections-returning-to-the-com.md +6 -0
- package/corpus/templates/clips/actions/disconnect-calendar.ts +57 -9
- package/corpus/templates/clips/actions/generate-workflow.ts +102 -59
- package/corpus/templates/clips/actions/get-recording-player-data.ts +64 -1
- package/corpus/templates/clips/actions/regenerate-summary.ts +7 -0
- package/corpus/templates/clips/actions/regenerate-title.ts +29 -11
- package/corpus/templates/clips/app/components/editor/editor-layout.tsx +22 -11
- package/corpus/templates/clips/app/components/editor/thumbnail-picker.tsx +87 -9
- package/corpus/templates/clips/app/components/editor/trim-handles.tsx +15 -0
- package/corpus/templates/clips/app/components/editor/waveform.tsx +21 -8
- package/corpus/templates/clips/app/components/library/folder-tree.tsx +52 -0
- package/corpus/templates/clips/app/components/player/settings-panel.tsx +86 -46
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +43 -37
- package/corpus/templates/clips/app/components/player/video-player.tsx +45 -1
- package/corpus/templates/clips/app/i18n/ar-SA.ts +2 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +2 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +2 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +2 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +2 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +2 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +2 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +2 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +2 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +2 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +2 -0
- package/corpus/templates/clips/app/lib/timestamp-mapping.ts +14 -0
- package/corpus/templates/clips/app/routes/_app.library._index.tsx +1 -2
- package/corpus/templates/clips/app/routes/_index.tsx +1 -2
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +71 -31
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +4 -1
- package/corpus/templates/clips/changelog/2026-07-15-ai-workflow-generation-now-stays-visible-avoids-duplicate-re.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-clip-playback-and-cta-controls-remain-interactive-through-ed.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-clip-titles-no-longer-describe-the-product-as-a-loom-alterna.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-description-regeneration-now-opens-the-agent-chat-so-progres.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-direct-recording-urls-now-respect-share-link-and-password-ac.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-disconnecting-a-calendar-now-clears-unrecorded-synced-meetin.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-folders-now-expose-rename-and-delete-actions-directly-in-the.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-recording-pages-now-explain-sign-in-access-and-avoid-showing.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-the-clips-extension-quick-actions-toolbar-can-be-moved-out-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-the-editor-now-skips-cut-sections-during-preview-and-keeps-t.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-thumbnail-capture-now-updates-previews-while-scrubbing-and-l.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-windows-permission-links-open-the-matching-settings-page.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +117 -2
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +27 -0
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -1
- package/corpus/templates/clips/server/lib/calendar-event-meetings.ts +139 -101
- package/corpus/templates/clips/server/lib/recording-page-access.ts +35 -0
- package/corpus/templates/design/app/components/design/design-canvas/external-preview.ts +7 -3
- package/corpus/templates/design/changelog/2026-07-15-prototype-print-and-download-buttons-now-work-in-preview.md +6 -0
- package/corpus/templates/slides/actions/extract-pdf.ts +1 -1
- package/corpus/templates/slides/actions/import-file.ts +4 -1
- package/corpus/templates/slides/app/components/editor/ImageGenPanel.tsx +1 -1
- package/corpus/templates/slides/app/components/editor/ImageSearchPanel.tsx +9 -12
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +29 -21
- package/corpus/templates/slides/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/slides/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/slides/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/slides/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/slides/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/slides/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/slides/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/slides/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/slides/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/slides/changelog/2026-07-15-image-search-and-generation-controls-now-use-the-registered-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-15-pdf-deck-references-can-be-imported-for-slide-inspiration-ag.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-15-stable-style-inspector-dock.md +6 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +5 -0
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +7 -0
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +8 -1
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +10 -3
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +58 -6
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/composer/asset-picker-url.d.ts +16 -0
- package/dist/client/composer/asset-picker-url.d.ts.map +1 -0
- package/dist/client/composer/asset-picker-url.js +64 -0
- package/dist/client/composer/asset-picker-url.js.map +1 -0
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +17 -0
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +6 -1
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
|
@@ -274,6 +274,27 @@ export function calendarEventToMeetingView(args: {
|
|
|
274
274
|
};
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Acquire the calendar account's write lock inside a caller-owned transaction.
|
|
279
|
+
* Disconnect and materialization both take this lock before touching the
|
|
280
|
+
* account's calendar events, so cleanup cannot race a meeting insert.
|
|
281
|
+
*/
|
|
282
|
+
export async function lockCalendarAccount(
|
|
283
|
+
db: any,
|
|
284
|
+
accountId: string,
|
|
285
|
+
ownerEmail?: string | null,
|
|
286
|
+
): Promise<boolean> {
|
|
287
|
+
const ownerFilter = ownerEmail
|
|
288
|
+
? eq(schema.calendarAccounts.ownerEmail, ownerEmail)
|
|
289
|
+
: isNull(schema.calendarAccounts.ownerEmail);
|
|
290
|
+
const locked = await db
|
|
291
|
+
.update(schema.calendarAccounts)
|
|
292
|
+
.set({ updatedAt: new Date().toISOString() })
|
|
293
|
+
.where(and(eq(schema.calendarAccounts.id, accountId), ownerFilter))
|
|
294
|
+
.returning({ id: schema.calendarAccounts.id });
|
|
295
|
+
return locked.length > 0;
|
|
296
|
+
}
|
|
297
|
+
|
|
277
298
|
export async function fetchLiveCalendarEventFromId(virtualId: string) {
|
|
278
299
|
const parsed = parseCalendarMeetingId(virtualId);
|
|
279
300
|
if (!parsed) return null;
|
|
@@ -317,11 +338,14 @@ export async function fetchLiveCalendarEventFromId(virtualId: string) {
|
|
|
317
338
|
}
|
|
318
339
|
}
|
|
319
340
|
|
|
320
|
-
export async function upsertCalendarEventSnapshot(
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
341
|
+
export async function upsertCalendarEventSnapshot(
|
|
342
|
+
args: {
|
|
343
|
+
account: CalendarAccountForEvents;
|
|
344
|
+
event: CalendarEvent;
|
|
345
|
+
},
|
|
346
|
+
database: any = getDb(),
|
|
347
|
+
) {
|
|
348
|
+
const db = database;
|
|
325
349
|
const startIso = eventStartIso(args.event);
|
|
326
350
|
const endIso = eventEndIso(args.event);
|
|
327
351
|
if (!args.event.id || !startIso || !endIso) {
|
|
@@ -397,120 +421,134 @@ export async function materializeCalendarMeetingFromVirtualId(
|
|
|
397
421
|
const live = await fetchLiveCalendarEventFromId(virtualId);
|
|
398
422
|
if (!live) return null;
|
|
399
423
|
const db = getDb();
|
|
400
|
-
const snapshot = await upsertCalendarEventSnapshot(live);
|
|
401
|
-
|
|
402
|
-
if (snapshot.meetingId) {
|
|
403
|
-
const [existingMeeting] = await db
|
|
404
|
-
.select()
|
|
405
|
-
.from(schema.meetings)
|
|
406
|
-
.where(eq(schema.meetings.id, snapshot.meetingId))
|
|
407
|
-
.limit(1);
|
|
408
|
-
if (existingMeeting) return { meeting: existingMeeting, created: false };
|
|
409
|
-
}
|
|
410
|
-
|
|
411
424
|
const ownerEmail = getCurrentOwnerEmail();
|
|
412
425
|
const orgId = (await getActiveOrganizationId().catch(() => null)) ?? null;
|
|
413
426
|
const joinUrl = pickJoinUrl(live.event);
|
|
414
427
|
const meetingId = nanoid();
|
|
415
428
|
const nowIso = new Date().toISOString();
|
|
416
429
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
.update(schema.calendarEvents)
|
|
424
|
-
.set({ meetingId, updatedAt: nowIso })
|
|
425
|
-
.where(
|
|
426
|
-
and(
|
|
427
|
-
eq(schema.calendarEvents.id, snapshot.id),
|
|
428
|
-
isNull(schema.calendarEvents.meetingId),
|
|
429
|
-
),
|
|
430
|
+
return db.transaction(async (tx: any) => {
|
|
431
|
+
// Disconnect takes this same account-row write lock before it snapshots
|
|
432
|
+
// and deletes events. If disconnect wins, the account is gone by the time
|
|
433
|
+
// this transaction reaches the lock and materialization becomes a no-op.
|
|
434
|
+
if (
|
|
435
|
+
!(await lockCalendarAccount(tx, live.account.id, live.account.ownerEmail))
|
|
430
436
|
)
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
.from(schema.calendarEvents)
|
|
438
|
-
.where(eq(schema.calendarEvents.id, snapshot.id))
|
|
439
|
-
.limit(1);
|
|
440
|
-
if (winnerEvent?.meetingId) {
|
|
441
|
-
const [winnerMeeting] = await db
|
|
437
|
+
return null;
|
|
438
|
+
|
|
439
|
+
const snapshot = await upsertCalendarEventSnapshot(live, tx);
|
|
440
|
+
|
|
441
|
+
if (snapshot.meetingId) {
|
|
442
|
+
const [existingMeeting] = await tx
|
|
442
443
|
.select()
|
|
443
444
|
.from(schema.meetings)
|
|
444
|
-
.where(eq(schema.meetings.id,
|
|
445
|
+
.where(eq(schema.meetings.id, snapshot.meetingId))
|
|
445
446
|
.limit(1);
|
|
446
|
-
if (
|
|
447
|
+
if (existingMeeting) {
|
|
448
|
+
return { meeting: existingMeeting, created: false };
|
|
449
|
+
}
|
|
447
450
|
}
|
|
448
|
-
return null;
|
|
449
|
-
}
|
|
450
451
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
scheduledEnd: eventEndIso(live.event),
|
|
458
|
-
actualStart: null,
|
|
459
|
-
actualEnd: null,
|
|
460
|
-
platform: detectPlatform(joinUrl),
|
|
461
|
-
joinUrl: joinUrl ?? null,
|
|
462
|
-
calendarEventId: snapshot.id,
|
|
463
|
-
recordingId: null,
|
|
464
|
-
transcriptStatus: "idle",
|
|
465
|
-
summaryMd: "",
|
|
466
|
-
bulletsJson: "[]",
|
|
467
|
-
actionItemsJson: "[]",
|
|
468
|
-
source: "calendar",
|
|
469
|
-
reminderFiredAt: null,
|
|
470
|
-
createdAt: nowIso,
|
|
471
|
-
updatedAt: nowIso,
|
|
472
|
-
ownerEmail,
|
|
473
|
-
orgId,
|
|
474
|
-
visibility: "private",
|
|
475
|
-
} as any);
|
|
476
|
-
|
|
477
|
-
const participants = calendarEventParticipants(live.event).filter(
|
|
478
|
-
(p) => p.email,
|
|
479
|
-
);
|
|
480
|
-
if (participants.length) {
|
|
481
|
-
await db.insert(schema.meetingParticipants).values(
|
|
482
|
-
participants.map((p) => ({
|
|
483
|
-
id: nanoid(),
|
|
484
|
-
meetingId,
|
|
485
|
-
email: p.email,
|
|
486
|
-
name: p.name ?? null,
|
|
487
|
-
isOrganizer: !!p.isOrganizer,
|
|
488
|
-
attendedAt: null,
|
|
489
|
-
createdAt: nowIso,
|
|
490
|
-
})) as any,
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
} catch (err) {
|
|
494
|
-
// Roll back the claim so a future call can retry — but only if it still
|
|
495
|
-
// points at our own meetingId (don't clobber a legitimate later claim).
|
|
496
|
-
await db
|
|
452
|
+
// Claim the calendar_events row atomically before inserting the meeting
|
|
453
|
+
// row, so two concurrent materialize calls for the same event can't both
|
|
454
|
+
// insert a `meetings` row (check-then-act TOCTOU). Only the caller whose
|
|
455
|
+
// UPDATE actually matched a row (meetingId still NULL) proceeds to insert;
|
|
456
|
+
// the loser re-reads and returns the winner's meeting instead.
|
|
457
|
+
const claimed = await tx
|
|
497
458
|
.update(schema.calendarEvents)
|
|
498
|
-
.set({ meetingId
|
|
459
|
+
.set({ meetingId, updatedAt: nowIso })
|
|
499
460
|
.where(
|
|
500
461
|
and(
|
|
501
462
|
eq(schema.calendarEvents.id, snapshot.id),
|
|
502
|
-
|
|
463
|
+
isNull(schema.calendarEvents.meetingId),
|
|
503
464
|
),
|
|
504
465
|
)
|
|
505
|
-
.
|
|
506
|
-
|
|
507
|
-
|
|
466
|
+
.returning({ id: schema.calendarEvents.id });
|
|
467
|
+
|
|
468
|
+
if (!claimed.length) {
|
|
469
|
+
// Someone else claimed it first — re-read and return the winner.
|
|
470
|
+
const [winnerEvent] = await tx
|
|
471
|
+
.select({ meetingId: schema.calendarEvents.meetingId })
|
|
472
|
+
.from(schema.calendarEvents)
|
|
473
|
+
.where(eq(schema.calendarEvents.id, snapshot.id))
|
|
474
|
+
.limit(1);
|
|
475
|
+
if (winnerEvent?.meetingId) {
|
|
476
|
+
const [winnerMeeting] = await tx
|
|
477
|
+
.select()
|
|
478
|
+
.from(schema.meetings)
|
|
479
|
+
.where(eq(schema.meetings.id, winnerEvent.meetingId))
|
|
480
|
+
.limit(1);
|
|
481
|
+
if (winnerMeeting) {
|
|
482
|
+
return { meeting: winnerMeeting, created: false };
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
508
487
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
488
|
+
try {
|
|
489
|
+
await tx.insert(schema.meetings).values({
|
|
490
|
+
id: meetingId,
|
|
491
|
+
organizationId: orgId ?? live.account.orgId ?? null,
|
|
492
|
+
title: live.event.summary || "Untitled meeting",
|
|
493
|
+
scheduledStart: eventStartIso(live.event),
|
|
494
|
+
scheduledEnd: eventEndIso(live.event),
|
|
495
|
+
actualStart: null,
|
|
496
|
+
actualEnd: null,
|
|
497
|
+
platform: detectPlatform(joinUrl),
|
|
498
|
+
joinUrl: joinUrl ?? null,
|
|
499
|
+
calendarEventId: snapshot.id,
|
|
500
|
+
recordingId: null,
|
|
501
|
+
transcriptStatus: "idle",
|
|
502
|
+
summaryMd: "",
|
|
503
|
+
bulletsJson: "[]",
|
|
504
|
+
actionItemsJson: "[]",
|
|
505
|
+
source: "calendar",
|
|
506
|
+
reminderFiredAt: null,
|
|
507
|
+
createdAt: nowIso,
|
|
508
|
+
updatedAt: nowIso,
|
|
509
|
+
ownerEmail,
|
|
510
|
+
orgId,
|
|
511
|
+
visibility: "private",
|
|
512
|
+
} as any);
|
|
513
|
+
|
|
514
|
+
const participants = calendarEventParticipants(live.event).filter(
|
|
515
|
+
(p) => p.email,
|
|
516
|
+
);
|
|
517
|
+
if (participants.length) {
|
|
518
|
+
await tx.insert(schema.meetingParticipants).values(
|
|
519
|
+
participants.map((p) => ({
|
|
520
|
+
id: nanoid(),
|
|
521
|
+
meetingId,
|
|
522
|
+
email: p.email,
|
|
523
|
+
name: p.name ?? null,
|
|
524
|
+
isOrganizer: !!p.isOrganizer,
|
|
525
|
+
attendedAt: null,
|
|
526
|
+
createdAt: nowIso,
|
|
527
|
+
})) as any,
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
} catch (err) {
|
|
531
|
+
// Roll back the claim so a future call can retry — but only if it still
|
|
532
|
+
// points at our own meetingId (don't clobber a legitimate later claim).
|
|
533
|
+
await tx
|
|
534
|
+
.update(schema.calendarEvents)
|
|
535
|
+
.set({ meetingId: null, updatedAt: new Date().toISOString() })
|
|
536
|
+
.where(
|
|
537
|
+
and(
|
|
538
|
+
eq(schema.calendarEvents.id, snapshot.id),
|
|
539
|
+
eq(schema.calendarEvents.meetingId, meetingId),
|
|
540
|
+
),
|
|
541
|
+
)
|
|
542
|
+
.catch(() => {});
|
|
543
|
+
throw err;
|
|
544
|
+
}
|
|
514
545
|
|
|
515
|
-
|
|
546
|
+
const [meeting] = await tx
|
|
547
|
+
.select()
|
|
548
|
+
.from(schema.meetings)
|
|
549
|
+
.where(eq(schema.meetings.id, meetingId))
|
|
550
|
+
.limit(1);
|
|
551
|
+
|
|
552
|
+
return { meeting, created: true };
|
|
553
|
+
});
|
|
516
554
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type RecordingPageAccessRole = "owner" | "admin" | "editor" | "viewer";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Match the public recording and video routes: only a finite expiry date can
|
|
5
|
+
* expire a recording, and the expiry is strict so the exact instant remains
|
|
6
|
+
* valid until time advances past it.
|
|
7
|
+
*/
|
|
8
|
+
export function isRecordingExpired(
|
|
9
|
+
expiresAt: string | null | undefined,
|
|
10
|
+
now = Date.now(),
|
|
11
|
+
): boolean {
|
|
12
|
+
if (!expiresAt) return false;
|
|
13
|
+
|
|
14
|
+
const expires = new Date(expiresAt).getTime();
|
|
15
|
+
return Number.isFinite(expires) && expires < now;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Decide whether an authenticated request may use the editor/player route.
|
|
20
|
+
* Public visibility is intentionally a share-link concern; a direct `/r/*`
|
|
21
|
+
* request must either be the owner or have an explicit share grant.
|
|
22
|
+
* Password-protected recordings stay on the password-aware share flow for
|
|
23
|
+
* every non-owner so the authenticated action cannot mint a bypass token.
|
|
24
|
+
*/
|
|
25
|
+
export function canOpenDirectRecordingPage(input: {
|
|
26
|
+
role: RecordingPageAccessRole;
|
|
27
|
+
visibility: "private" | "org" | "public";
|
|
28
|
+
hasPassword: boolean;
|
|
29
|
+
hasExplicitShare: boolean;
|
|
30
|
+
}): boolean {
|
|
31
|
+
if (input.role === "owner") return true;
|
|
32
|
+
if (input.hasPassword) return false;
|
|
33
|
+
if (input.visibility === "public") return input.hasExplicitShare;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
@@ -110,12 +110,16 @@ export function sanitizeLocalhostSourceSnapshotHtml(html: string): string {
|
|
|
110
110
|
);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
// Prototypes are still sandboxed, but user-initiated print/download controls
|
|
114
|
+
// need the browser permissions that make `window.print()` and download links
|
|
115
|
+
// work inside an iframe. Without these tokens the browser silently ignores
|
|
116
|
+
// the common "Download / Print PDF" pattern.
|
|
113
117
|
const EXTERNAL_PREVIEW_IFRAME_SANDBOX =
|
|
114
|
-
"allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-same-origin";
|
|
118
|
+
"allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads allow-modals allow-same-origin";
|
|
115
119
|
const EDITABLE_INLINE_IFRAME_SANDBOX =
|
|
116
|
-
"allow-scripts allow-popups allow-popups-to-escape-sandbox allow-same-origin";
|
|
120
|
+
"allow-scripts allow-popups allow-popups-to-escape-sandbox allow-downloads allow-modals allow-same-origin";
|
|
117
121
|
const READ_ONLY_INLINE_IFRAME_SANDBOX =
|
|
118
|
-
"allow-scripts allow-popups allow-popups-to-escape-sandbox";
|
|
122
|
+
"allow-scripts allow-popups allow-popups-to-escape-sandbox allow-downloads allow-modals";
|
|
119
123
|
|
|
120
124
|
export function getDesignCanvasIframeSandbox(args: {
|
|
121
125
|
externalPreview: boolean;
|
|
@@ -11,7 +11,7 @@ export default async function (args: string[]) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const buf = fs.readFileSync(pdfPath);
|
|
14
|
-
const pdf = new PDFParse(new Uint8Array(buf));
|
|
14
|
+
const pdf = new PDFParse({ data: new Uint8Array(buf) });
|
|
15
15
|
const result = await pdf.getText();
|
|
16
16
|
const pages = result.pages || [];
|
|
17
17
|
console.log("Total pages:", pages.length);
|
|
@@ -214,7 +214,10 @@ export default defineAction({
|
|
|
214
214
|
const { PDFParse } = await import("pdf-parse");
|
|
215
215
|
const { convertSectionsToSlides } =
|
|
216
216
|
await import("../server/handlers/import/html-converter.js");
|
|
217
|
-
|
|
217
|
+
// pdf-parse v2 expects a LoadParameters object. Passing the byte array
|
|
218
|
+
// directly uses the old v1 shape and can fail while pdf.js initializes
|
|
219
|
+
// in production (the reported DOMMatrix error).
|
|
220
|
+
const pdf = new PDFParse({ data: new Uint8Array(fileBuffer) });
|
|
218
221
|
const result = await pdf.getText();
|
|
219
222
|
const pages = normalizePdfPages(result);
|
|
220
223
|
const textPages = pages.filter((p) => p.text.trim());
|
|
@@ -69,7 +69,7 @@ export default function ImageGenPanel({
|
|
|
69
69
|
const contextParts: string[] = [];
|
|
70
70
|
|
|
71
71
|
contextParts.push(
|
|
72
|
-
"Generate 3 image variations
|
|
72
|
+
"Generate 3 image variations by calling the registered `generate-image-api` action three times with the same prompt.",
|
|
73
73
|
);
|
|
74
74
|
contextParts.push(
|
|
75
75
|
"The deliverables must be actual generated image assets from the action. Do not create placeholder HTML/CSS, oversized icon compositions, inline SVGs, or text-only mockups.",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { callAction, useT } from "@agent-native/core/client";
|
|
2
2
|
import { IconX, IconSearch, IconLoader2 } from "@tabler/icons-react";
|
|
3
3
|
import { useState, useEffect, useRef } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
@@ -61,18 +61,15 @@ export default function ImageSearchPanel({
|
|
|
61
61
|
setLoading(true);
|
|
62
62
|
setError(null);
|
|
63
63
|
try {
|
|
64
|
-
const
|
|
65
|
-
|
|
64
|
+
const data = await callAction<SearchResult[]>(
|
|
65
|
+
"search-images",
|
|
66
|
+
{ q: query.trim() },
|
|
67
|
+
{ method: "GET" },
|
|
66
68
|
);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
} else {
|
|
72
|
-
setResults(await res.json());
|
|
73
|
-
}
|
|
74
|
-
} catch {
|
|
75
|
-
setError("Search failed");
|
|
69
|
+
setResults(data);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
setError(error instanceof Error ? error.message : t("raw.searchFailed"));
|
|
72
|
+
setResults([]);
|
|
76
73
|
} finally {
|
|
77
74
|
setLoading(false);
|
|
78
75
|
}
|
|
@@ -1141,7 +1141,10 @@ export default function SlideEditor({
|
|
|
1141
1141
|
const selector = getBuilderSelector(el);
|
|
1142
1142
|
el.contentEditable = "true";
|
|
1143
1143
|
el.setAttribute("data-editing-block", "true");
|
|
1144
|
-
|
|
1144
|
+
// Keep the inspector selection mounted while text is being edited. The
|
|
1145
|
+
// inspector is a stable dock, so clearing it here would make the canvas
|
|
1146
|
+
// resize and auto-fit again on the second click.
|
|
1147
|
+
setSelectedElementRect(null);
|
|
1145
1148
|
captureInlineEditDraft(slide.id);
|
|
1146
1149
|
// Mark the deck dirty immediately so SSE/poll refreshes do not replace
|
|
1147
1150
|
// the deck under an active contentEditable edit, even before the user
|
|
@@ -1167,13 +1170,7 @@ export default function SlideEditor({
|
|
|
1167
1170
|
);
|
|
1168
1171
|
}
|
|
1169
1172
|
},
|
|
1170
|
-
[
|
|
1171
|
-
buildSelectionState,
|
|
1172
|
-
captureInlineEditDraft,
|
|
1173
|
-
clearSelectedElement,
|
|
1174
|
-
onInlineEditStart,
|
|
1175
|
-
slide.id,
|
|
1176
|
-
],
|
|
1173
|
+
[buildSelectionState, captureInlineEditDraft, onInlineEditStart, slide.id],
|
|
1177
1174
|
);
|
|
1178
1175
|
|
|
1179
1176
|
// Exit edit mode when switching slides — save pending content first so
|
|
@@ -2053,18 +2050,29 @@ export default function SlideEditor({
|
|
|
2053
2050
|
)}
|
|
2054
2051
|
</div>
|
|
2055
2052
|
|
|
2056
|
-
{
|
|
2057
|
-
<div
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2053
|
+
{!readOnly && (
|
|
2054
|
+
<div
|
|
2055
|
+
className="relative z-[70] hidden h-full w-[17rem] shrink-0 border-l border-border/70 bg-background/95 lg:block"
|
|
2056
|
+
data-slide-style-dock="true"
|
|
2057
|
+
>
|
|
2058
|
+
{selectedStyleSnapshot ? (
|
|
2059
|
+
<SlideStyleInspector
|
|
2060
|
+
snapshot={selectedStyleSnapshot}
|
|
2061
|
+
designSystem={designSystem}
|
|
2062
|
+
className="h-full w-full rounded-none border-0 bg-transparent shadow-none"
|
|
2063
|
+
onChange={applySelectedStylePatch}
|
|
2064
|
+
onClose={() => {
|
|
2065
|
+
clearSelectedElement();
|
|
2066
|
+
syncSelectionToAppState(null);
|
|
2067
|
+
}}
|
|
2068
|
+
/>
|
|
2069
|
+
) : (
|
|
2070
|
+
<div className="flex h-11 items-center border-b border-border/70 px-3">
|
|
2071
|
+
<span className="text-[10px] font-semibold uppercase tracking-[0.16em] text-muted-foreground/70">
|
|
2072
|
+
{t("styleInspector.title")}
|
|
2073
|
+
</span>
|
|
2074
|
+
</div>
|
|
2075
|
+
)}
|
|
2068
2076
|
</div>
|
|
2069
2077
|
)}
|
|
2070
2078
|
</div>
|
|
@@ -2082,7 +2090,7 @@ export default function SlideEditor({
|
|
|
2082
2090
|
viewportRect={selectionViewportRect}
|
|
2083
2091
|
/>
|
|
2084
2092
|
)}
|
|
2085
|
-
{selectedElementRect && (
|
|
2093
|
+
{selectedElementRect && !editingEl && (
|
|
2086
2094
|
<ElementSelectionOutline
|
|
2087
2095
|
rect={selectedElementRect}
|
|
2088
2096
|
viewportRect={selectionViewportRect}
|
|
@@ -103,6 +103,7 @@ const messages = {
|
|
|
103
103
|
searchImagesPlaceholder: "Buscar imagens...",
|
|
104
104
|
searchForLogosImagesIcons: "Buscar logos, imagens, ícones...",
|
|
105
105
|
search: "بحث",
|
|
106
|
+
searchFailed: "فشل البحث",
|
|
106
107
|
logoSearchTitle: "بحث عن الشعار",
|
|
107
108
|
searchCompanyLogo: "Busque uma empresa para encontrar seu logo",
|
|
108
109
|
searchCompanyPlaceholder: "Buscar nome da empresa (ex.: Intuit)",
|
|
@@ -106,6 +106,7 @@ const messages = {
|
|
|
106
106
|
searchImagesPlaceholder: "Nach Bildern suchen...",
|
|
107
107
|
searchForLogosImagesIcons: "Nach Logos, Bildern, Icons suchen...",
|
|
108
108
|
search: "Suchen",
|
|
109
|
+
searchFailed: "Suche fehlgeschlagen",
|
|
109
110
|
logoSearchTitle: "Logo-Suche",
|
|
110
111
|
searchCompanyLogo: "Suche nach einem Unternehmen, um sein Logo zu finden",
|
|
111
112
|
searchCompanyPlaceholder: "Unternehmensname suchen (z. B. Intuit)",
|
|
@@ -104,6 +104,7 @@ const messages = {
|
|
|
104
104
|
searchImagesPlaceholder: "Search for images...",
|
|
105
105
|
searchForLogosImagesIcons: "Search for logos, images, icons...",
|
|
106
106
|
search: "Search",
|
|
107
|
+
searchFailed: "Search failed",
|
|
107
108
|
logoSearchTitle: "Logo Search",
|
|
108
109
|
searchCompanyLogo: "Search for a company to find their logo",
|
|
109
110
|
searchCompanyPlaceholder: "Search company name (e.g. Intuit)",
|
|
@@ -105,6 +105,7 @@ const messages = {
|
|
|
105
105
|
searchImagesPlaceholder: "Buscar imágenes...",
|
|
106
106
|
searchForLogosImagesIcons: "Buscar logos, imágenes, iconos...",
|
|
107
107
|
search: "Buscar",
|
|
108
|
+
searchFailed: "Error al buscar",
|
|
108
109
|
logoSearchTitle: "Búsqueda de logos",
|
|
109
110
|
searchCompanyLogo: "Busca una empresa para encontrar su logo",
|
|
110
111
|
searchCompanyPlaceholder: "Buscar nombre de empresa (p. ej. Intuit)",
|
|
@@ -106,6 +106,7 @@ const messages = {
|
|
|
106
106
|
searchImagesPlaceholder: "Rechercher des images...",
|
|
107
107
|
searchForLogosImagesIcons: "Rechercher des logos, images, icônes...",
|
|
108
108
|
search: "Rechercher",
|
|
109
|
+
searchFailed: "Échec de la recherche",
|
|
109
110
|
logoSearchTitle: "Recherche de logo",
|
|
110
111
|
searchCompanyLogo: "Recherchez une entreprise pour trouver son logo",
|
|
111
112
|
searchCompanyPlaceholder: "Rechercher un nom d’entreprise (ex. Intuit)",
|
|
@@ -103,6 +103,7 @@ const messages = {
|
|
|
103
103
|
searchImagesPlaceholder: "Buscar imagens...",
|
|
104
104
|
searchForLogosImagesIcons: "Buscar logos, imagens, ícones...",
|
|
105
105
|
search: "खोजें",
|
|
106
|
+
searchFailed: "खोज विफल",
|
|
106
107
|
logoSearchTitle: "लोगो खोज",
|
|
107
108
|
searchCompanyLogo: "Busque uma empresa para encontrar seu logo",
|
|
108
109
|
searchCompanyPlaceholder: "Buscar nome da empresa (ex.: Intuit)",
|
|
@@ -104,6 +104,7 @@ const messages = {
|
|
|
104
104
|
searchImagesPlaceholder: "画像を検索...",
|
|
105
105
|
searchForLogosImagesIcons: "ロゴ、画像、アイコンを検索...",
|
|
106
106
|
search: "検索",
|
|
107
|
+
searchFailed: "検索に失敗しました",
|
|
107
108
|
logoSearchTitle: "ロゴ検索",
|
|
108
109
|
searchCompanyLogo: "会社を検索してロゴを見つける",
|
|
109
110
|
searchCompanyPlaceholder: "会社名を検索(例: Intuit)",
|
|
@@ -104,6 +104,7 @@ const messages = {
|
|
|
104
104
|
searchImagesPlaceholder: "画像を検索...",
|
|
105
105
|
searchForLogosImagesIcons: "ロゴ、画像、アイコンを検索...",
|
|
106
106
|
search: "검색",
|
|
107
|
+
searchFailed: "검색 실패",
|
|
107
108
|
logoSearchTitle: "로고 검색",
|
|
108
109
|
searchCompanyLogo: "会社を検索してロゴを見つける",
|
|
109
110
|
searchCompanyPlaceholder: "会社名を検索(例: Intuit)",
|
|
@@ -104,6 +104,7 @@ const messages = {
|
|
|
104
104
|
searchImagesPlaceholder: "Buscar imagens...",
|
|
105
105
|
searchForLogosImagesIcons: "Buscar logos, imagens, ícones...",
|
|
106
106
|
search: "Buscar",
|
|
107
|
+
searchFailed: "Falha na pesquisa",
|
|
107
108
|
logoSearchTitle: "Busca de logo",
|
|
108
109
|
searchCompanyLogo: "Busque uma empresa para encontrar seu logo",
|
|
109
110
|
searchCompanyPlaceholder: "Buscar nome da empresa (ex.: Intuit)",
|
|
@@ -102,6 +102,7 @@ const messages = {
|
|
|
102
102
|
searchImagesPlaceholder: "画像を検索...",
|
|
103
103
|
searchForLogosImagesIcons: "ロゴ、画像、アイコンを検索...",
|
|
104
104
|
search: "搜索",
|
|
105
|
+
searchFailed: "搜索失败",
|
|
105
106
|
logoSearchTitle: "徽标搜索",
|
|
106
107
|
searchCompanyLogo: "会社を検索してロゴを見つける",
|
|
107
108
|
searchCompanyPlaceholder: "会社名を検索(例: Intuit)",
|
|
@@ -100,6 +100,7 @@ const messages = {
|
|
|
100
100
|
searchImagesPlaceholder: "搜尋圖片...",
|
|
101
101
|
searchForLogosImagesIcons: "搜尋徽標、圖片、圖示...",
|
|
102
102
|
search: "搜尋",
|
|
103
|
+
searchFailed: "搜尋失敗",
|
|
103
104
|
logoSearchTitle: "徽標搜尋",
|
|
104
105
|
searchCompanyLogo: "搜尋公司以尋找徽標",
|
|
105
106
|
searchCompanyPlaceholder: "搜尋公司名稱(例如:Intuit)",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentPanel.d.ts","sourceRoot":"","sources":["../../src/client/AgentPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAmBH,OAAO,KASN,MAAM,OAAO,CAAC;AAkCf,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAapE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAY7D,OAAO,KAAK,EACV,gCAAgC,EAChC,0BAA0B,EAC3B,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"AgentPanel.d.ts","sourceRoot":"","sources":["../../src/client/AgentPanel.tsx"],"names":[],"mappings":"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"}
|