@agent-native/core 0.81.2 → 0.82.0
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 +25 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/client/frame.ts +55 -0
- package/corpus/core/src/file-upload/builder.ts +199 -37
- package/corpus/core/src/file-upload/index.ts +2 -0
- package/corpus/core/src/file-upload/types.ts +38 -0
- package/corpus/core/src/mcp/build-server.ts +30 -4
- package/corpus/core/src/mcp/embed-app.ts +33 -18
- package/corpus/templates/clips/actions/create-recording.ts +44 -0
- package/corpus/templates/clips/actions/finalize-recording.ts +198 -88
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +12 -0
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +83 -29
- package/corpus/templates/clips/app/routes/record.tsx +12 -1
- package/corpus/templates/clips/server/lib/resumable-session.ts +39 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +2 -0
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +186 -29
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +4 -0
- package/corpus/templates/clips/shared/recording-core.ts +5 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +63 -16
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +28 -33
- package/corpus/templates/content/app/components/sidebar/document-sidebar-sections.ts +47 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +37 -0
- package/corpus/templates/content/changelog/2026-06-30-sidebar-favorites-now-keep-long-titles-tidy-and-stay-in-sync.md +6 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +8 -1
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +11 -2
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +89 -16
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +21 -14
- package/corpus/templates/design/app/pages/DesignEditor.tsx +557 -211
- package/corpus/templates/design/changelog/2026-06-30-design-studio-canvas-layers-can-be-copied-pasted-and-reparen.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +3 -1
- package/corpus/templates/design/e2e/helpers.ts +4 -1
- package/corpus/templates/design/playwright.config.ts +4 -1
- package/corpus/templates/plan/actions/consume-plan-feedback.ts +1 -9
- package/corpus/templates/plan/actions/convert-visual-plan-to-prototype.ts +1 -1
- package/corpus/templates/plan/actions/create-plan-design.ts +1 -1
- package/corpus/templates/plan/actions/create-prototype-plan.ts +1 -1
- package/corpus/templates/plan/actions/create-ui-plan.ts +1 -1
- package/corpus/templates/plan/actions/create-visual-plan.ts +36 -19
- package/corpus/templates/plan/actions/create-visual-questions.ts +1 -1
- package/corpus/templates/plan/actions/create-visual-recap.ts +1 -1
- package/corpus/templates/plan/actions/delete-plan-comment.ts +1 -9
- package/corpus/templates/plan/actions/delete-visual-plan.ts +1 -9
- package/corpus/templates/plan/actions/get-plan-feedback.ts +1 -9
- package/corpus/templates/plan/actions/get-visual-plan.ts +1 -9
- package/corpus/templates/plan/actions/import-visual-plan-source.ts +1 -1
- package/corpus/templates/plan/actions/list-visual-plans.ts +1 -9
- package/corpus/templates/plan/actions/reply-to-plan-comment.ts +1 -9
- package/corpus/templates/plan/actions/resolve-plan-comment.ts +1 -9
- package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
- package/corpus/templates/plan/actions/visual-answer.ts +1 -1
- package/corpus/templates/plan/app/components/layout/Layout.tsx +15 -0
- package/corpus/templates/plan/app/entry.client.tsx +10 -0
- package/corpus/templates/plan/app/global.css +28 -0
- package/corpus/templates/plan/shared/plan-content.ts +10 -6
- package/dist/client/frame.d.ts.map +1 -1
- package/dist/client/frame.js +59 -0
- package/dist/client/frame.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/builder.d.ts.map +1 -1
- package/dist/file-upload/builder.js +137 -25
- package/dist/file-upload/builder.js.map +1 -1
- package/dist/file-upload/index.d.ts +1 -1
- package/dist/file-upload/index.d.ts.map +1 -1
- package/dist/file-upload/index.js.map +1 -1
- package/dist/file-upload/types.d.ts +26 -0
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +31 -4
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +33 -18
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.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
|
@@ -16,7 +16,9 @@ export const E2E_EMAIL = "e2e@local.test";
|
|
|
16
16
|
export const E2E_PASSWORD = "password-e2e-1234";
|
|
17
17
|
export const SEED_TITLE = "E2E Seed Design";
|
|
18
18
|
|
|
19
|
-
const AUTH_DIR =
|
|
19
|
+
const AUTH_DIR = process.env.E2E_AUTH_DIR
|
|
20
|
+
? path.resolve(process.env.E2E_AUTH_DIR)
|
|
21
|
+
: path.join(import.meta.dirname, ".auth");
|
|
20
22
|
const STATE_PATH = path.join(AUTH_DIR, "state.json");
|
|
21
23
|
const SEED_PATH = path.join(AUTH_DIR, "seed.json");
|
|
22
24
|
const BROWSER_CHANNEL = process.env.E2E_BROWSER_CHANNEL;
|
|
@@ -25,7 +25,10 @@ import { FIXTURE_HTML, SEED_TITLE } from "./global-setup";
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
export async function readSeedDesignId(): Promise<string> {
|
|
28
|
-
const
|
|
28
|
+
const authDir = process.env.E2E_AUTH_DIR
|
|
29
|
+
? path.resolve(process.env.E2E_AUTH_DIR)
|
|
30
|
+
: path.join(import.meta.dirname, ".auth");
|
|
31
|
+
const seedPath = path.join(authDir, "seed.json");
|
|
29
32
|
const raw = await readFile(seedPath, "utf8");
|
|
30
33
|
const { designId } = JSON.parse(raw) as { designId: string };
|
|
31
34
|
if (!designId) throw new Error("no seeded designId - global-setup failed");
|
|
@@ -15,6 +15,9 @@ import { defineConfig, devices } from "@playwright/test";
|
|
|
15
15
|
*/
|
|
16
16
|
const PORT = Number(process.env.E2E_PORT ?? 9333);
|
|
17
17
|
const BASE_URL = process.env.E2E_BASE_URL ?? `http://127.0.0.1:${PORT}`;
|
|
18
|
+
const AUTH_DIR = process.env.E2E_AUTH_DIR
|
|
19
|
+
? path.resolve(process.env.E2E_AUTH_DIR)
|
|
20
|
+
: path.join(import.meta.dirname, "e2e", ".auth");
|
|
18
21
|
const E2E_DATABASE_URL = `file:${path.join(
|
|
19
22
|
import.meta.dirname,
|
|
20
23
|
"data",
|
|
@@ -34,7 +37,7 @@ export default defineConfig({
|
|
|
34
37
|
globalSetup: path.join(import.meta.dirname, "e2e", "global-setup.ts"),
|
|
35
38
|
use: {
|
|
36
39
|
baseURL: BASE_URL,
|
|
37
|
-
storageState: path.join(
|
|
40
|
+
storageState: path.join(AUTH_DIR, "state.json"),
|
|
38
41
|
trace: "on-first-retry",
|
|
39
42
|
actionTimeout: 15_000,
|
|
40
43
|
navigationTimeout: 30_000,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { and, eq, inArray, isNull } from "drizzle-orm";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
@@ -28,14 +28,6 @@ export default defineAction({
|
|
|
28
28
|
},
|
|
29
29
|
mcpApp: {
|
|
30
30
|
compactCatalog: true,
|
|
31
|
-
resource: embedApp({
|
|
32
|
-
title: "Consume Feedback",
|
|
33
|
-
description:
|
|
34
|
-
"Open the Agent-Native Plan surface to view and manage feedback comments.",
|
|
35
|
-
iframeTitle: "Agent-Native Plan",
|
|
36
|
-
openLabel: "Open Plan",
|
|
37
|
-
height: 860,
|
|
38
|
-
}),
|
|
39
31
|
},
|
|
40
32
|
run: async (args) => {
|
|
41
33
|
// Consuming feedback requires editor access — same as authoring changes in
|
|
@@ -200,7 +200,7 @@ export default defineAction({
|
|
|
200
200
|
"Open the Agent-Native Plan design review surface for full-fidelity screens, prototype behavior, comments, and implementation notes.",
|
|
201
201
|
iframeTitle: "Agent-Native Plan",
|
|
202
202
|
openLabel: "Open Plan Design",
|
|
203
|
-
height:
|
|
203
|
+
height: 900,
|
|
204
204
|
}),
|
|
205
205
|
},
|
|
206
206
|
run: async (args) => {
|
|
@@ -158,7 +158,7 @@ export default defineAction({
|
|
|
158
158
|
"Open the Agent-Native Plan prototype review surface for functional states, comments, static mocks, and implementation notes.",
|
|
159
159
|
iframeTitle: "Agent-Native Plan",
|
|
160
160
|
openLabel: "Open Visual Plan",
|
|
161
|
-
height:
|
|
161
|
+
height: 900,
|
|
162
162
|
}),
|
|
163
163
|
},
|
|
164
164
|
run: async (args) => {
|
|
@@ -127,7 +127,7 @@ export default defineAction({
|
|
|
127
127
|
"Open the Agent-Native Plan UI review surface for sketch mockups, state annotations, implementation maps, snippets, and validation notes.",
|
|
128
128
|
iframeTitle: "Agent-Native Plan",
|
|
129
129
|
openLabel: "Open UI Plan",
|
|
130
|
-
height:
|
|
130
|
+
height: 900,
|
|
131
131
|
}),
|
|
132
132
|
},
|
|
133
133
|
run: async (args) => {
|
|
@@ -53,7 +53,7 @@ function inferImportedPlanTitle(planText: string): string {
|
|
|
53
53
|
|
|
54
54
|
export default defineAction({
|
|
55
55
|
description:
|
|
56
|
-
"Create a document-first structured plan for any coding task. For a plan whose centerpiece is wireframed screens/states on a canvas use create-ui-plan; for a recap of an existing diff use create-visual-recap; for a running interactive prototype use create-prototype-plan; for a full-fidelity branded design use create-plan-design. Also accepts imported Codex, Claude Code, Markdown, or pasted plan text via planText. Publish via this tool; never deliver the plan as inline chat text.",
|
|
56
|
+
"Create a document-first structured plan for any coding task. Call this EXACTLY ONCE per plan — produce the final plan in a single call. Do NOT create a draft and then a second 'clean' version; if you need to revise after creating, call update-visual-plan with the existing planId instead of creating another plan (each create renders its own embed, so a second create leaves a duplicate). For a plan whose centerpiece is wireframed screens/states on a canvas use create-ui-plan; for a recap of an existing diff use create-visual-recap; for a running interactive prototype use create-prototype-plan; for a full-fidelity branded design use create-plan-design. Also accepts imported Codex, Claude Code, Markdown, or pasted plan text via planText. Publish via this tool; never deliver the plan as inline chat text.",
|
|
57
57
|
schema: z
|
|
58
58
|
.object({
|
|
59
59
|
title: z.string().optional().describe("Short plan title"),
|
|
@@ -121,7 +121,7 @@ export default defineAction({
|
|
|
121
121
|
"Open the Agent-Native Plan review surface for structured blocks, inline diagrams, optional UI wireframes/prototypes, and comments.",
|
|
122
122
|
iframeTitle: "Agent-Native Plan",
|
|
123
123
|
openLabel: "Open Plan",
|
|
124
|
-
height:
|
|
124
|
+
height: 900,
|
|
125
125
|
}),
|
|
126
126
|
},
|
|
127
127
|
run: async (args) => {
|
|
@@ -216,26 +216,43 @@ export default defineAction({
|
|
|
216
216
|
visibility: "private",
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
219
|
+
// `planSections.id` is a GLOBAL primary key, so a client-supplied id (e.g.
|
|
220
|
+
// "section-1") collides across plans/retries and throws on insert. Always
|
|
221
|
+
// generate a unique server id; keep a logical-id -> row-id map so comment
|
|
222
|
+
// anchors can be remapped instead of failing the foreign key.
|
|
223
|
+
const sectionIdByLogical = new Map<string, string>();
|
|
224
|
+
const sectionRows = sections.map((section, index) => {
|
|
225
|
+
const rowId = newId("sec");
|
|
226
|
+
const logicalId = section.id ?? `section-${index + 1}`;
|
|
227
|
+
sectionIdByLogical.set(logicalId, rowId);
|
|
228
|
+
if (section.id) sectionIdByLogical.set(section.id, rowId);
|
|
229
|
+
return {
|
|
230
|
+
id: rowId,
|
|
231
|
+
planId: id,
|
|
232
|
+
type: section.type,
|
|
233
|
+
title: section.title,
|
|
234
|
+
body: section.body,
|
|
235
|
+
html: section.html ?? null,
|
|
236
|
+
order: section.order ?? index,
|
|
237
|
+
createdBy: section.createdBy,
|
|
238
|
+
createdAt: now,
|
|
239
|
+
updatedAt: now,
|
|
240
|
+
};
|
|
241
|
+
});
|
|
242
|
+
await getDb().insert(schema.planSections).values(sectionRows);
|
|
243
|
+
|
|
244
|
+
// Remap each comment's sectionId to its real row id; drop (undefined)
|
|
245
|
+
// anchors that match no section rather than failing the FK and blocking the
|
|
246
|
+
// publish.
|
|
247
|
+
const commentsForInsert = args.comments.map((comment) => {
|
|
248
|
+
if (!comment.sectionId) return comment;
|
|
249
|
+
const mapped = sectionIdByLogical.get(comment.sectionId);
|
|
250
|
+
return { ...comment, sectionId: mapped };
|
|
251
|
+
});
|
|
235
252
|
|
|
236
253
|
await insertInitialPlanComments({
|
|
237
254
|
planId: id,
|
|
238
|
-
comments:
|
|
255
|
+
comments: commentsForInsert,
|
|
239
256
|
requestEmail: requesterEmail,
|
|
240
257
|
requestName: requesterName,
|
|
241
258
|
now,
|
|
@@ -149,7 +149,7 @@ export default defineAction({
|
|
|
149
149
|
"Open an interactive visual intake form with chips, mockup options, diagrams, freeform answers, and agent handoff.",
|
|
150
150
|
iframeTitle: "Agent-Native Plan",
|
|
151
151
|
openLabel: "Open Visual Questions",
|
|
152
|
-
height:
|
|
152
|
+
height: 900,
|
|
153
153
|
}),
|
|
154
154
|
},
|
|
155
155
|
run: async (args) => {
|
|
@@ -265,7 +265,7 @@ export default defineAction({
|
|
|
265
265
|
"Open the Agent-Native Plan review surface for a visual code-review recap.",
|
|
266
266
|
iframeTitle: "Agent-Native Plan",
|
|
267
267
|
openLabel: "Open Recap",
|
|
268
|
-
height:
|
|
268
|
+
height: 900,
|
|
269
269
|
}),
|
|
270
270
|
},
|
|
271
271
|
run: async (args) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
3
3
|
import {
|
|
4
4
|
ForbiddenError,
|
|
@@ -72,14 +72,6 @@ export default defineAction({
|
|
|
72
72
|
},
|
|
73
73
|
mcpApp: {
|
|
74
74
|
compactCatalog: true,
|
|
75
|
-
resource: embedApp({
|
|
76
|
-
title: "Delete Comment",
|
|
77
|
-
description:
|
|
78
|
-
"Open the Agent-Native Plan surface to manage reviewer comments.",
|
|
79
|
-
iframeTitle: "Agent-Native Plan",
|
|
80
|
-
openLabel: "Open Plan",
|
|
81
|
-
height: 860,
|
|
82
|
-
}),
|
|
83
75
|
},
|
|
84
76
|
run: async (args) => {
|
|
85
77
|
const requesterEmail = getRequestUserEmail();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { deleteCollabState } from "@agent-native/core/collab";
|
|
3
3
|
import { getDbExec } from "@agent-native/core/db";
|
|
4
4
|
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
@@ -206,14 +206,6 @@ export default defineAction({
|
|
|
206
206
|
needsApproval: (args) => args.mode === "hard",
|
|
207
207
|
mcpApp: {
|
|
208
208
|
compactCatalog: true,
|
|
209
|
-
resource: embedApp({
|
|
210
|
-
title: "Delete Plan Data",
|
|
211
|
-
description:
|
|
212
|
-
"Open the Agent-Native Plan surface to manage hosted plan deletion.",
|
|
213
|
-
iframeTitle: "Agent-Native Plan",
|
|
214
|
-
openLabel: "Open Plan",
|
|
215
|
-
height: 860,
|
|
216
|
-
}),
|
|
217
209
|
},
|
|
218
210
|
run: async (args) => {
|
|
219
211
|
const deleteOwnerEmail = requireDeleteOwnerEmail();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
import { loadPlanBundle } from "../server/plans.js";
|
|
@@ -410,14 +410,6 @@ export default defineAction({
|
|
|
410
410
|
},
|
|
411
411
|
mcpApp: {
|
|
412
412
|
compactCatalog: true,
|
|
413
|
-
resource: embedApp({
|
|
414
|
-
title: "Plan Feedback",
|
|
415
|
-
description:
|
|
416
|
-
"Open the Agent-Native Plan surface for reviewer feedback, annotations, and comments.",
|
|
417
|
-
iframeTitle: "Agent-Native Plan",
|
|
418
|
-
openLabel: "Open Plan Feedback",
|
|
419
|
-
height: 860,
|
|
420
|
-
}),
|
|
421
413
|
},
|
|
422
414
|
run: async (args) => {
|
|
423
415
|
const bundle = await loadPlanBundle(args.planId);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -64,14 +64,6 @@ export default defineAction({
|
|
|
64
64
|
},
|
|
65
65
|
mcpApp: {
|
|
66
66
|
compactCatalog: true,
|
|
67
|
-
resource: embedApp({
|
|
68
|
-
title: "Plan",
|
|
69
|
-
description:
|
|
70
|
-
"Open the Agent-Native Plan review surface for structured blocks, annotations, and comments.",
|
|
71
|
-
iframeTitle: "Agent-Native Plan",
|
|
72
|
-
openLabel: "Open Plan",
|
|
73
|
-
height: 860,
|
|
74
|
-
}),
|
|
75
67
|
},
|
|
76
68
|
run: async (args, ctx) => {
|
|
77
69
|
const bundle = await loadPlanBundle(args.id);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import { accessFilter, currentAccess } from "@agent-native/core/sharing";
|
|
3
3
|
import { and, desc, eq, isNotNull, isNull, or } from "drizzle-orm";
|
|
4
4
|
import { z } from "zod";
|
|
@@ -36,14 +36,6 @@ export default defineAction({
|
|
|
36
36
|
readOnly: true,
|
|
37
37
|
mcpApp: {
|
|
38
38
|
compactCatalog: true,
|
|
39
|
-
resource: embedApp({
|
|
40
|
-
title: "Plans",
|
|
41
|
-
description:
|
|
42
|
-
"Open the Agent-Native Plan index for existing plans and recaps.",
|
|
43
|
-
iframeTitle: "Agent-Native Plan",
|
|
44
|
-
openLabel: "Open Plans",
|
|
45
|
-
height: 860,
|
|
46
|
-
}),
|
|
47
39
|
},
|
|
48
40
|
run: async (args) => {
|
|
49
41
|
// Project only the columns the list/summary needs. A bare `.select()` pulls
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
3
|
getRequestUserEmail,
|
|
4
4
|
getRequestUserName,
|
|
@@ -63,14 +63,6 @@ export default defineAction({
|
|
|
63
63
|
},
|
|
64
64
|
mcpApp: {
|
|
65
65
|
compactCatalog: true,
|
|
66
|
-
resource: embedApp({
|
|
67
|
-
title: "Reply to Comment",
|
|
68
|
-
description:
|
|
69
|
-
"Open the Agent-Native Plan surface to view and reply to comment threads.",
|
|
70
|
-
iframeTitle: "Agent-Native Plan",
|
|
71
|
-
openLabel: "Open Plan",
|
|
72
|
-
height: 860,
|
|
73
|
-
}),
|
|
74
66
|
},
|
|
75
67
|
run: async (args) => {
|
|
76
68
|
const requesterEmail = getRequestUserEmail();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineAction
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
3
|
getRequestUserEmail,
|
|
4
4
|
getRequestUserName,
|
|
@@ -101,14 +101,6 @@ export default defineAction({
|
|
|
101
101
|
},
|
|
102
102
|
mcpApp: {
|
|
103
103
|
compactCatalog: true,
|
|
104
|
-
resource: embedApp({
|
|
105
|
-
title: "Resolve Comment",
|
|
106
|
-
description:
|
|
107
|
-
"Open the Agent-Native Plan surface to manage comment thread statuses.",
|
|
108
|
-
iframeTitle: "Agent-Native Plan",
|
|
109
|
-
openLabel: "Open Plan",
|
|
110
|
-
height: 860,
|
|
111
|
-
}),
|
|
112
104
|
},
|
|
113
105
|
run: async (args) => {
|
|
114
106
|
const requesterEmail = getRequestUserEmail();
|
|
@@ -456,7 +456,7 @@ export default defineAction({
|
|
|
456
456
|
"Open the Agent-Native Plan editor for structured content, comments, and status changes.",
|
|
457
457
|
iframeTitle: "Agent-Native Plan",
|
|
458
458
|
openLabel: "Open Plan",
|
|
459
|
-
height:
|
|
459
|
+
height: 900,
|
|
460
460
|
}),
|
|
461
461
|
},
|
|
462
462
|
run: async (args) => {
|
|
@@ -182,7 +182,7 @@ export default defineAction({
|
|
|
182
182
|
description: "Open the Agent-Native Plan visual answer surface.",
|
|
183
183
|
iframeTitle: "Agent-Native Plan",
|
|
184
184
|
openLabel: "Open Visual Answer",
|
|
185
|
-
height:
|
|
185
|
+
height: 900,
|
|
186
186
|
}),
|
|
187
187
|
},
|
|
188
188
|
// Render the answer's diagram/wireframe/api-spec/data-model blocks INLINE in
|
|
@@ -132,6 +132,21 @@ export function Layout({ children }: LayoutProps) {
|
|
|
132
132
|
window.removeEventListener(PLAN_READER_VIEW_EVENT, onPlanReaderView);
|
|
133
133
|
}, [planDetailRoute]);
|
|
134
134
|
|
|
135
|
+
// Embed mode: render just the reader, flowing — no Sidebar, no AgentSidebar,
|
|
136
|
+
// no h-screen shell. Those (some in shared core) lock the embed to the iframe
|
|
137
|
+
// height; bypassing them lets the document flow so the shell sizes to content
|
|
138
|
+
// (see global.css `html[data-embed]` + frame.ts content-height reporting).
|
|
139
|
+
const embedded = new URLSearchParams(location.search).get("embedded") === "1";
|
|
140
|
+
if (embedded) {
|
|
141
|
+
return (
|
|
142
|
+
<HeaderActionsProvider>
|
|
143
|
+
<div className="agent-embed-root flex w-full flex-col bg-background text-foreground">
|
|
144
|
+
{children}
|
|
145
|
+
</div>
|
|
146
|
+
</HeaderActionsProvider>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
135
150
|
const pageContent = (
|
|
136
151
|
<div className="flex h-full flex-1 flex-col overflow-hidden">
|
|
137
152
|
{ownsToolbar ? (
|
|
@@ -16,4 +16,14 @@ if (context) {
|
|
|
16
16
|
context.basename = routerBasePath;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
// Embed mode: mark the document so the reader flows to its content height (see
|
|
20
|
+
// global.css `html[data-embed]`). Set before hydration so there's no flash.
|
|
21
|
+
try {
|
|
22
|
+
if (new URLSearchParams(window.location.search).get("embedded") === "1") {
|
|
23
|
+
document.documentElement.dataset.embed = "1";
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// ignore — non-embedded contexts never set the marker
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
hydrateRoot(document, <HydratedRouter useTransitions={false} />);
|
|
@@ -2394,3 +2394,31 @@
|
|
|
2394
2394
|
outline-offset: 2px;
|
|
2395
2395
|
border-radius: 6px;
|
|
2396
2396
|
}
|
|
2397
|
+
|
|
2398
|
+
/* Embed mode (set by entry.client.tsx on `?embedded=1`). The app shell is
|
|
2399
|
+
* fixed-viewport (`h-screen` + `overflow-hidden`), so inside the iframe
|
|
2400
|
+
* scrollHeight equals the iframe height and the embed can't size to content.
|
|
2401
|
+
* Flow the shell -> reader chain so frame.ts reports the real height. Scoped to
|
|
2402
|
+
* [data-embed]; covers the AgentSidebar wrapper too since the chain spans
|
|
2403
|
+
* several containers. */
|
|
2404
|
+
html[data-embed="1"],
|
|
2405
|
+
html[data-embed="1"] body,
|
|
2406
|
+
html[data-embed="1"] #root {
|
|
2407
|
+
height: auto !important;
|
|
2408
|
+
min-height: 0 !important;
|
|
2409
|
+
overflow: visible !important;
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
html[data-embed="1"] .agent-layout-shell,
|
|
2413
|
+
html[data-embed="1"] .agent-layout-main-surface,
|
|
2414
|
+
html[data-embed="1"] .agent-sidebar-root,
|
|
2415
|
+
html[data-embed="1"] .agent-sidebar-content,
|
|
2416
|
+
html[data-embed="1"] .plans-workspace,
|
|
2417
|
+
html[data-embed="1"] .plan-content-surface,
|
|
2418
|
+
html[data-embed="1"] [data-agent-sidebar],
|
|
2419
|
+
html[data-embed="1"] [data-agent-sidebar-content] {
|
|
2420
|
+
height: auto !important;
|
|
2421
|
+
min-height: 0 !important;
|
|
2422
|
+
max-height: none !important;
|
|
2423
|
+
overflow: visible !important;
|
|
2424
|
+
}
|
|
@@ -1412,10 +1412,14 @@ export const imageDataSchema: z.ZodType<PlanImageBlock["data"]> = z
|
|
|
1412
1412
|
message: "Image block requires an assetId or url.",
|
|
1413
1413
|
});
|
|
1414
1414
|
|
|
1415
|
+
// Generous max lengths so a long question title/label never hard-fails a
|
|
1416
|
+
// publish (which forces the agent to retry and leaves an empty embed behind).
|
|
1417
|
+
// These are well above any realistic title/label; the renderer truncates
|
|
1418
|
+
// visually as needed.
|
|
1415
1419
|
const planQuestionOptionSchema: z.ZodType<PlanQuestionOption> = z.object({
|
|
1416
1420
|
id: idSchema,
|
|
1417
|
-
label: z.string().trim().min(1).max(
|
|
1418
|
-
detail: z.string().trim().max(
|
|
1421
|
+
label: z.string().trim().min(1).max(2000),
|
|
1422
|
+
detail: z.string().trim().max(4000).optional(),
|
|
1419
1423
|
recommended: z.boolean().optional(),
|
|
1420
1424
|
wireframe: wireframeDataSchema.optional(),
|
|
1421
1425
|
diagram: diagramDataSchema.optional(),
|
|
@@ -1423,19 +1427,19 @@ const planQuestionOptionSchema: z.ZodType<PlanQuestionOption> = z.object({
|
|
|
1423
1427
|
|
|
1424
1428
|
const planQuestionSchema: z.ZodType<PlanQuestion> = z.object({
|
|
1425
1429
|
id: idSchema,
|
|
1426
|
-
title: z.string().trim().min(1).max(
|
|
1427
|
-
subtitle: z.string().trim().max(
|
|
1430
|
+
title: z.string().trim().min(1).max(2000),
|
|
1431
|
+
subtitle: z.string().trim().max(4000).optional(),
|
|
1428
1432
|
mode: z.enum(["single", "multi", "freeform"]),
|
|
1429
1433
|
options: z.array(planQuestionOptionSchema).max(40).optional(),
|
|
1430
1434
|
allowOther: z.boolean().optional(),
|
|
1431
|
-
placeholder: z.string().trim().max(
|
|
1435
|
+
placeholder: z.string().trim().max(1000).optional(),
|
|
1432
1436
|
required: z.boolean().optional(),
|
|
1433
1437
|
});
|
|
1434
1438
|
|
|
1435
1439
|
export const questionFormDataSchema: z.ZodType<PlanQuestionFormBlock["data"]> =
|
|
1436
1440
|
z.object({
|
|
1437
1441
|
questions: z.array(planQuestionSchema).min(1).max(40),
|
|
1438
|
-
submitLabel: z.string().trim().max(
|
|
1442
|
+
submitLabel: z.string().trim().max(400).optional(),
|
|
1439
1443
|
});
|
|
1440
1444
|
|
|
1441
1445
|
export const planBlockSchema: z.ZodType<PlanBlock> = z.lazy(() =>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/client/frame.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAMH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAM1D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,GAC3B,MAAM,IAAI,CAWZ;AAkBD,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,IAAI,CAG/D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAiBlE;
|
|
1
|
+
{"version":3,"file":"frame.d.ts","sourceRoot":"","sources":["../../src/client/frame.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAMH;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,CAM1D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,GAC3B,MAAM,IAAI,CAWZ;AAkBD,wBAAgB,+BAA+B,IAAI,MAAM,GAAG,IAAI,CAG/D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAiBlE;AAgFD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAED;;;GAGG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AA6CD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAY7D;AAMD,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,SAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoCnE;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAExD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
package/dist/client/frame.js
CHANGED
|
@@ -73,6 +73,64 @@ export function isTrustedFrameMessage(event) {
|
|
|
73
73
|
return false;
|
|
74
74
|
return event.source === window.parent || event.source === window;
|
|
75
75
|
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Content-height reporting (for MCP App embeds)
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
//
|
|
80
|
+
// The embed shell renders this app in a cross-origin iframe and can't measure
|
|
81
|
+
// its content, so we post the real content height for the shell to size to.
|
|
82
|
+
// Only shrinks when the document flows to its natural height — embed layouts
|
|
83
|
+
// must not force `100vh`/`h-screen` on the root, or scrollHeight just equals
|
|
84
|
+
// the iframe height.
|
|
85
|
+
let _contentHeightReportingStarted = false;
|
|
86
|
+
let _lastReportedContentHeight = 0;
|
|
87
|
+
function measureContentHeight() {
|
|
88
|
+
if (typeof document === "undefined")
|
|
89
|
+
return 0;
|
|
90
|
+
const doc = document.documentElement;
|
|
91
|
+
const body = document.body;
|
|
92
|
+
return Math.ceil(Math.max(doc ? doc.scrollHeight : 0, body ? body.scrollHeight : 0));
|
|
93
|
+
}
|
|
94
|
+
function reportContentHeight() {
|
|
95
|
+
if (typeof window === "undefined" || window.parent === window)
|
|
96
|
+
return;
|
|
97
|
+
const height = measureContentHeight();
|
|
98
|
+
if (!height || Math.abs(height - _lastReportedContentHeight) < 2)
|
|
99
|
+
return;
|
|
100
|
+
_lastReportedContentHeight = height;
|
|
101
|
+
sendToFrame("agentNative.contentHeight", { height });
|
|
102
|
+
}
|
|
103
|
+
function startContentHeightReporting() {
|
|
104
|
+
if (_contentHeightReportingStarted || typeof window === "undefined")
|
|
105
|
+
return;
|
|
106
|
+
if (window.parent === window)
|
|
107
|
+
return;
|
|
108
|
+
_contentHeightReportingStarted = true;
|
|
109
|
+
let scheduled = false;
|
|
110
|
+
const schedule = () => {
|
|
111
|
+
if (scheduled)
|
|
112
|
+
return;
|
|
113
|
+
scheduled = true;
|
|
114
|
+
window.requestAnimationFrame(() => {
|
|
115
|
+
scheduled = false;
|
|
116
|
+
reportContentHeight();
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
schedule();
|
|
120
|
+
for (const delay of [100, 300, 800, 1500])
|
|
121
|
+
window.setTimeout(schedule, delay);
|
|
122
|
+
try {
|
|
123
|
+
const observer = new ResizeObserver(schedule);
|
|
124
|
+
if (document.documentElement)
|
|
125
|
+
observer.observe(document.documentElement);
|
|
126
|
+
if (document.body)
|
|
127
|
+
observer.observe(document.body);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
window.addEventListener("resize", schedule, { passive: true });
|
|
131
|
+
}
|
|
132
|
+
window.addEventListener("load", schedule, { passive: true });
|
|
133
|
+
}
|
|
76
134
|
// Listen for frame origin message and cache it.
|
|
77
135
|
// Only accept from the direct parent frame, and only set once.
|
|
78
136
|
if (typeof window !== "undefined") {
|
|
@@ -87,6 +145,7 @@ if (typeof window !== "undefined") {
|
|
|
87
145
|
event.source === window.parent) {
|
|
88
146
|
_frameOrigin = origin;
|
|
89
147
|
window.parent.postMessage({ type: "agentNative.embeddedAppReady" }, getFramePostMessageTargetOrigin() ?? window.location.origin);
|
|
148
|
+
startContentHeightReporting();
|
|
90
149
|
}
|
|
91
150
|
});
|
|
92
151
|
}
|