@mindstudio-ai/remy 0.1.230 → 0.1.232
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/dist/headless.js +148 -86
- package/dist/index.js +158 -91
- package/dist/subagents/browserAutomation/prompt.md +11 -0
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -2882,6 +2882,19 @@ ${partial}` : "[INTERRUPTED] Tool execution was stopped.";
|
|
|
2882
2882
|
}
|
|
2883
2883
|
};
|
|
2884
2884
|
|
|
2885
|
+
// src/toolResultCap.ts
|
|
2886
|
+
var MAX_TOOL_RESULT_BYTES = 256 * 1024;
|
|
2887
|
+
function capToolResult(result) {
|
|
2888
|
+
const total = Buffer.byteLength(result, "utf-8");
|
|
2889
|
+
if (total <= MAX_TOOL_RESULT_BYTES) {
|
|
2890
|
+
return result;
|
|
2891
|
+
}
|
|
2892
|
+
const head = Buffer.from(result, "utf-8").subarray(0, MAX_TOOL_RESULT_BYTES).toString("utf-8");
|
|
2893
|
+
return head + `
|
|
2894
|
+
|
|
2895
|
+
(tool result truncated at ${(MAX_TOOL_RESULT_BYTES / 1024).toFixed(0)}KB of ${(total / 1024).toFixed(0)}KB \u2014 too large to keep in context. Narrow the call (select fewer fields, paginate, or query a subset) instead of fetching everything.)`;
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2885
2898
|
// src/statusWatcher.ts
|
|
2886
2899
|
function startStatusWatcher(config) {
|
|
2887
2900
|
const { apiConfig, getContext, onStatus, interval = 5e3, signal } = config;
|
|
@@ -3407,7 +3420,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3407
3420
|
subAgentMessages
|
|
3408
3421
|
);
|
|
3409
3422
|
}
|
|
3410
|
-
safeSettle(result, result.startsWith("Error"));
|
|
3423
|
+
safeSettle(capToolResult(result), result.startsWith("Error"));
|
|
3411
3424
|
} catch (err) {
|
|
3412
3425
|
safeSettle(`Error: ${err.message}`, true);
|
|
3413
3426
|
}
|
|
@@ -3595,9 +3608,10 @@ var BROWSER_TOOLS = [
|
|
|
3595
3608
|
"evaluate",
|
|
3596
3609
|
"styles",
|
|
3597
3610
|
"screenshotFullPage",
|
|
3598
|
-
"screenshotViewport"
|
|
3611
|
+
"screenshotViewport",
|
|
3612
|
+
"setViewport"
|
|
3599
3613
|
],
|
|
3600
|
-
description:
|
|
3614
|
+
description: 'snapshot: accessibility tree of the page (waits for network to settle). click: click an element (animated cursor, full event sequence). type: type text into input (one char at a time, works with React/Vue/Svelte). select: select a dropdown option by text. wait: wait for an element to appear (polls 100ms, waits for network). navigate: navigate to a URL within the app (waits for load, subsequent steps run on new page). evaluate: run JS in the page. styles: read computed CSS styles from elements (pass properties array with camelCase names, or omit for defaults). screenshotFullPage: full-page viewport-stitched screenshot (returns CDN url with dimensions). screenshotViewport: screenshot of just the visible viewport \u2014 pass `scrollToSelector` (or `scrollY`) on this step to scroll a section into view and capture it in one atomic step (no separate scroll needed). setViewport: switch the browser between desktop and mobile rendering (pass `mode`: "desktop" or "mobile"). Reloads the page so responsive layouts, media queries, and matchMedia re-evaluate \u2014 use it to QA mobile/responsive views.'
|
|
3601
3615
|
},
|
|
3602
3616
|
ref: {
|
|
3603
3617
|
type: "string",
|
|
@@ -3651,6 +3665,11 @@ var BROWSER_TOOLS = [
|
|
|
3651
3665
|
scrollY: {
|
|
3652
3666
|
type: "number",
|
|
3653
3667
|
description: "For screenshotViewport: absolute Y offset to scroll to before the shot, when no selector is available."
|
|
3668
|
+
},
|
|
3669
|
+
mode: {
|
|
3670
|
+
type: "string",
|
|
3671
|
+
enum: ["desktop", "mobile"],
|
|
3672
|
+
description: 'For setViewport: the rendering mode to switch to. "mobile" emulates a phone (narrow width, touch, device pixel ratio); "desktop" is the standard wide viewport.'
|
|
3654
3673
|
}
|
|
3655
3674
|
},
|
|
3656
3675
|
required: ["command"]
|
|
@@ -3700,6 +3719,14 @@ var log7 = createLogger("browser-automation");
|
|
|
3700
3719
|
async function runBrowserAutomation(task, context, opts) {
|
|
3701
3720
|
const release = await acquireBrowserLock();
|
|
3702
3721
|
try {
|
|
3722
|
+
try {
|
|
3723
|
+
await sidecarRequest(
|
|
3724
|
+
"/set-viewport",
|
|
3725
|
+
{ mode: "default" },
|
|
3726
|
+
{ timeout: 2e4 }
|
|
3727
|
+
);
|
|
3728
|
+
} catch {
|
|
3729
|
+
}
|
|
3703
3730
|
let lastBrowserCommandViewport;
|
|
3704
3731
|
const result = await runSubAgent({
|
|
3705
3732
|
system: getBrowserAutomationPrompt(),
|
|
@@ -5122,6 +5149,50 @@ ${summaryText}
|
|
|
5122
5149
|
var DESCRIPTION = `
|
|
5123
5150
|
Visual design expert. Describe the situation and what you need \u2014 the agent decides what to deliver. It reads the spec files automatically. Include relevant user requirements and context it can't get from the spec, but do not list specific deliverables or tell it how to do its job. Do not suggest implementation details or ideas - only relay what is needed.
|
|
5124
5151
|
`.trim();
|
|
5152
|
+
var RENDER_WRITE_TOOL_NAMES = /* @__PURE__ */ new Set(["writeFile", "editFile"]);
|
|
5153
|
+
var DESIGN_EXPERT_RENDER_TOOLS = [
|
|
5154
|
+
...DESIGN_EXPERT_TOOLS,
|
|
5155
|
+
writeFileTool.definition,
|
|
5156
|
+
editFileTool.definition
|
|
5157
|
+
];
|
|
5158
|
+
async function runDesignExpert(opts, context) {
|
|
5159
|
+
const history = context.conversationMessages ? getSubAgentHistory(context.conversationMessages, "visualDesignExpert") : [];
|
|
5160
|
+
return runSubAgent({
|
|
5161
|
+
system: getDesignExpertPrompt(context.onboardingState),
|
|
5162
|
+
task: opts.task,
|
|
5163
|
+
history: history.length > 0 ? history : void 0,
|
|
5164
|
+
tools: opts.enableWrite ? DESIGN_EXPERT_RENDER_TOOLS : DESIGN_EXPERT_TOOLS,
|
|
5165
|
+
externalTools: /* @__PURE__ */ new Set(),
|
|
5166
|
+
executeTool: (name, input, toolCallId, onLog, sams) => {
|
|
5167
|
+
const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
|
|
5168
|
+
if (COMMON_READ_TOOL_NAMES.has(name)) {
|
|
5169
|
+
return executeTool(name, input, childCtx);
|
|
5170
|
+
}
|
|
5171
|
+
if (opts.enableWrite && RENDER_WRITE_TOOL_NAMES.has(name)) {
|
|
5172
|
+
return executeTool(name, input, childCtx);
|
|
5173
|
+
}
|
|
5174
|
+
return executeDesignExpertTool(name, input, childCtx, toolCallId, onLog);
|
|
5175
|
+
},
|
|
5176
|
+
apiConfig: context.apiConfig,
|
|
5177
|
+
model: resolveModel("visualDesignExpert", context.models, context.model),
|
|
5178
|
+
subAgentId: "visualDesignExpert",
|
|
5179
|
+
signal: context.signal,
|
|
5180
|
+
parentToolId: context.toolCallId,
|
|
5181
|
+
requestId: context.requestId,
|
|
5182
|
+
onEvent: context.onEvent,
|
|
5183
|
+
resolveExternalTool: context.resolveExternalTool,
|
|
5184
|
+
toolRegistry: context.toolRegistry,
|
|
5185
|
+
background: opts.background,
|
|
5186
|
+
onBackgroundComplete: opts.background ? (bgResult) => {
|
|
5187
|
+
context.onBackgroundComplete?.(
|
|
5188
|
+
context.toolCallId,
|
|
5189
|
+
opts.reportingName ?? "visualDesignExpert",
|
|
5190
|
+
bgResult.text,
|
|
5191
|
+
bgResult.messages
|
|
5192
|
+
);
|
|
5193
|
+
} : void 0
|
|
5194
|
+
});
|
|
5195
|
+
}
|
|
5125
5196
|
var designExpertTool = {
|
|
5126
5197
|
clearable: false,
|
|
5127
5198
|
definition: {
|
|
@@ -5146,49 +5217,20 @@ var designExpertTool = {
|
|
|
5146
5217
|
if (!context) {
|
|
5147
5218
|
return "Error: visual design expert requires execution context";
|
|
5148
5219
|
}
|
|
5149
|
-
const
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
history: history.length > 0 ? history : void 0,
|
|
5154
|
-
tools: DESIGN_EXPERT_TOOLS,
|
|
5155
|
-
externalTools: /* @__PURE__ */ new Set(),
|
|
5156
|
-
executeTool: (name, input2, toolCallId, onLog, sams) => {
|
|
5157
|
-
const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
|
|
5158
|
-
if (COMMON_READ_TOOL_NAMES.has(name)) {
|
|
5159
|
-
return executeTool(name, input2, childCtx);
|
|
5160
|
-
}
|
|
5161
|
-
return executeDesignExpertTool(
|
|
5162
|
-
name,
|
|
5163
|
-
input2,
|
|
5164
|
-
childCtx,
|
|
5165
|
-
toolCallId,
|
|
5166
|
-
onLog
|
|
5167
|
-
);
|
|
5220
|
+
const result = await runDesignExpert(
|
|
5221
|
+
{
|
|
5222
|
+
task: input.task,
|
|
5223
|
+
background: input.background
|
|
5168
5224
|
},
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
subAgentId: "visualDesignExpert",
|
|
5172
|
-
signal: context.signal,
|
|
5173
|
-
parentToolId: context.toolCallId,
|
|
5174
|
-
requestId: context.requestId,
|
|
5175
|
-
onEvent: context.onEvent,
|
|
5176
|
-
resolveExternalTool: context.resolveExternalTool,
|
|
5177
|
-
toolRegistry: context.toolRegistry,
|
|
5178
|
-
background: input.background,
|
|
5179
|
-
onBackgroundComplete: input.background ? (bgResult) => {
|
|
5180
|
-
context.onBackgroundComplete?.(
|
|
5181
|
-
context.toolCallId,
|
|
5182
|
-
"visualDesignExpert",
|
|
5183
|
-
bgResult.text,
|
|
5184
|
-
bgResult.messages
|
|
5185
|
-
);
|
|
5186
|
-
} : void 0
|
|
5187
|
-
});
|
|
5225
|
+
context
|
|
5226
|
+
);
|
|
5188
5227
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
5189
5228
|
return result.text;
|
|
5190
5229
|
}
|
|
5191
5230
|
};
|
|
5231
|
+
async function runDesignExpertRender(opts, context) {
|
|
5232
|
+
return runDesignExpert({ ...opts, enableWrite: true }, context);
|
|
5233
|
+
}
|
|
5192
5234
|
|
|
5193
5235
|
// src/subagents/productVision/tools.ts
|
|
5194
5236
|
var VISION_TOOLS = [
|
|
@@ -5293,16 +5335,25 @@ ${unifiedDiff(filePath, oldContent, "")}`;
|
|
|
5293
5335
|
const filePath = resolve("pitch.html");
|
|
5294
5336
|
try {
|
|
5295
5337
|
fs19.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
5296
|
-
const
|
|
5297
|
-
const
|
|
5338
|
+
const exists = fs19.existsSync(filePath);
|
|
5339
|
+
const before = exists ? fs19.statSync(filePath).mtimeMs : null;
|
|
5340
|
+
const delivery = exists ? `### Your deliverable
|
|
5341
|
+
The pitch deck already exists at \`${filePath}\`. Read it, then update it for the new <pitch_content>, keeping the presentation scaffolding intact \u2014 change only what needs to change.
|
|
5342
|
+
|
|
5343
|
+
Reply with a one-line summary of what you changed \u2014 not the HTML.` : `### Your deliverable
|
|
5344
|
+
Write the complete pitch deck to \`${filePath}\`. It does not exist yet \u2014 start from this scaffold, keeping its progress bar, chevron navigation, keyboard navigation, and transition mechanics intact:
|
|
5345
|
+
|
|
5346
|
+
<pitch_deck_shell>
|
|
5347
|
+
${PITCH_DECK_SHELL}
|
|
5348
|
+
</pitch_deck_shell>
|
|
5349
|
+
|
|
5350
|
+
Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
|
|
5298
5351
|
const task = `
|
|
5299
5352
|
<pitch_content>${input.task}</pitch_content>
|
|
5300
5353
|
|
|
5301
|
-
<current_deck>${currentDeck}</current_deck>
|
|
5302
|
-
|
|
5303
5354
|
We are building the pitch deck for the app. Using the provided <pitch_content>, as well as the app's spec data, think about what would make a compelling, interactive, self-contained horizontally-scrolling HTML slide deck for this product. Keep it simple, clean, powerful. Giant text, large logo, big, bold stats and claims. Edit the content as necessary to create the most impactful, bold, and beautiful slides. This should not feel like an essay, and it should not feel like a landing page \u2014 it should feel like a modern interactive presentation that leaves the user wowed by the product and excited about its future.
|
|
5304
5355
|
|
|
5305
|
-
|
|
5356
|
+
Maintain the bones of the presentation scaffolding. Always keep the progress bar, chevron navigation, and keyboard navigation - they are part of the scaffold.
|
|
5306
5357
|
|
|
5307
5358
|
### Rules
|
|
5308
5359
|
- The deck must be a single HTML file \u2014 it will be rendered in an iframe.
|
|
@@ -5312,14 +5363,18 @@ Use <current_deck> as your starting point and replace or update the content as n
|
|
|
5312
5363
|
- Code must be clean, bug free, and easy to parse. Use GSAP for animations. Pay close attention to layout and alignment to make sure everything is perfect.
|
|
5313
5364
|
- Keep the progress bar and edge chevrons from the shell \u2014 they are part of the navigation UX.
|
|
5314
5365
|
|
|
5315
|
-
|
|
5316
|
-
const result = await
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5366
|
+
${delivery}`;
|
|
5367
|
+
const result = await runDesignExpertRender({ task }, context);
|
|
5368
|
+
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
5369
|
+
if (!fs19.existsSync(filePath)) {
|
|
5370
|
+
return `Error: the design expert did not write ${filePath}. Its reply was:
|
|
5371
|
+
${result.text}`;
|
|
5372
|
+
}
|
|
5373
|
+
if (before !== null && fs19.statSync(filePath).mtimeMs === before) {
|
|
5374
|
+
return `Error: the pitch deck at ${filePath} was not modified. The design expert's reply was:
|
|
5375
|
+
${result.text}`;
|
|
5376
|
+
}
|
|
5377
|
+
return `Pitch deck written to ${filePath}. ${result.text}`;
|
|
5323
5378
|
} catch (err) {
|
|
5324
5379
|
return `Error generating pitch deck: ${err.message}`;
|
|
5325
5380
|
}
|
|
@@ -5553,7 +5608,7 @@ import fs20 from "fs";
|
|
|
5553
5608
|
var OVERVIEW_FILE = "src/overview.html";
|
|
5554
5609
|
var DESIGN_BRIEF = `We are building the Build Overview for this app \u2014 the home page of its Spec tab. It is a calm, dense, one-page reference of everything the app actually contains, including the parts the user can't see. It renders flush inside the Spec tab's content panel (the IDE supplies the surrounding nav).
|
|
5555
5610
|
|
|
5556
|
-
Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand.
|
|
5611
|
+
Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand.
|
|
5557
5612
|
|
|
5558
5613
|
### The single hard rule
|
|
5559
5614
|
The copy in <overview_copy> is final \u2014 it was authored and edited before it reached you. Treat it as locked content to typeset, not a draft to improve. Reproduce the words exactly: do not rewrite, rephrase, shorten, expand, reorder, or "polish" them, and do not run them through any copy tool. This is the opposite of your usual role \u2014 here you own layout, typography, and visual design only, and the words (every number, name, label, claim, and sentence) are fixed. A single changed word or wrong number breaks this document's purpose.
|
|
@@ -5568,9 +5623,7 @@ The copy in <overview_copy> is final \u2014 it was authored and edited before it
|
|
|
5568
5623
|
|
|
5569
5624
|
### Constraints
|
|
5570
5625
|
- A single self-contained HTML file. Fonts may load from a CDN; everything else (CSS, the logo SVG) is inline.
|
|
5571
|
-
- Responsive: fills the embedded panel width and collapses gracefully at narrow widths
|
|
5572
|
-
|
|
5573
|
-
Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to src/overview.html.`;
|
|
5626
|
+
- Responsive: fills the embedded panel width and collapses gracefully at narrow widths.`;
|
|
5574
5627
|
var OVERVIEW_SHELL = `<!DOCTYPE html>
|
|
5575
5628
|
<html lang="en">
|
|
5576
5629
|
<head>
|
|
@@ -5591,6 +5644,22 @@ var OVERVIEW_SHELL = `<!DOCTYPE html>
|
|
|
5591
5644
|
app's spec. -->
|
|
5592
5645
|
</body>
|
|
5593
5646
|
</html>`;
|
|
5647
|
+
function initialDelivery() {
|
|
5648
|
+
return `### Your deliverable
|
|
5649
|
+
Write the complete Build Overview to \`${OVERVIEW_FILE}\`. The file does not exist yet \u2014 start from this scaffold, which carries the technical hygiene for the iframed render context (keep the viewport meta and the reset). Layout, sections, type, and styling are yours to compose.
|
|
5650
|
+
|
|
5651
|
+
<overview_shell>
|
|
5652
|
+
${OVERVIEW_SHELL}
|
|
5653
|
+
</overview_shell>
|
|
5654
|
+
|
|
5655
|
+
Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
|
|
5656
|
+
}
|
|
5657
|
+
function refreshDelivery() {
|
|
5658
|
+
return `### Your deliverable
|
|
5659
|
+
The Build Overview already exists at \`${OVERVIEW_FILE}\`. Read it, then update it to reflect <overview_copy>, preserving its established skin \u2014 change only what the copy changed.
|
|
5660
|
+
|
|
5661
|
+
Reply with a one-line summary of what you changed \u2014 not the HTML.`;
|
|
5662
|
+
}
|
|
5594
5663
|
var buildOverviewTool = {
|
|
5595
5664
|
clearable: false,
|
|
5596
5665
|
definition: {
|
|
@@ -5615,21 +5684,29 @@ var buildOverviewTool = {
|
|
|
5615
5684
|
if (!content) {
|
|
5616
5685
|
return "Error: writeBuildOverview requires non-empty `content` (the overview copy).";
|
|
5617
5686
|
}
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
const currentOverview = existing || OVERVIEW_SHELL;
|
|
5621
|
-
const task = `<overview_copy>${content}</overview_copy>
|
|
5687
|
+
const exists = fs20.existsSync(OVERVIEW_FILE);
|
|
5688
|
+
const task = `<overview_copy>${content}</overview_copy>
|
|
5622
5689
|
|
|
5623
|
-
|
|
5690
|
+
${DESIGN_BRIEF}
|
|
5624
5691
|
|
|
5625
|
-
${
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5692
|
+
${exists ? refreshDelivery() : initialDelivery()}`;
|
|
5693
|
+
try {
|
|
5694
|
+
if (exists) {
|
|
5695
|
+
input.background = true;
|
|
5696
|
+
const result2 = await runDesignExpertRender(
|
|
5697
|
+
{ task, background: true, reportingName: "writeBuildOverview" },
|
|
5698
|
+
context
|
|
5699
|
+
);
|
|
5700
|
+
context.subAgentMessages?.set(context.toolCallId, result2.messages);
|
|
5701
|
+
return result2.text;
|
|
5702
|
+
}
|
|
5703
|
+
const result = await runDesignExpertRender({ task }, context);
|
|
5704
|
+
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
5705
|
+
if (!fs20.existsSync(OVERVIEW_FILE)) {
|
|
5706
|
+
return `Error: the design expert did not write ${OVERVIEW_FILE}. Its reply was:
|
|
5707
|
+
${result.text}`;
|
|
5708
|
+
}
|
|
5709
|
+
return `Build overview written to ${OVERVIEW_FILE}. ${result.text}`;
|
|
5633
5710
|
} catch (err) {
|
|
5634
5711
|
return `Error generating build overview: ${err.message}`;
|
|
5635
5712
|
}
|
|
@@ -6351,21 +6428,6 @@ function triggerBrandExtraction(apiConfig, model) {
|
|
|
6351
6428
|
// src/session.ts
|
|
6352
6429
|
import fs22 from "fs";
|
|
6353
6430
|
import path11 from "path";
|
|
6354
|
-
|
|
6355
|
-
// src/toolResultCap.ts
|
|
6356
|
-
var MAX_TOOL_RESULT_BYTES = 256 * 1024;
|
|
6357
|
-
function capToolResult(result) {
|
|
6358
|
-
const total = Buffer.byteLength(result, "utf-8");
|
|
6359
|
-
if (total <= MAX_TOOL_RESULT_BYTES) {
|
|
6360
|
-
return result;
|
|
6361
|
-
}
|
|
6362
|
-
const head = Buffer.from(result, "utf-8").subarray(0, MAX_TOOL_RESULT_BYTES).toString("utf-8");
|
|
6363
|
-
return head + `
|
|
6364
|
-
|
|
6365
|
-
(tool result truncated at ${(MAX_TOOL_RESULT_BYTES / 1024).toFixed(0)}KB of ${(total / 1024).toFixed(0)}KB \u2014 too large to keep in context. Narrow the call (select fewer fields, paginate, or query a subset) instead of fetching everything.)`;
|
|
6366
|
-
}
|
|
6367
|
-
|
|
6368
|
-
// src/session.ts
|
|
6369
6431
|
var log12 = createLogger("session");
|
|
6370
6432
|
var SESSION_FILE = ".remy-session.json";
|
|
6371
6433
|
var ARCHIVE_DIR = ".logs/sessions";
|
package/dist/index.js
CHANGED
|
@@ -3513,6 +3513,25 @@ ${partial}` : "[INTERRUPTED] Tool execution was stopped.";
|
|
|
3513
3513
|
}
|
|
3514
3514
|
});
|
|
3515
3515
|
|
|
3516
|
+
// src/toolResultCap.ts
|
|
3517
|
+
function capToolResult(result) {
|
|
3518
|
+
const total = Buffer.byteLength(result, "utf-8");
|
|
3519
|
+
if (total <= MAX_TOOL_RESULT_BYTES) {
|
|
3520
|
+
return result;
|
|
3521
|
+
}
|
|
3522
|
+
const head = Buffer.from(result, "utf-8").subarray(0, MAX_TOOL_RESULT_BYTES).toString("utf-8");
|
|
3523
|
+
return head + `
|
|
3524
|
+
|
|
3525
|
+
(tool result truncated at ${(MAX_TOOL_RESULT_BYTES / 1024).toFixed(0)}KB of ${(total / 1024).toFixed(0)}KB \u2014 too large to keep in context. Narrow the call (select fewer fields, paginate, or query a subset) instead of fetching everything.)`;
|
|
3526
|
+
}
|
|
3527
|
+
var MAX_TOOL_RESULT_BYTES;
|
|
3528
|
+
var init_toolResultCap = __esm({
|
|
3529
|
+
"src/toolResultCap.ts"() {
|
|
3530
|
+
"use strict";
|
|
3531
|
+
MAX_TOOL_RESULT_BYTES = 256 * 1024;
|
|
3532
|
+
}
|
|
3533
|
+
});
|
|
3534
|
+
|
|
3516
3535
|
// src/statusWatcher.ts
|
|
3517
3536
|
function startStatusWatcher(config) {
|
|
3518
3537
|
const { apiConfig, getContext, onStatus, interval = 5e3, signal } = config;
|
|
@@ -4053,7 +4072,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
4053
4072
|
subAgentMessages
|
|
4054
4073
|
);
|
|
4055
4074
|
}
|
|
4056
|
-
safeSettle(result, result.startsWith("Error"));
|
|
4075
|
+
safeSettle(capToolResult(result), result.startsWith("Error"));
|
|
4057
4076
|
} catch (err) {
|
|
4058
4077
|
safeSettle(`Error: ${err.message}`, true);
|
|
4059
4078
|
}
|
|
@@ -4189,6 +4208,7 @@ var init_runner = __esm({
|
|
|
4189
4208
|
init_logger();
|
|
4190
4209
|
init_usageLedger();
|
|
4191
4210
|
init_toolRegistry();
|
|
4211
|
+
init_toolResultCap();
|
|
4192
4212
|
init_statusWatcher();
|
|
4193
4213
|
init_cleanMessages();
|
|
4194
4214
|
log7 = createLogger("sub-agent");
|
|
@@ -4258,9 +4278,10 @@ var init_tools = __esm({
|
|
|
4258
4278
|
"evaluate",
|
|
4259
4279
|
"styles",
|
|
4260
4280
|
"screenshotFullPage",
|
|
4261
|
-
"screenshotViewport"
|
|
4281
|
+
"screenshotViewport",
|
|
4282
|
+
"setViewport"
|
|
4262
4283
|
],
|
|
4263
|
-
description:
|
|
4284
|
+
description: 'snapshot: accessibility tree of the page (waits for network to settle). click: click an element (animated cursor, full event sequence). type: type text into input (one char at a time, works with React/Vue/Svelte). select: select a dropdown option by text. wait: wait for an element to appear (polls 100ms, waits for network). navigate: navigate to a URL within the app (waits for load, subsequent steps run on new page). evaluate: run JS in the page. styles: read computed CSS styles from elements (pass properties array with camelCase names, or omit for defaults). screenshotFullPage: full-page viewport-stitched screenshot (returns CDN url with dimensions). screenshotViewport: screenshot of just the visible viewport \u2014 pass `scrollToSelector` (or `scrollY`) on this step to scroll a section into view and capture it in one atomic step (no separate scroll needed). setViewport: switch the browser between desktop and mobile rendering (pass `mode`: "desktop" or "mobile"). Reloads the page so responsive layouts, media queries, and matchMedia re-evaluate \u2014 use it to QA mobile/responsive views.'
|
|
4264
4285
|
},
|
|
4265
4286
|
ref: {
|
|
4266
4287
|
type: "string",
|
|
@@ -4314,6 +4335,11 @@ var init_tools = __esm({
|
|
|
4314
4335
|
scrollY: {
|
|
4315
4336
|
type: "number",
|
|
4316
4337
|
description: "For screenshotViewport: absolute Y offset to scroll to before the shot, when no selector is available."
|
|
4338
|
+
},
|
|
4339
|
+
mode: {
|
|
4340
|
+
type: "string",
|
|
4341
|
+
enum: ["desktop", "mobile"],
|
|
4342
|
+
description: 'For setViewport: the rendering mode to switch to. "mobile" emulates a phone (narrow width, touch, device pixel ratio); "desktop" is the standard wide viewport.'
|
|
4317
4343
|
}
|
|
4318
4344
|
},
|
|
4319
4345
|
required: ["command"]
|
|
@@ -4371,6 +4397,14 @@ var init_prompt2 = __esm({
|
|
|
4371
4397
|
async function runBrowserAutomation(task, context, opts) {
|
|
4372
4398
|
const release = await acquireBrowserLock();
|
|
4373
4399
|
try {
|
|
4400
|
+
try {
|
|
4401
|
+
await sidecarRequest(
|
|
4402
|
+
"/set-viewport",
|
|
4403
|
+
{ mode: "default" },
|
|
4404
|
+
{ timeout: 2e4 }
|
|
4405
|
+
);
|
|
4406
|
+
} catch {
|
|
4407
|
+
}
|
|
4374
4408
|
let lastBrowserCommandViewport;
|
|
4375
4409
|
const result = await runSubAgent({
|
|
4376
4410
|
system: getBrowserAutomationPrompt(),
|
|
@@ -5988,7 +6022,48 @@ var init_history = __esm({
|
|
|
5988
6022
|
});
|
|
5989
6023
|
|
|
5990
6024
|
// src/subagents/designExpert/index.ts
|
|
5991
|
-
|
|
6025
|
+
async function runDesignExpert(opts, context) {
|
|
6026
|
+
const history = context.conversationMessages ? getSubAgentHistory(context.conversationMessages, "visualDesignExpert") : [];
|
|
6027
|
+
return runSubAgent({
|
|
6028
|
+
system: getDesignExpertPrompt(context.onboardingState),
|
|
6029
|
+
task: opts.task,
|
|
6030
|
+
history: history.length > 0 ? history : void 0,
|
|
6031
|
+
tools: opts.enableWrite ? DESIGN_EXPERT_RENDER_TOOLS : DESIGN_EXPERT_TOOLS,
|
|
6032
|
+
externalTools: /* @__PURE__ */ new Set(),
|
|
6033
|
+
executeTool: (name, input, toolCallId, onLog, sams) => {
|
|
6034
|
+
const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
|
|
6035
|
+
if (COMMON_READ_TOOL_NAMES.has(name)) {
|
|
6036
|
+
return executeTool(name, input, childCtx);
|
|
6037
|
+
}
|
|
6038
|
+
if (opts.enableWrite && RENDER_WRITE_TOOL_NAMES.has(name)) {
|
|
6039
|
+
return executeTool(name, input, childCtx);
|
|
6040
|
+
}
|
|
6041
|
+
return executeDesignExpertTool(name, input, childCtx, toolCallId, onLog);
|
|
6042
|
+
},
|
|
6043
|
+
apiConfig: context.apiConfig,
|
|
6044
|
+
model: resolveModel("visualDesignExpert", context.models, context.model),
|
|
6045
|
+
subAgentId: "visualDesignExpert",
|
|
6046
|
+
signal: context.signal,
|
|
6047
|
+
parentToolId: context.toolCallId,
|
|
6048
|
+
requestId: context.requestId,
|
|
6049
|
+
onEvent: context.onEvent,
|
|
6050
|
+
resolveExternalTool: context.resolveExternalTool,
|
|
6051
|
+
toolRegistry: context.toolRegistry,
|
|
6052
|
+
background: opts.background,
|
|
6053
|
+
onBackgroundComplete: opts.background ? (bgResult) => {
|
|
6054
|
+
context.onBackgroundComplete?.(
|
|
6055
|
+
context.toolCallId,
|
|
6056
|
+
opts.reportingName ?? "visualDesignExpert",
|
|
6057
|
+
bgResult.text,
|
|
6058
|
+
bgResult.messages
|
|
6059
|
+
);
|
|
6060
|
+
} : void 0
|
|
6061
|
+
});
|
|
6062
|
+
}
|
|
6063
|
+
async function runDesignExpertRender(opts, context) {
|
|
6064
|
+
return runDesignExpert({ ...opts, enableWrite: true }, context);
|
|
6065
|
+
}
|
|
6066
|
+
var DESCRIPTION, RENDER_WRITE_TOOL_NAMES, DESIGN_EXPERT_RENDER_TOOLS, designExpertTool;
|
|
5992
6067
|
var init_designExpert = __esm({
|
|
5993
6068
|
"src/subagents/designExpert/index.ts"() {
|
|
5994
6069
|
"use strict";
|
|
@@ -5999,9 +6074,17 @@ var init_designExpert = __esm({
|
|
|
5999
6074
|
init_prompt3();
|
|
6000
6075
|
init_history();
|
|
6001
6076
|
init_surfaces();
|
|
6077
|
+
init_writeFile();
|
|
6078
|
+
init_editFile();
|
|
6002
6079
|
DESCRIPTION = `
|
|
6003
6080
|
Visual design expert. Describe the situation and what you need \u2014 the agent decides what to deliver. It reads the spec files automatically. Include relevant user requirements and context it can't get from the spec, but do not list specific deliverables or tell it how to do its job. Do not suggest implementation details or ideas - only relay what is needed.
|
|
6004
6081
|
`.trim();
|
|
6082
|
+
RENDER_WRITE_TOOL_NAMES = /* @__PURE__ */ new Set(["writeFile", "editFile"]);
|
|
6083
|
+
DESIGN_EXPERT_RENDER_TOOLS = [
|
|
6084
|
+
...DESIGN_EXPERT_TOOLS,
|
|
6085
|
+
writeFileTool.definition,
|
|
6086
|
+
editFileTool.definition
|
|
6087
|
+
];
|
|
6005
6088
|
designExpertTool = {
|
|
6006
6089
|
clearable: false,
|
|
6007
6090
|
definition: {
|
|
@@ -6026,45 +6109,13 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
|
|
|
6026
6109
|
if (!context) {
|
|
6027
6110
|
return "Error: visual design expert requires execution context";
|
|
6028
6111
|
}
|
|
6029
|
-
const
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
history: history.length > 0 ? history : void 0,
|
|
6034
|
-
tools: DESIGN_EXPERT_TOOLS,
|
|
6035
|
-
externalTools: /* @__PURE__ */ new Set(),
|
|
6036
|
-
executeTool: (name, input2, toolCallId, onLog, sams) => {
|
|
6037
|
-
const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
|
|
6038
|
-
if (COMMON_READ_TOOL_NAMES.has(name)) {
|
|
6039
|
-
return executeTool(name, input2, childCtx);
|
|
6040
|
-
}
|
|
6041
|
-
return executeDesignExpertTool(
|
|
6042
|
-
name,
|
|
6043
|
-
input2,
|
|
6044
|
-
childCtx,
|
|
6045
|
-
toolCallId,
|
|
6046
|
-
onLog
|
|
6047
|
-
);
|
|
6112
|
+
const result = await runDesignExpert(
|
|
6113
|
+
{
|
|
6114
|
+
task: input.task,
|
|
6115
|
+
background: input.background
|
|
6048
6116
|
},
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
subAgentId: "visualDesignExpert",
|
|
6052
|
-
signal: context.signal,
|
|
6053
|
-
parentToolId: context.toolCallId,
|
|
6054
|
-
requestId: context.requestId,
|
|
6055
|
-
onEvent: context.onEvent,
|
|
6056
|
-
resolveExternalTool: context.resolveExternalTool,
|
|
6057
|
-
toolRegistry: context.toolRegistry,
|
|
6058
|
-
background: input.background,
|
|
6059
|
-
onBackgroundComplete: input.background ? (bgResult) => {
|
|
6060
|
-
context.onBackgroundComplete?.(
|
|
6061
|
-
context.toolCallId,
|
|
6062
|
-
"visualDesignExpert",
|
|
6063
|
-
bgResult.text,
|
|
6064
|
-
bgResult.messages
|
|
6065
|
-
);
|
|
6066
|
-
} : void 0
|
|
6067
|
-
});
|
|
6117
|
+
context
|
|
6118
|
+
);
|
|
6068
6119
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
6069
6120
|
return result.text;
|
|
6070
6121
|
}
|
|
@@ -6177,16 +6228,25 @@ ${unifiedDiff(filePath, oldContent, "")}`;
|
|
|
6177
6228
|
const filePath = resolve("pitch.html");
|
|
6178
6229
|
try {
|
|
6179
6230
|
fs18.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
6180
|
-
const
|
|
6181
|
-
const
|
|
6231
|
+
const exists = fs18.existsSync(filePath);
|
|
6232
|
+
const before = exists ? fs18.statSync(filePath).mtimeMs : null;
|
|
6233
|
+
const delivery = exists ? `### Your deliverable
|
|
6234
|
+
The pitch deck already exists at \`${filePath}\`. Read it, then update it for the new <pitch_content>, keeping the presentation scaffolding intact \u2014 change only what needs to change.
|
|
6235
|
+
|
|
6236
|
+
Reply with a one-line summary of what you changed \u2014 not the HTML.` : `### Your deliverable
|
|
6237
|
+
Write the complete pitch deck to \`${filePath}\`. It does not exist yet \u2014 start from this scaffold, keeping its progress bar, chevron navigation, keyboard navigation, and transition mechanics intact:
|
|
6238
|
+
|
|
6239
|
+
<pitch_deck_shell>
|
|
6240
|
+
${PITCH_DECK_SHELL}
|
|
6241
|
+
</pitch_deck_shell>
|
|
6242
|
+
|
|
6243
|
+
Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
|
|
6182
6244
|
const task = `
|
|
6183
6245
|
<pitch_content>${input.task}</pitch_content>
|
|
6184
6246
|
|
|
6185
|
-
<current_deck>${currentDeck}</current_deck>
|
|
6186
|
-
|
|
6187
6247
|
We are building the pitch deck for the app. Using the provided <pitch_content>, as well as the app's spec data, think about what would make a compelling, interactive, self-contained horizontally-scrolling HTML slide deck for this product. Keep it simple, clean, powerful. Giant text, large logo, big, bold stats and claims. Edit the content as necessary to create the most impactful, bold, and beautiful slides. This should not feel like an essay, and it should not feel like a landing page \u2014 it should feel like a modern interactive presentation that leaves the user wowed by the product and excited about its future.
|
|
6188
6248
|
|
|
6189
|
-
|
|
6249
|
+
Maintain the bones of the presentation scaffolding. Always keep the progress bar, chevron navigation, and keyboard navigation - they are part of the scaffold.
|
|
6190
6250
|
|
|
6191
6251
|
### Rules
|
|
6192
6252
|
- The deck must be a single HTML file \u2014 it will be rendered in an iframe.
|
|
@@ -6196,14 +6256,18 @@ Use <current_deck> as your starting point and replace or update the content as n
|
|
|
6196
6256
|
- Code must be clean, bug free, and easy to parse. Use GSAP for animations. Pay close attention to layout and alignment to make sure everything is perfect.
|
|
6197
6257
|
- Keep the progress bar and edge chevrons from the shell \u2014 they are part of the navigation UX.
|
|
6198
6258
|
|
|
6199
|
-
|
|
6200
|
-
const result = await
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6259
|
+
${delivery}`;
|
|
6260
|
+
const result = await runDesignExpertRender({ task }, context);
|
|
6261
|
+
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
6262
|
+
if (!fs18.existsSync(filePath)) {
|
|
6263
|
+
return `Error: the design expert did not write ${filePath}. Its reply was:
|
|
6264
|
+
${result.text}`;
|
|
6265
|
+
}
|
|
6266
|
+
if (before !== null && fs18.statSync(filePath).mtimeMs === before) {
|
|
6267
|
+
return `Error: the pitch deck at ${filePath} was not modified. The design expert's reply was:
|
|
6268
|
+
${result.text}`;
|
|
6269
|
+
}
|
|
6270
|
+
return `Pitch deck written to ${filePath}. ${result.text}`;
|
|
6207
6271
|
} catch (err) {
|
|
6208
6272
|
return `Error generating pitch deck: ${err.message}`;
|
|
6209
6273
|
}
|
|
@@ -6498,6 +6562,22 @@ var init_scrapeWebUrl2 = __esm({
|
|
|
6498
6562
|
|
|
6499
6563
|
// src/tools/spec/writeBuildOverview.ts
|
|
6500
6564
|
import fs19 from "fs";
|
|
6565
|
+
function initialDelivery() {
|
|
6566
|
+
return `### Your deliverable
|
|
6567
|
+
Write the complete Build Overview to \`${OVERVIEW_FILE}\`. The file does not exist yet \u2014 start from this scaffold, which carries the technical hygiene for the iframed render context (keep the viewport meta and the reset). Layout, sections, type, and styling are yours to compose.
|
|
6568
|
+
|
|
6569
|
+
<overview_shell>
|
|
6570
|
+
${OVERVIEW_SHELL}
|
|
6571
|
+
</overview_shell>
|
|
6572
|
+
|
|
6573
|
+
Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
|
|
6574
|
+
}
|
|
6575
|
+
function refreshDelivery() {
|
|
6576
|
+
return `### Your deliverable
|
|
6577
|
+
The Build Overview already exists at \`${OVERVIEW_FILE}\`. Read it, then update it to reflect <overview_copy>, preserving its established skin \u2014 change only what the copy changed.
|
|
6578
|
+
|
|
6579
|
+
Reply with a one-line summary of what you changed \u2014 not the HTML.`;
|
|
6580
|
+
}
|
|
6501
6581
|
var OVERVIEW_FILE, DESIGN_BRIEF, OVERVIEW_SHELL, buildOverviewTool;
|
|
6502
6582
|
var init_writeBuildOverview = __esm({
|
|
6503
6583
|
"src/tools/spec/writeBuildOverview.ts"() {
|
|
@@ -6506,7 +6586,7 @@ var init_writeBuildOverview = __esm({
|
|
|
6506
6586
|
OVERVIEW_FILE = "src/overview.html";
|
|
6507
6587
|
DESIGN_BRIEF = `We are building the Build Overview for this app \u2014 the home page of its Spec tab. It is a calm, dense, one-page reference of everything the app actually contains, including the parts the user can't see. It renders flush inside the Spec tab's content panel (the IDE supplies the surrounding nav).
|
|
6508
6588
|
|
|
6509
|
-
Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand.
|
|
6589
|
+
Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand.
|
|
6510
6590
|
|
|
6511
6591
|
### The single hard rule
|
|
6512
6592
|
The copy in <overview_copy> is final \u2014 it was authored and edited before it reached you. Treat it as locked content to typeset, not a draft to improve. Reproduce the words exactly: do not rewrite, rephrase, shorten, expand, reorder, or "polish" them, and do not run them through any copy tool. This is the opposite of your usual role \u2014 here you own layout, typography, and visual design only, and the words (every number, name, label, claim, and sentence) are fixed. A single changed word or wrong number breaks this document's purpose.
|
|
@@ -6521,9 +6601,7 @@ The copy in <overview_copy> is final \u2014 it was authored and edited before it
|
|
|
6521
6601
|
|
|
6522
6602
|
### Constraints
|
|
6523
6603
|
- A single self-contained HTML file. Fonts may load from a CDN; everything else (CSS, the logo SVG) is inline.
|
|
6524
|
-
- Responsive: fills the embedded panel width and collapses gracefully at narrow widths
|
|
6525
|
-
|
|
6526
|
-
Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to src/overview.html.`;
|
|
6604
|
+
- Responsive: fills the embedded panel width and collapses gracefully at narrow widths.`;
|
|
6527
6605
|
OVERVIEW_SHELL = `<!DOCTYPE html>
|
|
6528
6606
|
<html lang="en">
|
|
6529
6607
|
<head>
|
|
@@ -6568,21 +6646,29 @@ Respond only with the complete HTML file and absolutely no other text. Your resp
|
|
|
6568
6646
|
if (!content) {
|
|
6569
6647
|
return "Error: writeBuildOverview requires non-empty `content` (the overview copy).";
|
|
6570
6648
|
}
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
const currentOverview = existing || OVERVIEW_SHELL;
|
|
6574
|
-
const task = `<overview_copy>${content}</overview_copy>
|
|
6649
|
+
const exists = fs19.existsSync(OVERVIEW_FILE);
|
|
6650
|
+
const task = `<overview_copy>${content}</overview_copy>
|
|
6575
6651
|
|
|
6576
|
-
|
|
6652
|
+
${DESIGN_BRIEF}
|
|
6577
6653
|
|
|
6578
|
-
${
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6654
|
+
${exists ? refreshDelivery() : initialDelivery()}`;
|
|
6655
|
+
try {
|
|
6656
|
+
if (exists) {
|
|
6657
|
+
input.background = true;
|
|
6658
|
+
const result2 = await runDesignExpertRender(
|
|
6659
|
+
{ task, background: true, reportingName: "writeBuildOverview" },
|
|
6660
|
+
context
|
|
6661
|
+
);
|
|
6662
|
+
context.subAgentMessages?.set(context.toolCallId, result2.messages);
|
|
6663
|
+
return result2.text;
|
|
6664
|
+
}
|
|
6665
|
+
const result = await runDesignExpertRender({ task }, context);
|
|
6666
|
+
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
6667
|
+
if (!fs19.existsSync(OVERVIEW_FILE)) {
|
|
6668
|
+
return `Error: the design expert did not write ${OVERVIEW_FILE}. Its reply was:
|
|
6669
|
+
${result.text}`;
|
|
6670
|
+
}
|
|
6671
|
+
return `Build overview written to ${OVERVIEW_FILE}. ${result.text}`;
|
|
6586
6672
|
} catch (err) {
|
|
6587
6673
|
return `Error generating build overview: ${err.message}`;
|
|
6588
6674
|
}
|
|
@@ -6703,25 +6789,6 @@ var init_tools7 = __esm({
|
|
|
6703
6789
|
}
|
|
6704
6790
|
});
|
|
6705
6791
|
|
|
6706
|
-
// src/toolResultCap.ts
|
|
6707
|
-
function capToolResult(result) {
|
|
6708
|
-
const total = Buffer.byteLength(result, "utf-8");
|
|
6709
|
-
if (total <= MAX_TOOL_RESULT_BYTES) {
|
|
6710
|
-
return result;
|
|
6711
|
-
}
|
|
6712
|
-
const head = Buffer.from(result, "utf-8").subarray(0, MAX_TOOL_RESULT_BYTES).toString("utf-8");
|
|
6713
|
-
return head + `
|
|
6714
|
-
|
|
6715
|
-
(tool result truncated at ${(MAX_TOOL_RESULT_BYTES / 1024).toFixed(0)}KB of ${(total / 1024).toFixed(0)}KB \u2014 too large to keep in context. Narrow the call (select fewer fields, paginate, or query a subset) instead of fetching everything.)`;
|
|
6716
|
-
}
|
|
6717
|
-
var MAX_TOOL_RESULT_BYTES;
|
|
6718
|
-
var init_toolResultCap = __esm({
|
|
6719
|
-
"src/toolResultCap.ts"() {
|
|
6720
|
-
"use strict";
|
|
6721
|
-
MAX_TOOL_RESULT_BYTES = 256 * 1024;
|
|
6722
|
-
}
|
|
6723
|
-
});
|
|
6724
|
-
|
|
6725
6792
|
// src/session.ts
|
|
6726
6793
|
import fs20 from "fs";
|
|
6727
6794
|
import path9 from "path";
|
|
@@ -44,6 +44,7 @@ Note: the snapshot concatenates inline text and strips whitespace. If you need t
|
|
|
44
44
|
- `evaluate`: Run arbitrary JavaScript in the page and return the result.
|
|
45
45
|
- `styles`: Read computed CSS styles from page elements. Pass a `properties` array with camelCase CSS property names (e.g., `["backgroundColor", "borderRadius", "fontSize"]`). Omit `properties` for a default set covering colors, typography, spacing, borders, shadows, dimensions, and layout. Uses the same targeting as click/type (ref, text, role, label, selector). Omit the target to get styles for all elements from the last snapshot.
|
|
46
46
|
- `screenshotViewport`: Take a screenshot of the visible viewport. Returns CDN url with full text analysis and dimensions. To capture a specific section, set `scrollToSelector` (a CSS selector) — or `scrollY` (an absolute offset) — on this same step; it scrolls the target into view and captures it atomically, so you do NOT need a separate scroll step. Do not use if you can get what you need with other tools - only use when you need to visually see the viewport.
|
|
47
|
+
- `setViewport`: Switch the browser between desktop and mobile rendering. Set `mode` to `"desktop"` or `"mobile"`. Mobile emulates a phone (390-wide, touch, device pixel ratio 2); desktop is the standard wide viewport. This reloads the page so media queries, responsive layouts, and `matchMedia` re-evaluate — the reload clears in-page state, so switch before you set up the state you want to inspect. The mode persists across navigations within a run. Each run starts in the app's default mode, so only use this when you need to check the other one.
|
|
47
48
|
|
|
48
49
|
### Element targeting (tried in order)
|
|
49
50
|
|
|
@@ -118,6 +119,16 @@ Capture a specific below-the-fold section (scroll + capture in one atomic step):
|
|
|
118
119
|
}
|
|
119
120
|
```
|
|
120
121
|
|
|
122
|
+
Check the mobile layout of a page:
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"steps": [
|
|
126
|
+
{ "command": "setViewport", "mode": "mobile" },
|
|
127
|
+
{ "command": "screenshotViewport" }
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
121
132
|
Navigate to a sub-page and interact with it:
|
|
122
133
|
```json
|
|
123
134
|
{
|