@mindstudio-ai/remy 0.1.246 → 0.1.248
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 +145 -53
- package/dist/index.js +150 -53
- package/dist/prompt/compiled/auth.md +2 -0
- package/dist/subagents/browserAutomation/prompt.md +1 -1
- package/dist/subagents/designExpert/data/sources/compile-font-descriptions.sh +1 -1
- package/dist/subagents/designExpert/data/sources/compile-inspiration.sh +2 -2
- package/dist/subagents/designExpert/data/sources/compile-ui-inspiration.sh +1 -1
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -476,6 +476,9 @@ var ALLOWED_MODELS_BY_TYPE = {
|
|
|
476
476
|
"claude-fable-5",
|
|
477
477
|
"claude-5-sonnet",
|
|
478
478
|
"gpt-5.5",
|
|
479
|
+
"gpt-5.6-sol",
|
|
480
|
+
"gpt-5.6-terra",
|
|
481
|
+
"gpt-5.6-luna",
|
|
479
482
|
"gemini-3-pro",
|
|
480
483
|
"gemini-3.1-pro",
|
|
481
484
|
"gemini-3-flash",
|
|
@@ -1624,6 +1627,15 @@ var confirmDestructiveActionTool = {
|
|
|
1624
1627
|
|
|
1625
1628
|
// src/subagents/common/runCli.ts
|
|
1626
1629
|
import { spawn } from "child_process";
|
|
1630
|
+
var SCRAPE_MAX_BUFFER = 4 * 1024 * 1024;
|
|
1631
|
+
var SEARCH_MAX_BUFFER = 512 * 1024;
|
|
1632
|
+
var SIGKILL_GRACE_MS = 2e3;
|
|
1633
|
+
function formatCliResult(r) {
|
|
1634
|
+
const logBlock = r.logs.length > 0 ? r.logs.join("\n") + "\n\n" : "";
|
|
1635
|
+
const body = r.ok ? r.output : `Error: ${r.output}`;
|
|
1636
|
+
const truncNote = r.truncated ? "\n\n[output truncated]" : "";
|
|
1637
|
+
return logBlock + body + truncNote;
|
|
1638
|
+
}
|
|
1627
1639
|
function runCli(command, args, options) {
|
|
1628
1640
|
return new Promise((resolve2) => {
|
|
1629
1641
|
const timeout = options?.timeout ?? 6e4;
|
|
@@ -1632,35 +1644,71 @@ function runCli(command, args, options) {
|
|
|
1632
1644
|
if (options?.jsonLogs && !args.includes("--json-logs")) {
|
|
1633
1645
|
finalArgs = args.length > 0 ? [args[0], "--json-logs", ...args.slice(1)] : ["--json-logs"];
|
|
1634
1646
|
}
|
|
1635
|
-
const child = spawn(command, finalArgs, {
|
|
1636
|
-
stdio: [options?.stdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
1637
|
-
});
|
|
1638
|
-
if (options?.stdin) {
|
|
1639
|
-
child.stdin.write(options.stdin);
|
|
1640
|
-
child.stdin.end();
|
|
1641
|
-
}
|
|
1642
1647
|
const logs = [];
|
|
1643
1648
|
let stdout = "";
|
|
1644
1649
|
let stderr = "";
|
|
1645
1650
|
let stdoutSize = 0;
|
|
1646
1651
|
let stderrSize = 0;
|
|
1647
1652
|
let killed = false;
|
|
1653
|
+
let timedOut = false;
|
|
1654
|
+
let truncated = false;
|
|
1655
|
+
let settled = false;
|
|
1656
|
+
let timer;
|
|
1657
|
+
let killTimer;
|
|
1658
|
+
const finish = (result) => {
|
|
1659
|
+
if (settled) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
settled = true;
|
|
1663
|
+
if (timer) {
|
|
1664
|
+
clearTimeout(timer);
|
|
1665
|
+
}
|
|
1666
|
+
if (killTimer) {
|
|
1667
|
+
clearTimeout(killTimer);
|
|
1668
|
+
}
|
|
1669
|
+
resolve2(result);
|
|
1670
|
+
};
|
|
1671
|
+
const child = spawn(command, finalArgs, {
|
|
1672
|
+
stdio: [options?.stdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
1673
|
+
});
|
|
1674
|
+
child.on("error", (err) => {
|
|
1675
|
+
finish({
|
|
1676
|
+
ok: false,
|
|
1677
|
+
output: err.message,
|
|
1678
|
+
logs,
|
|
1679
|
+
timedOut: false,
|
|
1680
|
+
truncated: false
|
|
1681
|
+
});
|
|
1682
|
+
});
|
|
1683
|
+
if (options?.stdin) {
|
|
1684
|
+
child.stdin.on("error", () => {
|
|
1685
|
+
});
|
|
1686
|
+
try {
|
|
1687
|
+
child.stdin.write(options.stdin);
|
|
1688
|
+
child.stdin.end();
|
|
1689
|
+
} catch {
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
const killForOverflow = () => {
|
|
1693
|
+
if (killed) {
|
|
1694
|
+
return;
|
|
1695
|
+
}
|
|
1696
|
+
killed = true;
|
|
1697
|
+
truncated = true;
|
|
1698
|
+
child.kill();
|
|
1699
|
+
};
|
|
1648
1700
|
child.stdout.on("data", (chunk) => {
|
|
1649
1701
|
stdoutSize += chunk.length;
|
|
1650
1702
|
if (stdoutSize <= maxBuffer) {
|
|
1651
1703
|
stdout += chunk.toString();
|
|
1652
|
-
} else
|
|
1653
|
-
|
|
1654
|
-
child.kill();
|
|
1704
|
+
} else {
|
|
1705
|
+
killForOverflow();
|
|
1655
1706
|
}
|
|
1656
1707
|
});
|
|
1657
1708
|
child.stderr.on("data", (chunk) => {
|
|
1658
1709
|
stderrSize += chunk.length;
|
|
1659
1710
|
if (stderrSize > maxBuffer) {
|
|
1660
|
-
|
|
1661
|
-
killed = true;
|
|
1662
|
-
child.kill();
|
|
1663
|
-
}
|
|
1711
|
+
killForOverflow();
|
|
1664
1712
|
return;
|
|
1665
1713
|
}
|
|
1666
1714
|
const text = chunk.toString();
|
|
@@ -1685,24 +1733,38 @@ function runCli(command, args, options) {
|
|
|
1685
1733
|
}
|
|
1686
1734
|
}
|
|
1687
1735
|
});
|
|
1688
|
-
|
|
1736
|
+
timer = setTimeout(() => {
|
|
1737
|
+
if (killed) {
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1689
1740
|
killed = true;
|
|
1741
|
+
timedOut = true;
|
|
1690
1742
|
child.kill();
|
|
1743
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), SIGKILL_GRACE_MS);
|
|
1691
1744
|
}, timeout);
|
|
1692
1745
|
child.on("close", (code) => {
|
|
1693
|
-
clearTimeout(timer);
|
|
1694
|
-
const logBlock = !options?.onLog && logs.length > 0 ? logs.join("\n") + "\n\n" : "";
|
|
1695
1746
|
const out = stdout.trim();
|
|
1696
|
-
if (
|
|
1697
|
-
|
|
1747
|
+
if (timedOut) {
|
|
1748
|
+
finish({
|
|
1749
|
+
ok: false,
|
|
1750
|
+
output: stderr.trim() || "Process timed out",
|
|
1751
|
+
logs,
|
|
1752
|
+
timedOut: true,
|
|
1753
|
+
truncated
|
|
1754
|
+
});
|
|
1698
1755
|
return;
|
|
1699
1756
|
}
|
|
1700
|
-
if (
|
|
1701
|
-
|
|
1702
|
-
resolve2(logBlock + `Error: ${errMsg}`);
|
|
1757
|
+
if (out) {
|
|
1758
|
+
finish({ ok: true, output: out, logs, timedOut: false, truncated });
|
|
1703
1759
|
return;
|
|
1704
1760
|
}
|
|
1705
|
-
|
|
1761
|
+
finish({
|
|
1762
|
+
ok: false,
|
|
1763
|
+
output: stderr.trim() || (code !== 0 ? `Exit code ${code}` : "(no response)"),
|
|
1764
|
+
logs,
|
|
1765
|
+
timedOut: false,
|
|
1766
|
+
truncated
|
|
1767
|
+
});
|
|
1706
1768
|
});
|
|
1707
1769
|
});
|
|
1708
1770
|
}
|
|
@@ -1726,11 +1788,12 @@ var askMindStudioSdkTool = {
|
|
|
1726
1788
|
},
|
|
1727
1789
|
async execute(input, context) {
|
|
1728
1790
|
const query = input.query;
|
|
1729
|
-
|
|
1791
|
+
const result = await runCli("mindstudio", ["ask", query], {
|
|
1730
1792
|
timeout: 2e5,
|
|
1731
1793
|
maxBuffer: 512 * 1024,
|
|
1732
1794
|
onLog: context?.onLog
|
|
1733
1795
|
});
|
|
1796
|
+
return formatCliResult(result);
|
|
1734
1797
|
}
|
|
1735
1798
|
};
|
|
1736
1799
|
|
|
@@ -1768,17 +1831,21 @@ function stripFlags(args) {
|
|
|
1768
1831
|
}
|
|
1769
1832
|
return out;
|
|
1770
1833
|
}
|
|
1771
|
-
async function
|
|
1834
|
+
async function runMindstudioCliResult(args, options) {
|
|
1772
1835
|
const cleanArgs = stripFlags(args);
|
|
1773
1836
|
const cliAction = args[0];
|
|
1774
1837
|
const agentName = options?.caller ?? "mindstudio-cli";
|
|
1775
1838
|
const start = Date.now();
|
|
1776
|
-
const
|
|
1839
|
+
const res = await runCli("mindstudio", cleanArgs, options);
|
|
1840
|
+
if (!res.ok) {
|
|
1841
|
+
return { ok: false, value: formatCliResult(res) };
|
|
1842
|
+
}
|
|
1843
|
+
const truncNote = res.truncated ? "\n\n[output truncated]" : "";
|
|
1777
1844
|
let envelope;
|
|
1778
1845
|
try {
|
|
1779
|
-
envelope = JSON.parse(
|
|
1846
|
+
envelope = JSON.parse(res.output);
|
|
1780
1847
|
} catch {
|
|
1781
|
-
return
|
|
1848
|
+
return { ok: true, value: res.output + truncNote };
|
|
1782
1849
|
}
|
|
1783
1850
|
if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
|
|
1784
1851
|
const durationMs = Date.now() - start;
|
|
@@ -1796,7 +1863,7 @@ async function runMindstudioCli(args, options) {
|
|
|
1796
1863
|
});
|
|
1797
1864
|
}
|
|
1798
1865
|
}
|
|
1799
|
-
return JSON.stringify(envelope.results);
|
|
1866
|
+
return { ok: true, value: JSON.stringify(envelope.results) + truncNote };
|
|
1800
1867
|
}
|
|
1801
1868
|
if (typeof envelope?.$billingCost === "number") {
|
|
1802
1869
|
recordUsage({
|
|
@@ -1817,11 +1884,18 @@ async function runMindstudioCli(args, options) {
|
|
|
1817
1884
|
if (options?.outputKey) {
|
|
1818
1885
|
const v = envelope?.[options.outputKey];
|
|
1819
1886
|
if (v === void 0 || v === null) {
|
|
1820
|
-
return JSON.stringify(stripDollarKeys(envelope));
|
|
1887
|
+
return { ok: false, value: JSON.stringify(stripDollarKeys(envelope)) };
|
|
1821
1888
|
}
|
|
1822
|
-
|
|
1889
|
+
const value = typeof v === "string" ? v : JSON.stringify(v);
|
|
1890
|
+
return { ok: true, value: value + truncNote };
|
|
1823
1891
|
}
|
|
1824
|
-
return
|
|
1892
|
+
return {
|
|
1893
|
+
ok: true,
|
|
1894
|
+
value: JSON.stringify(stripDollarKeys(envelope)) + truncNote
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
async function runMindstudioCli(args, options) {
|
|
1898
|
+
return (await runMindstudioCliResult(args, options)).value;
|
|
1825
1899
|
}
|
|
1826
1900
|
function stripDollarKeys(envelope) {
|
|
1827
1901
|
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
@@ -1857,7 +1931,12 @@ var searchGoogleTool = {
|
|
|
1857
1931
|
const query = input.query;
|
|
1858
1932
|
return runMindstudioCli(
|
|
1859
1933
|
["search-google", "--query", query, "--export-type", "json"],
|
|
1860
|
-
{
|
|
1934
|
+
{
|
|
1935
|
+
outputKey: "results",
|
|
1936
|
+
maxBuffer: SEARCH_MAX_BUFFER,
|
|
1937
|
+
onLog: context?.onLog,
|
|
1938
|
+
caller: "parent"
|
|
1939
|
+
}
|
|
1861
1940
|
);
|
|
1862
1941
|
}
|
|
1863
1942
|
};
|
|
@@ -2762,7 +2841,7 @@ var runMethodTool = {
|
|
|
2762
2841
|
},
|
|
2763
2842
|
userId: {
|
|
2764
2843
|
type: "string",
|
|
2765
|
-
description:
|
|
2844
|
+
description: `Optional. Run the method as a specific user. Pass "testUser" to auto-auth as the default test user (the sandbox handles user creation/lookup \u2014 no scenario setup needed); works for email-code, sms-code, and "Sign in with Remy" apps (for sign-in-with-remy apps it resolves to the developer's own delegated identity rather than the test user). Or pass a real user ID from scenario-seeded data for a specific user. Overrides session-level impersonation for this call only.`
|
|
2766
2845
|
},
|
|
2767
2846
|
roles: {
|
|
2768
2847
|
type: "array",
|
|
@@ -4146,7 +4225,12 @@ var definition = {
|
|
|
4146
4225
|
async function execute(input, onLog) {
|
|
4147
4226
|
return runMindstudioCli(
|
|
4148
4227
|
["search-google", "--query", input.query, "--export-type", "json"],
|
|
4149
|
-
{
|
|
4228
|
+
{
|
|
4229
|
+
outputKey: "results",
|
|
4230
|
+
onLog,
|
|
4231
|
+
caller: "designExpert",
|
|
4232
|
+
maxBuffer: SEARCH_MAX_BUFFER
|
|
4233
|
+
}
|
|
4150
4234
|
);
|
|
4151
4235
|
}
|
|
4152
4236
|
|
|
@@ -4173,9 +4257,6 @@ var definition2 = {
|
|
|
4173
4257
|
};
|
|
4174
4258
|
async function execute2(input, onLog) {
|
|
4175
4259
|
const pageOptions = { onlyMainContent: true };
|
|
4176
|
-
if (input.screenshot) {
|
|
4177
|
-
pageOptions.screenshot = true;
|
|
4178
|
-
}
|
|
4179
4260
|
return runMindstudioCli(
|
|
4180
4261
|
[
|
|
4181
4262
|
"scrape-url",
|
|
@@ -4184,7 +4265,7 @@ async function execute2(input, onLog) {
|
|
|
4184
4265
|
"--page-options",
|
|
4185
4266
|
JSON.stringify(pageOptions)
|
|
4186
4267
|
],
|
|
4187
|
-
{ onLog, caller: "designExpert" }
|
|
4268
|
+
{ onLog, caller: "designExpert", maxBuffer: SCRAPE_MAX_BUFFER }
|
|
4188
4269
|
);
|
|
4189
4270
|
}
|
|
4190
4271
|
|
|
@@ -4242,7 +4323,7 @@ async function execute3(input, onLog, context) {
|
|
|
4242
4323
|
const isImageUrl = /\.(png|jpe?g|webp|gif|svg|avif)(\?|$)/i.test(url);
|
|
4243
4324
|
let imageUrl = url;
|
|
4244
4325
|
if (!isImageUrl) {
|
|
4245
|
-
const
|
|
4326
|
+
const ss = await runMindstudioCliResult(
|
|
4246
4327
|
[
|
|
4247
4328
|
"screenshot-url",
|
|
4248
4329
|
"--url",
|
|
@@ -4261,10 +4342,10 @@ async function execute3(input, onLog, context) {
|
|
|
4261
4342
|
caller: "designExpert"
|
|
4262
4343
|
}
|
|
4263
4344
|
);
|
|
4264
|
-
if (
|
|
4265
|
-
return `Could not screenshot ${url}: ${
|
|
4345
|
+
if (!ss.ok) {
|
|
4346
|
+
return `Could not screenshot ${url}: ${ss.value}`;
|
|
4266
4347
|
}
|
|
4267
|
-
imageUrl =
|
|
4348
|
+
imageUrl = ss.value;
|
|
4268
4349
|
}
|
|
4269
4350
|
const analysis = await analyzeImage({
|
|
4270
4351
|
prompt: analysisPrompt,
|
|
@@ -4430,7 +4511,7 @@ ${context}
|
|
|
4430
4511
|
<brief>
|
|
4431
4512
|
${brief}
|
|
4432
4513
|
</brief>`;
|
|
4433
|
-
const enhanced = await
|
|
4514
|
+
const enhanced = await runMindstudioCliResult(
|
|
4434
4515
|
[
|
|
4435
4516
|
"generate-text",
|
|
4436
4517
|
"--message",
|
|
@@ -4440,7 +4521,11 @@ ${brief}
|
|
|
4440
4521
|
],
|
|
4441
4522
|
{ outputKey: "content", timeout: 6e4, onLog, caller: "designExpert" }
|
|
4442
4523
|
);
|
|
4443
|
-
|
|
4524
|
+
if (!enhanced.ok) {
|
|
4525
|
+
onLog?.(`[enhancePrompt] enhancement failed, using original brief`);
|
|
4526
|
+
return brief;
|
|
4527
|
+
}
|
|
4528
|
+
return enhanced.value.trim();
|
|
4444
4529
|
}
|
|
4445
4530
|
|
|
4446
4531
|
// src/subagents/designExpert/tools/images/imageGenerator.ts
|
|
@@ -4492,7 +4577,7 @@ async function generateImageAssets(opts) {
|
|
|
4492
4577
|
config
|
|
4493
4578
|
}
|
|
4494
4579
|
});
|
|
4495
|
-
const
|
|
4580
|
+
const res = await runMindstudioCliResult(["generate-image"], {
|
|
4496
4581
|
outputKey: "imageUrl",
|
|
4497
4582
|
jsonLogs: true,
|
|
4498
4583
|
timeout: 2e5,
|
|
@@ -4500,7 +4585,7 @@ async function generateImageAssets(opts) {
|
|
|
4500
4585
|
stdin: step,
|
|
4501
4586
|
caller: "designExpert"
|
|
4502
4587
|
});
|
|
4503
|
-
imageUrls = [
|
|
4588
|
+
imageUrls = [res.ok ? res.value : `Error: ${res.value}`];
|
|
4504
4589
|
} else {
|
|
4505
4590
|
const steps = enhancedPrompts.map((prompt) => ({
|
|
4506
4591
|
stepType: "generateImage",
|
|
@@ -4512,20 +4597,23 @@ async function generateImageAssets(opts) {
|
|
|
4512
4597
|
}
|
|
4513
4598
|
}
|
|
4514
4599
|
}));
|
|
4515
|
-
const
|
|
4600
|
+
const batchRes = await runMindstudioCliResult(["batch"], {
|
|
4516
4601
|
jsonLogs: true,
|
|
4517
4602
|
timeout: 2e5,
|
|
4518
4603
|
onLog,
|
|
4519
4604
|
stdin: JSON.stringify(steps),
|
|
4520
4605
|
caller: "designExpert"
|
|
4521
4606
|
});
|
|
4607
|
+
if (!batchRes.ok) {
|
|
4608
|
+
return batchRes.value;
|
|
4609
|
+
}
|
|
4522
4610
|
try {
|
|
4523
|
-
const parsed = JSON.parse(
|
|
4611
|
+
const parsed = JSON.parse(batchRes.value);
|
|
4524
4612
|
imageUrls = parsed.map(
|
|
4525
4613
|
(r) => r.output?.imageUrl ?? `Error: ${r.error}`
|
|
4526
4614
|
);
|
|
4527
4615
|
} catch {
|
|
4528
|
-
return
|
|
4616
|
+
return batchRes.value;
|
|
4529
4617
|
}
|
|
4530
4618
|
}
|
|
4531
4619
|
if (transparentBackground) {
|
|
@@ -4534,7 +4622,7 @@ async function generateImageAssets(opts) {
|
|
|
4534
4622
|
if (url.startsWith("Error")) {
|
|
4535
4623
|
return url;
|
|
4536
4624
|
}
|
|
4537
|
-
const result = await
|
|
4625
|
+
const result = await runMindstudioCliResult(
|
|
4538
4626
|
["remove-background-from-image", "--image-url", url],
|
|
4539
4627
|
{
|
|
4540
4628
|
outputKey: "imageUrl",
|
|
@@ -4543,7 +4631,7 @@ async function generateImageAssets(opts) {
|
|
|
4543
4631
|
caller: "designExpert"
|
|
4544
4632
|
}
|
|
4545
4633
|
);
|
|
4546
|
-
return result.
|
|
4634
|
+
return result.ok ? result.value : url;
|
|
4547
4635
|
})
|
|
4548
4636
|
);
|
|
4549
4637
|
}
|
|
@@ -5773,7 +5861,11 @@ var scrapeWebUrlTool = {
|
|
|
5773
5861
|
"--page-options",
|
|
5774
5862
|
JSON.stringify(pageOptions)
|
|
5775
5863
|
],
|
|
5776
|
-
{
|
|
5864
|
+
{
|
|
5865
|
+
onLog: context?.onLog,
|
|
5866
|
+
maxBuffer: SCRAPE_MAX_BUFFER,
|
|
5867
|
+
caller: "parent"
|
|
5868
|
+
}
|
|
5777
5869
|
);
|
|
5778
5870
|
}
|
|
5779
5871
|
};
|
package/dist/index.js
CHANGED
|
@@ -1169,6 +1169,12 @@ var init_confirmDestructiveAction = __esm({
|
|
|
1169
1169
|
|
|
1170
1170
|
// src/subagents/common/runCli.ts
|
|
1171
1171
|
import { spawn } from "child_process";
|
|
1172
|
+
function formatCliResult(r) {
|
|
1173
|
+
const logBlock = r.logs.length > 0 ? r.logs.join("\n") + "\n\n" : "";
|
|
1174
|
+
const body = r.ok ? r.output : `Error: ${r.output}`;
|
|
1175
|
+
const truncNote = r.truncated ? "\n\n[output truncated]" : "";
|
|
1176
|
+
return logBlock + body + truncNote;
|
|
1177
|
+
}
|
|
1172
1178
|
function runCli(command, args2, options) {
|
|
1173
1179
|
return new Promise((resolve2) => {
|
|
1174
1180
|
const timeout = options?.timeout ?? 6e4;
|
|
@@ -1177,35 +1183,71 @@ function runCli(command, args2, options) {
|
|
|
1177
1183
|
if (options?.jsonLogs && !args2.includes("--json-logs")) {
|
|
1178
1184
|
finalArgs = args2.length > 0 ? [args2[0], "--json-logs", ...args2.slice(1)] : ["--json-logs"];
|
|
1179
1185
|
}
|
|
1180
|
-
const child = spawn(command, finalArgs, {
|
|
1181
|
-
stdio: [options?.stdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
1182
|
-
});
|
|
1183
|
-
if (options?.stdin) {
|
|
1184
|
-
child.stdin.write(options.stdin);
|
|
1185
|
-
child.stdin.end();
|
|
1186
|
-
}
|
|
1187
1186
|
const logs = [];
|
|
1188
1187
|
let stdout = "";
|
|
1189
1188
|
let stderr = "";
|
|
1190
1189
|
let stdoutSize = 0;
|
|
1191
1190
|
let stderrSize = 0;
|
|
1192
1191
|
let killed = false;
|
|
1192
|
+
let timedOut = false;
|
|
1193
|
+
let truncated = false;
|
|
1194
|
+
let settled = false;
|
|
1195
|
+
let timer;
|
|
1196
|
+
let killTimer;
|
|
1197
|
+
const finish = (result) => {
|
|
1198
|
+
if (settled) {
|
|
1199
|
+
return;
|
|
1200
|
+
}
|
|
1201
|
+
settled = true;
|
|
1202
|
+
if (timer) {
|
|
1203
|
+
clearTimeout(timer);
|
|
1204
|
+
}
|
|
1205
|
+
if (killTimer) {
|
|
1206
|
+
clearTimeout(killTimer);
|
|
1207
|
+
}
|
|
1208
|
+
resolve2(result);
|
|
1209
|
+
};
|
|
1210
|
+
const child = spawn(command, finalArgs, {
|
|
1211
|
+
stdio: [options?.stdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
1212
|
+
});
|
|
1213
|
+
child.on("error", (err) => {
|
|
1214
|
+
finish({
|
|
1215
|
+
ok: false,
|
|
1216
|
+
output: err.message,
|
|
1217
|
+
logs,
|
|
1218
|
+
timedOut: false,
|
|
1219
|
+
truncated: false
|
|
1220
|
+
});
|
|
1221
|
+
});
|
|
1222
|
+
if (options?.stdin) {
|
|
1223
|
+
child.stdin.on("error", () => {
|
|
1224
|
+
});
|
|
1225
|
+
try {
|
|
1226
|
+
child.stdin.write(options.stdin);
|
|
1227
|
+
child.stdin.end();
|
|
1228
|
+
} catch {
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
const killForOverflow = () => {
|
|
1232
|
+
if (killed) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
killed = true;
|
|
1236
|
+
truncated = true;
|
|
1237
|
+
child.kill();
|
|
1238
|
+
};
|
|
1193
1239
|
child.stdout.on("data", (chunk) => {
|
|
1194
1240
|
stdoutSize += chunk.length;
|
|
1195
1241
|
if (stdoutSize <= maxBuffer) {
|
|
1196
1242
|
stdout += chunk.toString();
|
|
1197
|
-
} else
|
|
1198
|
-
|
|
1199
|
-
child.kill();
|
|
1243
|
+
} else {
|
|
1244
|
+
killForOverflow();
|
|
1200
1245
|
}
|
|
1201
1246
|
});
|
|
1202
1247
|
child.stderr.on("data", (chunk) => {
|
|
1203
1248
|
stderrSize += chunk.length;
|
|
1204
1249
|
if (stderrSize > maxBuffer) {
|
|
1205
|
-
|
|
1206
|
-
killed = true;
|
|
1207
|
-
child.kill();
|
|
1208
|
-
}
|
|
1250
|
+
killForOverflow();
|
|
1209
1251
|
return;
|
|
1210
1252
|
}
|
|
1211
1253
|
const text = chunk.toString();
|
|
@@ -1230,30 +1272,48 @@ function runCli(command, args2, options) {
|
|
|
1230
1272
|
}
|
|
1231
1273
|
}
|
|
1232
1274
|
});
|
|
1233
|
-
|
|
1275
|
+
timer = setTimeout(() => {
|
|
1276
|
+
if (killed) {
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1234
1279
|
killed = true;
|
|
1280
|
+
timedOut = true;
|
|
1235
1281
|
child.kill();
|
|
1282
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), SIGKILL_GRACE_MS);
|
|
1236
1283
|
}, timeout);
|
|
1237
1284
|
child.on("close", (code) => {
|
|
1238
|
-
clearTimeout(timer);
|
|
1239
|
-
const logBlock = !options?.onLog && logs.length > 0 ? logs.join("\n") + "\n\n" : "";
|
|
1240
1285
|
const out = stdout.trim();
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1286
|
+
if (timedOut) {
|
|
1287
|
+
finish({
|
|
1288
|
+
ok: false,
|
|
1289
|
+
output: stderr.trim() || "Process timed out",
|
|
1290
|
+
logs,
|
|
1291
|
+
timedOut: true,
|
|
1292
|
+
truncated
|
|
1293
|
+
});
|
|
1243
1294
|
return;
|
|
1244
1295
|
}
|
|
1245
|
-
if (
|
|
1246
|
-
|
|
1247
|
-
resolve2(logBlock + `Error: ${errMsg}`);
|
|
1296
|
+
if (out) {
|
|
1297
|
+
finish({ ok: true, output: out, logs, timedOut: false, truncated });
|
|
1248
1298
|
return;
|
|
1249
1299
|
}
|
|
1250
|
-
|
|
1300
|
+
finish({
|
|
1301
|
+
ok: false,
|
|
1302
|
+
output: stderr.trim() || (code !== 0 ? `Exit code ${code}` : "(no response)"),
|
|
1303
|
+
logs,
|
|
1304
|
+
timedOut: false,
|
|
1305
|
+
truncated
|
|
1306
|
+
});
|
|
1251
1307
|
});
|
|
1252
1308
|
});
|
|
1253
1309
|
}
|
|
1310
|
+
var SCRAPE_MAX_BUFFER, SEARCH_MAX_BUFFER, SIGKILL_GRACE_MS;
|
|
1254
1311
|
var init_runCli = __esm({
|
|
1255
1312
|
"src/subagents/common/runCli.ts"() {
|
|
1256
1313
|
"use strict";
|
|
1314
|
+
SCRAPE_MAX_BUFFER = 4 * 1024 * 1024;
|
|
1315
|
+
SEARCH_MAX_BUFFER = 512 * 1024;
|
|
1316
|
+
SIGKILL_GRACE_MS = 2e3;
|
|
1257
1317
|
}
|
|
1258
1318
|
});
|
|
1259
1319
|
|
|
@@ -1281,11 +1341,12 @@ var init_sdkConsultant = __esm({
|
|
|
1281
1341
|
},
|
|
1282
1342
|
async execute(input, context) {
|
|
1283
1343
|
const query = input.query;
|
|
1284
|
-
|
|
1344
|
+
const result = await runCli("mindstudio", ["ask", query], {
|
|
1285
1345
|
timeout: 2e5,
|
|
1286
1346
|
maxBuffer: 512 * 1024,
|
|
1287
1347
|
onLog: context?.onLog
|
|
1288
1348
|
});
|
|
1349
|
+
return formatCliResult(result);
|
|
1289
1350
|
}
|
|
1290
1351
|
};
|
|
1291
1352
|
}
|
|
@@ -1331,17 +1392,21 @@ function stripFlags(args2) {
|
|
|
1331
1392
|
}
|
|
1332
1393
|
return out;
|
|
1333
1394
|
}
|
|
1334
|
-
async function
|
|
1395
|
+
async function runMindstudioCliResult(args2, options) {
|
|
1335
1396
|
const cleanArgs = stripFlags(args2);
|
|
1336
1397
|
const cliAction = args2[0];
|
|
1337
1398
|
const agentName = options?.caller ?? "mindstudio-cli";
|
|
1338
1399
|
const start = Date.now();
|
|
1339
|
-
const
|
|
1400
|
+
const res = await runCli("mindstudio", cleanArgs, options);
|
|
1401
|
+
if (!res.ok) {
|
|
1402
|
+
return { ok: false, value: formatCliResult(res) };
|
|
1403
|
+
}
|
|
1404
|
+
const truncNote = res.truncated ? "\n\n[output truncated]" : "";
|
|
1340
1405
|
let envelope;
|
|
1341
1406
|
try {
|
|
1342
|
-
envelope = JSON.parse(
|
|
1407
|
+
envelope = JSON.parse(res.output);
|
|
1343
1408
|
} catch {
|
|
1344
|
-
return
|
|
1409
|
+
return { ok: true, value: res.output + truncNote };
|
|
1345
1410
|
}
|
|
1346
1411
|
if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
|
|
1347
1412
|
const durationMs = Date.now() - start;
|
|
@@ -1359,7 +1424,7 @@ async function runMindstudioCli(args2, options) {
|
|
|
1359
1424
|
});
|
|
1360
1425
|
}
|
|
1361
1426
|
}
|
|
1362
|
-
return JSON.stringify(envelope.results);
|
|
1427
|
+
return { ok: true, value: JSON.stringify(envelope.results) + truncNote };
|
|
1363
1428
|
}
|
|
1364
1429
|
if (typeof envelope?.$billingCost === "number") {
|
|
1365
1430
|
recordUsage({
|
|
@@ -1380,11 +1445,18 @@ async function runMindstudioCli(args2, options) {
|
|
|
1380
1445
|
if (options?.outputKey) {
|
|
1381
1446
|
const v = envelope?.[options.outputKey];
|
|
1382
1447
|
if (v === void 0 || v === null) {
|
|
1383
|
-
return JSON.stringify(stripDollarKeys(envelope));
|
|
1448
|
+
return { ok: false, value: JSON.stringify(stripDollarKeys(envelope)) };
|
|
1384
1449
|
}
|
|
1385
|
-
|
|
1450
|
+
const value = typeof v === "string" ? v : JSON.stringify(v);
|
|
1451
|
+
return { ok: true, value: value + truncNote };
|
|
1386
1452
|
}
|
|
1387
|
-
return
|
|
1453
|
+
return {
|
|
1454
|
+
ok: true,
|
|
1455
|
+
value: JSON.stringify(stripDollarKeys(envelope)) + truncNote
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
async function runMindstudioCli(args2, options) {
|
|
1459
|
+
return (await runMindstudioCliResult(args2, options)).value;
|
|
1388
1460
|
}
|
|
1389
1461
|
function stripDollarKeys(envelope) {
|
|
1390
1462
|
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
@@ -1412,6 +1484,7 @@ var init_searchGoogle = __esm({
|
|
|
1412
1484
|
"src/tools/common/searchGoogle.ts"() {
|
|
1413
1485
|
"use strict";
|
|
1414
1486
|
init_runMindstudioCli();
|
|
1487
|
+
init_runCli();
|
|
1415
1488
|
searchGoogleTool = {
|
|
1416
1489
|
clearable: false,
|
|
1417
1490
|
definition: {
|
|
@@ -1432,7 +1505,12 @@ var init_searchGoogle = __esm({
|
|
|
1432
1505
|
const query = input.query;
|
|
1433
1506
|
return runMindstudioCli(
|
|
1434
1507
|
["search-google", "--query", query, "--export-type", "json"],
|
|
1435
|
-
{
|
|
1508
|
+
{
|
|
1509
|
+
outputKey: "results",
|
|
1510
|
+
maxBuffer: SEARCH_MAX_BUFFER,
|
|
1511
|
+
onLog: context?.onLog,
|
|
1512
|
+
caller: "parent"
|
|
1513
|
+
}
|
|
1436
1514
|
);
|
|
1437
1515
|
}
|
|
1438
1516
|
};
|
|
@@ -2011,6 +2089,9 @@ var init_surfaces = __esm({
|
|
|
2011
2089
|
"claude-fable-5",
|
|
2012
2090
|
"claude-5-sonnet",
|
|
2013
2091
|
"gpt-5.5",
|
|
2092
|
+
"gpt-5.6-sol",
|
|
2093
|
+
"gpt-5.6-terra",
|
|
2094
|
+
"gpt-5.6-luna",
|
|
2014
2095
|
"gemini-3-pro",
|
|
2015
2096
|
"gemini-3.1-pro",
|
|
2016
2097
|
"gemini-3-flash",
|
|
@@ -3606,7 +3687,7 @@ var init_runMethod = __esm({
|
|
|
3606
3687
|
},
|
|
3607
3688
|
userId: {
|
|
3608
3689
|
type: "string",
|
|
3609
|
-
description:
|
|
3690
|
+
description: `Optional. Run the method as a specific user. Pass "testUser" to auto-auth as the default test user (the sandbox handles user creation/lookup \u2014 no scenario setup needed); works for email-code, sms-code, and "Sign in with Remy" apps (for sign-in-with-remy apps it resolves to the developer's own delegated identity rather than the test user). Or pass a real user ID from scenario-seeded data for a specific user. Overrides session-level impersonation for this call only.`
|
|
3610
3691
|
},
|
|
3611
3692
|
roles: {
|
|
3612
3693
|
type: "array",
|
|
@@ -4890,7 +4971,12 @@ __export(searchGoogle_exports, {
|
|
|
4890
4971
|
async function execute(input, onLog) {
|
|
4891
4972
|
return runMindstudioCli(
|
|
4892
4973
|
["search-google", "--query", input.query, "--export-type", "json"],
|
|
4893
|
-
{
|
|
4974
|
+
{
|
|
4975
|
+
outputKey: "results",
|
|
4976
|
+
onLog,
|
|
4977
|
+
caller: "designExpert",
|
|
4978
|
+
maxBuffer: SEARCH_MAX_BUFFER
|
|
4979
|
+
}
|
|
4894
4980
|
);
|
|
4895
4981
|
}
|
|
4896
4982
|
var definition;
|
|
@@ -4898,6 +4984,7 @@ var init_searchGoogle2 = __esm({
|
|
|
4898
4984
|
"src/subagents/designExpert/tools/searchGoogle.ts"() {
|
|
4899
4985
|
"use strict";
|
|
4900
4986
|
init_runMindstudioCli();
|
|
4987
|
+
init_runCli();
|
|
4901
4988
|
definition = {
|
|
4902
4989
|
clearable: false,
|
|
4903
4990
|
name: "searchGoogle",
|
|
@@ -4924,9 +5011,6 @@ __export(scrapeWebUrl_exports, {
|
|
|
4924
5011
|
});
|
|
4925
5012
|
async function execute2(input, onLog) {
|
|
4926
5013
|
const pageOptions = { onlyMainContent: true };
|
|
4927
|
-
if (input.screenshot) {
|
|
4928
|
-
pageOptions.screenshot = true;
|
|
4929
|
-
}
|
|
4930
5014
|
return runMindstudioCli(
|
|
4931
5015
|
[
|
|
4932
5016
|
"scrape-url",
|
|
@@ -4935,7 +5019,7 @@ async function execute2(input, onLog) {
|
|
|
4935
5019
|
"--page-options",
|
|
4936
5020
|
JSON.stringify(pageOptions)
|
|
4937
5021
|
],
|
|
4938
|
-
{ onLog, caller: "designExpert" }
|
|
5022
|
+
{ onLog, caller: "designExpert", maxBuffer: SCRAPE_MAX_BUFFER }
|
|
4939
5023
|
);
|
|
4940
5024
|
}
|
|
4941
5025
|
var definition2;
|
|
@@ -4943,6 +5027,7 @@ var init_scrapeWebUrl = __esm({
|
|
|
4943
5027
|
"src/subagents/designExpert/tools/scrapeWebUrl.ts"() {
|
|
4944
5028
|
"use strict";
|
|
4945
5029
|
init_runMindstudioCli();
|
|
5030
|
+
init_runCli();
|
|
4946
5031
|
definition2 = {
|
|
4947
5032
|
clearable: false,
|
|
4948
5033
|
name: "scrapeWebUrl",
|
|
@@ -4973,7 +5058,7 @@ async function execute3(input, onLog, context) {
|
|
|
4973
5058
|
const isImageUrl = /\.(png|jpe?g|webp|gif|svg|avif)(\?|$)/i.test(url);
|
|
4974
5059
|
let imageUrl = url;
|
|
4975
5060
|
if (!isImageUrl) {
|
|
4976
|
-
const
|
|
5061
|
+
const ss = await runMindstudioCliResult(
|
|
4977
5062
|
[
|
|
4978
5063
|
"screenshot-url",
|
|
4979
5064
|
"--url",
|
|
@@ -4992,10 +5077,10 @@ async function execute3(input, onLog, context) {
|
|
|
4992
5077
|
caller: "designExpert"
|
|
4993
5078
|
}
|
|
4994
5079
|
);
|
|
4995
|
-
if (
|
|
4996
|
-
return `Could not screenshot ${url}: ${
|
|
5080
|
+
if (!ss.ok) {
|
|
5081
|
+
return `Could not screenshot ${url}: ${ss.value}`;
|
|
4997
5082
|
}
|
|
4998
|
-
imageUrl =
|
|
5083
|
+
imageUrl = ss.value;
|
|
4999
5084
|
}
|
|
5000
5085
|
const analysis = await analyzeImage({
|
|
5001
5086
|
prompt: analysisPrompt,
|
|
@@ -5221,7 +5306,7 @@ ${context}
|
|
|
5221
5306
|
<brief>
|
|
5222
5307
|
${brief}
|
|
5223
5308
|
</brief>`;
|
|
5224
|
-
const enhanced = await
|
|
5309
|
+
const enhanced = await runMindstudioCliResult(
|
|
5225
5310
|
[
|
|
5226
5311
|
"generate-text",
|
|
5227
5312
|
"--message",
|
|
@@ -5231,7 +5316,11 @@ ${brief}
|
|
|
5231
5316
|
],
|
|
5232
5317
|
{ outputKey: "content", timeout: 6e4, onLog, caller: "designExpert" }
|
|
5233
5318
|
);
|
|
5234
|
-
|
|
5319
|
+
if (!enhanced.ok) {
|
|
5320
|
+
onLog?.(`[enhancePrompt] enhancement failed, using original brief`);
|
|
5321
|
+
return brief;
|
|
5322
|
+
}
|
|
5323
|
+
return enhanced.value.trim();
|
|
5235
5324
|
}
|
|
5236
5325
|
var SYSTEM_PROMPT;
|
|
5237
5326
|
var init_enhancePrompt = __esm({
|
|
@@ -5293,7 +5382,7 @@ async function generateImageAssets(opts) {
|
|
|
5293
5382
|
config
|
|
5294
5383
|
}
|
|
5295
5384
|
});
|
|
5296
|
-
const
|
|
5385
|
+
const res = await runMindstudioCliResult(["generate-image"], {
|
|
5297
5386
|
outputKey: "imageUrl",
|
|
5298
5387
|
jsonLogs: true,
|
|
5299
5388
|
timeout: 2e5,
|
|
@@ -5301,7 +5390,7 @@ async function generateImageAssets(opts) {
|
|
|
5301
5390
|
stdin: step,
|
|
5302
5391
|
caller: "designExpert"
|
|
5303
5392
|
});
|
|
5304
|
-
imageUrls = [
|
|
5393
|
+
imageUrls = [res.ok ? res.value : `Error: ${res.value}`];
|
|
5305
5394
|
} else {
|
|
5306
5395
|
const steps = enhancedPrompts.map((prompt) => ({
|
|
5307
5396
|
stepType: "generateImage",
|
|
@@ -5313,20 +5402,23 @@ async function generateImageAssets(opts) {
|
|
|
5313
5402
|
}
|
|
5314
5403
|
}
|
|
5315
5404
|
}));
|
|
5316
|
-
const
|
|
5405
|
+
const batchRes = await runMindstudioCliResult(["batch"], {
|
|
5317
5406
|
jsonLogs: true,
|
|
5318
5407
|
timeout: 2e5,
|
|
5319
5408
|
onLog,
|
|
5320
5409
|
stdin: JSON.stringify(steps),
|
|
5321
5410
|
caller: "designExpert"
|
|
5322
5411
|
});
|
|
5412
|
+
if (!batchRes.ok) {
|
|
5413
|
+
return batchRes.value;
|
|
5414
|
+
}
|
|
5323
5415
|
try {
|
|
5324
|
-
const parsed = JSON.parse(
|
|
5416
|
+
const parsed = JSON.parse(batchRes.value);
|
|
5325
5417
|
imageUrls = parsed.map(
|
|
5326
5418
|
(r) => r.output?.imageUrl ?? `Error: ${r.error}`
|
|
5327
5419
|
);
|
|
5328
5420
|
} catch {
|
|
5329
|
-
return
|
|
5421
|
+
return batchRes.value;
|
|
5330
5422
|
}
|
|
5331
5423
|
}
|
|
5332
5424
|
if (transparentBackground) {
|
|
@@ -5335,7 +5427,7 @@ async function generateImageAssets(opts) {
|
|
|
5335
5427
|
if (url.startsWith("Error")) {
|
|
5336
5428
|
return url;
|
|
5337
5429
|
}
|
|
5338
|
-
const result = await
|
|
5430
|
+
const result = await runMindstudioCliResult(
|
|
5339
5431
|
["remove-background-from-image", "--image-url", url],
|
|
5340
5432
|
{
|
|
5341
5433
|
outputKey: "imageUrl",
|
|
@@ -5344,7 +5436,7 @@ async function generateImageAssets(opts) {
|
|
|
5344
5436
|
caller: "designExpert"
|
|
5345
5437
|
}
|
|
5346
5438
|
);
|
|
5347
|
-
return result.
|
|
5439
|
+
return result.ok ? result.value : url;
|
|
5348
5440
|
})
|
|
5349
5441
|
);
|
|
5350
5442
|
}
|
|
@@ -6834,6 +6926,7 @@ var init_scrapeWebUrl2 = __esm({
|
|
|
6834
6926
|
"src/tools/common/scrapeWebUrl.ts"() {
|
|
6835
6927
|
"use strict";
|
|
6836
6928
|
init_runMindstudioCli();
|
|
6929
|
+
init_runCli();
|
|
6837
6930
|
scrapeWebUrlTool = {
|
|
6838
6931
|
clearable: false,
|
|
6839
6932
|
definition: {
|
|
@@ -6869,7 +6962,11 @@ var init_scrapeWebUrl2 = __esm({
|
|
|
6869
6962
|
"--page-options",
|
|
6870
6963
|
JSON.stringify(pageOptions)
|
|
6871
6964
|
],
|
|
6872
|
-
{
|
|
6965
|
+
{
|
|
6966
|
+
onLog: context?.onLog,
|
|
6967
|
+
maxBuffer: SCRAPE_MAX_BUFFER,
|
|
6968
|
+
caller: "parent"
|
|
6969
|
+
}
|
|
6873
6970
|
);
|
|
6874
6971
|
}
|
|
6875
6972
|
};
|
|
@@ -420,4 +420,6 @@ All other emails and phone numbers receive real codes. There is no dev-mode bypa
|
|
|
420
420
|
|
|
421
421
|
The `runMethod` tool's `userId: "testUser"` shortcut resolves to this same dev-bypass identity. The platform find-or-creates a real users-table row for it on first call and caches the row's UUID for the rest of the dev session. **`auth.userId` inside the method is that UUID — not the literal string `"testUser"`.** The user row already exists, so don't try to insert it. If you need the UUID to seed app-specific rows that reference it (profiles, preferences, foreign keys), read it from any method response or query the users table directly: `SELECT id FROM users WHERE email = 'remy@mindstudio.ai'` (or `phone = '+15555555555'` for SMS-auth apps).
|
|
422
422
|
|
|
423
|
+
For **"Sign in with Remy"** apps (`auth.methods` is `["remy"]`, with no `email-code`/`sms-code`), `testUser` — and `setupBrowser` — resolve to **the developer's own delegated Remy identity**, not the `remy@mindstudio.ai` code-bypass user. `auth.userId` is still that user's real UUID, but the `remy@mindstudio.ai` email lookup above does not apply — read the UUID from a method response instead.
|
|
424
|
+
|
|
423
425
|
Browser automation tools (screenshots, automated browser tests) handle their own auth sessions. Scenarios seed database data but do not create browser auth sessions.
|
|
@@ -9,7 +9,7 @@ You are a browser smoke test agent. You verify that features work end to end by
|
|
|
9
9
|
The user is watching the automation happen on their screen in real-time. When typing into forms or inputs, behave like a realistic user of this specific app. Use the app context (if provided) to understand the audience and tone. Type the way that audience would actually type — not formal, not robotic. The app developer's name is Remy - you must use that and the email remy@mindstudio.ai as the basis for any testing that requires a persona.
|
|
10
10
|
|
|
11
11
|
### Auth Testing
|
|
12
|
-
When the content you need to test is behind authentication, use the `setupBrowser` tool to automatically pre-authenticate instead of manually navigating login flows. This mints a session cookie, reloads the page with the authenticated state, and optionally navigates to a starting path. Use `remy@mindstudio.ai` as the email. If the test requires a specific role, pass it in the `roles` array.
|
|
12
|
+
When the content you need to test is behind authentication, use the `setupBrowser` tool to automatically pre-authenticate instead of manually navigating login flows. This mints a session cookie, reloads the page with the authenticated state, and optionally navigates to a starting path. Use `remy@mindstudio.ai` as the email. If the test requires a specific role, pass it in the `roles` array. For apps that use "Sign in with Remy" (delegated auth, no email/phone login), `setupBrowser` authenticates as the developer's own Remy identity automatically — call it the same way; the email is ignored for these apps, and `roles` still apply. Do not try to click through the "Sign in with Remy" button manually.
|
|
13
13
|
|
|
14
14
|
If you need to test the login/signup flow itself (e.g., verifying the UI, error states, or the verification code input), navigate it manually: use `remy@mindstudio.ai` for email and `+15551234567` for phone. In the dev environment, verification codes are bypassed for this email and any 555-prefixed phone number — enter any 6-digit code (e.g., `123456`).
|
|
15
15
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# in specimens/fonts/{slug}.png, runs analyze-image, and writes the
|
|
7
7
|
# description back to the font's "description" field.
|
|
8
8
|
#
|
|
9
|
-
# Run: bash src/subagents/designExpert/data/compile-font-descriptions.sh
|
|
9
|
+
# Run: bash src/subagents/designExpert/data/sources/compile-font-descriptions.sh
|
|
10
10
|
# Supports resuming — skips fonts that already have a description.
|
|
11
11
|
|
|
12
12
|
set -euo pipefail
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# Reads each image URL from inspiration.raw.json, runs analyze-image via the
|
|
6
6
|
# mindstudio CLI, and writes the compiled output with URL + analysis.
|
|
7
7
|
#
|
|
8
|
-
# Run manually: bash src/subagents/designExpert/data/compile-inspiration.sh
|
|
8
|
+
# Run manually: bash src/subagents/designExpert/data/sources/compile-inspiration.sh
|
|
9
9
|
# Processes images sequentially (one API call at a time).
|
|
10
10
|
# Supports resuming — skips URLs already present in the output file.
|
|
11
11
|
|
|
@@ -67,7 +67,7 @@ process_one() {
|
|
|
67
67
|
--output-key analysis \
|
|
68
68
|
--no-meta 2>&1) || true
|
|
69
69
|
|
|
70
|
-
if echo "$ANALYSIS" | grep -q '"error"'; then
|
|
70
|
+
if [ -z "$ANALYSIS" ] || echo "$ANALYSIS" | grep -q '"error"'; then
|
|
71
71
|
echo " FAILED — $url"
|
|
72
72
|
return
|
|
73
73
|
fi
|