@mindstudio-ai/remy 0.1.229 → 0.1.231

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/headless.js CHANGED
@@ -682,11 +682,17 @@ function parseFrontmatter(filePath) {
682
682
  return { name: "", description: "", type: "" };
683
683
  }
684
684
  }
685
- function loadPlanStatus() {
685
+ function loadPlanStatus(onboardingState) {
686
686
  try {
687
687
  const content = fs4.readFileSync(".remy-plan.md", "utf-8");
688
688
  const match = content.match(/^---\n([\s\S]*?)\n---/);
689
689
  const status = match?.[1]?.match(/^status:\s*(.+)$/m)?.[1]?.trim();
690
+ if (status === "pending" && onboardingState === "intake") {
691
+ return `
692
+ <pending_initial_plan>
693
+ This is your initial plan, proposed via writePlan and awaiting the user's decision. The user approves it by pressing "Start Building" \u2014 you'll get an approveInitialPlan message when they do, and it will tell you to begin. Until then, stay in intake: keep discussing, and revise with writePlan if the user asks. Don't start building on your own, even if the user says "looks good" in chat.
694
+ </pending_initial_plan>`;
695
+ }
690
696
  if (status === "pending") {
691
697
  return `
692
698
  <pending_plan>
@@ -868,7 +874,7 @@ The user is currently in ${viewContext?.mode ?? "code"} mode.
868
874
  ${viewContext?.activeFile ? `Active file: ${viewContext.activeFile}` : ""}
869
875
  </view_context>
870
876
 
871
- ${loadPlanStatus()}
877
+ ${loadPlanStatus(onboardingState)}
872
878
  `;
873
879
  return resolveIncludes(template);
874
880
  }
@@ -1379,8 +1385,11 @@ var updatePlanStatusTool = {
1379
1385
  required: ["status"]
1380
1386
  }
1381
1387
  },
1382
- async execute(input) {
1388
+ async execute(input, context) {
1383
1389
  const status = input.status;
1390
+ if (context?.onboardingState === "intake") {
1391
+ return `The initial plan isn't approved or rejected through this tool \u2014 the user decides via "Start Building". Keep discussing, and revise the plan with writePlan if they want changes.`;
1392
+ }
1384
1393
  let content;
1385
1394
  try {
1386
1395
  content = await fs10.readFile(PLAN_FILE2, "utf-8");
@@ -5113,6 +5122,50 @@ ${summaryText}
5113
5122
  var DESCRIPTION = `
5114
5123
  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.
5115
5124
  `.trim();
5125
+ var RENDER_WRITE_TOOL_NAMES = /* @__PURE__ */ new Set(["writeFile", "editFile"]);
5126
+ var DESIGN_EXPERT_RENDER_TOOLS = [
5127
+ ...DESIGN_EXPERT_TOOLS,
5128
+ writeFileTool.definition,
5129
+ editFileTool.definition
5130
+ ];
5131
+ async function runDesignExpert(opts, context) {
5132
+ const history = context.conversationMessages ? getSubAgentHistory(context.conversationMessages, "visualDesignExpert") : [];
5133
+ return runSubAgent({
5134
+ system: getDesignExpertPrompt(context.onboardingState),
5135
+ task: opts.task,
5136
+ history: history.length > 0 ? history : void 0,
5137
+ tools: opts.enableWrite ? DESIGN_EXPERT_RENDER_TOOLS : DESIGN_EXPERT_TOOLS,
5138
+ externalTools: /* @__PURE__ */ new Set(),
5139
+ executeTool: (name, input, toolCallId, onLog, sams) => {
5140
+ const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
5141
+ if (COMMON_READ_TOOL_NAMES.has(name)) {
5142
+ return executeTool(name, input, childCtx);
5143
+ }
5144
+ if (opts.enableWrite && RENDER_WRITE_TOOL_NAMES.has(name)) {
5145
+ return executeTool(name, input, childCtx);
5146
+ }
5147
+ return executeDesignExpertTool(name, input, childCtx, toolCallId, onLog);
5148
+ },
5149
+ apiConfig: context.apiConfig,
5150
+ model: resolveModel("visualDesignExpert", context.models, context.model),
5151
+ subAgentId: "visualDesignExpert",
5152
+ signal: context.signal,
5153
+ parentToolId: context.toolCallId,
5154
+ requestId: context.requestId,
5155
+ onEvent: context.onEvent,
5156
+ resolveExternalTool: context.resolveExternalTool,
5157
+ toolRegistry: context.toolRegistry,
5158
+ background: opts.background,
5159
+ onBackgroundComplete: opts.background ? (bgResult) => {
5160
+ context.onBackgroundComplete?.(
5161
+ context.toolCallId,
5162
+ opts.reportingName ?? "visualDesignExpert",
5163
+ bgResult.text,
5164
+ bgResult.messages
5165
+ );
5166
+ } : void 0
5167
+ });
5168
+ }
5116
5169
  var designExpertTool = {
5117
5170
  clearable: false,
5118
5171
  definition: {
@@ -5137,49 +5190,20 @@ var designExpertTool = {
5137
5190
  if (!context) {
5138
5191
  return "Error: visual design expert requires execution context";
5139
5192
  }
5140
- const history = context.conversationMessages ? getSubAgentHistory(context.conversationMessages, "visualDesignExpert") : [];
5141
- const result = await runSubAgent({
5142
- system: getDesignExpertPrompt(context.onboardingState),
5143
- task: input.task,
5144
- history: history.length > 0 ? history : void 0,
5145
- tools: DESIGN_EXPERT_TOOLS,
5146
- externalTools: /* @__PURE__ */ new Set(),
5147
- executeTool: (name, input2, toolCallId, onLog, sams) => {
5148
- const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
5149
- if (COMMON_READ_TOOL_NAMES.has(name)) {
5150
- return executeTool(name, input2, childCtx);
5151
- }
5152
- return executeDesignExpertTool(
5153
- name,
5154
- input2,
5155
- childCtx,
5156
- toolCallId,
5157
- onLog
5158
- );
5193
+ const result = await runDesignExpert(
5194
+ {
5195
+ task: input.task,
5196
+ background: input.background
5159
5197
  },
5160
- apiConfig: context.apiConfig,
5161
- model: resolveModel("visualDesignExpert", context.models, context.model),
5162
- subAgentId: "visualDesignExpert",
5163
- signal: context.signal,
5164
- parentToolId: context.toolCallId,
5165
- requestId: context.requestId,
5166
- onEvent: context.onEvent,
5167
- resolveExternalTool: context.resolveExternalTool,
5168
- toolRegistry: context.toolRegistry,
5169
- background: input.background,
5170
- onBackgroundComplete: input.background ? (bgResult) => {
5171
- context.onBackgroundComplete?.(
5172
- context.toolCallId,
5173
- "visualDesignExpert",
5174
- bgResult.text,
5175
- bgResult.messages
5176
- );
5177
- } : void 0
5178
- });
5198
+ context
5199
+ );
5179
5200
  context.subAgentMessages?.set(context.toolCallId, result.messages);
5180
5201
  return result.text;
5181
5202
  }
5182
5203
  };
5204
+ async function runDesignExpertRender(opts, context) {
5205
+ return runDesignExpert({ ...opts, enableWrite: true }, context);
5206
+ }
5183
5207
 
5184
5208
  // src/subagents/productVision/tools.ts
5185
5209
  var VISION_TOOLS = [
@@ -5284,16 +5308,25 @@ ${unifiedDiff(filePath, oldContent, "")}`;
5284
5308
  const filePath = resolve("pitch.html");
5285
5309
  try {
5286
5310
  fs19.mkdirSync(ROADMAP_DIR, { recursive: true });
5287
- const existing = fs19.existsSync(filePath) ? fs19.readFileSync(filePath, "utf-8").trim() : "";
5288
- const currentDeck = existing || PITCH_DECK_SHELL;
5311
+ const exists = fs19.existsSync(filePath);
5312
+ const before = exists ? fs19.statSync(filePath).mtimeMs : null;
5313
+ const delivery = exists ? `### Your deliverable
5314
+ The pitch deck already exists at \`${filePath}\`. Read it, then update it for the new <pitch_content>, keeping the presentation scaffolding intact \u2014 change only what needs to change.
5315
+
5316
+ Reply with a one-line summary of what you changed \u2014 not the HTML.` : `### Your deliverable
5317
+ Write the complete pitch deck to \`${filePath}\`. It does not exist yet \u2014 start from this scaffold, keeping its progress bar, chevron navigation, keyboard navigation, and transition mechanics intact:
5318
+
5319
+ <pitch_deck_shell>
5320
+ ${PITCH_DECK_SHELL}
5321
+ </pitch_deck_shell>
5322
+
5323
+ Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
5289
5324
  const task = `
5290
5325
  <pitch_content>${input.task}</pitch_content>
5291
5326
 
5292
- <current_deck>${currentDeck}</current_deck>
5293
-
5294
5327
  We are building the pitch deck for the app. Using the provided <pitch_content>, as well as the app's spec data, think about what would make a compelling, interactive, self-contained horizontally-scrolling HTML slide deck for this product. Keep it simple, clean, powerful. Giant text, large logo, big, bold stats and claims. Edit the content as necessary to create the most impactful, bold, and beautiful slides. This should not feel like an essay, and it should not feel like a landing page \u2014 it should feel like a modern interactive presentation that leaves the user wowed by the product and excited about its future.
5295
5328
 
5296
- Use <current_deck> as your starting point and replace or update the content as needed, maintaining the bones of the presentation scaffolding. Always keep the progress bar, chevron navigation, and keyboard navigation - they are part of the scaffold.
5329
+ Maintain the bones of the presentation scaffolding. Always keep the progress bar, chevron navigation, and keyboard navigation - they are part of the scaffold.
5297
5330
 
5298
5331
  ### Rules
5299
5332
  - The deck must be a single HTML file \u2014 it will be rendered in an iframe.
@@ -5303,14 +5336,18 @@ Use <current_deck> as your starting point and replace or update the content as n
5303
5336
  - Code must be clean, bug free, and easy to parse. Use GSAP for animations. Pay close attention to layout and alignment to make sure everything is perfect.
5304
5337
  - Keep the progress bar and edge chevrons from the shell \u2014 they are part of the navigation UX.
5305
5338
 
5306
- Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to an html file.`;
5307
- const result = await designExpertTool.execute({ task }, context);
5308
- const htmlMatch = result.match(
5309
- /```(?:html|wireframe)\n([\s\S]*?)```/
5310
- );
5311
- const html = htmlMatch ? htmlMatch[1].trim() : result;
5312
- fs19.writeFileSync(filePath, html, "utf-8");
5313
- return `Pitch deck written successfully.`;
5339
+ ${delivery}`;
5340
+ const result = await runDesignExpertRender({ task }, context);
5341
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
5342
+ if (!fs19.existsSync(filePath)) {
5343
+ return `Error: the design expert did not write ${filePath}. Its reply was:
5344
+ ${result.text}`;
5345
+ }
5346
+ if (before !== null && fs19.statSync(filePath).mtimeMs === before) {
5347
+ return `Error: the pitch deck at ${filePath} was not modified. The design expert's reply was:
5348
+ ${result.text}`;
5349
+ }
5350
+ return `Pitch deck written to ${filePath}. ${result.text}`;
5314
5351
  } catch (err) {
5315
5352
  return `Error generating pitch deck: ${err.message}`;
5316
5353
  }
@@ -5544,7 +5581,7 @@ import fs20 from "fs";
5544
5581
  var OVERVIEW_FILE = "src/overview.html";
5545
5582
  var DESIGN_BRIEF = `We are building the Build Overview for this app \u2014 the home page of its Spec tab. It is a calm, dense, one-page reference of everything the app actually contains, including the parts the user can't see. It renders flush inside the Spec tab's content panel (the IDE supplies the surrounding nav).
5546
5583
 
5547
- Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand. If <current_overview> is non-empty, use it as your starting point and preserve its established skin, updating only what the copy changed.
5584
+ Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand.
5548
5585
 
5549
5586
  ### The single hard rule
5550
5587
  The copy in <overview_copy> is final \u2014 it was authored and edited before it reached you. Treat it as locked content to typeset, not a draft to improve. Reproduce the words exactly: do not rewrite, rephrase, shorten, expand, reorder, or "polish" them, and do not run them through any copy tool. This is the opposite of your usual role \u2014 here you own layout, typography, and visual design only, and the words (every number, name, label, claim, and sentence) are fixed. A single changed word or wrong number breaks this document's purpose.
@@ -5559,9 +5596,7 @@ The copy in <overview_copy> is final \u2014 it was authored and edited before it
5559
5596
 
5560
5597
  ### Constraints
5561
5598
  - A single self-contained HTML file. Fonts may load from a CDN; everything else (CSS, the logo SVG) is inline.
5562
- - Responsive: fills the embedded panel width and collapses gracefully at narrow widths.
5563
-
5564
- Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to src/overview.html.`;
5599
+ - Responsive: fills the embedded panel width and collapses gracefully at narrow widths.`;
5565
5600
  var OVERVIEW_SHELL = `<!DOCTYPE html>
5566
5601
  <html lang="en">
5567
5602
  <head>
@@ -5582,6 +5617,22 @@ var OVERVIEW_SHELL = `<!DOCTYPE html>
5582
5617
  app's spec. -->
5583
5618
  </body>
5584
5619
  </html>`;
5620
+ function initialDelivery() {
5621
+ return `### Your deliverable
5622
+ Write the complete Build Overview to \`${OVERVIEW_FILE}\`. The file does not exist yet \u2014 start from this scaffold, which carries the technical hygiene for the iframed render context (keep the viewport meta and the reset). Layout, sections, type, and styling are yours to compose.
5623
+
5624
+ <overview_shell>
5625
+ ${OVERVIEW_SHELL}
5626
+ </overview_shell>
5627
+
5628
+ Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
5629
+ }
5630
+ function refreshDelivery() {
5631
+ return `### Your deliverable
5632
+ The Build Overview already exists at \`${OVERVIEW_FILE}\`. Read it, then update it to reflect <overview_copy>, preserving its established skin \u2014 change only what the copy changed.
5633
+
5634
+ Reply with a one-line summary of what you changed \u2014 not the HTML.`;
5635
+ }
5585
5636
  var buildOverviewTool = {
5586
5637
  clearable: false,
5587
5638
  definition: {
@@ -5606,21 +5657,29 @@ var buildOverviewTool = {
5606
5657
  if (!content) {
5607
5658
  return "Error: writeBuildOverview requires non-empty `content` (the overview copy).";
5608
5659
  }
5609
- try {
5610
- const existing = fs20.existsSync(OVERVIEW_FILE) ? fs20.readFileSync(OVERVIEW_FILE, "utf-8").trim() : "";
5611
- const currentOverview = existing || OVERVIEW_SHELL;
5612
- const task = `<overview_copy>${content}</overview_copy>
5660
+ const exists = fs20.existsSync(OVERVIEW_FILE);
5661
+ const task = `<overview_copy>${content}</overview_copy>
5613
5662
 
5614
- <current_overview>${currentOverview}</current_overview>
5663
+ ${DESIGN_BRIEF}
5615
5664
 
5616
- ${DESIGN_BRIEF}`;
5617
- const result = await designExpertTool.execute({ task }, context);
5618
- const htmlMatch = result.match(
5619
- /```(?:html|wireframe)\n([\s\S]*?)```/
5620
- );
5621
- const html = htmlMatch ? htmlMatch[1].trim() : result;
5622
- fs20.writeFileSync(OVERVIEW_FILE, html, "utf-8");
5623
- return "Build overview written successfully to src/overview.html.";
5665
+ ${exists ? refreshDelivery() : initialDelivery()}`;
5666
+ try {
5667
+ if (exists) {
5668
+ input.background = true;
5669
+ const result2 = await runDesignExpertRender(
5670
+ { task, background: true, reportingName: "writeBuildOverview" },
5671
+ context
5672
+ );
5673
+ context.subAgentMessages?.set(context.toolCallId, result2.messages);
5674
+ return result2.text;
5675
+ }
5676
+ const result = await runDesignExpertRender({ task }, context);
5677
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
5678
+ if (!fs20.existsSync(OVERVIEW_FILE)) {
5679
+ return `Error: the design expert did not write ${OVERVIEW_FILE}. Its reply was:
5680
+ ${result.text}`;
5681
+ }
5682
+ return `Build overview written to ${OVERVIEW_FILE}. ${result.text}`;
5624
5683
  } catch (err) {
5625
5684
  return `Error generating build overview: ${err.message}`;
5626
5685
  }
package/dist/index.js CHANGED
@@ -938,8 +938,11 @@ var init_updatePlanStatus = __esm({
938
938
  required: ["status"]
939
939
  }
940
940
  },
941
- async execute(input) {
941
+ async execute(input, context) {
942
942
  const status = input.status;
943
+ if (context?.onboardingState === "intake") {
944
+ return `The initial plan isn't approved or rejected through this tool \u2014 the user decides via "Start Building". Keep discussing, and revise the plan with writePlan if they want changes.`;
945
+ }
943
946
  let content;
944
947
  try {
945
948
  content = await fs7.readFile(PLAN_FILE2, "utf-8");
@@ -1893,11 +1896,17 @@ function parseFrontmatter(filePath) {
1893
1896
  return { name: "", description: "", type: "" };
1894
1897
  }
1895
1898
  }
1896
- function loadPlanStatus() {
1899
+ function loadPlanStatus(onboardingState) {
1897
1900
  try {
1898
1901
  const content = fs10.readFileSync(".remy-plan.md", "utf-8");
1899
1902
  const match = content.match(/^---\n([\s\S]*?)\n---/);
1900
1903
  const status = match?.[1]?.match(/^status:\s*(.+)$/m)?.[1]?.trim();
1904
+ if (status === "pending" && onboardingState === "intake") {
1905
+ return `
1906
+ <pending_initial_plan>
1907
+ This is your initial plan, proposed via writePlan and awaiting the user's decision. The user approves it by pressing "Start Building" \u2014 you'll get an approveInitialPlan message when they do, and it will tell you to begin. Until then, stay in intake: keep discussing, and revise with writePlan if the user asks. Don't start building on your own, even if the user says "looks good" in chat.
1908
+ </pending_initial_plan>`;
1909
+ }
1901
1910
  if (status === "pending") {
1902
1911
  return `
1903
1912
  <pending_plan>
@@ -2292,7 +2301,7 @@ The user is currently in ${viewContext?.mode ?? "code"} mode.
2292
2301
  ${viewContext?.activeFile ? `Active file: ${viewContext.activeFile}` : ""}
2293
2302
  </view_context>
2294
2303
 
2295
- ${loadPlanStatus()}
2304
+ ${loadPlanStatus(onboardingState)}
2296
2305
  `;
2297
2306
  return resolveIncludes(template);
2298
2307
  }
@@ -5979,7 +5988,48 @@ var init_history = __esm({
5979
5988
  });
5980
5989
 
5981
5990
  // src/subagents/designExpert/index.ts
5982
- var DESCRIPTION, designExpertTool;
5991
+ async function runDesignExpert(opts, context) {
5992
+ const history = context.conversationMessages ? getSubAgentHistory(context.conversationMessages, "visualDesignExpert") : [];
5993
+ return runSubAgent({
5994
+ system: getDesignExpertPrompt(context.onboardingState),
5995
+ task: opts.task,
5996
+ history: history.length > 0 ? history : void 0,
5997
+ tools: opts.enableWrite ? DESIGN_EXPERT_RENDER_TOOLS : DESIGN_EXPERT_TOOLS,
5998
+ externalTools: /* @__PURE__ */ new Set(),
5999
+ executeTool: (name, input, toolCallId, onLog, sams) => {
6000
+ const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
6001
+ if (COMMON_READ_TOOL_NAMES.has(name)) {
6002
+ return executeTool(name, input, childCtx);
6003
+ }
6004
+ if (opts.enableWrite && RENDER_WRITE_TOOL_NAMES.has(name)) {
6005
+ return executeTool(name, input, childCtx);
6006
+ }
6007
+ return executeDesignExpertTool(name, input, childCtx, toolCallId, onLog);
6008
+ },
6009
+ apiConfig: context.apiConfig,
6010
+ model: resolveModel("visualDesignExpert", context.models, context.model),
6011
+ subAgentId: "visualDesignExpert",
6012
+ signal: context.signal,
6013
+ parentToolId: context.toolCallId,
6014
+ requestId: context.requestId,
6015
+ onEvent: context.onEvent,
6016
+ resolveExternalTool: context.resolveExternalTool,
6017
+ toolRegistry: context.toolRegistry,
6018
+ background: opts.background,
6019
+ onBackgroundComplete: opts.background ? (bgResult) => {
6020
+ context.onBackgroundComplete?.(
6021
+ context.toolCallId,
6022
+ opts.reportingName ?? "visualDesignExpert",
6023
+ bgResult.text,
6024
+ bgResult.messages
6025
+ );
6026
+ } : void 0
6027
+ });
6028
+ }
6029
+ async function runDesignExpertRender(opts, context) {
6030
+ return runDesignExpert({ ...opts, enableWrite: true }, context);
6031
+ }
6032
+ var DESCRIPTION, RENDER_WRITE_TOOL_NAMES, DESIGN_EXPERT_RENDER_TOOLS, designExpertTool;
5983
6033
  var init_designExpert = __esm({
5984
6034
  "src/subagents/designExpert/index.ts"() {
5985
6035
  "use strict";
@@ -5990,9 +6040,17 @@ var init_designExpert = __esm({
5990
6040
  init_prompt3();
5991
6041
  init_history();
5992
6042
  init_surfaces();
6043
+ init_writeFile();
6044
+ init_editFile();
5993
6045
  DESCRIPTION = `
5994
6046
  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.
5995
6047
  `.trim();
6048
+ RENDER_WRITE_TOOL_NAMES = /* @__PURE__ */ new Set(["writeFile", "editFile"]);
6049
+ DESIGN_EXPERT_RENDER_TOOLS = [
6050
+ ...DESIGN_EXPERT_TOOLS,
6051
+ writeFileTool.definition,
6052
+ editFileTool.definition
6053
+ ];
5996
6054
  designExpertTool = {
5997
6055
  clearable: false,
5998
6056
  definition: {
@@ -6017,45 +6075,13 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
6017
6075
  if (!context) {
6018
6076
  return "Error: visual design expert requires execution context";
6019
6077
  }
6020
- const history = context.conversationMessages ? getSubAgentHistory(context.conversationMessages, "visualDesignExpert") : [];
6021
- const result = await runSubAgent({
6022
- system: getDesignExpertPrompt(context.onboardingState),
6023
- task: input.task,
6024
- history: history.length > 0 ? history : void 0,
6025
- tools: DESIGN_EXPERT_TOOLS,
6026
- externalTools: /* @__PURE__ */ new Set(),
6027
- executeTool: (name, input2, toolCallId, onLog, sams) => {
6028
- const childCtx = toolCallId ? { ...deriveContext(context, toolCallId), subAgentMessages: sams } : { ...context, subAgentMessages: sams };
6029
- if (COMMON_READ_TOOL_NAMES.has(name)) {
6030
- return executeTool(name, input2, childCtx);
6031
- }
6032
- return executeDesignExpertTool(
6033
- name,
6034
- input2,
6035
- childCtx,
6036
- toolCallId,
6037
- onLog
6038
- );
6078
+ const result = await runDesignExpert(
6079
+ {
6080
+ task: input.task,
6081
+ background: input.background
6039
6082
  },
6040
- apiConfig: context.apiConfig,
6041
- model: resolveModel("visualDesignExpert", context.models, context.model),
6042
- subAgentId: "visualDesignExpert",
6043
- signal: context.signal,
6044
- parentToolId: context.toolCallId,
6045
- requestId: context.requestId,
6046
- onEvent: context.onEvent,
6047
- resolveExternalTool: context.resolveExternalTool,
6048
- toolRegistry: context.toolRegistry,
6049
- background: input.background,
6050
- onBackgroundComplete: input.background ? (bgResult) => {
6051
- context.onBackgroundComplete?.(
6052
- context.toolCallId,
6053
- "visualDesignExpert",
6054
- bgResult.text,
6055
- bgResult.messages
6056
- );
6057
- } : void 0
6058
- });
6083
+ context
6084
+ );
6059
6085
  context.subAgentMessages?.set(context.toolCallId, result.messages);
6060
6086
  return result.text;
6061
6087
  }
@@ -6168,16 +6194,25 @@ ${unifiedDiff(filePath, oldContent, "")}`;
6168
6194
  const filePath = resolve("pitch.html");
6169
6195
  try {
6170
6196
  fs18.mkdirSync(ROADMAP_DIR, { recursive: true });
6171
- const existing = fs18.existsSync(filePath) ? fs18.readFileSync(filePath, "utf-8").trim() : "";
6172
- const currentDeck = existing || PITCH_DECK_SHELL;
6197
+ const exists = fs18.existsSync(filePath);
6198
+ const before = exists ? fs18.statSync(filePath).mtimeMs : null;
6199
+ const delivery = exists ? `### Your deliverable
6200
+ The pitch deck already exists at \`${filePath}\`. Read it, then update it for the new <pitch_content>, keeping the presentation scaffolding intact \u2014 change only what needs to change.
6201
+
6202
+ Reply with a one-line summary of what you changed \u2014 not the HTML.` : `### Your deliverable
6203
+ Write the complete pitch deck to \`${filePath}\`. It does not exist yet \u2014 start from this scaffold, keeping its progress bar, chevron navigation, keyboard navigation, and transition mechanics intact:
6204
+
6205
+ <pitch_deck_shell>
6206
+ ${PITCH_DECK_SHELL}
6207
+ </pitch_deck_shell>
6208
+
6209
+ Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
6173
6210
  const task = `
6174
6211
  <pitch_content>${input.task}</pitch_content>
6175
6212
 
6176
- <current_deck>${currentDeck}</current_deck>
6177
-
6178
6213
  We are building the pitch deck for the app. Using the provided <pitch_content>, as well as the app's spec data, think about what would make a compelling, interactive, self-contained horizontally-scrolling HTML slide deck for this product. Keep it simple, clean, powerful. Giant text, large logo, big, bold stats and claims. Edit the content as necessary to create the most impactful, bold, and beautiful slides. This should not feel like an essay, and it should not feel like a landing page \u2014 it should feel like a modern interactive presentation that leaves the user wowed by the product and excited about its future.
6179
6214
 
6180
- Use <current_deck> as your starting point and replace or update the content as needed, maintaining the bones of the presentation scaffolding. Always keep the progress bar, chevron navigation, and keyboard navigation - they are part of the scaffold.
6215
+ Maintain the bones of the presentation scaffolding. Always keep the progress bar, chevron navigation, and keyboard navigation - they are part of the scaffold.
6181
6216
 
6182
6217
  ### Rules
6183
6218
  - The deck must be a single HTML file \u2014 it will be rendered in an iframe.
@@ -6187,14 +6222,18 @@ Use <current_deck> as your starting point and replace or update the content as n
6187
6222
  - Code must be clean, bug free, and easy to parse. Use GSAP for animations. Pay close attention to layout and alignment to make sure everything is perfect.
6188
6223
  - Keep the progress bar and edge chevrons from the shell \u2014 they are part of the navigation UX.
6189
6224
 
6190
- Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to an html file.`;
6191
- const result = await designExpertTool.execute({ task }, context);
6192
- const htmlMatch = result.match(
6193
- /```(?:html|wireframe)\n([\s\S]*?)```/
6194
- );
6195
- const html = htmlMatch ? htmlMatch[1].trim() : result;
6196
- fs18.writeFileSync(filePath, html, "utf-8");
6197
- return `Pitch deck written successfully.`;
6225
+ ${delivery}`;
6226
+ const result = await runDesignExpertRender({ task }, context);
6227
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
6228
+ if (!fs18.existsSync(filePath)) {
6229
+ return `Error: the design expert did not write ${filePath}. Its reply was:
6230
+ ${result.text}`;
6231
+ }
6232
+ if (before !== null && fs18.statSync(filePath).mtimeMs === before) {
6233
+ return `Error: the pitch deck at ${filePath} was not modified. The design expert's reply was:
6234
+ ${result.text}`;
6235
+ }
6236
+ return `Pitch deck written to ${filePath}. ${result.text}`;
6198
6237
  } catch (err) {
6199
6238
  return `Error generating pitch deck: ${err.message}`;
6200
6239
  }
@@ -6489,6 +6528,22 @@ var init_scrapeWebUrl2 = __esm({
6489
6528
 
6490
6529
  // src/tools/spec/writeBuildOverview.ts
6491
6530
  import fs19 from "fs";
6531
+ function initialDelivery() {
6532
+ return `### Your deliverable
6533
+ Write the complete Build Overview to \`${OVERVIEW_FILE}\`. The file does not exist yet \u2014 start from this scaffold, which carries the technical hygiene for the iframed render context (keep the viewport meta and the reset). Layout, sections, type, and styling are yours to compose.
6534
+
6535
+ <overview_shell>
6536
+ ${OVERVIEW_SHELL}
6537
+ </overview_shell>
6538
+
6539
+ Reply with a one-line summary of what you wrote \u2014 not the HTML.`;
6540
+ }
6541
+ function refreshDelivery() {
6542
+ return `### Your deliverable
6543
+ The Build Overview already exists at \`${OVERVIEW_FILE}\`. Read it, then update it to reflect <overview_copy>, preserving its established skin \u2014 change only what the copy changed.
6544
+
6545
+ Reply with a one-line summary of what you changed \u2014 not the HTML.`;
6546
+ }
6492
6547
  var OVERVIEW_FILE, DESIGN_BRIEF, OVERVIEW_SHELL, buildOverviewTool;
6493
6548
  var init_writeBuildOverview = __esm({
6494
6549
  "src/tools/spec/writeBuildOverview.ts"() {
@@ -6497,7 +6552,7 @@ var init_writeBuildOverview = __esm({
6497
6552
  OVERVIEW_FILE = "src/overview.html";
6498
6553
  DESIGN_BRIEF = `We are building the Build Overview for this app \u2014 the home page of its Spec tab. It is a calm, dense, one-page reference of everything the app actually contains, including the parts the user can't see. It renders flush inside the Spec tab's content panel (the IDE supplies the surrounding nav).
6499
6554
 
6500
- Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand. If <current_overview> is non-empty, use it as your starting point and preserve its established skin, updating only what the copy changed.
6555
+ Take the plain-language copy in <overview_copy> and lay it out and skin it into a single, beautiful, self-contained HTML document in the app's own brand.
6501
6556
 
6502
6557
  ### The single hard rule
6503
6558
  The copy in <overview_copy> is final \u2014 it was authored and edited before it reached you. Treat it as locked content to typeset, not a draft to improve. Reproduce the words exactly: do not rewrite, rephrase, shorten, expand, reorder, or "polish" them, and do not run them through any copy tool. This is the opposite of your usual role \u2014 here you own layout, typography, and visual design only, and the words (every number, name, label, claim, and sentence) are fixed. A single changed word or wrong number breaks this document's purpose.
@@ -6512,9 +6567,7 @@ The copy in <overview_copy> is final \u2014 it was authored and edited before it
6512
6567
 
6513
6568
  ### Constraints
6514
6569
  - A single self-contained HTML file. Fonts may load from a CDN; everything else (CSS, the logo SVG) is inline.
6515
- - Responsive: fills the embedded panel width and collapses gracefully at narrow widths.
6516
-
6517
- Respond only with the complete HTML file and absolutely no other text. Your response will be written directly to src/overview.html.`;
6570
+ - Responsive: fills the embedded panel width and collapses gracefully at narrow widths.`;
6518
6571
  OVERVIEW_SHELL = `<!DOCTYPE html>
6519
6572
  <html lang="en">
6520
6573
  <head>
@@ -6559,21 +6612,29 @@ Respond only with the complete HTML file and absolutely no other text. Your resp
6559
6612
  if (!content) {
6560
6613
  return "Error: writeBuildOverview requires non-empty `content` (the overview copy).";
6561
6614
  }
6562
- try {
6563
- const existing = fs19.existsSync(OVERVIEW_FILE) ? fs19.readFileSync(OVERVIEW_FILE, "utf-8").trim() : "";
6564
- const currentOverview = existing || OVERVIEW_SHELL;
6565
- const task = `<overview_copy>${content}</overview_copy>
6615
+ const exists = fs19.existsSync(OVERVIEW_FILE);
6616
+ const task = `<overview_copy>${content}</overview_copy>
6566
6617
 
6567
- <current_overview>${currentOverview}</current_overview>
6618
+ ${DESIGN_BRIEF}
6568
6619
 
6569
- ${DESIGN_BRIEF}`;
6570
- const result = await designExpertTool.execute({ task }, context);
6571
- const htmlMatch = result.match(
6572
- /```(?:html|wireframe)\n([\s\S]*?)```/
6573
- );
6574
- const html = htmlMatch ? htmlMatch[1].trim() : result;
6575
- fs19.writeFileSync(OVERVIEW_FILE, html, "utf-8");
6576
- return "Build overview written successfully to src/overview.html.";
6620
+ ${exists ? refreshDelivery() : initialDelivery()}`;
6621
+ try {
6622
+ if (exists) {
6623
+ input.background = true;
6624
+ const result2 = await runDesignExpertRender(
6625
+ { task, background: true, reportingName: "writeBuildOverview" },
6626
+ context
6627
+ );
6628
+ context.subAgentMessages?.set(context.toolCallId, result2.messages);
6629
+ return result2.text;
6630
+ }
6631
+ const result = await runDesignExpertRender({ task }, context);
6632
+ context.subAgentMessages?.set(context.toolCallId, result.messages);
6633
+ if (!fs19.existsSync(OVERVIEW_FILE)) {
6634
+ return `Error: the design expert did not write ${OVERVIEW_FILE}. Its reply was:
6635
+ ${result.text}`;
6636
+ }
6637
+ return `Build overview written to ${OVERVIEW_FILE}. ${result.text}`;
6577
6638
  } catch (err) {
6578
6639
  return `Error generating build overview: ${err.message}`;
6579
6640
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.229",
3
+ "version": "0.1.231",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",