@agent-native/core 0.114.12 → 0.114.13
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/core/CHANGELOG.md +6 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/application-state/index.ts +3 -0
- package/corpus/core/src/application-state/script-helpers.ts +12 -1
- package/corpus/core/src/application-state/store.ts +216 -15
- package/corpus/core/src/db/client.ts +44 -1
- package/corpus/templates/clips/changelog/2026-07-21-live-dictation-text-now-appears-above-the-desktop-recording-.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +14 -3
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +25 -0
- package/corpus/templates/clips/desktop/src/styles.css +20 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +3 -4
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +11 -4
- package/corpus/templates/design/AGENTS.md +7 -3
- package/corpus/templates/design/actions/begin-node-rewrite-request.ts +78 -0
- package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +17 -7
- package/corpus/templates/design/actions/propose-node-rewrite.ts +26 -18
- package/corpus/templates/design/actions/resolve-node-rewrite.ts +67 -19
- package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +1 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +2 -6
- package/corpus/templates/design/shared/node-rewrite.ts +32 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +6 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +11 -18
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +9 -5
- package/corpus/templates/slides/app/context/DeckContext.tsx +18 -0
- package/corpus/templates/slides/changelog/2026-07-21-decks-list-now-refreshes-when-you-switch-organizations.md +6 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldCreateBar.tsx +13 -19
- package/corpus/templates/tasks/app/components/custom-fields/FieldListRow.tsx +27 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsList.tsx +26 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsListSkeleton.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/FieldsPage.tsx +4 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldEditorSidebar.tsx +12 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldTitleSection.tsx +6 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/CurrencyConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/NumberConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/PercentConfigControl.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/SelectConfigControl.tsx +17 -7
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/select-colors.ts +37 -9
- package/corpus/templates/tasks/app/components/custom-fields/field-types.ts +23 -0
- package/corpus/templates/tasks/app/components/inbox/InboxList.tsx +24 -16
- package/corpus/templates/tasks/app/components/inbox/InboxListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/inbox/InboxListRow.tsx +7 -5
- package/corpus/templates/tasks/app/components/layout/Header.tsx +10 -10
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +11 -7
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +17 -10
- package/corpus/templates/tasks/app/components/shared/AddListItemInput.tsx +14 -8
- package/corpus/templates/tasks/app/components/shared/AlertDialog.tsx +6 -2
- package/corpus/templates/tasks/app/components/shared/BulkDeleteDialog.tsx +13 -6
- package/corpus/templates/tasks/app/components/shared/ChipSelect.tsx +12 -5
- package/corpus/templates/tasks/app/components/shared/DeleteItemDialog.tsx +6 -6
- package/corpus/templates/tasks/app/components/shared/ListViewHeader.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/SidePanel.tsx +5 -2
- package/corpus/templates/tasks/app/components/shared/list/ListRowDragHandle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionBar.tsx +46 -20
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionHeaderToggle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionToolbar.tsx +10 -6
- package/corpus/templates/tasks/app/components/tasks/TaskList.tsx +24 -13
- package/corpus/templates/tasks/app/components/tasks/TaskListHeaderRow.tsx +4 -1
- package/corpus/templates/tasks/app/components/tasks/TaskListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +15 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskFieldsSidebar.tsx +11 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskTitleSection.tsx +8 -3
- package/corpus/templates/tasks/app/components/tasks/fields/controls/RichTextValueControl.tsx +12 -6
- package/corpus/templates/tasks/app/components/tasks/fields/controls/SingleSelectValueControl.tsx +6 -1
- package/corpus/templates/tasks/app/i18n/en-US.ts +209 -0
- package/corpus/templates/tasks/app/i18n/index.ts +34 -0
- package/corpus/templates/tasks/app/root.tsx +34 -2
- package/corpus/templates/tasks/app/routes/extensions.$id.tsx +2 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -1
- package/corpus/templates/tasks/app/routes/fields.tsx +2 -1
- package/corpus/templates/tasks/app/routes/inbox.tsx +2 -1
- package/corpus/templates/tasks/app/routes/tasks.tsx +2 -1
- package/corpus/templates/tasks/app/routes/team.tsx +6 -3
- package/corpus/templates/tasks/changelog/2026-07-20-tasks-is-now-available-in-10-additional-languages.md +6 -0
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts +3 -1
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +7 -1
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/application-state/store.d.ts +7 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +143 -17
- package/dist/application-state/store.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +39 -1
- package/dist/db/client.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- 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
- package/src/application-state/index.ts +3 -0
- package/src/application-state/script-helpers.ts +12 -1
- package/src/application-state/store.ts +216 -15
- package/src/db/client.ts +44 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import {
|
|
3
|
+
compareAndSetAppState,
|
|
4
|
+
readAppState,
|
|
5
|
+
} from "@agent-native/core/application-state";
|
|
6
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
designRepromptPendingStateKey,
|
|
11
|
+
isNodeRewriteResolutionClaim,
|
|
12
|
+
isPendingDesignReprompt,
|
|
13
|
+
type PendingDesignReprompt,
|
|
14
|
+
} from "../shared/node-rewrite.js";
|
|
15
|
+
|
|
16
|
+
const targetSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
nodeId: z.string().min(1).optional(),
|
|
19
|
+
selector: z.string().min(1).optional(),
|
|
20
|
+
})
|
|
21
|
+
.refine((target) => target.nodeId || target.selector, {
|
|
22
|
+
message: "target.nodeId or target.selector is required",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default defineAction({
|
|
26
|
+
agentTool: false,
|
|
27
|
+
description:
|
|
28
|
+
"Atomically starts or supersedes one pending node rewrite unless its current proposal is being accepted.",
|
|
29
|
+
schema: z.object({
|
|
30
|
+
repromptId: z.string().min(1),
|
|
31
|
+
designId: z.string().min(1),
|
|
32
|
+
fileId: z.string().min(1),
|
|
33
|
+
target: targetSchema,
|
|
34
|
+
baseVersionHash: z.string().min(1),
|
|
35
|
+
instruction: z.string().trim().min(1),
|
|
36
|
+
createdAt: z.string().min(1),
|
|
37
|
+
priorProposalId: z.string().min(1).optional(),
|
|
38
|
+
priorRepromptId: z.string().min(1).optional(),
|
|
39
|
+
}),
|
|
40
|
+
run: async (request) => {
|
|
41
|
+
await assertAccess("design", request.designId, "editor");
|
|
42
|
+
const pendingKey = designRepromptPendingStateKey(
|
|
43
|
+
request.designId,
|
|
44
|
+
request.fileId,
|
|
45
|
+
);
|
|
46
|
+
const current = await readAppState(pendingKey);
|
|
47
|
+
if (isNodeRewriteResolutionClaim(current)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"This candidate is currently being accepted. Wait for it to finish before regenerating.",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (
|
|
53
|
+
request.priorRepromptId &&
|
|
54
|
+
(!isPendingDesignReprompt(current) ||
|
|
55
|
+
current.repromptId !== request.priorRepromptId)
|
|
56
|
+
) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"The candidates changed before refinement started. Review the latest candidates instead.",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const pending: PendingDesignReprompt = {
|
|
63
|
+
...request,
|
|
64
|
+
status: "pending",
|
|
65
|
+
};
|
|
66
|
+
const started = await compareAndSetAppState(
|
|
67
|
+
pendingKey,
|
|
68
|
+
current,
|
|
69
|
+
pending as unknown as Record<string, unknown>,
|
|
70
|
+
);
|
|
71
|
+
if (!started) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"The regeneration request changed concurrently. Try again with the latest candidates.",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return { started: true, repromptId: request.repromptId };
|
|
77
|
+
},
|
|
78
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
3
|
compareAndSetAppState,
|
|
4
|
+
compareAndSetManyAppState,
|
|
4
5
|
readAppState,
|
|
5
6
|
} from "@agent-native/core/application-state";
|
|
6
7
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
@@ -39,15 +40,24 @@ export default defineAction({
|
|
|
39
40
|
repromptId,
|
|
40
41
|
);
|
|
41
42
|
const proposal = await readAppState(proposalKey);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
const proposalCancelled = isNodeRewriteProposal(proposal);
|
|
44
|
+
const pendingCancelled = proposalCancelled
|
|
45
|
+
? await compareAndSetManyAppState([
|
|
46
|
+
{
|
|
47
|
+
key: pendingKey,
|
|
48
|
+
expectedValue: pending,
|
|
49
|
+
nextValue: null,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: proposalKey,
|
|
53
|
+
expectedValue: proposal,
|
|
54
|
+
nextValue: null,
|
|
55
|
+
},
|
|
56
|
+
])
|
|
57
|
+
: await compareAndSetAppState(pendingKey, pending, null);
|
|
48
58
|
return {
|
|
49
59
|
cancelled: pendingCancelled,
|
|
50
|
-
proposalCancelled,
|
|
60
|
+
proposalCancelled: proposalCancelled && pendingCancelled,
|
|
51
61
|
superseded: !pendingCancelled,
|
|
52
62
|
};
|
|
53
63
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
compareAndSetManyAppState,
|
|
4
4
|
readAppState,
|
|
5
|
-
|
|
5
|
+
type AppStateCompareAndSetOperation,
|
|
6
6
|
} from "@agent-native/core/application-state";
|
|
7
7
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
8
8
|
import { and, eq } from "drizzle-orm";
|
|
@@ -68,6 +68,7 @@ const variantSchema = z.object({
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
const pendingRepromptSchema = z.object({
|
|
71
|
+
status: z.literal("pending").optional(),
|
|
71
72
|
repromptId: z.string().min(1),
|
|
72
73
|
designId: z.string().min(1),
|
|
73
74
|
fileId: z.string().min(1),
|
|
@@ -241,21 +242,18 @@ export default defineAction({
|
|
|
241
242
|
file.id,
|
|
242
243
|
repromptId,
|
|
243
244
|
);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
proposalKey,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"This regeneration was superseded by a newer request before its candidates were published.",
|
|
257
|
-
);
|
|
258
|
-
}
|
|
245
|
+
const publishOperations: AppStateCompareAndSetOperation[] = [
|
|
246
|
+
{
|
|
247
|
+
key: pendingKey,
|
|
248
|
+
expectedValue: pending as unknown as Record<string, unknown>,
|
|
249
|
+
nextValue: pending as unknown as Record<string, unknown>,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
key: proposalKey,
|
|
253
|
+
expectedValue: null,
|
|
254
|
+
nextValue: proposal as unknown as Record<string, unknown>,
|
|
255
|
+
},
|
|
256
|
+
];
|
|
259
257
|
if (pending.priorProposalId && pending.priorRepromptId) {
|
|
260
258
|
const priorProposalKey = designRepromptProposalStateKey(
|
|
261
259
|
file.designId,
|
|
@@ -264,9 +262,19 @@ export default defineAction({
|
|
|
264
262
|
);
|
|
265
263
|
const priorProposal = await readAppState(priorProposalKey);
|
|
266
264
|
if (priorProposal?.proposalId === pending.priorProposalId) {
|
|
267
|
-
|
|
265
|
+
publishOperations.push({
|
|
266
|
+
key: priorProposalKey,
|
|
267
|
+
expectedValue: priorProposal,
|
|
268
|
+
nextValue: null,
|
|
269
|
+
});
|
|
268
270
|
}
|
|
269
271
|
}
|
|
272
|
+
const published = await compareAndSetManyAppState(publishOperations);
|
|
273
|
+
if (!published) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
"This regeneration was superseded by a newer request before its candidates were published.",
|
|
276
|
+
);
|
|
277
|
+
}
|
|
270
278
|
|
|
271
279
|
const bridgeMessages: NodeHtmlPreviewBridgeMessage[] = [
|
|
272
280
|
{
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
3
|
compareAndSetAppState,
|
|
4
|
+
compareAndSetManyAppState,
|
|
4
5
|
listAppState,
|
|
5
6
|
readAppState,
|
|
6
7
|
} from "@agent-native/core/application-state";
|
|
7
8
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
8
9
|
import { and, eq } from "drizzle-orm";
|
|
10
|
+
import { nanoid } from "nanoid";
|
|
9
11
|
import { z } from "zod";
|
|
10
12
|
|
|
11
13
|
import { getDb, schema } from "../server/db/index.js";
|
|
@@ -22,6 +24,7 @@ import {
|
|
|
22
24
|
isPendingDesignReprompt,
|
|
23
25
|
spliceNodeRewriteVariant,
|
|
24
26
|
type NodeHtmlPreviewBridgeMessage,
|
|
27
|
+
type NodeRewriteResolutionClaim,
|
|
25
28
|
type NodeRewriteProposal,
|
|
26
29
|
} from "../shared/node-rewrite.js";
|
|
27
30
|
import { designSourceTypeFromData } from "../shared/source-mode.js";
|
|
@@ -142,22 +145,19 @@ async function clearProposalState(
|
|
|
142
145
|
proposalKey: string,
|
|
143
146
|
proposal: NodeRewriteProposal,
|
|
144
147
|
pending: Record<string, unknown>,
|
|
145
|
-
): Promise<
|
|
148
|
+
): Promise<boolean> {
|
|
146
149
|
const pendingKey = designRepromptPendingStateKey(
|
|
147
150
|
proposal.designId,
|
|
148
151
|
proposal.fileId,
|
|
149
152
|
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
proposalKey,
|
|
153
|
-
proposal as unknown as Record<string, unknown>,
|
|
154
|
-
null,
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
return compareAndSetManyAppState([
|
|
154
|
+
{
|
|
155
|
+
key: proposalKey,
|
|
156
|
+
expectedValue: proposal as unknown as Record<string, unknown>,
|
|
157
|
+
nextValue: null,
|
|
158
|
+
},
|
|
159
|
+
{ key: pendingKey, expectedValue: pending, nextValue: null },
|
|
157
160
|
]);
|
|
158
|
-
if (!proposalCleared) {
|
|
159
|
-
throw new Error("Node rewrite proposal changed while it was resolving.");
|
|
160
|
-
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
export default defineAction({
|
|
@@ -195,7 +195,16 @@ export default defineAction({
|
|
|
195
195
|
|
|
196
196
|
if (resolution === "reject") {
|
|
197
197
|
await assertAccess("design", proposal.designId, "editor");
|
|
198
|
-
await clearProposalState(
|
|
198
|
+
const cleanupComplete = await clearProposalState(
|
|
199
|
+
proposalKey,
|
|
200
|
+
proposal,
|
|
201
|
+
pending,
|
|
202
|
+
);
|
|
203
|
+
if (!cleanupComplete) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
"The proposal changed while it was being rejected. Review the latest candidates instead.",
|
|
206
|
+
);
|
|
207
|
+
}
|
|
199
208
|
return {
|
|
200
209
|
proposalId,
|
|
201
210
|
repromptId: proposal.repromptId,
|
|
@@ -234,13 +243,51 @@ export default defineAction({
|
|
|
234
243
|
source,
|
|
235
244
|
fileType: file.fileType,
|
|
236
245
|
});
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
const claim: NodeRewriteResolutionClaim = {
|
|
247
|
+
...pending,
|
|
248
|
+
status: "resolving",
|
|
249
|
+
claimId: `node-rewrite-claim-${nanoid()}`,
|
|
250
|
+
proposalId,
|
|
251
|
+
resolution: "accept",
|
|
252
|
+
};
|
|
253
|
+
const claimValue = claim as unknown as Record<string, unknown>;
|
|
254
|
+
const claimed = await compareAndSetAppState(
|
|
255
|
+
pendingKey,
|
|
256
|
+
pending,
|
|
257
|
+
claimValue,
|
|
258
|
+
);
|
|
259
|
+
if (!claimed) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
"A newer regeneration request replaced this proposal before it could be accepted.",
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let write;
|
|
266
|
+
try {
|
|
267
|
+
write = await writeInlineSourceFile({
|
|
268
|
+
designId: file.designId,
|
|
269
|
+
file,
|
|
270
|
+
content: rewrite.content,
|
|
271
|
+
expectedVersionHash: proposal.baseVersionHash,
|
|
272
|
+
});
|
|
273
|
+
} catch (error) {
|
|
274
|
+
const released = await compareAndSetAppState(
|
|
275
|
+
pendingKey,
|
|
276
|
+
claimValue,
|
|
277
|
+
pending,
|
|
278
|
+
);
|
|
279
|
+
if (!released) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
"The design write failed and its regeneration reservation could not be restored.",
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
const cleanupComplete = await clearProposalState(
|
|
287
|
+
proposalKey,
|
|
288
|
+
proposal,
|
|
289
|
+
claimValue,
|
|
290
|
+
);
|
|
244
291
|
|
|
245
292
|
return {
|
|
246
293
|
proposalId,
|
|
@@ -252,6 +299,7 @@ export default defineAction({
|
|
|
252
299
|
designId: file.designId,
|
|
253
300
|
fileId: file.id,
|
|
254
301
|
versionHash: write.versionHash,
|
|
302
|
+
cleanupComplete,
|
|
255
303
|
};
|
|
256
304
|
},
|
|
257
305
|
});
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callAction,
|
|
3
|
-
setClientAppState,
|
|
4
3
|
useActionMutation,
|
|
5
4
|
useChangeVersion,
|
|
6
5
|
} from "@agent-native/core/client/hooks";
|
|
7
6
|
import { useT } from "@agent-native/core/client/i18n";
|
|
8
7
|
import {
|
|
9
|
-
designRepromptPendingStateKey,
|
|
10
8
|
isNodeRewriteProposal,
|
|
11
9
|
type NodeHtmlPreviewBridgeMessage,
|
|
12
10
|
type NodeRewriteProposal,
|
|
@@ -426,7 +424,6 @@ export function NodeRewriteProposal({
|
|
|
426
424
|
if (!proposal || !instruction || refining || resolveMutation.isPending)
|
|
427
425
|
return;
|
|
428
426
|
const repromptId = crypto.randomUUID();
|
|
429
|
-
const pendingKey = designRepromptPendingStateKey(designId, fileId);
|
|
430
427
|
const pending = {
|
|
431
428
|
repromptId,
|
|
432
429
|
designId,
|
|
@@ -440,7 +437,7 @@ export function NodeRewriteProposal({
|
|
|
440
437
|
};
|
|
441
438
|
setRefining(true);
|
|
442
439
|
try {
|
|
443
|
-
await
|
|
440
|
+
await callAction("begin-node-rewrite-request", pending);
|
|
444
441
|
const submission = formatNodeRepromptSubmission({
|
|
445
442
|
...pending,
|
|
446
443
|
priorProposalId: proposal.proposalId,
|
|
@@ -10,10 +10,7 @@ import {
|
|
|
10
10
|
type ReviewThread,
|
|
11
11
|
} from "@agent-native/core/client/review";
|
|
12
12
|
import type { ReviewComment } from "@agent-native/core/review";
|
|
13
|
-
import {
|
|
14
|
-
designRepromptPendingStateKey,
|
|
15
|
-
type NodeRewriteTarget,
|
|
16
|
-
} from "@shared/node-rewrite";
|
|
13
|
+
import type { NodeRewriteTarget } from "@shared/node-rewrite";
|
|
17
14
|
import {
|
|
18
15
|
IconArrowUp,
|
|
19
16
|
IconChevronDown,
|
|
@@ -874,10 +871,9 @@ export function ReviewCanvasPins({
|
|
|
874
871
|
element = null;
|
|
875
872
|
}
|
|
876
873
|
}
|
|
877
|
-
const stateKey = designRepromptPendingStateKey(resourceId, targetId);
|
|
878
874
|
setAgentSubmitting(true);
|
|
879
875
|
try {
|
|
880
|
-
await
|
|
876
|
+
await callAction("begin-node-rewrite-request", pending);
|
|
881
877
|
const submission = formatNodeRepromptSubmission({
|
|
882
878
|
...pending,
|
|
883
879
|
subtreeHtml:
|
|
@@ -15,6 +15,7 @@ export const MAX_NODE_REWRITE_PROPOSAL_BYTES = 256 * 1024;
|
|
|
15
15
|
export type NodeRewriteTarget = EditIntentTarget;
|
|
16
16
|
|
|
17
17
|
export interface PendingDesignReprompt {
|
|
18
|
+
status?: "pending";
|
|
18
19
|
repromptId: string;
|
|
19
20
|
designId: string;
|
|
20
21
|
fileId: string;
|
|
@@ -26,6 +27,16 @@ export interface PendingDesignReprompt {
|
|
|
26
27
|
priorRepromptId?: string;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
export interface NodeRewriteResolutionClaim extends Omit<
|
|
31
|
+
PendingDesignReprompt,
|
|
32
|
+
"status"
|
|
33
|
+
> {
|
|
34
|
+
status: "resolving";
|
|
35
|
+
claimId: string;
|
|
36
|
+
proposalId: string;
|
|
37
|
+
resolution: "accept";
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
export interface NodeRewriteVariant {
|
|
30
41
|
html: string;
|
|
31
42
|
summary: string;
|
|
@@ -69,6 +80,7 @@ export function isPendingDesignReprompt(
|
|
|
69
80
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
70
81
|
const pending = value as Partial<PendingDesignReprompt>;
|
|
71
82
|
return (
|
|
83
|
+
(pending.status === undefined || pending.status === "pending") &&
|
|
72
84
|
typeof pending.repromptId === "string" &&
|
|
73
85
|
typeof pending.designId === "string" &&
|
|
74
86
|
typeof pending.fileId === "string" &&
|
|
@@ -79,6 +91,26 @@ export function isPendingDesignReprompt(
|
|
|
79
91
|
);
|
|
80
92
|
}
|
|
81
93
|
|
|
94
|
+
export function isNodeRewriteResolutionClaim(
|
|
95
|
+
value: unknown,
|
|
96
|
+
): value is NodeRewriteResolutionClaim {
|
|
97
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
98
|
+
const claim = value as Partial<NodeRewriteResolutionClaim>;
|
|
99
|
+
return (
|
|
100
|
+
claim.status === "resolving" &&
|
|
101
|
+
typeof claim.claimId === "string" &&
|
|
102
|
+
typeof claim.proposalId === "string" &&
|
|
103
|
+
claim.resolution === "accept" &&
|
|
104
|
+
typeof claim.repromptId === "string" &&
|
|
105
|
+
typeof claim.designId === "string" &&
|
|
106
|
+
typeof claim.fileId === "string" &&
|
|
107
|
+
typeof claim.baseVersionHash === "string" &&
|
|
108
|
+
typeof claim.instruction === "string" &&
|
|
109
|
+
typeof claim.createdAt === "string" &&
|
|
110
|
+
Boolean(claim.target)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
82
114
|
export interface NodeHtmlPreviewBridgeMessage {
|
|
83
115
|
type: "node-html-preview";
|
|
84
116
|
proposalId: string;
|
|
@@ -12,6 +12,7 @@ import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
|
12
12
|
import {
|
|
13
13
|
IconArrowUp,
|
|
14
14
|
IconPlus,
|
|
15
|
+
IconLoader2,
|
|
15
16
|
IconMenu2,
|
|
16
17
|
IconX,
|
|
17
18
|
IconMessageCircle,
|
|
@@ -88,11 +89,9 @@ export function Sidebar() {
|
|
|
88
89
|
|
|
89
90
|
function handleSkip() {
|
|
90
91
|
setPopoverOpen(false);
|
|
91
|
-
const tempId = crypto.randomUUID().replace(/-/g, "").slice(0, 10);
|
|
92
|
-
navigate(`/forms/${tempId}`);
|
|
93
92
|
createForm.mutate(
|
|
94
93
|
{ title: t("sidebar.untitledForm") },
|
|
95
|
-
{ onSuccess: (form) => navigate(`/forms/${form.id}
|
|
94
|
+
{ onSuccess: (form) => navigate(`/forms/${form.id}`) },
|
|
96
95
|
);
|
|
97
96
|
}
|
|
98
97
|
|
|
@@ -171,7 +170,11 @@ export function Sidebar() {
|
|
|
171
170
|
size="sm"
|
|
172
171
|
className="min-h-10 px-2 text-xs text-muted-foreground active:scale-[0.96] transition-[background-color,color,transform]"
|
|
173
172
|
onClick={handleSkip}
|
|
173
|
+
disabled={createForm.isPending}
|
|
174
174
|
>
|
|
175
|
+
{createForm.isPending && (
|
|
176
|
+
<IconLoader2 className="h-3 w-3 animate-spin" />
|
|
177
|
+
)}
|
|
175
178
|
{t("sidebar.skipPrompt")}
|
|
176
179
|
</Button>
|
|
177
180
|
<span className="text-[11px] text-muted-foreground/70">
|
|
@@ -626,20 +626,15 @@ export function FormBuilderPage() {
|
|
|
626
626
|
</Tooltip>
|
|
627
627
|
)}
|
|
628
628
|
|
|
629
|
-
|
|
630
|
-
<
|
|
631
|
-
<
|
|
629
|
+
{form.status === "published" && (
|
|
630
|
+
<Tooltip>
|
|
631
|
+
<TooltipTrigger asChild>
|
|
632
632
|
<Button
|
|
633
633
|
variant="ghost"
|
|
634
634
|
size="icon"
|
|
635
635
|
className="h-10 w-10 active:scale-[0.96] motion-reduce:active:scale-100"
|
|
636
636
|
onClick={copyShareLink}
|
|
637
|
-
|
|
638
|
-
aria-label={
|
|
639
|
-
form.status === "published"
|
|
640
|
-
? t("builder.copyPublicFormLink")
|
|
641
|
-
: t("builder.publishBeforeCopyPublicFormLink")
|
|
642
|
-
}
|
|
637
|
+
aria-label={t("builder.copyPublicFormLink")}
|
|
643
638
|
>
|
|
644
639
|
<span className="relative inline-flex h-4 w-4 items-center justify-center">
|
|
645
640
|
<IconCopy
|
|
@@ -660,16 +655,14 @@ export function FormBuilderPage() {
|
|
|
660
655
|
/>
|
|
661
656
|
</span>
|
|
662
657
|
</Button>
|
|
663
|
-
</
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
{form.status === "published"
|
|
667
|
-
? copied
|
|
658
|
+
</TooltipTrigger>
|
|
659
|
+
<TooltipContent>
|
|
660
|
+
{copied
|
|
668
661
|
? t("builder.publicLinkCopied")
|
|
669
|
-
: t("builder.copyPublishedPublicLink")
|
|
670
|
-
|
|
671
|
-
</
|
|
672
|
-
|
|
662
|
+
: t("builder.copyPublishedPublicLink")}
|
|
663
|
+
</TooltipContent>
|
|
664
|
+
</Tooltip>
|
|
665
|
+
)}
|
|
673
666
|
|
|
674
667
|
<Tooltip>
|
|
675
668
|
<TooltipTrigger asChild>
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { VisibilityBadge } from "@agent-native/toolkit/sharing";
|
|
8
8
|
import {
|
|
9
9
|
IconPlus,
|
|
10
|
+
IconLoader2,
|
|
10
11
|
IconDots,
|
|
11
12
|
IconTrash,
|
|
12
13
|
IconCopy,
|
|
@@ -100,11 +101,9 @@ export function FormsListPage() {
|
|
|
100
101
|
}, [forms]);
|
|
101
102
|
|
|
102
103
|
function handleCreate() {
|
|
103
|
-
const tempId = crypto.randomUUID().replace(/-/g, "").slice(0, 10);
|
|
104
|
-
navigate(`/forms/${tempId}`);
|
|
105
104
|
createForm.mutate(
|
|
106
105
|
{ title: t("forms.untitled") },
|
|
107
|
-
{ onSuccess: (form) => navigate(`/forms/${form.id}
|
|
106
|
+
{ onSuccess: (form) => navigate(`/forms/${form.id}`) },
|
|
108
107
|
);
|
|
109
108
|
}
|
|
110
109
|
|
|
@@ -114,16 +113,21 @@ export function FormsListPage() {
|
|
|
114
113
|
() => (
|
|
115
114
|
<Button
|
|
116
115
|
onClick={handleCreate}
|
|
116
|
+
disabled={createForm.isPending}
|
|
117
117
|
size="sm"
|
|
118
118
|
className="min-h-10 shrink-0 cursor-pointer active:scale-[0.96] transition-[background-color,box-shadow,transform]"
|
|
119
119
|
>
|
|
120
|
-
|
|
120
|
+
{createForm.isPending ? (
|
|
121
|
+
<IconLoader2 className="h-3.5 w-3.5 animate-spin" />
|
|
122
|
+
) : (
|
|
123
|
+
<IconPlus className="h-3.5 w-3.5" />
|
|
124
|
+
)}
|
|
121
125
|
<span className="hidden sm:inline">{t("forms.newForm")}</span>
|
|
122
126
|
<span className="sm:hidden">{t("forms.new")}</span>
|
|
123
127
|
</Button>
|
|
124
128
|
),
|
|
125
129
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
126
|
-
[],
|
|
130
|
+
[createForm.isPending],
|
|
127
131
|
);
|
|
128
132
|
useSetHeaderActions(headerActions);
|
|
129
133
|
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@agent-native/core/client/collab";
|
|
10
10
|
import { callAction } from "@agent-native/core/client/hooks";
|
|
11
11
|
import { isEmbedAuthActive } from "@agent-native/core/client/host";
|
|
12
|
+
import { useOrg } from "@agent-native/core/client/org";
|
|
12
13
|
import { nanoid } from "nanoid";
|
|
13
14
|
import {
|
|
14
15
|
createContext,
|
|
@@ -950,6 +951,7 @@ export const defaultSlideContent: Record<SlideLayout, string> = {
|
|
|
950
951
|
};
|
|
951
952
|
|
|
952
953
|
export function DeckProvider({ children }: { children: ReactNode }) {
|
|
954
|
+
const { data: org } = useOrg();
|
|
953
955
|
const [decks, setDecks] = useState<Deck[]>([]);
|
|
954
956
|
const [loading, setLoading] = useState(true);
|
|
955
957
|
const [loadError, setLoadError] = useState(false);
|
|
@@ -1269,6 +1271,22 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1269
1271
|
});
|
|
1270
1272
|
}, [resetDeckBaseline]);
|
|
1271
1273
|
|
|
1274
|
+
// Switching orgs re-scopes list-decks server-side but leaves this context's
|
|
1275
|
+
// in-memory list untouched, so the previous org's decks linger. Reload when
|
|
1276
|
+
// the org id actually changes; skip the first observed id so we don't double
|
|
1277
|
+
// up on the mount fetch above.
|
|
1278
|
+
const lastOrgIdRef = useRef<string | null | undefined>(undefined);
|
|
1279
|
+
useEffect(() => {
|
|
1280
|
+
const orgId = org?.orgId ?? null;
|
|
1281
|
+
if (lastOrgIdRef.current === undefined) {
|
|
1282
|
+
lastOrgIdRef.current = orgId;
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
if (lastOrgIdRef.current === orgId) return;
|
|
1286
|
+
lastOrgIdRef.current = orgId;
|
|
1287
|
+
void reloadDecks();
|
|
1288
|
+
}, [org?.orgId, reloadDecks]);
|
|
1289
|
+
|
|
1272
1290
|
// Fallback polling for deck list + open-deck changes. SSE is the primary
|
|
1273
1291
|
// path; this catches agent/db writes that bypass it without hammering idle
|
|
1274
1292
|
// editor pages.
|