@mindstudio-ai/remy 0.1.281 → 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
@@ -281,8 +281,19 @@ async function* streamChat(params) {
281
281
  }
282
282
  var MAX_RETRIES = 5;
283
283
  var INITIAL_BACKOFF_MS = 1e3;
284
- function isRetryableError(error) {
285
- return /Network error/i.test(error) || /HTTP 5\d\d/i.test(error) || /Stream stalled/i.test(error) || /overloaded/i.test(error) || /terminated/i.test(error) || // Anthropic fetches url-source image blocks server-side on every call;
284
+ var RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
285
+ "api_error",
286
+ // Anthropic's 500-equivalent ("The server had an error…")
287
+ "overloaded_error"
288
+ // Anthropic's 529-equivalent
289
+ ]);
290
+ function isRetryableError(error, code) {
291
+ if (code && RETRYABLE_ERROR_CODES.has(code)) {
292
+ return true;
293
+ }
294
+ return /Network error/i.test(error) || /HTTP 5\d\d/i.test(error) || /Stream stalled/i.test(error) || /overloaded/i.test(error) || /terminated/i.test(error) || // The API's friendly mapping of a provider 500 — belt-and-suspenders for
295
+ // pods that don't send a machine-readable code.
296
+ /Internal API error/i.test(error) || // Anthropic fetches url-source image blocks server-side on every call;
286
297
  // a transient failure anywhere in that chain (S3 signing edge, resize
287
298
  // proxy, their fetcher) surfaces as this message. The images themselves
288
299
  // are fine — the same URLs typically succeed on the next attempt.
@@ -297,7 +308,7 @@ async function* streamChatWithRetry(params, options) {
297
308
  let retryableFailure = false;
298
309
  for await (const event of streamChat(params)) {
299
310
  if (event.type === "error") {
300
- if (isRetryableError(event.error) && attempt < MAX_RETRIES - 1) {
311
+ if (isRetryableError(event.error, event.code) && attempt < MAX_RETRIES - 1) {
301
312
  options?.onRetry?.(attempt, event.error);
302
313
  retryableFailure = true;
303
314
  break;
@@ -2698,8 +2709,8 @@ function formatSize(bytes) {
2698
2709
  }
2699
2710
  async function formatFile(dirPath, name, indent) {
2700
2711
  try {
2701
- const stat2 = await fs16.stat(path8.join(dirPath, name));
2702
- 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)}`;
2703
2714
  } catch {
2704
2715
  return `${indent}${name}`;
2705
2716
  }
@@ -5559,20 +5570,24 @@ __export(createWireframe_exports, {
5559
5570
  definition: () => definition10,
5560
5571
  execute: () => execute10
5561
5572
  });
5562
- import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
5573
+ import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
5563
5574
  import { join as join2 } from "path";
5564
5575
  var log9 = createLogger("createWireframe");
5565
5576
  var WIREFRAMES_DIR = "src/.wireframes";
5566
5577
  var UPLOAD_TIMEOUT_MS2 = 3e4;
5567
5578
  var definition10 = {
5568
5579
  name: "createWireframe",
5569
- 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.",
5570
5581
  inputSchema: {
5571
5582
  type: "object",
5572
5583
  properties: {
5573
5584
  name: {
5574
5585
  type: "string",
5575
- 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.'
5576
5591
  },
5577
5592
  description: {
5578
5593
  type: "string",
@@ -5583,20 +5598,24 @@ var definition10 = {
5583
5598
  description: "The complete HTML document (<html>\u2026</html>), self-contained vanilla HTML/CSS/JS. No frontmatter \u2014 it is added for you."
5584
5599
  }
5585
5600
  },
5586
- required: ["name", "description", "html"]
5601
+ required: ["name", "slug", "description", "html"]
5587
5602
  }
5588
5603
  };
5589
- function slugify(name) {
5590
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "wireframe";
5591
- }
5604
+ var SLUG_RE = /^[a-z0-9][a-z0-9-]{0,79}$/;
5592
5605
  function singleLine(value) {
5593
5606
  return value.replace(/\s+/g, " ").trim();
5594
5607
  }
5595
- function validate(name, html) {
5608
+ function validate(name, slug, html) {
5596
5609
  const warnings = [];
5597
5610
  if (!name.trim()) {
5598
5611
  return { error: "Error: name is required.", warnings };
5599
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
+ }
5600
5619
  if (!html.trim()) {
5601
5620
  return { error: "Error: html is required.", warnings };
5602
5621
  }
@@ -5655,13 +5674,13 @@ async function execute10(input, onLog, context) {
5655
5674
  return "Error: createWireframe requires execution context";
5656
5675
  }
5657
5676
  const name = String(input.name ?? "");
5677
+ const slug = String(input.slug ?? "");
5658
5678
  const description = String(input.description ?? "");
5659
5679
  const html = String(input.html ?? "");
5660
- const { error, warnings } = validate(name, html);
5680
+ const { error, warnings } = validate(name, slug, html);
5661
5681
  if (error) {
5662
5682
  return error;
5663
5683
  }
5664
- const slug = `${slugify(name)}-${Math.random().toString(36).slice(2, 8)}`;
5665
5684
  const relPath = `${WIREFRAMES_DIR}/${slug}.html`;
5666
5685
  const content = [
5667
5686
  "---",
@@ -5672,6 +5691,10 @@ async function execute10(input, onLog, context) {
5672
5691
  ""
5673
5692
  ].join("\n");
5674
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
+ );
5675
5698
  await writeFile2(join2(PROJECT_ROOT, relPath), content, "utf8");
5676
5699
  onLog?.(`Wrote ${relPath}, mirroring for preview...`);
5677
5700
  const mirror = await uploadMirror(context, slug, content);
@@ -5679,7 +5702,7 @@ async function execute10(input, onLog, context) {
5679
5702
  log9.warn("Wireframe mirror upload failed", { slug, note: mirror.note });
5680
5703
  }
5681
5704
  const lines = [
5682
- `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." : ""}`,
5683
5706
  `Reference it in your response and in specs with exactly: ![${singleLine(name)}](${relPath})`
5684
5707
  ];
5685
5708
  if (!mirror.ok) {
package/dist/index.js CHANGED
@@ -262,8 +262,13 @@ async function* streamChat(params) {
262
262
  };
263
263
  }
264
264
  }
265
- function isRetryableError(error) {
266
- return /Network error/i.test(error) || /HTTP 5\d\d/i.test(error) || /Stream stalled/i.test(error) || /overloaded/i.test(error) || /terminated/i.test(error) || // Anthropic fetches url-source image blocks server-side on every call;
265
+ function isRetryableError(error, code) {
266
+ if (code && RETRYABLE_ERROR_CODES.has(code)) {
267
+ return true;
268
+ }
269
+ return /Network error/i.test(error) || /HTTP 5\d\d/i.test(error) || /Stream stalled/i.test(error) || /overloaded/i.test(error) || /terminated/i.test(error) || // The API's friendly mapping of a provider 500 — belt-and-suspenders for
270
+ // pods that don't send a machine-readable code.
271
+ /Internal API error/i.test(error) || // Anthropic fetches url-source image blocks server-side on every call;
267
272
  // a transient failure anywhere in that chain (S3 signing edge, resize
268
273
  // proxy, their fetcher) surfaces as this message. The images themselves
269
274
  // are fine — the same URLs typically succeed on the next attempt.
@@ -278,7 +283,7 @@ async function* streamChatWithRetry(params, options) {
278
283
  let retryableFailure = false;
279
284
  for await (const event of streamChat(params)) {
280
285
  if (event.type === "error") {
281
- if (isRetryableError(event.error) && attempt < MAX_RETRIES - 1) {
286
+ if (isRetryableError(event.error, event.code) && attempt < MAX_RETRIES - 1) {
282
287
  options?.onRetry?.(attempt, event.error);
283
288
  retryableFailure = true;
284
289
  break;
@@ -360,7 +365,7 @@ async function fetchRemyContext(config) {
360
365
  return null;
361
366
  }
362
367
  }
363
- var log, MAX_RETRIES, INITIAL_BACKOFF_MS, FALLBACK_ACK;
368
+ var log, MAX_RETRIES, INITIAL_BACKOFF_MS, RETRYABLE_ERROR_CODES, FALLBACK_ACK;
364
369
  var init_api = __esm({
365
370
  "src/api.ts"() {
366
371
  "use strict";
@@ -368,6 +373,12 @@ var init_api = __esm({
368
373
  log = createLogger("api");
369
374
  MAX_RETRIES = 5;
370
375
  INITIAL_BACKOFF_MS = 1e3;
376
+ RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
377
+ "api_error",
378
+ // Anthropic's 500-equivalent ("The server had an error…")
379
+ "overloaded_error"
380
+ // Anthropic's 529-equivalent
381
+ ]);
371
382
  FALLBACK_ACK = "[Message sent to agent. Agent is working in the background and will report back with its results when finished.]";
372
383
  }
373
384
  });
@@ -3805,8 +3816,8 @@ function formatSize(bytes) {
3805
3816
  }
3806
3817
  async function formatFile(dirPath, name, indent) {
3807
3818
  try {
3808
- const stat2 = await fs15.stat(path8.join(dirPath, name));
3809
- 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)}`;
3810
3821
  } catch {
3811
3822
  return `${indent}${name}`;
3812
3823
  }
@@ -6741,19 +6752,22 @@ __export(createWireframe_exports, {
6741
6752
  definition: () => definition10,
6742
6753
  execute: () => execute10
6743
6754
  });
6744
- import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
6755
+ import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
6745
6756
  import { join as join2 } from "path";
6746
- function slugify(name) {
6747
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "") || "wireframe";
6748
- }
6749
6757
  function singleLine(value) {
6750
6758
  return value.replace(/\s+/g, " ").trim();
6751
6759
  }
6752
- function validate(name, html) {
6760
+ function validate(name, slug, html) {
6753
6761
  const warnings = [];
6754
6762
  if (!name.trim()) {
6755
6763
  return { error: "Error: name is required.", warnings };
6756
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
+ }
6757
6771
  if (!html.trim()) {
6758
6772
  return { error: "Error: html is required.", warnings };
6759
6773
  }
@@ -6812,13 +6826,13 @@ async function execute10(input, onLog, context) {
6812
6826
  return "Error: createWireframe requires execution context";
6813
6827
  }
6814
6828
  const name = String(input.name ?? "");
6829
+ const slug = String(input.slug ?? "");
6815
6830
  const description = String(input.description ?? "");
6816
6831
  const html = String(input.html ?? "");
6817
- const { error, warnings } = validate(name, html);
6832
+ const { error, warnings } = validate(name, slug, html);
6818
6833
  if (error) {
6819
6834
  return error;
6820
6835
  }
6821
- const slug = `${slugify(name)}-${Math.random().toString(36).slice(2, 8)}`;
6822
6836
  const relPath = `${WIREFRAMES_DIR}/${slug}.html`;
6823
6837
  const content = [
6824
6838
  "---",
@@ -6829,6 +6843,10 @@ async function execute10(input, onLog, context) {
6829
6843
  ""
6830
6844
  ].join("\n");
6831
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
+ );
6832
6850
  await writeFile2(join2(PROJECT_ROOT, relPath), content, "utf8");
6833
6851
  onLog?.(`Wrote ${relPath}, mirroring for preview...`);
6834
6852
  const mirror = await uploadMirror(context, slug, content);
@@ -6836,7 +6854,7 @@ async function execute10(input, onLog, context) {
6836
6854
  log10.warn("Wireframe mirror upload failed", { slug, note: mirror.note });
6837
6855
  }
6838
6856
  const lines = [
6839
- `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." : ""}`,
6840
6858
  `Reference it in your response and in specs with exactly: ![${singleLine(name)}](${relPath})`
6841
6859
  ];
6842
6860
  if (!mirror.ok) {
@@ -6849,7 +6867,7 @@ async function execute10(input, onLog, context) {
6849
6867
  }
6850
6868
  return lines.join("\n");
6851
6869
  }
6852
- var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition10;
6870
+ var log10, WIREFRAMES_DIR, UPLOAD_TIMEOUT_MS2, definition10, SLUG_RE;
6853
6871
  var init_createWireframe = __esm({
6854
6872
  "src/subagents/designExpert/tools/createWireframe.ts"() {
6855
6873
  "use strict";
@@ -6860,13 +6878,17 @@ var init_createWireframe = __esm({
6860
6878
  UPLOAD_TIMEOUT_MS2 = 3e4;
6861
6879
  definition10 = {
6862
6880
  name: "createWireframe",
6863
- 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.",
6864
6882
  inputSchema: {
6865
6883
  type: "object",
6866
6884
  properties: {
6867
6885
  name: {
6868
6886
  type: "string",
6869
- 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.'
6870
6892
  },
6871
6893
  description: {
6872
6894
  type: "string",
@@ -6877,9 +6899,10 @@ var init_createWireframe = __esm({
6877
6899
  description: "The complete HTML document (<html>\u2026</html>), self-contained vanilla HTML/CSS/JS. No frontmatter \u2014 it is added for you."
6878
6900
  }
6879
6901
  },
6880
- required: ["name", "description", "html"]
6902
+ required: ["name", "slug", "description", "html"]
6881
6903
  }
6882
6904
  };
6905
+ SLUG_RE = /^[a-z0-9][a-z0-9-]{0,79}$/;
6883
6906
  }
6884
6907
  });
6885
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.281",
3
+ "version": "0.1.283",
4
4
  "description": "Remy coding agent",
5
5
  "repository": {
6
6
  "type": "git",