@imenam/mcp-design 1.0.4 → 1.0.6

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.
Files changed (47) hide show
  1. package/README.md +61 -8
  2. package/dist/shared/icons/icon-data.d.ts +2 -0
  3. package/dist/shared/icons/icon-data.js +5 -0
  4. package/dist/shared/icons/icon-keywords.d.ts +1 -0
  5. package/dist/shared/icons/icon-keywords.js +4 -0
  6. package/dist/shared/icons/index.d.ts +47 -0
  7. package/dist/shared/icons/index.js +107 -0
  8. package/dist/shared/icons/search.d.ts +31 -0
  9. package/dist/shared/icons/search.js +104 -0
  10. package/dist/shared/instances.d.ts +39 -0
  11. package/dist/shared/instances.js +94 -0
  12. package/dist/shared/node-defaults.d.ts +2 -0
  13. package/dist/shared/node-defaults.js +32 -4
  14. package/dist/shared/node-fields.d.ts +2 -0
  15. package/dist/shared/node-fields.js +17 -4
  16. package/dist/shared/render.d.ts +31 -1
  17. package/dist/shared/render.js +65 -6
  18. package/dist/shared/schemas/design.schema.d.ts +19 -1
  19. package/dist/shared/schemas/design.schema.js +13 -1
  20. package/dist/src/core/clone.d.ts +23 -0
  21. package/dist/src/core/clone.js +34 -0
  22. package/dist/src/core/diff.js +2 -2
  23. package/dist/src/core/export.js +63 -3
  24. package/dist/src/core/hierarchy.d.ts +7 -0
  25. package/dist/src/core/hierarchy.js +75 -5
  26. package/dist/src/core/node-factory.js +55 -5
  27. package/dist/src/core/screenshot.d.ts +12 -0
  28. package/dist/src/core/screenshot.js +17 -6
  29. package/dist/src/index.js +97 -7
  30. package/dist/src/tools/add-nodes.js +7 -1
  31. package/dist/src/tools/delete-nodes.js +10 -1
  32. package/dist/src/tools/detach-instances.d.ts +14 -0
  33. package/dist/src/tools/detach-instances.js +61 -0
  34. package/dist/src/tools/duplicate-nodes.js +20 -28
  35. package/dist/src/tools/search-icons.d.ts +12 -0
  36. package/dist/src/tools/search-icons.js +87 -0
  37. package/dist/src/tools/ungroup-nodes.js +8 -0
  38. package/dist/src/version.d.ts +1 -1
  39. package/dist/src/version.js +1 -1
  40. package/gui/dist/assets/index-B-q92Pfu.js +10 -0
  41. package/gui/dist/assets/index-PQqxUQLx.css +1 -0
  42. package/gui/dist/assets/search-C-KcHHKM.js +1 -0
  43. package/gui/dist/index.html +2 -2
  44. package/package.json +4 -2
  45. package/scripts/generate-icons.js +85 -0
  46. package/gui/dist/assets/index-C6fXmzfu.css +0 -1
  47. package/gui/dist/assets/index-Cmo-X8Zs.js +0 -10
@@ -0,0 +1,87 @@
1
+ import { escapeXml, iconElementToSvg, iconElementsOf, iconStyle } from "../../shared/render.js";
2
+ import { CORE_ICONS, ICON_GRID, iconCount } from "../../shared/icons/index.js";
3
+ import { searchIcons } from "../../shared/icons/search.js";
4
+ import { rasterize } from "../core/screenshot.js";
5
+ import { requireString } from "./types.js";
6
+ /** Au-dela, la planche coute plus de contexte qu'elle n'aide a choisir. */
7
+ export const MAX_ICON_RESULTS = 48;
8
+ export const DEFAULT_ICON_RESULTS = 24;
9
+ const SHEET_COLUMNS = 6;
10
+ const CELL_WIDTH = 120;
11
+ const CELL_HEIGHT = 96;
12
+ const GLYPH_SIZE = 40;
13
+ /**
14
+ * Planche de vignettes : le nom seul ne suffit pas toujours a distinguer
15
+ * "shopping-cart" de "shopping-basket". L'agent lit les noms dans le texte et
16
+ * verifie la forme sur l'image — les deux canaux disent la meme chose.
17
+ */
18
+ function contactSheet(names) {
19
+ const rows = Math.ceil(names.length / SHEET_COLUMNS);
20
+ const width = SHEET_COLUMNS * CELL_WIDTH;
21
+ const height = rows * CELL_HEIGHT;
22
+ const cells = names.map((name, index) => {
23
+ const column = index % SHEET_COLUMNS;
24
+ const row = Math.floor(index / SHEET_COLUMNS);
25
+ const centerX = column * CELL_WIDTH + CELL_WIDTH / 2;
26
+ const top = row * CELL_HEIGHT;
27
+ const node = { icon: name, stroke: "#1a1a18" };
28
+ const scale = GLYPH_SIZE / ICON_GRID;
29
+ const glyph = `<g transform="translate(${centerX - GLYPH_SIZE / 2} ${top + 18}) scale(${scale})" ` +
30
+ Object.entries(iconStyle(node))
31
+ .map(([key, value]) => `${key}="${escapeXml(value)}"`)
32
+ .join(" ") +
33
+ `>${iconElementsOf(node).map(iconElementToSvg).join("")}</g>`;
34
+ // Le nom est tronque plutot que rogne : un libelle coupe au milieu d'un mot
35
+ // reste identifiable, un libelle qui deborde sur la vignette voisine non.
36
+ const label = name.length > 18 ? `${name.slice(0, 17)}…` : name;
37
+ return (glyph +
38
+ `<text x="${centerX}" y="${top + 78}" text-anchor="middle" font-family="Segoe UI, sans-serif" ` +
39
+ `font-size="11" fill="#4a4a48">${escapeXml(label)}</text>`);
40
+ });
41
+ return (`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">` +
42
+ `<rect x="0" y="0" width="${width}" height="${height}" fill="#ffffff" />` +
43
+ cells.join("") +
44
+ `</svg>`);
45
+ }
46
+ /**
47
+ * Recherche d'une icone par description.
48
+ *
49
+ * C'est la traine longue de la bibliotheque : les icones les plus courantes
50
+ * sont deja listees dans la description de `add_nodes`, donc un agent qui
51
+ * habille une interface ordinaire n'a pas besoin de passer par ici.
52
+ */
53
+ export function searchIconsTool(args) {
54
+ const query = requireString(args, "query");
55
+ const requested = args?.limit === undefined ? DEFAULT_ICON_RESULTS : Number(args.limit);
56
+ const limit = Math.max(1, Math.min(MAX_ICON_RESULTS, Number.isFinite(requested) ? requested : DEFAULT_ICON_RESULTS));
57
+ const withPreview = args?.preview !== false;
58
+ const matches = searchIcons(query, limit);
59
+ if (matches.length === 0) {
60
+ return {
61
+ content: [
62
+ {
63
+ type: "text",
64
+ text: `No icon matches "${query}" among the ${iconCount()} available. ` +
65
+ `Search in English and with a single concept ("cart", "user", "warning"). ` +
66
+ `Common icons: ${CORE_ICONS.slice(0, 30).join(", ")}.`,
67
+ },
68
+ ],
69
+ };
70
+ }
71
+ const lines = matches.map((match) => {
72
+ const synonyms = match.keywords.filter((word) => !match.name.includes(word)).slice(0, 6);
73
+ return `- ${match.name}${synonyms.length > 0 ? ` — ${synonyms.join(", ")}` : ""}`;
74
+ });
75
+ const header = `${matches.length} icon(s) matching "${query}", best first (of ${iconCount()} available). ` +
76
+ `Use the name as the "icon" field of an "icon" node — never redraw it out of shapes.`;
77
+ const text = [header, "", ...lines].join("\n");
78
+ if (!withPreview)
79
+ return { content: [{ type: "text", text }] };
80
+ const sheet = rasterize(contactSheet(matches.map((match) => match.name)), 2);
81
+ return {
82
+ content: [
83
+ { type: "text", text: `${text}\n\nThe image below shows them in the same order, left to right.` },
84
+ { type: "image", data: sheet.png.toString("base64"), mimeType: "image/png" },
85
+ ],
86
+ };
87
+ }
@@ -1,3 +1,4 @@
1
+ import { survivingInstancesOf } from "../core/hierarchy.js";
1
2
  import { DesignError } from "../core/node-factory.js";
2
3
  import { requireString, textResult } from "./types.js";
3
4
  /**
@@ -22,6 +23,13 @@ export function ungroupNodes(store, args) {
22
23
  return node;
23
24
  });
24
25
  const dissolved = new Set(groups.map((group) => group.id));
26
+ // Dissoudre un composant reviendrait a le supprimer pour ses instances.
27
+ const orphaned = survivingInstancesOf(current.nodes, dissolved);
28
+ if (orphaned.length > 0) {
29
+ throw new DesignError(`Group(s) ${[...new Set(orphaned.map((instance) => instance.componentId))].join(", ")} are still mirrored by ` +
30
+ `${orphaned.length} instance(s) (${orphaned.map((instance) => instance.id).join(", ")}). ` +
31
+ `Run detach_instances on them first, or delete them.`);
32
+ }
25
33
  let promoted = 0;
26
34
  const design = store.mutate(id, "agent", (draft) => {
27
35
  const nodesById = new Map(draft.nodes.map((node) => [node.id, node]));
@@ -1 +1 @@
1
- export declare const APP_VERSION = "1.0.4";
1
+ export declare const APP_VERSION = "1.0.6";
@@ -1,2 +1,2 @@
1
1
  // Auto-generated version file - do not edit manually
2
- export const APP_VERSION = '1.0.4';
2
+ export const APP_VERSION = '1.0.6';