@mindstudio-ai/remy 0.1.69 → 0.1.70

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
@@ -398,6 +398,7 @@ var init_readSpec = __esm({
398
398
  init_helpers();
399
399
  DEFAULT_MAX_LINES = 500;
400
400
  readSpecTool = {
401
+ clearable: true,
401
402
  definition: {
402
403
  name: "readSpec",
403
404
  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).",
@@ -511,6 +512,7 @@ var init_writeSpec = __esm({
511
512
  init_helpers();
512
513
  init_diff();
513
514
  writeSpecTool = {
515
+ clearable: true,
514
516
  definition: {
515
517
  name: "writeSpec",
516
518
  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.",
@@ -572,6 +574,7 @@ var init_editSpec = __esm({
572
574
  init_helpers();
573
575
  init_diff();
574
576
  editSpecTool = {
577
+ clearable: true,
575
578
  definition: {
576
579
  name: "editSpec",
577
580
  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.',
@@ -714,6 +717,7 @@ var init_listSpecFiles = __esm({
714
717
  "src/tools/spec/listSpecFiles.ts"() {
715
718
  "use strict";
716
719
  listSpecFilesTool = {
720
+ clearable: false,
717
721
  definition: {
718
722
  name: "listSpecFiles",
719
723
  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.",
@@ -747,6 +751,7 @@ var init_clearSyncStatus = __esm({
747
751
  "src/tools/spec/clearSyncStatus.ts"() {
748
752
  "use strict";
749
753
  clearSyncStatusTool = {
754
+ clearable: false,
750
755
  definition: {
751
756
  name: "clearSyncStatus",
752
757
  description: "Clear the sync status flags after syncing spec and code. Call this after finishing a sync operation.",
@@ -768,6 +773,7 @@ var init_presentSyncPlan = __esm({
768
773
  "src/tools/spec/presentSyncPlan.ts"() {
769
774
  "use strict";
770
775
  presentSyncPlanTool = {
776
+ clearable: false,
771
777
  definition: {
772
778
  name: "presentSyncPlan",
773
779
  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.",
@@ -796,6 +802,7 @@ var init_presentPublishPlan = __esm({
796
802
  "src/tools/spec/presentPublishPlan.ts"() {
797
803
  "use strict";
798
804
  presentPublishPlanTool = {
805
+ clearable: false,
799
806
  definition: {
800
807
  name: "presentPublishPlan",
801
808
  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.",
@@ -824,6 +831,7 @@ var init_presentPlan = __esm({
824
831
  "src/tools/spec/presentPlan.ts"() {
825
832
  "use strict";
826
833
  presentPlanTool = {
834
+ clearable: false,
827
835
  definition: {
828
836
  name: "presentPlan",
829
837
  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.",
@@ -852,19 +860,16 @@ var init_setProjectOnboardingState = __esm({
852
860
  "src/tools/common/setProjectOnboardingState.ts"() {
853
861
  "use strict";
854
862
  setProjectOnboardingStateTool = {
863
+ clearable: false,
855
864
  definition: {
856
865
  name: "setProjectOnboardingState",
857
- 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.",
866
+ 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.",
858
867
  inputSchema: {
859
868
  type: "object",
860
869
  properties: {
861
870
  state: {
862
871
  type: "string",
863
- enum: [
864
- "initialSpecAuthoring",
865
- "initialCodegen",
866
- "onboardingFinished"
867
- ],
872
+ enum: ["initialSpecReview", "initialCodegen", "onboardingFinished"],
868
873
  description: "The onboarding state to advance to."
869
874
  }
870
875
  },
@@ -884,6 +889,7 @@ var init_promptUser = __esm({
884
889
  "src/tools/common/promptUser.ts"() {
885
890
  "use strict";
886
891
  promptUserTool = {
892
+ clearable: false,
887
893
  definition: {
888
894
  name: "promptUser",
889
895
  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.',
@@ -1021,6 +1027,7 @@ var init_confirmDestructiveAction = __esm({
1021
1027
  "src/tools/common/confirmDestructiveAction.ts"() {
1022
1028
  "use strict";
1023
1029
  confirmDestructiveActionTool = {
1030
+ clearable: false,
1024
1031
  definition: {
1025
1032
  name: "confirmDestructiveAction",
1026
1033
  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.",
@@ -1144,9 +1151,10 @@ var init_sdkConsultant = __esm({
1144
1151
  "use strict";
1145
1152
  init_runCli();
1146
1153
  askMindStudioSdkTool = {
1154
+ clearable: false,
1147
1155
  definition: {
1148
1156
  name: "askMindStudioSdk",
1149
- 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.",
1157
+ 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.",
1150
1158
  inputSchema: {
1151
1159
  type: "object",
1152
1160
  properties: {
@@ -1177,6 +1185,7 @@ var init_searchGoogle = __esm({
1177
1185
  "use strict";
1178
1186
  init_runCli();
1179
1187
  searchGoogleTool = {
1188
+ clearable: false,
1180
1189
  definition: {
1181
1190
  name: "searchGoogle",
1182
1191
  description: "Search Google and return results. Use for research, finding documentation, looking up APIs, or any task where web search would help.",
@@ -1208,6 +1217,7 @@ var init_setProjectMetadata = __esm({
1208
1217
  "src/tools/common/setProjectMetadata.ts"() {
1209
1218
  "use strict";
1210
1219
  setProjectMetadataTool = {
1220
+ clearable: false,
1211
1221
  definition: {
1212
1222
  name: "setProjectMetadata",
1213
1223
  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.",
@@ -1253,6 +1263,7 @@ var init_readFile = __esm({
1253
1263
  "use strict";
1254
1264
  DEFAULT_MAX_LINES2 = 500;
1255
1265
  readFileTool = {
1266
+ clearable: true,
1256
1267
  definition: {
1257
1268
  name: "readFile",
1258
1269
  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).",
@@ -1321,6 +1332,7 @@ var init_writeFile = __esm({
1321
1332
  "use strict";
1322
1333
  init_diff();
1323
1334
  writeFileTool = {
1335
+ clearable: true,
1324
1336
  definition: {
1325
1337
  name: "writeFile",
1326
1338
  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.",
@@ -1475,6 +1487,7 @@ var init_editFile = __esm({
1475
1487
  init_diff();
1476
1488
  init_helpers2();
1477
1489
  editFileTool = {
1490
+ clearable: true,
1478
1491
  definition: {
1479
1492
  name: "editFile",
1480
1493
  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.",
@@ -1568,6 +1581,7 @@ var init_bash = __esm({
1568
1581
  DEFAULT_TIMEOUT_MS = 12e4;
1569
1582
  DEFAULT_MAX_LINES3 = 500;
1570
1583
  bashTool = {
1584
+ clearable: true,
1571
1585
  definition: {
1572
1586
  name: "bash",
1573
1587
  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.",
@@ -1657,6 +1671,7 @@ var init_grep = __esm({
1657
1671
  "use strict";
1658
1672
  DEFAULT_MAX = 50;
1659
1673
  grepTool = {
1674
+ clearable: true,
1660
1675
  definition: {
1661
1676
  name: "grep",
1662
1677
  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.",
@@ -1718,6 +1733,7 @@ var init_glob = __esm({
1718
1733
  "use strict";
1719
1734
  DEFAULT_MAX2 = 200;
1720
1735
  globTool = {
1736
+ clearable: true,
1721
1737
  definition: {
1722
1738
  name: "glob",
1723
1739
  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.',
@@ -1770,6 +1786,7 @@ var init_listDir = __esm({
1770
1786
  "src/tools/code/listDir.ts"() {
1771
1787
  "use strict";
1772
1788
  listDirTool = {
1789
+ clearable: true,
1773
1790
  definition: {
1774
1791
  name: "listDir",
1775
1792
  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.",
@@ -1811,6 +1828,7 @@ var init_editsFinished = __esm({
1811
1828
  "src/tools/code/editsFinished.ts"() {
1812
1829
  "use strict";
1813
1830
  editsFinishedTool = {
1831
+ clearable: false,
1814
1832
  definition: {
1815
1833
  name: "editsFinished",
1816
1834
  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.",
@@ -1891,6 +1909,7 @@ var init_lspDiagnostics = __esm({
1891
1909
  "use strict";
1892
1910
  init_lsp();
1893
1911
  lspDiagnosticsTool = {
1912
+ clearable: true,
1894
1913
  definition: {
1895
1914
  name: "lspDiagnostics",
1896
1915
  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.",
@@ -1946,6 +1965,7 @@ var init_restartProcess = __esm({
1946
1965
  "use strict";
1947
1966
  init_lsp();
1948
1967
  restartProcessTool = {
1968
+ clearable: false,
1949
1969
  definition: {
1950
1970
  name: "restartProcess",
1951
1971
  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.",
@@ -1978,6 +1998,7 @@ var init_runScenario = __esm({
1978
1998
  "src/tools/code/runScenario.ts"() {
1979
1999
  "use strict";
1980
2000
  runScenarioTool = {
2001
+ clearable: true,
1981
2002
  definition: {
1982
2003
  name: "runScenario",
1983
2004
  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.",
@@ -2005,6 +2026,7 @@ var init_runMethod = __esm({
2005
2026
  "src/tools/code/runMethod.ts"() {
2006
2027
  "use strict";
2007
2028
  runMethodTool = {
2029
+ clearable: true,
2008
2030
  definition: {
2009
2031
  name: "runMethod",
2010
2032
  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.",
@@ -2109,6 +2131,7 @@ var init_screenshot2 = __esm({
2109
2131
  "use strict";
2110
2132
  init_screenshot();
2111
2133
  screenshotTool = {
2134
+ clearable: true,
2112
2135
  definition: {
2113
2136
  name: "screenshot",
2114
2137
  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.",
@@ -2378,6 +2401,7 @@ async function runSubAgent(config) {
2378
2401
  const fullSystem = `${system}
2379
2402
 
2380
2403
  Current date: ${dateStr}`;
2404
+ const excludeToolsFromClearing = tools2.filter((t) => t.clearable === false).map((t) => t.name);
2381
2405
  let turns = 0;
2382
2406
  const run = async () => {
2383
2407
  const messages = [
@@ -2441,6 +2465,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
2441
2465
  system: fullSystem,
2442
2466
  messages: cleanMessagesForApi(messages),
2443
2467
  tools: tools2,
2468
+ excludeToolsFromClearing,
2444
2469
  signal
2445
2470
  },
2446
2471
  {
@@ -2706,6 +2731,7 @@ var init_tools = __esm({
2706
2731
  "use strict";
2707
2732
  BROWSER_TOOLS = [
2708
2733
  {
2734
+ clearable: true,
2709
2735
  name: "browserCommand",
2710
2736
  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.",
2711
2737
  inputSchema: {
@@ -2786,6 +2812,7 @@ var init_tools = __esm({
2786
2812
  }
2787
2813
  },
2788
2814
  {
2815
+ clearable: true,
2789
2816
  name: "screenshotFullPage",
2790
2817
  description: "Capture a full-height screenshot of the current page. Returns a CDN URL with full text analysis and description.",
2791
2818
  inputSchema: {
@@ -2799,6 +2826,7 @@ var init_tools = __esm({
2799
2826
  }
2800
2827
  },
2801
2828
  {
2829
+ clearable: false,
2802
2830
  name: "resetBrowser",
2803
2831
  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.",
2804
2832
  inputSchema: {
@@ -2893,6 +2921,7 @@ var init_browserAutomation = __esm({
2893
2921
  init_logger();
2894
2922
  log4 = createLogger("browser-automation");
2895
2923
  browserAutomationTool = {
2924
+ clearable: true,
2896
2925
  definition: {
2897
2926
  name: "runAutomatedBrowserTest",
2898
2927
  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.",
@@ -3027,6 +3056,7 @@ var init_searchGoogle2 = __esm({
3027
3056
  "use strict";
3028
3057
  init_runCli();
3029
3058
  definition = {
3059
+ clearable: false,
3030
3060
  name: "searchGoogle",
3031
3061
  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.',
3032
3062
  inputSchema: {
@@ -3065,6 +3095,7 @@ var init_scrapeWebUrl = __esm({
3065
3095
  "use strict";
3066
3096
  init_runCli();
3067
3097
  definition2 = {
3098
+ clearable: false,
3068
3099
  name: "scrapeWebUrl",
3069
3100
  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.",
3070
3101
  inputSchema: {
@@ -3139,6 +3170,7 @@ Identify the specific design moves that make this page interesting and unique, d
3139
3170
  Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.
3140
3171
  `;
3141
3172
  definition3 = {
3173
+ clearable: false,
3142
3174
  name: "analyzeDesign",
3143
3175
  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.",
3144
3176
  inputSchema: {
@@ -3182,6 +3214,7 @@ var init_analyzeImage2 = __esm({
3182
3214
  init_analyzeImage();
3183
3215
  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.";
3184
3216
  definition4 = {
3217
+ clearable: true,
3185
3218
  name: "analyzeImage",
3186
3219
  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.",
3187
3220
  inputSchema: {
@@ -3249,6 +3282,7 @@ var init_screenshot3 = __esm({
3249
3282
  init_analyzeImage();
3250
3283
  init_browserAutomation();
3251
3284
  definition5 = {
3285
+ clearable: true,
3252
3286
  name: "screenshot",
3253
3287
  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.",
3254
3288
  inputSchema: {
@@ -3449,6 +3483,7 @@ var init_generateImages = __esm({
3449
3483
  "use strict";
3450
3484
  init_imageGenerator();
3451
3485
  definition6 = {
3486
+ clearable: false,
3452
3487
  name: "generateImages",
3453
3488
  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.",
3454
3489
  inputSchema: {
@@ -3502,6 +3537,7 @@ var init_editImages = __esm({
3502
3537
  "use strict";
3503
3538
  init_imageGenerator();
3504
3539
  definition7 = {
3540
+ clearable: false,
3505
3541
  name: "editImages",
3506
3542
  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.",
3507
3543
  inputSchema: {
@@ -3656,7 +3692,7 @@ Each interface type invokes the same backend methods. Methods don't know which i
3656
3692
  TypeScript running in a sandboxed environment. Any npm package can be installed. Key capabilities:
3657
3693
 
3658
3694
  - Managed SQLite database with typed schemas and automatic migrations. Define a TypeScript interface, push, and the platform handles diffing and migrating.
3659
- - Built-in role-based auth. Define roles in the manifest, gate methods with auth.requireRole(). Platform handles sessions, tokens, user resolution.
3695
+ - 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.
3660
3696
  - Sandboxed execution with npm packages pre-installed.
3661
3697
  - Git-native deployment. Push to default branch to deploy.
3662
3698
 
@@ -3910,6 +3946,7 @@ var init_designExpert = __esm({
3910
3946
  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.
3911
3947
  `.trim();
3912
3948
  designExpertTool = {
3949
+ clearable: false,
3913
3950
  definition: {
3914
3951
  name: "visualDesignExpert",
3915
3952
  description: DESCRIPTION,
@@ -4244,6 +4281,7 @@ var init_productVision = __esm({
4244
4281
  init_prompt3();
4245
4282
  init_history();
4246
4283
  productVisionTool = {
4284
+ clearable: false,
4247
4285
  definition: {
4248
4286
  name: "productVision",
4249
4287
  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.",
@@ -4409,6 +4447,7 @@ var init_codeSanityCheck = __esm({
4409
4447
  init_tools4();
4410
4448
  BASE_PROMPT3 = readAsset("subagents/codeSanityCheck", "prompt.md");
4411
4449
  codeSanityCheckTool = {
4450
+ clearable: false,
4412
4451
  definition: {
4413
4452
  name: "codeSanityCheck",
4414
4453
  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.',
@@ -4464,6 +4503,7 @@ var init_scrapeWebUrl2 = __esm({
4464
4503
  "use strict";
4465
4504
  init_runCli();
4466
4505
  scrapeWebUrlTool = {
4506
+ clearable: false,
4467
4507
  definition: {
4468
4508
  name: "scrapeWebUrl",
4469
4509
  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",
@@ -4512,7 +4552,7 @@ function executeTool(name, input, context) {
4512
4552
  }
4513
4553
  return tool.execute(input, context);
4514
4554
  }
4515
- var ALL_TOOLS;
4555
+ var ALL_TOOLS, CLEARABLE_TOOLS;
4516
4556
  var init_tools5 = __esm({
4517
4557
  "src/tools/index.ts"() {
4518
4558
  "use strict";
@@ -4587,6 +4627,9 @@ var init_tools5 = __esm({
4587
4627
  lspDiagnosticsTool,
4588
4628
  restartProcessTool
4589
4629
  ];
4630
+ CLEARABLE_TOOLS = new Set(
4631
+ ALL_TOOLS.filter((t) => t.clearable).map((t) => t.definition.name)
4632
+ );
4590
4633
  }
4591
4634
  });
4592
4635
 
@@ -4901,6 +4944,7 @@ async function runTurn(params) {
4901
4944
  onBackgroundComplete
4902
4945
  } = params;
4903
4946
  const tools2 = getToolDefinitions(onboardingState);
4947
+ const excludeToolsFromClearing = tools2.filter((t) => !CLEARABLE_TOOLS.has(t.name)).map((t) => t.name);
4904
4948
  log6.info("Turn started", {
4905
4949
  requestId,
4906
4950
  model,
@@ -4910,11 +4954,17 @@ async function runTurn(params) {
4910
4954
  }
4911
4955
  });
4912
4956
  onEvent({ type: "turn_started" });
4957
+ const hasText = userMessage.trim().length > 0;
4958
+ const hasAttachments = attachments && attachments.length > 0;
4959
+ if (!hasText && !hasAttachments) {
4960
+ onEvent({ type: "error", error: "Empty message" });
4961
+ return;
4962
+ }
4913
4963
  const userMsg = { role: "user", content: userMessage };
4914
4964
  if (hidden) {
4915
4965
  userMsg.hidden = true;
4916
4966
  }
4917
- if (attachments && attachments.length > 0) {
4967
+ if (hasAttachments) {
4918
4968
  userMsg.attachments = attachments;
4919
4969
  }
4920
4970
  state.messages.push(userMsg);
@@ -5040,6 +5090,7 @@ async function runTurn(params) {
5040
5090
  system,
5041
5091
  messages: cleanMessagesForApi(state.messages),
5042
5092
  tools: tools2,
5093
+ excludeToolsFromClearing,
5043
5094
  signal
5044
5095
  },
5045
5096
  {
@@ -5358,6 +5409,7 @@ var init_agent = __esm({
5358
5409
  init_statusWatcher();
5359
5410
  init_errors();
5360
5411
  init_cleanMessages();
5412
+ init_tools5();
5361
5413
  log6 = createLogger("agent");
5362
5414
  EXTERNAL_TOOLS = /* @__PURE__ */ new Set([
5363
5415
  "promptUser",
@@ -5698,7 +5750,7 @@ var init_config = __esm({
5698
5750
  });
5699
5751
 
5700
5752
  // src/compaction/index.ts
5701
- async function compactConversation(state, apiConfig) {
5753
+ async function compactConversation(state, apiConfig, system, tools2) {
5702
5754
  const insertionIndex = findSafeInsertionPoint(state.messages);
5703
5755
  const summaries = [];
5704
5756
  const tasks = [];
@@ -5712,7 +5764,9 @@ async function compactConversation(state, apiConfig) {
5712
5764
  apiConfig,
5713
5765
  "conversation",
5714
5766
  CONVERSATION_SUMMARY_PROMPT,
5715
- conversationMessages
5767
+ conversationMessages,
5768
+ system,
5769
+ tools2
5716
5770
  ).then((text) => {
5717
5771
  if (text) {
5718
5772
  summaries.push({ name: "conversation", text });
@@ -5732,7 +5786,9 @@ async function compactConversation(state, apiConfig) {
5732
5786
  apiConfig,
5733
5787
  name,
5734
5788
  SUBAGENT_SUMMARY_PROMPT,
5735
- subagentMessages
5789
+ subagentMessages,
5790
+ system,
5791
+ tools2
5736
5792
  ).then((text) => {
5737
5793
  if (text) {
5738
5794
  summaries.push({ name, text });
@@ -5859,22 +5915,33 @@ function serializeForSummary(messages) {
5859
5915
  return `[${msg.role}]: ${parts.join("\n")}`;
5860
5916
  }).join("\n\n");
5861
5917
  }
5862
- async function generateSummary(apiConfig, name, systemPrompt, messagesToSummarize) {
5918
+ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSummarize, mainSystem, mainTools) {
5863
5919
  const serialized = serializeForSummary(messagesToSummarize);
5864
5920
  if (!serialized.trim()) {
5865
5921
  return null;
5866
5922
  }
5867
5923
  log8.info("Generating summary", {
5868
5924
  name,
5869
- messageCount: messagesToSummarize.length
5925
+ messageCount: messagesToSummarize.length,
5926
+ cacheReuse: !!mainSystem
5870
5927
  });
5871
5928
  let summaryText = "";
5929
+ const useMainCache = !!mainSystem;
5930
+ const system = useMainCache ? mainSystem : compactionPrompt;
5931
+ const tools2 = useMainCache ? mainTools ?? [] : [];
5932
+ const userContent = useMainCache ? `${compactionPrompt}
5933
+
5934
+ ---
5935
+
5936
+ Conversation to summarize:
5937
+
5938
+ ${serialized}` : serialized;
5872
5939
  for await (const event of streamChat({
5873
5940
  ...apiConfig,
5874
5941
  subAgentId: "conversationSummarizer",
5875
- system: systemPrompt,
5876
- messages: [{ role: "user", content: serialized }],
5877
- tools: []
5942
+ system,
5943
+ messages: [{ role: "user", content: userContent }],
5944
+ tools: tools2
5878
5945
  })) {
5879
5946
  if (event.type === "text") {
5880
5947
  summaryText += event.text;
@@ -6088,6 +6155,7 @@ async function startHeadless(opts = {}) {
6088
6155
  let currentAbort = null;
6089
6156
  let currentRequestId;
6090
6157
  let completedEmitted = false;
6158
+ let turnStart = 0;
6091
6159
  const EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
6092
6160
  const pendingTools = /* @__PURE__ */ new Map();
6093
6161
  const earlyResults = /* @__PURE__ */ new Map();
@@ -6200,8 +6268,8 @@ ${xmlParts}
6200
6268
  function onEvent(e) {
6201
6269
  const rid = currentRequestId;
6202
6270
  switch (e.type) {
6203
- // Suppressed — caller already knows the request started
6204
6271
  case "turn_started":
6272
+ emit("turn_started", {}, rid);
6205
6273
  return;
6206
6274
  // Terminal events — translate to `completed`
6207
6275
  case "turn_done":
@@ -6220,7 +6288,11 @@ ${xmlParts}
6220
6288
  writeFileSync(".remy-stats.json", JSON.stringify(sessionStats));
6221
6289
  } catch {
6222
6290
  }
6223
- emit("completed", { success: true }, rid);
6291
+ emit(
6292
+ "completed",
6293
+ { success: true, durationMs: Date.now() - turnStart },
6294
+ rid
6295
+ );
6224
6296
  setTimeout(() => {
6225
6297
  applyPendingBlockUpdates();
6226
6298
  flushBackgroundQueue();
@@ -6360,7 +6432,7 @@ ${xmlParts}
6360
6432
  currentRequestId = requestId;
6361
6433
  currentAbort = new AbortController();
6362
6434
  completedEmitted = false;
6363
- const turnStart = Date.now();
6435
+ turnStart = Date.now();
6364
6436
  const attachments = parsed.attachments;
6365
6437
  if (attachments?.length) {
6366
6438
  console.warn(
@@ -6505,7 +6577,9 @@ ${xmlParts}
6505
6577
  writeFileSync(".remy-stats.json", JSON.stringify(sessionStats));
6506
6578
  } catch {
6507
6579
  }
6508
- compactConversation(state, config).then(() => {
6580
+ const compactSystem = buildSystemPrompt("onboardingFinished");
6581
+ const compactTools = getToolDefinitions("onboardingFinished");
6582
+ compactConversation(state, config, compactSystem, compactTools).then(() => {
6509
6583
  saveSession(state);
6510
6584
  emit("compaction_complete", {}, requestId);
6511
6585
  emit("completed", { success: true }, requestId);
@@ -6564,6 +6638,7 @@ var init_headless = __esm({
6564
6638
  init_config();
6565
6639
  init_prompt4();
6566
6640
  init_compaction();
6641
+ init_tools5();
6567
6642
  init_lsp();
6568
6643
  init_agent();
6569
6644
  init_session();