@agent-native/core 0.182.1 → 0.182.2-nightly-20260917210345
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 +1 -1
- package/corpus/templates/clips/app/root.tsx +59 -10
- package/corpus/templates/clips/changelog/2026-09-17-desktop-popover-closes-when-clicking-away.md +6 -0
- package/corpus/templates/clips/changelog/2026-09-17-self-hosted-extension-sign-in.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +45 -25
- package/corpus/templates/clips/chrome-extension/src/content-script.ts +43 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +55 -6
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +1 -0
- package/corpus/templates/design/actions/add-localhost-screens.ts +54 -22
- package/corpus/templates/design/actions/apply-visual-edit.ts +1 -0
- package/corpus/templates/design/actions/create-design-from-template.ts +50 -35
- package/corpus/templates/design/actions/create-design-version.ts +21 -0
- package/corpus/templates/design/actions/create-file.ts +35 -33
- package/corpus/templates/design/actions/delete-design.ts +29 -28
- package/corpus/templates/design/actions/delete-file.ts +154 -23
- package/corpus/templates/design/actions/generate-design.ts +28 -16
- package/corpus/templates/design/actions/get-component-details.ts +187 -33
- package/corpus/templates/design/actions/get-design-version.ts +9 -1
- package/corpus/templates/design/actions/go-to-main-component.ts +37 -35
- package/corpus/templates/design/actions/index-components.ts +241 -126
- package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +12 -9
- package/corpus/templates/design/actions/present-design-variants.ts +68 -72
- package/corpus/templates/design/actions/rename-component.ts +294 -0
- package/corpus/templates/design/actions/rename-screen.ts +10 -10
- package/corpus/templates/design/actions/update-file.ts +327 -330
- package/corpus/templates/design/actions/update-screen-source.ts +2 -43
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +8 -1
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +55 -33
- package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/inline-provider.ts +4 -2
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +5 -1
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +57 -9
- package/corpus/templates/design/app/components/design/types.ts +1 -0
- package/corpus/templates/design/app/hooks/use-design-versions.ts +3 -2
- package/corpus/templates/design/app/i18n-breakpoints.ts +0 -110
- package/corpus/templates/design/app/i18n-data.ts +0 -10
- package/corpus/templates/design/app/pages/DesignEditor.tsx +250 -107
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +2 -0
- package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +69 -47
- package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +8 -1
- package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +107 -2
- package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +26 -1
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +63 -2
- package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +74 -22
- package/corpus/templates/design/app/pages/design-editor/source-publication.ts +14 -2
- package/corpus/templates/design/changelog/2026-09-16-design-components-retain-linked-identities-when-edited-and-d.md +6 -0
- package/corpus/templates/design/changelog/2026-09-17-screen-deletion-is-immediate-and-undoable-with-history-that-.md +6 -0
- package/corpus/templates/design/e2e/fixtures/design-component-react/index.html +98 -0
- package/corpus/templates/design/e2e/fixtures/design-component-react/inline-component.html +65 -0
- package/corpus/templates/design/server/lib/design-data-mutation.ts +9 -5
- package/corpus/templates/design/server/lib/design-snapshot.ts +28 -16
- package/corpus/templates/design/server/lib/design-versions.ts +208 -130
- package/corpus/templates/design/server/lib/fusion-screens.ts +46 -20
- package/corpus/templates/design/server/lib/import-design-files.ts +5 -1
- package/corpus/templates/design/server/lib/localhost-connection.ts +54 -0
- package/corpus/templates/design/server/source-workspace.ts +412 -356
- package/corpus/templates/design/shared/component-library.ts +36 -6
- package/corpus/templates/design/shared/component-model.ts +8 -2
- package/dist/automation/index.d.ts +1 -1
- package/dist/client/chat/agentkit-protocol.js +148 -34
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/package.json +4 -4
- package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +0 -66
|
@@ -8,6 +8,7 @@ import { z } from "zod";
|
|
|
8
8
|
import { getDb, schema } from "../server/db/index.js";
|
|
9
9
|
import { mutateDesignData } from "../server/lib/design-data-mutation.js";
|
|
10
10
|
import { snapshotDesignBeforeAgentEdit } from "../server/lib/design-versions.js";
|
|
11
|
+
import { withDesignSourceMutationTransaction } from "../server/source-workspace.js";
|
|
11
12
|
import {
|
|
12
13
|
mergeCanvasFramePlacements,
|
|
13
14
|
nextFreeCanvasRowY,
|
|
@@ -55,26 +56,6 @@ export default defineAction({
|
|
|
55
56
|
await assertAccess("design", designId, "editor");
|
|
56
57
|
await snapshotDesignBeforeAgentEdit(designId, context);
|
|
57
58
|
|
|
58
|
-
const db = getDb();
|
|
59
|
-
|
|
60
|
-
// Guard against duplicate (designId, filename) — edit-design uses .limit(1)
|
|
61
|
-
// which is non-deterministic when multiple rows match the same key.
|
|
62
|
-
const [existing] = await db
|
|
63
|
-
.select({ id: schema.designFiles.id })
|
|
64
|
-
.from(schema.designFiles)
|
|
65
|
-
.where(
|
|
66
|
-
and(
|
|
67
|
-
eq(schema.designFiles.designId, designId),
|
|
68
|
-
eq(schema.designFiles.filename, filename),
|
|
69
|
-
),
|
|
70
|
-
)
|
|
71
|
-
.limit(1);
|
|
72
|
-
if (existing) {
|
|
73
|
-
throw new Error(
|
|
74
|
-
`File "${filename}" already exists in design ${designId} — use edit-design to modify it`,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
59
|
const id = nanoid();
|
|
79
60
|
const now = new Date().toISOString();
|
|
80
61
|
|
|
@@ -92,24 +73,45 @@ export default defineAction({
|
|
|
92
73
|
filename,
|
|
93
74
|
});
|
|
94
75
|
|
|
95
|
-
await
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
76
|
+
await withDesignSourceMutationTransaction(designId, async (tx) => {
|
|
77
|
+
// Guard against duplicate (designId, filename) inside the same
|
|
78
|
+
// transaction as the insert; the unique index remains the final guard.
|
|
79
|
+
const [existing] = await tx
|
|
80
|
+
.select({ id: schema.designFiles.id })
|
|
81
|
+
.from(schema.designFiles)
|
|
82
|
+
.where(
|
|
83
|
+
and(
|
|
84
|
+
eq(schema.designFiles.designId, designId),
|
|
85
|
+
eq(schema.designFiles.filename, filename),
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
.limit(1);
|
|
89
|
+
if (existing) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`File "${filename}" already exists in design ${designId} — use edit-design to modify it`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
await tx.insert(schema.designFiles).values({
|
|
96
|
+
id,
|
|
97
|
+
designId,
|
|
98
|
+
filename,
|
|
99
|
+
fileType: fileType ?? "html",
|
|
100
|
+
content: annotatedContent,
|
|
101
|
+
createdAt: now,
|
|
102
|
+
updatedAt: now,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await tx
|
|
106
|
+
.update(schema.designs)
|
|
107
|
+
.set({ updatedAt: now })
|
|
108
|
+
.where(eq(schema.designs.id, designId));
|
|
103
109
|
});
|
|
104
110
|
|
|
105
111
|
// Seed collab state for the new file
|
|
106
112
|
await seedFromText(id, annotatedContent);
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
await db
|
|
110
|
-
.update(schema.designs)
|
|
111
|
-
.set({ updatedAt: now })
|
|
112
|
-
.where(eq(schema.designs.id, designId));
|
|
114
|
+
const db = getDb();
|
|
113
115
|
|
|
114
116
|
const resolvedFileType = fileType ?? "html";
|
|
115
117
|
const renderable =
|
|
@@ -3,7 +3,8 @@ import { assertAccess } from "@agent-native/core/sharing";
|
|
|
3
3
|
import { eq } from "drizzle-orm";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { schema } from "../server/db/index.js";
|
|
7
|
+
import { withDesignSourceMutationTransaction } from "../server/source-workspace.js";
|
|
7
8
|
|
|
8
9
|
export default defineAction({
|
|
9
10
|
description:
|
|
@@ -14,40 +15,40 @@ export default defineAction({
|
|
|
14
15
|
run: async ({ id }) => {
|
|
15
16
|
await assertAccess("design", id, "admin");
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
await withDesignSourceMutationTransaction(id, async (tx) => {
|
|
19
|
+
await tx
|
|
20
|
+
.delete(schema.designShares)
|
|
21
|
+
.where(eq(schema.designShares.resourceId, id));
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
await tx
|
|
24
|
+
.delete(schema.componentIndex)
|
|
25
|
+
.where(eq(schema.componentIndex.designId, id));
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
await tx
|
|
28
|
+
.delete(schema.motionTimeline)
|
|
29
|
+
.where(eq(schema.motionTimeline.designId, id));
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
await tx
|
|
32
|
+
.delete(schema.designState)
|
|
33
|
+
.where(eq(schema.designState.designId, id));
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
await tx
|
|
36
|
+
.delete(schema.designReviewSnapshot)
|
|
37
|
+
.where(eq(schema.designReviewSnapshot.designId, id));
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
// Delete associated files first
|
|
40
|
+
await tx
|
|
41
|
+
.delete(schema.designFiles)
|
|
42
|
+
.where(eq(schema.designFiles.designId, id));
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
// Delete associated versions
|
|
45
|
+
await tx
|
|
46
|
+
.delete(schema.designVersions)
|
|
47
|
+
.where(eq(schema.designVersions.designId, id));
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
.where(eq(schema.designVersions.designId, id));
|
|
48
|
-
|
|
49
|
-
// Delete the design itself
|
|
50
|
-
await db.delete(schema.designs).where(eq(schema.designs.id, id));
|
|
49
|
+
// Delete the design itself
|
|
50
|
+
await tx.delete(schema.designs).where(eq(schema.designs.id, id));
|
|
51
|
+
});
|
|
51
52
|
|
|
52
53
|
return { id, deleted: true };
|
|
53
54
|
},
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core/action";
|
|
2
2
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
3
|
-
import { and, eq } from "drizzle-orm";
|
|
3
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
snapshotDesignBeforeAgentEditInVersionLock,
|
|
9
|
+
withDesignVersionLock,
|
|
10
|
+
} from "../server/lib/design-versions.js";
|
|
11
|
+
import {
|
|
12
|
+
affectedRowCount,
|
|
13
|
+
designSourceMutationLockKey,
|
|
14
|
+
lockDesignFilesTable,
|
|
15
|
+
} from "../server/source-workspace.js";
|
|
16
|
+
import { isOverviewScreenFile } from "../shared/design-files.js";
|
|
9
17
|
import { countLockedLayers } from "../shared/locked-layers.js";
|
|
10
18
|
|
|
11
19
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
@@ -61,6 +69,27 @@ function pruneDeletedFileMetadata(
|
|
|
61
69
|
};
|
|
62
70
|
}
|
|
63
71
|
|
|
72
|
+
function nextUpdatedAt(current: string | null, now: Date): string {
|
|
73
|
+
const currentMs = current ? Date.parse(current) : Number.NaN;
|
|
74
|
+
return new Date(
|
|
75
|
+
Math.max(now.getTime(), Number.isFinite(currentMs) ? currentMs + 1 : 0),
|
|
76
|
+
).toISOString();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function parseDesignData(
|
|
80
|
+
designId: string,
|
|
81
|
+
serialized: string | null,
|
|
82
|
+
): Record<string, unknown> {
|
|
83
|
+
if (serialized === null) return {};
|
|
84
|
+
try {
|
|
85
|
+
const parsed: unknown = JSON.parse(serialized);
|
|
86
|
+
if (isRecord(parsed)) return parsed;
|
|
87
|
+
} catch {
|
|
88
|
+
throw new Error(`Design "${designId}" has invalid data JSON.`);
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`Design "${designId}" has invalid data JSON.`);
|
|
91
|
+
}
|
|
92
|
+
|
|
64
93
|
export default defineAction({
|
|
65
94
|
description:
|
|
66
95
|
"Delete a file from a design project. Idempotent: if the file is already gone, returns deleted=false so cleanup retries can continue. Validates ownership via the parent design's access when the file exists.",
|
|
@@ -73,8 +102,14 @@ export default defineAction({
|
|
|
73
102
|
.describe(
|
|
74
103
|
"Delete the screen even though it holds locked layers. Only set this when the user explicitly asked for that screen to go.",
|
|
75
104
|
),
|
|
105
|
+
historyCheckpointId: z
|
|
106
|
+
.string()
|
|
107
|
+
.optional()
|
|
108
|
+
.describe(
|
|
109
|
+
"Existing frontend editor checkpoint to reuse for one grouped screen deletion.",
|
|
110
|
+
),
|
|
76
111
|
}),
|
|
77
|
-
run: async ({ id, allowLockedLayers }, context) => {
|
|
112
|
+
run: async ({ id, allowLockedLayers, historyCheckpointId }, context) => {
|
|
78
113
|
const db = getDb();
|
|
79
114
|
|
|
80
115
|
// Look up the file to get its designId for access check
|
|
@@ -82,6 +117,8 @@ export default defineAction({
|
|
|
82
117
|
.select({
|
|
83
118
|
id: schema.designFiles.id,
|
|
84
119
|
designId: schema.designFiles.designId,
|
|
120
|
+
filename: schema.designFiles.filename,
|
|
121
|
+
fileType: schema.designFiles.fileType,
|
|
85
122
|
content: schema.designFiles.content,
|
|
86
123
|
})
|
|
87
124
|
.from(schema.designFiles)
|
|
@@ -100,7 +137,6 @@ export default defineAction({
|
|
|
100
137
|
if (!file) return { id, deleted: false, alreadyMissing: true };
|
|
101
138
|
|
|
102
139
|
await assertAccess("design", file.designId, "editor");
|
|
103
|
-
await snapshotDesignBeforeAgentEdit(file.designId, context);
|
|
104
140
|
// Locks exist to stop an agent destroying template branding in passing.
|
|
105
141
|
// A person deleting their own screen has already decided, and every
|
|
106
142
|
// template-backed screen carries locked layers — without this opt-in they
|
|
@@ -111,25 +147,120 @@ export default defineAction({
|
|
|
111
147
|
);
|
|
112
148
|
}
|
|
113
149
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
150
|
+
if (historyCheckpointId !== undefined) {
|
|
151
|
+
if (context?.caller !== "frontend") {
|
|
152
|
+
throw new Error(
|
|
153
|
+
"A reusable editor history checkpoint is only valid for frontend deletes.",
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const [checkpoint] = await db
|
|
157
|
+
.select({
|
|
158
|
+
id: schema.designVersions.id,
|
|
159
|
+
designId: schema.designVersions.designId,
|
|
160
|
+
})
|
|
161
|
+
.from(schema.designVersions)
|
|
162
|
+
.where(
|
|
163
|
+
and(
|
|
164
|
+
eq(schema.designVersions.id, historyCheckpointId),
|
|
165
|
+
eq(schema.designVersions.designId, file.designId),
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
.limit(1);
|
|
169
|
+
if (!checkpoint) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
"The editor history checkpoint is no longer available.",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Restore locks the same design and updates file rows before designs.data.
|
|
177
|
+
// Keep the checkpoint and mutation under the same table/version boundary so
|
|
178
|
+
// history cannot capture a state that interleaves with the delete.
|
|
179
|
+
const deleted = await withDesignVersionLock(file.designId, async () => {
|
|
180
|
+
return db.transaction(async (tx) => {
|
|
181
|
+
await tx.execute(
|
|
182
|
+
sql`SELECT pg_advisory_xact_lock(hashtextextended(${designSourceMutationLockKey(file.designId)}, 0::bigint))`,
|
|
183
|
+
);
|
|
184
|
+
await lockDesignFilesTable(tx);
|
|
185
|
+
const currentFiles = await tx
|
|
186
|
+
.select({
|
|
187
|
+
id: schema.designFiles.id,
|
|
188
|
+
filename: schema.designFiles.filename,
|
|
189
|
+
fileType: schema.designFiles.fileType,
|
|
190
|
+
})
|
|
191
|
+
.from(schema.designFiles)
|
|
192
|
+
.where(eq(schema.designFiles.designId, file.designId))
|
|
193
|
+
.for("update");
|
|
194
|
+
const currentFile = currentFiles.find(
|
|
195
|
+
(candidate) => candidate.id === id,
|
|
196
|
+
);
|
|
197
|
+
if (!currentFile) return false;
|
|
198
|
+
if (
|
|
199
|
+
isOverviewScreenFile(currentFile) &&
|
|
200
|
+
currentFiles.filter(isOverviewScreenFile).length <= 1
|
|
201
|
+
) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
"A design must keep at least one user screen. Delete another screen first.",
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
if (historyCheckpointId === undefined) {
|
|
207
|
+
await snapshotDesignBeforeAgentEditInVersionLock(
|
|
208
|
+
file.designId,
|
|
209
|
+
context,
|
|
210
|
+
tx,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
125
213
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
214
|
+
const deleteResult = await tx
|
|
215
|
+
.delete(schema.designFiles)
|
|
216
|
+
.where(
|
|
217
|
+
and(
|
|
218
|
+
eq(schema.designFiles.id, id),
|
|
219
|
+
eq(schema.designFiles.designId, file.designId),
|
|
220
|
+
),
|
|
221
|
+
);
|
|
222
|
+
const affected = affectedRowCount(deleteResult);
|
|
223
|
+
if (affected === 0) return false;
|
|
224
|
+
if (affected === undefined)
|
|
225
|
+
throw new Error("Could not verify that the design file was deleted.");
|
|
226
|
+
if (affected !== 1)
|
|
227
|
+
throw new Error("Unexpected design file delete result.");
|
|
228
|
+
|
|
229
|
+
const [design] = await tx
|
|
230
|
+
.select({
|
|
231
|
+
data: schema.designs.data,
|
|
232
|
+
updatedAt: schema.designs.updatedAt,
|
|
233
|
+
})
|
|
234
|
+
.from(schema.designs)
|
|
235
|
+
.where(eq(schema.designs.id, file.designId))
|
|
236
|
+
.for("update");
|
|
237
|
+
if (!design) throw new Error(`Design "${file.designId}" not found.`);
|
|
238
|
+
|
|
239
|
+
const updatedAt = nextUpdatedAt(design.updatedAt, new Date());
|
|
240
|
+
const data = pruneDeletedFileMetadata(
|
|
241
|
+
parseDesignData(file.designId, design.data),
|
|
242
|
+
id,
|
|
243
|
+
);
|
|
244
|
+
data.updatedAt = updatedAt;
|
|
245
|
+
const designUpdateResult = await tx
|
|
246
|
+
.update(schema.designs)
|
|
247
|
+
.set({ data: JSON.stringify(data), updatedAt })
|
|
248
|
+
.where(eq(schema.designs.id, file.designId));
|
|
249
|
+
const designAffected = affectedRowCount(designUpdateResult);
|
|
250
|
+
if (designAffected === undefined) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
"Could not verify that the design metadata was updated.",
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
if (designAffected !== 1) {
|
|
256
|
+
throw new Error("Unexpected design metadata update result.");
|
|
257
|
+
}
|
|
258
|
+
return true;
|
|
259
|
+
});
|
|
260
|
+
});
|
|
132
261
|
|
|
133
|
-
return
|
|
262
|
+
return deleted
|
|
263
|
+
? { id, deleted: true }
|
|
264
|
+
: { id, deleted: false, alreadyMissing: true };
|
|
134
265
|
},
|
|
135
266
|
});
|
|
@@ -34,6 +34,7 @@ import { snapshotDesignBeforeAgentEdit } from "../server/lib/design-versions.js"
|
|
|
34
34
|
import {
|
|
35
35
|
readLiveSourceFile,
|
|
36
36
|
SourceWorkspaceEditConflictError,
|
|
37
|
+
withDesignSourceMutationTransaction,
|
|
37
38
|
writeInlineSourceFile,
|
|
38
39
|
type SourceWorkspaceFile,
|
|
39
40
|
} from "../server/source-workspace.js";
|
|
@@ -910,10 +911,19 @@ const generateDesignAction = defineAction({
|
|
|
910
911
|
// html -> jsx), matching the original update behavior.
|
|
911
912
|
const nextFileType = file.fileType ?? "html";
|
|
912
913
|
if (nextFileType !== (existing.fileType ?? "html")) {
|
|
913
|
-
await
|
|
914
|
-
.
|
|
915
|
-
|
|
916
|
-
|
|
914
|
+
await withDesignSourceMutationTransaction(
|
|
915
|
+
existing.designId,
|
|
916
|
+
(tx) =>
|
|
917
|
+
tx
|
|
918
|
+
.update(schema.designFiles)
|
|
919
|
+
.set({ fileType: nextFileType, updatedAt: now })
|
|
920
|
+
.where(
|
|
921
|
+
and(
|
|
922
|
+
eq(schema.designFiles.id, existing.id),
|
|
923
|
+
eq(schema.designFiles.designId, existing.designId),
|
|
924
|
+
),
|
|
925
|
+
),
|
|
926
|
+
);
|
|
917
927
|
}
|
|
918
928
|
} finally {
|
|
919
929
|
agentLeaveDocument(existing.id);
|
|
@@ -956,18 +966,20 @@ const generateDesignAction = defineAction({
|
|
|
956
966
|
} else {
|
|
957
967
|
// Create new file
|
|
958
968
|
const fileId = nanoid();
|
|
959
|
-
await
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
969
|
+
await withDesignSourceMutationTransaction(designId, (tx) =>
|
|
970
|
+
tx.insert(schema.designFiles).values({
|
|
971
|
+
id: fileId,
|
|
972
|
+
designId,
|
|
973
|
+
filename: file.filename,
|
|
974
|
+
fileType: file.fileType ?? "html",
|
|
975
|
+
content: file.content,
|
|
976
|
+
contentOperationSource: null,
|
|
977
|
+
contentOperationRevision: null,
|
|
978
|
+
contentOperationResultHash: null,
|
|
979
|
+
createdAt: now,
|
|
980
|
+
updatedAt: now,
|
|
981
|
+
}),
|
|
982
|
+
);
|
|
971
983
|
|
|
972
984
|
// Publish agent presence for the new file before seeding.
|
|
973
985
|
agentEnterDocument(fileId);
|