@mindstudio-ai/remy 0.1.126 → 0.1.127
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/automatedActions/publish.md +1 -1
- package/dist/headless.js +167 -190
- package/dist/index.js +170 -190
- package/dist/prompt/static/authoring.md +6 -9
- package/dist/prompt/static/team.md +1 -1
- package/dist/subagents/productVision/prompt.md +46 -11
- package/package.json +1 -1
|
@@ -12,6 +12,6 @@ If approved:
|
|
|
12
12
|
- Stage and commit any uncommitted changes with a clean, descriptive commit message
|
|
13
13
|
- Push to main
|
|
14
14
|
- Use `mindstudio-prod releases status --wait` to poll the build until it completes. Let the user know it's deploying, then report back when it's live.
|
|
15
|
-
- Once deployed, offer to help with next steps
|
|
15
|
+
- Once deployed, offer to help with next steps. This includes technical steps likesetting up a custom domain (`mindstudio-prod domains`), checking for errors (`mindstudio-prod requests stats`), seeding production data (`mindstudio-prod db`), managing env vars/secrets, or anything else they need for launch. It also includes going above and beyond and helping holistically. If it's the initial deploy, offer to help create collateral to announce the launch (e.g., an image for sharing on social media, text copy for a post, etc); if it's a meaningful incremental update, an annoucement post or something similar - go above and beyond here to help the user see that you care about the product from end-to-end, not just writing code! They will be appreciative, grateful, and pleased with your creativity here. Refer to the design guidance in the spec for how to talk about the product, and consider consulting the design expert to generate images or other marketing collateral.
|
|
16
16
|
|
|
17
17
|
If dismissed, acknowledge and do nothing.
|
package/dist/headless.js
CHANGED
|
@@ -583,13 +583,13 @@ async function* streamChat(params) {
|
|
|
583
583
|
}
|
|
584
584
|
}
|
|
585
585
|
}
|
|
586
|
-
var MAX_RETRIES =
|
|
586
|
+
var MAX_RETRIES = 5;
|
|
587
587
|
var INITIAL_BACKOFF_MS = 1e3;
|
|
588
588
|
function isRetryableError(error) {
|
|
589
589
|
return /Network error/i.test(error) || /HTTP 5\d\d/i.test(error) || /Stream stalled/i.test(error) || /overloaded/i.test(error) || /terminated/i.test(error);
|
|
590
590
|
}
|
|
591
591
|
function sleep(ms) {
|
|
592
|
-
return new Promise((
|
|
592
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
593
593
|
}
|
|
594
594
|
async function* streamChatWithRetry(params, options) {
|
|
595
595
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
@@ -1569,7 +1569,7 @@ var confirmDestructiveActionTool = {
|
|
|
1569
1569
|
// src/subagents/common/runCli.ts
|
|
1570
1570
|
import { spawn } from "child_process";
|
|
1571
1571
|
function runCli(cmd, options) {
|
|
1572
|
-
return new Promise((
|
|
1572
|
+
return new Promise((resolve2) => {
|
|
1573
1573
|
const timeout = options?.timeout ?? 6e4;
|
|
1574
1574
|
const maxBuffer = options?.maxBuffer ?? 1024 * 1024;
|
|
1575
1575
|
const cmdWithLogs = options?.jsonLogs && !cmd.includes("--json-logs") ? cmd.replace(/^(mindstudio\s+\S+)/, "$1 --json-logs") : cmd;
|
|
@@ -1635,15 +1635,15 @@ function runCli(cmd, options) {
|
|
|
1635
1635
|
const logBlock = !options?.onLog && logs.length > 0 ? logs.join("\n") + "\n\n" : "";
|
|
1636
1636
|
const out = stdout.trim();
|
|
1637
1637
|
if (out) {
|
|
1638
|
-
|
|
1638
|
+
resolve2(logBlock + out);
|
|
1639
1639
|
return;
|
|
1640
1640
|
}
|
|
1641
1641
|
if (code !== 0 || killed) {
|
|
1642
1642
|
const errMsg = stderr.trim() || (killed ? "Process timed out" : `Exit code ${code}`);
|
|
1643
|
-
|
|
1643
|
+
resolve2(logBlock + `Error: ${errMsg}`);
|
|
1644
1644
|
return;
|
|
1645
1645
|
}
|
|
1646
|
-
|
|
1646
|
+
resolve2(logBlock + "(no response)");
|
|
1647
1647
|
});
|
|
1648
1648
|
});
|
|
1649
1649
|
}
|
|
@@ -2077,7 +2077,7 @@ var bashTool = {
|
|
|
2077
2077
|
async execute(input, context) {
|
|
2078
2078
|
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines || DEFAULT_MAX_LINES3;
|
|
2079
2079
|
const timeoutMs = input.timeout ? input.timeout * 1e3 : DEFAULT_TIMEOUT_MS;
|
|
2080
|
-
return new Promise((
|
|
2080
|
+
return new Promise((resolve2) => {
|
|
2081
2081
|
const child = spawn2("sh", ["-c", input.command], {
|
|
2082
2082
|
cwd: input.cwd || void 0,
|
|
2083
2083
|
env: { ...process.env, FORCE_COLOR: "1" }
|
|
@@ -2100,26 +2100,26 @@ var bashTool = {
|
|
|
2100
2100
|
clearTimeout(timer);
|
|
2101
2101
|
if (!output) {
|
|
2102
2102
|
if (code && code !== 0) {
|
|
2103
|
-
|
|
2103
|
+
resolve2(`Error: process exited with code ${code}`);
|
|
2104
2104
|
} else {
|
|
2105
|
-
|
|
2105
|
+
resolve2("(no output)");
|
|
2106
2106
|
}
|
|
2107
2107
|
return;
|
|
2108
2108
|
}
|
|
2109
2109
|
const lines = output.split("\n");
|
|
2110
2110
|
if (lines.length > maxLines) {
|
|
2111
|
-
|
|
2111
|
+
resolve2(
|
|
2112
2112
|
lines.slice(0, maxLines).join("\n") + `
|
|
2113
2113
|
|
|
2114
2114
|
(truncated at ${maxLines} lines of ${lines.length} total \u2014 increase maxLines to see more)`
|
|
2115
2115
|
);
|
|
2116
2116
|
} else {
|
|
2117
|
-
|
|
2117
|
+
resolve2(output);
|
|
2118
2118
|
}
|
|
2119
2119
|
});
|
|
2120
2120
|
child.on("error", (err) => {
|
|
2121
2121
|
clearTimeout(timer);
|
|
2122
|
-
|
|
2122
|
+
resolve2(`Error: ${err.message}`);
|
|
2123
2123
|
});
|
|
2124
2124
|
});
|
|
2125
2125
|
}
|
|
@@ -2173,17 +2173,17 @@ var grepTool = {
|
|
|
2173
2173
|
const escaped = input.pattern.replace(/'/g, "'\\''");
|
|
2174
2174
|
const rgCmd = `rg -n --no-heading --max-count=${max}${globFlag} '${escaped}' ${searchPath}`;
|
|
2175
2175
|
const grepCmd = `grep -rn --max-count=${max} '${escaped}' ${searchPath} --include='*.ts' --include='*.tsx' --include='*.js' --include='*.json' --include='*.md'`;
|
|
2176
|
-
return new Promise((
|
|
2176
|
+
return new Promise((resolve2) => {
|
|
2177
2177
|
exec(rgCmd, { maxBuffer: 512 * 1024 }, (err, stdout) => {
|
|
2178
2178
|
if (stdout?.trim()) {
|
|
2179
|
-
|
|
2179
|
+
resolve2(formatResults(stdout, max));
|
|
2180
2180
|
return;
|
|
2181
2181
|
}
|
|
2182
2182
|
exec(grepCmd, { maxBuffer: 512 * 1024 }, (_err, grepStdout) => {
|
|
2183
2183
|
if (grepStdout?.trim()) {
|
|
2184
|
-
|
|
2184
|
+
resolve2(formatResults(grepStdout, max));
|
|
2185
2185
|
} else {
|
|
2186
|
-
|
|
2186
|
+
resolve2("No matches found.");
|
|
2187
2187
|
}
|
|
2188
2188
|
});
|
|
2189
2189
|
});
|
|
@@ -2431,7 +2431,7 @@ var restartProcessTool = {
|
|
|
2431
2431
|
async execute(input) {
|
|
2432
2432
|
const data = await lspRequest("/restart-process", { name: input.name });
|
|
2433
2433
|
if (data.ok) {
|
|
2434
|
-
await new Promise((
|
|
2434
|
+
await new Promise((resolve2) => setTimeout(resolve2, 5e3));
|
|
2435
2435
|
return `Restarted ${input.name}.`;
|
|
2436
2436
|
}
|
|
2437
2437
|
return `Error: unexpected response: ${JSON.stringify(data)}`;
|
|
@@ -2522,7 +2522,7 @@ var queryDatabaseTool = {
|
|
|
2522
2522
|
};
|
|
2523
2523
|
|
|
2524
2524
|
// src/subagents/common/analyzeImage.ts
|
|
2525
|
-
var VISION_MODEL = "
|
|
2525
|
+
var VISION_MODEL = "claude-4-6-sonnet";
|
|
2526
2526
|
var VISION_MODEL_OVERRIDE = JSON.stringify({
|
|
2527
2527
|
model: VISION_MODEL,
|
|
2528
2528
|
config: { thinkingBudget: "off" }
|
|
@@ -3763,10 +3763,10 @@ __export(generateImages_exports, {
|
|
|
3763
3763
|
});
|
|
3764
3764
|
|
|
3765
3765
|
// src/subagents/designExpert/tools/images/enhancePrompt.ts
|
|
3766
|
-
var ENHANCE_MODEL = "
|
|
3766
|
+
var ENHANCE_MODEL = "claude-4-6-sonnet";
|
|
3767
3767
|
var MODEL_OVERRIDE = JSON.stringify({
|
|
3768
3768
|
model: ENHANCE_MODEL,
|
|
3769
|
-
config: {
|
|
3769
|
+
config: { reasoning: "false" }
|
|
3770
3770
|
});
|
|
3771
3771
|
var SYSTEM_PROMPT = readAsset(
|
|
3772
3772
|
"subagents/designExpert/tools/images/enhance-image-prompt.md"
|
|
@@ -4014,7 +4014,8 @@ async function executeDesignExpertTool(name, input, context, toolCallId, onLog)
|
|
|
4014
4014
|
if (!tool) {
|
|
4015
4015
|
return `Error: unknown tool "${name}"`;
|
|
4016
4016
|
}
|
|
4017
|
-
|
|
4017
|
+
const childContext = context && toolCallId ? deriveContext(context, toolCallId) : context;
|
|
4018
|
+
return tool.execute(input, onLog, childContext);
|
|
4018
4019
|
}
|
|
4019
4020
|
|
|
4020
4021
|
// src/subagents/common/context.ts
|
|
@@ -4408,97 +4409,71 @@ var designExpertTool = {
|
|
|
4408
4409
|
// src/subagents/productVision/tools.ts
|
|
4409
4410
|
var VISION_TOOLS = [
|
|
4410
4411
|
{
|
|
4411
|
-
name: "
|
|
4412
|
-
description: "
|
|
4412
|
+
name: "listDir",
|
|
4413
|
+
description: "List files in src/roadmap/.",
|
|
4414
|
+
inputSchema: {
|
|
4415
|
+
type: "object",
|
|
4416
|
+
properties: {}
|
|
4417
|
+
}
|
|
4418
|
+
},
|
|
4419
|
+
{
|
|
4420
|
+
name: "readFile",
|
|
4421
|
+
description: 'Read a file from src/roadmap/. Path is relative to src/roadmap/ (e.g. "index.json", "mute.md").',
|
|
4413
4422
|
inputSchema: {
|
|
4414
4423
|
type: "object",
|
|
4415
4424
|
properties: {
|
|
4416
|
-
|
|
4417
|
-
type: "string",
|
|
4418
|
-
description: 'Kebab-case filename (without .md). e.g. "ai-weekly-digest"'
|
|
4419
|
-
},
|
|
4420
|
-
name: {
|
|
4421
|
-
type: "string",
|
|
4422
|
-
description: "User-facing feature name."
|
|
4423
|
-
},
|
|
4424
|
-
description: {
|
|
4425
|
-
type: "string",
|
|
4426
|
-
description: "Short user-facing summary (1-2 sentences)."
|
|
4427
|
-
},
|
|
4428
|
-
effort: {
|
|
4429
|
-
type: "string",
|
|
4430
|
-
enum: ["quick", "small", "medium", "large"]
|
|
4431
|
-
},
|
|
4432
|
-
requires: {
|
|
4433
|
-
type: "array",
|
|
4434
|
-
items: { type: "string" },
|
|
4435
|
-
description: "Slugs of prerequisite roadmap items. Empty array if independent."
|
|
4436
|
-
},
|
|
4437
|
-
body: {
|
|
4425
|
+
path: {
|
|
4438
4426
|
type: "string",
|
|
4439
|
-
description: "
|
|
4427
|
+
description: "File path relative to src/roadmap/."
|
|
4440
4428
|
}
|
|
4441
4429
|
},
|
|
4442
|
-
required: ["
|
|
4430
|
+
required: ["path"]
|
|
4443
4431
|
}
|
|
4444
4432
|
},
|
|
4445
4433
|
{
|
|
4446
|
-
name: "
|
|
4447
|
-
description:
|
|
4434
|
+
name: "writeFile",
|
|
4435
|
+
description: 'Create or overwrite a file in src/roadmap/. Path is relative to src/roadmap/ (e.g. "index.json", "ai-weekly-digest.md").',
|
|
4448
4436
|
inputSchema: {
|
|
4449
4437
|
type: "object",
|
|
4450
4438
|
properties: {
|
|
4451
|
-
|
|
4452
|
-
type: "string",
|
|
4453
|
-
description: "The slug of the item to update (filename without .md)."
|
|
4454
|
-
},
|
|
4455
|
-
status: {
|
|
4456
|
-
type: "string",
|
|
4457
|
-
enum: ["done", "in-progress", "not-started"],
|
|
4458
|
-
description: "New status."
|
|
4459
|
-
},
|
|
4460
|
-
name: {
|
|
4461
|
-
type: "string",
|
|
4462
|
-
description: "Updated feature name."
|
|
4463
|
-
},
|
|
4464
|
-
description: {
|
|
4465
|
-
type: "string",
|
|
4466
|
-
description: "Updated summary."
|
|
4467
|
-
},
|
|
4468
|
-
effort: {
|
|
4439
|
+
path: {
|
|
4469
4440
|
type: "string",
|
|
4470
|
-
|
|
4471
|
-
description: "Updated effort level."
|
|
4441
|
+
description: "File path relative to src/roadmap/."
|
|
4472
4442
|
},
|
|
4473
|
-
|
|
4474
|
-
type: "array",
|
|
4475
|
-
items: { type: "string" },
|
|
4476
|
-
description: "Updated prerequisites."
|
|
4477
|
-
},
|
|
4478
|
-
body: {
|
|
4443
|
+
content: {
|
|
4479
4444
|
type: "string",
|
|
4480
|
-
description: "
|
|
4481
|
-
}
|
|
4482
|
-
|
|
4445
|
+
description: "The full content to write to the file."
|
|
4446
|
+
}
|
|
4447
|
+
},
|
|
4448
|
+
required: ["path", "content"]
|
|
4449
|
+
}
|
|
4450
|
+
},
|
|
4451
|
+
{
|
|
4452
|
+
name: "deleteFile",
|
|
4453
|
+
description: "Delete a file from src/roadmap/. Path is relative to src/roadmap/.",
|
|
4454
|
+
inputSchema: {
|
|
4455
|
+
type: "object",
|
|
4456
|
+
properties: {
|
|
4457
|
+
path: {
|
|
4483
4458
|
type: "string",
|
|
4484
|
-
description:
|
|
4459
|
+
description: "File path relative to src/roadmap/."
|
|
4485
4460
|
}
|
|
4486
4461
|
},
|
|
4487
|
-
required: ["
|
|
4462
|
+
required: ["path"]
|
|
4488
4463
|
}
|
|
4489
4464
|
},
|
|
4490
4465
|
{
|
|
4491
|
-
name: "
|
|
4492
|
-
description: "
|
|
4466
|
+
name: "writePitchDeck",
|
|
4467
|
+
description: "Generate a branded HTML pitch deck for the product and save it to src/roadmap/pitch.html. Delegates to the design expert who builds a beautiful self-contained slide deck from your request. Do NOT describe the design or structure of the deck, only provide the copy.",
|
|
4493
4468
|
inputSchema: {
|
|
4494
4469
|
type: "object",
|
|
4495
4470
|
properties: {
|
|
4496
|
-
|
|
4471
|
+
task: {
|
|
4497
4472
|
type: "string",
|
|
4498
|
-
description: "
|
|
4473
|
+
description: "Full description of the pitch deck content. Include the full copy of each slide in detail."
|
|
4499
4474
|
}
|
|
4500
4475
|
},
|
|
4501
|
-
required: ["
|
|
4476
|
+
required: ["task"]
|
|
4502
4477
|
}
|
|
4503
4478
|
}
|
|
4504
4479
|
];
|
|
@@ -4507,115 +4482,62 @@ var VISION_TOOLS = [
|
|
|
4507
4482
|
import fs16 from "fs";
|
|
4508
4483
|
import path9 from "path";
|
|
4509
4484
|
var ROADMAP_DIR = "src/roadmap";
|
|
4510
|
-
function
|
|
4511
|
-
return
|
|
4485
|
+
function resolve(filePath) {
|
|
4486
|
+
return path9.join(ROADMAP_DIR, filePath);
|
|
4512
4487
|
}
|
|
4513
|
-
async function executeVisionTool(name, input) {
|
|
4488
|
+
async function executeVisionTool(name, input, context) {
|
|
4514
4489
|
switch (name) {
|
|
4515
|
-
case "
|
|
4516
|
-
const {
|
|
4517
|
-
slug,
|
|
4518
|
-
name: itemName,
|
|
4519
|
-
description,
|
|
4520
|
-
effort,
|
|
4521
|
-
requires,
|
|
4522
|
-
body
|
|
4523
|
-
} = input;
|
|
4524
|
-
const filePath = path9.join(ROADMAP_DIR, `${slug}.md`);
|
|
4490
|
+
case "listDir": {
|
|
4525
4491
|
try {
|
|
4526
4492
|
fs16.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
4527
|
-
const
|
|
4528
|
-
const
|
|
4529
|
-
name
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
${
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
const lineCount = content.split("\n").length;
|
|
4541
|
-
const label = oldContent ? "Updated" : "Wrote";
|
|
4542
|
-
return `${label} ${filePath} (${lineCount} lines)
|
|
4543
|
-
${unifiedDiff(filePath, oldContent, content)}`;
|
|
4493
|
+
const entries = fs16.readdirSync(ROADMAP_DIR, { withFileTypes: true });
|
|
4494
|
+
const lines = [];
|
|
4495
|
+
const dirs = entries.filter((e) => e.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
|
|
4496
|
+
const files = entries.filter((e) => !e.isDirectory()).sort((a, b) => a.name.localeCompare(b.name));
|
|
4497
|
+
for (const d of dirs) {
|
|
4498
|
+
lines.push(`${d.name}/`);
|
|
4499
|
+
}
|
|
4500
|
+
for (const f of files) {
|
|
4501
|
+
const stat = fs16.statSync(resolve(f.name));
|
|
4502
|
+
const size = stat.size < 1024 ? `${stat.size}B` : `${(stat.size / 1024).toFixed(1)}KB`;
|
|
4503
|
+
lines.push(`${f.name} (${size})`);
|
|
4504
|
+
}
|
|
4505
|
+
return lines.length > 0 ? lines.join("\n") : "(empty)";
|
|
4544
4506
|
} catch (err) {
|
|
4545
|
-
return `Error
|
|
4507
|
+
return `Error: ${err.message}`;
|
|
4546
4508
|
}
|
|
4547
4509
|
}
|
|
4548
|
-
case "
|
|
4549
|
-
const
|
|
4550
|
-
const filePath = path9.join(ROADMAP_DIR, `${slug}.md`);
|
|
4510
|
+
case "readFile": {
|
|
4511
|
+
const filePath = resolve(input.path);
|
|
4551
4512
|
try {
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
}
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
/^description:\s*.+$/m,
|
|
4569
|
-
`description: ${input.description}`
|
|
4570
|
-
);
|
|
4571
|
-
}
|
|
4572
|
-
if (input.effort) {
|
|
4573
|
-
content = content.replace(
|
|
4574
|
-
/^effort:\s*.+$/m,
|
|
4575
|
-
`effort: ${input.effort}`
|
|
4576
|
-
);
|
|
4577
|
-
}
|
|
4578
|
-
if (input.requires) {
|
|
4579
|
-
content = content.replace(
|
|
4580
|
-
/^requires:\s*.+$/m,
|
|
4581
|
-
`requires: ${formatRequires(input.requires)}`
|
|
4582
|
-
);
|
|
4583
|
-
}
|
|
4584
|
-
if (input.body) {
|
|
4585
|
-
const endOfFrontmatter = content.indexOf("---", 4);
|
|
4586
|
-
if (endOfFrontmatter !== -1) {
|
|
4587
|
-
const frontmatter = content.slice(0, endOfFrontmatter + 3);
|
|
4588
|
-
content = `${frontmatter}
|
|
4589
|
-
|
|
4590
|
-
${input.body}
|
|
4591
|
-
`;
|
|
4592
|
-
}
|
|
4593
|
-
}
|
|
4594
|
-
if (input.appendHistory) {
|
|
4595
|
-
if (content.includes("## History")) {
|
|
4596
|
-
content = content.trimEnd() + `
|
|
4597
|
-
${input.appendHistory}
|
|
4598
|
-
`;
|
|
4599
|
-
} else {
|
|
4600
|
-
content = content.trimEnd() + `
|
|
4601
|
-
|
|
4602
|
-
## History
|
|
4603
|
-
|
|
4604
|
-
${input.appendHistory}
|
|
4605
|
-
`;
|
|
4606
|
-
}
|
|
4513
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
4514
|
+
const lines = content.split("\n");
|
|
4515
|
+
const numbered = lines.map((line, i) => `${String(i + 1).padStart(4)} ${line}`).join("\n");
|
|
4516
|
+
return numbered;
|
|
4517
|
+
} catch (err) {
|
|
4518
|
+
return `Error reading ${filePath}: ${err.message}`;
|
|
4519
|
+
}
|
|
4520
|
+
}
|
|
4521
|
+
case "writeFile": {
|
|
4522
|
+
const filePath = resolve(input.path);
|
|
4523
|
+
try {
|
|
4524
|
+
fs16.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
4525
|
+
let oldContent = null;
|
|
4526
|
+
try {
|
|
4527
|
+
oldContent = fs16.readFileSync(filePath, "utf-8");
|
|
4528
|
+
} catch {
|
|
4607
4529
|
}
|
|
4608
|
-
fs16.writeFileSync(filePath, content, "utf-8");
|
|
4609
|
-
const lineCount = content.split("\n").length;
|
|
4610
|
-
|
|
4611
|
-
${
|
|
4530
|
+
fs16.writeFileSync(filePath, input.content, "utf-8");
|
|
4531
|
+
const lineCount = input.content.split("\n").length;
|
|
4532
|
+
const label = oldContent !== null ? "Wrote" : "Created";
|
|
4533
|
+
return `${label} ${filePath} (${lineCount} lines)
|
|
4534
|
+
${unifiedDiff(filePath, oldContent ?? "", input.content)}`;
|
|
4612
4535
|
} catch (err) {
|
|
4613
|
-
return `Error
|
|
4536
|
+
return `Error writing ${filePath}: ${err.message}`;
|
|
4614
4537
|
}
|
|
4615
4538
|
}
|
|
4616
|
-
case "
|
|
4617
|
-
const
|
|
4618
|
-
const filePath = path9.join(ROADMAP_DIR, `${slug}.md`);
|
|
4539
|
+
case "deleteFile": {
|
|
4540
|
+
const filePath = resolve(input.path);
|
|
4619
4541
|
try {
|
|
4620
4542
|
if (!fs16.existsSync(filePath)) {
|
|
4621
4543
|
return `Error: ${filePath} does not exist`;
|
|
@@ -4628,6 +4550,53 @@ ${unifiedDiff(filePath, oldContent, "")}`;
|
|
|
4628
4550
|
return `Error deleting ${filePath}: ${err.message}`;
|
|
4629
4551
|
}
|
|
4630
4552
|
}
|
|
4553
|
+
case "writePitchDeck": {
|
|
4554
|
+
if (!context) {
|
|
4555
|
+
return "Error: writePitchDeck requires execution context for design expert delegation";
|
|
4556
|
+
}
|
|
4557
|
+
const filePath = resolve("pitch.html");
|
|
4558
|
+
try {
|
|
4559
|
+
fs16.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
4560
|
+
const existingHtml = fs16.existsSync(filePath) ? fs16.readFileSync(filePath, "utf-8").trim() : "";
|
|
4561
|
+
let task = `
|
|
4562
|
+
<pitch_content>${input.task}</pitch_content>
|
|
4563
|
+
|
|
4564
|
+
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 text heavy, and it should not feel like a landing page - it should feel like a modern interactive presentation that leaves the user wowed by the product.
|
|
4565
|
+
|
|
4566
|
+
### Rules
|
|
4567
|
+
- The deck must be a single HTML file - it will be rendered in an iFrame.
|
|
4568
|
+
- Keep it simple: 100svh 100vw slides that scroll horizontally using browser scrolling. Must look beautiful on desktop and mobile - use all the principles you know about designing effective landing pages to make a beautiful deck.
|
|
4569
|
+
- The deck must support keyboard navigation left and right, and big clickable arrows to transition.
|
|
4570
|
+
- Animation between slides must be seamless, no flicker or flashing.
|
|
4571
|
+
- Be bold and impactful. Do not be wordy or verbose, no one reads decks with too many words.
|
|
4572
|
+
- Keep it simple: 5-7 slides max. No fluff, just imapct.
|
|
4573
|
+
- Code must be clean, bug free, and easy-to-parse. Use GSAP for animations.
|
|
4574
|
+
`;
|
|
4575
|
+
if (existingHtml) {
|
|
4576
|
+
task += `
|
|
4577
|
+
|
|
4578
|
+
The current pitch deck HTML is below. Refine and update it rather than starting from scratch \u2014 preserve the existing design and structure where it still works, and update the content and slides to reflect the new pitch.
|
|
4579
|
+
|
|
4580
|
+
<existing_pitch_html>${existingHtml}</existing_pitch_html>`;
|
|
4581
|
+
}
|
|
4582
|
+
task += `
|
|
4583
|
+
|
|
4584
|
+
Respond only with the HTML of the deck as a single fenced markdown block and absolutely no other text - your response will be written directly to a file.`;
|
|
4585
|
+
const result = await designExpertTool.execute({ task }, context);
|
|
4586
|
+
const htmlMatch = result.match(
|
|
4587
|
+
/```(?:html|wireframe)\n([\s\S]*?)```/
|
|
4588
|
+
);
|
|
4589
|
+
const html = htmlMatch ? htmlMatch[1].trim() : result;
|
|
4590
|
+
const oldContent = fs16.existsSync(filePath) ? fs16.readFileSync(filePath, "utf-8") : "";
|
|
4591
|
+
fs16.writeFileSync(filePath, html, "utf-8");
|
|
4592
|
+
const lineCount = html.split("\n").length;
|
|
4593
|
+
const label = oldContent ? "Wrote" : "Created";
|
|
4594
|
+
return `${label} ${filePath} (${lineCount} lines)
|
|
4595
|
+
${unifiedDiff(filePath, oldContent, html)}`;
|
|
4596
|
+
} catch (err) {
|
|
4597
|
+
return `Error generating pitch deck: ${err.message}`;
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4631
4600
|
default:
|
|
4632
4601
|
return `Error: unknown tool "${name}"`;
|
|
4633
4602
|
}
|
|
@@ -4681,7 +4650,11 @@ var productVisionTool = {
|
|
|
4681
4650
|
history: history.length > 0 ? history : void 0,
|
|
4682
4651
|
tools: VISION_TOOLS,
|
|
4683
4652
|
externalTools: /* @__PURE__ */ new Set(),
|
|
4684
|
-
executeTool: executeVisionTool
|
|
4653
|
+
executeTool: (name, input2, toolCallId) => executeVisionTool(
|
|
4654
|
+
name,
|
|
4655
|
+
input2,
|
|
4656
|
+
toolCallId ? deriveContext(context, toolCallId) : context
|
|
4657
|
+
),
|
|
4685
4658
|
apiConfig: context.apiConfig,
|
|
4686
4659
|
model: context.model,
|
|
4687
4660
|
subAgentId: "productVision",
|
|
@@ -4883,6 +4856,9 @@ var scrapeWebUrlTool = {
|
|
|
4883
4856
|
};
|
|
4884
4857
|
|
|
4885
4858
|
// src/tools/index.ts
|
|
4859
|
+
function deriveContext(parent, toolCallId) {
|
|
4860
|
+
return { ...parent, toolCallId };
|
|
4861
|
+
}
|
|
4886
4862
|
var ALL_TOOLS = [
|
|
4887
4863
|
// Common
|
|
4888
4864
|
setProjectOnboardingStateTool,
|
|
@@ -5820,9 +5796,6 @@ function emit(event, data, requestId) {
|
|
|
5820
5796
|
}
|
|
5821
5797
|
process.stdout.write(JSON.stringify(payload) + "\n");
|
|
5822
5798
|
}
|
|
5823
|
-
function handleGetHistory(state) {
|
|
5824
|
-
return { messages: state.messages };
|
|
5825
|
-
}
|
|
5826
5799
|
function handleClear(state) {
|
|
5827
5800
|
clearSession(state);
|
|
5828
5801
|
return {};
|
|
@@ -5967,17 +5940,17 @@ ${xmlParts}
|
|
|
5967
5940
|
return Promise.resolve(early);
|
|
5968
5941
|
}
|
|
5969
5942
|
const shouldTimeout = !USER_FACING_TOOLS.has(name);
|
|
5970
|
-
return new Promise((
|
|
5943
|
+
return new Promise((resolve2) => {
|
|
5971
5944
|
const timeout = shouldTimeout ? setTimeout(() => {
|
|
5972
5945
|
pendingTools.delete(id);
|
|
5973
|
-
|
|
5946
|
+
resolve2(
|
|
5974
5947
|
"Error: Tool timed out \u2014 no response from the app environment after 5 minutes."
|
|
5975
5948
|
);
|
|
5976
5949
|
}, EXTERNAL_TOOL_TIMEOUT_MS) : void 0;
|
|
5977
5950
|
pendingTools.set(id, {
|
|
5978
5951
|
resolve: (result) => {
|
|
5979
5952
|
clearTimeout(timeout);
|
|
5980
|
-
|
|
5953
|
+
resolve2(result);
|
|
5981
5954
|
},
|
|
5982
5955
|
timeout
|
|
5983
5956
|
});
|
|
@@ -6250,7 +6223,11 @@ ${xmlParts}
|
|
|
6250
6223
|
}
|
|
6251
6224
|
if (action === "get_history") {
|
|
6252
6225
|
applyPendingBlockUpdates();
|
|
6253
|
-
dispatchSimple(requestId, "history", () =>
|
|
6226
|
+
dispatchSimple(requestId, "history", () => ({
|
|
6227
|
+
messages: state.messages,
|
|
6228
|
+
running,
|
|
6229
|
+
...running && currentRequestId ? { currentRequestId } : {}
|
|
6230
|
+
}));
|
|
6254
6231
|
return;
|
|
6255
6232
|
}
|
|
6256
6233
|
if (action === "clear") {
|