@ikas/code-components-mcp 1.4.0-beta.100 → 1.4.0-beta.101
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/data/storefront-api.json +1 -1
- package/data/storefront-types.json +1 -1
- package/dist/index.js +438 -146
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2623,7 +2623,7 @@ server.tool("list_types", "List storefront types and enums. Use `domain` and/or
|
|
|
2623
2623
|
return { content: [{ type: "text", text: parts.join("\n") }] };
|
|
2624
2624
|
});
|
|
2625
2625
|
// Tool: get_prop_types
|
|
2626
|
-
server.tool("get_prop_types",
|
|
2626
|
+
server.tool("get_prop_types", 'Get all available ikas.config.json prop types with descriptions, TypeScript types, and examples. NOTE: these are the TypeScript prop-definition types for authoring a component — they are NOT the runtime JSON value shapes you write via `update_section_prop` (e.g. a TEXT prop is typed `string` here but written as `{ "value": "..." }`, and an IMAGE is `IkasImage | null` here but written as `{ "id": "..." }`). For the value shapes to pass to `update_section_prop`, see that tool\'s description. Tip: Use `npx ikas-component config add-component --props \'[...]\'` to create a component with all props in one command, or `add-prop` to add props incrementally. NEVER manually edit types.ts — it is auto-generated by the CLI.', {}, async () => {
|
|
2627
2627
|
const propTypesTopic = frameworkData.topics["prop-types"];
|
|
2628
2628
|
if (propTypesTopic) {
|
|
2629
2629
|
return {
|
|
@@ -3615,7 +3615,7 @@ server.tool("import_section", "Import a built section-type code component into t
|
|
|
3615
3615
|
return callEditorAction(project_root, args);
|
|
3616
3616
|
});
|
|
3617
3617
|
// Tool: add_section_to_page
|
|
3618
|
-
server.tool("add_section_to_page",
|
|
3618
|
+
server.tool("add_section_to_page", "Place a SINGLE already-imported section-type code component on a page. Use this ONLY when adding exactly one section. If you are adding more than one section — or building/populating a page — call `add_sections_to_page` instead: it places them all AND fills their props in ONE call. Calling this tool repeatedly (one section per call) is the slow path and should be avoided. Equivalent to right-clicking the section in the dev-components panel and choosing \"Add to Page\". Errors if the component is not imported, is not section-type, or the page id is unknown. Use `list_editor_pages` to discover page ids and `list_imported_sections` to discover component ids. After placing, change the section's prop values with `update_section_prop` / `update_page_sections` (use `list_page_sections` to get the placement's `elementId` and prop names).", {
|
|
3619
3619
|
project_root: z
|
|
3620
3620
|
.string()
|
|
3621
3621
|
.describe("Absolute path to the code-component project."),
|
|
@@ -3647,11 +3647,15 @@ server.tool("add_section_to_page", 'Place a SINGLE already-imported section-type
|
|
|
3647
3647
|
});
|
|
3648
3648
|
// Tool: add_sections_to_page
|
|
3649
3649
|
server.tool("add_sections_to_page", "Place MANY sections on a page in a SINGLE call — and optionally set each section's prop values AT placement time, so you skip the separate fill step. The fastest way to build a page: one round-trip instead of one add (and one fill) per section. Pass `sections`, each `{ component_id, index?, updates?: [{ prop_name|prop_id, value }] }`; values use the same per-type shapes as update_section_prop / get_editor_workflow. Returns the new `elementId` for each placement (plus written prop results). Built-but-unimported section AND child code components are auto-imported. All update values are validated before anything is placed. Use `list_editor_pages` for page ids and `list_imported_sections` for component ids.", {
|
|
3650
|
-
project_root: z
|
|
3650
|
+
project_root: z
|
|
3651
|
+
.string()
|
|
3652
|
+
.describe("Absolute path to the code-component project."),
|
|
3651
3653
|
page_id: z.string().describe("Target page id (from `list_editor_pages`)."),
|
|
3652
3654
|
sections: z
|
|
3653
3655
|
.array(z.object({
|
|
3654
|
-
component_id: z
|
|
3656
|
+
component_id: z
|
|
3657
|
+
.string()
|
|
3658
|
+
.describe("Imported (or built) section-type code component id."),
|
|
3655
3659
|
index: z
|
|
3656
3660
|
.number()
|
|
3657
3661
|
.int()
|
|
@@ -3660,22 +3664,33 @@ server.tool("add_sections_to_page", "Place MANY sections on a page in a SINGLE c
|
|
|
3660
3664
|
.describe("Zero-based insertion index; appends when omitted."),
|
|
3661
3665
|
updates: z
|
|
3662
3666
|
.array(z.object({
|
|
3663
|
-
prop_id: z
|
|
3664
|
-
|
|
3665
|
-
|
|
3667
|
+
prop_id: z
|
|
3668
|
+
.string()
|
|
3669
|
+
.optional()
|
|
3670
|
+
.describe("Blueprint prop id (provide this or prop_name)."),
|
|
3671
|
+
prop_name: z
|
|
3672
|
+
.string()
|
|
3673
|
+
.optional()
|
|
3674
|
+
.describe("Blueprint prop name (alternative to prop_id)."),
|
|
3675
|
+
value: z
|
|
3676
|
+
.any()
|
|
3677
|
+
.describe("Prop value, same shape update_section_prop expects for that type."),
|
|
3666
3678
|
}))
|
|
3667
3679
|
.optional()
|
|
3668
3680
|
.describe("Optional prop values to set on this section right after placing it."),
|
|
3669
3681
|
}))
|
|
3670
3682
|
.describe("Non-empty array of sections to place (in order), each with its componentId and optional prop updates."),
|
|
3671
|
-
port: z
|
|
3683
|
+
port: z
|
|
3684
|
+
.number()
|
|
3685
|
+
.optional()
|
|
3686
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3672
3687
|
}, async ({ project_root, page_id, sections, port }) => {
|
|
3673
|
-
const normalized = (sections || []).map(s => ({
|
|
3688
|
+
const normalized = (sections || []).map((s) => ({
|
|
3674
3689
|
componentId: s.component_id,
|
|
3675
3690
|
...(typeof s.index === "number" ? { index: s.index } : {}),
|
|
3676
3691
|
...(s.updates
|
|
3677
3692
|
? {
|
|
3678
|
-
updates: s.updates.map(u => ({
|
|
3693
|
+
updates: s.updates.map((u) => ({
|
|
3679
3694
|
...(u.prop_id ? { propId: u.prop_id } : {}),
|
|
3680
3695
|
...(u.prop_name ? { propName: u.prop_name } : {}),
|
|
3681
3696
|
value: u.value,
|
|
@@ -3714,11 +3729,16 @@ server.tool("list_page_sections", "List the sections placed on a page — a LEAN
|
|
|
3714
3729
|
});
|
|
3715
3730
|
// Tool: get_component_props
|
|
3716
3731
|
server.tool("get_component_props", "Get prop blueprints straight from the editor (the source of truth) for one or MANY components in a single call — for any section OR child code component ids. Returns `{ components: [...] }`, each prop carrying its `id`, `name`, `type`, `required`, `default`, and crucially: a ready-to-use `writeExample` (the EXACT value shape to pass to update_section_prop / update_page_sections — e.g. PRODUCT_LIST, BLOG_LIST, COMPONENT_LIST, LINK) plus a `writeNote` for variants, so you do NOT have to guess or trial-write the JSON; for ENUM props the `options` (valid `value`s); and for COMPONENT/COMPONENT_LIST props the `allowedComponentIds` (which children the slot permits — when empty, an `allowedComponentsNote` says any imported code component is allowed). Use this (its `writeExample`/`options`/`allowedComponentIds`) instead of guessing or reading ikas.config.json. Pass ALL the section/child ids you need at once (batch). Child component ids come from a parent prop's `allowedComponentIds` (or get_section_template).", {
|
|
3717
|
-
project_root: z
|
|
3732
|
+
project_root: z
|
|
3733
|
+
.string()
|
|
3734
|
+
.describe("Absolute path to the code-component project."),
|
|
3718
3735
|
component_ids: z
|
|
3719
3736
|
.array(z.string())
|
|
3720
3737
|
.describe("Section/child code-component ids to resolve (batch). From list_imported_sections or a COMPONENT_LIST prop's allowedComponentIds."),
|
|
3721
|
-
port: z
|
|
3738
|
+
port: z
|
|
3739
|
+
.number()
|
|
3740
|
+
.optional()
|
|
3741
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3722
3742
|
}, async ({ project_root, component_ids, port }) => {
|
|
3723
3743
|
const args = [
|
|
3724
3744
|
"get-component-props",
|
|
@@ -3730,12 +3750,17 @@ server.tool("get_component_props", "Get prop blueprints straight from the editor
|
|
|
3730
3750
|
});
|
|
3731
3751
|
// Tool: get_section_values
|
|
3732
3752
|
server.tool("get_section_values", "Get the CURRENT prop values of one or MANY placed sections (each with its full `propValues` plus blueprint `props` — every prop carrying a `writeExample`/`writeNote` for the exact value shape, plus ENUM `options` and COMPONENT_LIST `allowedComponentIds`). `list_page_sections` is lean and omits values to avoid truncation; use this to read sections' values — needed for read-modify-write of a COMPONENT_LIST, or to inspect the exact stored shape of an existing value. Returns `{ sections: [...] }`. Pass all the elementIds you need at once (batch).", {
|
|
3733
|
-
project_root: z
|
|
3753
|
+
project_root: z
|
|
3754
|
+
.string()
|
|
3755
|
+
.describe("Absolute path to the code-component project."),
|
|
3734
3756
|
page_id: z.string().describe("Target page id (from `list_editor_pages`)."),
|
|
3735
3757
|
element_ids: z
|
|
3736
3758
|
.array(z.string())
|
|
3737
3759
|
.describe("Placed-section elementIds to read (batch). From `list_page_sections`."),
|
|
3738
|
-
port: z
|
|
3760
|
+
port: z
|
|
3761
|
+
.number()
|
|
3762
|
+
.optional()
|
|
3763
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3739
3764
|
}, async ({ project_root, page_id, element_ids, port }) => {
|
|
3740
3765
|
const args = [
|
|
3741
3766
|
"get-section-values",
|
|
@@ -3774,7 +3799,7 @@ server.tool("update_section_prop", 'Change a single prop value of a section plac
|
|
|
3774
3799
|
.number()
|
|
3775
3800
|
.optional()
|
|
3776
3801
|
.describe("Dev server WebSocket port (default 5201)."),
|
|
3777
|
-
}, async ({ project_root, page_id, element_id, prop_id, prop_name, value, port }) => {
|
|
3802
|
+
}, async ({ project_root, page_id, element_id, prop_id, prop_name, value, port, }) => {
|
|
3778
3803
|
const args = [
|
|
3779
3804
|
"update-section-prop",
|
|
3780
3805
|
"--page-id",
|
|
@@ -3793,7 +3818,7 @@ server.tool("update_section_prop", 'Change a single prop value of a section plac
|
|
|
3793
3818
|
return callEditorAction(project_root, args);
|
|
3794
3819
|
});
|
|
3795
3820
|
// Tool: upload_image
|
|
3796
|
-
server.tool("upload_image",
|
|
3821
|
+
server.tool("upload_image", 'Upload an image to the connected editor\'s project and get back its image `id`. Provide the image via `file_path` (a local path) OR `image_url`. Use the returned `id` as the `id` of an IMAGE prop value passed to `update_section_prop` (e.g. `{ "id": "<returned-id>", "altText": "...", "isVideo": false }`). This is the way to set an image prop — `update_section_prop` does not upload, it only references an existing image id. Supported types: png, jpg, jpeg, webp, gif; max 10MB. Requires the editor to be embedded in the ikas admin panel (the admin panel performs the actual upload; a standalone editor cannot upload and will error/time out).', {
|
|
3797
3822
|
project_root: z
|
|
3798
3823
|
.string()
|
|
3799
3824
|
.describe("Absolute path to the code-component project."),
|
|
@@ -3805,7 +3830,10 @@ server.tool("upload_image", "Upload an image to the connected editor's project a
|
|
|
3805
3830
|
.string()
|
|
3806
3831
|
.optional()
|
|
3807
3832
|
.describe("Image URL to fetch and upload (alternative to `file_path`)."),
|
|
3808
|
-
alt_text: z
|
|
3833
|
+
alt_text: z
|
|
3834
|
+
.string()
|
|
3835
|
+
.optional()
|
|
3836
|
+
.describe("Alt text to store with the image."),
|
|
3809
3837
|
port: z
|
|
3810
3838
|
.number()
|
|
3811
3839
|
.optional()
|
|
@@ -3822,25 +3850,40 @@ server.tool("upload_image", "Upload an image to the connected editor's project a
|
|
|
3822
3850
|
});
|
|
3823
3851
|
// Tool: update_page_sections
|
|
3824
3852
|
server.tool("update_page_sections", "Fill MANY placed sections of a page in a SINGLE call — the fastest way to populate a whole page (one round-trip for the entire page instead of one call per section/prop). Takes `sections`, each `{ element_id, updates: [{ prop_name|prop_id, value }] }`; values use the same per-type shapes as update_section_prop / get_editor_workflow. All-or-nothing across the whole page: every value is resolved and deeply validated (and built-but-unimported child code components auto-imported) before anything is written — one invalid value rejects the entire page update. Prefer this over many update_section_prop(s) calls.", {
|
|
3825
|
-
project_root: z
|
|
3853
|
+
project_root: z
|
|
3854
|
+
.string()
|
|
3855
|
+
.describe("Absolute path to the code-component project."),
|
|
3826
3856
|
page_id: z.string().describe("Target page id (from list_editor_pages)."),
|
|
3827
3857
|
sections: z
|
|
3828
3858
|
.array(z.object({
|
|
3829
|
-
element_id: z
|
|
3859
|
+
element_id: z
|
|
3860
|
+
.string()
|
|
3861
|
+
.describe("Placed-section elementId (from list_page_sections)."),
|
|
3830
3862
|
updates: z
|
|
3831
3863
|
.array(z.object({
|
|
3832
|
-
prop_id: z
|
|
3833
|
-
|
|
3834
|
-
|
|
3864
|
+
prop_id: z
|
|
3865
|
+
.string()
|
|
3866
|
+
.optional()
|
|
3867
|
+
.describe("Blueprint prop id (provide this or prop_name)."),
|
|
3868
|
+
prop_name: z
|
|
3869
|
+
.string()
|
|
3870
|
+
.optional()
|
|
3871
|
+
.describe("Blueprint prop name (alternative to prop_id)."),
|
|
3872
|
+
value: z
|
|
3873
|
+
.any()
|
|
3874
|
+
.describe("Prop value, same shape update_section_prop expects for that type."),
|
|
3835
3875
|
}))
|
|
3836
3876
|
.describe("Non-empty array of prop updates for this section."),
|
|
3837
3877
|
}))
|
|
3838
3878
|
.describe("Non-empty array of sections to fill, each with its elementId and prop updates."),
|
|
3839
|
-
port: z
|
|
3879
|
+
port: z
|
|
3880
|
+
.number()
|
|
3881
|
+
.optional()
|
|
3882
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3840
3883
|
}, async ({ project_root, page_id, sections, port }) => {
|
|
3841
|
-
const normalized = (sections || []).map(s => ({
|
|
3884
|
+
const normalized = (sections || []).map((s) => ({
|
|
3842
3885
|
elementId: s.element_id,
|
|
3843
|
-
updates: (s.updates || []).map(u => ({
|
|
3886
|
+
updates: (s.updates || []).map((u) => ({
|
|
3844
3887
|
...(u.prop_id ? { propId: u.prop_id } : {}),
|
|
3845
3888
|
...(u.prop_name ? { propName: u.prop_name } : {}),
|
|
3846
3889
|
value: u.value,
|
|
@@ -3858,17 +3901,28 @@ server.tool("update_page_sections", "Fill MANY placed sections of a page in a SI
|
|
|
3858
3901
|
});
|
|
3859
3902
|
// Tool: upload_images
|
|
3860
3903
|
server.tool("upload_images", "Upload MANY images in one call (batch upload_image) and get their ids back in order — the host uploads them all in a single round-trip. Pass `images`, each `{ file_path?, image_url?, alt_text? }`. Returns an array of { id, fileName, altText, isVideo } in the same order; use each id in an IMAGE prop value. Prefer this over multiple upload_image calls when a section/page needs several images. Supported: png/jpg/jpeg/webp/gif, max 10MB each. Requires the editor embedded in the ikas admin panel.", {
|
|
3861
|
-
project_root: z
|
|
3904
|
+
project_root: z
|
|
3905
|
+
.string()
|
|
3906
|
+
.describe("Absolute path to the code-component project."),
|
|
3862
3907
|
images: z
|
|
3863
3908
|
.array(z.object({
|
|
3864
|
-
file_path: z
|
|
3865
|
-
|
|
3909
|
+
file_path: z
|
|
3910
|
+
.string()
|
|
3911
|
+
.optional()
|
|
3912
|
+
.describe("Local image file path (provide this or image_url)."),
|
|
3913
|
+
image_url: z
|
|
3914
|
+
.string()
|
|
3915
|
+
.optional()
|
|
3916
|
+
.describe("Image URL to fetch (alternative to file_path)."),
|
|
3866
3917
|
alt_text: z.string().optional().describe("Alt text for this image."),
|
|
3867
3918
|
}))
|
|
3868
3919
|
.describe("Non-empty array of images to upload."),
|
|
3869
|
-
port: z
|
|
3920
|
+
port: z
|
|
3921
|
+
.number()
|
|
3922
|
+
.optional()
|
|
3923
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3870
3924
|
}, async ({ project_root, images, port }) => {
|
|
3871
|
-
const manifest = (images || []).map(im => ({
|
|
3925
|
+
const manifest = (images || []).map((im) => ({
|
|
3872
3926
|
...(im.file_path ? { file: im.file_path } : {}),
|
|
3873
3927
|
...(im.image_url ? { url: im.image_url } : {}),
|
|
3874
3928
|
...(im.alt_text ? { alt: im.alt_text } : {}),
|
|
@@ -3882,48 +3936,81 @@ server.tool("upload_images", "Upload MANY images in one call (batch upload_image
|
|
|
3882
3936
|
return callEditorAction(project_root, args);
|
|
3883
3937
|
});
|
|
3884
3938
|
// Tool: search_products
|
|
3885
|
-
server.tool("search_products",
|
|
3939
|
+
server.tool("search_products", 'Search the connected store\'s products to obtain a real productId (and first variantId) for a PRODUCT prop value. Returns products with productId, variantId, name, slug, variantCount, and `imageSrc` (the full-resolution CDN URL of the product\'s main image). To use that product image in an IMAGE prop, you CANNOT reuse a product image id directly (it is not a theme asset) — pass the `imageSrc` URL to `upload_image(image_url: <imageSrc>)` (or `upload_images`), then use the returned id in the IMAGE value. This gives real product imagery instead of external/placeholder URLs. Use the result in update_section_prop as `{ "productId": "<productId>", "variantId": "<variantId>" }`. Pass `query` for free-text search, or `product_ids` to resolve specific ids. Requires the editor embedded in the ikas admin panel (the admin panel runs the search; a standalone editor cannot).', {
|
|
3886
3940
|
project_root: z
|
|
3887
3941
|
.string()
|
|
3888
3942
|
.describe("Absolute path to the code-component project."),
|
|
3889
|
-
query: z
|
|
3943
|
+
query: z
|
|
3944
|
+
.string()
|
|
3945
|
+
.optional()
|
|
3946
|
+
.describe("Free-text product search (name, sku, barcode)."),
|
|
3890
3947
|
product_ids: z
|
|
3891
3948
|
.array(z.string())
|
|
3892
3949
|
.optional()
|
|
3893
3950
|
.describe("Specific product ids to resolve directly (alternative to `query`)."),
|
|
3894
3951
|
per_page: z.number().optional().describe("Results per page."),
|
|
3895
|
-
port: z
|
|
3952
|
+
port: z
|
|
3953
|
+
.number()
|
|
3954
|
+
.optional()
|
|
3955
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3896
3956
|
}, async ({ project_root, query, product_ids, per_page, port }) => {
|
|
3897
3957
|
const args = [
|
|
3898
3958
|
"search-products",
|
|
3899
3959
|
...(query ? ["--query", query] : []),
|
|
3900
|
-
...(product_ids && product_ids.length
|
|
3960
|
+
...(product_ids && product_ids.length
|
|
3961
|
+
? ["--ids", product_ids.join(",")]
|
|
3962
|
+
: []),
|
|
3901
3963
|
...(typeof per_page === "number" ? ["--per-page", String(per_page)] : []),
|
|
3902
3964
|
...(port ? ["--port", String(port)] : []),
|
|
3903
3965
|
];
|
|
3904
3966
|
return callEditorAction(project_root, args);
|
|
3905
3967
|
});
|
|
3906
3968
|
// Tool: list_categories
|
|
3907
|
-
server.tool("list_categories",
|
|
3908
|
-
project_root: z
|
|
3909
|
-
|
|
3969
|
+
server.tool("list_categories", 'List the store\'s product categories and their ids, to fill a CATEGORY prop value `{ "categoryId": "<id>" }`. Returns categoryId, name, slug, parentId for each. Returns all categories (no query). To link to a category from a LINK prop, also call `get_page_by_type("CATEGORY")` for the page id, then build `{ "linkType": "PAGE", "pageId": <pageId>, "pageType": "CATEGORY", "itemId": <categoryId>, "id": <unique>, "label": "..." }`. Requires the editor embedded in the ikas admin panel.', {
|
|
3970
|
+
project_root: z
|
|
3971
|
+
.string()
|
|
3972
|
+
.describe("Absolute path to the code-component project."),
|
|
3973
|
+
port: z
|
|
3974
|
+
.number()
|
|
3975
|
+
.optional()
|
|
3976
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3910
3977
|
}, async ({ project_root, port }) => {
|
|
3911
|
-
const args = [
|
|
3978
|
+
const args = [
|
|
3979
|
+
"list-entities",
|
|
3980
|
+
"--kind",
|
|
3981
|
+
"category",
|
|
3982
|
+
...(port ? ["--port", String(port)] : []),
|
|
3983
|
+
];
|
|
3912
3984
|
return callEditorAction(project_root, args);
|
|
3913
3985
|
});
|
|
3914
3986
|
// Tool: list_brands
|
|
3915
|
-
server.tool("list_brands",
|
|
3916
|
-
project_root: z
|
|
3917
|
-
|
|
3987
|
+
server.tool("list_brands", 'List the store\'s product brands and their ids, to fill a BRAND prop value `{ "brandId": "<id>" }`. Returns brandId, name, slug for each. Returns all brands (no query). To link to a brand from a LINK prop, also call `get_page_by_type("BRAND")` for the page id, then build `{ "linkType": "PAGE", "pageId": <pageId>, "pageType": "BRAND", "itemId": <brandId>, "id": <unique>, "label": "..." }`. Requires the editor embedded in the ikas admin panel.', {
|
|
3988
|
+
project_root: z
|
|
3989
|
+
.string()
|
|
3990
|
+
.describe("Absolute path to the code-component project."),
|
|
3991
|
+
port: z
|
|
3992
|
+
.number()
|
|
3993
|
+
.optional()
|
|
3994
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3918
3995
|
}, async ({ project_root, port }) => {
|
|
3919
|
-
const args = [
|
|
3996
|
+
const args = [
|
|
3997
|
+
"list-entities",
|
|
3998
|
+
"--kind",
|
|
3999
|
+
"brand",
|
|
4000
|
+
...(port ? ["--port", String(port)] : []),
|
|
4001
|
+
];
|
|
3920
4002
|
return callEditorAction(project_root, args);
|
|
3921
4003
|
});
|
|
3922
4004
|
// Tool: list_blogs
|
|
3923
|
-
server.tool("list_blogs",
|
|
3924
|
-
project_root: z
|
|
4005
|
+
server.tool("list_blogs", 'List the store\'s blogs and their ids, to fill a BLOG prop value `{ "blogId": "<id>" }`. Returns blogId, name, slug for each. Accepts an optional `query` for free-text search. To link to a blog from a LINK prop, also call `get_page_by_type("BLOG")` for the page id, then build `{ "linkType": "PAGE", "pageId": <pageId>, "pageType": "BLOG", "itemId": <blogId>, "id": <unique>, "label": "..." }`. Requires the editor embedded in the ikas admin panel.', {
|
|
4006
|
+
project_root: z
|
|
4007
|
+
.string()
|
|
4008
|
+
.describe("Absolute path to the code-component project."),
|
|
3925
4009
|
query: z.string().optional().describe("Free-text blog search."),
|
|
3926
|
-
port: z
|
|
4010
|
+
port: z
|
|
4011
|
+
.number()
|
|
4012
|
+
.optional()
|
|
4013
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3927
4014
|
}, async ({ project_root, query, port }) => {
|
|
3928
4015
|
const args = [
|
|
3929
4016
|
"list-entities",
|
|
@@ -3935,10 +4022,15 @@ server.tool("list_blogs", "List the store's blogs and their ids, to fill a BLOG
|
|
|
3935
4022
|
return callEditorAction(project_root, args);
|
|
3936
4023
|
});
|
|
3937
4024
|
// Tool: list_blog_categories
|
|
3938
|
-
server.tool("list_blog_categories",
|
|
3939
|
-
project_root: z
|
|
4025
|
+
server.tool("list_blog_categories", 'List the store\'s blog categories and their ids, to fill a BLOG_CATEGORY prop value `{ "blogCategoryId": "<id>" }`. Returns blogCategoryId, name, slug for each. Accepts an optional `query` for free-text search. To link to a blog category from a LINK prop, also call `get_page_by_type("BLOG_CATEGORY")` for the page id, then build `{ "linkType": "PAGE", "pageId": <pageId>, "pageType": "BLOG_CATEGORY", "itemId": <blogCategoryId>, "id": <unique>, "label": "..." }`. Requires the editor embedded in the ikas admin panel.', {
|
|
4026
|
+
project_root: z
|
|
4027
|
+
.string()
|
|
4028
|
+
.describe("Absolute path to the code-component project."),
|
|
3940
4029
|
query: z.string().optional().describe("Free-text blog-category search."),
|
|
3941
|
-
port: z
|
|
4030
|
+
port: z
|
|
4031
|
+
.number()
|
|
4032
|
+
.optional()
|
|
4033
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3942
4034
|
}, async ({ project_root, query, port }) => {
|
|
3943
4035
|
const args = [
|
|
3944
4036
|
"list-entities",
|
|
@@ -3950,12 +4042,17 @@ server.tool("list_blog_categories", "List the store's blog categories and their
|
|
|
3950
4042
|
return callEditorAction(project_root, args);
|
|
3951
4043
|
});
|
|
3952
4044
|
// Tool: get_page_by_type
|
|
3953
|
-
server.tool("get_page_by_type",
|
|
3954
|
-
project_root: z
|
|
4045
|
+
server.tool("get_page_by_type", 'Resolve a theme page\'s id from its pageType (CATEGORY, PRODUCT, BRAND, BLOG, BLOG_CATEGORY, INDEX, …). Use this to get the `pageId` needed to build a PAGE link to an entity: pair it with the entity id from list_categories/list_brands/list_blogs/list_blog_categories — `{ linkType:"PAGE", pageId:<this pageId>, pageType:<type>, itemId:<entityId>, id:<unique>, label:... }`. Returns `pageId: null` (with a note) if no page of that type exists yet — in that case call `create_page(page_type)` to add it, then use the returned pageId (do not guess a slug/EXTERNAL URL).', {
|
|
4046
|
+
project_root: z
|
|
4047
|
+
.string()
|
|
4048
|
+
.describe("Absolute path to the code-component project."),
|
|
3955
4049
|
page_type: z
|
|
3956
4050
|
.string()
|
|
3957
4051
|
.describe("Page type to resolve, e.g. CATEGORY, PRODUCT, BRAND, BLOG, BLOG_CATEGORY, INDEX."),
|
|
3958
|
-
port: z
|
|
4052
|
+
port: z
|
|
4053
|
+
.number()
|
|
4054
|
+
.optional()
|
|
4055
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3959
4056
|
}, async ({ project_root, page_type, port }) => {
|
|
3960
4057
|
const args = [
|
|
3961
4058
|
"get-page-by-type",
|
|
@@ -3966,14 +4063,25 @@ server.tool("get_page_by_type", "Resolve a theme page's id from its pageType (CA
|
|
|
3966
4063
|
return callEditorAction(project_root, args);
|
|
3967
4064
|
});
|
|
3968
4065
|
// Tool: create_page
|
|
3969
|
-
server.tool("create_page",
|
|
3970
|
-
project_root: z
|
|
4066
|
+
server.tool("create_page", 'Create a theme page of a given pageType in the connected editor. Use this when get_page_by_type returns `pageId: null` for a dynamic page (CATEGORY/PRODUCT/BRAND/BLOG/BLOG_CATEGORY) you need to link to: create the page, then build a PAGE link `{ linkType:"PAGE", pageId:<this pageId>, pageType:<type>, itemId:<entityId>, id:<unique>, label:... }` — do NOT guess a slug/EXTERNAL URL. Non-CUSTOM page types are unique per theme: if one already exists it is returned unchanged (`alreadyExisted: true`). CUSTOM pages require `name` and a unique `slug`. Account sub-pages (ADDRESSES/ORDERS/ORDER_DETAIL/FAVORITE_PRODUCTS/RAFFLE_ACCOUNT) need an ACCOUNT page first. Returns `{ pageType, pageId, name, slug }`. Requires `ikas-component dev` running with the editor connected.', {
|
|
4067
|
+
project_root: z
|
|
4068
|
+
.string()
|
|
4069
|
+
.describe("Absolute path to the code-component project."),
|
|
3971
4070
|
page_type: z
|
|
3972
4071
|
.string()
|
|
3973
4072
|
.describe("Page type to create, e.g. CATEGORY, PRODUCT, BRAND, BLOG, BLOG_CATEGORY, INDEX, CUSTOM."),
|
|
3974
|
-
name: z
|
|
3975
|
-
|
|
3976
|
-
|
|
4073
|
+
name: z
|
|
4074
|
+
.string()
|
|
4075
|
+
.optional()
|
|
4076
|
+
.describe("Page name. Required for CUSTOM pages; ignored otherwise."),
|
|
4077
|
+
slug: z
|
|
4078
|
+
.string()
|
|
4079
|
+
.optional()
|
|
4080
|
+
.describe("Page slug. Required (and unique) for CUSTOM pages; ignored otherwise."),
|
|
4081
|
+
port: z
|
|
4082
|
+
.number()
|
|
4083
|
+
.optional()
|
|
4084
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
3977
4085
|
}, async ({ project_root, page_type, name, slug, port }) => {
|
|
3978
4086
|
const args = [
|
|
3979
4087
|
"create-page",
|
|
@@ -3987,7 +4095,9 @@ server.tool("create_page", "Create a theme page of a given pageType in the conne
|
|
|
3987
4095
|
});
|
|
3988
4096
|
// Tool: publish_theme
|
|
3989
4097
|
server.tool("publish_theme", "Publish the current theme LIVE — the same action as the editor's Publish button (uploads the whole project to the storefront). This is REAL and customer-facing: the published site changes. SAFETY: it publishes nothing unless `confirm: true` is passed; if you omit it you get a dry-run with the `previewUrl` and a warning describing the impact. The MAIN/production theme additionally requires `confirm_production: true` (its URL is the live customer-facing domain). Use this when the user explicitly asks to publish/go live — do NOT publish on your own initiative. On success returns `{ published: true, previewUrl, isMainTheme }`; open `previewUrl` to review the result. Requires `ikas-component dev` running with the editor connected.", {
|
|
3990
|
-
project_root: z
|
|
4098
|
+
project_root: z
|
|
4099
|
+
.string()
|
|
4100
|
+
.describe("Absolute path to the code-component project."),
|
|
3991
4101
|
confirm: z
|
|
3992
4102
|
.boolean()
|
|
3993
4103
|
.optional()
|
|
@@ -3996,7 +4106,10 @@ server.tool("publish_theme", "Publish the current theme LIVE — the same action
|
|
|
3996
4106
|
.boolean()
|
|
3997
4107
|
.optional()
|
|
3998
4108
|
.describe("Required IN ADDITION to confirm when the target is the MAIN/production theme (live customer-facing site)."),
|
|
3999
|
-
port: z
|
|
4109
|
+
port: z
|
|
4110
|
+
.number()
|
|
4111
|
+
.optional()
|
|
4112
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4000
4113
|
}, async ({ project_root, confirm, confirm_production, port }) => {
|
|
4001
4114
|
const args = [
|
|
4002
4115
|
"publish-theme",
|
|
@@ -4029,21 +4142,21 @@ const EDITOR_WORKFLOW_GUIDE = [
|
|
|
4029
4142
|
"- For a single section: list_imported_sections (confirm imported; else import_section, after building) → add_section_to_page(component_id, page_id, index?) → then list_page_sections to get its elementId.",
|
|
4030
4143
|
"",
|
|
4031
4144
|
"## Value shapes by prop type (what to pass as `value`)",
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4145
|
+
'- Scalars are WRAPPED: TEXT/RICH_TEXT { "value": "..." }, BOOLEAN { "value": true }, NUMBER { "value": 12 }, COLOR { "value": "#FF0000" }, ENUM { "value": "<key>" }, DATE { "value": ... }.',
|
|
4146
|
+
'- SVG is value-wrapped: { "value": "<svg markup>" }. NUMBER_RANGE: { "value": <number>, "unit": "px"|null }.',
|
|
4147
|
+
'- SVG naming: the editor shows each svg\'s `class` attribute as its display name in the list; add class="my-icon" to name it. SVG_LIST items with no class render as svg-1, svg-2, ….',
|
|
4148
|
+
'- Object props are NOT wrapped (no { "value": ... }):',
|
|
4149
|
+
' - IMAGE: { "id": "<asset-id>", "altText"?: "...", "isVideo"?: false } — get the id from upload_image. Same shape at section level AND nested in a component list. IMAGE_LIST: { "images": [ <image>, ... ] }.',
|
|
4150
|
+
' - VIDEO: { "video": { "id": "<asset-id>" }, "thumbnailImage"?: { "id": "..." }, "autoplay"?: false, "controls"?: true, "loop"?: false, "muted"?: false } — NOT a bare { "id": ... }. SVG_LIST: { "svgs": [ "<svg>", ... ] }.',
|
|
4151
|
+
' - LINK: { "id": "<unique>", "linkType": "PAGE"|"EXTERNAL"|"FILE", "label": "...", "subLinks": [] } plus target — for a static page: pageId + pageType (from list_editor_pages); for EXTERNAL: externalLink. To link to a CATEGORY/BRAND/BLOG/BLOG_CATEGORY entity, do NOT guess a slug — get the entity id from list_categories/list_brands/list_blogs/list_blog_categories and the page id from get_page_by_type(\'<TYPE>\'), then build { id, linkType:\'PAGE\', label, pageId:<pageId>, pageType:\'<TYPE>\', itemId:<entityId>, subLinks:[] }. LIST_OF_LINK = { "links": [ <link>, ... ] }.',
|
|
4152
|
+
' - Entity props PRODUCT/CATEGORY/BRAND/BLOG/BLOG_CATEGORY/RAFFLE: { "<entity>Id": "...", "usePageData"?: false } — e.g. { "productId": "...", "variantId"?: "..." }, { "categoryId": "..." }. Get real ids (never invent them) from: search_products (PRODUCT), list_categories (CATEGORY), list_brands (BRAND), list_blogs (BLOG), list_blog_categories (BLOG_CATEGORY). (RAFFLE has no lookup tool yet — read an existing value or ask the user.)',
|
|
4040
4153
|
" - List/collection props (PRODUCT_LIST/CATEGORY_LIST/BRAND_LIST/BLOG_LIST/…): typed objects keyed by a <entity>ListType discriminator plus initialSort/initialLimit. The id field DEPENDS on the type — for PRODUCT_LIST: STATIC → productIds:[{productId,variantId}] (from search_products); CATEGORY → category:'<categoryId>' (from list_categories) — the field is `category`, NOT `categoryId` (categoryId is ONLY the standalone CATEGORY entity prop above); ALL/DISCOUNTED/RECOMMENDED/etc → no id field. Get the exact field set + writeNote from get_component_props, or read+edit an existing value via get_section_values. Unknown sub-fields (e.g. categoryId inside a PRODUCT_LIST) are REJECTED.",
|
|
4041
|
-
|
|
4154
|
+
' - COMPONENT_LIST: { "components": [ { "id": "<unique>", "codeComponentId": "<child-id>", "propValues": { "<childProp>": <value>, ... } }, ... ] }. A single COMPONENT prop is one such entry. childProp values use these same per-type shapes, recursively.',
|
|
4042
4155
|
"",
|
|
4043
4156
|
"## COMPONENT_LIST rules (the part most often gotten wrong)",
|
|
4044
4157
|
"- READ-MODIFY-WRITE: update_section_prop REPLACES the whole prop value. To add/edit/remove one child, take the CURRENT { components: [...] } from get_section_values, edit it, and resend the ENTIRE array (with all existing entries and their ids). Sending only your new entry wipes the rest.",
|
|
4045
4158
|
"- Each entry needs a UNIQUE id (a short string you generate; it does not need to match anything). Do not reuse another entry's id.",
|
|
4046
|
-
|
|
4159
|
+
'- Reference a code component with "codeComponentId" and a built-in theme component with "componentId" — not the other way around. Use "propValues" (not "props").',
|
|
4047
4160
|
"- Child ids are opaque — take them from get_section_template / list_imported_sections; never invent them.",
|
|
4048
4161
|
"- Auto-import: a referenced child that is BUILT but not yet imported is imported automatically (returned under autoImported). A child that is not built at all errors — build it first.",
|
|
4049
4162
|
"",
|
|
@@ -4057,14 +4170,24 @@ const EDITOR_WORKFLOW_GUIDE = [
|
|
|
4057
4170
|
"Values are validated server-side (deeply, including nested children). Wrong shape or wrong semantics (double-encoded string, { value } wrapper on an object prop, props vs propValues, missing/duplicate id, wrong reference key, nonexistent component id, unknown prop name) are REJECTED with an explanatory error instead of being stored silently. Read the error and fix the value; if unsure of a shape, read it with get_section_values and match it.",
|
|
4058
4171
|
].join("\n");
|
|
4059
4172
|
server.tool("get_editor_workflow", "Read this FIRST when the user wants to place a section on a page or fill/edit a section's content (text, image, link, slides, component lists) in the live editor. Returns the complete step-by-step workflow for the live-editor tools (list_editor_pages, list_imported_sections, import_section, add_section_to_page, list_page_sections, update_section_prop, upload_image), the per-prop-type value shapes, the COMPONENT_LIST read-modify-write rules, and how validation/auto-import behave. Use it to avoid the common mistake of writing component code to set a value a section already supports.", {}, async () => {
|
|
4060
|
-
return {
|
|
4173
|
+
return {
|
|
4174
|
+
content: [{ type: "text", text: EDITOR_WORKFLOW_GUIDE }],
|
|
4175
|
+
};
|
|
4061
4176
|
});
|
|
4062
4177
|
// Tool: list_theme_globals
|
|
4063
4178
|
server.tool("list_theme_globals", "List the theme's global settings from the connected editor: global variables (Theme Settings) and design tokens (colors, typography, breakpoints, keyframes, color schemes). Call this BEFORE generating sections/components so you reuse the theme's existing variables and tokens (read them in component code via `getThemeSetting`/`getThemeColors`/... from `@ikas/bp-storefront`). Includes items created manually in the editor UI. Requires `ikas-component dev` running with the editor connected. Two shape gotchas when consuming the result at runtime: (1) color schemes — `colorSchemes.schemes` holds only `{id,name}` slot LABELS; the actual colors live in `colorSchemes.values[].colorsByScheme` keyed by slot id, so iterate `values[].colorsByScheme` (iterating `schemes` renders empty). (2) An IMAGE setting's `value` is an image REFERENCE like `{id:'theme-images/<uuid>'}` with no `.url` — resolve it via `getDefaultSrc`/`getSrc`. (3) Each keyframe now includes its animation `settings` (type-dependent { property, value } entries — duration/iteration/timing/etc. for keyframe, transition for transition) and each point's resolved `styles`, so you can read back the full animation config, not just the `ref`. (4) Each typography entry may include `supportedFontWeights` — the exact numeric weights that text style's font actually ships (e.g. `[400]` for Modak); when present, only set `font_weight` to a value in this list (via `update_text_style`/`create_theme_global`), otherwise the write is rejected. If the field is absent the font's weight set couldn't be determined — fall back to 400 or rely on the validation error. (5) Token NAMES are NOT unique — a theme can contain two tokens with the SAME name (e.g. colors pulled from two different design assets), so NEVER match a token by its human name. ALWAYS identify a token by its `id` (globally unique). IN COMPONENT CODE: prefer embedding the token's id-derived STABLE ref directly — color → cssVar `var(--<id>)`, typography → `className` `_<id>`, keyframe (animation-name) → `ref` `_<id>` — so you don't look anything up at runtime. If you DO need to pick a token out of a `getThemeColors()` / `getThemeTypography()` / `getThemeKeyframes()` / `getThemeColorSchemes()` array, match on `.id` (e.g. `getThemeColors().find(c => c.id === \"<id>\")`), NEVER on `.name`. EXCEPTION — global variables/settings: `getThemeSetting(name)` takes the token's `name`, but here `name` is the unique runtime key (`variableName`, the `_<id>` form returned in this list), which IS safe; do NOT pass a setting's human `displayName`. The update/delete tools also identify a token ONLY by `id` (they do NOT look up by name — on those tools `name` means the NEW name when renaming). Always take the `id` (or, for settings, the `name`/variableName) from THIS list. (6) GROUPING convention: a \"/\" in a token's NAME organizes it into a group in the editor UI — the text before the first \"/\" is the group, the rest is the item label. This applies to COLORS (e.g. \"Brand/Primary\"), TEXT STYLES (e.g. \"Heading/H1\"), and COLOR-SCHEME SLOTS (e.g. \"PrimaryButton/Background\"). When you create globals (via `create_theme_global`/`update_theme_color_scheme`), use \"/\"-prefixed names to keep related tokens grouped and tidy; reuse an existing group's exact prefix so they nest together.", {
|
|
4064
|
-
project_root: z
|
|
4065
|
-
|
|
4179
|
+
project_root: z
|
|
4180
|
+
.string()
|
|
4181
|
+
.describe("Absolute path to the code-component project (where `node_modules/.bin/ikas-component` lives)."),
|
|
4182
|
+
port: z
|
|
4183
|
+
.number()
|
|
4184
|
+
.optional()
|
|
4185
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4066
4186
|
}, async ({ project_root, port }) => {
|
|
4067
|
-
const args = [
|
|
4187
|
+
const args = [
|
|
4188
|
+
"list-theme-globals",
|
|
4189
|
+
...(port ? ["--port", String(port)] : []),
|
|
4190
|
+
];
|
|
4068
4191
|
return callEditorAction(project_root, args);
|
|
4069
4192
|
});
|
|
4070
4193
|
// Shared text-style (typography) font-property schema — kept in lock-step with the editor's
|
|
@@ -4072,25 +4195,48 @@ server.tool("list_theme_globals", "List the theme's global settings from the con
|
|
|
4072
4195
|
// Each enum prop documents its accepted values so a bad value is caught with a clear error. Spread
|
|
4073
4196
|
// into both create_theme_global (typography) and update_text_style so the two never drift apart.
|
|
4074
4197
|
const textStyleFontParams = {
|
|
4075
|
-
font_family: z
|
|
4198
|
+
font_family: z
|
|
4199
|
+
.string()
|
|
4200
|
+
.optional()
|
|
4201
|
+
.describe('A real font family the editor offers — a Google Fonts name with EXACT casing (e.g. "Inter", "Roboto", ' +
|
|
4202
|
+
'"Poppins"), or a font already used by an existing text style in list_theme_globals. An unknown font ' +
|
|
4203
|
+
"(or wrong casing) is rejected; do NOT invent a family name."),
|
|
4076
4204
|
font_size: z.string().optional(),
|
|
4077
4205
|
font_weight: z
|
|
4078
4206
|
.string()
|
|
4079
4207
|
.optional()
|
|
4080
|
-
.describe(
|
|
4081
|
-
|
|
4208
|
+
.describe('font-weight as a number (e.g. "600"); append \'i\' for italic (e.g. "600i"). Must be a weight the chosen ' +
|
|
4209
|
+
'font ships — if it isn\'t, the error lists the supported weights; when unsure use "400".'),
|
|
4082
4210
|
line_height: z.string().optional(),
|
|
4083
4211
|
letter_spacing: z.string().optional(),
|
|
4084
|
-
text_decoration: z
|
|
4085
|
-
|
|
4086
|
-
|
|
4212
|
+
text_decoration: z
|
|
4213
|
+
.string()
|
|
4214
|
+
.optional()
|
|
4215
|
+
.describe("text-decoration: none | underline | line-through"),
|
|
4216
|
+
text_transform: z
|
|
4217
|
+
.string()
|
|
4218
|
+
.optional()
|
|
4219
|
+
.describe("text-transform: none | uppercase | lowercase | capitalize"),
|
|
4220
|
+
text_overflow: z
|
|
4221
|
+
.string()
|
|
4222
|
+
.optional()
|
|
4223
|
+
.describe("text-overflow: clip | ellipsis"),
|
|
4087
4224
|
white_space: z
|
|
4088
4225
|
.string()
|
|
4089
4226
|
.optional()
|
|
4090
4227
|
.describe("white-space: normal | pre | pre-wrap | pre-line | wrap | nowrap | collapse"),
|
|
4091
|
-
line_break: z
|
|
4092
|
-
|
|
4093
|
-
|
|
4228
|
+
line_break: z
|
|
4229
|
+
.string()
|
|
4230
|
+
.optional()
|
|
4231
|
+
.describe("line-break: auto | loose | normal | strict | anywhere"),
|
|
4232
|
+
word_break: z
|
|
4233
|
+
.string()
|
|
4234
|
+
.optional()
|
|
4235
|
+
.describe("word-break: normal | break-all | keep-all"),
|
|
4236
|
+
text_wrap_style: z
|
|
4237
|
+
.string()
|
|
4238
|
+
.optional()
|
|
4239
|
+
.describe("text-wrap-style: auto | balance | pretty | stable"),
|
|
4094
4240
|
};
|
|
4095
4241
|
// Turn the supplied text-style font params into `ikas-component` CLI flags (omitted ones dropped).
|
|
4096
4242
|
// The editor validates each value and rejects an unsupported one with the offending value + allowed set.
|
|
@@ -4109,27 +4255,46 @@ function textStyleFontArgs(input) {
|
|
|
4109
4255
|
"--word-break": input.word_break,
|
|
4110
4256
|
"--text-wrap-style": input.text_wrap_style,
|
|
4111
4257
|
};
|
|
4112
|
-
return Object.entries(map).flatMap(([flag, value]) =>
|
|
4258
|
+
return Object.entries(map).flatMap(([flag, value]) => value ? [flag, value] : []);
|
|
4113
4259
|
}
|
|
4114
4260
|
// Tool: create_theme_global
|
|
4115
4261
|
server.tool("create_theme_global", "Create a theme global setting in the connected editor. `kind` selects what to create:\n" +
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4262
|
+
'- globalVariable: requires display_name + type (TEXT|RICH_TEXT|IMAGE|COLOR|NUMBER|BOOLEAN|BORDER|SHADOW); value optional. Pass `value` as a REAL JSON value, never a stringified JSON. Value shapes — TEXT/COLOR: string; RICH_TEXT: HTML string; NUMBER: number; BOOLEAN: real JSON boolean true/false (NOT the string "true"); IMAGE: an image REFERENCE object { id: "theme-images/<uuid>" } (NOT { url }) — get a real id from list_theme_globals; do NOT invent/fabricate an id, omit value instead if you don\'t have one; BORDER: { width: { value, unit }, style, color }; SHADOW: { x, y, blur, spread, color, position: "outside"|"inside" }. For object types (IMAGE/BORDER/SHADOW) pass an actual JSON object, not a JSON-encoded string.\n' +
|
|
4263
|
+
'- color: requires name + value — a CONCRETE color (hex e.g. "#ff0000", rgb()/hsl() or a CSS color name). A color token cannot alias another color, so a "var(...)" reference is REJECTED here (to reuse another theme color, reference its cssVar in component code, or in a colorScheme slot). TIP: a "/" in the `name` GROUPS the color in the editor UI (e.g. "Brand/Primary", "Brand/Accent" appear under a "Brand" group); use this to organize related colors. To CHANGE an existing color later, use `update_theme_color` (edits in place, keeps the cssVar stable) — do NOT delete+recreate.\n' +
|
|
4264
|
+
'- typography: requires name + at least one text-style property. These are exactly the fields the editor\'s "Update Text Style" modal exposes — nothing else (in particular there is NO color or text-align on a text style). VALUE FORMATS (all validated; a bad value is rejected with the offending value and the allowed set): font_weight is one of 100,200,300,400,500,600,700,800,900 (append \'i\' for italic, e.g. "600i") AND must be a weight the chosen font actually ships (many fonts provide only a subset, e.g. "Modak" only ships 400) — if unavailable the call fails and lists the supported weights, so when unsure use 400; stored as a numeric weight + a font-style entry; font_size is a number WITH a unit (e.g. "16px", "1.2rem", "80%"); line_height is "normal", a unitless number (e.g. "1.5") or a length; letter_spacing is "normal" or a length (e.g. "0.02em", "0.5px"); font_family is a real font the editor offers (a Google Fonts name with EXACT casing, e.g. "Inter") — an unknown/invented family is rejected; text_decoration is none|underline|line-through; text_transform is none|uppercase|lowercase|capitalize; text_overflow is clip|ellipsis; white_space is normal|pre|pre-wrap|pre-line|wrap|nowrap|collapse; line_break is auto|loose|normal|strict|anywhere; word_break is normal|break-all|keep-all; text_wrap_style is auto|balance|pretty|stable. TIP: a "/" in the `name` GROUPS the text style in the editor UI (e.g. "Heading/H1", "Heading/H2" appear under a "Heading" group); use this to organize related styles. To CHANGE an existing text style later, use `update_text_style` (edits in place, keeps the `className` stable) — do NOT delete+recreate, which changes the id/className.\n' +
|
|
4119
4265
|
"- breakpoint: requires name + width (a positive INTEGER, in px — no decimals). To CHANGE an existing breakpoint later, use `update_theme_breakpoint` (edits in place, keeps the id).\n" +
|
|
4120
4266
|
"- keyframe: requires name + points (array of { point, styles? }) where each style is { property, value } using a CSS property name (opacity, transform, filter, background, color, …); keyframe_type defaults to \"keyframe\". Optional `settings` = animation-level config as { property, value } entries, TYPE-DEPENDENT: for keyframe — animation-duration, animation-iteration-count, animation-play-state, animation-delay, animation-timing-function, animation-direction, animation-fill-mode, animation-timeline, animation-range, transform-origin, backface-visibility; for transition — transition, backface-visibility. Setting these means the editor drives the animation timing (you don't have to hand-write `animation:` CSS). Use the keyframe's `ref` as the CSS animation-name. For a TRANSITION keyframe, put the target/hover-state styles on the 100% point (points[1].styles) — the 0% point is ignored (the start state is the element's own normal state). To CHANGE an existing keyframe later, use `update_theme_keyframe` (edits in place, keeps the `ref` stable) — do NOT delete+recreate, which changes the ref and breaks references.\n" +
|
|
4121
|
-
|
|
4267
|
+
'- colorScheme: requires name + colors (array of { slotId? | newSlotName?, value }) — each color targets ONE color SLOT, EITHER by `slotId` (an EXISTING slot\'s id, from `list_theme_globals` → colorSchemes.schemes[].id or a `colorsByScheme` key — the id-keyed path) OR by `newSlotName` (a name to CREATE-or-reuse a slot; write-only, for the standard vocabulary and brand-new slots). Pass EXACTLY ONE of the two per entry. `value` is EITHER a literal color (hex/rgb/hsl or a CSS color name, e.g. "#0b1120") OR a REFERENCE to an existing theme color, passed as that color\'s cssVar from `list_theme_globals` (e.g. "var(--<colorId>)"). A `var(--id)` value is stored as a linked reference (editing the global color updates the scheme too and the dependency is tracked) — do NOT inline a hex you copied from a global color; pass its cssVar. SLOT IDENTITY: `colorSchemes.schemes` lists each slot as `{id, name}`. To set a color on an EXISTING slot, find it there by name and pass its `slotId` (names are NOT unique — two design assets can each have a "Background" — so when ambiguous disambiguate via the scheme\'s existing `colorsByScheme` keys); use `newSlotName` only to add a slot the scheme does not have yet. When creating slots use the theme\'s STANDARD slot names so components resolve them: "Background", "Heading", "Text", "Link", "HoverLink", "Border", and per button "PrimaryButton/Background", "PrimaryButton/Text", "PrimaryButton/Border", "PrimaryButton/HoverBackground", "PrimaryButton/HoverText", "PrimaryButton/HoverBorder" (and the same six under "SecondaryButton/"); a "/" groups the slot in the editor UI. A scheme should normally define EVERY slot it uses; omitted slots fall back to the default scheme\'s color. A mistaken slot can be removed with `delete_theme_global` kind `colorSchemeSlot` (by slot id), or renamed in place (id stays stable) with `rename_theme_color_scheme_slot`. To CHANGE an existing scheme later, use `update_theme_color_scheme` (edits in place, keeps the className stable; merges colors by slot, and can set/clear its default flag via `is_default`).\n' +
|
|
4122
4268
|
"Read created items back with `list_theme_globals`. Requires `ikas-component dev` running with the editor connected.", {
|
|
4123
|
-
project_root: z
|
|
4269
|
+
project_root: z
|
|
4270
|
+
.string()
|
|
4271
|
+
.describe("Absolute path to the code-component project."),
|
|
4124
4272
|
kind: z
|
|
4125
|
-
.enum([
|
|
4273
|
+
.enum([
|
|
4274
|
+
"globalVariable",
|
|
4275
|
+
"color",
|
|
4276
|
+
"typography",
|
|
4277
|
+
"breakpoint",
|
|
4278
|
+
"keyframe",
|
|
4279
|
+
"colorScheme",
|
|
4280
|
+
])
|
|
4126
4281
|
.describe("What to create."),
|
|
4127
4282
|
name: z.string().optional().describe("Name (design tokens)."),
|
|
4128
|
-
display_name: z
|
|
4283
|
+
display_name: z
|
|
4284
|
+
.string()
|
|
4285
|
+
.optional()
|
|
4286
|
+
.describe("Human label (globalVariable)."),
|
|
4129
4287
|
type: z.string().optional().describe("globalVariable value type."),
|
|
4130
|
-
value: z
|
|
4288
|
+
value: z
|
|
4289
|
+
.any()
|
|
4290
|
+
.optional()
|
|
4291
|
+
.describe("globalVariable default value (shape depends on type — see tool description), or color hex string."),
|
|
4131
4292
|
...textStyleFontParams,
|
|
4132
|
-
width: z
|
|
4293
|
+
width: z
|
|
4294
|
+
.number()
|
|
4295
|
+
.int()
|
|
4296
|
+
.optional()
|
|
4297
|
+
.describe("breakpoint width in px (positive integer, no decimals)."),
|
|
4133
4298
|
keyframe_type: z.enum(["keyframe", "transition"]).optional(),
|
|
4134
4299
|
points: z.any().optional().describe("keyframe points array."),
|
|
4135
4300
|
settings: z
|
|
@@ -4139,8 +4304,11 @@ server.tool("create_theme_global", "Create a theme global setting in the connect
|
|
|
4139
4304
|
colors: z
|
|
4140
4305
|
.any()
|
|
4141
4306
|
.optional()
|
|
4142
|
-
.describe(
|
|
4143
|
-
port: z
|
|
4307
|
+
.describe('colorScheme colors: array of { slotId? | newSlotName?, value } — target an EXISTING slot by `slotId` (its id from list_theme_globals → colorSchemes.schemes / colorsByScheme keys) OR create/reuse one by `newSlotName` (use the standard slot names, "/" to group, e.g. "PrimaryButton/Background"). Exactly one per entry. value = a literal color hex/rgb/hsl/name, OR an existing theme color\'s cssVar "var(--<colorId>)" to store a linked reference.'),
|
|
4308
|
+
port: z
|
|
4309
|
+
.number()
|
|
4310
|
+
.optional()
|
|
4311
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4144
4312
|
}, async (input) => {
|
|
4145
4313
|
const p = input.port ? ["--port", String(input.port)] : [];
|
|
4146
4314
|
let args;
|
|
@@ -4152,18 +4320,40 @@ server.tool("create_theme_global", "Create a theme global setting in the connect
|
|
|
4152
4320
|
String(input.display_name ?? ""),
|
|
4153
4321
|
"--type",
|
|
4154
4322
|
String(input.type ?? ""),
|
|
4155
|
-
...(input.value !== undefined
|
|
4323
|
+
...(input.value !== undefined
|
|
4324
|
+
? ["--value", JSON.stringify(input.value)]
|
|
4325
|
+
: []),
|
|
4156
4326
|
...p,
|
|
4157
4327
|
];
|
|
4158
4328
|
break;
|
|
4159
4329
|
case "color":
|
|
4160
|
-
args = [
|
|
4330
|
+
args = [
|
|
4331
|
+
"create-color",
|
|
4332
|
+
"--name",
|
|
4333
|
+
String(input.name ?? ""),
|
|
4334
|
+
"--value",
|
|
4335
|
+
String(input.value ?? ""),
|
|
4336
|
+
...p,
|
|
4337
|
+
];
|
|
4161
4338
|
break;
|
|
4162
4339
|
case "typography":
|
|
4163
|
-
args = [
|
|
4340
|
+
args = [
|
|
4341
|
+
"create-text-style",
|
|
4342
|
+
"--name",
|
|
4343
|
+
String(input.name ?? ""),
|
|
4344
|
+
...textStyleFontArgs(input),
|
|
4345
|
+
...p,
|
|
4346
|
+
];
|
|
4164
4347
|
break;
|
|
4165
4348
|
case "breakpoint":
|
|
4166
|
-
args = [
|
|
4349
|
+
args = [
|
|
4350
|
+
"create-breakpoint",
|
|
4351
|
+
"--name",
|
|
4352
|
+
String(input.name ?? ""),
|
|
4353
|
+
"--width",
|
|
4354
|
+
String(input.width ?? ""),
|
|
4355
|
+
...p,
|
|
4356
|
+
];
|
|
4167
4357
|
break;
|
|
4168
4358
|
case "keyframe":
|
|
4169
4359
|
args = [
|
|
@@ -4173,7 +4363,9 @@ server.tool("create_theme_global", "Create a theme global setting in the connect
|
|
|
4173
4363
|
...(input.keyframe_type ? ["--type", input.keyframe_type] : []),
|
|
4174
4364
|
"--points",
|
|
4175
4365
|
toJsonArrayArg(input.points),
|
|
4176
|
-
...(input.settings !== undefined
|
|
4366
|
+
...(input.settings !== undefined
|
|
4367
|
+
? ["--settings", toJsonArrayArg(input.settings)]
|
|
4368
|
+
: []),
|
|
4177
4369
|
...p,
|
|
4178
4370
|
];
|
|
4179
4371
|
break;
|
|
@@ -4188,18 +4380,38 @@ server.tool("create_theme_global", "Create a theme global setting in the connect
|
|
|
4188
4380
|
];
|
|
4189
4381
|
break;
|
|
4190
4382
|
default:
|
|
4191
|
-
return {
|
|
4383
|
+
return {
|
|
4384
|
+
content: [
|
|
4385
|
+
{
|
|
4386
|
+
type: "text",
|
|
4387
|
+
text: `Error: unknown kind "${input.kind}"`,
|
|
4388
|
+
},
|
|
4389
|
+
],
|
|
4390
|
+
};
|
|
4192
4391
|
}
|
|
4193
4392
|
return callEditorAction(input.project_root, args);
|
|
4194
4393
|
});
|
|
4195
4394
|
// Tool: update_theme_global
|
|
4196
|
-
server.tool("update_theme_global",
|
|
4197
|
-
project_root: z
|
|
4198
|
-
|
|
4395
|
+
server.tool("update_theme_global", 'Update an existing global variable in the connected editor (e.g. fix its value or change its type). Identify it by `name` (the runtime key from `list_theme_globals`). Only the fields you pass are changed. Value shapes follow `create_theme_global` — pass `value` as REAL JSON (objects/booleans, never stringified); IMAGE is an image REFERENCE object { id: "theme-images/<uuid>" } (NOT { url }), BOOLEAN is a real boolean, BORDER/SHADOW are real objects.', {
|
|
4396
|
+
project_root: z
|
|
4397
|
+
.string()
|
|
4398
|
+
.describe("Absolute path to the code-component project."),
|
|
4399
|
+
name: z
|
|
4400
|
+
.string()
|
|
4401
|
+
.describe("The variable's runtime key (from `list_theme_globals`)."),
|
|
4199
4402
|
display_name: z.string().optional().describe("New label."),
|
|
4200
|
-
type: z
|
|
4201
|
-
|
|
4202
|
-
|
|
4403
|
+
type: z
|
|
4404
|
+
.string()
|
|
4405
|
+
.optional()
|
|
4406
|
+
.describe("New value type (TEXT|RICH_TEXT|IMAGE|COLOR|NUMBER|BOOLEAN|BORDER|SHADOW)."),
|
|
4407
|
+
value: z
|
|
4408
|
+
.any()
|
|
4409
|
+
.optional()
|
|
4410
|
+
.describe('New value as REAL JSON (shape depends on type; e.g. IMAGE: { id: "theme-images/<uuid>" }, BOOLEAN: true/false — see create_theme_global).'),
|
|
4411
|
+
port: z
|
|
4412
|
+
.number()
|
|
4413
|
+
.optional()
|
|
4414
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4203
4415
|
}, async ({ project_root, name, display_name, type, value, port }) => {
|
|
4204
4416
|
const args = [
|
|
4205
4417
|
"update-global-variable",
|
|
@@ -4219,26 +4431,38 @@ server.tool("update_theme_keyframe", "Update an existing theme keyframe IN PLACE
|
|
|
4219
4431
|
"`list_theme_globals`); name-based lookup is intentionally NOT supported here because names can collide across " +
|
|
4220
4432
|
"design assets. To rename, pass `name` (the new name) together with `id`. " +
|
|
4221
4433
|
"`points` REPLACES the keyframe's points: an array of { point, styles? } where `point` is a CSS " +
|
|
4222
|
-
|
|
4434
|
+
'keyframe offset (e.g. "0%", "50%", "100%") and each style is { property, value } using a CSS property ' +
|
|
4223
4435
|
"name (opacity, transform, filter, background, color, …). Pass `points` as REAL JSON (not a stringified array). " +
|
|
4224
4436
|
"For a TRANSITION keyframe, put the target/hover-state styles on the 100% point (points[1].styles) — the 0% " +
|
|
4225
4437
|
"point is ignored (the start state is the element's own normal state). " +
|
|
4226
4438
|
"Optional `settings` REPLACES the keyframe's animation settings (type-dependent { property, value } entries — " +
|
|
4227
4439
|
"see `create_theme_global`); OMIT it to keep the existing settings, or pass [] to clear them. " +
|
|
4228
4440
|
"Requires `ikas-component dev` running with the editor connected.", {
|
|
4229
|
-
project_root: z
|
|
4230
|
-
|
|
4441
|
+
project_root: z
|
|
4442
|
+
.string()
|
|
4443
|
+
.describe("Absolute path to the code-component project."),
|
|
4444
|
+
id: z
|
|
4445
|
+
.string()
|
|
4446
|
+
.describe("Keyframe id (REQUIRED) from `list_theme_globals`. The token is always identified by id."),
|
|
4231
4447
|
name: z
|
|
4232
4448
|
.string()
|
|
4233
4449
|
.optional()
|
|
4234
4450
|
.describe("Optional NEW name to rename the keyframe to. NOT used to find the token — lookup is always by id."),
|
|
4235
|
-
keyframe_type: z
|
|
4236
|
-
|
|
4451
|
+
keyframe_type: z
|
|
4452
|
+
.enum(["keyframe", "transition"])
|
|
4453
|
+
.optional()
|
|
4454
|
+
.describe("Optional new keyframe type."),
|
|
4455
|
+
points: z
|
|
4456
|
+
.any()
|
|
4457
|
+
.describe("New keyframe points array of { point, styles? } — REPLACES the existing points."),
|
|
4237
4458
|
settings: z
|
|
4238
4459
|
.any()
|
|
4239
4460
|
.optional()
|
|
4240
4461
|
.describe("New animation settings { property, value } array (type-dependent — see create_theme_global). Omit to keep existing; [] to clear."),
|
|
4241
|
-
port: z
|
|
4462
|
+
port: z
|
|
4463
|
+
.number()
|
|
4464
|
+
.optional()
|
|
4465
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4242
4466
|
}, async ({ project_root, id, name, keyframe_type, points, settings, port }) => {
|
|
4243
4467
|
const args = [
|
|
4244
4468
|
"update-keyframe",
|
|
@@ -4248,7 +4472,9 @@ server.tool("update_theme_keyframe", "Update an existing theme keyframe IN PLACE
|
|
|
4248
4472
|
...(keyframe_type ? ["--type", keyframe_type] : []),
|
|
4249
4473
|
"--points",
|
|
4250
4474
|
toJsonArrayArg(points),
|
|
4251
|
-
...(settings !== undefined
|
|
4475
|
+
...(settings !== undefined
|
|
4476
|
+
? ["--settings", toJsonArrayArg(settings)]
|
|
4477
|
+
: []),
|
|
4252
4478
|
...(port ? ["--port", String(port)] : []),
|
|
4253
4479
|
];
|
|
4254
4480
|
return callEditorAction(project_root, args);
|
|
@@ -4259,25 +4485,34 @@ server.tool("update_text_style", "Update an existing theme typography token (tex
|
|
|
4259
4485
|
"stays STABLE. Identify the text style by `id` (REQUIRED — globally unique, from `list_theme_globals`); " +
|
|
4260
4486
|
"name-based lookup is intentionally NOT supported here because names can collide across design assets. " +
|
|
4261
4487
|
"To rename, pass `name` (the new name) together with `id`. Pass only the properties you want to change; omitted " +
|
|
4262
|
-
|
|
4488
|
+
'ones keep their existing values. The settable properties are exactly the editor\'s "Update Text Style" modal ' +
|
|
4263
4489
|
"fields — there is NO color or text-align on a text style. VALUE FORMATS (all validated; a bad value is rejected " +
|
|
4264
4490
|
"with the offending value and the allowed set): font_weight is one of 100…900 (append 'i' for italic, e.g. " +
|
|
4265
|
-
"
|
|
4491
|
+
'"600i") AND must be a weight the chosen font actually ships — many fonts only provide a subset (e.g. "Modak" ' +
|
|
4266
4492
|
"only ships 400); if a weight isn't available the call fails and the error lists the supported weights, so when " +
|
|
4267
|
-
|
|
4268
|
-
|
|
4493
|
+
'unsure use 400; font_size is a number with a unit (e.g. "16px"); line_height is "normal", a unitless number ' +
|
|
4494
|
+
'or a length; letter_spacing is "normal" or a length (e.g. "0.02em"); font_family is a real font the editor ' +
|
|
4495
|
+
'offers (a Google Fonts name with EXACT casing, e.g. "Inter") — an unknown/invented family is rejected; ' +
|
|
4496
|
+
"text_decoration is none|underline|" +
|
|
4269
4497
|
"line-through; text_transform is none|uppercase|lowercase|capitalize; text_overflow is clip|ellipsis; white_space " +
|
|
4270
4498
|
"is normal|pre|pre-wrap|pre-line|wrap|nowrap|collapse; line_break is auto|loose|normal|strict|anywhere; word_break " +
|
|
4271
4499
|
"is normal|break-all|keep-all; text_wrap_style is auto|balance|pretty|stable. Requires `ikas-component dev` " +
|
|
4272
4500
|
"running with the editor connected.", {
|
|
4273
|
-
project_root: z
|
|
4274
|
-
|
|
4501
|
+
project_root: z
|
|
4502
|
+
.string()
|
|
4503
|
+
.describe("Absolute path to the code-component project."),
|
|
4504
|
+
id: z
|
|
4505
|
+
.string()
|
|
4506
|
+
.describe("Text style id (REQUIRED) from `list_theme_globals`. The token is always identified by id."),
|
|
4275
4507
|
name: z
|
|
4276
4508
|
.string()
|
|
4277
4509
|
.optional()
|
|
4278
4510
|
.describe("Optional NEW name to rename the text style to. NOT used to find the token — lookup is always by id."),
|
|
4279
4511
|
...textStyleFontParams,
|
|
4280
|
-
port: z
|
|
4512
|
+
port: z
|
|
4513
|
+
.number()
|
|
4514
|
+
.optional()
|
|
4515
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4281
4516
|
}, async (input) => {
|
|
4282
4517
|
const { project_root, id, name, port } = input;
|
|
4283
4518
|
const args = [
|
|
@@ -4296,11 +4531,15 @@ server.tool("update_theme_color", "Update an existing theme color token IN PLACE
|
|
|
4296
4531
|
"Identify it by `id` (REQUIRED — globally unique, from `list_theme_globals`); name-based lookup is intentionally " +
|
|
4297
4532
|
"NOT supported here because a theme can have two colors with the same name (e.g. from two different design assets). " +
|
|
4298
4533
|
"To rename, pass `name` (the new name) together with `id`. Pass `value` to change the color — a CONCRETE " +
|
|
4299
|
-
|
|
4534
|
+
'color (hex/rgb/hsl or a CSS color name), NOT a "var(...)" reference (a color token can\'t alias another ' +
|
|
4300
4535
|
"color); omit it to only rename. Requires `ikas-component " +
|
|
4301
4536
|
"dev` running with the editor connected.", {
|
|
4302
|
-
project_root: z
|
|
4303
|
-
|
|
4537
|
+
project_root: z
|
|
4538
|
+
.string()
|
|
4539
|
+
.describe("Absolute path to the code-component project."),
|
|
4540
|
+
id: z
|
|
4541
|
+
.string()
|
|
4542
|
+
.describe("Color id (REQUIRED) from `list_theme_globals`. The token is always identified by id."),
|
|
4304
4543
|
name: z
|
|
4305
4544
|
.string()
|
|
4306
4545
|
.optional()
|
|
@@ -4309,7 +4548,10 @@ server.tool("update_theme_color", "Update an existing theme color token IN PLACE
|
|
|
4309
4548
|
.string()
|
|
4310
4549
|
.optional()
|
|
4311
4550
|
.describe('New color value — a concrete color (e.g. "#ff0000", rgb/hsl/name), not a "var(...)" reference. Omit to only rename.'),
|
|
4312
|
-
port: z
|
|
4551
|
+
port: z
|
|
4552
|
+
.number()
|
|
4553
|
+
.optional()
|
|
4554
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4313
4555
|
}, async ({ project_root, id, name, value, port }) => {
|
|
4314
4556
|
const args = [
|
|
4315
4557
|
"update-color",
|
|
@@ -4327,14 +4569,25 @@ server.tool("update_theme_breakpoint", "Update an existing theme breakpoint IN P
|
|
|
4327
4569
|
"because names can collide across design assets. To rename, pass `name` (the new name) together with `id`. " +
|
|
4328
4570
|
"Pass `width` (px) to change it; omit it to only rename. " +
|
|
4329
4571
|
"Requires `ikas-component dev` running with the editor connected.", {
|
|
4330
|
-
project_root: z
|
|
4331
|
-
|
|
4572
|
+
project_root: z
|
|
4573
|
+
.string()
|
|
4574
|
+
.describe("Absolute path to the code-component project."),
|
|
4575
|
+
id: z
|
|
4576
|
+
.string()
|
|
4577
|
+
.describe("Breakpoint id (REQUIRED) from `list_theme_globals`. The token is always identified by id."),
|
|
4332
4578
|
name: z
|
|
4333
4579
|
.string()
|
|
4334
4580
|
.optional()
|
|
4335
4581
|
.describe("Optional NEW name to rename the breakpoint to. NOT used to find the token — lookup is always by id."),
|
|
4336
|
-
width: z
|
|
4337
|
-
|
|
4582
|
+
width: z
|
|
4583
|
+
.number()
|
|
4584
|
+
.int()
|
|
4585
|
+
.optional()
|
|
4586
|
+
.describe("New breakpoint width in px (positive integer, no decimals). Omit to only rename."),
|
|
4587
|
+
port: z
|
|
4588
|
+
.number()
|
|
4589
|
+
.optional()
|
|
4590
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4338
4591
|
}, async ({ project_root, id, name, width, port }) => {
|
|
4339
4592
|
const args = [
|
|
4340
4593
|
"update-breakpoint",
|
|
@@ -4354,8 +4607,8 @@ server.tool("update_theme_color_scheme", "Update an existing theme color scheme
|
|
|
4354
4607
|
"`colors` is an array of { slotId? | newSlotName?, value } — each entry targets ONE slot, EITHER by " +
|
|
4355
4608
|
"`slotId` (an EXISTING slot's id, from list_theme_globals colorsByScheme keys / colorSchemes.schemes — the " +
|
|
4356
4609
|
"id-keyed path; slot names ARE listed in colorSchemes.schemes but are not unique, so prefer the scheme's colorsByScheme keys to get the right id) OR by `newSlotName` (create/reuse " +
|
|
4357
|
-
|
|
4358
|
-
|
|
4610
|
+
'a slot by name; use the standard slot names, "/" to group, e.g. "PrimaryButton/Background"); value = a ' +
|
|
4611
|
+
'literal color hex/rgb/hsl/name, OR an existing theme color\'s cssVar "var(--<colorId>)" from ' +
|
|
4359
4612
|
"list_theme_globals to store it as a LINKED reference — pass the cssVar, not a hex copied from a global color) " +
|
|
4360
4613
|
"and MERGES by slot — only the slots you pass change. Pass `colors` as REAL " +
|
|
4361
4614
|
"JSON (not a stringified array). Set `is_default: true` to make this the theme's DEFAULT scheme (the " +
|
|
@@ -4363,8 +4616,12 @@ server.tool("update_theme_color_scheme", "Update an existing theme color scheme
|
|
|
4363
4616
|
"automatically clears the default flag from any other scheme in the same group, so there is always exactly " +
|
|
4364
4617
|
"one default. Set `is_default: false` to remove the default flag from this scheme. Omit all of name/colors/" +
|
|
4365
4618
|
"is_default to no-op. Requires `ikas-component dev` running with the editor connected.", {
|
|
4366
|
-
project_root: z
|
|
4367
|
-
|
|
4619
|
+
project_root: z
|
|
4620
|
+
.string()
|
|
4621
|
+
.describe("Absolute path to the code-component project."),
|
|
4622
|
+
id: z
|
|
4623
|
+
.string()
|
|
4624
|
+
.describe("Color scheme id (REQUIRED) from `list_theme_globals`. The token is always identified by id."),
|
|
4368
4625
|
name: z
|
|
4369
4626
|
.string()
|
|
4370
4627
|
.optional()
|
|
@@ -4372,12 +4629,15 @@ server.tool("update_theme_color_scheme", "Update an existing theme color scheme
|
|
|
4372
4629
|
colors: z
|
|
4373
4630
|
.any()
|
|
4374
4631
|
.optional()
|
|
4375
|
-
.describe(
|
|
4632
|
+
.describe('Array of { slotId? | newSlotName?, value } to set — target an existing slot by `slotId` (from list_theme_globals colorsByScheme keys / colorSchemes.schemes) or create/reuse by `newSlotName`; value = a literal color hex/rgb/hsl/name, OR an existing theme color\'s cssVar "var(--<colorId>)" (linked reference). Merges by slot. Omit to only rename.'),
|
|
4376
4633
|
is_default: z
|
|
4377
4634
|
.boolean()
|
|
4378
4635
|
.optional()
|
|
4379
4636
|
.describe("true = make this the default scheme (exclusive — the editor clears the default flag from every other scheme in its group); false = remove the default flag. Omit to leave the default unchanged. The result echoes the persisted `isDefault`."),
|
|
4380
|
-
port: z
|
|
4637
|
+
port: z
|
|
4638
|
+
.number()
|
|
4639
|
+
.optional()
|
|
4640
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4381
4641
|
}, async ({ project_root, id, name, colors, is_default, port }) => {
|
|
4382
4642
|
const args = [
|
|
4383
4643
|
"update-color-scheme",
|
|
@@ -4385,23 +4645,29 @@ server.tool("update_theme_color_scheme", "Update an existing theme color scheme
|
|
|
4385
4645
|
id,
|
|
4386
4646
|
...(name !== undefined ? ["--name", name] : []),
|
|
4387
4647
|
...(colors !== undefined ? ["--colors", toJsonArrayArg(colors)] : []),
|
|
4388
|
-
...(is_default === true
|
|
4648
|
+
...(is_default === true
|
|
4649
|
+
? ["--default"]
|
|
4650
|
+
: is_default === false
|
|
4651
|
+
? ["--no-default"]
|
|
4652
|
+
: []),
|
|
4389
4653
|
...(port ? ["--port", String(port)] : []),
|
|
4390
4654
|
];
|
|
4391
4655
|
return callEditorAction(project_root, args);
|
|
4392
4656
|
});
|
|
4393
4657
|
// Tool: rename_theme_color_scheme_slot
|
|
4394
|
-
server.tool("rename_theme_color_scheme_slot",
|
|
4658
|
+
server.tool("rename_theme_color_scheme_slot", 'Rename a color scheme SLOT (a scheme key like "Background" or "PrimaryButton/Text") IN PLACE in the ' +
|
|
4395
4659
|
"connected editor. A slot's id is STABLE, so renaming keeps every runtime reference intact " +
|
|
4396
4660
|
"(`var(--<slotId>)` in CSS, `colorsByScheme[slotId]` in component code) — only the human display name " +
|
|
4397
4661
|
"changes; nothing rebinds. Identify the slot by `id` (REQUIRED — the slot id from `list_theme_globals` → " +
|
|
4398
4662
|
"colorSchemes.schemes[].id or a `colorsByScheme` key); name-based lookup is intentionally NOT supported " +
|
|
4399
|
-
|
|
4400
|
-
|
|
4663
|
+
'because slot names can collide across design assets. `name` is the NEW slot name (a "/" groups it in the ' +
|
|
4664
|
+
'editor UI, e.g. "PrimaryButton/Background"). Only non-design-asset (user/theme) slots can be renamed here. ' +
|
|
4401
4665
|
"This renames the slot itself across ALL schemes that use it (a slot is shared) — it does NOT rename a single " +
|
|
4402
4666
|
"scheme/palette (for that use `update_theme_color_scheme`). Requires `ikas-component dev` running with the " +
|
|
4403
4667
|
"editor connected.", {
|
|
4404
|
-
project_root: z
|
|
4668
|
+
project_root: z
|
|
4669
|
+
.string()
|
|
4670
|
+
.describe("Absolute path to the code-component project."),
|
|
4405
4671
|
id: z
|
|
4406
4672
|
.string()
|
|
4407
4673
|
.min(1, "id is REQUIRED — the slot id from list_theme_globals (colorSchemes.schemes[].id / colorsByScheme keys).")
|
|
@@ -4409,8 +4675,11 @@ server.tool("rename_theme_color_scheme_slot", "Rename a color scheme SLOT (a sch
|
|
|
4409
4675
|
name: z
|
|
4410
4676
|
.string()
|
|
4411
4677
|
.min(1, "name is REQUIRED — the new slot name (non-empty).")
|
|
4412
|
-
.describe(
|
|
4413
|
-
port: z
|
|
4678
|
+
.describe('The NEW slot name (non-empty). A "/" groups it in the editor UI (e.g. "PrimaryButton/Background").'),
|
|
4679
|
+
port: z
|
|
4680
|
+
.number()
|
|
4681
|
+
.optional()
|
|
4682
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4414
4683
|
}, async ({ project_root, id, name, port }) => {
|
|
4415
4684
|
const args = [
|
|
4416
4685
|
"rename-color-scheme-slot",
|
|
@@ -4423,22 +4692,45 @@ server.tool("rename_theme_color_scheme_slot", "Rename a color scheme SLOT (a sch
|
|
|
4423
4692
|
return callEditorAction(project_root, args);
|
|
4424
4693
|
});
|
|
4425
4694
|
// Tool: delete_theme_global
|
|
4426
|
-
server.tool("delete_theme_global",
|
|
4427
|
-
project_root: z
|
|
4695
|
+
server.tool("delete_theme_global", 'Delete a theme global setting from the connected editor. For `kind: globalVariable` pass `name` (the runtime key); for design-token kinds (color | typography | breakpoint | keyframe | colorScheme) pass the token `id`. For `kind: colorSchemeSlot` pass the color SLOT id (from `list_theme_globals` → colorSchemes.schemes[].id or a `colorsByScheme` key) — this deletes the slot itself across ALL schemes (use it to clean up a junk slot created by a typo); it CASCADES: the slot\'s color is removed from every scheme and any element/component style bound to that slot is cleared, so only delete a slot you are sure is unused. Only non-design-asset (user/theme) slots can be deleted here. Get names/ids from `list_theme_globals`. Deleting a non-existent id fails with a "not found" error (it does NOT report a false success), so a success result means the token really existed and was removed.', {
|
|
4696
|
+
project_root: z
|
|
4697
|
+
.string()
|
|
4698
|
+
.describe("Absolute path to the code-component project."),
|
|
4428
4699
|
kind: z
|
|
4429
|
-
.enum([
|
|
4700
|
+
.enum([
|
|
4701
|
+
"globalVariable",
|
|
4702
|
+
"color",
|
|
4703
|
+
"typography",
|
|
4704
|
+
"breakpoint",
|
|
4705
|
+
"keyframe",
|
|
4706
|
+
"colorScheme",
|
|
4707
|
+
"colorSchemeSlot",
|
|
4708
|
+
])
|
|
4430
4709
|
.describe("What to delete."),
|
|
4431
|
-
name: z
|
|
4710
|
+
name: z
|
|
4711
|
+
.string()
|
|
4712
|
+
.optional()
|
|
4713
|
+
.describe("globalVariable runtime key (from `list_theme_globals`)."),
|
|
4432
4714
|
id: z
|
|
4433
4715
|
.string()
|
|
4434
4716
|
.optional()
|
|
4435
4717
|
.describe("design-token id, or for colorSchemeSlot the slot id from `list_theme_globals` → colorSchemes.schemes."),
|
|
4436
|
-
port: z
|
|
4718
|
+
port: z
|
|
4719
|
+
.number()
|
|
4720
|
+
.optional()
|
|
4721
|
+
.describe("Dev server WebSocket port (default 5201)."),
|
|
4437
4722
|
}, async ({ project_root, kind, name, id, port }) => {
|
|
4438
4723
|
const p = port ? ["--port", String(port)] : [];
|
|
4439
4724
|
const args = kind === "globalVariable"
|
|
4440
4725
|
? ["delete-global-variable", "--name", String(name ?? ""), ...p]
|
|
4441
|
-
: [
|
|
4726
|
+
: [
|
|
4727
|
+
"delete-design-token",
|
|
4728
|
+
"--token-type",
|
|
4729
|
+
kind,
|
|
4730
|
+
"--id",
|
|
4731
|
+
String(id ?? ""),
|
|
4732
|
+
...p,
|
|
4733
|
+
];
|
|
4442
4734
|
return callEditorAction(project_root, args);
|
|
4443
4735
|
});
|
|
4444
4736
|
// --- Start server ---
|