@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.
- package/README.md +61 -8
- package/dist/shared/icons/icon-data.d.ts +2 -0
- package/dist/shared/icons/icon-data.js +5 -0
- package/dist/shared/icons/icon-keywords.d.ts +1 -0
- package/dist/shared/icons/icon-keywords.js +4 -0
- package/dist/shared/icons/index.d.ts +47 -0
- package/dist/shared/icons/index.js +107 -0
- package/dist/shared/icons/search.d.ts +31 -0
- package/dist/shared/icons/search.js +104 -0
- package/dist/shared/instances.d.ts +39 -0
- package/dist/shared/instances.js +94 -0
- package/dist/shared/node-defaults.d.ts +2 -0
- package/dist/shared/node-defaults.js +32 -4
- package/dist/shared/node-fields.d.ts +2 -0
- package/dist/shared/node-fields.js +17 -4
- package/dist/shared/render.d.ts +31 -1
- package/dist/shared/render.js +65 -6
- package/dist/shared/schemas/design.schema.d.ts +19 -1
- package/dist/shared/schemas/design.schema.js +13 -1
- package/dist/src/core/clone.d.ts +23 -0
- package/dist/src/core/clone.js +34 -0
- package/dist/src/core/diff.js +2 -2
- package/dist/src/core/export.js +63 -3
- package/dist/src/core/hierarchy.d.ts +7 -0
- package/dist/src/core/hierarchy.js +75 -5
- package/dist/src/core/node-factory.js +55 -5
- package/dist/src/core/screenshot.d.ts +12 -0
- package/dist/src/core/screenshot.js +17 -6
- package/dist/src/index.js +97 -7
- package/dist/src/tools/add-nodes.js +7 -1
- package/dist/src/tools/delete-nodes.js +10 -1
- package/dist/src/tools/detach-instances.d.ts +14 -0
- package/dist/src/tools/detach-instances.js +61 -0
- package/dist/src/tools/duplicate-nodes.js +20 -28
- package/dist/src/tools/search-icons.d.ts +12 -0
- package/dist/src/tools/search-icons.js +87 -0
- package/dist/src/tools/ungroup-nodes.js +8 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/gui/dist/assets/index-B-q92Pfu.js +10 -0
- package/gui/dist/assets/index-PQqxUQLx.css +1 -0
- package/gui/dist/assets/search-C-KcHHKM.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +4 -2
- package/scripts/generate-icons.js +85 -0
- package/gui/dist/assets/index-C6fXmzfu.css +0 -1
- 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]));
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const APP_VERSION = "1.0.
|
|
1
|
+
export declare const APP_VERSION = "1.0.6";
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated version file - do not edit manually
|
|
2
|
-
export const APP_VERSION = '1.0.
|
|
2
|
+
export const APP_VERSION = '1.0.6';
|