@mindstudio-ai/remy 0.1.249 → 0.1.251

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
@@ -4479,11 +4479,34 @@ var init_runner = __esm({
4479
4479
  }
4480
4480
  });
4481
4481
 
4482
+ // src/subagents/common/tools.ts
4483
+ var COMMON_READ_TOOLS, COMMON_READ_TOOL_NAMES;
4484
+ var init_tools = __esm({
4485
+ "src/subagents/common/tools.ts"() {
4486
+ "use strict";
4487
+ init_readFile();
4488
+ init_listDir();
4489
+ init_grep();
4490
+ init_glob();
4491
+ COMMON_READ_TOOLS = [
4492
+ readFileTool.definition,
4493
+ listDirTool.definition,
4494
+ grepTool.definition,
4495
+ globTool.definition
4496
+ ];
4497
+ COMMON_READ_TOOL_NAMES = new Set(
4498
+ COMMON_READ_TOOLS.map((t) => t.name)
4499
+ );
4500
+ }
4501
+ });
4502
+
4482
4503
  // src/subagents/browserAutomation/tools.ts
4483
4504
  var BROWSER_TOOLS, BROWSER_EXTERNAL_TOOLS;
4484
- var init_tools = __esm({
4505
+ var init_tools2 = __esm({
4485
4506
  "src/subagents/browserAutomation/tools.ts"() {
4486
4507
  "use strict";
4508
+ init_tools();
4509
+ init_readSpec();
4487
4510
  BROWSER_TOOLS = [
4488
4511
  {
4489
4512
  clearable: false,
@@ -4626,24 +4649,199 @@ var init_tools = __esm({
4626
4649
  }
4627
4650
  }
4628
4651
  }
4629
- }
4652
+ },
4653
+ // Read tools so the QA agent can pull full spec detail on demand — the spec
4654
+ // context in its prompt is a lightweight index (see prompt.ts) that points
4655
+ // here. Routed to the global executeTool in index.ts, mirroring specSync.
4656
+ ...COMMON_READ_TOOLS,
4657
+ readSpecTool.definition
4630
4658
  ];
4631
4659
  BROWSER_EXTERNAL_TOOLS = /* @__PURE__ */ new Set(["browserCommand"]);
4632
4660
  }
4633
4661
  });
4634
4662
 
4635
- // src/subagents/browserAutomation/prompt.ts
4663
+ // src/subagents/common/context.ts
4636
4664
  import fs15 from "fs";
4637
- function getBrowserAutomationPrompt() {
4665
+ import path8 from "path";
4666
+ function walkMdFiles(dir, skip) {
4667
+ const files = [];
4638
4668
  try {
4639
- const appSpec = fs15.readFileSync("src/app.md", "utf-8").trim();
4640
- return `${BASE_PROMPT}
4669
+ for (const entry of fs15.readdirSync(dir, { withFileTypes: true })) {
4670
+ const full = path8.join(dir, entry.name);
4671
+ if (entry.isDirectory()) {
4672
+ if (!skip?.has(entry.name)) {
4673
+ files.push(...walkMdFiles(full, skip));
4674
+ }
4675
+ } else if (entry.name.endsWith(".md")) {
4676
+ files.push(full);
4677
+ }
4678
+ }
4679
+ } catch {
4680
+ }
4681
+ return files.sort();
4682
+ }
4683
+ function parseFrontmatter(filePath) {
4684
+ try {
4685
+ const content = fs15.readFileSync(filePath, "utf-8");
4686
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
4687
+ if (!match) {
4688
+ return {};
4689
+ }
4690
+ const fm = {};
4691
+ for (const line of match[1].split("\n")) {
4692
+ const sep = line.indexOf(":");
4693
+ if (sep > 0) {
4694
+ const key = line.slice(0, sep).trim();
4695
+ const val = line.slice(sep + 1).trim();
4696
+ fm[key] = val;
4697
+ }
4698
+ }
4699
+ return fm;
4700
+ } catch {
4701
+ return {};
4702
+ }
4703
+ }
4704
+ function loadSpecIndex() {
4705
+ const files = walkMdFiles("src", /* @__PURE__ */ new Set(["roadmap"]));
4706
+ if (files.length === 0) {
4707
+ return "";
4708
+ }
4709
+ const lines = files.map((f) => {
4710
+ const fm = parseFrontmatter(f);
4711
+ let line = `- ${f}`;
4712
+ if (fm.name) {
4713
+ line += ` \u2014 "${fm.name}"`;
4714
+ }
4715
+ if (fm.description) {
4716
+ line += ` \u2014 ${fm.description}`;
4717
+ }
4718
+ return line;
4719
+ });
4720
+ return `<spec_files>
4721
+ ## Project Spec Files
4722
+ Use readFile to access full contents.
4641
4723
 
4642
- <!-- cache_breakpoint -->
4724
+ ${lines.join("\n")}
4725
+ </spec_files>`;
4726
+ }
4727
+ function loadRoadmapIndex() {
4728
+ const parts = [];
4729
+ try {
4730
+ const indexJson = JSON.parse(
4731
+ fs15.readFileSync("src/roadmap/index.json", "utf-8")
4732
+ );
4733
+ if (indexJson.lanes?.length > 0) {
4734
+ const laneLines = indexJson.lanes.map(
4735
+ (l) => `- **${l.name}**: ${l.narrative || ""} (${l.items?.length || 0} items)`
4736
+ );
4737
+ parts.push(`### Lanes
4738
+ ${laneLines.join("\n")}`);
4739
+ }
4740
+ if (indexJson.standalone?.length > 0) {
4741
+ parts.push(
4742
+ `### Standalone
4743
+ ${indexJson.standalone.map((s) => `- ${s}`).join("\n")}`
4744
+ );
4745
+ }
4746
+ } catch {
4747
+ }
4748
+ const files = walkMdFiles("src/roadmap");
4749
+ if (files.length > 0) {
4750
+ const lines = files.map((f) => {
4751
+ const fm = parseFrontmatter(f);
4752
+ let line = `- ${f}`;
4753
+ if (fm.name) {
4754
+ line += ` \u2014 "${fm.name}"`;
4755
+ }
4756
+ if (fm.status) {
4757
+ line += ` (${fm.status})`;
4758
+ }
4759
+ if (fm.description) {
4760
+ line += ` \u2014 ${fm.description}`;
4761
+ }
4762
+ return line;
4763
+ });
4764
+ parts.push(`### Items
4765
+ ${lines.join("\n")}`);
4766
+ }
4767
+ if (parts.length === 0) {
4768
+ return "";
4769
+ }
4770
+ return `<current_roadmap>
4771
+ ## Roadmap
4772
+ Use readFile to access full contents.
4773
+
4774
+ ${parts.join("\n\n")}
4775
+ </current_roadmap>`;
4776
+ }
4777
+ function loadPlatformBrief() {
4778
+ return `<platform_brief>
4779
+ ## What is a Remy app?
4780
+
4781
+ A Remy 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.
4782
+
4783
+ 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.
4784
+
4785
+ ## What people build
4786
+
4787
+ - Business tools \u2014 client portals, approval workflows, admin panels with role-based access
4788
+ - AI-powered apps \u2014 document processors, image/video tools, content generators, conversational agents that take actions
4789
+ - Full-stack web apps \u2014 social platforms, membership sites, marketplaces, booking systems, community hubs \u2014 multi-user apps with auth, data, UI
4790
+ - Automations with no UI \u2014 cron jobs, webhook handlers, email processors, data sync pipelines
4791
+ - Marketing & launch pages \u2014 landing pages, waitlist pages with referral mechanics, product sites with scroll animations
4792
+ - Agent tools \u2014 MCP tool servers for AI assistants
4793
+ - Creative/interactive projects \u2014 browser games with p5.js or Three.js, interactive visualizations, generative art, portfolio sites
4794
+ - API services \u2014 backend logic exposed as REST endpoints
4795
+ - Simple static sites \u2014 no backend needed, just a web interface with a build step
4796
+
4797
+ An app can be any combination of these.
4798
+
4799
+ ## Interfaces
4643
4800
 
4644
- <app_context>
4645
- ${appSpec}
4646
- </app_context>`;
4801
+ Each interface type invokes the same backend methods. Methods don't know which interface called them.
4802
+
4803
+ - Web \u2014 any TypeScript project with a build command. Framework-agnostic (React, Vue, Svelte, vanilla, anything). The frontend SDK provides typed RPC to backend methods.
4804
+ - API \u2014 auto-generated REST endpoints for every method
4805
+ - Cron \u2014 scheduled jobs on a configurable interval
4806
+ - Webhook \u2014 HTTP endpoints that trigger methods
4807
+ - Email \u2014 inbound email processing
4808
+ - MCP \u2014 tool servers for AI assistants
4809
+ - Agent \u2014 conversational LLM interface with tool access to backend methods
4810
+
4811
+ ## Backend
4812
+
4813
+ TypeScript running in a sandboxed environment. Any npm package can be installed. Key capabilities:
4814
+
4815
+ - Managed SQLite database with typed schemas and automatic migrations. Define a TypeScript interface, push, and the platform handles diffing and migrating.
4816
+ - Built-in app-managed auth. Opt-in via manifest \u2014 developer builds login UI, platform handles verification codes (email-code, sms-code) and cookie sessions. API key auth for programmatic access. No OAuth, no social login (no Apple, Google, Facebook, or GitHub sign-in). Backend methods use auth.requireRole() for access control.
4817
+ - Encrypted secrets with separate dev/prod values, injected as process.env. For third-party service credentials not covered by the SDK.
4818
+ - Git-native deployment. Push to default branch to deploy.
4819
+
4820
+ ## MindStudio SDK
4821
+
4822
+ 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.
4823
+
4824
+ ## What Remy apps are NOT good for
4825
+
4826
+ - Native mobile apps (iOS/Android). Mobile-responsive web apps are fine.
4827
+ - Real-time multiplayer with persistent connections (no WebSocket support). Turn-based or async patterns work.
4828
+ </platform_brief>`;
4829
+ }
4830
+ var init_context = __esm({
4831
+ "src/subagents/common/context.ts"() {
4832
+ "use strict";
4833
+ }
4834
+ });
4835
+
4836
+ // src/subagents/browserAutomation/prompt.ts
4837
+ function getBrowserAutomationPrompt() {
4838
+ try {
4839
+ const specIndex = loadSpecIndex();
4840
+ const parts = [BASE_PROMPT, "<!-- cache_breakpoint -->"];
4841
+ if (specIndex) {
4842
+ parts.push(specIndex);
4843
+ }
4844
+ return parts.join("\n\n");
4647
4845
  } catch {
4648
4846
  return BASE_PROMPT;
4649
4847
  }
@@ -4653,6 +4851,7 @@ var init_prompt = __esm({
4653
4851
  "src/subagents/browserAutomation/prompt.ts"() {
4654
4852
  "use strict";
4655
4853
  init_assets();
4854
+ init_context();
4656
4855
  BASE_PROMPT = readAsset("subagents/browserAutomation", "prompt.md");
4657
4856
  }
4658
4857
  });
@@ -4707,6 +4906,9 @@ async function runBrowserAutomation(task, context, opts) {
4707
4906
  return `Error taking screenshot: ${err.message}`;
4708
4907
  }
4709
4908
  }
4909
+ if (COMMON_READ_TOOL_NAMES.has(name) || name === readSpecTool.definition.name) {
4910
+ return executeTool(name, _input, context);
4911
+ }
4710
4912
  return `Error: unknown local tool "${name}"`;
4711
4913
  },
4712
4914
  apiConfig: context.apiConfig,
@@ -4794,8 +4996,11 @@ var log8, browserAutomationTool;
4794
4996
  var init_browserAutomation = __esm({
4795
4997
  "src/subagents/browserAutomation/index.ts"() {
4796
4998
  "use strict";
4999
+ init_tools8();
4797
5000
  init_runner();
5001
+ init_tools2();
4798
5002
  init_tools();
5003
+ init_readSpec();
4799
5004
  init_prompt();
4800
5005
  init_sidecar();
4801
5006
  init_browserLock();
@@ -4941,27 +5146,6 @@ var init_screenshot2 = __esm({
4941
5146
  }
4942
5147
  });
4943
5148
 
4944
- // src/subagents/common/tools.ts
4945
- var COMMON_READ_TOOLS, COMMON_READ_TOOL_NAMES;
4946
- var init_tools2 = __esm({
4947
- "src/subagents/common/tools.ts"() {
4948
- "use strict";
4949
- init_readFile();
4950
- init_listDir();
4951
- init_grep();
4952
- init_glob();
4953
- COMMON_READ_TOOLS = [
4954
- readFileTool.definition,
4955
- listDirTool.definition,
4956
- grepTool.definition,
4957
- globTool.definition
4958
- ];
4959
- COMMON_READ_TOOL_NAMES = new Set(
4960
- COMMON_READ_TOOLS.map((t) => t.name)
4961
- );
4962
- }
4963
- });
4964
-
4965
5149
  // src/subagents/designExpert/tools/searchGoogle.ts
4966
5150
  var searchGoogle_exports = {};
4967
5151
  __export(searchGoogle_exports, {
@@ -5631,185 +5815,12 @@ var init_editImages = __esm({
5631
5815
  }
5632
5816
  });
5633
5817
 
5634
- // src/subagents/common/context.ts
5635
- import fs16 from "fs";
5636
- import path8 from "path";
5637
- function walkMdFiles(dir, skip) {
5638
- const files = [];
5639
- try {
5640
- for (const entry of fs16.readdirSync(dir, { withFileTypes: true })) {
5641
- const full = path8.join(dir, entry.name);
5642
- if (entry.isDirectory()) {
5643
- if (!skip?.has(entry.name)) {
5644
- files.push(...walkMdFiles(full, skip));
5645
- }
5646
- } else if (entry.name.endsWith(".md")) {
5647
- files.push(full);
5648
- }
5649
- }
5650
- } catch {
5651
- }
5652
- return files.sort();
5653
- }
5654
- function parseFrontmatter(filePath) {
5655
- try {
5656
- const content = fs16.readFileSync(filePath, "utf-8");
5657
- const match = content.match(/^---\n([\s\S]*?)\n---/);
5658
- if (!match) {
5659
- return {};
5660
- }
5661
- const fm = {};
5662
- for (const line of match[1].split("\n")) {
5663
- const sep = line.indexOf(":");
5664
- if (sep > 0) {
5665
- const key = line.slice(0, sep).trim();
5666
- const val = line.slice(sep + 1).trim();
5667
- fm[key] = val;
5668
- }
5669
- }
5670
- return fm;
5671
- } catch {
5672
- return {};
5673
- }
5674
- }
5675
- function loadSpecIndex() {
5676
- const files = walkMdFiles("src", /* @__PURE__ */ new Set(["roadmap"]));
5677
- if (files.length === 0) {
5678
- return "";
5679
- }
5680
- const lines = files.map((f) => {
5681
- const fm = parseFrontmatter(f);
5682
- let line = `- ${f}`;
5683
- if (fm.name) {
5684
- line += ` \u2014 "${fm.name}"`;
5685
- }
5686
- if (fm.description) {
5687
- line += ` \u2014 ${fm.description}`;
5688
- }
5689
- return line;
5690
- });
5691
- return `<spec_files>
5692
- ## Project Spec Files
5693
- Use readFile to access full contents.
5694
-
5695
- ${lines.join("\n")}
5696
- </spec_files>`;
5697
- }
5698
- function loadRoadmapIndex() {
5699
- const parts = [];
5700
- try {
5701
- const indexJson = JSON.parse(
5702
- fs16.readFileSync("src/roadmap/index.json", "utf-8")
5703
- );
5704
- if (indexJson.lanes?.length > 0) {
5705
- const laneLines = indexJson.lanes.map(
5706
- (l) => `- **${l.name}**: ${l.narrative || ""} (${l.items?.length || 0} items)`
5707
- );
5708
- parts.push(`### Lanes
5709
- ${laneLines.join("\n")}`);
5710
- }
5711
- if (indexJson.standalone?.length > 0) {
5712
- parts.push(
5713
- `### Standalone
5714
- ${indexJson.standalone.map((s) => `- ${s}`).join("\n")}`
5715
- );
5716
- }
5717
- } catch {
5718
- }
5719
- const files = walkMdFiles("src/roadmap");
5720
- if (files.length > 0) {
5721
- const lines = files.map((f) => {
5722
- const fm = parseFrontmatter(f);
5723
- let line = `- ${f}`;
5724
- if (fm.name) {
5725
- line += ` \u2014 "${fm.name}"`;
5726
- }
5727
- if (fm.status) {
5728
- line += ` (${fm.status})`;
5729
- }
5730
- if (fm.description) {
5731
- line += ` \u2014 ${fm.description}`;
5732
- }
5733
- return line;
5734
- });
5735
- parts.push(`### Items
5736
- ${lines.join("\n")}`);
5737
- }
5738
- if (parts.length === 0) {
5739
- return "";
5740
- }
5741
- return `<current_roadmap>
5742
- ## Roadmap
5743
- Use readFile to access full contents.
5744
-
5745
- ${parts.join("\n\n")}
5746
- </current_roadmap>`;
5747
- }
5748
- function loadPlatformBrief() {
5749
- return `<platform_brief>
5750
- ## What is a Remy app?
5751
-
5752
- A Remy 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.
5753
-
5754
- 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.
5755
-
5756
- ## What people build
5757
-
5758
- - Business tools \u2014 client portals, approval workflows, admin panels with role-based access
5759
- - AI-powered apps \u2014 document processors, image/video tools, content generators, conversational agents that take actions
5760
- - Full-stack web apps \u2014 social platforms, membership sites, marketplaces, booking systems, community hubs \u2014 multi-user apps with auth, data, UI
5761
- - Automations with no UI \u2014 cron jobs, webhook handlers, email processors, data sync pipelines
5762
- - Marketing & launch pages \u2014 landing pages, waitlist pages with referral mechanics, product sites with scroll animations
5763
- - Agent tools \u2014 MCP tool servers for AI assistants
5764
- - Creative/interactive projects \u2014 browser games with p5.js or Three.js, interactive visualizations, generative art, portfolio sites
5765
- - API services \u2014 backend logic exposed as REST endpoints
5766
- - Simple static sites \u2014 no backend needed, just a web interface with a build step
5767
-
5768
- An app can be any combination of these.
5769
-
5770
- ## Interfaces
5771
-
5772
- Each interface type invokes the same backend methods. Methods don't know which interface called them.
5773
-
5774
- - Web \u2014 any TypeScript project with a build command. Framework-agnostic (React, Vue, Svelte, vanilla, anything). The frontend SDK provides typed RPC to backend methods.
5775
- - API \u2014 auto-generated REST endpoints for every method
5776
- - Cron \u2014 scheduled jobs on a configurable interval
5777
- - Webhook \u2014 HTTP endpoints that trigger methods
5778
- - Email \u2014 inbound email processing
5779
- - MCP \u2014 tool servers for AI assistants
5780
- - Agent \u2014 conversational LLM interface with tool access to backend methods
5781
-
5782
- ## Backend
5783
-
5784
- TypeScript running in a sandboxed environment. Any npm package can be installed. Key capabilities:
5785
-
5786
- - Managed SQLite database with typed schemas and automatic migrations. Define a TypeScript interface, push, and the platform handles diffing and migrating.
5787
- - Built-in app-managed auth. Opt-in via manifest \u2014 developer builds login UI, platform handles verification codes (email-code, sms-code) and cookie sessions. API key auth for programmatic access. No OAuth, no social login (no Apple, Google, Facebook, or GitHub sign-in). Backend methods use auth.requireRole() for access control.
5788
- - Encrypted secrets with separate dev/prod values, injected as process.env. For third-party service credentials not covered by the SDK.
5789
- - Git-native deployment. Push to default branch to deploy.
5790
-
5791
- ## MindStudio SDK
5792
-
5793
- 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.
5794
-
5795
- ## What Remy apps are NOT good for
5796
-
5797
- - Native mobile apps (iOS/Android). Mobile-responsive web apps are fine.
5798
- - Real-time multiplayer with persistent connections (no WebSocket support). Turn-based or async patterns work.
5799
- </platform_brief>`;
5800
- }
5801
- var init_context = __esm({
5802
- "src/subagents/common/context.ts"() {
5803
- "use strict";
5804
- }
5805
- });
5806
-
5807
5818
  // src/subagents/copyEditor/tools.ts
5808
5819
  var COPY_EDITOR_TOOLS;
5809
5820
  var init_tools3 = __esm({
5810
5821
  "src/subagents/copyEditor/tools.ts"() {
5811
5822
  "use strict";
5812
- init_tools2();
5823
+ init_tools();
5813
5824
  COPY_EDITOR_TOOLS = [...COMMON_READ_TOOLS];
5814
5825
  }
5815
5826
  });
@@ -5922,7 +5933,7 @@ var init_tools4 = __esm({
5922
5933
  "src/subagents/designExpert/tools/index.ts"() {
5923
5934
  "use strict";
5924
5935
  init_tools8();
5925
- init_tools2();
5936
+ init_tools();
5926
5937
  init_searchGoogle2();
5927
5938
  init_scrapeWebUrl();
5928
5939
  init_analyzeDesign();
@@ -6012,7 +6023,7 @@ var init_orgContext = __esm({
6012
6023
  });
6013
6024
 
6014
6025
  // src/subagents/designExpert/data/sampleCache.ts
6015
- import fs17 from "fs";
6026
+ import fs16 from "fs";
6016
6027
  function generateIndices(poolSize, sampleSize) {
6017
6028
  const n = Math.min(sampleSize, poolSize);
6018
6029
  const indices = Array.from({ length: poolSize }, (_, i) => i);
@@ -6024,14 +6035,14 @@ function generateIndices(poolSize, sampleSize) {
6024
6035
  }
6025
6036
  function load() {
6026
6037
  try {
6027
- return JSON.parse(fs17.readFileSync(SAMPLE_FILE, "utf-8"));
6038
+ return JSON.parse(fs16.readFileSync(SAMPLE_FILE, "utf-8"));
6028
6039
  } catch {
6029
6040
  return null;
6030
6041
  }
6031
6042
  }
6032
6043
  function save(indices) {
6033
6044
  try {
6034
- fs17.writeFileSync(SAMPLE_FILE, JSON.stringify(indices));
6045
+ fs16.writeFileSync(SAMPLE_FILE, JSON.stringify(indices));
6035
6046
  } catch {
6036
6047
  }
6037
6048
  }
@@ -6353,7 +6364,7 @@ var init_designExpert = __esm({
6353
6364
  init_tools8();
6354
6365
  init_runner();
6355
6366
  init_tools4();
6356
- init_tools2();
6367
+ init_tools();
6357
6368
  init_prompt2();
6358
6369
  init_history();
6359
6370
  init_surfaces();
@@ -6411,7 +6422,7 @@ var VISION_TOOLS;
6411
6422
  var init_tools5 = __esm({
6412
6423
  "src/subagents/productVision/tools.ts"() {
6413
6424
  "use strict";
6414
- init_tools2();
6425
+ init_tools();
6415
6426
  VISION_TOOLS = [
6416
6427
  ...COMMON_READ_TOOLS,
6417
6428
  {
@@ -6465,7 +6476,7 @@ var init_tools5 = __esm({
6465
6476
  });
6466
6477
 
6467
6478
  // src/subagents/productVision/executor.ts
6468
- import fs18 from "fs";
6479
+ import fs17 from "fs";
6469
6480
  import path9 from "path";
6470
6481
  function resolve(filePath) {
6471
6482
  return path9.join(ROADMAP_DIR, filePath);
@@ -6475,13 +6486,13 @@ async function executeVisionTool(name, input, context) {
6475
6486
  case "writeFile": {
6476
6487
  const filePath = resolve(input.path);
6477
6488
  try {
6478
- fs18.mkdirSync(ROADMAP_DIR, { recursive: true });
6489
+ fs17.mkdirSync(ROADMAP_DIR, { recursive: true });
6479
6490
  let oldContent = null;
6480
6491
  try {
6481
- oldContent = fs18.readFileSync(filePath, "utf-8");
6492
+ oldContent = fs17.readFileSync(filePath, "utf-8");
6482
6493
  } catch {
6483
6494
  }
6484
- fs18.writeFileSync(filePath, input.content, "utf-8");
6495
+ fs17.writeFileSync(filePath, input.content, "utf-8");
6485
6496
  const lineCount = input.content.split("\n").length;
6486
6497
  const label = oldContent !== null ? "Wrote" : "Created";
6487
6498
  return `${label} ${filePath} (${lineCount} lines)
@@ -6493,11 +6504,11 @@ ${unifiedDiff(filePath, oldContent ?? "", input.content)}`;
6493
6504
  case "deleteFile": {
6494
6505
  const filePath = resolve(input.path);
6495
6506
  try {
6496
- if (!fs18.existsSync(filePath)) {
6507
+ if (!fs17.existsSync(filePath)) {
6497
6508
  return `Error: ${filePath} does not exist`;
6498
6509
  }
6499
- const oldContent = fs18.readFileSync(filePath, "utf-8");
6500
- fs18.unlinkSync(filePath);
6510
+ const oldContent = fs17.readFileSync(filePath, "utf-8");
6511
+ fs17.unlinkSync(filePath);
6501
6512
  return `Deleted ${filePath}
6502
6513
  ${unifiedDiff(filePath, oldContent, "")}`;
6503
6514
  } catch (err) {
@@ -6510,9 +6521,9 @@ ${unifiedDiff(filePath, oldContent, "")}`;
6510
6521
  }
6511
6522
  const filePath = resolve("pitch.html");
6512
6523
  try {
6513
- fs18.mkdirSync(ROADMAP_DIR, { recursive: true });
6514
- const exists = fs18.existsSync(filePath);
6515
- const before = exists ? fs18.statSync(filePath).mtimeMs : null;
6524
+ fs17.mkdirSync(ROADMAP_DIR, { recursive: true });
6525
+ const exists = fs17.existsSync(filePath);
6526
+ const before = exists ? fs17.statSync(filePath).mtimeMs : null;
6516
6527
  const delivery = exists ? `### Your deliverable
6517
6528
  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.
6518
6529
 
@@ -6542,11 +6553,11 @@ Maintain the bones of the presentation scaffolding. Always keep the progress bar
6542
6553
  ${delivery}`;
6543
6554
  const result = await runDesignExpertRender({ task }, context);
6544
6555
  context.subAgentMessages?.set(context.toolCallId, result.messages);
6545
- if (!fs18.existsSync(filePath)) {
6556
+ if (!fs17.existsSync(filePath)) {
6546
6557
  return `Error: the design expert did not write ${filePath}. Its reply was:
6547
6558
  ${result.text}`;
6548
6559
  }
6549
- if (before !== null && fs18.statSync(filePath).mtimeMs === before) {
6560
+ if (before !== null && fs17.statSync(filePath).mtimeMs === before) {
6550
6561
  return `Error: the pitch deck at ${filePath} was not modified. The design expert's reply was:
6551
6562
  ${result.text}`;
6552
6563
  }
@@ -6566,7 +6577,6 @@ var init_executor = __esm({
6566
6577
  init_diff();
6567
6578
  init_designExpert();
6568
6579
  init_assets();
6569
- init_context();
6570
6580
  ROADMAP_DIR = "src/roadmap";
6571
6581
  PITCH_DECK_SHELL = readAsset(
6572
6582
  "subagents/productVision",
@@ -6594,7 +6604,6 @@ var init_prompt3 = __esm({
6594
6604
  "src/subagents/productVision/prompt.ts"() {
6595
6605
  "use strict";
6596
6606
  init_assets();
6597
- init_executor();
6598
6607
  init_context();
6599
6608
  BASE_PROMPT3 = readAsset("subagents/productVision", "prompt.md");
6600
6609
  }
@@ -6608,7 +6617,7 @@ var init_productVision = __esm({
6608
6617
  init_tools8();
6609
6618
  init_runner();
6610
6619
  init_tools5();
6611
- init_tools2();
6620
+ init_tools();
6612
6621
  init_executor();
6613
6622
  init_prompt3();
6614
6623
  init_history();
@@ -6682,7 +6691,7 @@ var SANITY_CHECK_TOOLS;
6682
6691
  var init_tools6 = __esm({
6683
6692
  "src/subagents/codeSanityCheck/tools.ts"() {
6684
6693
  "use strict";
6685
- init_tools2();
6694
+ init_tools();
6686
6695
  SANITY_CHECK_TOOLS = [
6687
6696
  ...COMMON_READ_TOOLS,
6688
6697
  {
@@ -6800,7 +6809,7 @@ var SPEC_SYNC_TOOLS;
6800
6809
  var init_tools7 = __esm({
6801
6810
  "src/subagents/specSync/tools.ts"() {
6802
6811
  "use strict";
6803
- init_tools2();
6812
+ init_tools();
6804
6813
  init_readSpec();
6805
6814
  init_editSpec();
6806
6815
  init_writeSpec();
@@ -6974,7 +6983,7 @@ var init_scrapeWebUrl2 = __esm({
6974
6983
  });
6975
6984
 
6976
6985
  // src/tools/spec/writeBuildOverview.ts
6977
- import fs19 from "fs";
6986
+ import fs18 from "fs";
6978
6987
  function initialDelivery() {
6979
6988
  return `### Your deliverable
6980
6989
  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.
@@ -7059,7 +7068,7 @@ The copy in <overview_copy> is final \u2014 it was authored and edited before it
7059
7068
  if (!content) {
7060
7069
  return "Error: writeBuildOverview requires non-empty `content` (the overview copy).";
7061
7070
  }
7062
- const exists = fs19.existsSync(OVERVIEW_FILE);
7071
+ const exists = fs18.existsSync(OVERVIEW_FILE);
7063
7072
  const task = `<overview_copy>${content}</overview_copy>
7064
7073
 
7065
7074
  ${DESIGN_BRIEF}
@@ -7077,7 +7086,7 @@ ${exists ? refreshDelivery() : initialDelivery()}`;
7077
7086
  }
7078
7087
  const result = await runDesignExpertRender({ task }, context);
7079
7088
  context.subAgentMessages?.set(context.toolCallId, result.messages);
7080
- if (!fs19.existsSync(OVERVIEW_FILE)) {
7089
+ if (!fs18.existsSync(OVERVIEW_FILE)) {
7081
7090
  return `Error: the design expert did not write ${OVERVIEW_FILE}. Its reply was:
7082
7091
  ${result.text}`;
7083
7092
  }
@@ -7416,7 +7425,7 @@ var init_errors = __esm({
7416
7425
  });
7417
7426
 
7418
7427
  // src/brandExtraction/index.ts
7419
- import fs20 from "fs";
7428
+ import fs19 from "fs";
7420
7429
  import path10 from "path";
7421
7430
  import { createHash } from "crypto";
7422
7431
  async function runExtraction(apiConfig, model) {
@@ -7463,7 +7472,7 @@ function sha256(input) {
7463
7472
  }
7464
7473
  function readSafe(filePath) {
7465
7474
  try {
7466
- return fs20.readFileSync(filePath, "utf-8");
7475
+ return fs19.readFileSync(filePath, "utf-8");
7467
7476
  } catch {
7468
7477
  return "";
7469
7478
  }
@@ -7471,7 +7480,7 @@ function readSafe(filePath) {
7471
7480
  function walkMdFiles2(dir) {
7472
7481
  const results = [];
7473
7482
  try {
7474
- const entries = fs20.readdirSync(dir, { withFileTypes: true });
7483
+ const entries = fs19.readdirSync(dir, { withFileTypes: true });
7475
7484
  for (const entry of entries) {
7476
7485
  const full = path10.join(dir, entry.name);
7477
7486
  if (entry.isDirectory()) {
@@ -7486,7 +7495,7 @@ function walkMdFiles2(dir) {
7486
7495
  }
7487
7496
  function parseFrontmatter2(filePath) {
7488
7497
  try {
7489
- const content = fs20.readFileSync(filePath, "utf-8");
7498
+ const content = fs19.readFileSync(filePath, "utf-8");
7490
7499
  const match = content.match(/^---\n([\s\S]*?)\n---/);
7491
7500
  if (!match) {
7492
7501
  return { type: "" };
@@ -7683,14 +7692,14 @@ function pickFont(raw) {
7683
7692
  }
7684
7693
  function persistBrand(brand, inputHash) {
7685
7694
  const tmp = `${BRAND_FILE}.tmp`;
7686
- fs20.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
7687
- fs20.renameSync(tmp, BRAND_FILE);
7695
+ fs19.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
7696
+ fs19.renameSync(tmp, BRAND_FILE);
7688
7697
  const cache = { inputHash, generatedAt: Date.now() };
7689
- fs20.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
7698
+ fs19.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
7690
7699
  }
7691
7700
  function readCache() {
7692
7701
  try {
7693
- const raw = fs20.readFileSync(CACHE_FILE, "utf-8");
7702
+ const raw = fs19.readFileSync(CACHE_FILE, "utf-8");
7694
7703
  const parsed = JSON.parse(raw);
7695
7704
  if (parsed && typeof parsed.inputHash === "string" && typeof parsed.generatedAt === "number") {
7696
7705
  return parsed;
@@ -8388,7 +8397,7 @@ var init_agent = __esm({
8388
8397
  });
8389
8398
 
8390
8399
  // src/prompt/static/projectContext.ts
8391
- import fs21 from "fs";
8400
+ import fs20 from "fs";
8392
8401
  import path11 from "path";
8393
8402
  function loadProjectRoot() {
8394
8403
  return `
@@ -8399,7 +8408,7 @@ File paths are relative to this directory. Every tool operates here and bash com
8399
8408
  }
8400
8409
  function loadProjectManifest() {
8401
8410
  try {
8402
- const manifest = fs21.readFileSync("mindstudio.json", "utf-8");
8411
+ const manifest = fs20.readFileSync("mindstudio.json", "utf-8");
8403
8412
  return `
8404
8413
  ## Project Manifest (mindstudio.json)
8405
8414
  \`\`\`json
@@ -8440,7 +8449,7 @@ ${entries.join("\n")}`;
8440
8449
  function walkMdFiles3(dir) {
8441
8450
  const results = [];
8442
8451
  try {
8443
- const entries = fs21.readdirSync(dir, { withFileTypes: true });
8452
+ const entries = fs20.readdirSync(dir, { withFileTypes: true });
8444
8453
  for (const entry of entries) {
8445
8454
  const full = path11.join(dir, entry.name);
8446
8455
  if (entry.isDirectory()) {
@@ -8455,7 +8464,7 @@ function walkMdFiles3(dir) {
8455
8464
  }
8456
8465
  function parseFrontmatter3(filePath) {
8457
8466
  try {
8458
- const content = fs21.readFileSync(filePath, "utf-8");
8467
+ const content = fs20.readFileSync(filePath, "utf-8");
8459
8468
  const match = content.match(/^---\n([\s\S]*?)\n---/);
8460
8469
  if (!match) {
8461
8470
  return { name: "", description: "", type: "" };
@@ -8471,7 +8480,7 @@ function parseFrontmatter3(filePath) {
8471
8480
  }
8472
8481
  function loadPlanStatus(onboardingState) {
8473
8482
  try {
8474
- const content = fs21.readFileSync(".remy-plan.md", "utf-8");
8483
+ const content = fs20.readFileSync(".remy-plan.md", "utf-8");
8475
8484
  const match = content.match(/^---\n([\s\S]*?)\n---/);
8476
8485
  const status = match?.[1]?.match(/^status:\s*(.+)$/m)?.[1]?.trim();
8477
8486
  if (status === "pending" && onboardingState === "intake") {
@@ -8499,7 +8508,7 @@ The user has approved your implementation plan in .remy-plan.md. You may referen
8499
8508
  }
8500
8509
  function loadProjectFileListing() {
8501
8510
  try {
8502
- const entries = fs21.readdirSync(".", { withFileTypes: true });
8511
+ const entries = fs20.readdirSync(".", { withFileTypes: true });
8503
8512
  const listing = entries.filter((e) => e.name !== ".git" && e.name !== "node_modules").sort((a, b) => {
8504
8513
  if (a.isDirectory() && !b.isDirectory()) {
8505
8514
  return -1;
@@ -8682,12 +8691,12 @@ var init_prompt4 = __esm({
8682
8691
  });
8683
8692
 
8684
8693
  // src/config.ts
8685
- import fs22 from "fs";
8694
+ import fs21 from "fs";
8686
8695
  import path12 from "path";
8687
8696
  import os from "os";
8688
8697
  function loadConfigFile() {
8689
8698
  try {
8690
- const raw = fs22.readFileSync(CONFIG_PATH, "utf-8");
8699
+ const raw = fs21.readFileSync(CONFIG_PATH, "utf-8");
8691
8700
  log13.debug("Loaded config file", { path: CONFIG_PATH });
8692
8701
  return JSON.parse(raw);
8693
8702
  } catch (err) {
@@ -10008,7 +10017,7 @@ var init_headless = __esm({
10008
10017
  // src/index.tsx
10009
10018
  import { render } from "ink";
10010
10019
  import os2 from "os";
10011
- import fs23 from "fs";
10020
+ import fs22 from "fs";
10012
10021
  import path13 from "path";
10013
10022
 
10014
10023
  // src/tui/App.tsx
@@ -10330,7 +10339,7 @@ for (let i = 0; i < args.length; i++) {
10330
10339
  var startupLog = createLogger("startup");
10331
10340
  function printDebugInfo(config) {
10332
10341
  const pkg = JSON.parse(
10333
- fs23.readFileSync(
10342
+ fs22.readFileSync(
10334
10343
  path13.join(import.meta.dirname, "..", "package.json"),
10335
10344
  "utf-8"
10336
10345
  )