@agent-native/core 0.90.3 → 0.90.4
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/bin/agent-native.js +25 -3
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +9 -0
- package/corpus/core/bin/agent-native.js +25 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/engine/index.ts +1 -0
- package/corpus/core/src/agent/engine/registry.ts +63 -2
- package/corpus/core/src/cli/create.ts +35 -0
- package/corpus/core/src/cli/design-connect.ts +248 -0
- package/corpus/core/src/cli/index.ts +84 -7
- package/corpus/core/src/cli/workspacify.ts +34 -0
- package/corpus/core/src/client/history/VersionHistoryPanel.tsx +77 -47
- package/corpus/core/src/client/history/index.ts +3 -0
- package/corpus/core/src/client/history/use-history.ts +28 -0
- package/corpus/core/src/client/index.ts +8 -0
- package/corpus/core/src/client/review/index.ts +5 -0
- package/corpus/core/src/client/review/use-review.ts +40 -2
- package/corpus/core/src/history/actions/create-resource-version.ts +11 -8
- package/corpus/core/src/history/index.ts +0 -1
- package/corpus/core/src/history/registry.ts +24 -12
- package/corpus/core/src/history/store.ts +84 -53
- package/corpus/core/src/review/actions/consume-review-feedback.ts +15 -5
- package/corpus/core/src/review/actions/delete-review-comment.ts +15 -3
- package/corpus/core/src/review/actions/resolve-review-thread.ts +12 -5
- package/corpus/core/src/review/index.ts +0 -5
- package/corpus/core/src/review/registry.ts +24 -12
- package/corpus/core/src/review/store.ts +10 -7
- package/corpus/core/src/server/agent-chat-plugin.ts +6 -0
- package/corpus/core/src/server/credential-provider.ts +13 -3
- package/corpus/templates/assets/actions/_preset-skeleton-validation.ts +11 -11
- package/corpus/templates/assets/actions/generate-image.ts +64 -28
- package/corpus/templates/assets/app/components/generation/GenerationResults.tsx +1 -1
- package/corpus/templates/assets/app/routes/brand-kits.$id_.presets.$presetId.tsx +91 -74
- package/corpus/templates/assets/server/lib/generation.ts +29 -4
- package/corpus/templates/assets/server/lib/image-processing.ts +131 -0
- package/corpus/templates/calendar/.agents/skills/event-management/SKILL.md +24 -2
- package/corpus/templates/calendar/AGENTS.md +3 -0
- package/corpus/templates/calendar/actions/create-event.ts +8 -34
- package/corpus/templates/calendar/actions/event-action-helpers.ts +52 -0
- package/corpus/templates/calendar/actions/manage-event-draft.ts +7 -34
- package/corpus/templates/calendar/actions/update-event.ts +10 -23
- package/corpus/templates/calendar/app/components/calendar/AttendeeAutocomplete.tsx +47 -0
- package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +23 -0
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +59 -2
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +40 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +34 -1
- package/corpus/templates/calendar/app/hooks/use-events.ts +6 -0
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/calendar/app/i18n-data.ts +40 -0
- package/corpus/templates/calendar/changelog/2026-07-07-you-can-mark-event-guests-as-optional-while-inviting-them-or.md +6 -0
- package/corpus/templates/calendar/server/handlers/events.ts +1 -0
- package/corpus/templates/calendar/server/lib/google-calendar.ts +4 -0
- package/corpus/templates/calendar/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/calendar/shared/api.ts +2 -0
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +29 -3
- package/corpus/templates/clips/actions/generate-workflow.ts +19 -8
- package/corpus/templates/clips/actions/get-clips-ai-prefs.ts +36 -0
- package/corpus/templates/clips/actions/lib/clips-ai-prefs.ts +28 -0
- package/corpus/templates/clips/actions/regenerate-chapters.ts +21 -7
- package/corpus/templates/clips/actions/regenerate-summary.ts +26 -8
- package/corpus/templates/clips/actions/regenerate-title.ts +44 -7
- package/corpus/templates/clips/actions/update-clips-ai-prefs.ts +50 -0
- package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +7 -2
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +25 -10
- package/corpus/templates/clips/app/i18n/ar-SA.ts +28 -6
- package/corpus/templates/clips/app/i18n/de-DE.ts +28 -6
- package/corpus/templates/clips/app/i18n/en-US.ts +29 -6
- package/corpus/templates/clips/app/i18n/es-ES.ts +29 -6
- package/corpus/templates/clips/app/i18n/fr-FR.ts +30 -6
- package/corpus/templates/clips/app/i18n/hi-IN.ts +26 -6
- package/corpus/templates/clips/app/i18n/ja-JP.ts +27 -6
- package/corpus/templates/clips/app/i18n/ko-KR.ts +28 -6
- package/corpus/templates/clips/app/i18n/pt-BR.ts +28 -6
- package/corpus/templates/clips/app/i18n/zh-CN.ts +26 -6
- package/corpus/templates/clips/app/i18n/zh-TW.ts +25 -6
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +73 -0
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -2
- package/corpus/templates/clips/changelog/2026-07-07-ai-tools-can-include-the-full-video-not-just-the-transcript-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-clips-desktop-now-surfaces-meetings-and-dictate-directly-in-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-meeting-notes-now-explain-exactly-how-to-start-granola-style.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-meeting-start-alerts-now-include-separate-start-notes-and-jo.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-07-recordings-start-more-predictably-and-newly-saved-clips-refr.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/desktop/src/app.tsx +435 -105
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +27 -21
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +23 -22
- package/corpus/templates/clips/desktop/src/styles.css +167 -2
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +3 -7
- package/corpus/templates/clips/desktop/src-tauri/src/tray_meetings.rs +5 -4
- package/corpus/templates/clips/server/routes/_agent-native/clips/user-prefs.put.ts +16 -8
- package/corpus/templates/clips/shared/clips-ai-prefs.ts +81 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +16 -1
- package/corpus/templates/design/actions/add-localhost-screens.ts +1 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +345 -11
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +89 -14
- package/corpus/templates/design/app/components/design/bridge-security.ts +7 -1
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -1
- package/corpus/templates/design/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/design/app/i18n-data.ts +41 -0
- package/corpus/templates/design/changelog/2026-07-07-local-visual-edit-uses-live-app-iframes-for-click-to-edit-pr.md +6 -0
- package/dist/agent/engine/index.d.ts +1 -1
- package/dist/agent/engine/index.d.ts.map +1 -1
- package/dist/agent/engine/index.js +1 -1
- package/dist/agent/engine/index.js.map +1 -1
- package/dist/agent/engine/registry.d.ts +14 -0
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +56 -2
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +31 -0
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +186 -0
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/index.js +76 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/workspacify.d.ts.map +1 -1
- package/dist/cli/workspacify.js +30 -0
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/history/VersionHistoryPanel.d.ts +1 -1
- package/dist/client/history/VersionHistoryPanel.d.ts.map +1 -1
- package/dist/client/history/VersionHistoryPanel.js +12 -5
- package/dist/client/history/VersionHistoryPanel.js.map +1 -1
- package/dist/client/history/index.d.ts +1 -1
- package/dist/client/history/index.d.ts.map +1 -1
- package/dist/client/history/index.js +1 -1
- package/dist/client/history/index.js.map +1 -1
- package/dist/client/history/use-history.d.ts +12 -0
- package/dist/client/history/use-history.d.ts.map +1 -1
- package/dist/client/history/use-history.js +6 -0
- package/dist/client/history/use-history.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/review/index.d.ts +1 -1
- package/dist/client/review/index.d.ts.map +1 -1
- package/dist/client/review/index.js +1 -1
- package/dist/client/review/index.js.map +1 -1
- package/dist/client/review/use-review.d.ts +23 -0
- package/dist/client/review/use-review.d.ts.map +1 -1
- package/dist/client/review/use-review.js +8 -0
- package/dist/client/review/use-review.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/history/actions/create-resource-version.js +7 -4
- package/dist/history/actions/create-resource-version.js.map +1 -1
- package/dist/history/index.d.ts +1 -1
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +1 -1
- package/dist/history/index.js.map +1 -1
- package/dist/history/registry.d.ts.map +1 -1
- package/dist/history/registry.js +14 -12
- package/dist/history/registry.js.map +1 -1
- package/dist/history/store.d.ts.map +1 -1
- package/dist/history/store.js +74 -49
- package/dist/history/store.js.map +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/review/actions/consume-review-feedback.d.ts +1 -0
- package/dist/review/actions/consume-review-feedback.js +8 -2
- package/dist/review/actions/consume-review-feedback.js.map +1 -1
- package/dist/review/actions/delete-review-comment.d.ts +2 -1
- package/dist/review/actions/delete-review-comment.js +11 -3
- package/dist/review/actions/delete-review-comment.js.map +1 -1
- package/dist/review/actions/resolve-review-thread.d.ts +2 -1
- package/dist/review/actions/resolve-review-thread.js +5 -2
- package/dist/review/actions/resolve-review-thread.js.map +1 -1
- package/dist/review/index.d.ts +1 -1
- package/dist/review/index.d.ts.map +1 -1
- package/dist/review/index.js +1 -1
- package/dist/review/index.js.map +1 -1
- package/dist/review/registry.d.ts.map +1 -1
- package/dist/review/registry.js +14 -12
- package/dist/review/registry.js.map +1 -1
- package/dist/review/store.d.ts +3 -3
- package/dist/review/store.d.ts.map +1 -1
- package/dist/review/store.js +7 -4
- package/dist/review/store.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +5 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +2 -0
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +13 -3
- package/dist/server/credential-provider.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,11 +23,21 @@ export default defineAction({
|
|
|
23
23
|
actionCtx,
|
|
24
24
|
"editor",
|
|
25
25
|
);
|
|
26
|
-
await consumeReviewFeedback(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
const updatedCount = await consumeReviewFeedback(
|
|
27
|
+
args.commentIds,
|
|
28
|
+
undefined,
|
|
29
|
+
{
|
|
30
|
+
resourceType: args.resourceType,
|
|
31
|
+
resourceId: args.resourceId,
|
|
32
|
+
},
|
|
33
|
+
);
|
|
34
|
+
if (updatedCount < 1) {
|
|
35
|
+
throw new Error("No matching review comments to consume");
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
consumedCommentIds: args.commentIds,
|
|
39
|
+
updatedCount,
|
|
40
|
+
};
|
|
31
41
|
},
|
|
32
42
|
audit: {
|
|
33
43
|
target: (args) => ({
|
|
@@ -39,12 +39,19 @@ export default defineAction({
|
|
|
39
39
|
}
|
|
40
40
|
const isAuthor =
|
|
41
41
|
Boolean(actionCtx?.userEmail) &&
|
|
42
|
-
comment.authorEmail ===
|
|
42
|
+
normalizeEmail(comment.authorEmail) ===
|
|
43
|
+
normalizeEmail(actionCtx?.userEmail);
|
|
43
44
|
if (!isAuthor && (!access || !roleSatisfies(access.role, "editor"))) {
|
|
44
45
|
throw new ForbiddenError("Not allowed to delete this review comment");
|
|
45
46
|
}
|
|
46
|
-
await deleteReviewComment(
|
|
47
|
-
|
|
47
|
+
const updatedCount = await deleteReviewComment(
|
|
48
|
+
comment.id,
|
|
49
|
+
actionCtx?.userEmail ?? null,
|
|
50
|
+
);
|
|
51
|
+
if (updatedCount < 1) {
|
|
52
|
+
throw new Error("Review comment not found");
|
|
53
|
+
}
|
|
54
|
+
return { commentId: comment.id, deleted: true as const, updatedCount };
|
|
48
55
|
},
|
|
49
56
|
audit: {
|
|
50
57
|
target: (args) => ({
|
|
@@ -53,3 +60,8 @@ export default defineAction({
|
|
|
53
60
|
}),
|
|
54
61
|
},
|
|
55
62
|
});
|
|
63
|
+
|
|
64
|
+
function normalizeEmail(email: string | null | undefined): string | null {
|
|
65
|
+
const normalized = email?.trim().toLowerCase();
|
|
66
|
+
return normalized || null;
|
|
67
|
+
}
|
|
@@ -45,11 +45,18 @@ export default defineAction({
|
|
|
45
45
|
if (!threadId) {
|
|
46
46
|
throw new Error("Provide threadId or commentId");
|
|
47
47
|
}
|
|
48
|
-
await resolveReviewThread(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
const updatedCount = await resolveReviewThread(
|
|
49
|
+
threadId,
|
|
50
|
+
actionCtx?.userEmail ?? null,
|
|
51
|
+
{
|
|
52
|
+
resourceType: args.resourceType,
|
|
53
|
+
resourceId: args.resourceId,
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
if (updatedCount < 1) {
|
|
57
|
+
throw new Error("Review thread not found");
|
|
58
|
+
}
|
|
59
|
+
return { threadId, resolved: true as const, updatedCount };
|
|
53
60
|
},
|
|
54
61
|
audit: {
|
|
55
62
|
target: (args) => ({
|
|
@@ -24,13 +24,8 @@ export {
|
|
|
24
24
|
} from "./registry.js";
|
|
25
25
|
export {
|
|
26
26
|
__resetReviewInitForTests,
|
|
27
|
-
consumeReviewFeedback,
|
|
28
|
-
deleteReviewComment,
|
|
29
27
|
ensureReviewTables,
|
|
30
28
|
getReviewCommentById,
|
|
31
29
|
getReviewStatus,
|
|
32
|
-
insertReviewComment,
|
|
33
30
|
queryReviewComments,
|
|
34
|
-
resolveReviewThread,
|
|
35
|
-
upsertReviewStatus,
|
|
36
31
|
} from "./store.js";
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ForbiddenError,
|
|
3
|
+
resolveAccess,
|
|
4
|
+
type AccessContext,
|
|
5
|
+
} from "../sharing/access.js";
|
|
2
6
|
import { getShareableResource } from "../sharing/registry.js";
|
|
3
7
|
import { roleSatisfies, type Visibility } from "../sharing/schema.js";
|
|
4
8
|
import type {
|
|
@@ -31,6 +35,16 @@ export function listReviewableResources(): ReviewableResourceRegistration[] {
|
|
|
31
35
|
return Array.from(registrations.values());
|
|
32
36
|
}
|
|
33
37
|
|
|
38
|
+
function accessContextFrom(
|
|
39
|
+
ctx?: ReviewResourceContext,
|
|
40
|
+
): AccessContext | undefined {
|
|
41
|
+
if (!ctx) return undefined;
|
|
42
|
+
return {
|
|
43
|
+
userEmail: ctx.userEmail ?? undefined,
|
|
44
|
+
orgId: ctx.orgId ?? undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
export async function resolveReviewableResourceAccess(
|
|
35
49
|
resourceType: string,
|
|
36
50
|
resourceId: string,
|
|
@@ -42,7 +56,11 @@ export async function resolveReviewableResourceAccess(
|
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
if (getShareableResource(resourceType)) {
|
|
45
|
-
const access = await resolveAccess(
|
|
59
|
+
const access = await resolveAccess(
|
|
60
|
+
resourceType,
|
|
61
|
+
resourceId,
|
|
62
|
+
accessContextFrom(ctx),
|
|
63
|
+
);
|
|
46
64
|
if (!access) {
|
|
47
65
|
return null;
|
|
48
66
|
}
|
|
@@ -55,16 +73,10 @@ export async function resolveReviewableResourceAccess(
|
|
|
55
73
|
};
|
|
56
74
|
}
|
|
57
75
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
role: "owner",
|
|
64
|
-
ownerEmail: userEmail,
|
|
65
|
-
orgId: ctx?.orgId ?? null,
|
|
66
|
-
visibility: "private",
|
|
67
|
-
};
|
|
76
|
+
// Fail closed: unregistered types, and registered types without an access
|
|
77
|
+
// resolver that aren't shareable, never invent ownership. bypassScope on
|
|
78
|
+
// review queries is only safe after a real resource ACL.
|
|
79
|
+
return null;
|
|
68
80
|
}
|
|
69
81
|
|
|
70
82
|
export async function assertReviewableResourceAccess(
|
|
@@ -310,13 +310,13 @@ export async function resolveReviewThread(
|
|
|
310
310
|
threadId: string,
|
|
311
311
|
resolvedBy?: string | null,
|
|
312
312
|
resource?: { resourceType: string; resourceId: string },
|
|
313
|
-
): Promise<
|
|
313
|
+
): Promise<number> {
|
|
314
314
|
await ensureReviewTables();
|
|
315
315
|
const now = new Date().toISOString();
|
|
316
316
|
const resourceClause = resource
|
|
317
317
|
? "AND resource_type = ? AND resource_id = ?"
|
|
318
318
|
: "";
|
|
319
|
-
await getDbExec().execute({
|
|
319
|
+
const result = await getDbExec().execute({
|
|
320
320
|
sql: `UPDATE agent_review_comments
|
|
321
321
|
SET status = 'resolved',
|
|
322
322
|
resolved_by = ?,
|
|
@@ -331,15 +331,16 @@ export async function resolveReviewThread(
|
|
|
331
331
|
...(resource ? [resource.resourceType, resource.resourceId] : []),
|
|
332
332
|
],
|
|
333
333
|
});
|
|
334
|
+
return result.rowsAffected ?? 0;
|
|
334
335
|
}
|
|
335
336
|
|
|
336
337
|
export async function deleteReviewComment(
|
|
337
338
|
id: string,
|
|
338
339
|
deletedBy?: string | null,
|
|
339
|
-
): Promise<
|
|
340
|
+
): Promise<number> {
|
|
340
341
|
await ensureReviewTables();
|
|
341
342
|
const now = new Date().toISOString();
|
|
342
|
-
await getDbExec().execute({
|
|
343
|
+
const result = await getDbExec().execute({
|
|
343
344
|
sql: `UPDATE agent_review_comments
|
|
344
345
|
SET status = 'deleted',
|
|
345
346
|
deleted_by = ?,
|
|
@@ -348,22 +349,23 @@ export async function deleteReviewComment(
|
|
|
348
349
|
WHERE id = ?`,
|
|
349
350
|
args: [deletedBy ?? null, now, now, id],
|
|
350
351
|
});
|
|
352
|
+
return result.rowsAffected ?? 0;
|
|
351
353
|
}
|
|
352
354
|
|
|
353
355
|
export async function consumeReviewFeedback(
|
|
354
356
|
ids: string[],
|
|
355
357
|
consumedAt = new Date().toISOString(),
|
|
356
358
|
resource?: { resourceType: string; resourceId: string },
|
|
357
|
-
): Promise<
|
|
359
|
+
): Promise<number> {
|
|
358
360
|
if (!ids.length) {
|
|
359
|
-
return;
|
|
361
|
+
return 0;
|
|
360
362
|
}
|
|
361
363
|
await ensureReviewTables();
|
|
362
364
|
const placeholders = ids.map(() => "?").join(", ");
|
|
363
365
|
const resourceClause = resource
|
|
364
366
|
? "AND resource_type = ? AND resource_id = ?"
|
|
365
367
|
: "";
|
|
366
|
-
await getDbExec().execute({
|
|
368
|
+
const result = await getDbExec().execute({
|
|
367
369
|
sql: `UPDATE agent_review_comments
|
|
368
370
|
SET consumed_at = ?,
|
|
369
371
|
updated_at = ?
|
|
@@ -375,6 +377,7 @@ export async function consumeReviewFeedback(
|
|
|
375
377
|
...(resource ? [resource.resourceType, resource.resourceId] : []),
|
|
376
378
|
],
|
|
377
379
|
});
|
|
380
|
+
return result.rowsAffected ?? 0;
|
|
378
381
|
}
|
|
379
382
|
|
|
380
383
|
export async function upsertReviewStatus(
|
|
@@ -6623,6 +6623,12 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6623
6623
|
scope: "user",
|
|
6624
6624
|
scopeId: ownerEmail,
|
|
6625
6625
|
});
|
|
6626
|
+
const { clearProviderCredentialAuthFailure } =
|
|
6627
|
+
await import("./credential-provider.js");
|
|
6628
|
+
await clearProviderCredentialAuthFailure({
|
|
6629
|
+
key: secretKey,
|
|
6630
|
+
value: trimmedKey,
|
|
6631
|
+
});
|
|
6626
6632
|
} catch (err) {
|
|
6627
6633
|
console.error(
|
|
6628
6634
|
"[agent-chat] save-key persistence failed:",
|
|
@@ -721,6 +721,8 @@ export async function clearBuilderCredentialAuthFailure(creds: {
|
|
|
721
721
|
}
|
|
722
722
|
|
|
723
723
|
const PROVIDER_AUTH_FAILURE_SETTING_PREFIX = "provider-auth-failure:";
|
|
724
|
+
/** Stale failure markers expire so a transient 401 cannot permanently block deploy keys. */
|
|
725
|
+
export const PROVIDER_AUTH_FAILURE_TTL_MS = 15 * 60 * 1000;
|
|
724
726
|
|
|
725
727
|
export interface ProviderCredentialAuthFailure {
|
|
726
728
|
fingerprint: string;
|
|
@@ -760,10 +762,18 @@ export async function getProviderCredentialAuthFailure(opts: {
|
|
|
760
762
|
const fingerprint = providerCredentialFingerprint(key, opts.value);
|
|
761
763
|
if (!fingerprint) return null;
|
|
762
764
|
try {
|
|
763
|
-
const
|
|
764
|
-
const
|
|
765
|
+
const settings = await import("../settings/store.js");
|
|
766
|
+
const settingKey = providerAuthFailureSettingKey(fingerprint);
|
|
767
|
+
const row = await settings.getSetting(settingKey);
|
|
765
768
|
if (!row) return null;
|
|
766
769
|
if (row.fingerprint !== fingerprint) return null;
|
|
770
|
+
const at = typeof row.at === "number" ? row.at : Date.now();
|
|
771
|
+
if (Date.now() - at > PROVIDER_AUTH_FAILURE_TTL_MS) {
|
|
772
|
+
if (typeof settings.deleteSetting === "function") {
|
|
773
|
+
await settings.deleteSetting(settingKey).catch(() => {});
|
|
774
|
+
}
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
767
777
|
return {
|
|
768
778
|
fingerprint,
|
|
769
779
|
key:
|
|
@@ -776,7 +786,7 @@ export async function getProviderCredentialAuthFailure(opts: {
|
|
|
776
786
|
: "The model provider rejected the saved API key.",
|
|
777
787
|
status: typeof row.status === "number" ? row.status : undefined,
|
|
778
788
|
code: typeof row.code === "string" ? row.code : undefined,
|
|
779
|
-
at
|
|
789
|
+
at,
|
|
780
790
|
ownerEmail:
|
|
781
791
|
typeof row.ownerEmail === "string" ? row.ownerEmail : undefined,
|
|
782
792
|
orgId: typeof row.orgId === "string" ? row.orgId : undefined,
|
|
@@ -25,8 +25,11 @@ export async function assertPresetSkeletonAssetsValid(input: {
|
|
|
25
25
|
skeleton.mask?.type === "asset" && typeof skeleton.mask.assetId === "string"
|
|
26
26
|
? skeleton.mask.assetId
|
|
27
27
|
: "";
|
|
28
|
-
if (!backgroundAssetId
|
|
28
|
+
if (!backgroundAssetId) return;
|
|
29
29
|
|
|
30
|
+
const assetIds = maskAssetId
|
|
31
|
+
? [backgroundAssetId, maskAssetId]
|
|
32
|
+
: [backgroundAssetId];
|
|
30
33
|
const rows = await input.db
|
|
31
34
|
.select({
|
|
32
35
|
id: schema.assets.id,
|
|
@@ -35,18 +38,15 @@ export async function assertPresetSkeletonAssetsValid(input: {
|
|
|
35
38
|
height: schema.assets.height,
|
|
36
39
|
})
|
|
37
40
|
.from(schema.assets)
|
|
38
|
-
.where(inArray(schema.assets.id,
|
|
41
|
+
.where(inArray(schema.assets.id, assetIds));
|
|
39
42
|
const background = rows.find((asset: any) => asset.id === backgroundAssetId);
|
|
43
|
+
if (!background || background.libraryId !== input.libraryId) {
|
|
44
|
+
throw new Error("Skeleton image must belong to this asset library.");
|
|
45
|
+
}
|
|
46
|
+
if (!maskAssetId) return;
|
|
40
47
|
const mask = rows.find((asset: any) => asset.id === maskAssetId);
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
!mask ||
|
|
44
|
-
background.libraryId !== input.libraryId ||
|
|
45
|
-
mask.libraryId !== input.libraryId
|
|
46
|
-
) {
|
|
47
|
-
throw new Error(
|
|
48
|
-
"Skeleton image and mask must belong to this asset library.",
|
|
49
|
-
);
|
|
48
|
+
if (!mask || mask.libraryId !== input.libraryId) {
|
|
49
|
+
throw new Error("Skeleton mask must belong to this asset library.");
|
|
50
50
|
}
|
|
51
51
|
if (
|
|
52
52
|
typeof background.width !== "number" ||
|
|
@@ -30,9 +30,11 @@ import {
|
|
|
30
30
|
compositeLogo,
|
|
31
31
|
maskFromManualMaskAlpha,
|
|
32
32
|
maskFromPlateAlpha,
|
|
33
|
+
prepareGptImage2SkeletonInpaintImages,
|
|
33
34
|
} from "../server/lib/image-processing.js";
|
|
34
35
|
import { nowIso, parseJson, stringifyJson } from "../server/lib/json.js";
|
|
35
36
|
import {
|
|
37
|
+
aspectRatioValue,
|
|
36
38
|
clampCutoutAspectRatio,
|
|
37
39
|
normalizePresetSkeletonSpec,
|
|
38
40
|
skeletonUsesCanonicalLogo,
|
|
@@ -350,13 +352,21 @@ export default defineAction({
|
|
|
350
352
|
isSkeletonCutout &&
|
|
351
353
|
Boolean(skeletonAssets?.backgroundAsset) &&
|
|
352
354
|
resolvedModel === "gpt-image-2";
|
|
355
|
+
const skeletonInpaint = useSkeletonInpaint
|
|
356
|
+
? await inpaintReferencesForSkeleton(skeletonAssets)
|
|
357
|
+
: null;
|
|
353
358
|
const resolvedAspectRatio =
|
|
354
|
-
|
|
355
|
-
?
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
:
|
|
359
|
+
useSkeletonInpaint && skeletonInpaint
|
|
360
|
+
? closestSupportedAspectRatioForSize(
|
|
361
|
+
skeletonInpaint.size,
|
|
362
|
+
supportedAspectRatiosForModel("gpt-image-2"),
|
|
363
|
+
)
|
|
364
|
+
: isSkeletonCutout
|
|
365
|
+
? clampCutoutAspectRatio({
|
|
366
|
+
aspectRatio: outputAspectRatio,
|
|
367
|
+
supported: supportedAspectRatiosForModel("gpt-image-1"),
|
|
368
|
+
})
|
|
369
|
+
: outputAspectRatio;
|
|
360
370
|
if (
|
|
361
371
|
isSkeletonCutout &&
|
|
362
372
|
!useSkeletonInpaint &&
|
|
@@ -386,7 +396,7 @@ export default defineAction({
|
|
|
386
396
|
: "";
|
|
387
397
|
let references: ReferenceForGeneration[];
|
|
388
398
|
if (useSkeletonInpaint) {
|
|
389
|
-
references =
|
|
399
|
+
references = skeletonInpaint?.references ?? [];
|
|
390
400
|
} else {
|
|
391
401
|
const backgroundPlateReference =
|
|
392
402
|
backgroundPlateReferenceForSkeleton(skeletonAssets);
|
|
@@ -839,7 +849,10 @@ function backgroundPlateReferenceForSkeleton(
|
|
|
839
849
|
|
|
840
850
|
async function inpaintReferencesForSkeleton(
|
|
841
851
|
skeletonAssets: LoadedSkeletonAssets | null,
|
|
842
|
-
): Promise<
|
|
852
|
+
): Promise<{
|
|
853
|
+
references: ReferenceForGeneration[];
|
|
854
|
+
size: { width: number; height: number };
|
|
855
|
+
}> {
|
|
843
856
|
if (
|
|
844
857
|
!skeletonAssets?.backgroundAsset ||
|
|
845
858
|
!skeletonAssets.backgroundAssetId ||
|
|
@@ -853,26 +866,49 @@ async function inpaintReferencesForSkeleton(
|
|
|
853
866
|
plate: skeletonAssets.backgroundAsset,
|
|
854
867
|
})
|
|
855
868
|
: await maskFromPlateAlpha(skeletonAssets.backgroundAsset);
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
869
|
+
const prepared = await prepareGptImage2SkeletonInpaintImages({
|
|
870
|
+
plate: skeletonAssets.backgroundAsset,
|
|
871
|
+
mask,
|
|
872
|
+
});
|
|
873
|
+
return {
|
|
874
|
+
size: prepared.size,
|
|
875
|
+
references: [
|
|
876
|
+
{
|
|
877
|
+
id: skeletonAssets.backgroundAssetId,
|
|
878
|
+
role: "edit_target",
|
|
879
|
+
category: "skeleton",
|
|
880
|
+
mimeType: prepared.resized
|
|
881
|
+
? "image/png"
|
|
882
|
+
: skeletonAssets.backgroundMimeType,
|
|
883
|
+
data: prepared.plate.toString("base64"),
|
|
884
|
+
selectionReason: "explicit",
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
id:
|
|
888
|
+
skeletonAssets.maskAssetId ??
|
|
889
|
+
`${skeletonAssets.backgroundAssetId}:mask`,
|
|
890
|
+
role: "mask",
|
|
891
|
+
category: "skeleton",
|
|
892
|
+
mimeType: "image/png",
|
|
893
|
+
data: prepared.mask.toString("base64"),
|
|
894
|
+
selectionReason: "explicit",
|
|
895
|
+
},
|
|
896
|
+
],
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
function closestSupportedAspectRatioForSize(
|
|
901
|
+
size: { width: number; height: number },
|
|
902
|
+
supported: readonly AspectRatio[],
|
|
903
|
+
): AspectRatio {
|
|
904
|
+
const target = size.width / size.height;
|
|
905
|
+
return (
|
|
906
|
+
[...supported].sort(
|
|
907
|
+
(left, right) =>
|
|
908
|
+
Math.abs(aspectRatioValue(left) - target) -
|
|
909
|
+
Math.abs(aspectRatioValue(right) - target),
|
|
910
|
+
)[0] ?? "1:1"
|
|
911
|
+
);
|
|
876
912
|
}
|
|
877
913
|
|
|
878
914
|
type LoadedSkeletonAssets = {
|
|
@@ -44,7 +44,7 @@ function variantStateKey(threadId: string | null) {
|
|
|
44
44
|
// STALE_IMAGE_RUN_MS in refresh-generation-run, so a slow-but-healthy run (e.g.
|
|
45
45
|
// gpt-image-2) is not flagged "interrupted" and flipped to an error slot before
|
|
46
46
|
// its finished image arrives.
|
|
47
|
-
const STALE_PENDING_RUN_MS =
|
|
47
|
+
const STALE_PENDING_RUN_MS = 10 * 60 * 1000;
|
|
48
48
|
|
|
49
49
|
function slotTime(slot: AssetVariantState["slots"][number]): number {
|
|
50
50
|
const raw = slot.createdAt ?? slot.updatedAt ?? "";
|