@mindstudio-ai/remy 0.1.282 → 0.1.283

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
@@ -2709,8 +2709,8 @@ function formatSize(bytes) {
2709
2709
  }
2710
2710
  async function formatFile(dirPath, name, indent) {
2711
2711
  try {
2712
- const stat2 = await fs16.stat(path8.join(dirPath, name));
2713
- return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat2.size)}`;
2712
+ const stat3 = await fs16.stat(path8.join(dirPath, name));
2713
+ return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat3.size)}`;
2714
2714
  } catch {
2715
2715
  return `${indent}${name}`;
2716
2716
  }
@@ -5570,20 +5570,24 @@ __export(createWireframe_exports, {
5570
5570
  definition: () => definition10,
5571
5571
  execute: () => execute10
5572
5572
  });
5573
- import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
5573
+ import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
5574
5574
  import { join as join2 } from "path";
5575
5575
  var log9 = createLogger("createWireframe");
5576
5576
  var WIREFRAMES_DIR = "src/.wireframes";
5577
5577
  var UPLOAD_TIMEOUT_MS2 = 3e4;
5578
5578
  var definition10 = {
5579
5579
  name: "createWireframe",
5580
- description: "Create a wireframe from self-contained HTML+CSS. Returns a markdown reference line \u2014 include that exact line in your response wherever the wireframe belongs, with your notes in the surrounding prose. To revise a wireframe, create a new one (read the old file first if you are iterating on it).",
5580
+ description: "Create (or revise) a wireframe from self-contained HTML+CSS. The wireframe is saved to src/.wireframes/{slug}.html \u2014 reference it in your response and in specs as ![name](src/.wireframes/{slug}.html), with your notes in the surrounding prose. Calling again with the same slug overwrites the wireframe in place, so a revision keeps its path and existing references stay current.",
5581
5581
  inputSchema: {
5582
5582
  type: "object",
5583
5583
  properties: {
5584
5584
  name: {
5585
5585
  type: "string",
5586
- description: 'Short display name, e.g. "Feed Post Card". Becomes the caption and the filename slug.'
5586
+ description: 'Short display name, e.g. "Feed Post Card". Becomes the caption.'
5587
+ },
5588
+ slug: {
5589
+ type: "string",
5590
+ description: 'Filename stem, lowercase kebab-case (e.g. "feed-post-card"). The wireframe lives at src/.wireframes/{slug}.html. Re-use a slug to revise that wireframe in place.'
5587
5591
  },
5588
5592
  description: {
5589
5593
  type: "string",
@@ -5594,20 +5598,24 @@ var definition10 = {
5594
5598
  description: "The complete HTML document (<html>\u2026</html>), self-contained vanilla HTML/CSS/JS. No frontmatter \u2014 it is added for you."
5595
5599
  }
5596
5600
  },
5597
- required: ["name", "description", "html"]
5601
+ required: ["name", "slug", "description", "html"]
5598
5602
  }
5599
5603
  };
5600
- function slugify(name) {
5601
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "wireframe";
5602
- }
5604
+ var SLUG_RE = /^[a-z0-9][a-z0-9-]{0,79}$/;
5603
5605
  function singleLine(value) {
5604
5606
  return value.replace(/\s+/g, " ").trim();
5605
5607
  }
5606
- function validate(name, html) {
5608
+ function validate(name, slug, html) {
5607
5609
  const warnings = [];
5608
5610
  if (!name.trim()) {
5609
5611
  return { error: "Error: name is required.", warnings };
5610
5612
  }
5613
+ if (!SLUG_RE.test(slug)) {
5614
+ return {
5615
+ error: 'Error: slug must be lowercase kebab-case ([a-z0-9-], starting with a letter or digit, \u2264 80 chars), e.g. "feed-post-card".',
5616
+ warnings
5617
+ };
5618
+ }
5611
5619
  if (!html.trim()) {
5612
5620
  return { error: "Error: html is required.", warnings };
5613
5621
  }
@@ -5666,13 +5674,13 @@ async function execute10(input, onLog, context) {
5666
5674
  return "Error: createWireframe requires execution context";
5667
5675
  }
5668
5676
  const name = String(input.name ?? "");
5677
+ const slug = String(input.slug ?? "");
5669
5678
  const description = String(input.description ?? "");
5670
5679
  const html = String(input.html ?? "");
5671
- const { error, warnings } = validate(name, html);
5680
+ const { error, warnings } = validate(name, slug, html);
5672
5681
  if (error) {
5673
5682
  return error;
5674
5683
  }
5675
- const slug = `${slugify(name)}-${Math.random().toString(36).slice(2, 8)}`;
5676
5684
  const relPath = `${WIREFRAMES_DIR}/${slug}.html`;
5677
5685
  const content = [
5678
5686
  "---",
@@ -5683,6 +5691,10 @@ async function execute10(input, onLog, context) {
5683
5691
  ""
5684
5692
  ].join("\n");
5685
5693
  await mkdir2(join2(PROJECT_ROOT, WIREFRAMES_DIR), { recursive: true });
5694
+ const existed = await stat2(join2(PROJECT_ROOT, relPath)).then(
5695
+ () => true,
5696
+ () => false
5697
+ );
5686
5698
  await writeFile2(join2(PROJECT_ROOT, relPath), content, "utf8");
5687
5699
  onLog?.(`Wrote ${relPath}, mirroring for preview...`);
5688
5700
  const mirror = await uploadMirror(context, slug, content);
@@ -5690,7 +5702,7 @@ async function execute10(input, onLog, context) {
5690
5702
  log9.warn("Wireframe mirror upload failed", { slug, note: mirror.note });
5691
5703
  }
5692
5704
  const lines = [
5693
- `Created wireframe "${singleLine(name)}" at ${relPath}.`,
5705
+ `${existed ? "Revised" : "Created"} wireframe "${singleLine(name)}" at ${relPath}.${existed ? " Existing references to this path now show the new version." : ""}`,
5694
5706
  `Reference it in your response and in specs with exactly: ![${singleLine(name)}](${relPath})`
5695
5707
  ];
5696
5708
  if (!mirror.ok) {
package/dist/index.js CHANGED
@@ -3816,8 +3816,8 @@ function formatSize(bytes) {
3816
3816
  }
3817
3817
  async function formatFile(dirPath, name, indent) {
3818
3818
  try {
3819
- const stat2 = await fs15.stat(path8.join(dirPath, name));
3820
- return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat2.size)}`;
3819
+ const stat3 = await fs15.stat(path8.join(dirPath, name));
3820
+ return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat3.size)}`;
3821
3821
  } catch {
3822
3822
  return `${indent}${name}`;
3823
3823
  }
@@ -6752,19 +6752,22 @@ __export(createWireframe_exports, {
6752
6752
  definition: () => definition10,
6753
6753
  execute: () => execute10
6754
6754
  });
6755
- import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
6755
+ import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
6756
6756
  import { join as join2 } from "path";
6757
- function slugify(name) {
6758
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "wireframe";
6759
- }
6760
6757
  function singleLine(value) {
6761
6758
  return value.replace(/\s+/g, " ").trim();
6762
6759
  }
6763
- function validate(name, html) {
6760
+ function validate(name, slug, html) {
6764
6761
  const warnings = [];
6765
6762
  if (!name.trim()) {
6766
6763
  return { error: "Error: name is required.", warnings };
6767
6764
  }
6765
+ if (!SLUG_RE.test(slug)) {
6766
+ return {
6767
+ error: 'Error: slug must be lowercase kebab-case ([a-z0-9-], starting with a letter or digit, \u2264 80 chars), e.g. "feed-post-card".',
6768
+ warnings
6769
+ };
6770
+ }
6768
6771
  if (!html.trim()) {
6769
6772
  return { error: "Error: html is required.", warnings };
6770
6773
  }
@@ -6823,13 +6826,13 @@ async function execute10(input, onLog, context) {
6823
6826
  return "Error: createWireframe requires execution context";
6824
6827
  }
6825
6828
  const name = String(input.name ?? "");
6829
+ const slug = String(input.slug ?? "");
6826
6830
  const description = String(input.description ?? "");
6827
6831
  const html = String(input.html ?? "");
6828
- const { error, warnings } = validate(name, html);
6832
+ const { error, warnings } = validate(name, slug, html);
6829
6833
  if (error) {
6830
6834
  return error;
6831
6835
  }
6832
- const slug = `${slugify(name)}-${Math.random().toString(36).slice(2, 8)}`;
6833
6836
  const relPath = `${WIREFRAMES_DIR}/${slug}.html`;
6834
6837
  const content = [
6835
6838
  "---",
@@ -6840,6 +6843,10 @@ async function execute10(input, onLog, context) {
6840
6843
  ""
6841
6844
  ].join("\n");
6842
6845
  await mkdir2(join2(PROJECT_ROOT, WIREFRAMES_DIR), { recursive: true });
6846
+ const existed = await stat2(join2(PROJECT_ROOT, relPath)).then(
6847
+ () => true,
6848
+ () => false
6849
+ );
6843
6850
  await writeFile2(join2(PROJECT_ROOT, relPath), content, "utf8");
6844
6851
  onLog?.(`Wrote ${relPath}, mirroring for preview...`);
6845
6852
  const mirror = await uploadMirror(context, slug, content);
@@ -6847,7 +6854,7 @@ async function execute10(input, onLog, context) {
6847
6854
  log10.warn("Wireframe mirror upload failed", { slug, note: mirror.note });
6848
6855
  }
6849
6856
  const lines = [
6850
- `Created wireframe "${singleLine(name)}" at ${relPath}.`,
6857
+ `${existed ? "Revised" : "Created"} wireframe "${singleLine(name)}" at ${relPath}.${existed ? " Existing references to this path now show the new version." : ""}`,
6851
6858
  `Reference it in your response and in specs with exactly: ![${singleLine(name)}](${relPath})`
6852
6859
  ];
6853
6860
  if (!mirror.ok) {
@@ -6860,7 +6867,7 @@ async function execute10(input, onLog, context) {
6860
6867
  }
6861
6868
  return lines.join("\n");
6862
6869
  }
6863
- var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition10;
6870
+ var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition10, SLUG_RE;
6864
6871
  var init_createWireframe = __esm({
6865
6872
  "src/subagents/designExpert/tools/createWireframe.ts"() {
6866
6873
  "use strict";
@@ -6871,13 +6878,17 @@ var init_createWireframe = __esm({
6871
6878
  UPLOAD_TIMEOUT_MS2 = 3e4;
6872
6879
  definition10 = {
6873
6880
  name: "createWireframe",
6874
- description: "Create a wireframe from self-contained HTML+CSS. Returns a markdown reference line \u2014 include that exact line in your response wherever the wireframe belongs, with your notes in the surrounding prose. To revise a wireframe, create a new one (read the old file first if you are iterating on it).",
6881
+ description: "Create (or revise) a wireframe from self-contained HTML+CSS. The wireframe is saved to src/.wireframes/{slug}.html \u2014 reference it in your response and in specs as ![name](src/.wireframes/{slug}.html), with your notes in the surrounding prose. Calling again with the same slug overwrites the wireframe in place, so a revision keeps its path and existing references stay current.",
6875
6882
  inputSchema: {
6876
6883
  type: "object",
6877
6884
  properties: {
6878
6885
  name: {
6879
6886
  type: "string",
6880
- description: 'Short display name, e.g. "Feed Post Card". Becomes the caption and the filename slug.'
6887
+ description: 'Short display name, e.g. "Feed Post Card". Becomes the caption.'
6888
+ },
6889
+ slug: {
6890
+ type: "string",
6891
+ description: 'Filename stem, lowercase kebab-case (e.g. "feed-post-card"). The wireframe lives at src/.wireframes/{slug}.html. Re-use a slug to revise that wireframe in place.'
6881
6892
  },
6882
6893
  description: {
6883
6894
  type: "string",
@@ -6888,9 +6899,10 @@ var init_createWireframe = __esm({
6888
6899
  description: "The complete HTML document (<html>\u2026</html>), self-contained vanilla HTML/CSS/JS. No frontmatter \u2014 it is added for you."
6889
6900
  }
6890
6901
  },
6891
- required: ["name", "description", "html"]
6902
+ required: ["name", "slug", "description", "html"]
6892
6903
  }
6893
6904
  };
6905
+ SLUG_RE = /^[a-z0-9][a-z0-9-]{0,79}$/;
6894
6906
  }
6895
6907
  });
6896
6908
 
@@ -12,7 +12,7 @@ Your designer. Consult for any visual decision — choosing a color, picking fon
12
12
 
13
13
  The design expert cannot see your conversation with the user, so include relevant context and requirements in your task. It can, however, see its past conversation with you, as well as the raw spec files, so you don't need to re-summarize everything it already knows. Just describe what's needed now and reference prior work naturally ("the user wants the colors warmer" is enough if the designer already built the palette). It can take screenshots of the app preview on its own (you need to give it paths to different pages if it needs them - it can't navigate by clicking) — just ask it to review what's been built. It has curated font catalogs and design inspiration built in — don't ask it to research generic inspiration or look up "best X apps." Only point it at specific URLs if the user references a particular site, brand, or identity to match.
14
14
 
15
- The designer will return concrete resources: hex values, font names with CSS URLs, image URLs, layout descriptions, as well as specific techniques, CSS properties, animation timings, code snippets, and other values. Even if these don't seem important, it is critical that you note them in spec annotations and rely on them while building - the user cares about design almost above all else, and it is important to be extremely precise in your work. The designer can also return code-fenced typography and color schemes (self-contained HTML and CSS) - write these directly into specs for future reference. Wireframes arrive as file references like `![Feed Post Card](src/.wireframes/feed-post-card-x7f2.html)`: copy the reference line into specs verbatim (it renders as a visual preview in chat and in the spec), and read the file at that path while building to get the exact markup and CSS the designer specified.
15
+ The designer will return concrete resources: hex values, font names with CSS URLs, image URLs, layout descriptions, as well as specific techniques, CSS properties, animation timings, code snippets, and other values. Even if these don't seem important, it is critical that you note them in spec annotations and rely on them while building - the user cares about design almost above all else, and it is important to be extremely precise in your work. The designer can also return code-fenced typography and color schemes (self-contained HTML and CSS) - write these directly into specs for future reference. Wireframes arrive as file references like `![Feed Post Card](src/.wireframes/feed-post-card.html)`: copy the reference line into specs verbatim (it renders as a visual preview in chat and in the spec), and read the file at that path while building to get the exact markup and CSS the designer specified. When the designer revises a wireframe it overwrites the same path, so existing references stay current.
16
16
 
17
17
  When delegating, describe the design problem — where the asset will be used, what it needs to communicate, what the brand feels like. Do not specify technical details like image formats, pixel dimensions, generation techniques, or workarounds. The design expert makes those decisions.
18
18
 
@@ -16,7 +16,7 @@ Think about the ways you can truly elevate the design. Use image generation to c
16
16
  - After you've taken a screenshot, use analyze image to ask different questions about it - don't re-screenshot the page unnecessarily.
17
17
  - Match the image engine to the job: `renderImage` (a browser rendering HTML you author) for token-exact graphics — share cards, wordmarks, flat icon tiles; `generateImages` (an image model) for organic, photographic, and illustrated work. Don't ask the image model to hit exact hex codes or typography, and don't hand-write SVG path data — compose HTML/CSS and render it.
18
18
  - When you write user-facing copy (headlines, captions, labels, body text), hand it to `polishCopy` before finalizing. It tightens prose so it reads like a person wrote it rather than a machine, without changing what it says. Cheap and fast — use it on any copy that will ship.
19
- - Deliver wireframes with `createWireframe`. Include the returned `![name](src/.wireframes/….html)` line in your response where the wireframe belongs — it renders as a live preview, and the developer reads the file for the exact markup.
19
+ - Deliver wireframes with `createWireframe`. Include the `![name](src/.wireframes/{slug}.html)` line in your response where the wireframe belongs — it renders as a live preview, and the developer reads the file for the exact markup. Same slug = revise in place; new slug = new wireframe.
20
20
 
21
21
  ## Voice
22
22
  - No emoji, no filler.
@@ -25,7 +25,7 @@ Some surfaces are deep enough to carry their own craft reference in <available_s
25
25
 
26
26
  ### Wireframes
27
27
 
28
- When you need to show a layout, component, interaction, or animation, create a wireframe with the `createWireframe` tool: pass a `name`, a one-line `description`, and self-contained HTML+CSS. The tool saves the wireframe as a file under `src/.wireframes/` and returns a markdown reference line like `![Feed Post Card](src/.wireframes/feed-post-card-x7f2.html)` — include that exact line in your response wherever the wireframe belongs, with your notes in the surrounding prose. The reference line renders as a live visual preview, and the developer reads the file itself for the exact markup and CSS.
28
+ When you need to show a layout, component, interaction, or animation, create a wireframe with the `createWireframe` tool: pass a `name`, a kebab-case `slug`, a one-line `description`, and self-contained HTML+CSS. The wireframe is saved to `src/.wireframes/{slug}.html`, and you reference it as `![Feed Post Card](src/.wireframes/feed-post-card.html)` — include that line in your response wherever the wireframe belongs, with your notes in the surrounding prose. The reference line renders as a live visual preview, and the developer reads the file itself for the exact markup and CSS. A reference only renders once its wireframe exists, so make the `createWireframe` call for every reference you write — in the same response is fine.
29
29
 
30
30
  Never use ASCII art, box-drawing characters, or code-block diagrams to describe layouts. Always use a wireframe instead, even if it's just grey rectangles with labels. A 20-line wireframe with placeholder boxes communicates proportions, spacing, and hierarchy better than any text diagram. For abstract layouts, use skeleton-style placeholders (grey boxes, rounded rects) rather than mocking up real content.
31
31
 
@@ -35,9 +35,9 @@ Wireframes render in a small transparent iframe. Set a background color and shad
35
35
 
36
36
  Wireframes are vanilla HTML/CSS/JS (no React). For animations beyond CSS, use GSAP via CDN: `<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>`
37
37
 
38
- Wireframe files are immutable — to revise one, create a new wireframe. If you're iterating on an earlier one, read its file first and riff from there.
38
+ To revise a wireframe, call `createWireframe` again with the same slug the file is overwritten in place and every existing reference to that path (in chat and in specs) shows the new version. Read the current file first if you're iterating on it. Use a new slug when it's genuinely a different wireframe, not a revision.
39
39
 
40
- Quick skeleton wireframe (grey boxes, just showing layout and hierarchy) — `createWireframe` with name "Content Card Layout", description "Card with image area, title, metadata row, rating, and actions. Skeleton placeholders showing proportions and hierarchy.", and this html:
40
+ Quick skeleton wireframe (grey boxes, just showing layout and hierarchy) — `createWireframe` with name "Content Card Layout", slug "content-card-layout", description "Card with image area, title, metadata row, rating, and actions. Skeleton placeholders showing proportions and hierarchy.", and this html:
41
41
 
42
42
  ```html
43
43
  <html lang="en"><head>
@@ -72,7 +72,7 @@ Quick skeleton wireframe (grey boxes, just showing layout and hierarchy) — `cr
72
72
  </html>
73
73
  ```
74
74
 
75
- Detailed component wireframe (showing specific design decisions) — `createWireframe` with name "Feed Post Card", description "Photo post card with header, image frame, action row (like/comment/share/bookmark), like count, and caption. Shows spacing, typography hierarchy, and icon placement.", and this html:
75
+ Detailed component wireframe (showing specific design decisions) — `createWireframe` with name "Feed Post Card", slug "feed-post-card", description "Photo post card with header, image frame, action row (like/comment/share/bookmark), like count, and caption. Shows spacing, typography hierarchy, and icon placement.", and this html:
76
76
 
77
77
  ```html
78
78
  <html lang="en"><head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindstudio-ai/remy",
3
- "version": "0.1.282",
3
+ "version": "0.1.283",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",