@mindstudio-ai/remy 0.1.74 → 0.1.76

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
@@ -1706,9 +1706,9 @@ var setProjectMetadataTool = {
1706
1706
  import fs9 from "fs/promises";
1707
1707
  var DEFAULT_MAX_LINES2 = 500;
1708
1708
  function isBinary(buffer) {
1709
- const sample4 = buffer.subarray(0, 8192);
1710
- for (let i = 0; i < sample4.length; i++) {
1711
- if (sample4[i] === 0) {
1709
+ const sample = buffer.subarray(0, 8192);
1710
+ for (let i = 0; i < sample.length; i++) {
1711
+ if (sample[i] === 0) {
1712
1712
  return true;
1713
1713
  }
1714
1714
  }
@@ -2328,13 +2328,17 @@ var runScenarioTool = {
2328
2328
  clearable: true,
2329
2329
  definition: {
2330
2330
  name: "runScenario",
2331
- description: "Run a scenario to seed the dev database with test data. Truncates all tables first, then executes the seed function and impersonates the scenario roles. Blocks until complete. Scenario IDs are defined in mindstudio.json. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for details. Return synchronously - no need to sleep before checking results.",
2331
+ description: "Run a scenario to seed the dev database with test data. By default truncates all tables first, then executes the seed function and impersonates the scenario roles. Use skipTruncate to run the seed function against existing data without resetting. 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.",
2332
2332
  inputSchema: {
2333
2333
  type: "object",
2334
2334
  properties: {
2335
2335
  scenarioId: {
2336
2336
  type: "string",
2337
2337
  description: "The scenario ID from mindstudio.json."
2338
+ },
2339
+ skipTruncate: {
2340
+ type: "boolean",
2341
+ description: "When true, skip the database reset step and run the seed function against existing data. Defaults to false (clean-slate)."
2338
2342
  }
2339
2343
  },
2340
2344
  required: ["scenarioId"]
@@ -2371,6 +2375,28 @@ var runMethodTool = {
2371
2375
  }
2372
2376
  };
2373
2377
 
2378
+ // src/tools/code/queryDatabase.ts
2379
+ var queryDatabaseTool = {
2380
+ clearable: true,
2381
+ definition: {
2382
+ name: "queryDatabase",
2383
+ description: "Execute a raw SQL query against the dev database and return the results. Use for inspecting data and debugging issues.",
2384
+ inputSchema: {
2385
+ type: "object",
2386
+ properties: {
2387
+ sql: {
2388
+ type: "string",
2389
+ description: "The SQL query to execute."
2390
+ }
2391
+ },
2392
+ required: ["sql"]
2393
+ }
2394
+ },
2395
+ async execute() {
2396
+ return "ok";
2397
+ }
2398
+ };
2399
+
2374
2400
  // src/subagents/common/analyzeImage.ts
2375
2401
  var VISION_MODEL = "gemini-3-flash";
2376
2402
  var VISION_MODEL_OVERRIDE = JSON.stringify({
@@ -3739,7 +3765,7 @@ async function executeDesignExpertTool(name, input, context, toolCallId, onLog)
3739
3765
  }
3740
3766
 
3741
3767
  // src/subagents/designExpert/prompt.ts
3742
- import fs15 from "fs";
3768
+ import fs16 from "fs";
3743
3769
 
3744
3770
  // src/subagents/common/context.ts
3745
3771
  import fs14 from "fs";
@@ -3841,25 +3867,74 @@ The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (Op
3841
3867
  </platform_brief>`;
3842
3868
  }
3843
3869
 
3870
+ // src/subagents/designExpert/data/sampleCache.ts
3871
+ import fs15 from "fs";
3872
+ var SAMPLE_FILE = ".remy-design-sample.json";
3873
+ var cached = null;
3874
+ function generateIndices(poolSize, sampleSize) {
3875
+ const n = Math.min(sampleSize, poolSize);
3876
+ const indices = Array.from({ length: poolSize }, (_, i) => i);
3877
+ for (let i = indices.length - 1; i > 0; i--) {
3878
+ const j = Math.floor(Math.random() * (i + 1));
3879
+ [indices[i], indices[j]] = [indices[j], indices[i]];
3880
+ }
3881
+ return indices.slice(0, n);
3882
+ }
3883
+ function load() {
3884
+ try {
3885
+ return JSON.parse(fs15.readFileSync(SAMPLE_FILE, "utf-8"));
3886
+ } catch {
3887
+ return null;
3888
+ }
3889
+ }
3890
+ function save(indices) {
3891
+ try {
3892
+ fs15.writeFileSync(SAMPLE_FILE, JSON.stringify(indices));
3893
+ } catch {
3894
+ }
3895
+ }
3896
+ function getSampleIndices(pools, sizes) {
3897
+ if (cached) {
3898
+ return cached;
3899
+ }
3900
+ const loaded = load();
3901
+ if (loaded) {
3902
+ let dirty = false;
3903
+ for (const key of ["uiInspiration", "designReferences", "fonts"]) {
3904
+ const before = loaded[key].length;
3905
+ loaded[key] = loaded[key].filter((i) => i < pools[key]);
3906
+ if (loaded[key].length < before) {
3907
+ dirty = true;
3908
+ }
3909
+ }
3910
+ if (dirty) {
3911
+ save(loaded);
3912
+ }
3913
+ cached = loaded;
3914
+ return cached;
3915
+ }
3916
+ cached = {
3917
+ uiInspiration: generateIndices(pools.uiInspiration, sizes.uiInspiration),
3918
+ designReferences: generateIndices(
3919
+ pools.designReferences,
3920
+ sizes.designReferences
3921
+ ),
3922
+ fonts: generateIndices(pools.fonts, sizes.fonts)
3923
+ };
3924
+ save(cached);
3925
+ return cached;
3926
+ }
3927
+ function pickByIndices(arr, indices) {
3928
+ return indices.filter((i) => i < arr.length).map((i) => arr[i]);
3929
+ }
3930
+
3844
3931
  // src/subagents/designExpert/data/getFontLibrarySample.ts
3845
3932
  var fontData = readJsonAsset(
3846
- { cssUrlPattern: "", fonts: [], pairings: [] },
3933
+ { cssUrlPattern: "", fonts: [] },
3847
3934
  "subagents/designExpert/data/sources/fonts.json"
3848
3935
  );
3849
- function sample(arr, n) {
3850
- if (arr.length <= n) {
3851
- return [...arr];
3852
- }
3853
- const copy = [...arr];
3854
- for (let i = copy.length - 1; i > 0; i--) {
3855
- const j = Math.floor(Math.random() * (i + 1));
3856
- [copy[i], copy[j]] = [copy[j], copy[i]];
3857
- }
3858
- return copy.slice(0, n);
3859
- }
3860
- function getFontLibrarySample() {
3861
- const fonts = sample(fontData.fonts, 60);
3862
- const pairings = sample(fontData.pairings, 30);
3936
+ function getFontLibrarySample(fontIndices) {
3937
+ const fonts = pickByIndices(fontData.fonts, fontIndices);
3863
3938
  if (!fonts.length) {
3864
3939
  return "";
3865
3940
  }
@@ -3875,16 +3950,11 @@ function getFontLibrarySample() {
3875
3950
  const desc = f.description ? ` ${f.description}` : "";
3876
3951
  return `- **${f.name}** \u2014 ${f.category}. Weights: ${f.weights.join(", ")}.${f.variable ? " Variable." : ""}${f.italics ? " Has italics." : ""}${cssInfo}${desc}`;
3877
3952
  }).join("\n");
3878
- const pairingList = pairings.map(
3879
- (p) => `- **${p.heading.font}** (${p.heading.weight}) heading + **${p.body.font}** (${p.body.weight}) body`
3880
- ).join("\n");
3881
3953
  return `
3882
3954
  ## Font Library
3883
3955
 
3884
3956
  This is your personal library of fonts you love. Use it as a starting point when thinking about anything related to typography.
3885
3957
 
3886
- ### Fonts
3887
-
3888
3958
  ${fontList}`.trim();
3889
3959
  }
3890
3960
 
@@ -3893,19 +3963,8 @@ var inspirationImages = readJsonAsset(
3893
3963
  { images: [] },
3894
3964
  "subagents/designExpert/data/sources/inspiration.json"
3895
3965
  ).images;
3896
- function sample2(arr, n) {
3897
- if (arr.length <= n) {
3898
- return [...arr];
3899
- }
3900
- const copy = [...arr];
3901
- for (let i = copy.length - 1; i > 0; i--) {
3902
- const j = Math.floor(Math.random() * (i + 1));
3903
- [copy[i], copy[j]] = [copy[j], copy[i]];
3904
- }
3905
- return copy.slice(0, n);
3906
- }
3907
- function getDesignReferencesSample() {
3908
- const images = sample2(inspirationImages, 25);
3966
+ function getDesignReferencesSample(indices) {
3967
+ const images = pickByIndices(inspirationImages, indices);
3909
3968
  if (!images.length) {
3910
3969
  return "";
3911
3970
  }
@@ -3924,19 +3983,8 @@ var uiScreens = readJsonAsset(
3924
3983
  { screens: [] },
3925
3984
  "subagents/designExpert/data/sources/ui_inspiration_compiled.json"
3926
3985
  ).screens;
3927
- function sample3(arr, n) {
3928
- if (arr.length <= n) {
3929
- return [...arr];
3930
- }
3931
- const copy = [...arr];
3932
- for (let i = copy.length - 1; i > 0; i--) {
3933
- const j = Math.floor(Math.random() * (i + 1));
3934
- [copy[i], copy[j]] = [copy[j], copy[i]];
3935
- }
3936
- return copy.slice(0, n);
3937
- }
3938
- function getUiInspirationSample() {
3939
- const screens = sample3(uiScreens, 25);
3986
+ function getUiInspirationSample(indices) {
3987
+ const screens = pickByIndices(uiScreens, indices);
3940
3988
  if (!screens.length) {
3941
3989
  return "";
3942
3990
  }
@@ -3963,10 +4011,28 @@ var PROMPT_TEMPLATE = readAsset(SUBAGENT, "prompt.md").replace(/\{\{([^}]+)\}\}/
3963
4011
  }).replace(/\n{3,}/g, "\n\n");
3964
4012
  function getDesignExpertPrompt() {
3965
4013
  const specContext = loadSpecContext();
4014
+ const indices = getSampleIndices(
4015
+ {
4016
+ uiInspiration: uiScreens.length,
4017
+ designReferences: inspirationImages.length,
4018
+ fonts: fontData.fonts.length
4019
+ },
4020
+ {
4021
+ uiInspiration: 50,
4022
+ designReferences: 50,
4023
+ fonts: 50
4024
+ }
4025
+ );
3966
4026
  let prompt = PROMPT_TEMPLATE.replace(
3967
4027
  "{{font_library}}",
3968
- getFontLibrarySample()
3969
- ).replace("{{visual_design_references}}", getDesignReferencesSample()).replace("{{ui_case_studies}}", getUiInspirationSample());
4028
+ getFontLibrarySample(indices.fonts)
4029
+ ).replace(
4030
+ "{{visual_design_references}}",
4031
+ getDesignReferencesSample(indices.designReferences)
4032
+ ).replace(
4033
+ "{{ui_case_studies}}",
4034
+ getUiInspirationSample(indices.uiInspiration)
4035
+ );
3970
4036
  prompt += "\n\n<!-- cache_breakpoint -->";
3971
4037
  if (specContext) {
3972
4038
  prompt += `
@@ -3974,7 +4040,7 @@ function getDesignExpertPrompt() {
3974
4040
  ${specContext}`;
3975
4041
  }
3976
4042
  try {
3977
- fs15.writeFileSync(`.design-prompt.md`, prompt);
4043
+ fs16.writeFileSync(`.design-prompt.md`, prompt);
3978
4044
  } catch {
3979
4045
  }
3980
4046
  return prompt;
@@ -4183,7 +4249,7 @@ var VISION_TOOLS = [
4183
4249
  ];
4184
4250
 
4185
4251
  // src/subagents/productVision/executor.ts
4186
- import fs16 from "fs";
4252
+ import fs17 from "fs";
4187
4253
  import path8 from "path";
4188
4254
  var ROADMAP_DIR = "src/roadmap";
4189
4255
  function formatRequires(requires) {
@@ -4202,8 +4268,8 @@ async function executeVisionTool(name, input) {
4202
4268
  } = input;
4203
4269
  const filePath = path8.join(ROADMAP_DIR, `${slug}.md`);
4204
4270
  try {
4205
- fs16.mkdirSync(ROADMAP_DIR, { recursive: true });
4206
- const oldContent = fs16.existsSync(filePath) ? fs16.readFileSync(filePath, "utf-8") : "";
4271
+ fs17.mkdirSync(ROADMAP_DIR, { recursive: true });
4272
+ const oldContent = fs17.existsSync(filePath) ? fs17.readFileSync(filePath, "utf-8") : "";
4207
4273
  const content = `---
4208
4274
  name: ${itemName}
4209
4275
  type: roadmap
@@ -4215,7 +4281,7 @@ requires: ${formatRequires(requires)}
4215
4281
 
4216
4282
  ${body}
4217
4283
  `;
4218
- fs16.writeFileSync(filePath, content, "utf-8");
4284
+ fs17.writeFileSync(filePath, content, "utf-8");
4219
4285
  const lineCount = content.split("\n").length;
4220
4286
  const label = oldContent ? "Updated" : "Wrote";
4221
4287
  return `${label} ${filePath} (${lineCount} lines)
@@ -4228,10 +4294,10 @@ ${unifiedDiff(filePath, oldContent, content)}`;
4228
4294
  const { slug } = input;
4229
4295
  const filePath = path8.join(ROADMAP_DIR, `${slug}.md`);
4230
4296
  try {
4231
- if (!fs16.existsSync(filePath)) {
4297
+ if (!fs17.existsSync(filePath)) {
4232
4298
  return `Error: ${filePath} does not exist`;
4233
4299
  }
4234
- const oldContent = fs16.readFileSync(filePath, "utf-8");
4300
+ const oldContent = fs17.readFileSync(filePath, "utf-8");
4235
4301
  let content = oldContent;
4236
4302
  if (input.status) {
4237
4303
  content = content.replace(
@@ -4284,7 +4350,7 @@ ${input.appendHistory}
4284
4350
  `;
4285
4351
  }
4286
4352
  }
4287
- fs16.writeFileSync(filePath, content, "utf-8");
4353
+ fs17.writeFileSync(filePath, content, "utf-8");
4288
4354
  const lineCount = content.split("\n").length;
4289
4355
  return `Updated ${filePath} (${lineCount} lines)
4290
4356
  ${unifiedDiff(filePath, oldContent, content)}`;
@@ -4296,11 +4362,11 @@ ${unifiedDiff(filePath, oldContent, content)}`;
4296
4362
  const { slug } = input;
4297
4363
  const filePath = path8.join(ROADMAP_DIR, `${slug}.md`);
4298
4364
  try {
4299
- if (!fs16.existsSync(filePath)) {
4365
+ if (!fs17.existsSync(filePath)) {
4300
4366
  return `Error: ${filePath} does not exist`;
4301
4367
  }
4302
- const oldContent = fs16.readFileSync(filePath, "utf-8");
4303
- fs16.unlinkSync(filePath);
4368
+ const oldContent = fs17.readFileSync(filePath, "utf-8");
4369
+ fs17.unlinkSync(filePath);
4304
4370
  return `Deleted ${filePath}
4305
4371
  ${unifiedDiff(filePath, oldContent, "")}`;
4306
4372
  } catch (err) {
@@ -4595,6 +4661,7 @@ var ALL_TOOLS = [
4595
4661
  editsFinishedTool,
4596
4662
  runScenarioTool,
4597
4663
  runMethodTool,
4664
+ queryDatabaseTool,
4598
4665
  screenshotTool,
4599
4666
  browserAutomationTool,
4600
4667
  // LSP
@@ -4619,12 +4686,12 @@ function executeTool(name, input, context) {
4619
4686
  }
4620
4687
 
4621
4688
  // src/session.ts
4622
- import fs17 from "fs";
4689
+ import fs18 from "fs";
4623
4690
  var log7 = createLogger("session");
4624
4691
  var SESSION_FILE = ".remy-session.json";
4625
4692
  function loadSession(state) {
4626
4693
  try {
4627
- const raw = fs17.readFileSync(SESSION_FILE, "utf-8");
4694
+ const raw = fs18.readFileSync(SESSION_FILE, "utf-8");
4628
4695
  const data = JSON.parse(raw);
4629
4696
  if (Array.isArray(data.messages) && data.messages.length > 0) {
4630
4697
  state.messages = sanitizeMessages(data.messages);
@@ -4673,7 +4740,7 @@ function sanitizeMessages(messages) {
4673
4740
  }
4674
4741
  function saveSession(state) {
4675
4742
  try {
4676
- fs17.writeFileSync(
4743
+ fs18.writeFileSync(
4677
4744
  SESSION_FILE,
4678
4745
  JSON.stringify({ messages: state.messages }, null, 2),
4679
4746
  "utf-8"
@@ -4686,7 +4753,7 @@ function saveSession(state) {
4686
4753
  function clearSession(state) {
4687
4754
  state.messages = [];
4688
4755
  try {
4689
- fs17.unlinkSync(SESSION_FILE);
4756
+ fs18.unlinkSync(SESSION_FILE);
4690
4757
  } catch {
4691
4758
  }
4692
4759
  }