@mindstudio-ai/remy 0.1.69 → 0.1.71

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/README.md CHANGED
@@ -49,7 +49,7 @@ Tool availability depends on the project's onboarding state, sent by the sandbox
49
49
 
50
50
  | Tool | Description |
51
51
  |------|-------------|
52
- | `setProjectOnboardingState` | Advance the onboarding flow (intake → initialSpecAuthoring → initialCodegen → onboardingFinished) |
52
+ | `setProjectOnboardingState` | Advance the onboarding flow (intake → initialSpecReview → initialCodegen → onboardingFinished) |
53
53
  | `setProjectName` | Set the project name |
54
54
  | `promptUser` | Ask the user structured questions (form or inline display) |
55
55
  | `confirmDestructiveAction` | Confirm a destructive or irreversible action with the user |
package/dist/headless.js CHANGED
@@ -650,7 +650,7 @@ var log4 = createLogger("compaction");
650
650
  var CONVERSATION_SUMMARY_PROMPT = readAsset("compaction", "conversation.md");
651
651
  var SUBAGENT_SUMMARY_PROMPT = readAsset("compaction", "subagent.md");
652
652
  var SUMMARIZABLE_SUBAGENTS = ["visualDesignExpert", "productVision"];
653
- async function compactConversation(state, apiConfig) {
653
+ async function compactConversation(state, apiConfig, system, tools2) {
654
654
  const insertionIndex = findSafeInsertionPoint(state.messages);
655
655
  const summaries = [];
656
656
  const tasks = [];
@@ -664,7 +664,9 @@ async function compactConversation(state, apiConfig) {
664
664
  apiConfig,
665
665
  "conversation",
666
666
  CONVERSATION_SUMMARY_PROMPT,
667
- conversationMessages
667
+ conversationMessages,
668
+ system,
669
+ tools2
668
670
  ).then((text) => {
669
671
  if (text) {
670
672
  summaries.push({ name: "conversation", text });
@@ -684,7 +686,9 @@ async function compactConversation(state, apiConfig) {
684
686
  apiConfig,
685
687
  name,
686
688
  SUBAGENT_SUMMARY_PROMPT,
687
- subagentMessages
689
+ subagentMessages,
690
+ system,
691
+ tools2
688
692
  ).then((text) => {
689
693
  if (text) {
690
694
  summaries.push({ name, text });
@@ -811,22 +815,33 @@ function serializeForSummary(messages) {
811
815
  return `[${msg.role}]: ${parts.join("\n")}`;
812
816
  }).join("\n\n");
813
817
  }
814
- async function generateSummary(apiConfig, name, systemPrompt, messagesToSummarize) {
818
+ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSummarize, mainSystem, mainTools) {
815
819
  const serialized = serializeForSummary(messagesToSummarize);
816
820
  if (!serialized.trim()) {
817
821
  return null;
818
822
  }
819
823
  log4.info("Generating summary", {
820
824
  name,
821
- messageCount: messagesToSummarize.length
825
+ messageCount: messagesToSummarize.length,
826
+ cacheReuse: !!mainSystem
822
827
  });
823
828
  let summaryText = "";
829
+ const useMainCache = !!mainSystem;
830
+ const system = useMainCache ? mainSystem : compactionPrompt;
831
+ const tools2 = useMainCache ? mainTools ?? [] : [];
832
+ const userContent = useMainCache ? `${compactionPrompt}
833
+
834
+ ---
835
+
836
+ Conversation to summarize:
837
+
838
+ ${serialized}` : serialized;
824
839
  for await (const event of streamChat({
825
840
  ...apiConfig,
826
841
  subAgentId: "conversationSummarizer",
827
- system: systemPrompt,
828
- messages: [{ role: "user", content: serialized }],
829
- tools: []
842
+ system,
843
+ messages: [{ role: "user", content: userContent }],
844
+ tools: tools2
830
845
  })) {
831
846
  if (event.type === "text") {
832
847
  summaryText += event.text;
@@ -934,6 +949,7 @@ function getHeadingTree(content) {
934
949
  // src/tools/spec/readSpec.ts
935
950
  var DEFAULT_MAX_LINES = 500;
936
951
  var readSpecTool = {
952
+ clearable: true,
937
953
  definition: {
938
954
  name: "readSpec",
939
955
  description: "Read a spec file from src/ with line numbers. Always read a spec file before editing it. Paths are relative to the project root and must start with src/ (e.g., src/app.md, src/interfaces/web.md).",
@@ -1035,6 +1051,7 @@ function unifiedDiff(filePath, oldText, newText) {
1035
1051
 
1036
1052
  // src/tools/spec/writeSpec.ts
1037
1053
  var writeSpecTool = {
1054
+ clearable: true,
1038
1055
  definition: {
1039
1056
  name: "writeSpec",
1040
1057
  description: "Create a new spec file or completely overwrite an existing one in src/. Parent directories are created automatically. Use this for new spec files or full rewrites. For targeted changes to existing specs, use editSpec instead.",
@@ -1088,6 +1105,7 @@ ${unifiedDiff(input.path, oldContent ?? "", input.content)}`;
1088
1105
  // src/tools/spec/editSpec.ts
1089
1106
  import fs7 from "fs/promises";
1090
1107
  var editSpecTool = {
1108
+ clearable: true,
1091
1109
  definition: {
1092
1110
  name: "editSpec",
1093
1111
  description: 'Make targeted edits to a spec file by heading path. This is the primary tool for modifying existing specs. Each edit targets a section by its heading hierarchy (e.g., "Vendors > Approval Flow") and applies an operation. Multiple edits are applied in order.',
@@ -1201,6 +1219,7 @@ ${tree}`;
1201
1219
  import fs8 from "fs/promises";
1202
1220
  import path5 from "path";
1203
1221
  var listSpecFilesTool = {
1222
+ clearable: false,
1204
1223
  definition: {
1205
1224
  name: "listSpecFiles",
1206
1225
  description: "List all files in the src/ directory (spec files, brand guidelines, interface specs, references). Use this to understand what spec files exist before reading or editing them.",
@@ -1251,6 +1270,7 @@ async function listRecursive(dir) {
1251
1270
 
1252
1271
  // src/tools/spec/clearSyncStatus.ts
1253
1272
  var clearSyncStatusTool = {
1273
+ clearable: false,
1254
1274
  definition: {
1255
1275
  name: "clearSyncStatus",
1256
1276
  description: "Clear the sync status flags after syncing spec and code. Call this after finishing a sync operation.",
@@ -1266,6 +1286,7 @@ var clearSyncStatusTool = {
1266
1286
 
1267
1287
  // src/tools/spec/presentSyncPlan.ts
1268
1288
  var presentSyncPlanTool = {
1289
+ clearable: false,
1269
1290
  definition: {
1270
1291
  name: "presentSyncPlan",
1271
1292
  description: "Present a structured sync plan to the user for approval. Write a clear markdown summary of what changed and what you intend to update. The user will see this in a full-screen view and can approve or dismiss. Call this BEFORE making any sync edits.",
@@ -1288,6 +1309,7 @@ var presentSyncPlanTool = {
1288
1309
 
1289
1310
  // src/tools/spec/presentPublishPlan.ts
1290
1311
  var presentPublishPlanTool = {
1312
+ clearable: false,
1291
1313
  definition: {
1292
1314
  name: "presentPublishPlan",
1293
1315
  description: "Present a publish changelog to the user for approval. Write a clear markdown summary of what changed since the last deploy. The user will see this in a full-screen view and can approve or dismiss. Call this BEFORE committing or pushing.",
@@ -1310,6 +1332,7 @@ var presentPublishPlanTool = {
1310
1332
 
1311
1333
  // src/tools/spec/presentPlan.ts
1312
1334
  var presentPlanTool = {
1335
+ clearable: false,
1313
1336
  definition: {
1314
1337
  name: "presentPlan",
1315
1338
  description: "Present an implementation plan for user approval before making changes. Use this only for large, multi-step changes like new features, new interface types, or when the user explicitly asks to see a plan. Most work should be done autonomously without a plan. Write a clear markdown summary of what you intend to do in plain language \u2014 describe the changes from the user's perspective, not as a list of files and code paths. If the user rejects with feedback, revise and present again.",
@@ -1332,19 +1355,16 @@ var presentPlanTool = {
1332
1355
 
1333
1356
  // src/tools/common/setProjectOnboardingState.ts
1334
1357
  var setProjectOnboardingStateTool = {
1358
+ clearable: false,
1335
1359
  definition: {
1336
1360
  name: "setProjectOnboardingState",
1337
- description: "Advance the project onboarding state. Call at natural transition points: before writing the first spec (initialSpecAuthoring), before starting the first code generation (initialCodegen), after the first build succeeds (onboardingFinished). Forward-only progression.",
1361
+ description: "Advance the project onboarding state. Call at natural transition points: after writing the first draft of the spec (initialSpecReview), before starting the first code generation (initialCodegen), after the first build succeeds (onboardingFinished). Forward-only progression.",
1338
1362
  inputSchema: {
1339
1363
  type: "object",
1340
1364
  properties: {
1341
1365
  state: {
1342
1366
  type: "string",
1343
- enum: [
1344
- "initialSpecAuthoring",
1345
- "initialCodegen",
1346
- "onboardingFinished"
1347
- ],
1367
+ enum: ["initialSpecReview", "initialCodegen", "onboardingFinished"],
1348
1368
  description: "The onboarding state to advance to."
1349
1369
  }
1350
1370
  },
@@ -1358,6 +1378,7 @@ var setProjectOnboardingStateTool = {
1358
1378
 
1359
1379
  // src/tools/common/promptUser.ts
1360
1380
  var promptUserTool = {
1381
+ clearable: false,
1361
1382
  definition: {
1362
1383
  name: "promptUser",
1363
1384
  description: 'Ask the user structured questions. Choose type first: "form" for structured intake (5+ questions, takes over screen), "inline" for quick clarifications or confirmations. Blocks until the user responds. Result contains `_dismissed: true` if the user dismisses without answering.',
@@ -1489,6 +1510,7 @@ ${lines.join("\n")}`;
1489
1510
 
1490
1511
  // src/tools/common/confirmDestructiveAction.ts
1491
1512
  var confirmDestructiveActionTool = {
1513
+ clearable: false,
1492
1514
  definition: {
1493
1515
  name: "confirmDestructiveAction",
1494
1516
  description: "Confirm a destructive or irreversible action with the user. Use for things like deleting data, resetting the database, or discarding draft work. Do not use after presentSyncPlan, presentPublishPlan, or presentPlan (those already include approval). Do not use before onboarding state transitions.",
@@ -1600,9 +1622,10 @@ function runCli(cmd, options) {
1600
1622
 
1601
1623
  // src/subagents/sdkConsultant/index.ts
1602
1624
  var askMindStudioSdkTool = {
1625
+ clearable: false,
1603
1626
  definition: {
1604
1627
  name: "askMindStudioSdk",
1605
- description: "@mindstudio-ai/agent SDK expert. Knows every action, model, connector, and configuration option. Returns architectural guidance and working code. Describe what you want to build, not just what API method you need. Batch related questions into a single query.",
1628
+ description: "@mindstudio-ai/agent backend SDK expert. Knows every backend action, AI model, connector, and configuration option. Returns architectural guidance and working code. Only covers the backend SDK (@mindstudio-ai/agent) \u2014 do NOT use for frontend/interface SDK questions (@mindstudio-ai/interface) like file uploads, auth, or client-side APIs. Describe what you want to build, not just what API method you need. Batch related questions into a single query.",
1606
1629
  inputSchema: {
1607
1630
  type: "object",
1608
1631
  properties: {
@@ -1626,6 +1649,7 @@ var askMindStudioSdkTool = {
1626
1649
 
1627
1650
  // src/tools/common/searchGoogle.ts
1628
1651
  var searchGoogleTool = {
1652
+ clearable: false,
1629
1653
  definition: {
1630
1654
  name: "searchGoogle",
1631
1655
  description: "Search Google and return results. Use for research, finding documentation, looking up APIs, or any task where web search would help.",
@@ -1651,6 +1675,7 @@ var searchGoogleTool = {
1651
1675
 
1652
1676
  // src/tools/common/setProjectMetadata.ts
1653
1677
  var setProjectMetadataTool = {
1678
+ clearable: false,
1654
1679
  definition: {
1655
1680
  name: "setProjectMetadata",
1656
1681
  description: "Set project metadata. Can update any combination of: display name, app icon, and Open Graph share image. Provide only the fields you want to change.",
@@ -1690,6 +1715,7 @@ function isBinary(buffer) {
1690
1715
  return false;
1691
1716
  }
1692
1717
  var readFileTool = {
1718
+ clearable: true,
1693
1719
  definition: {
1694
1720
  name: "readFile",
1695
1721
  description: "Read a file's contents with line numbers. Always read a file before editing it \u2014 never guess at contents. For large files, consider using symbols first to identify the relevant section, then use offset and maxLines to read just that section. Line numbers in the output correspond to what editFile expects. Defaults to first 500 lines. Use a negative offset to read from the end of the file (e.g., offset: -50 reads the last 50 lines).",
@@ -1751,6 +1777,7 @@ var readFileTool = {
1751
1777
  import fs10 from "fs/promises";
1752
1778
  import path6 from "path";
1753
1779
  var writeFileTool = {
1780
+ clearable: true,
1754
1781
  definition: {
1755
1782
  name: "writeFile",
1756
1783
  description: "Create a new file or completely overwrite an existing one. Parent directories are created automatically. Use this for new files or full rewrites. For targeted changes to existing files, use editFile instead \u2014 it preserves the parts you don't want to change and avoids errors from forgetting to include unchanged code.",
@@ -1894,6 +1921,7 @@ function formatOccurrenceError(count, lines, filePath) {
1894
1921
 
1895
1922
  // src/tools/code/editFile/index.ts
1896
1923
  var editFileTool = {
1924
+ clearable: true,
1897
1925
  definition: {
1898
1926
  name: "editFile",
1899
1927
  description: "Replace a string in a file. old_string must appear exactly once (minor indentation differences are handled automatically). Set replace_all to true to replace every occurrence at once. For bulk mechanical substitutions (renaming a variable, swapping colors), prefer replace_all. Always read the file first so you know the exact text to match. When editing nested structures (objects, function bodies, arrays, template literals), always include the full enclosing structure in old_string rather than just an inner fragment. Replacing a partial slice from the middle of nested code is the most common source of syntax errors.",
@@ -1981,6 +2009,7 @@ import { exec } from "child_process";
1981
2009
  var DEFAULT_TIMEOUT_MS = 12e4;
1982
2010
  var DEFAULT_MAX_LINES3 = 500;
1983
2011
  var bashTool = {
2012
+ clearable: true,
1984
2013
  definition: {
1985
2014
  name: "bash",
1986
2015
  description: "Run a shell command and return stdout + stderr. 120-second timeout by default (configurable). Use for: npm install/build/test, git operations, tsc --noEmit, or any CLI tool. Prefer dedicated tools over bash when available (use grep instead of bash + rg, readFile instead of bash + cat). Output is truncated to 500 lines by default.",
@@ -2064,6 +2093,7 @@ function formatResults(stdout, max) {
2064
2093
  return result;
2065
2094
  }
2066
2095
  var grepTool = {
2096
+ clearable: true,
2067
2097
  definition: {
2068
2098
  name: "grep",
2069
2099
  description: "Search file contents for a regex pattern. Returns matching lines with file paths and line numbers (default 50 results). Use this to find where something is used, locate function definitions, or search for patterns across the codebase. For finding a symbol's definition precisely, prefer the definition tool if LSP is available. Automatically excludes node_modules and .git.",
@@ -2119,6 +2149,7 @@ var grepTool = {
2119
2149
  import fg from "fast-glob";
2120
2150
  var DEFAULT_MAX2 = 200;
2121
2151
  var globTool = {
2152
+ clearable: true,
2122
2153
  definition: {
2123
2154
  name: "glob",
2124
2155
  description: 'Find files matching a glob pattern. Returns matching file paths sorted alphabetically (default 200 results). Use this to discover project structure, find files by name or extension, or check if a file exists. Common patterns: "**/*.ts" (all TypeScript files), "src/**/*.tsx" (React components in src), "*.json" (root-level JSON files). Automatically excludes node_modules and .git.',
@@ -2165,6 +2196,7 @@ var globTool = {
2165
2196
  // src/tools/code/listDir.ts
2166
2197
  import fs12 from "fs/promises";
2167
2198
  var listDirTool = {
2199
+ clearable: true,
2168
2200
  definition: {
2169
2201
  name: "listDir",
2170
2202
  description: "List the contents of a directory. Shows entries with / suffix for directories, sorted directories-first then alphabetically. Use this for a quick overview of a directory's contents. For finding files across the whole project, use glob instead.",
@@ -2200,6 +2232,7 @@ var listDirTool = {
2200
2232
 
2201
2233
  // src/tools/code/editsFinished.ts
2202
2234
  var editsFinishedTool = {
2235
+ clearable: false,
2203
2236
  definition: {
2204
2237
  name: "editsFinished",
2205
2238
  description: "Signal that file edits are complete. Call this after you finish writing/editing files so the live preview updates cleanly. The preview is paused while you edit to avoid showing broken intermediate states \u2014 this unpauses it. If you forget to call this, the preview updates when your turn ends.",
@@ -2216,6 +2249,7 @@ var editsFinishedTool = {
2216
2249
 
2217
2250
  // src/tools/code/lspDiagnostics.ts
2218
2251
  var lspDiagnosticsTool = {
2252
+ clearable: true,
2219
2253
  definition: {
2220
2254
  name: "lspDiagnostics",
2221
2255
  description: "Get TypeScript diagnostics (type errors, warnings) for a file, with suggested fixes when available. Use this after editing a file to check for errors.",
@@ -2264,6 +2298,7 @@ var lspDiagnosticsTool = {
2264
2298
 
2265
2299
  // src/tools/code/restartProcess.ts
2266
2300
  var restartProcessTool = {
2301
+ clearable: false,
2267
2302
  definition: {
2268
2303
  name: "restartProcess",
2269
2304
  description: "Restart a managed sandbox process. Use this after running npm install or changing package.json to restart the dev server so it picks up new dependencies.",
@@ -2290,6 +2325,7 @@ var restartProcessTool = {
2290
2325
 
2291
2326
  // src/tools/code/runScenario.ts
2292
2327
  var runScenarioTool = {
2328
+ clearable: true,
2293
2329
  definition: {
2294
2330
  name: "runScenario",
2295
2331
  description: "Run a scenario to seed the dev database with test data. Truncates all tables first, then executes the seed function and impersonates the scenario roles. Blocks until complete. Scenario IDs are defined in mindstudio.json. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for details. Return synchronously - no need to sleep before checking results.",
@@ -2311,6 +2347,7 @@ var runScenarioTool = {
2311
2347
 
2312
2348
  // src/tools/code/runMethod.ts
2313
2349
  var runMethodTool = {
2350
+ clearable: true,
2314
2351
  definition: {
2315
2352
  name: "runMethod",
2316
2353
  description: "Run a method in the dev environment and return the result. Use for testing methods after writing or modifying them. Returns output, captured console output, errors with stack traces, and duration. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for more details. Return synchronously - no need to sleep before checking results.",
@@ -2393,6 +2430,7 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
2393
2430
 
2394
2431
  // src/tools/code/screenshot.ts
2395
2432
  var screenshotTool = {
2433
+ clearable: true,
2396
2434
  definition: {
2397
2435
  name: "screenshot",
2398
2436
  description: "Capture a full-height screenshot of the app preview and get a description of what's on screen. Provides static image analysis only, will not capture animations or video. Optionally provide specific questions about what you're looking for. Use a bulleted list to ask many questions at once. To ask additional questions about a screenshot you have already captured, pass its URL as imageUrl to skip recapture.",
@@ -2651,6 +2689,7 @@ async function runSubAgent(config) {
2651
2689
  const fullSystem = `${system}
2652
2690
 
2653
2691
  Current date: ${dateStr}`;
2692
+ const excludeToolsFromClearing = tools2.filter((t) => t.clearable === false).map((t) => t.name);
2654
2693
  let turns = 0;
2655
2694
  const run = async () => {
2656
2695
  const messages = [
@@ -2714,6 +2753,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
2714
2753
  system: fullSystem,
2715
2754
  messages: cleanMessagesForApi(messages),
2716
2755
  tools: tools2,
2756
+ excludeToolsFromClearing,
2717
2757
  signal
2718
2758
  },
2719
2759
  {
@@ -2964,6 +3004,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
2964
3004
  // src/subagents/browserAutomation/tools.ts
2965
3005
  var BROWSER_TOOLS = [
2966
3006
  {
3007
+ clearable: true,
2967
3008
  name: "browserCommand",
2968
3009
  description: "Interact with the app's live preview by sending browser commands. Commands execute sequentially with an animated cursor. Always start with a snapshot to see the current state and get ref identifiers. The result includes a snapshot field with the final page state after all steps complete. On error, the failing step has an error field and execution stops. Timeout: 120s.",
2969
3010
  inputSchema: {
@@ -3044,6 +3085,7 @@ var BROWSER_TOOLS = [
3044
3085
  }
3045
3086
  },
3046
3087
  {
3088
+ clearable: true,
3047
3089
  name: "screenshotFullPage",
3048
3090
  description: "Capture a full-height screenshot of the current page. Returns a CDN URL with full text analysis and description.",
3049
3091
  inputSchema: {
@@ -3057,6 +3099,7 @@ var BROWSER_TOOLS = [
3057
3099
  }
3058
3100
  },
3059
3101
  {
3102
+ clearable: false,
3060
3103
  name: "resetBrowser",
3061
3104
  description: "Reset the browser to a clean state. Call this once after all tests are complete to restore the preview for the user. Fire and forget \u2014 does not wait for the reload to finish.",
3062
3105
  inputSchema: {
@@ -3088,6 +3131,7 @@ ${appSpec}
3088
3131
  // src/subagents/browserAutomation/index.ts
3089
3132
  var log6 = createLogger("browser-automation");
3090
3133
  var browserAutomationTool = {
3134
+ clearable: true,
3091
3135
  definition: {
3092
3136
  name: "runAutomatedBrowserTest",
3093
3137
  description: "Run an automated browser test against the live preview. Describe what to test \u2014 the agent figures out how. Use after meaningful changes frontend code, to reproduce user-reported issues, or to test end-to-end flows.",
@@ -3209,6 +3253,7 @@ __export(searchGoogle_exports, {
3209
3253
  execute: () => execute
3210
3254
  });
3211
3255
  var definition = {
3256
+ clearable: false,
3212
3257
  name: "searchGoogle",
3213
3258
  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. Pick one or more URLs from the results and then use `scrapeWebUrl` to get their text content.',
3214
3259
  inputSchema: {
@@ -3236,6 +3281,7 @@ __export(scrapeWebUrl_exports, {
3236
3281
  execute: () => execute2
3237
3282
  });
3238
3283
  var definition2 = {
3284
+ clearable: false,
3239
3285
  name: "scrapeWebUrl",
3240
3286
  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.",
3241
3287
  inputSchema: {
@@ -3290,6 +3336,7 @@ Identify the specific design moves that make this page interesting and unique, d
3290
3336
  Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.
3291
3337
  `;
3292
3338
  var definition3 = {
3339
+ clearable: false,
3293
3340
  name: "analyzeDesign",
3294
3341
  description: "Analyze the visual design of a website or image URL. Websites are automatically screenshotted first. Provides static image analysis only, will not capture animations or video. If no prompt is provided, performs a full design reference analysis (mood, color, typography, layout, distinctiveness). Provide a custom prompt to ask a specific design question instead. Use a bulleted list to ask many questions at once.",
3295
3342
  inputSchema: {
@@ -3338,6 +3385,7 @@ __export(analyzeImage_exports, {
3338
3385
  });
3339
3386
  var DEFAULT_PROMPT = "Describe everything visible in this image \u2014 every element, its position, its size relative to the frame, its colors, its content. Be comprehensive, thorough and spatial. After the inventory, note anything that looks visually broken (overlapping elements, clipped text, misaligned components). Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.";
3340
3387
  var definition4 = {
3388
+ clearable: true,
3341
3389
  name: "analyzeImage",
3342
3390
  description: "Analyze an image by URL 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.",
3343
3391
  inputSchema: {
@@ -3373,6 +3421,7 @@ __export(screenshot_exports, {
3373
3421
  execute: () => execute5
3374
3422
  });
3375
3423
  var definition5 = {
3424
+ clearable: true,
3376
3425
  name: "screenshot",
3377
3426
  description: "Capture a full-height screenshot of the current app preview. Returns a CDN URL along with visual analysis. Use to review the current state of the UI being built. Remember, the screenshot analysis is not overly precise - for example, it cannot reliably identify specific fonts by name \u2014 it can only describe what letterforms look like.",
3378
3427
  inputSchema: {
@@ -3575,6 +3624,7 @@ async function generateImageAssets(opts) {
3575
3624
 
3576
3625
  // src/subagents/designExpert/tools/images/generateImages.ts
3577
3626
  var definition6 = {
3627
+ clearable: false,
3578
3628
  name: "generateImages",
3579
3629
  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.",
3580
3630
  inputSchema: {
@@ -3620,6 +3670,7 @@ __export(editImages_exports, {
3620
3670
  execute: () => execute7
3621
3671
  });
3622
3672
  var definition7 = {
3673
+ clearable: false,
3623
3674
  name: "editImages",
3624
3675
  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.",
3625
3676
  inputSchema: {
@@ -3739,15 +3790,19 @@ function loadPlatformBrief() {
3739
3790
  return `<platform_brief>
3740
3791
  ## What is a MindStudio app?
3741
3792
 
3742
- A MindStudio app is a managed TypeScript project with three layers: a spec (natural language in src/), a backend contract (methods, tables, roles in dist/), and one or more interfaces (web, API, bots, cron, etc.). The spec is the source of truth; code is derived from it.
3793
+ A MindStudio app is a managed full-stack TypeScript project with three layers: a spec (natural language in src/), a backend contract (methods, tables, roles in dist/), and one or more interfaces (web, API, bots, cron, etc.). The spec is the source of truth; code is derived from it.
3794
+
3795
+ This is a capable, stable platform used in production by 100k+ users. Build with confidence \u2014 you're building production-grade apps, not fragile prototypes.
3743
3796
 
3744
3797
  ## What people build
3745
3798
 
3746
- - Business tools \u2014 dashboards, admin panels, approval workflows, data entry apps, internal tools with role-based access
3747
- - AI-powered apps \u2014 chatbots, content generators, document processors, image/video tools, AI agents that take actions
3799
+ - Business tools \u2014 client portals, approval workflows, admin panels with role-based access
3800
+ - AI-powered apps \u2014 document processors, image/video tools, content generators, conversational agents that take actions
3801
+ - Full-stack web apps \u2014 social platforms, membership sites, marketplaces, booking systems, community hubs \u2014 multi-user apps with auth, data, UI
3748
3802
  - Automations with no UI \u2014 cron jobs, webhook handlers, email processors, data sync pipelines
3803
+ - Marketing & launch pages \u2014 landing pages, waitlist pages with referral mechanics, product sites with scroll animations
3749
3804
  - Bots \u2014 Discord slash-command bots, Telegram bots, MCP tool servers for AI assistants
3750
- - Creative/interactive projects \u2014 games, interactive visualizations, generative art, portfolio sites
3805
+ - Creative/interactive projects \u2014 browser games with p5.js or Three.js, interactive visualizations, generative art, portfolio sites
3751
3806
  - API services \u2014 backend logic exposed as REST endpoints
3752
3807
  - Simple static sites \u2014 no backend needed, just a web interface with a build step
3753
3808
 
@@ -3772,13 +3827,12 @@ Each interface type invokes the same backend methods. Methods don't know which i
3772
3827
  TypeScript running in a sandboxed environment. Any npm package can be installed. Key capabilities:
3773
3828
 
3774
3829
  - Managed SQLite database with typed schemas and automatic migrations. Define a TypeScript interface, push, and the platform handles diffing and migrating.
3775
- - Built-in role-based auth. Define roles in the manifest, gate methods with auth.requireRole(). Platform handles sessions, tokens, user resolution.
3776
- - Sandboxed execution with npm packages pre-installed.
3830
+ - Built-in app-managed auth. Opt-in via manifest \u2014 developer builds login UI, platform handles verification codes (email/SMS), cookie sessions, and role enforcement. Backend methods use auth.requireRole() for access control.
3777
3831
  - Git-native deployment. Push to default branch to deploy.
3778
3832
 
3779
3833
  ## MindStudio SDK
3780
3834
 
3781
- The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (OpenAI, Anthropic, Google, Meta, Mistral, and more) and 1000+ integrations (email, SMS, Slack, HubSpot, Google Workspace, web scraping, image/video generation, media processing, and much more) with zero configuration \u2014 credentials are handled automatically in the execution environment. No API keys needed.
3835
+ The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (OpenAI, Anthropic, Google, Meta, Mistral, and more) and 1000+ integrations (email, SMS, Slack, HubSpot, Google Workspace, web scraping, image/video generation, media processing, and much more) with zero configuration \u2014 credentials are handled automatically in the execution environment. No API keys needed. This SDK is robust and battle-tested in production.
3782
3836
 
3783
3837
  ## What MindStudio apps are NOT good for
3784
3838
 
@@ -3975,6 +4029,7 @@ var DESCRIPTION = `
3975
4029
  Visual design expert. Describe the situation and what you need \u2014 the agent decides what to deliver. It reads the spec files automatically. Include relevant user requirements and context it can't get from the spec, but do not list specific deliverables or tell it how to do its job. Do not suggest implementation details or ideas - only relay what is needed.
3976
4030
  `.trim();
3977
4031
  var designExpertTool = {
4032
+ clearable: false,
3978
4033
  definition: {
3979
4034
  name: "visualDesignExpert",
3980
4035
  description: DESCRIPTION,
@@ -4275,6 +4330,7 @@ function getProductVisionPrompt() {
4275
4330
 
4276
4331
  // src/subagents/productVision/index.ts
4277
4332
  var productVisionTool = {
4333
+ clearable: false,
4278
4334
  definition: {
4279
4335
  name: "productVision",
4280
4336
  description: "Owns the product roadmap. Reads spec and roadmap files automatically. Creates, updates, and deletes roadmap items in src/roadmap/. Describe the situation and what needs to happen.",
@@ -4423,6 +4479,7 @@ var SANITY_CHECK_TOOLS = [
4423
4479
  // src/subagents/codeSanityCheck/index.ts
4424
4480
  var BASE_PROMPT3 = readAsset("subagents/codeSanityCheck", "prompt.md");
4425
4481
  var codeSanityCheckTool = {
4482
+ clearable: false,
4426
4483
  definition: {
4427
4484
  name: "codeSanityCheck",
4428
4485
  description: 'Quick sanity check on an approach before building. Reviews architecture, package choices, and flags potential issues. Usually responds with "looks good." Occasionally catches something important. Readonly \u2014 can search the web and read code but cannot modify anything.',
@@ -4471,6 +4528,7 @@ var codeSanityCheckTool = {
4471
4528
 
4472
4529
  // src/tools/common/scrapeWebUrl.ts
4473
4530
  var scrapeWebUrlTool = {
4531
+ clearable: false,
4474
4532
  definition: {
4475
4533
  name: "scrapeWebUrl",
4476
4534
  description: "Scrape the content of a web page. Returns the HTML of the page as markdown text. Optionally capture a screenshot if you need see the visual design. Use this when you need to fetch or analyze content from a website",
@@ -4543,6 +4601,9 @@ var ALL_TOOLS = [
4543
4601
  lspDiagnosticsTool,
4544
4602
  restartProcessTool
4545
4603
  ];
4604
+ var CLEARABLE_TOOLS = new Set(
4605
+ ALL_TOOLS.filter((t) => t.clearable).map((t) => t.definition.name)
4606
+ );
4546
4607
  function getToolDefinitions(_onboardingState) {
4547
4608
  return ALL_TOOLS.map((t) => t.definition);
4548
4609
  }
@@ -4863,6 +4924,7 @@ async function runTurn(params) {
4863
4924
  onBackgroundComplete
4864
4925
  } = params;
4865
4926
  const tools2 = getToolDefinitions(onboardingState);
4927
+ const excludeToolsFromClearing = tools2.filter((t) => !CLEARABLE_TOOLS.has(t.name)).map((t) => t.name);
4866
4928
  log8.info("Turn started", {
4867
4929
  requestId,
4868
4930
  model,
@@ -4872,11 +4934,17 @@ async function runTurn(params) {
4872
4934
  }
4873
4935
  });
4874
4936
  onEvent({ type: "turn_started" });
4937
+ const hasText = userMessage.trim().length > 0;
4938
+ const hasAttachments = attachments && attachments.length > 0;
4939
+ if (!hasText && !hasAttachments) {
4940
+ onEvent({ type: "error", error: "Empty message" });
4941
+ return;
4942
+ }
4875
4943
  const userMsg = { role: "user", content: userMessage };
4876
4944
  if (hidden) {
4877
4945
  userMsg.hidden = true;
4878
4946
  }
4879
- if (attachments && attachments.length > 0) {
4947
+ if (hasAttachments) {
4880
4948
  userMsg.attachments = attachments;
4881
4949
  }
4882
4950
  state.messages.push(userMsg);
@@ -5002,6 +5070,7 @@ async function runTurn(params) {
5002
5070
  system,
5003
5071
  messages: cleanMessagesForApi(state.messages),
5004
5072
  tools: tools2,
5073
+ excludeToolsFromClearing,
5005
5074
  signal
5006
5075
  },
5007
5076
  {
@@ -5474,6 +5543,7 @@ async function startHeadless(opts = {}) {
5474
5543
  let currentAbort = null;
5475
5544
  let currentRequestId;
5476
5545
  let completedEmitted = false;
5546
+ let turnStart = 0;
5477
5547
  const EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
5478
5548
  const pendingTools = /* @__PURE__ */ new Map();
5479
5549
  const earlyResults = /* @__PURE__ */ new Map();
@@ -5586,8 +5656,8 @@ ${xmlParts}
5586
5656
  function onEvent(e) {
5587
5657
  const rid = currentRequestId;
5588
5658
  switch (e.type) {
5589
- // Suppressed — caller already knows the request started
5590
5659
  case "turn_started":
5660
+ emit("turn_started", {}, rid);
5591
5661
  return;
5592
5662
  // Terminal events — translate to `completed`
5593
5663
  case "turn_done":
@@ -5606,7 +5676,11 @@ ${xmlParts}
5606
5676
  writeFileSync(".remy-stats.json", JSON.stringify(sessionStats));
5607
5677
  } catch {
5608
5678
  }
5609
- emit("completed", { success: true }, rid);
5679
+ emit(
5680
+ "completed",
5681
+ { success: true, durationMs: Date.now() - turnStart },
5682
+ rid
5683
+ );
5610
5684
  setTimeout(() => {
5611
5685
  applyPendingBlockUpdates();
5612
5686
  flushBackgroundQueue();
@@ -5746,7 +5820,7 @@ ${xmlParts}
5746
5820
  currentRequestId = requestId;
5747
5821
  currentAbort = new AbortController();
5748
5822
  completedEmitted = false;
5749
- const turnStart = Date.now();
5823
+ turnStart = Date.now();
5750
5824
  const attachments = parsed.attachments;
5751
5825
  if (attachments?.length) {
5752
5826
  console.warn(
@@ -5891,7 +5965,9 @@ ${xmlParts}
5891
5965
  writeFileSync(".remy-stats.json", JSON.stringify(sessionStats));
5892
5966
  } catch {
5893
5967
  }
5894
- compactConversation(state, config).then(() => {
5968
+ const compactSystem = buildSystemPrompt("onboardingFinished");
5969
+ const compactTools = getToolDefinitions("onboardingFinished");
5970
+ compactConversation(state, config, compactSystem, compactTools).then(() => {
5895
5971
  saveSession(state);
5896
5972
  emit("compaction_complete", {}, requestId);
5897
5973
  emit("completed", { success: true }, requestId);