@mindstudio-ai/remy 0.1.313 → 0.1.314

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/index.js CHANGED
@@ -1389,179 +1389,6 @@ var init_sdkConsultant = __esm({
1389
1389
  }
1390
1390
  });
1391
1391
 
1392
- // src/usageLedger.ts
1393
- import fs8 from "fs";
1394
- function nanoToDollars(nano) {
1395
- return typeof nano === "number" ? nano / 1e9 : void 0;
1396
- }
1397
- function recordUsage(entry) {
1398
- try {
1399
- if (fd === null) {
1400
- fs8.mkdirSync(".logs", { recursive: true });
1401
- fd = fs8.openSync(LEDGER_FILE, "a");
1402
- }
1403
- fs8.writeSync(fd, JSON.stringify(entry) + "\n");
1404
- } catch {
1405
- }
1406
- }
1407
- var LEDGER_FILE, fd;
1408
- var init_usageLedger = __esm({
1409
- "src/usageLedger.ts"() {
1410
- "use strict";
1411
- LEDGER_FILE = ".logs/usage.ndjson";
1412
- fd = null;
1413
- }
1414
- });
1415
-
1416
- // src/subagents/common/runMindstudioCli.ts
1417
- function stripFlags(args2) {
1418
- const out = [];
1419
- for (let i = 0; i < args2.length; i++) {
1420
- const arg = args2[i];
1421
- if (arg === "--no-meta") {
1422
- continue;
1423
- }
1424
- if (arg === "--output-key") {
1425
- i++;
1426
- continue;
1427
- }
1428
- out.push(arg);
1429
- }
1430
- return out;
1431
- }
1432
- async function runMindstudioCliResult(args2, options) {
1433
- const cleanArgs = stripFlags(args2);
1434
- const cliAction = args2[0];
1435
- const agentName = options?.caller ?? "mindstudio-cli";
1436
- const start = Date.now();
1437
- const res = await runCli("mindstudio", cleanArgs, options);
1438
- if (!res.ok) {
1439
- return { ok: false, value: formatCliResult(res) };
1440
- }
1441
- const truncNote = res.truncated ? "\n\n[output truncated]" : "";
1442
- let envelope;
1443
- try {
1444
- envelope = JSON.parse(res.output);
1445
- } catch {
1446
- return { ok: true, value: res.output + truncNote };
1447
- }
1448
- if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
1449
- const durationMs = Date.now() - start;
1450
- for (const step of envelope.results) {
1451
- if (typeof step?.billingCost === "number") {
1452
- recordUsage({
1453
- ts: Date.now(),
1454
- agentName,
1455
- cliAction: `${cliAction}:${step.stepType ?? "step"}`,
1456
- cost: nanoToDollars(step.billingCost),
1457
- inputTokens: 0,
1458
- outputTokens: 0,
1459
- durationMs,
1460
- toolNames: []
1461
- });
1462
- }
1463
- }
1464
- return { ok: true, value: JSON.stringify(envelope.results) + truncNote };
1465
- }
1466
- if (typeof envelope?.$billingCost === "number") {
1467
- recordUsage({
1468
- ts: Date.now(),
1469
- agentName,
1470
- cliAction,
1471
- cost: nanoToDollars(envelope.$billingCost),
1472
- billingEvents: envelope.$billingEvents,
1473
- // CLI billing isn't expressed as input/output tokens for most actions
1474
- // (image gen is per-image, scrape per-page, etc). `numUnits` inside each
1475
- // billingEvent carries the per-event unit count.
1476
- inputTokens: 0,
1477
- outputTokens: 0,
1478
- durationMs: Date.now() - start,
1479
- toolNames: []
1480
- });
1481
- }
1482
- if (options?.outputKey) {
1483
- const v = envelope?.[options.outputKey];
1484
- if (v === void 0 || v === null) {
1485
- return { ok: false, value: JSON.stringify(stripDollarKeys(envelope)) };
1486
- }
1487
- const value = typeof v === "string" ? v : JSON.stringify(v);
1488
- return { ok: true, value: value + truncNote };
1489
- }
1490
- return {
1491
- ok: true,
1492
- value: JSON.stringify(stripDollarKeys(envelope)) + truncNote
1493
- };
1494
- }
1495
- async function runMindstudioCli(args2, options) {
1496
- return (await runMindstudioCliResult(args2, options)).value;
1497
- }
1498
- function stripDollarKeys(envelope) {
1499
- if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
1500
- return envelope;
1501
- }
1502
- const out = {};
1503
- for (const [k, v] of Object.entries(envelope)) {
1504
- if (!k.startsWith("$")) {
1505
- out[k] = v;
1506
- }
1507
- }
1508
- return out;
1509
- }
1510
- var init_runMindstudioCli = __esm({
1511
- "src/subagents/common/runMindstudioCli.ts"() {
1512
- "use strict";
1513
- init_runCli();
1514
- init_usageLedger();
1515
- }
1516
- });
1517
-
1518
- // src/tools/common/searchGoogle.ts
1519
- var FETCH_TOP_N, searchGoogleTool;
1520
- var init_searchGoogle = __esm({
1521
- "src/tools/common/searchGoogle.ts"() {
1522
- "use strict";
1523
- init_runMindstudioCli();
1524
- init_runCli();
1525
- FETCH_TOP_N = 5;
1526
- searchGoogleTool = {
1527
- definition: {
1528
- name: "searchGoogle",
1529
- description: "Search Google and return results. Use for research, finding documentation, looking up APIs, or any task where web search would help. The top results come back with their page content already included, so read those before reaching for scrapeWebUrl \u2014 you only need that for URLs this did not return, or for a result further down the list.",
1530
- inputSchema: {
1531
- type: "object",
1532
- properties: {
1533
- query: {
1534
- type: "string",
1535
- description: "The search query."
1536
- }
1537
- },
1538
- required: ["query"]
1539
- }
1540
- },
1541
- async execute(input, context) {
1542
- const query = input.query;
1543
- return runMindstudioCli(
1544
- [
1545
- "search-google",
1546
- "--query",
1547
- query,
1548
- "--export-type",
1549
- "json",
1550
- "--fetch-top-n",
1551
- String(FETCH_TOP_N)
1552
- ],
1553
- {
1554
- outputKey: "results",
1555
- maxBuffer: SEARCH_MAX_BUFFER,
1556
- onLog: context?.onLog,
1557
- caller: "parent"
1558
- }
1559
- );
1560
- }
1561
- };
1562
- }
1563
- });
1564
-
1565
1392
  // src/tools/common/setProjectMetadata.ts
1566
1393
  var setProjectMetadataTool;
1567
1394
  var init_setProjectMetadata = __esm({
@@ -1601,7 +1428,7 @@ var init_setProjectMetadata = __esm({
1601
1428
  });
1602
1429
 
1603
1430
  // src/assets.ts
1604
- import fs9 from "fs";
1431
+ import fs8 from "fs";
1605
1432
  import path3 from "path";
1606
1433
  function assetPath(...segments) {
1607
1434
  return path3.join(ASSETS_BASE, ...segments);
@@ -1609,7 +1436,7 @@ function assetPath(...segments) {
1609
1436
  function readAsset(...segments) {
1610
1437
  const full = assetPath(...segments);
1611
1438
  try {
1612
- return fs9.readFileSync(full, "utf-8").trim();
1439
+ return fs8.readFileSync(full, "utf-8").trim();
1613
1440
  } catch {
1614
1441
  throw new Error(`Required asset missing: ${full}`);
1615
1442
  }
@@ -1617,7 +1444,7 @@ function readAsset(...segments) {
1617
1444
  function readJsonAsset(fallback, ...segments) {
1618
1445
  const full = assetPath(...segments);
1619
1446
  try {
1620
- return JSON.parse(fs9.readFileSync(full, "utf-8"));
1447
+ return JSON.parse(fs8.readFileSync(full, "utf-8"));
1621
1448
  } catch {
1622
1449
  return fallback;
1623
1450
  }
@@ -1683,6 +1510,30 @@ var init_sentinel = __esm({
1683
1510
  }
1684
1511
  });
1685
1512
 
1513
+ // src/usageLedger.ts
1514
+ import fs9 from "fs";
1515
+ function nanoToDollars(nano) {
1516
+ return typeof nano === "number" ? nano / 1e9 : void 0;
1517
+ }
1518
+ function recordUsage(entry) {
1519
+ try {
1520
+ if (fd === null) {
1521
+ fs9.mkdirSync(".logs", { recursive: true });
1522
+ fd = fs9.openSync(LEDGER_FILE, "a");
1523
+ }
1524
+ fs9.writeSync(fd, JSON.stringify(entry) + "\n");
1525
+ } catch {
1526
+ }
1527
+ }
1528
+ var LEDGER_FILE, fd;
1529
+ var init_usageLedger = __esm({
1530
+ "src/usageLedger.ts"() {
1531
+ "use strict";
1532
+ LEDGER_FILE = ".logs/usage.ndjson";
1533
+ fd = null;
1534
+ }
1535
+ });
1536
+
1686
1537
  // src/compaction/index.ts
1687
1538
  async function compactConversation(messages, apiConfig, model, signal) {
1688
1539
  const endIndex = findSafeInsertionPoint(messages);
@@ -2096,7 +1947,7 @@ var init_compaction = __esm({
2096
1947
  init_api();
2097
1948
  init_assets();
2098
1949
  init_sentinel();
2099
- init_tools8();
1950
+ init_tools9();
2100
1951
  init_logger();
2101
1952
  init_usageLedger();
2102
1953
  log2 = createLogger("compaction");
@@ -2200,6 +2051,13 @@ var init_surfaces = __esm({
2200
2051
  modelType: "text",
2201
2052
  userPickable: true
2202
2053
  },
2054
+ research: {
2055
+ default: "claude-5-sonnet",
2056
+ label: "Research Agent",
2057
+ description: "Researches using the web and reports back with citations.",
2058
+ modelType: "text",
2059
+ userPickable: true
2060
+ },
2203
2061
  copyEditor: {
2204
2062
  default: "claude-5-sonnet",
2205
2063
  label: "Copy Agent",
@@ -4322,6 +4180,108 @@ var init_queryDatabase = __esm({
4322
4180
  }
4323
4181
  });
4324
4182
 
4183
+ // src/subagents/common/runMindstudioCli.ts
4184
+ function stripFlags(args2) {
4185
+ const out = [];
4186
+ for (let i = 0; i < args2.length; i++) {
4187
+ const arg = args2[i];
4188
+ if (arg === "--no-meta") {
4189
+ continue;
4190
+ }
4191
+ if (arg === "--output-key") {
4192
+ i++;
4193
+ continue;
4194
+ }
4195
+ out.push(arg);
4196
+ }
4197
+ return out;
4198
+ }
4199
+ async function runMindstudioCliResult(args2, options) {
4200
+ const cleanArgs = stripFlags(args2);
4201
+ const cliAction = args2[0];
4202
+ const agentName = options?.caller ?? "mindstudio-cli";
4203
+ const start = Date.now();
4204
+ const res = await runCli("mindstudio", cleanArgs, options);
4205
+ if (!res.ok) {
4206
+ return { ok: false, value: formatCliResult(res) };
4207
+ }
4208
+ const truncNote = res.truncated ? "\n\n[output truncated]" : "";
4209
+ let envelope;
4210
+ try {
4211
+ envelope = JSON.parse(res.output);
4212
+ } catch {
4213
+ return { ok: true, value: res.output + truncNote };
4214
+ }
4215
+ if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
4216
+ const durationMs = Date.now() - start;
4217
+ for (const step of envelope.results) {
4218
+ if (typeof step?.billingCost === "number") {
4219
+ recordUsage({
4220
+ ts: Date.now(),
4221
+ agentName,
4222
+ cliAction: `${cliAction}:${step.stepType ?? "step"}`,
4223
+ cost: nanoToDollars(step.billingCost),
4224
+ inputTokens: 0,
4225
+ outputTokens: 0,
4226
+ durationMs,
4227
+ toolNames: []
4228
+ });
4229
+ }
4230
+ }
4231
+ return { ok: true, value: JSON.stringify(envelope.results) + truncNote };
4232
+ }
4233
+ if (typeof envelope?.$billingCost === "number") {
4234
+ recordUsage({
4235
+ ts: Date.now(),
4236
+ agentName,
4237
+ cliAction,
4238
+ cost: nanoToDollars(envelope.$billingCost),
4239
+ billingEvents: envelope.$billingEvents,
4240
+ // CLI billing isn't expressed as input/output tokens for most actions
4241
+ // (image gen is per-image, scrape per-page, etc). `numUnits` inside each
4242
+ // billingEvent carries the per-event unit count.
4243
+ inputTokens: 0,
4244
+ outputTokens: 0,
4245
+ durationMs: Date.now() - start,
4246
+ toolNames: []
4247
+ });
4248
+ }
4249
+ if (options?.outputKey) {
4250
+ const v = envelope?.[options.outputKey];
4251
+ if (v === void 0 || v === null) {
4252
+ return { ok: false, value: JSON.stringify(stripDollarKeys(envelope)) };
4253
+ }
4254
+ const value = typeof v === "string" ? v : JSON.stringify(v);
4255
+ return { ok: true, value: value + truncNote };
4256
+ }
4257
+ return {
4258
+ ok: true,
4259
+ value: JSON.stringify(stripDollarKeys(envelope)) + truncNote
4260
+ };
4261
+ }
4262
+ async function runMindstudioCli(args2, options) {
4263
+ return (await runMindstudioCliResult(args2, options)).value;
4264
+ }
4265
+ function stripDollarKeys(envelope) {
4266
+ if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
4267
+ return envelope;
4268
+ }
4269
+ const out = {};
4270
+ for (const [k, v] of Object.entries(envelope)) {
4271
+ if (!k.startsWith("$")) {
4272
+ out[k] = v;
4273
+ }
4274
+ }
4275
+ return out;
4276
+ }
4277
+ var init_runMindstudioCli = __esm({
4278
+ "src/subagents/common/runMindstudioCli.ts"() {
4279
+ "use strict";
4280
+ init_runCli();
4281
+ init_usageLedger();
4282
+ }
4283
+ });
4284
+
4325
4285
  // src/tools/_helpers/uploadImage.ts
4326
4286
  import { readFile, stat } from "fs/promises";
4327
4287
  import { basename, extname, resolve } from "path";
@@ -5653,7 +5613,7 @@ The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (Op
5653
5613
  ## What Remy apps are NOT good for
5654
5614
 
5655
5615
  - Native mobile apps (iOS/Android). Mobile-responsive web apps are fine.
5656
- - Fast-twitch multiplayer and live co-editing (shared cursors, 60fps sync) \u2014 client\u2192server is always a method invoke, so sub-100ms bidirectional interaction isn't a fit.
5616
+ - Real-time action games (server-authoritative simulation, guaranteed-order sync) \u2014 event delivery is at-most-once and ordering is the app's job, so there is no server tick to build one on.
5657
5617
  </platform_brief>`;
5658
5618
  }
5659
5619
  var init_context = __esm({
@@ -5818,7 +5778,7 @@ var log9, CAPTURE_COMMANDS, browserAutomationTool;
5818
5778
  var init_browserAutomation = __esm({
5819
5779
  "src/subagents/browserAutomation/index.ts"() {
5820
5780
  "use strict";
5821
- init_tools8();
5781
+ init_tools9();
5822
5782
  init_runner();
5823
5783
  init_tools2();
5824
5784
  init_tools();
@@ -5983,62 +5943,175 @@ var init_screenshot2 = __esm({
5983
5943
  }
5984
5944
  });
5985
5945
 
5986
- // src/subagents/designExpert/tools/searchGoogle.ts
5987
- var searchGoogle_exports = {};
5988
- __export(searchGoogle_exports, {
5989
- definition: () => definition,
5990
- execute: () => execute
5991
- });
5992
- async function execute(input, onLog) {
5946
+ // src/subagents/research/tools.ts
5947
+ async function executeSearchGoogle(input, onLog, caller) {
5948
+ const fetchTopN = Math.max(0, Math.round(Number(input.fetchTopN) || 0));
5993
5949
  return runMindstudioCli(
5994
5950
  [
5995
5951
  "search-google",
5996
5952
  "--query",
5997
- input.query,
5953
+ String(input.query),
5998
5954
  "--export-type",
5999
5955
  "json",
6000
5956
  "--fetch-top-n",
6001
- String(FETCH_TOP_N2)
5957
+ String(fetchTopN)
6002
5958
  ],
6003
5959
  {
6004
5960
  outputKey: "results",
5961
+ maxBuffer: SEARCH_MAX_BUFFER,
6005
5962
  onLog,
6006
- caller: "designExpert",
6007
- maxBuffer: SEARCH_MAX_BUFFER
5963
+ caller
6008
5964
  }
6009
5965
  );
6010
5966
  }
6011
- var FETCH_TOP_N2, definition;
6012
- var init_searchGoogle2 = __esm({
6013
- "src/subagents/designExpert/tools/searchGoogle.ts"() {
5967
+ async function executeScrapeWebUrl(input, onLog, caller) {
5968
+ return runMindstudioCli(
5969
+ [
5970
+ "scrape-url",
5971
+ "--url",
5972
+ String(input.url),
5973
+ "--page-options",
5974
+ JSON.stringify({ onlyMainContent: true })
5975
+ ],
5976
+ {
5977
+ maxBuffer: SCRAPE_MAX_BUFFER,
5978
+ onLog,
5979
+ caller
5980
+ }
5981
+ );
5982
+ }
5983
+ var searchGoogleDefinition, scrapeWebUrlDefinition, RESEARCH_TOOLS;
5984
+ var init_tools3 = __esm({
5985
+ "src/subagents/research/tools.ts"() {
6014
5986
  "use strict";
5987
+ init_tools();
6015
5988
  init_runMindstudioCli();
6016
5989
  init_runCli();
6017
- FETCH_TOP_N2 = 5;
6018
- definition = {
5990
+ init_bash();
5991
+ searchGoogleDefinition = {
6019
5992
  name: "searchGoogle",
6020
- description: 'Search Google for web results. Reserch modern design trends in industries or verticals, "best [domain] apps 2026", ui patterns, or find something specific if the the user has an explicit reference. Searching for and reading case studies is a great way to get information and context about a project\'s domain. Prioritize authoritative sources like Figma and other design leaders, avoid random blog spam. The top results come back with their page content already included, so read those directly \u2014 only use `scrapeWebUrl` for a result further down the list, or for a URL this did not return.',
5993
+ description: "Search Google. Returns ~25 results (title, description, URL) \u2014 fast (~5s) when `fetchTopN` is omitted. Set `fetchTopN` (3\u20135) to also get the top results' page content inline, capped at ~4,000 chars per page \u2014 one call delivers excerpts, but it is much slower (~30\u201360s). Default pattern: fire SERP-only searches in parallel, then scrape the specific pages worth reading in full.",
6021
5994
  inputSchema: {
6022
5995
  type: "object",
6023
5996
  properties: {
6024
5997
  query: {
6025
5998
  type: "string",
6026
5999
  description: "The search query."
6000
+ },
6001
+ fetchTopN: {
6002
+ type: "number",
6003
+ description: "Also fetch page content (capped ~4,000 chars each) for this many top results. Omit for a fast SERP-only search."
6027
6004
  }
6028
6005
  },
6029
6006
  required: ["query"]
6030
6007
  }
6031
6008
  };
6009
+ scrapeWebUrlDefinition = {
6010
+ name: "scrapeWebUrl",
6011
+ description: "Fetch a web page as markdown. Renders JavaScript, so client-rendered pages come back complete. Returns the full page \u2014 long docs can run tens of thousands of tokens, so fetch only pages you have chosen to read, and fire independent fetches in parallel. For code hosted on GitHub/npm, prefer cloning with bash over scraping the repo page.",
6012
+ inputSchema: {
6013
+ type: "object",
6014
+ properties: {
6015
+ url: {
6016
+ type: "string",
6017
+ description: "The URL to fetch."
6018
+ }
6019
+ },
6020
+ required: ["url"]
6021
+ }
6022
+ };
6023
+ RESEARCH_TOOLS = [
6024
+ ...COMMON_READ_TOOLS,
6025
+ searchGoogleDefinition,
6026
+ scrapeWebUrlDefinition,
6027
+ bashTool.definition
6028
+ ];
6029
+ }
6030
+ });
6031
+
6032
+ // src/subagents/research/index.ts
6033
+ async function runResearch(task, context) {
6034
+ const specIndex = loadSpecIndex();
6035
+ const parts = [BASE_PROMPT2, loadPlatformBrief()];
6036
+ parts.push("<!-- cache_breakpoint -->");
6037
+ if (specIndex) {
6038
+ parts.push(specIndex);
6039
+ }
6040
+ const system = parts.join("\n\n");
6041
+ const result = await runSubAgent({
6042
+ system,
6043
+ task,
6044
+ tools: RESEARCH_TOOLS,
6045
+ externalTools: /* @__PURE__ */ new Set(),
6046
+ executeTool: (name, toolInput, toolCallId, onLog, sams) => {
6047
+ const childCtx = toolCallId ? {
6048
+ ...deriveContext(context, toolCallId, onLog),
6049
+ subAgentMessages: sams
6050
+ } : context;
6051
+ if (name === "searchGoogle") {
6052
+ return executeSearchGoogle(toolInput, childCtx.onLog, "research");
6053
+ }
6054
+ if (name === "scrapeWebUrl") {
6055
+ return executeScrapeWebUrl(toolInput, childCtx.onLog, "research");
6056
+ }
6057
+ return executeTool(name, toolInput, childCtx);
6058
+ },
6059
+ apiConfig: context.apiConfig,
6060
+ model: resolveModel("research", context.models, context.model),
6061
+ subAgentId: "research",
6062
+ signal: context.signal,
6063
+ parentToolId: context.toolCallId,
6064
+ requestId: context.requestId,
6065
+ onEvent: context.onEvent,
6066
+ resolveExternalTool: context.resolveExternalTool,
6067
+ toolRegistry: context.toolRegistry
6068
+ });
6069
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
6070
+ return result.text;
6071
+ }
6072
+ var BASE_PROMPT2, researchTool;
6073
+ var init_research = __esm({
6074
+ "src/subagents/research/index.ts"() {
6075
+ "use strict";
6076
+ init_assets();
6077
+ init_runner();
6078
+ init_context();
6079
+ init_tools9();
6080
+ init_tools3();
6081
+ init_surfaces();
6082
+ BASE_PROMPT2 = readAsset("subagents/research", "prompt.md");
6083
+ researchTool = {
6084
+ definition: {
6085
+ name: "research",
6086
+ description: "Your researcher. Hand it a question and it searches the web, reads the pages and source code that matter, and returns a distilled, citation-backed report. Use it for both objective research like third-party APIs and services, as well as for subjective things like current trends, patterns, and approaches (from architecture to UI to even just high-level framings and ideas). Brief it neutrally: state the question and the relevant project context, not the answer you expect.",
6087
+ inputSchema: {
6088
+ type: "object",
6089
+ properties: {
6090
+ task: {
6091
+ type: "string",
6092
+ description: "What you need to find out, in natural language, plus any project context it cannot get from reading the spec. Phrase it as a question to answer, not a conclusion to confirm."
6093
+ }
6094
+ },
6095
+ required: ["task"]
6096
+ }
6097
+ },
6098
+ async execute(input, context) {
6099
+ if (!context) {
6100
+ return "Error: research requires execution context";
6101
+ }
6102
+ return runResearch(input.task, context);
6103
+ }
6104
+ };
6032
6105
  }
6033
6106
  });
6034
6107
 
6035
6108
  // src/subagents/designExpert/tools/scrapeWebUrl.ts
6036
6109
  var scrapeWebUrl_exports = {};
6037
6110
  __export(scrapeWebUrl_exports, {
6038
- definition: () => definition2,
6039
- execute: () => execute2
6111
+ definition: () => definition,
6112
+ execute: () => execute
6040
6113
  });
6041
- async function execute2(input, onLog) {
6114
+ async function execute(input, onLog) {
6042
6115
  const pageOptions = { onlyMainContent: true };
6043
6116
  return runMindstudioCli(
6044
6117
  [
@@ -6051,15 +6124,15 @@ async function execute2(input, onLog) {
6051
6124
  { onLog, caller: "designExpert", maxBuffer: SCRAPE_MAX_BUFFER }
6052
6125
  );
6053
6126
  }
6054
- var definition2;
6127
+ var definition;
6055
6128
  var init_scrapeWebUrl = __esm({
6056
6129
  "src/subagents/designExpert/tools/scrapeWebUrl.ts"() {
6057
6130
  "use strict";
6058
6131
  init_runMindstudioCli();
6059
6132
  init_runCli();
6060
- definition2 = {
6133
+ definition = {
6061
6134
  name: "scrapeWebUrl",
6062
- description: "Fetch the content of a web page as markdown. Use when reading sites from search results or specific things the user wants to incorporate.",
6135
+ description: "Fetch the content of a web page as markdown. Use for reading a specific URL \u2014 a site the user referenced, a brand to match, a page the researcher cited that you want in full.",
6063
6136
  inputSchema: {
6064
6137
  type: "object",
6065
6138
  properties: {
@@ -6078,14 +6151,14 @@ var init_scrapeWebUrl = __esm({
6078
6151
  var renderImage_exports = {};
6079
6152
  __export(renderImage_exports, {
6080
6153
  RENDER_ANALYZE_PROMPT: () => RENDER_ANALYZE_PROMPT,
6081
- definition: () => definition3,
6082
- execute: () => execute3
6154
+ definition: () => definition2,
6155
+ execute: () => execute2
6083
6156
  });
6084
6157
  import { mkdir, unlink, writeFile } from "fs/promises";
6085
6158
  import { tmpdir } from "os";
6086
6159
  import { dirname, join, resolve as resolve2, sep } from "path";
6087
6160
  import { randomUUID } from "crypto";
6088
- async function execute3(input, onLog, context) {
6161
+ async function execute2(input, onLog, context) {
6089
6162
  const html = typeof input.html === "string" ? input.html : "";
6090
6163
  const width = Math.round(Number(input.width));
6091
6164
  const height = Math.round(Number(input.height));
@@ -6169,7 +6242,7 @@ async function execute3(input, onLog, context) {
6169
6242
  ]
6170
6243
  });
6171
6244
  }
6172
- var MIN_DIMENSION, MAX_DIMENSION, RENDER_ANALYZE_PROMPT, definition3;
6245
+ var MIN_DIMENSION, MAX_DIMENSION, RENDER_ANALYZE_PROMPT, definition2;
6173
6246
  var init_renderImage = __esm({
6174
6247
  "src/subagents/designExpert/tools/images/renderImage.ts"() {
6175
6248
  "use strict";
@@ -6182,7 +6255,7 @@ var init_renderImage = __esm({
6182
6255
  MIN_DIMENSION = 16;
6183
6256
  MAX_DIMENSION = 4096;
6184
6257
  RENDER_ANALYZE_PROMPT = 'You are reviewing a browser-rendered graphic (composed from HTML/CSS by a designer) for fidelity. Report: whether the composition fills the full canvas or leaves unintended gaps at any edge, any clipped or overflowing text, whether custom webfonts appear to have loaded (distinctive letterforms vs generic fallback serif/sans), any misalignment or uneven spacing, any unintended scrollbars or default-styling artifacts, and \u2014 if the background is transparent \u2014 any fringing or stray opaque pixels at the edges. Then briefly describe the overall composition and how polished it looks. Be concise and practical. Respond only with your analysis as Markdown (starting with the title "Render Review") and absolutely no other text. Do not use emojis - use unicode if you need symbols.';
6185
- definition3 = {
6258
+ definition2 = {
6186
6259
  name: "renderImage",
6187
6260
  description: "Render a self-contained HTML document in a real browser and capture it as a hosted PNG at exact pixel dimensions, with a fidelity review included. Deterministic \u2014 exact hex colors, real loaded webfonts, precise geometry \u2014 unlike generateImages, which is an image model. Use for token-exact graphics: Open Graph share cards, wordmarks, flat/geometric icon tiles, badges, any composition where letterforms and spacing carry the design. Compose with HTML/CSS (link webfonts from CDNs \u2014 the renderer waits for them to load); inline existing SVG markup when needed, but never hand-write new SVG path data.",
6188
6261
  inputSchema: {
@@ -6222,8 +6295,8 @@ var init_renderImage = __esm({
6222
6295
  // src/subagents/designExpert/tools/analyzeDesign.ts
6223
6296
  var analyzeDesign_exports = {};
6224
6297
  __export(analyzeDesign_exports, {
6225
- definition: () => definition4,
6226
- execute: () => execute4
6298
+ definition: () => definition3,
6299
+ execute: () => execute3
6227
6300
  });
6228
6301
  import { readFile as readFile2 } from "fs/promises";
6229
6302
  import { extname as extname2, join as join2 } from "path";
@@ -6245,7 +6318,7 @@ function splitFrontmatter(raw) {
6245
6318
  html: raw.slice(match[0].length)
6246
6319
  };
6247
6320
  }
6248
- async function execute4(input, onLog, context) {
6321
+ async function execute3(input, onLog, context) {
6249
6322
  const url = String(input.url ?? "").trim();
6250
6323
  if (!url) {
6251
6324
  return "Error: url is required.";
@@ -6349,7 +6422,7 @@ ${basePrompt}` : basePrompt;
6349
6422
  renderedHeight: rendered.height
6350
6423
  });
6351
6424
  }
6352
- var DESIGN_REFERENCE_PROMPT, definition4, IMAGE_EXT_RE, HTML_EXTS, HTML_RENDER_WIDTH, HTML_RENDER_START_HEIGHT;
6425
+ var DESIGN_REFERENCE_PROMPT, definition3, IMAGE_EXT_RE, HTML_EXTS, HTML_RENDER_WIDTH, HTML_RENDER_START_HEIGHT;
6353
6426
  var init_analyzeDesign = __esm({
6354
6427
  "src/subagents/designExpert/tools/analyzeDesign.ts"() {
6355
6428
  "use strict";
@@ -6384,7 +6457,7 @@ Identify the specific design moves that make this page interesting and unique, d
6384
6457
 
6385
6458
  Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.
6386
6459
  `;
6387
- definition4 = {
6460
+ definition3 = {
6388
6461
  name: "analyzeDesign",
6389
6462
  description: "Analyze the visual design of a website, an image (URL or file on disk), or an HTML document on disk. Websites are screenshotted first; an HTML file is rendered in a real browser first and the render is analyzed, which is how you look at a wireframe you authored. Provides static image analysis only, will not capture animations or video. With no prompt, a website or image gets a full design reference analysis (mood, color, typography, layout, distinctiveness) and a rendered HTML document gets a fidelity review (clipping, overflow, webfont loading, alignment). Provide a custom prompt to ask a specific design question instead. Use a bulleted list to ask many questions at once.",
6390
6463
  inputSchema: {
@@ -6412,10 +6485,10 @@ Respond only with your analysis as Markdown and absolutely no other text. Do not
6412
6485
  // src/subagents/designExpert/tools/analyzeImage.ts
6413
6486
  var analyzeImage_exports = {};
6414
6487
  __export(analyzeImage_exports, {
6415
- definition: () => definition5,
6416
- execute: () => execute5
6488
+ definition: () => definition4,
6489
+ execute: () => execute4
6417
6490
  });
6418
- async function execute5(input, onLog, context) {
6491
+ async function execute4(input, onLog, context) {
6419
6492
  const prompt = buildScreenshotAnalysisPrompt({
6420
6493
  prompt: input.prompt
6421
6494
  });
@@ -6428,14 +6501,14 @@ async function execute5(input, onLog, context) {
6428
6501
  });
6429
6502
  return JSON.stringify({ url, analysis });
6430
6503
  }
6431
- var definition5;
6504
+ var definition4;
6432
6505
  var init_analyzeImage2 = __esm({
6433
6506
  "src/subagents/designExpert/tools/analyzeImage.ts"() {
6434
6507
  "use strict";
6435
6508
  init_analyzeImage();
6436
6509
  init_screenshot();
6437
6510
  init_surfaces();
6438
- definition5 = {
6511
+ definition4 = {
6439
6512
  name: "analyzeImage",
6440
6513
  description: "Analyze an image using a vision model. Provides static image analysis only, will not capture animations or video. Returns an objective description of what is visible \u2014 shapes, colors, layout, text, artifacts. Use for factual inventory of image contents, not for subjective design judgment - the vision model providing the analysis has no sense of design. You are the design expert - use the analysis tool for factual inventory, then apply your own expertise for quality and suitability assessments. Optionally provide specific questions about what you're looking for. Use a bulleted list to ask many questions at once. If you are analyzing a screenshot of the app preview, you can reuse the same screenshot URL multiple times to ask multiple questions.",
6441
6514
  inputSchema: {
@@ -6703,10 +6776,10 @@ var init_imageGenerator = __esm({
6703
6776
  // src/subagents/designExpert/tools/images/generateImages.ts
6704
6777
  var generateImages_exports = {};
6705
6778
  __export(generateImages_exports, {
6706
- definition: () => definition6,
6707
- execute: () => execute6
6779
+ definition: () => definition5,
6780
+ execute: () => execute5
6708
6781
  });
6709
- async function execute6(input, onLog, context) {
6782
+ async function execute5(input, onLog, context) {
6710
6783
  return generateImageAssets({
6711
6784
  prompts: input.prompts,
6712
6785
  width: input.width,
@@ -6733,13 +6806,13 @@ async function execute6(input, onLog, context) {
6733
6806
  )
6734
6807
  });
6735
6808
  }
6736
- var definition6;
6809
+ var definition5;
6737
6810
  var init_generateImages = __esm({
6738
6811
  "src/subagents/designExpert/tools/images/generateImages.ts"() {
6739
6812
  "use strict";
6740
6813
  init_imageGenerator();
6741
6814
  init_surfaces();
6742
- definition6 = {
6815
+ definition5 = {
6743
6816
  name: "generateImages",
6744
6817
  description: "Generate images. Returns CDN URLs with a quality analysis for each image. Produces high-quality results for everything from photorealistic images and abstract/creative visuals. Pass multiple prompts to generate in parallel. No need to analyze images separately after generating \u2014 the analysis is included.",
6745
6818
  inputSchema: {
@@ -6778,10 +6851,10 @@ var init_generateImages = __esm({
6778
6851
  // src/subagents/designExpert/tools/images/editImages.ts
6779
6852
  var editImages_exports = {};
6780
6853
  __export(editImages_exports, {
6781
- definition: () => definition7,
6782
- execute: () => execute7
6854
+ definition: () => definition6,
6855
+ execute: () => execute6
6783
6856
  });
6784
- async function execute7(input, onLog, context) {
6857
+ async function execute6(input, onLog, context) {
6785
6858
  return generateImageAssets({
6786
6859
  prompts: input.prompts,
6787
6860
  sourceImages: input.sourceImages,
@@ -6808,13 +6881,13 @@ async function execute7(input, onLog, context) {
6808
6881
  )
6809
6882
  });
6810
6883
  }
6811
- var definition7;
6884
+ var definition6;
6812
6885
  var init_editImages = __esm({
6813
6886
  "src/subagents/designExpert/tools/images/editImages.ts"() {
6814
6887
  "use strict";
6815
6888
  init_imageGenerator();
6816
6889
  init_surfaces();
6817
- definition7 = {
6890
+ definition6 = {
6818
6891
  name: "editImages",
6819
6892
  description: "Edit or transform existing images. Provide one or more source image URLs as reference and a prompt describing the desired edit. Use for compositing, style transfer, subject transformation, blending multiple references, or incorporating one or more references into something new. Returns CDN URLs with analysis.",
6820
6893
  inputSchema: {
@@ -6855,7 +6928,7 @@ var init_editImages = __esm({
6855
6928
 
6856
6929
  // src/subagents/copyEditor/tools.ts
6857
6930
  var COPY_EDITOR_TOOLS;
6858
- var init_tools3 = __esm({
6931
+ var init_tools4 = __esm({
6859
6932
  "src/subagents/copyEditor/tools.ts"() {
6860
6933
  "use strict";
6861
6934
  init_tools();
@@ -6864,17 +6937,17 @@ var init_tools3 = __esm({
6864
6937
  });
6865
6938
 
6866
6939
  // src/subagents/copyEditor/index.ts
6867
- var BASE_PROMPT2, copyEditorTool;
6940
+ var BASE_PROMPT3, copyEditorTool;
6868
6941
  var init_copyEditor = __esm({
6869
6942
  "src/subagents/copyEditor/index.ts"() {
6870
6943
  "use strict";
6871
6944
  init_assets();
6872
6945
  init_runner();
6873
6946
  init_context();
6874
- init_tools8();
6875
- init_tools3();
6947
+ init_tools9();
6948
+ init_tools4();
6876
6949
  init_surfaces();
6877
- BASE_PROMPT2 = readAsset("subagents/copyEditor", "prompt.md");
6950
+ BASE_PROMPT3 = readAsset("subagents/copyEditor", "prompt.md");
6878
6951
  copyEditorTool = {
6879
6952
  definition: {
6880
6953
  name: "copyEditor",
@@ -6895,7 +6968,7 @@ var init_copyEditor = __esm({
6895
6968
  return "Error: copy editor requires execution context";
6896
6969
  }
6897
6970
  const specIndex = loadSpecIndex();
6898
- const parts = [BASE_PROMPT2];
6971
+ const parts = [BASE_PROMPT3];
6899
6972
  parts.push("<!-- cache_breakpoint -->");
6900
6973
  if (specIndex) {
6901
6974
  parts.push(specIndex);
@@ -6933,18 +7006,18 @@ var init_copyEditor = __esm({
6933
7006
  // src/subagents/designExpert/tools/polishCopy.ts
6934
7007
  var polishCopy_exports = {};
6935
7008
  __export(polishCopy_exports, {
6936
- definition: () => definition8,
6937
- execute: () => execute8
7009
+ definition: () => definition7,
7010
+ execute: () => execute7
6938
7011
  });
6939
- async function execute8(input, _onLog, context) {
7012
+ async function execute7(input, _onLog, context) {
6940
7013
  return copyEditorTool.execute(input, context);
6941
7014
  }
6942
- var definition8;
7015
+ var definition7;
6943
7016
  var init_polishCopy = __esm({
6944
7017
  "src/subagents/designExpert/tools/polishCopy.ts"() {
6945
7018
  "use strict";
6946
7019
  init_copyEditor();
6947
- definition8 = {
7020
+ definition7 = {
6948
7021
  name: "polishCopy",
6949
7022
  description: "Hand off any user-facing copy you've written \u2014 headlines, captions, labels, body text \u2014 and get back a sharper version: better built for its audience and free of the fingerprints that make writing read as AI. It elevates how the copy communicates without inventing facts or claims you didn't give it. Give it the text plus what it's for (where it appears, the audience).",
6950
7023
  inputSchema: {
@@ -6982,10 +7055,10 @@ A loaded reference drops out of the conversation once it ages out. Re-read it at
6982
7055
  // src/subagents/designExpert/tools/loadSkill.ts
6983
7056
  var loadSkill_exports = {};
6984
7057
  __export(loadSkill_exports, {
6985
- definition: () => definition9,
6986
- execute: () => execute9
7058
+ definition: () => definition8,
7059
+ execute: () => execute8
6987
7060
  });
6988
- async function execute9(input) {
7061
+ async function execute8(input) {
6989
7062
  const id = String(input.skill ?? "");
6990
7063
  const skill = designSkillCatalog.get(id);
6991
7064
  if (!skill) {
@@ -7001,12 +7074,12 @@ This reference lives at ${skill.path}. Re-read it with readFile if you need it a
7001
7074
  return `Error loading skill "${id}": ${err.message}`;
7002
7075
  }
7003
7076
  }
7004
- var definition9;
7077
+ var definition8;
7005
7078
  var init_loadSkill2 = __esm({
7006
7079
  "src/subagents/designExpert/tools/loadSkill.ts"() {
7007
7080
  "use strict";
7008
7081
  init_catalog2();
7009
- definition9 = {
7082
+ definition8 = {
7010
7083
  name: "loadSkill",
7011
7084
  description: "Load the full craft reference for a design surface that isn't in your prompt. The available skills and the trigger for each are listed in <available_skills>. Load one before designing in its area, not after \u2014 these are hard-won technique recipes, and the defaulted version of these surfaces is exactly what they exist to prevent. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it.",
7012
7085
  inputSchema: {
@@ -7031,8 +7104,8 @@ var init_loadSkill2 = __esm({
7031
7104
  var createWireframe_exports = {};
7032
7105
  __export(createWireframe_exports, {
7033
7106
  WIREFRAMES_DIR: () => WIREFRAMES_DIR,
7034
- definition: () => definition10,
7035
- execute: () => execute10
7107
+ definition: () => definition9,
7108
+ execute: () => execute9
7036
7109
  });
7037
7110
  import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
7038
7111
  import { join as join3 } from "path";
@@ -7103,7 +7176,7 @@ async function uploadMirror(context, slug, content) {
7103
7176
  return { ok: false, note: err.message };
7104
7177
  }
7105
7178
  }
7106
- async function execute10(input, onLog, context) {
7179
+ async function execute9(input, onLog, context) {
7107
7180
  if (!context) {
7108
7181
  return "Error: createWireframe requires execution context";
7109
7182
  }
@@ -7149,7 +7222,7 @@ async function execute10(input, onLog, context) {
7149
7222
  }
7150
7223
  return lines.join("\n");
7151
7224
  }
7152
- var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition10, SLUG_RE;
7225
+ var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition9, SLUG_RE;
7153
7226
  var init_createWireframe = __esm({
7154
7227
  "src/subagents/designExpert/tools/createWireframe.ts"() {
7155
7228
  "use strict";
@@ -7158,7 +7231,7 @@ var init_createWireframe = __esm({
7158
7231
  log10 = createLogger("createWireframe");
7159
7232
  WIREFRAMES_DIR = "src/.wireframes";
7160
7233
  UPLOAD_TIMEOUT_MS2 = 3e4;
7161
- definition10 = {
7234
+ definition9 = {
7162
7235
  name: "createWireframe",
7163
7236
  description: "Generate a wireframe from self-contained HTML+CSS you author and write it to disk as a design artifact. This is how a wireframe comes to exist \u2014 the way generateImages is how an image comes to exist \u2014 and the developer builds from the file it creates. The result also hands back the reference line that embeds the wireframe in your response and in specs; paste it wherever the wireframe belongs and it renders as a live preview. Calling again with the same slug revises the wireframe in place, so existing references stay current \u2014 a revision is a call to this tool, never a prose description of changes to an earlier wireframe.",
7164
7237
  inputSchema: {
@@ -7197,13 +7270,13 @@ async function executeDesignExpertTool(name, input, context, toolCallId, onLog)
7197
7270
  const childContext = context && toolCallId ? deriveContext(context, toolCallId, onLog) : context;
7198
7271
  return tool.execute(input, onLog, childContext);
7199
7272
  }
7200
- var tools, DESIGN_EXPERT_TOOLS;
7201
- var init_tools4 = __esm({
7273
+ var research, tools, DESIGN_EXPERT_TOOLS;
7274
+ var init_tools5 = __esm({
7202
7275
  "src/subagents/designExpert/tools/index.ts"() {
7203
7276
  "use strict";
7204
- init_tools8();
7277
+ init_tools9();
7205
7278
  init_tools();
7206
- init_searchGoogle2();
7279
+ init_research();
7207
7280
  init_scrapeWebUrl();
7208
7281
  init_analyzeDesign();
7209
7282
  init_analyzeImage2();
@@ -7214,8 +7287,29 @@ var init_tools4 = __esm({
7214
7287
  init_loadSkill2();
7215
7288
  init_createWireframe();
7216
7289
  init_screenshot2();
7290
+ research = {
7291
+ definition: {
7292
+ name: "research",
7293
+ description: "Your researcher, for design questions your built-in catalogs and expertise do not settle: how leading products present a specific kind of data or interaction, current conventions or best practices for a pattern, general-purpose ideas and inspiration. It searches the web, reads the sources that matter, and returns a distilled report with citations and concrete specifics. Brief it neutrally: the question or topic, not the answer you expect.",
7294
+ inputSchema: {
7295
+ type: "object",
7296
+ properties: {
7297
+ task: {
7298
+ type: "string",
7299
+ description: "What you need to find out, in natural language, with enough product context to make the findings relevant."
7300
+ }
7301
+ },
7302
+ required: ["task"]
7303
+ }
7304
+ },
7305
+ execute: (input, _onLog, context) => {
7306
+ if (!context) {
7307
+ return Promise.resolve("Error: research requires execution context");
7308
+ }
7309
+ return runResearch(input.task, context);
7310
+ }
7311
+ };
7217
7312
  tools = {
7218
- searchGoogle: searchGoogle_exports,
7219
7313
  scrapeWebUrl: scrapeWebUrl_exports,
7220
7314
  analyzeDesign: analyzeDesign_exports,
7221
7315
  analyzeImage: analyzeImage_exports,
@@ -7229,7 +7323,8 @@ var init_tools4 = __esm({
7229
7323
  polishCopy: polishCopy_exports,
7230
7324
  loadSkill: loadSkill_exports,
7231
7325
  // Appended last: tool order is part of the subagent's prompt-cache prefix.
7232
- createWireframe: createWireframe_exports
7326
+ createWireframe: createWireframe_exports,
7327
+ research
7233
7328
  };
7234
7329
  DESIGN_EXPERT_TOOLS = [
7235
7330
  ...COMMON_READ_TOOLS,
@@ -7708,9 +7803,9 @@ var DESCRIPTION, RENDER_WRITE_TOOL_NAMES, DESIGN_EXPERT_RENDER_TOOLS, designExpe
7708
7803
  var init_designExpert = __esm({
7709
7804
  "src/subagents/designExpert/index.ts"() {
7710
7805
  "use strict";
7711
- init_tools8();
7806
+ init_tools9();
7712
7807
  init_runner();
7713
- init_tools4();
7808
+ init_tools5();
7714
7809
  init_tools();
7715
7810
  init_prompt2();
7716
7811
  init_validateWireframeRefs();
@@ -7766,7 +7861,7 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
7766
7861
 
7767
7862
  // src/subagents/productVision/tools.ts
7768
7863
  var VISION_TOOLS;
7769
- var init_tools5 = __esm({
7864
+ var init_tools6 = __esm({
7770
7865
  "src/subagents/productVision/tools.ts"() {
7771
7866
  "use strict";
7772
7867
  init_tools();
@@ -7936,7 +8031,7 @@ var init_executor = __esm({
7936
8031
  function getProductVisionPrompt() {
7937
8032
  const specIndex = loadSpecIndex();
7938
8033
  const roadmapIndex = loadRoadmapIndex();
7939
- const parts = [BASE_PROMPT3, loadPlatformBrief()];
8034
+ const parts = [BASE_PROMPT4, loadPlatformBrief()];
7940
8035
  parts.push("<!-- cache_breakpoint -->");
7941
8036
  if (specIndex) {
7942
8037
  parts.push(specIndex);
@@ -7946,13 +8041,13 @@ function getProductVisionPrompt() {
7946
8041
  }
7947
8042
  return parts.join("\n\n");
7948
8043
  }
7949
- var BASE_PROMPT3;
8044
+ var BASE_PROMPT4;
7950
8045
  var init_prompt3 = __esm({
7951
8046
  "src/subagents/productVision/prompt.ts"() {
7952
8047
  "use strict";
7953
8048
  init_assets();
7954
8049
  init_context();
7955
- BASE_PROMPT3 = readAsset("subagents/productVision", "prompt.md");
8050
+ BASE_PROMPT4 = readAsset("subagents/productVision", "prompt.md");
7956
8051
  }
7957
8052
  });
7958
8053
 
@@ -7961,9 +8056,9 @@ var productVisionTool;
7961
8056
  var init_productVision = __esm({
7962
8057
  "src/subagents/productVision/index.ts"() {
7963
8058
  "use strict";
7964
- init_tools8();
8059
+ init_tools9();
7965
8060
  init_runner();
7966
- init_tools5();
8061
+ init_tools6();
7967
8062
  init_tools();
7968
8063
  init_executor();
7969
8064
  init_prompt3();
@@ -8039,7 +8134,7 @@ var init_productVision = __esm({
8039
8134
 
8040
8135
  // src/subagents/codeSanityCheck/tools.ts
8041
8136
  var SANITY_CHECK_TOOLS;
8042
- var init_tools6 = __esm({
8137
+ var init_tools7 = __esm({
8043
8138
  "src/subagents/codeSanityCheck/tools.ts"() {
8044
8139
  "use strict";
8045
8140
  init_tools();
@@ -8088,23 +8183,40 @@ var init_tools6 = __esm({
8088
8183
  },
8089
8184
  required: ["command"]
8090
8185
  }
8186
+ },
8187
+ // Appended last: tool order is part of the subagent's prompt-cache prefix.
8188
+ {
8189
+ name: "research",
8190
+ description: "Deep researcher. When the plan hinges on an unfamiliar third-party service, API, or claim you cannot settle with a quick search, hand it the question \u2014 it researches properly (multiple sources, official docs, reading real source code) and returns a distilled, citation-backed report. Quick package-liveness checks stay on searchGoogle; use this when being wrong would be expensive. Brief it neutrally: the question, not the answer you expect.",
8191
+ inputSchema: {
8192
+ type: "object",
8193
+ properties: {
8194
+ task: {
8195
+ type: "string",
8196
+ description: "What you need to find out, in natural language."
8197
+ }
8198
+ },
8199
+ required: ["task"]
8200
+ }
8091
8201
  }
8092
8202
  ];
8093
8203
  }
8094
8204
  });
8095
8205
 
8096
8206
  // src/subagents/codeSanityCheck/index.ts
8097
- var BASE_PROMPT4, codeSanityCheckTool;
8207
+ var BASE_PROMPT5, codeSanityCheckTool;
8098
8208
  var init_codeSanityCheck = __esm({
8099
8209
  "src/subagents/codeSanityCheck/index.ts"() {
8100
8210
  "use strict";
8101
8211
  init_assets();
8102
8212
  init_runner();
8103
8213
  init_context();
8104
- init_tools8();
8105
- init_tools6();
8214
+ init_tools9();
8215
+ init_tools7();
8216
+ init_research();
8217
+ init_tools3();
8106
8218
  init_surfaces();
8107
- BASE_PROMPT4 = readAsset("subagents/codeSanityCheck", "prompt.md");
8219
+ BASE_PROMPT5 = readAsset("subagents/codeSanityCheck", "prompt.md");
8108
8220
  codeSanityCheckTool = {
8109
8221
  definition: {
8110
8222
  name: "codeSanityCheck",
@@ -8125,7 +8237,7 @@ var init_codeSanityCheck = __esm({
8125
8237
  return "Error: code sanity check requires execution context";
8126
8238
  }
8127
8239
  const specIndex = loadSpecIndex();
8128
- const parts = [BASE_PROMPT4, loadPlatformBrief()];
8240
+ const parts = [BASE_PROMPT5, loadPlatformBrief()];
8129
8241
  parts.push("<!-- cache_breakpoint -->");
8130
8242
  if (specIndex) {
8131
8243
  parts.push(specIndex);
@@ -8141,6 +8253,16 @@ var init_codeSanityCheck = __esm({
8141
8253
  ...deriveContext(context, toolCallId, onLog),
8142
8254
  subAgentMessages: sams
8143
8255
  } : context;
8256
+ if (name === "searchGoogle") {
8257
+ return executeSearchGoogle(
8258
+ { ...toolInput, fetchTopN: 5 },
8259
+ childCtx.onLog,
8260
+ "codeSanityCheck"
8261
+ );
8262
+ }
8263
+ if (name === "research") {
8264
+ return runResearch(String(toolInput.task ?? ""), childCtx);
8265
+ }
8144
8266
  return executeTool(name, toolInput, childCtx);
8145
8267
  },
8146
8268
  apiConfig: context.apiConfig,
@@ -8284,7 +8406,7 @@ The copy in <overview_copy> is final \u2014 it was authored and edited before it
8284
8406
 
8285
8407
  // src/subagents/specSync/tools.ts
8286
8408
  var SPEC_SYNC_TOOLS;
8287
- var init_tools7 = __esm({
8409
+ var init_tools8 = __esm({
8288
8410
  "src/subagents/specSync/tools.ts"() {
8289
8411
  "use strict";
8290
8412
  init_tools();
@@ -8319,19 +8441,19 @@ var init_lock = __esm({
8319
8441
  });
8320
8442
 
8321
8443
  // src/subagents/specSync/index.ts
8322
- var BASE_PROMPT5, MSFM_DOCS, specSyncTool;
8444
+ var BASE_PROMPT6, MSFM_DOCS, specSyncTool;
8323
8445
  var init_specSync = __esm({
8324
8446
  "src/subagents/specSync/index.ts"() {
8325
8447
  "use strict";
8326
8448
  init_assets();
8327
8449
  init_runner();
8328
8450
  init_context();
8329
- init_tools8();
8451
+ init_tools9();
8330
8452
  init_writeBuildOverview();
8331
- init_tools7();
8453
+ init_tools8();
8332
8454
  init_lock();
8333
8455
  init_surfaces();
8334
- BASE_PROMPT5 = readAsset("subagents/specSync", "prompt.md");
8456
+ BASE_PROMPT6 = readAsset("subagents/specSync", "prompt.md");
8335
8457
  MSFM_DOCS = `<mindstudio_flavored_markdown_spec_docs>
8336
8458
  ${readAsset(
8337
8459
  "prompt",
@@ -8370,7 +8492,7 @@ ${readAsset(
8370
8492
  }
8371
8493
  const specIndex = loadSpecIndex();
8372
8494
  const parts = [
8373
- BASE_PROMPT5,
8495
+ BASE_PROMPT6,
8374
8496
  loadPlatformBrief(),
8375
8497
  MSFM_DOCS,
8376
8498
  "<!-- cache_breakpoint -->"
@@ -8502,7 +8624,7 @@ function executeTool(name, input, context) {
8502
8624
  return tool.execute(input, context);
8503
8625
  }
8504
8626
  var ALL_TOOLS, SUBAGENT_TOOL_NAMES;
8505
- var init_tools8 = __esm({
8627
+ var init_tools9 = __esm({
8506
8628
  "src/tools/index.ts"() {
8507
8629
  "use strict";
8508
8630
  init_readSpec();
@@ -8516,7 +8638,6 @@ var init_tools8 = __esm({
8516
8638
  init_promptUser();
8517
8639
  init_confirmDestructiveAction();
8518
8640
  init_sdkConsultant();
8519
- init_searchGoogle();
8520
8641
  init_setProjectMetadata();
8521
8642
  init_compactConversation();
8522
8643
  init_loadSkill();
@@ -8541,6 +8662,7 @@ var init_tools8 = __esm({
8541
8662
  init_codeSanityCheck();
8542
8663
  init_copyEditor();
8543
8664
  init_specSync();
8665
+ init_research();
8544
8666
  init_scrapeWebUrl2();
8545
8667
  init_writeBuildOverview();
8546
8668
  ALL_TOOLS = [
@@ -8550,7 +8672,6 @@ var init_tools8 = __esm({
8550
8672
  confirmDestructiveActionTool,
8551
8673
  askMindStudioSdkTool,
8552
8674
  scrapeWebUrlTool,
8553
- searchGoogleTool,
8554
8675
  setProjectMetadataTool,
8555
8676
  designExpertTool,
8556
8677
  productVisionTool,
@@ -8589,7 +8710,8 @@ var init_tools8 = __esm({
8589
8710
  // Appended rather than grouped: position is part of the cache prefix, so a
8590
8711
  // new tool goes at the end to leave every existing session's prefix intact.
8591
8712
  loadSkillTool,
8592
- testJewelTool
8713
+ testJewelTool,
8714
+ researchTool
8593
8715
  ];
8594
8716
  SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
8595
8717
  "visualDesignExpert",
@@ -8598,7 +8720,8 @@ var init_tools8 = __esm({
8598
8720
  "copyEditor",
8599
8721
  "specSync",
8600
8722
  "runAutomatedBrowserTest",
8601
- "askMindStudioSdk"
8723
+ "askMindStudioSdk",
8724
+ "research"
8602
8725
  ]);
8603
8726
  }
8604
8727
  });
@@ -10110,7 +10233,7 @@ var init_agent = __esm({
10110
10233
  "src/agent.ts"() {
10111
10234
  "use strict";
10112
10235
  init_api();
10113
- init_tools8();
10236
+ init_tools9();
10114
10237
  init_session();
10115
10238
  init_logger();
10116
10239
  init_usageLedger();
@@ -10821,7 +10944,7 @@ var init_headless = __esm({
10821
10944
  init_attachments();
10822
10945
  init_planFile();
10823
10946
  init_stats();
10824
- init_tools8();
10947
+ init_tools9();
10825
10948
  init_messageQueue();
10826
10949
  init_resolve();
10827
10950
  init_sentinel();