@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 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 if (!killed) {
1653
- killed = true;
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
- if (!killed) {
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
- const timer = setTimeout(() => {
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 (out) {
1697
- resolve2(logBlock + out);
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 (code !== 0 || killed) {
1701
- const errMsg = stderr.trim() || (killed ? "Process timed out" : `Exit code ${code}`);
1702
- resolve2(logBlock + `Error: ${errMsg}`);
1757
+ if (out) {
1758
+ finish({ ok: true, output: out, logs, timedOut: false, truncated });
1703
1759
  return;
1704
1760
  }
1705
- resolve2(logBlock + "(no response)");
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
- return runCli("mindstudio", ["ask", query], {
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 runMindstudioCli(args, options) {
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 raw = await runCli("mindstudio", cleanArgs, options);
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(raw);
1846
+ envelope = JSON.parse(res.output);
1780
1847
  } catch {
1781
- return raw;
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
- return typeof v === "string" ? v : JSON.stringify(v);
1889
+ const value = typeof v === "string" ? v : JSON.stringify(v);
1890
+ return { ok: true, value: value + truncNote };
1823
1891
  }
1824
- return JSON.stringify(stripDollarKeys(envelope));
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
- { outputKey: "results", maxBuffer: 512 * 1024, onLog: context?.onLog }
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: '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). Or pass a real user ID from scenario-seeded data for a specific user. Overrides session-level impersonation for this call only.'
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
- { outputKey: "results", onLog, caller: "designExpert" }
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 ssUrl = await runMindstudioCli(
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 (ssUrl.startsWith("Error")) {
4265
- return `Could not screenshot ${url}: ${ssUrl}`;
4345
+ if (!ss.ok) {
4346
+ return `Could not screenshot ${url}: ${ss.value}`;
4266
4347
  }
4267
- imageUrl = ssUrl;
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 runMindstudioCli(
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
- return enhanced.trim();
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 url = await runMindstudioCli(["generate-image"], {
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 = [url];
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 batchResult = await runMindstudioCli(["batch"], {
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(batchResult);
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 batchResult;
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 runMindstudioCli(
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.startsWith("Error") ? url : 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
- { onLog: context?.onLog }
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 if (!killed) {
1198
- killed = true;
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
- if (!killed) {
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
- const timer = setTimeout(() => {
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 (out) {
1242
- resolve2(logBlock + out);
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 (code !== 0 || killed) {
1246
- const errMsg = stderr.trim() || (killed ? "Process timed out" : `Exit code ${code}`);
1247
- resolve2(logBlock + `Error: ${errMsg}`);
1296
+ if (out) {
1297
+ finish({ ok: true, output: out, logs, timedOut: false, truncated });
1248
1298
  return;
1249
1299
  }
1250
- resolve2(logBlock + "(no response)");
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
- return runCli("mindstudio", ["ask", query], {
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 runMindstudioCli(args2, options) {
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 raw = await runCli("mindstudio", cleanArgs, options);
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(raw);
1407
+ envelope = JSON.parse(res.output);
1343
1408
  } catch {
1344
- return raw;
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
- return typeof v === "string" ? v : JSON.stringify(v);
1450
+ const value = typeof v === "string" ? v : JSON.stringify(v);
1451
+ return { ok: true, value: value + truncNote };
1386
1452
  }
1387
- return JSON.stringify(stripDollarKeys(envelope));
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
- { outputKey: "results", maxBuffer: 512 * 1024, onLog: context?.onLog }
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: '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). Or pass a real user ID from scenario-seeded data for a specific user. Overrides session-level impersonation for this call only.'
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
- { outputKey: "results", onLog, caller: "designExpert" }
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 ssUrl = await runMindstudioCli(
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 (ssUrl.startsWith("Error")) {
4996
- return `Could not screenshot ${url}: ${ssUrl}`;
5080
+ if (!ss.ok) {
5081
+ return `Could not screenshot ${url}: ${ss.value}`;
4997
5082
  }
4998
- imageUrl = ssUrl;
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 runMindstudioCli(
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
- return enhanced.trim();
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 url = await runMindstudioCli(["generate-image"], {
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 = [url];
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 batchResult = await runMindstudioCli(["batch"], {
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(batchResult);
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 batchResult;
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 runMindstudioCli(
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.startsWith("Error") ? url : 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
- { onLog: context?.onLog }
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
@@ -68,7 +68,7 @@ process_one() {
68
68
  --output-key analysis \
69
69
  --no-meta 2>&1) || true
70
70
 
71
- if echo "$ANALYSIS" | grep -q '"error"'; then
71
+ if [ -z "$ANALYSIS" ] || echo "$ANALYSIS" | grep -q '"error"'; then
72
72
  echo " FAILED — $url"
73
73
  return
74
74
  fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.246",
3
+ "version": "0.1.248",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",