@a-company/atelier 0.29.0 → 0.36.0
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/chunk-5QQESXI6.js +4432 -0
- package/dist/chunk-5QQESXI6.js.map +1 -0
- package/dist/cli.cjs +2391 -530
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +301 -429
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +2233 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +584 -2
- package/dist/index.d.ts +584 -2
- package/dist/index.js +111 -3
- package/dist/mcp.cjs +1215 -365
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +1209 -365
- package/dist/mcp.js.map +1 -1
- package/package.json +13 -7
- package/src/web/inline-app.ts +867 -0
- package/src/web/tsconfig.json +9 -0
- package/templates/welcome.atelier +67 -0
- package/dist/chunk-JV7RGETS.js +0 -2292
- package/dist/chunk-JV7RGETS.js.map +0 -1
package/dist/mcp.cjs
CHANGED
|
@@ -21,18 +21,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
// ../mcp/src/index.ts
|
|
22
22
|
var src_exports = {};
|
|
23
23
|
__export(src_exports, {
|
|
24
|
+
BRIDGE_PROTOCOL_VERSION: () => BRIDGE_PROTOCOL_VERSION,
|
|
24
25
|
DocumentStore: () => DocumentStore,
|
|
26
|
+
WebSocketServerTransport: () => WebSocketServerTransport,
|
|
25
27
|
createServer: () => createServer,
|
|
28
|
+
isBridgeEnvelope: () => isBridgeEnvelope,
|
|
26
29
|
registerAssetTools: () => register12,
|
|
27
30
|
registerDeltaTools: () => register5,
|
|
28
31
|
registerDocumentTools: () => register,
|
|
29
32
|
registerExportTools: () => register11,
|
|
33
|
+
registerImportImageTools: () => register19,
|
|
30
34
|
registerInteractionTools: () => register14,
|
|
31
35
|
registerLayerEffectTools: () => register9,
|
|
32
36
|
registerLayerTools: () => register2,
|
|
37
|
+
registerOverlayTools: () => register17,
|
|
33
38
|
registerPerformanceTools: () => register16,
|
|
34
39
|
registerPresetTools: () => register6,
|
|
35
40
|
registerPreviewTools: () => register7,
|
|
41
|
+
registerRecipeTools: () => register18,
|
|
36
42
|
registerRefTools: () => register15,
|
|
37
43
|
registerShapeTools: () => register3,
|
|
38
44
|
registerStateConfigTools: () => register10,
|
|
@@ -52,13 +58,15 @@ function generateId() {
|
|
|
52
58
|
}
|
|
53
59
|
var DocumentStore = class {
|
|
54
60
|
docs = /* @__PURE__ */ new Map();
|
|
61
|
+
listeners = [];
|
|
55
62
|
/** Create a new document entry. Returns the assigned ID. */
|
|
56
|
-
create(doc, id) {
|
|
63
|
+
create(doc, id, source = "system") {
|
|
57
64
|
const docId = id ?? generateId();
|
|
58
65
|
if (this.docs.has(docId)) {
|
|
59
66
|
throw new Error(`Document "${docId}" already exists`);
|
|
60
67
|
}
|
|
61
68
|
this.docs.set(docId, doc);
|
|
69
|
+
this.emit(docId, doc, source);
|
|
62
70
|
return docId;
|
|
63
71
|
}
|
|
64
72
|
/** Get a document by ID. */
|
|
@@ -66,12 +74,15 @@ var DocumentStore = class {
|
|
|
66
74
|
return this.docs.get(id);
|
|
67
75
|
}
|
|
68
76
|
/** Set (overwrite) a document by ID. */
|
|
69
|
-
set(id, doc) {
|
|
77
|
+
set(id, doc, source = "system") {
|
|
70
78
|
this.docs.set(id, doc);
|
|
79
|
+
this.emit(id, doc, source);
|
|
71
80
|
}
|
|
72
81
|
/** Delete a document by ID. Returns true if it existed. */
|
|
73
|
-
delete(id) {
|
|
74
|
-
|
|
82
|
+
delete(id, source = "system") {
|
|
83
|
+
const existed = this.docs.delete(id);
|
|
84
|
+
if (existed) this.emit(id, null, source);
|
|
85
|
+
return existed;
|
|
75
86
|
}
|
|
76
87
|
/** Check if a document exists. */
|
|
77
88
|
has(id) {
|
|
@@ -85,14 +96,43 @@ var DocumentStore = class {
|
|
|
85
96
|
}
|
|
86
97
|
return result;
|
|
87
98
|
}
|
|
88
|
-
/** Clear all documents (useful for testing). */
|
|
99
|
+
/** Clear all documents (useful for testing). Does NOT fire onChange. */
|
|
89
100
|
clear() {
|
|
90
101
|
this.docs.clear();
|
|
91
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Subscribe to mutation events. The listener is invoked after every
|
|
105
|
+
* create()/set()/delete() with the changed document ID, the new value
|
|
106
|
+
* (or `null` when deleted), and the source tag.
|
|
107
|
+
*
|
|
108
|
+
* Returns an unsubscribe function. Multiple listeners are supported and
|
|
109
|
+
* delivered in registration order. A listener that throws is isolated —
|
|
110
|
+
* the error is swallowed and remaining listeners still fire.
|
|
111
|
+
*
|
|
112
|
+
* TODO(#10): the live WS bridge will subscribe here to forward LLM-side
|
|
113
|
+
* mutations into the in-browser Studio (which exposes the symmetric
|
|
114
|
+
* `AtelierStudio.applyMutation()` API).
|
|
115
|
+
*/
|
|
116
|
+
onChange(listener) {
|
|
117
|
+
this.listeners.push(listener);
|
|
118
|
+
return () => {
|
|
119
|
+
const idx = this.listeners.indexOf(listener);
|
|
120
|
+
if (idx !== -1) this.listeners.splice(idx, 1);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
emit(id, doc, source) {
|
|
124
|
+
const snapshot = this.listeners.slice();
|
|
125
|
+
for (const listener of snapshot) {
|
|
126
|
+
try {
|
|
127
|
+
listener(id, doc, source);
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
92
132
|
};
|
|
93
133
|
|
|
94
134
|
// ../mcp/src/tools/document.ts
|
|
95
|
-
var
|
|
135
|
+
var import_zod16 = require("zod");
|
|
96
136
|
|
|
97
137
|
// ../schema/dist/index.js
|
|
98
138
|
var import_zod = require("zod");
|
|
@@ -109,6 +149,7 @@ var import_zod11 = require("zod");
|
|
|
109
149
|
var import_zod12 = require("zod");
|
|
110
150
|
var import_zod13 = require("zod");
|
|
111
151
|
var import_zod14 = require("zod");
|
|
152
|
+
var import_zod15 = require("zod");
|
|
112
153
|
var import_yaml = require("yaml");
|
|
113
154
|
var PixelSchema = import_zod.z.number();
|
|
114
155
|
var PercentageSchema = import_zod.z.string().regex(/^-?\d+(\.\d+)?%$/, {
|
|
@@ -532,6 +573,121 @@ var AtelierDocumentSchema = import_zod14.z.object({
|
|
|
532
573
|
layers: import_zod14.z.array(LayerSchema),
|
|
533
574
|
states: import_zod14.z.record(import_zod14.z.string(), StateSchema)
|
|
534
575
|
});
|
|
576
|
+
var SilencePolicySchema = import_zod15.z.object({
|
|
577
|
+
noise: import_zod15.z.string().optional(),
|
|
578
|
+
min_silence: import_zod15.z.number().nonnegative().optional(),
|
|
579
|
+
default_padding_pre: import_zod15.z.number().nonnegative().optional(),
|
|
580
|
+
default_padding_post: import_zod15.z.number().nonnegative().optional(),
|
|
581
|
+
match_tolerance: import_zod15.z.number().nonnegative().optional()
|
|
582
|
+
}).strict();
|
|
583
|
+
var CaptionStyleSchema = import_zod15.z.object({
|
|
584
|
+
font_family: import_zod15.z.string().optional(),
|
|
585
|
+
font_size: import_zod15.z.number().positive().optional(),
|
|
586
|
+
font_weight: import_zod15.z.union([import_zod15.z.literal("normal"), import_zod15.z.literal("bold"), import_zod15.z.number()]).optional(),
|
|
587
|
+
text_align: import_zod15.z.enum(["left", "center", "right"]).optional(),
|
|
588
|
+
color: import_zod15.z.string().optional(),
|
|
589
|
+
y_ratio: import_zod15.z.number().min(0).max(1).optional(),
|
|
590
|
+
width_ratio: import_zod15.z.number().min(0).max(1).optional(),
|
|
591
|
+
fade_seconds: import_zod15.z.number().nonnegative().optional()
|
|
592
|
+
}).strict();
|
|
593
|
+
var CaptionGroupingSchema = import_zod15.z.object({
|
|
594
|
+
max_words: import_zod15.z.number().int().positive().optional(),
|
|
595
|
+
pause_gap: import_zod15.z.number().nonnegative().optional()
|
|
596
|
+
}).strict();
|
|
597
|
+
var OverlayAnchorSchema = import_zod15.z.enum([
|
|
598
|
+
"top-left",
|
|
599
|
+
"top-right",
|
|
600
|
+
"bottom-left",
|
|
601
|
+
"bottom-right"
|
|
602
|
+
]);
|
|
603
|
+
var OverlayTextStyleSchema = import_zod15.z.object({
|
|
604
|
+
font_family: import_zod15.z.string().optional(),
|
|
605
|
+
font_size: import_zod15.z.number().positive().optional(),
|
|
606
|
+
font_weight: import_zod15.z.union([import_zod15.z.literal("normal"), import_zod15.z.literal("bold"), import_zod15.z.number()]).optional(),
|
|
607
|
+
color: import_zod15.z.string().optional()
|
|
608
|
+
}).strict();
|
|
609
|
+
function validatePageNumberFormat(format, ctx) {
|
|
610
|
+
if (format.length === 0) {
|
|
611
|
+
ctx.addIssue({
|
|
612
|
+
code: import_zod15.z.ZodIssueCode.custom,
|
|
613
|
+
message: "format must be a non-empty string"
|
|
614
|
+
});
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const open = (format.match(/\{/g) ?? []).length;
|
|
618
|
+
const close = (format.match(/\}/g) ?? []).length;
|
|
619
|
+
if (open !== close) {
|
|
620
|
+
ctx.addIssue({
|
|
621
|
+
code: import_zod15.z.ZodIssueCode.custom,
|
|
622
|
+
message: `format has unbalanced braces (${open} '{' vs ${close} '}')`
|
|
623
|
+
});
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
const groupRe = /\{([^{}]*)\}/g;
|
|
627
|
+
const groupRule = /^(current|total)(:0\d+d)?$/;
|
|
628
|
+
let m;
|
|
629
|
+
let sawCurrent = false;
|
|
630
|
+
let sawTotal = false;
|
|
631
|
+
while ((m = groupRe.exec(format)) !== null) {
|
|
632
|
+
const inner = m[1];
|
|
633
|
+
if (!groupRule.test(inner)) {
|
|
634
|
+
ctx.addIssue({
|
|
635
|
+
code: import_zod15.z.ZodIssueCode.custom,
|
|
636
|
+
message: `format placeholder "{${inner}}" is not recognized \u2014 expected {current}, {total}, {current:0Nd}, or {total:0Nd}`
|
|
637
|
+
});
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if (inner.startsWith("current")) sawCurrent = true;
|
|
641
|
+
if (inner.startsWith("total")) sawTotal = true;
|
|
642
|
+
}
|
|
643
|
+
if (!sawCurrent && !sawTotal) {
|
|
644
|
+
ctx.addIssue({
|
|
645
|
+
code: import_zod15.z.ZodIssueCode.custom,
|
|
646
|
+
message: "format must contain at least one {current} or {total} placeholder"
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
var OverlayHandleRuleSchema = import_zod15.z.object({
|
|
651
|
+
text: import_zod15.z.string().min(1),
|
|
652
|
+
anchor: OverlayAnchorSchema,
|
|
653
|
+
margin: import_zod15.z.number().nonnegative().optional(),
|
|
654
|
+
style: OverlayTextStyleSchema.optional()
|
|
655
|
+
}).strict();
|
|
656
|
+
var OverlayPageNumberRuleSchema = import_zod15.z.object({
|
|
657
|
+
format: import_zod15.z.string().superRefine(validatePageNumberFormat),
|
|
658
|
+
anchor: OverlayAnchorSchema,
|
|
659
|
+
margin: import_zod15.z.number().nonnegative().optional(),
|
|
660
|
+
style: OverlayTextStyleSchema.optional()
|
|
661
|
+
}).strict();
|
|
662
|
+
var OverlayRulesSchema = import_zod15.z.object({
|
|
663
|
+
handle: OverlayHandleRuleSchema.optional(),
|
|
664
|
+
page_number: OverlayPageNumberRuleSchema.optional()
|
|
665
|
+
}).strict();
|
|
666
|
+
var StudioRecipeSchema = import_zod15.z.object({
|
|
667
|
+
version: import_zod15.z.string(),
|
|
668
|
+
name: import_zod15.z.string(),
|
|
669
|
+
description: import_zod15.z.string().optional(),
|
|
670
|
+
author: import_zod15.z.string().optional(),
|
|
671
|
+
tags: import_zod15.z.array(import_zod15.z.string()).optional(),
|
|
672
|
+
silence_policy: SilencePolicySchema.optional(),
|
|
673
|
+
caption_style: CaptionStyleSchema.optional(),
|
|
674
|
+
caption_grouping: CaptionGroupingSchema.optional(),
|
|
675
|
+
// Phase 1.5 — first-class overlay rules
|
|
676
|
+
overlay_rules: OverlayRulesSchema.optional(),
|
|
677
|
+
// Reserved — Phase 3 (parse-opaque)
|
|
678
|
+
caption_highlight: import_zod15.z.unknown().optional(),
|
|
679
|
+
transition_kit: import_zod15.z.unknown().optional(),
|
|
680
|
+
palette: import_zod15.z.unknown().optional(),
|
|
681
|
+
audio_policy: import_zod15.z.unknown().optional(),
|
|
682
|
+
aspect_targets: import_zod15.z.array(import_zod15.z.unknown()).optional()
|
|
683
|
+
}).strict();
|
|
684
|
+
var RESERVED_RECIPE_FIELDS = [
|
|
685
|
+
"caption_highlight",
|
|
686
|
+
"transition_kit",
|
|
687
|
+
"palette",
|
|
688
|
+
"audio_policy",
|
|
689
|
+
"aspect_targets"
|
|
690
|
+
];
|
|
535
691
|
function formatErrors(error) {
|
|
536
692
|
return error.issues.map((issue) => ({
|
|
537
693
|
path: issue.path.join(".") || "(root)",
|
|
@@ -545,14 +701,30 @@ function validateDocument(input) {
|
|
|
545
701
|
}
|
|
546
702
|
return { success: false, errors: formatErrors(result.error) };
|
|
547
703
|
}
|
|
704
|
+
function validateRecipe(recipe) {
|
|
705
|
+
const parsed = StudioRecipeSchema.safeParse(recipe);
|
|
706
|
+
if (!parsed.success) {
|
|
707
|
+
return { success: false, errors: formatErrors(parsed.error) };
|
|
708
|
+
}
|
|
709
|
+
const warnings = [];
|
|
710
|
+
const data = parsed.data;
|
|
711
|
+
for (const field of RESERVED_RECIPE_FIELDS) {
|
|
712
|
+
if (data[field] !== void 0) {
|
|
713
|
+
warnings.push(
|
|
714
|
+
`${field} is reserved for Phase 3 and currently has no effect.`
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return { success: true, data, ...warnings.length > 0 && { warnings } };
|
|
719
|
+
}
|
|
548
720
|
function parseAtelier(yamlString) {
|
|
549
721
|
let parsed;
|
|
550
722
|
try {
|
|
551
723
|
parsed = (0, import_yaml.parse)(yamlString);
|
|
552
|
-
} catch (
|
|
724
|
+
} catch (err20) {
|
|
553
725
|
return {
|
|
554
726
|
success: false,
|
|
555
|
-
errors: [{ path: "(yaml)", message: `YAML parse error: ${
|
|
727
|
+
errors: [{ path: "(yaml)", message: `YAML parse error: ${err20.message}` }]
|
|
556
728
|
};
|
|
557
729
|
}
|
|
558
730
|
return validateDocument(parsed);
|
|
@@ -578,13 +750,13 @@ function register(server, store) {
|
|
|
578
750
|
"atelier_create",
|
|
579
751
|
"Create a new Atelier animation document with canvas settings",
|
|
580
752
|
{
|
|
581
|
-
name:
|
|
582
|
-
width:
|
|
583
|
-
height:
|
|
584
|
-
fps:
|
|
585
|
-
background:
|
|
586
|
-
description:
|
|
587
|
-
tags:
|
|
753
|
+
name: import_zod16.z.string().describe("Animation name"),
|
|
754
|
+
width: import_zod16.z.number().positive().describe("Canvas width in pixels"),
|
|
755
|
+
height: import_zod16.z.number().positive().describe("Canvas height in pixels"),
|
|
756
|
+
fps: import_zod16.z.number().positive().int().describe("Frames per second"),
|
|
757
|
+
background: import_zod16.z.string().optional().describe("Background color (hex string)"),
|
|
758
|
+
description: import_zod16.z.string().optional().describe("Animation description"),
|
|
759
|
+
tags: import_zod16.z.array(import_zod16.z.string()).optional().describe("Tags for categorization")
|
|
588
760
|
},
|
|
589
761
|
{ readOnlyHint: false, destructiveHint: false },
|
|
590
762
|
async ({ name, width, height, fps, background, description, tags }) => {
|
|
@@ -609,7 +781,7 @@ function register(server, store) {
|
|
|
609
781
|
"atelier_info",
|
|
610
782
|
"Get summary information about an Atelier document",
|
|
611
783
|
{
|
|
612
|
-
id:
|
|
784
|
+
id: import_zod16.z.string().describe("Document ID")
|
|
613
785
|
},
|
|
614
786
|
{ readOnlyHint: true, destructiveHint: false },
|
|
615
787
|
async ({ id }) => {
|
|
@@ -637,8 +809,8 @@ function register(server, store) {
|
|
|
637
809
|
"atelier_load",
|
|
638
810
|
"Load an Atelier document from a YAML string",
|
|
639
811
|
{
|
|
640
|
-
id:
|
|
641
|
-
yaml:
|
|
812
|
+
id: import_zod16.z.string().optional().describe("Custom document ID (auto-generated if omitted)"),
|
|
813
|
+
yaml: import_zod16.z.string().describe("YAML string representing an Atelier document")
|
|
642
814
|
},
|
|
643
815
|
{ readOnlyHint: false, destructiveHint: false },
|
|
644
816
|
async ({ id, yaml }) => {
|
|
@@ -654,7 +826,7 @@ function register(server, store) {
|
|
|
654
826
|
"atelier_export",
|
|
655
827
|
"Export an Atelier document as a YAML string",
|
|
656
828
|
{
|
|
657
|
-
id:
|
|
829
|
+
id: import_zod16.z.string().describe("Document ID")
|
|
658
830
|
},
|
|
659
831
|
{ readOnlyHint: true, destructiveHint: false },
|
|
660
832
|
async ({ id }) => {
|
|
@@ -677,7 +849,7 @@ function register(server, store) {
|
|
|
677
849
|
}
|
|
678
850
|
|
|
679
851
|
// ../mcp/src/tools/layers.ts
|
|
680
|
-
var
|
|
852
|
+
var import_zod17 = require("zod");
|
|
681
853
|
function getDoc2(store, id) {
|
|
682
854
|
const doc = store.get(id);
|
|
683
855
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -689,69 +861,69 @@ function ok2(data) {
|
|
|
689
861
|
function err2(message) {
|
|
690
862
|
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
691
863
|
}
|
|
692
|
-
var VisualInputSchema =
|
|
693
|
-
type:
|
|
864
|
+
var VisualInputSchema = import_zod17.z.object({
|
|
865
|
+
type: import_zod17.z.enum(["shape", "text", "image", "group", "ref"]).describe("Visual type"),
|
|
694
866
|
// shape visual fields
|
|
695
|
-
shape:
|
|
696
|
-
type:
|
|
697
|
-
cornerRadius:
|
|
698
|
-
points:
|
|
699
|
-
x:
|
|
700
|
-
y:
|
|
701
|
-
in:
|
|
702
|
-
out:
|
|
867
|
+
shape: import_zod17.z.object({
|
|
868
|
+
type: import_zod17.z.enum(["rect", "ellipse", "path"]),
|
|
869
|
+
cornerRadius: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.tuple([import_zod17.z.number(), import_zod17.z.number(), import_zod17.z.number(), import_zod17.z.number()])]).optional(),
|
|
870
|
+
points: import_zod17.z.array(import_zod17.z.object({
|
|
871
|
+
x: import_zod17.z.number(),
|
|
872
|
+
y: import_zod17.z.number(),
|
|
873
|
+
in: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional(),
|
|
874
|
+
out: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional()
|
|
703
875
|
})).optional(),
|
|
704
|
-
closed:
|
|
876
|
+
closed: import_zod17.z.boolean().optional()
|
|
705
877
|
}).optional(),
|
|
706
|
-
fill:
|
|
707
|
-
stroke:
|
|
878
|
+
fill: import_zod17.z.record(import_zod17.z.unknown()).optional(),
|
|
879
|
+
stroke: import_zod17.z.record(import_zod17.z.unknown()).optional(),
|
|
708
880
|
// text visual fields
|
|
709
|
-
content:
|
|
710
|
-
style:
|
|
881
|
+
content: import_zod17.z.string().optional(),
|
|
882
|
+
style: import_zod17.z.record(import_zod17.z.unknown()).optional(),
|
|
711
883
|
// image visual fields
|
|
712
|
-
assetId:
|
|
713
|
-
sourceRect:
|
|
714
|
-
x:
|
|
715
|
-
y:
|
|
716
|
-
width:
|
|
717
|
-
height:
|
|
884
|
+
assetId: import_zod17.z.string().optional(),
|
|
885
|
+
sourceRect: import_zod17.z.object({
|
|
886
|
+
x: import_zod17.z.number(),
|
|
887
|
+
y: import_zod17.z.number(),
|
|
888
|
+
width: import_zod17.z.number().positive(),
|
|
889
|
+
height: import_zod17.z.number().positive()
|
|
718
890
|
}).optional(),
|
|
719
|
-
spritesheet:
|
|
720
|
-
columns:
|
|
721
|
-
rows:
|
|
722
|
-
frameCount:
|
|
723
|
-
frameWidth:
|
|
724
|
-
frameHeight:
|
|
891
|
+
spritesheet: import_zod17.z.object({
|
|
892
|
+
columns: import_zod17.z.number().int().positive(),
|
|
893
|
+
rows: import_zod17.z.number().int().positive(),
|
|
894
|
+
frameCount: import_zod17.z.number().int().positive().optional(),
|
|
895
|
+
frameWidth: import_zod17.z.number().positive(),
|
|
896
|
+
frameHeight: import_zod17.z.number().positive()
|
|
725
897
|
}).optional(),
|
|
726
|
-
frameIndex:
|
|
898
|
+
frameIndex: import_zod17.z.number().int().min(0).optional(),
|
|
727
899
|
// ref visual fields
|
|
728
|
-
src:
|
|
729
|
-
state:
|
|
730
|
-
frame:
|
|
900
|
+
src: import_zod17.z.string().optional(),
|
|
901
|
+
state: import_zod17.z.string().optional(),
|
|
902
|
+
frame: import_zod17.z.number().int().min(0).optional()
|
|
731
903
|
}).describe("Visual content definition");
|
|
732
904
|
function register2(server, store) {
|
|
733
905
|
server.tool(
|
|
734
906
|
"atelier_add_layer",
|
|
735
907
|
"Add a new layer to an Atelier document",
|
|
736
908
|
{
|
|
737
|
-
id:
|
|
738
|
-
layerId:
|
|
909
|
+
id: import_zod17.z.string().describe("Document ID"),
|
|
910
|
+
layerId: import_zod17.z.string().describe("Unique layer ID"),
|
|
739
911
|
visual: VisualInputSchema.describe("Visual content definition"),
|
|
740
|
-
x:
|
|
741
|
-
y:
|
|
742
|
-
width:
|
|
743
|
-
height:
|
|
744
|
-
description:
|
|
745
|
-
tags:
|
|
746
|
-
opacity:
|
|
747
|
-
rotation:
|
|
748
|
-
parentId:
|
|
749
|
-
anchorPoint:
|
|
750
|
-
scale:
|
|
751
|
-
visible:
|
|
752
|
-
tint:
|
|
753
|
-
color:
|
|
754
|
-
amount:
|
|
912
|
+
x: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).describe("X position (pixels or percentage)"),
|
|
913
|
+
y: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).describe("Y position (pixels or percentage)"),
|
|
914
|
+
width: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).describe("Width (pixels or percentage)"),
|
|
915
|
+
height: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).describe("Height (pixels or percentage)"),
|
|
916
|
+
description: import_zod17.z.string().optional().describe("Layer description"),
|
|
917
|
+
tags: import_zod17.z.array(import_zod17.z.string()).optional().describe("Tags"),
|
|
918
|
+
opacity: import_zod17.z.number().min(0).max(1).optional().describe("Opacity 0-1"),
|
|
919
|
+
rotation: import_zod17.z.number().optional().describe("Rotation in degrees"),
|
|
920
|
+
parentId: import_zod17.z.string().optional().describe("Parent layer ID for transform inheritance"),
|
|
921
|
+
anchorPoint: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional().describe("Anchor point (0-1 normalized)"),
|
|
922
|
+
scale: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional().describe("Scale factors"),
|
|
923
|
+
visible: import_zod17.z.boolean().optional().describe("Whether layer is visible"),
|
|
924
|
+
tint: import_zod17.z.object({
|
|
925
|
+
color: import_zod17.z.string().describe("Tint color (hex string)"),
|
|
926
|
+
amount: import_zod17.z.number().min(0).max(1).describe("Tint amount (0 = none, 1 = full)")
|
|
755
927
|
}).optional().describe("Color tint overlay")
|
|
756
928
|
},
|
|
757
929
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -788,20 +960,20 @@ function register2(server, store) {
|
|
|
788
960
|
"atelier_edit_layer",
|
|
789
961
|
"Edit properties of an existing layer",
|
|
790
962
|
{
|
|
791
|
-
id:
|
|
792
|
-
layerId:
|
|
793
|
-
x:
|
|
794
|
-
y:
|
|
795
|
-
width:
|
|
796
|
-
height:
|
|
797
|
-
description:
|
|
798
|
-
tags:
|
|
799
|
-
opacity:
|
|
800
|
-
rotation:
|
|
801
|
-
parentId:
|
|
802
|
-
anchorPoint:
|
|
803
|
-
scale:
|
|
804
|
-
visible:
|
|
963
|
+
id: import_zod17.z.string().describe("Document ID"),
|
|
964
|
+
layerId: import_zod17.z.string().describe("Layer ID to edit"),
|
|
965
|
+
x: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).optional().describe("New X position"),
|
|
966
|
+
y: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).optional().describe("New Y position"),
|
|
967
|
+
width: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).optional().describe("New width"),
|
|
968
|
+
height: import_zod17.z.union([import_zod17.z.number(), import_zod17.z.string()]).optional().describe("New height"),
|
|
969
|
+
description: import_zod17.z.string().optional().describe("New description"),
|
|
970
|
+
tags: import_zod17.z.array(import_zod17.z.string()).optional().describe("New tags"),
|
|
971
|
+
opacity: import_zod17.z.number().min(0).max(1).optional().describe("New opacity"),
|
|
972
|
+
rotation: import_zod17.z.number().optional().describe("New rotation"),
|
|
973
|
+
parentId: import_zod17.z.string().nullable().optional().describe("New parent layer ID (null to clear)"),
|
|
974
|
+
anchorPoint: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional().describe("New anchor point"),
|
|
975
|
+
scale: import_zod17.z.object({ x: import_zod17.z.number(), y: import_zod17.z.number() }).optional().describe("New scale"),
|
|
976
|
+
visible: import_zod17.z.boolean().optional().describe("New visibility")
|
|
805
977
|
},
|
|
806
978
|
{ readOnlyHint: false, destructiveHint: false },
|
|
807
979
|
async ({ id, layerId, x, y, width, height, description, tags, opacity, rotation, parentId, anchorPoint, scale, visible }) => {
|
|
@@ -836,8 +1008,8 @@ function register2(server, store) {
|
|
|
836
1008
|
"atelier_remove_layer",
|
|
837
1009
|
"Remove a layer from an Atelier document",
|
|
838
1010
|
{
|
|
839
|
-
id:
|
|
840
|
-
layerId:
|
|
1011
|
+
id: import_zod17.z.string().describe("Document ID"),
|
|
1012
|
+
layerId: import_zod17.z.string().describe("Layer ID to remove")
|
|
841
1013
|
},
|
|
842
1014
|
{ readOnlyHint: false, destructiveHint: true },
|
|
843
1015
|
async ({ id, layerId }) => {
|
|
@@ -865,7 +1037,7 @@ function register2(server, store) {
|
|
|
865
1037
|
"atelier_list_layers",
|
|
866
1038
|
"List all layers in an Atelier document",
|
|
867
1039
|
{
|
|
868
|
-
id:
|
|
1040
|
+
id: import_zod17.z.string().describe("Document ID")
|
|
869
1041
|
},
|
|
870
1042
|
{ readOnlyHint: true, destructiveHint: false },
|
|
871
1043
|
async ({ id }) => {
|
|
@@ -892,9 +1064,9 @@ function register2(server, store) {
|
|
|
892
1064
|
"atelier_reorder",
|
|
893
1065
|
"Move a layer to a new position in the layer stack",
|
|
894
1066
|
{
|
|
895
|
-
id:
|
|
896
|
-
layerId:
|
|
897
|
-
position:
|
|
1067
|
+
id: import_zod17.z.string().describe("Document ID"),
|
|
1068
|
+
layerId: import_zod17.z.string().describe("Layer ID to move"),
|
|
1069
|
+
position: import_zod17.z.number().int().min(0).describe("Target position index (0-based)")
|
|
898
1070
|
},
|
|
899
1071
|
{ readOnlyHint: false, destructiveHint: false },
|
|
900
1072
|
async ({ id, layerId, position }) => {
|
|
@@ -912,7 +1084,7 @@ function register2(server, store) {
|
|
|
912
1084
|
}
|
|
913
1085
|
|
|
914
1086
|
// ../mcp/src/tools/shapes.ts
|
|
915
|
-
var
|
|
1087
|
+
var import_zod18 = require("zod");
|
|
916
1088
|
function getDoc3(store, id) {
|
|
917
1089
|
const doc = store.get(id);
|
|
918
1090
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -929,21 +1101,21 @@ function register3(server, store) {
|
|
|
929
1101
|
"atelier_set_shape",
|
|
930
1102
|
"Set the shape on a shape-type layer",
|
|
931
1103
|
{
|
|
932
|
-
id:
|
|
933
|
-
layerId:
|
|
934
|
-
shape:
|
|
935
|
-
type:
|
|
936
|
-
cornerRadius:
|
|
937
|
-
|
|
938
|
-
|
|
1104
|
+
id: import_zod18.z.string().describe("Document ID"),
|
|
1105
|
+
layerId: import_zod18.z.string().describe("Layer ID (must be a shape visual)"),
|
|
1106
|
+
shape: import_zod18.z.object({
|
|
1107
|
+
type: import_zod18.z.enum(["rect", "ellipse", "path"]).describe("Shape type"),
|
|
1108
|
+
cornerRadius: import_zod18.z.union([
|
|
1109
|
+
import_zod18.z.number(),
|
|
1110
|
+
import_zod18.z.tuple([import_zod18.z.number(), import_zod18.z.number(), import_zod18.z.number(), import_zod18.z.number()])
|
|
939
1111
|
]).optional().describe("Corner radius (rect only)"),
|
|
940
|
-
points:
|
|
941
|
-
x:
|
|
942
|
-
y:
|
|
943
|
-
in:
|
|
944
|
-
out:
|
|
1112
|
+
points: import_zod18.z.array(import_zod18.z.object({
|
|
1113
|
+
x: import_zod18.z.number(),
|
|
1114
|
+
y: import_zod18.z.number(),
|
|
1115
|
+
in: import_zod18.z.object({ x: import_zod18.z.number(), y: import_zod18.z.number() }).optional(),
|
|
1116
|
+
out: import_zod18.z.object({ x: import_zod18.z.number(), y: import_zod18.z.number() }).optional()
|
|
945
1117
|
})).optional().describe("Path points (path only)"),
|
|
946
|
-
closed:
|
|
1118
|
+
closed: import_zod18.z.boolean().optional().describe("Whether path is closed (path only)")
|
|
947
1119
|
}).describe("Shape definition")
|
|
948
1120
|
},
|
|
949
1121
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -962,20 +1134,20 @@ function register3(server, store) {
|
|
|
962
1134
|
"atelier_set_fill",
|
|
963
1135
|
"Set the fill on a shape-type layer",
|
|
964
1136
|
{
|
|
965
|
-
id:
|
|
966
|
-
layerId:
|
|
967
|
-
fill:
|
|
968
|
-
type:
|
|
969
|
-
color:
|
|
970
|
-
angle:
|
|
971
|
-
center:
|
|
972
|
-
x:
|
|
973
|
-
y:
|
|
1137
|
+
id: import_zod18.z.string().describe("Document ID"),
|
|
1138
|
+
layerId: import_zod18.z.string().describe("Layer ID (must be a shape visual)"),
|
|
1139
|
+
fill: import_zod18.z.object({
|
|
1140
|
+
type: import_zod18.z.enum(["solid", "linear-gradient", "radial-gradient"]).describe("Fill type"),
|
|
1141
|
+
color: import_zod18.z.unknown().optional().describe("Color for solid fill (hex string or RGBA/HSLA object)"),
|
|
1142
|
+
angle: import_zod18.z.number().optional().describe("Angle in degrees (linear-gradient only)"),
|
|
1143
|
+
center: import_zod18.z.object({
|
|
1144
|
+
x: import_zod18.z.union([import_zod18.z.number(), import_zod18.z.string()]),
|
|
1145
|
+
y: import_zod18.z.union([import_zod18.z.number(), import_zod18.z.string()])
|
|
974
1146
|
}).optional().describe("Center point (radial-gradient only)"),
|
|
975
|
-
radius:
|
|
976
|
-
stops:
|
|
977
|
-
offset:
|
|
978
|
-
color:
|
|
1147
|
+
radius: import_zod18.z.union([import_zod18.z.number(), import_zod18.z.string()]).optional().describe("Radius (radial-gradient only)"),
|
|
1148
|
+
stops: import_zod18.z.array(import_zod18.z.object({
|
|
1149
|
+
offset: import_zod18.z.number().min(0).max(1),
|
|
1150
|
+
color: import_zod18.z.unknown()
|
|
979
1151
|
})).optional().describe("Gradient stops")
|
|
980
1152
|
}).describe("Fill definition")
|
|
981
1153
|
},
|
|
@@ -995,14 +1167,14 @@ function register3(server, store) {
|
|
|
995
1167
|
"atelier_set_stroke",
|
|
996
1168
|
"Set the stroke on a shape-type layer",
|
|
997
1169
|
{
|
|
998
|
-
id:
|
|
999
|
-
layerId:
|
|
1000
|
-
stroke:
|
|
1001
|
-
color:
|
|
1002
|
-
width:
|
|
1003
|
-
dash:
|
|
1004
|
-
lineCap:
|
|
1005
|
-
lineJoin:
|
|
1170
|
+
id: import_zod18.z.string().describe("Document ID"),
|
|
1171
|
+
layerId: import_zod18.z.string().describe("Layer ID (must be a shape visual)"),
|
|
1172
|
+
stroke: import_zod18.z.object({
|
|
1173
|
+
color: import_zod18.z.unknown().describe("Stroke color (hex string or RGBA/HSLA object)"),
|
|
1174
|
+
width: import_zod18.z.number().positive().describe("Stroke width in pixels"),
|
|
1175
|
+
dash: import_zod18.z.array(import_zod18.z.number()).optional().describe("Dash pattern"),
|
|
1176
|
+
lineCap: import_zod18.z.enum(["butt", "round", "square"]).optional().describe("Line cap style"),
|
|
1177
|
+
lineJoin: import_zod18.z.enum(["miter", "round", "bevel"]).optional().describe("Line join style")
|
|
1006
1178
|
}).describe("Stroke definition")
|
|
1007
1179
|
},
|
|
1008
1180
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -1020,7 +1192,7 @@ function register3(server, store) {
|
|
|
1020
1192
|
}
|
|
1021
1193
|
|
|
1022
1194
|
// ../mcp/src/tools/states.ts
|
|
1023
|
-
var
|
|
1195
|
+
var import_zod19 = require("zod");
|
|
1024
1196
|
function getDoc4(store, id) {
|
|
1025
1197
|
const doc = store.get(id);
|
|
1026
1198
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -1037,11 +1209,11 @@ function register4(server, store) {
|
|
|
1037
1209
|
"atelier_add_state",
|
|
1038
1210
|
"Add a named animation state to a document",
|
|
1039
1211
|
{
|
|
1040
|
-
id:
|
|
1041
|
-
stateName:
|
|
1042
|
-
duration:
|
|
1043
|
-
description:
|
|
1044
|
-
tags:
|
|
1212
|
+
id: import_zod19.z.string().describe("Document ID"),
|
|
1213
|
+
stateName: import_zod19.z.string().describe("State name (e.g. 'intro', 'hover', 'exit')"),
|
|
1214
|
+
duration: import_zod19.z.number().positive().int().describe("Duration in frames"),
|
|
1215
|
+
description: import_zod19.z.string().optional().describe("State description"),
|
|
1216
|
+
tags: import_zod19.z.array(import_zod19.z.string()).optional().describe("Tags")
|
|
1045
1217
|
},
|
|
1046
1218
|
{ readOnlyHint: false, destructiveHint: false },
|
|
1047
1219
|
async ({ id, stateName, duration, description, tags }) => {
|
|
@@ -1064,11 +1236,11 @@ function register4(server, store) {
|
|
|
1064
1236
|
"atelier_edit_state",
|
|
1065
1237
|
"Edit metadata of an existing animation state",
|
|
1066
1238
|
{
|
|
1067
|
-
id:
|
|
1068
|
-
stateName:
|
|
1069
|
-
duration:
|
|
1070
|
-
description:
|
|
1071
|
-
tags:
|
|
1239
|
+
id: import_zod19.z.string().describe("Document ID"),
|
|
1240
|
+
stateName: import_zod19.z.string().describe("State name to edit"),
|
|
1241
|
+
duration: import_zod19.z.number().positive().int().optional().describe("New duration in frames"),
|
|
1242
|
+
description: import_zod19.z.string().optional().describe("New description"),
|
|
1243
|
+
tags: import_zod19.z.array(import_zod19.z.string()).optional().describe("New tags")
|
|
1072
1244
|
},
|
|
1073
1245
|
{ readOnlyHint: false, destructiveHint: false },
|
|
1074
1246
|
async ({ id, stateName, duration, description, tags }) => {
|
|
@@ -1087,8 +1259,8 @@ function register4(server, store) {
|
|
|
1087
1259
|
"atelier_remove_state",
|
|
1088
1260
|
"Remove an animation state and all its deltas",
|
|
1089
1261
|
{
|
|
1090
|
-
id:
|
|
1091
|
-
stateName:
|
|
1262
|
+
id: import_zod19.z.string().describe("Document ID"),
|
|
1263
|
+
stateName: import_zod19.z.string().describe("State name to remove")
|
|
1092
1264
|
},
|
|
1093
1265
|
{ readOnlyHint: false, destructiveHint: true },
|
|
1094
1266
|
async ({ id, stateName }) => {
|
|
@@ -1105,7 +1277,7 @@ function register4(server, store) {
|
|
|
1105
1277
|
"atelier_list_states",
|
|
1106
1278
|
"List all animation states in a document",
|
|
1107
1279
|
{
|
|
1108
|
-
id:
|
|
1280
|
+
id: import_zod19.z.string().describe("Document ID")
|
|
1109
1281
|
},
|
|
1110
1282
|
{ readOnlyHint: true, destructiveHint: false },
|
|
1111
1283
|
async ({ id }) => {
|
|
@@ -1125,7 +1297,7 @@ function register4(server, store) {
|
|
|
1125
1297
|
}
|
|
1126
1298
|
|
|
1127
1299
|
// ../mcp/src/tools/deltas.ts
|
|
1128
|
-
var
|
|
1300
|
+
var import_zod20 = require("zod");
|
|
1129
1301
|
|
|
1130
1302
|
// ../math/dist/index.js
|
|
1131
1303
|
function linear(t) {
|
|
@@ -1864,17 +2036,17 @@ function register5(server, store) {
|
|
|
1864
2036
|
"atelier_add_delta",
|
|
1865
2037
|
"Add an animation delta (keyframe transition) to a state",
|
|
1866
2038
|
{
|
|
1867
|
-
id:
|
|
1868
|
-
stateName:
|
|
1869
|
-
layer:
|
|
2039
|
+
id: import_zod20.z.string().describe("Document ID"),
|
|
2040
|
+
stateName: import_zod20.z.string().describe("State name"),
|
|
2041
|
+
layer: import_zod20.z.string().describe("Target layer ID"),
|
|
1870
2042
|
property: AnimatablePropertyEnum.describe("Property to animate"),
|
|
1871
|
-
range:
|
|
1872
|
-
from:
|
|
1873
|
-
to:
|
|
2043
|
+
range: import_zod20.z.tuple([import_zod20.z.number().int().min(0), import_zod20.z.number().int().min(0)]).describe("Frame range [start, end] inclusive"),
|
|
2044
|
+
from: import_zod20.z.unknown().describe("Starting value"),
|
|
2045
|
+
to: import_zod20.z.unknown().describe("Ending value"),
|
|
1874
2046
|
easing: EasingInputSchema.optional().describe("Easing function"),
|
|
1875
|
-
description:
|
|
1876
|
-
tags:
|
|
1877
|
-
deltaId:
|
|
2047
|
+
description: import_zod20.z.string().optional().describe("Delta description"),
|
|
2048
|
+
tags: import_zod20.z.array(import_zod20.z.string()).optional().describe("Tags"),
|
|
2049
|
+
deltaId: import_zod20.z.string().optional().describe("Custom delta ID")
|
|
1878
2050
|
},
|
|
1879
2051
|
{ readOnlyHint: false, destructiveHint: false },
|
|
1880
2052
|
async ({ id, stateName, layer, property, range, from, to, easing, description, tags, deltaId }) => {
|
|
@@ -1912,17 +2084,17 @@ function register5(server, store) {
|
|
|
1912
2084
|
"atelier_edit_delta",
|
|
1913
2085
|
"Edit an existing delta by index within a state",
|
|
1914
2086
|
{
|
|
1915
|
-
id:
|
|
1916
|
-
stateName:
|
|
1917
|
-
deltaIndex:
|
|
1918
|
-
layer:
|
|
2087
|
+
id: import_zod20.z.string().describe("Document ID"),
|
|
2088
|
+
stateName: import_zod20.z.string().describe("State name"),
|
|
2089
|
+
deltaIndex: import_zod20.z.number().int().min(0).describe("Delta index within the state"),
|
|
2090
|
+
layer: import_zod20.z.string().optional().describe("New target layer ID"),
|
|
1919
2091
|
property: AnimatablePropertyEnum.optional().describe("New property to animate"),
|
|
1920
|
-
range:
|
|
1921
|
-
from:
|
|
1922
|
-
to:
|
|
2092
|
+
range: import_zod20.z.tuple([import_zod20.z.number().int().min(0), import_zod20.z.number().int().min(0)]).optional().describe("New frame range [start, end]"),
|
|
2093
|
+
from: import_zod20.z.unknown().optional().describe("New starting value"),
|
|
2094
|
+
to: import_zod20.z.unknown().optional().describe("New ending value"),
|
|
1923
2095
|
easing: EasingInputSchema.optional().describe("New easing function"),
|
|
1924
|
-
description:
|
|
1925
|
-
tags:
|
|
2096
|
+
description: import_zod20.z.string().optional().describe("New description"),
|
|
2097
|
+
tags: import_zod20.z.array(import_zod20.z.string()).optional().describe("New tags")
|
|
1926
2098
|
},
|
|
1927
2099
|
{ readOnlyHint: false, destructiveHint: false },
|
|
1928
2100
|
async ({ id, stateName, deltaIndex, layer, property, range, from, to, easing, description, tags }) => {
|
|
@@ -1961,9 +2133,9 @@ function register5(server, store) {
|
|
|
1961
2133
|
"atelier_remove_delta",
|
|
1962
2134
|
"Remove a delta by index from a state",
|
|
1963
2135
|
{
|
|
1964
|
-
id:
|
|
1965
|
-
stateName:
|
|
1966
|
-
deltaIndex:
|
|
2136
|
+
id: import_zod20.z.string().describe("Document ID"),
|
|
2137
|
+
stateName: import_zod20.z.string().describe("State name"),
|
|
2138
|
+
deltaIndex: import_zod20.z.number().int().min(0).describe("Delta index to remove")
|
|
1967
2139
|
},
|
|
1968
2140
|
{ readOnlyHint: false, destructiveHint: true },
|
|
1969
2141
|
async ({ id, stateName, deltaIndex }) => {
|
|
@@ -1991,12 +2163,12 @@ function register5(server, store) {
|
|
|
1991
2163
|
"atelier_apply_preset",
|
|
1992
2164
|
"Apply a preset to a layer, expanding it into concrete deltas",
|
|
1993
2165
|
{
|
|
1994
|
-
id:
|
|
1995
|
-
stateName:
|
|
1996
|
-
presetName:
|
|
1997
|
-
layerId:
|
|
1998
|
-
startFrame:
|
|
1999
|
-
duration:
|
|
2166
|
+
id: import_zod20.z.string().describe("Document ID"),
|
|
2167
|
+
stateName: import_zod20.z.string().describe("State name to add deltas to"),
|
|
2168
|
+
presetName: import_zod20.z.string().describe("Preset name defined in the document"),
|
|
2169
|
+
layerId: import_zod20.z.string().describe("Target layer ID"),
|
|
2170
|
+
startFrame: import_zod20.z.number().int().min(0).optional().describe("Start frame (default: 0)"),
|
|
2171
|
+
duration: import_zod20.z.number().positive().int().optional().describe("Duration for preset (default: state duration)")
|
|
2000
2172
|
},
|
|
2001
2173
|
{ readOnlyHint: false, destructiveHint: false },
|
|
2002
2174
|
async ({ id, stateName, presetName, layerId, startFrame, duration }) => {
|
|
@@ -2039,7 +2211,7 @@ ${errors.join("\n")}`);
|
|
|
2039
2211
|
}
|
|
2040
2212
|
|
|
2041
2213
|
// ../mcp/src/tools/presets.ts
|
|
2042
|
-
var
|
|
2214
|
+
var import_zod21 = require("zod");
|
|
2043
2215
|
function getDoc6(store, id) {
|
|
2044
2216
|
const doc = store.get(id);
|
|
2045
2217
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -2053,11 +2225,11 @@ function err6(message) {
|
|
|
2053
2225
|
}
|
|
2054
2226
|
var AnimatablePropertyEnum2 = AnimatablePropertySchema;
|
|
2055
2227
|
var EasingInputSchema2 = EasingSchema;
|
|
2056
|
-
var PresetDeltaSchema2 =
|
|
2228
|
+
var PresetDeltaSchema2 = import_zod21.z.object({
|
|
2057
2229
|
property: AnimatablePropertyEnum2.describe("Animatable property"),
|
|
2058
|
-
offset:
|
|
2059
|
-
from:
|
|
2060
|
-
to:
|
|
2230
|
+
offset: import_zod21.z.tuple([import_zod21.z.number().int().min(0), import_zod21.z.number().int().min(0)]).optional().describe("Relative frame offset [start, end]"),
|
|
2231
|
+
from: import_zod21.z.unknown().describe("Starting value"),
|
|
2232
|
+
to: import_zod21.z.unknown().describe("Ending value"),
|
|
2061
2233
|
easing: EasingInputSchema2.optional().describe("Easing function")
|
|
2062
2234
|
});
|
|
2063
2235
|
function register6(server, store) {
|
|
@@ -2065,11 +2237,11 @@ function register6(server, store) {
|
|
|
2065
2237
|
"atelier_define_preset",
|
|
2066
2238
|
"Define a reusable animation preset on a document",
|
|
2067
2239
|
{
|
|
2068
|
-
id:
|
|
2069
|
-
presetName:
|
|
2070
|
-
description:
|
|
2071
|
-
tags:
|
|
2072
|
-
deltas:
|
|
2240
|
+
id: import_zod21.z.string().describe("Document ID"),
|
|
2241
|
+
presetName: import_zod21.z.string().describe("Preset name"),
|
|
2242
|
+
description: import_zod21.z.string().optional().describe("Preset description"),
|
|
2243
|
+
tags: import_zod21.z.array(import_zod21.z.string()).optional().describe("Tags"),
|
|
2244
|
+
deltas: import_zod21.z.array(PresetDeltaSchema2).min(1).describe("Array of preset delta definitions")
|
|
2073
2245
|
},
|
|
2074
2246
|
{ readOnlyHint: false, destructiveHint: false },
|
|
2075
2247
|
async ({ id, presetName, description, tags, deltas }) => {
|
|
@@ -2090,7 +2262,7 @@ function register6(server, store) {
|
|
|
2090
2262
|
"atelier_list_presets",
|
|
2091
2263
|
"List all presets defined on a document",
|
|
2092
2264
|
{
|
|
2093
|
-
id:
|
|
2265
|
+
id: import_zod21.z.string().describe("Document ID")
|
|
2094
2266
|
},
|
|
2095
2267
|
{ readOnlyHint: true, destructiveHint: false },
|
|
2096
2268
|
async ({ id }) => {
|
|
@@ -2113,7 +2285,7 @@ function register6(server, store) {
|
|
|
2113
2285
|
}
|
|
2114
2286
|
|
|
2115
2287
|
// ../mcp/src/tools/preview.ts
|
|
2116
|
-
var
|
|
2288
|
+
var import_zod22 = require("zod");
|
|
2117
2289
|
function getDoc7(store, id) {
|
|
2118
2290
|
const doc = store.get(id);
|
|
2119
2291
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -2130,7 +2302,7 @@ function register7(server, store) {
|
|
|
2130
2302
|
"atelier_validate",
|
|
2131
2303
|
"Validate an Atelier document for schema correctness and delta overlaps",
|
|
2132
2304
|
{
|
|
2133
|
-
id:
|
|
2305
|
+
id: import_zod22.z.string().describe("Document ID")
|
|
2134
2306
|
},
|
|
2135
2307
|
{ readOnlyHint: true, destructiveHint: false },
|
|
2136
2308
|
async ({ id }) => {
|
|
@@ -2159,9 +2331,9 @@ function register7(server, store) {
|
|
|
2159
2331
|
"atelier_preview",
|
|
2160
2332
|
"Preview the resolved state of all layers at a specific frame",
|
|
2161
2333
|
{
|
|
2162
|
-
id:
|
|
2163
|
-
stateName:
|
|
2164
|
-
frame:
|
|
2334
|
+
id: import_zod22.z.string().describe("Document ID"),
|
|
2335
|
+
stateName: import_zod22.z.string().describe("State name to preview"),
|
|
2336
|
+
frame: import_zod22.z.number().int().min(0).describe("Frame number to resolve")
|
|
2165
2337
|
},
|
|
2166
2338
|
{ readOnlyHint: true, destructiveHint: false },
|
|
2167
2339
|
async ({ id, stateName, frame }) => {
|
|
@@ -2196,7 +2368,7 @@ function register7(server, store) {
|
|
|
2196
2368
|
}
|
|
2197
2369
|
|
|
2198
2370
|
// ../mcp/src/tools/templates.ts
|
|
2199
|
-
var
|
|
2371
|
+
var import_zod23 = require("zod");
|
|
2200
2372
|
function getDoc8(store, id) {
|
|
2201
2373
|
const doc = store.get(id);
|
|
2202
2374
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -2213,8 +2385,8 @@ function register8(server, store) {
|
|
|
2213
2385
|
"atelier_instantiate_template",
|
|
2214
2386
|
"Instantiate a template document with variable bindings. Creates a new document in the store.",
|
|
2215
2387
|
{
|
|
2216
|
-
id:
|
|
2217
|
-
bindings:
|
|
2388
|
+
id: import_zod23.z.string().describe("Template document ID"),
|
|
2389
|
+
bindings: import_zod23.z.record(import_zod23.z.unknown()).describe("Variable bindings: { variableName: value }")
|
|
2218
2390
|
},
|
|
2219
2391
|
{ readOnlyHint: false, destructiveHint: false },
|
|
2220
2392
|
async ({ id, bindings }) => {
|
|
@@ -2237,7 +2409,7 @@ function register8(server, store) {
|
|
|
2237
2409
|
"atelier_find_variables",
|
|
2238
2410
|
"Scan a document for {{variableName}} patterns. Returns the list of variable references found.",
|
|
2239
2411
|
{
|
|
2240
|
-
id:
|
|
2412
|
+
id: import_zod23.z.string().describe("Document ID")
|
|
2241
2413
|
},
|
|
2242
2414
|
{ readOnlyHint: true, destructiveHint: false },
|
|
2243
2415
|
async ({ id }) => {
|
|
@@ -2257,7 +2429,7 @@ function register8(server, store) {
|
|
|
2257
2429
|
}
|
|
2258
2430
|
|
|
2259
2431
|
// ../mcp/src/tools/layer-effects.ts
|
|
2260
|
-
var
|
|
2432
|
+
var import_zod24 = require("zod");
|
|
2261
2433
|
function getDoc9(store, id) {
|
|
2262
2434
|
const doc = store.get(id);
|
|
2263
2435
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -2274,9 +2446,9 @@ function register9(server, store) {
|
|
|
2274
2446
|
"atelier_set_blend_mode",
|
|
2275
2447
|
"Set or clear the blend mode on a layer",
|
|
2276
2448
|
{
|
|
2277
|
-
id:
|
|
2278
|
-
layerId:
|
|
2279
|
-
blendMode:
|
|
2449
|
+
id: import_zod24.z.string().describe("Document ID"),
|
|
2450
|
+
layerId: import_zod24.z.string().describe("Layer ID"),
|
|
2451
|
+
blendMode: import_zod24.z.enum([
|
|
2280
2452
|
"normal",
|
|
2281
2453
|
"multiply",
|
|
2282
2454
|
"screen",
|
|
@@ -2314,13 +2486,13 @@ function register9(server, store) {
|
|
|
2314
2486
|
"atelier_set_shadow",
|
|
2315
2487
|
"Set or remove a drop shadow on a layer",
|
|
2316
2488
|
{
|
|
2317
|
-
id:
|
|
2318
|
-
layerId:
|
|
2319
|
-
shadow:
|
|
2320
|
-
color:
|
|
2321
|
-
blur:
|
|
2322
|
-
offsetX:
|
|
2323
|
-
offsetY:
|
|
2489
|
+
id: import_zod24.z.string().describe("Document ID"),
|
|
2490
|
+
layerId: import_zod24.z.string().describe("Layer ID"),
|
|
2491
|
+
shadow: import_zod24.z.object({
|
|
2492
|
+
color: import_zod24.z.unknown().describe("Shadow color (hex string or RGBA/HSLA object)"),
|
|
2493
|
+
blur: import_zod24.z.number().min(0).describe("Blur radius in pixels"),
|
|
2494
|
+
offsetX: import_zod24.z.number().optional().describe("Horizontal offset in pixels"),
|
|
2495
|
+
offsetY: import_zod24.z.number().optional().describe("Vertical offset in pixels")
|
|
2324
2496
|
}).nullable().describe("Shadow definition, or null to remove")
|
|
2325
2497
|
},
|
|
2326
2498
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -2342,11 +2514,11 @@ function register9(server, store) {
|
|
|
2342
2514
|
"atelier_set_tint",
|
|
2343
2515
|
"Set or remove a color tint on a layer (works on any visual type)",
|
|
2344
2516
|
{
|
|
2345
|
-
id:
|
|
2346
|
-
layerId:
|
|
2347
|
-
tint:
|
|
2348
|
-
color:
|
|
2349
|
-
amount:
|
|
2517
|
+
id: import_zod24.z.string().describe("Document ID"),
|
|
2518
|
+
layerId: import_zod24.z.string().describe("Layer ID"),
|
|
2519
|
+
tint: import_zod24.z.object({
|
|
2520
|
+
color: import_zod24.z.string().describe("Tint color (hex string)"),
|
|
2521
|
+
amount: import_zod24.z.number().min(0).max(1).describe("Tint amount (0 = none, 1 = full)")
|
|
2350
2522
|
}).nullable().describe("Tint definition, or null to remove")
|
|
2351
2523
|
},
|
|
2352
2524
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -2368,18 +2540,18 @@ function register9(server, store) {
|
|
|
2368
2540
|
"atelier_set_motion_path",
|
|
2369
2541
|
"Set or remove a motion path on a layer for path-based position animation",
|
|
2370
2542
|
{
|
|
2371
|
-
id:
|
|
2372
|
-
layerId:
|
|
2373
|
-
motionPath:
|
|
2374
|
-
points:
|
|
2375
|
-
x:
|
|
2376
|
-
y:
|
|
2377
|
-
in:
|
|
2378
|
-
out:
|
|
2543
|
+
id: import_zod24.z.string().describe("Document ID"),
|
|
2544
|
+
layerId: import_zod24.z.string().describe("Layer ID"),
|
|
2545
|
+
motionPath: import_zod24.z.object({
|
|
2546
|
+
points: import_zod24.z.array(import_zod24.z.object({
|
|
2547
|
+
x: import_zod24.z.number(),
|
|
2548
|
+
y: import_zod24.z.number(),
|
|
2549
|
+
in: import_zod24.z.object({ x: import_zod24.z.number(), y: import_zod24.z.number() }).optional(),
|
|
2550
|
+
out: import_zod24.z.object({ x: import_zod24.z.number(), y: import_zod24.z.number() }).optional()
|
|
2379
2551
|
})).min(2).describe("Path points (minimum 2)"),
|
|
2380
|
-
closed:
|
|
2381
|
-
autoRotate:
|
|
2382
|
-
autoRotateOffset:
|
|
2552
|
+
closed: import_zod24.z.boolean().optional().describe("Whether the path is closed"),
|
|
2553
|
+
autoRotate: import_zod24.z.boolean().optional().describe("Auto-rotate layer to follow path tangent"),
|
|
2554
|
+
autoRotateOffset: import_zod24.z.number().optional().describe("Rotation offset in degrees when autoRotate is enabled")
|
|
2383
2555
|
}).nullable().describe("Motion path definition, or null to remove")
|
|
2384
2556
|
},
|
|
2385
2557
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -2401,21 +2573,21 @@ function register9(server, store) {
|
|
|
2401
2573
|
"atelier_set_clip_path",
|
|
2402
2574
|
"Set or remove a clip path on a layer to restrict rendering to within a shape",
|
|
2403
2575
|
{
|
|
2404
|
-
id:
|
|
2405
|
-
layerId:
|
|
2406
|
-
clipPath:
|
|
2407
|
-
type:
|
|
2408
|
-
cornerRadius:
|
|
2409
|
-
|
|
2410
|
-
|
|
2576
|
+
id: import_zod24.z.string().describe("Document ID"),
|
|
2577
|
+
layerId: import_zod24.z.string().describe("Layer ID"),
|
|
2578
|
+
clipPath: import_zod24.z.object({
|
|
2579
|
+
type: import_zod24.z.enum(["rect", "ellipse", "path"]).describe("Clip shape type"),
|
|
2580
|
+
cornerRadius: import_zod24.z.union([
|
|
2581
|
+
import_zod24.z.number(),
|
|
2582
|
+
import_zod24.z.tuple([import_zod24.z.number(), import_zod24.z.number(), import_zod24.z.number(), import_zod24.z.number()])
|
|
2411
2583
|
]).optional().describe("Corner radius (rect only)"),
|
|
2412
|
-
points:
|
|
2413
|
-
x:
|
|
2414
|
-
y:
|
|
2415
|
-
in:
|
|
2416
|
-
out:
|
|
2584
|
+
points: import_zod24.z.array(import_zod24.z.object({
|
|
2585
|
+
x: import_zod24.z.number(),
|
|
2586
|
+
y: import_zod24.z.number(),
|
|
2587
|
+
in: import_zod24.z.object({ x: import_zod24.z.number(), y: import_zod24.z.number() }).optional(),
|
|
2588
|
+
out: import_zod24.z.object({ x: import_zod24.z.number(), y: import_zod24.z.number() }).optional()
|
|
2417
2589
|
})).optional().describe("Path points (path only)"),
|
|
2418
|
-
closed:
|
|
2590
|
+
closed: import_zod24.z.boolean().optional().describe("Whether path is closed (path only)")
|
|
2419
2591
|
}).nullable().describe("Clip path shape, or null to remove")
|
|
2420
2592
|
},
|
|
2421
2593
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -2437,45 +2609,45 @@ function register9(server, store) {
|
|
|
2437
2609
|
"atelier_edit_visual",
|
|
2438
2610
|
"Edit visual content of an existing layer (text content/style, image src/assetId, shape/fill/stroke)",
|
|
2439
2611
|
{
|
|
2440
|
-
id:
|
|
2441
|
-
layerId:
|
|
2612
|
+
id: import_zod24.z.string().describe("Document ID"),
|
|
2613
|
+
layerId: import_zod24.z.string().describe("Layer ID"),
|
|
2442
2614
|
// Text fields
|
|
2443
|
-
content:
|
|
2444
|
-
style:
|
|
2615
|
+
content: import_zod24.z.string().optional().describe("New text content (text layers only)"),
|
|
2616
|
+
style: import_zod24.z.record(import_zod24.z.unknown()).optional().describe("Partial style update \u2014 only provided keys are overwritten (text layers only)"),
|
|
2445
2617
|
// Image fields
|
|
2446
|
-
src:
|
|
2447
|
-
assetId:
|
|
2448
|
-
sourceRect:
|
|
2449
|
-
x:
|
|
2450
|
-
y:
|
|
2451
|
-
width:
|
|
2452
|
-
height:
|
|
2618
|
+
src: import_zod24.z.string().optional().describe("Image source URL (image layers only)"),
|
|
2619
|
+
assetId: import_zod24.z.string().optional().describe("Asset ID reference (image layers only)"),
|
|
2620
|
+
sourceRect: import_zod24.z.object({
|
|
2621
|
+
x: import_zod24.z.number(),
|
|
2622
|
+
y: import_zod24.z.number(),
|
|
2623
|
+
width: import_zod24.z.number().positive(),
|
|
2624
|
+
height: import_zod24.z.number().positive()
|
|
2453
2625
|
}).nullable().optional().describe("Source rectangle crop (image layers only). Null to remove."),
|
|
2454
|
-
spritesheet:
|
|
2455
|
-
columns:
|
|
2456
|
-
rows:
|
|
2457
|
-
frameCount:
|
|
2458
|
-
frameWidth:
|
|
2459
|
-
frameHeight:
|
|
2626
|
+
spritesheet: import_zod24.z.object({
|
|
2627
|
+
columns: import_zod24.z.number().int().positive(),
|
|
2628
|
+
rows: import_zod24.z.number().int().positive(),
|
|
2629
|
+
frameCount: import_zod24.z.number().int().positive().optional(),
|
|
2630
|
+
frameWidth: import_zod24.z.number().positive(),
|
|
2631
|
+
frameHeight: import_zod24.z.number().positive()
|
|
2460
2632
|
}).nullable().optional().describe("Spritesheet config (image layers only). Null to remove."),
|
|
2461
|
-
frameIndex:
|
|
2633
|
+
frameIndex: import_zod24.z.number().int().min(0).optional().describe("Spritesheet frame index (image layers only)"),
|
|
2462
2634
|
// Shape fields
|
|
2463
|
-
shape:
|
|
2464
|
-
type:
|
|
2465
|
-
cornerRadius:
|
|
2466
|
-
|
|
2467
|
-
|
|
2635
|
+
shape: import_zod24.z.object({
|
|
2636
|
+
type: import_zod24.z.enum(["rect", "ellipse", "path"]),
|
|
2637
|
+
cornerRadius: import_zod24.z.union([
|
|
2638
|
+
import_zod24.z.number(),
|
|
2639
|
+
import_zod24.z.tuple([import_zod24.z.number(), import_zod24.z.number(), import_zod24.z.number(), import_zod24.z.number()])
|
|
2468
2640
|
]).optional(),
|
|
2469
|
-
points:
|
|
2470
|
-
x:
|
|
2471
|
-
y:
|
|
2472
|
-
in:
|
|
2473
|
-
out:
|
|
2641
|
+
points: import_zod24.z.array(import_zod24.z.object({
|
|
2642
|
+
x: import_zod24.z.number(),
|
|
2643
|
+
y: import_zod24.z.number(),
|
|
2644
|
+
in: import_zod24.z.object({ x: import_zod24.z.number(), y: import_zod24.z.number() }).optional(),
|
|
2645
|
+
out: import_zod24.z.object({ x: import_zod24.z.number(), y: import_zod24.z.number() }).optional()
|
|
2474
2646
|
})).optional(),
|
|
2475
|
-
closed:
|
|
2647
|
+
closed: import_zod24.z.boolean().optional()
|
|
2476
2648
|
}).optional().describe("New shape (shape layers only)"),
|
|
2477
|
-
fill:
|
|
2478
|
-
stroke:
|
|
2649
|
+
fill: import_zod24.z.record(import_zod24.z.unknown()).optional().describe("New fill definition (shape layers only)"),
|
|
2650
|
+
stroke: import_zod24.z.record(import_zod24.z.unknown()).optional().describe("New stroke definition (shape layers only)")
|
|
2479
2651
|
},
|
|
2480
2652
|
{ readOnlyHint: false, destructiveHint: false },
|
|
2481
2653
|
async ({ id, layerId, content, style, src, assetId, sourceRect, spritesheet, frameIndex, shape, fill, stroke }) => {
|
|
@@ -2556,7 +2728,7 @@ function register9(server, store) {
|
|
|
2556
2728
|
}
|
|
2557
2729
|
|
|
2558
2730
|
// ../mcp/src/tools/state-config.ts
|
|
2559
|
-
var
|
|
2731
|
+
var import_zod25 = require("zod");
|
|
2560
2732
|
function getDoc10(store, id) {
|
|
2561
2733
|
const doc = store.get(id);
|
|
2562
2734
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -2568,27 +2740,27 @@ function ok10(data) {
|
|
|
2568
2740
|
function err10(message) {
|
|
2569
2741
|
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
2570
2742
|
}
|
|
2571
|
-
var EasingInputSchema3 =
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
type:
|
|
2576
|
-
x1:
|
|
2577
|
-
y1:
|
|
2578
|
-
x2:
|
|
2579
|
-
y2:
|
|
2743
|
+
var EasingInputSchema3 = import_zod25.z.union([
|
|
2744
|
+
import_zod25.z.enum(["ease-in", "ease-out", "ease-in-out"]),
|
|
2745
|
+
import_zod25.z.object({ type: import_zod25.z.literal("linear") }),
|
|
2746
|
+
import_zod25.z.object({
|
|
2747
|
+
type: import_zod25.z.literal("cubic-bezier"),
|
|
2748
|
+
x1: import_zod25.z.number(),
|
|
2749
|
+
y1: import_zod25.z.number(),
|
|
2750
|
+
x2: import_zod25.z.number(),
|
|
2751
|
+
y2: import_zod25.z.number()
|
|
2580
2752
|
}),
|
|
2581
|
-
|
|
2582
|
-
type:
|
|
2583
|
-
mass:
|
|
2584
|
-
stiffness:
|
|
2585
|
-
damping:
|
|
2586
|
-
velocity:
|
|
2753
|
+
import_zod25.z.object({
|
|
2754
|
+
type: import_zod25.z.literal("spring"),
|
|
2755
|
+
mass: import_zod25.z.number().optional(),
|
|
2756
|
+
stiffness: import_zod25.z.number().optional(),
|
|
2757
|
+
damping: import_zod25.z.number().optional(),
|
|
2758
|
+
velocity: import_zod25.z.number().optional()
|
|
2587
2759
|
}),
|
|
2588
|
-
|
|
2589
|
-
type:
|
|
2590
|
-
steps:
|
|
2591
|
-
position:
|
|
2760
|
+
import_zod25.z.object({
|
|
2761
|
+
type: import_zod25.z.literal("step"),
|
|
2762
|
+
steps: import_zod25.z.number().int().positive(),
|
|
2763
|
+
position: import_zod25.z.enum(["start", "end"]).optional()
|
|
2592
2764
|
})
|
|
2593
2765
|
]).describe("Easing function");
|
|
2594
2766
|
function register10(server, store) {
|
|
@@ -2596,14 +2768,14 @@ function register10(server, store) {
|
|
|
2596
2768
|
"atelier_set_audio",
|
|
2597
2769
|
"Set or remove an audio track on a state",
|
|
2598
2770
|
{
|
|
2599
|
-
id:
|
|
2600
|
-
stateName:
|
|
2601
|
-
audio:
|
|
2602
|
-
src:
|
|
2603
|
-
offset:
|
|
2604
|
-
volume:
|
|
2605
|
-
loop:
|
|
2606
|
-
startFrame:
|
|
2771
|
+
id: import_zod25.z.string().describe("Document ID"),
|
|
2772
|
+
stateName: import_zod25.z.string().describe("State name"),
|
|
2773
|
+
audio: import_zod25.z.object({
|
|
2774
|
+
src: import_zod25.z.string().describe("Audio source \u2014 asset reference, file path, or URL"),
|
|
2775
|
+
offset: import_zod25.z.number().min(0).optional().describe("Skip into audio in seconds (default: 0)"),
|
|
2776
|
+
volume: import_zod25.z.number().min(0).max(1).optional().describe("Playback volume 0\u20131 (default: 1)"),
|
|
2777
|
+
loop: import_zod25.z.boolean().optional().describe("Loop for state duration (default: false)"),
|
|
2778
|
+
startFrame: import_zod25.z.number().int().min(0).optional().describe("Frame to start playing (default: 0)")
|
|
2607
2779
|
}).nullable().describe("Audio configuration, or null to remove")
|
|
2608
2780
|
},
|
|
2609
2781
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -2625,11 +2797,11 @@ function register10(server, store) {
|
|
|
2625
2797
|
"atelier_configure_transition",
|
|
2626
2798
|
"Configure or remove a transition from one state to a target state",
|
|
2627
2799
|
{
|
|
2628
|
-
id:
|
|
2629
|
-
stateName:
|
|
2630
|
-
targetState:
|
|
2631
|
-
transition:
|
|
2632
|
-
duration:
|
|
2800
|
+
id: import_zod25.z.string().describe("Document ID"),
|
|
2801
|
+
stateName: import_zod25.z.string().describe("Source state name"),
|
|
2802
|
+
targetState: import_zod25.z.string().describe("Target state name"),
|
|
2803
|
+
transition: import_zod25.z.object({
|
|
2804
|
+
duration: import_zod25.z.number().positive().int().describe("Transition duration in frames"),
|
|
2633
2805
|
easing: EasingInputSchema3.optional()
|
|
2634
2806
|
}).nullable().describe("Transition config, or null to remove")
|
|
2635
2807
|
},
|
|
@@ -2666,9 +2838,9 @@ function register10(server, store) {
|
|
|
2666
2838
|
"atelier_set_state_parent",
|
|
2667
2839
|
"Set or clear the parent state for hierarchical delta inheritance",
|
|
2668
2840
|
{
|
|
2669
|
-
id:
|
|
2670
|
-
stateName:
|
|
2671
|
-
parent:
|
|
2841
|
+
id: import_zod25.z.string().describe("Document ID"),
|
|
2842
|
+
stateName: import_zod25.z.string().describe("State name"),
|
|
2843
|
+
parent: import_zod25.z.string().nullable().describe("Parent state name, or null to clear")
|
|
2672
2844
|
},
|
|
2673
2845
|
{ readOnlyHint: false, destructiveHint: false },
|
|
2674
2846
|
async ({ id, stateName, parent }) => {
|
|
@@ -2703,7 +2875,7 @@ function register10(server, store) {
|
|
|
2703
2875
|
}
|
|
2704
2876
|
|
|
2705
2877
|
// ../mcp/src/tools/export.ts
|
|
2706
|
-
var
|
|
2878
|
+
var import_zod26 = require("zod");
|
|
2707
2879
|
|
|
2708
2880
|
// ../canvas/dist/index.js
|
|
2709
2881
|
function colorToCSS(color) {
|
|
@@ -3888,12 +4060,12 @@ function register11(server, store) {
|
|
|
3888
4060
|
"atelier_export_svg",
|
|
3889
4061
|
"Export a frame as an SVG string",
|
|
3890
4062
|
{
|
|
3891
|
-
id:
|
|
3892
|
-
stateName:
|
|
3893
|
-
frame:
|
|
3894
|
-
xmlDeclaration:
|
|
3895
|
-
viewBox:
|
|
3896
|
-
indent:
|
|
4063
|
+
id: import_zod26.z.string().describe("Document ID"),
|
|
4064
|
+
stateName: import_zod26.z.string().optional().describe("State name (defaults to first state)"),
|
|
4065
|
+
frame: import_zod26.z.number().int().min(0).optional().describe("Frame number (defaults to 0)"),
|
|
4066
|
+
xmlDeclaration: import_zod26.z.boolean().optional().describe("Include XML declaration (default: false)"),
|
|
4067
|
+
viewBox: import_zod26.z.boolean().optional().describe("Include viewBox attribute (default: true)"),
|
|
4068
|
+
indent: import_zod26.z.number().int().min(0).optional().describe("Indent size in spaces (default: 2)")
|
|
3897
4069
|
},
|
|
3898
4070
|
{ readOnlyHint: true, destructiveHint: false },
|
|
3899
4071
|
async ({ id, stateName, frame, xmlDeclaration, viewBox, indent }) => {
|
|
@@ -3924,8 +4096,8 @@ function register11(server, store) {
|
|
|
3924
4096
|
"atelier_export_lottie",
|
|
3925
4097
|
"Export a document to Lottie JSON format (lossy, best-effort)",
|
|
3926
4098
|
{
|
|
3927
|
-
id:
|
|
3928
|
-
stateName:
|
|
4099
|
+
id: import_zod26.z.string().describe("Document ID"),
|
|
4100
|
+
stateName: import_zod26.z.string().optional().describe("State to export (defaults to first state)")
|
|
3929
4101
|
},
|
|
3930
4102
|
{ readOnlyHint: true, destructiveHint: false },
|
|
3931
4103
|
async ({ id, stateName }) => {
|
|
@@ -3945,7 +4117,7 @@ function register11(server, store) {
|
|
|
3945
4117
|
}
|
|
3946
4118
|
|
|
3947
4119
|
// ../mcp/src/tools/assets.ts
|
|
3948
|
-
var
|
|
4120
|
+
var import_zod27 = require("zod");
|
|
3949
4121
|
function getDoc12(store, id) {
|
|
3950
4122
|
const doc = store.get(id);
|
|
3951
4123
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -3962,17 +4134,17 @@ function register12(server, store) {
|
|
|
3962
4134
|
"atelier_add_asset",
|
|
3963
4135
|
"Register an external asset (image, SVG, font, animation, audio) on a document",
|
|
3964
4136
|
{
|
|
3965
|
-
id:
|
|
3966
|
-
assetId:
|
|
3967
|
-
type:
|
|
3968
|
-
src:
|
|
3969
|
-
description:
|
|
3970
|
-
spritesheet:
|
|
3971
|
-
columns:
|
|
3972
|
-
rows:
|
|
3973
|
-
frameCount:
|
|
3974
|
-
frameWidth:
|
|
3975
|
-
frameHeight:
|
|
4137
|
+
id: import_zod27.z.string().describe("Document ID"),
|
|
4138
|
+
assetId: import_zod27.z.string().describe("Unique asset identifier"),
|
|
4139
|
+
type: import_zod27.z.enum(["image", "svg", "font", "animation", "audio"]).describe("Asset type"),
|
|
4140
|
+
src: import_zod27.z.string().describe("File path or URL"),
|
|
4141
|
+
description: import_zod27.z.string().optional().describe("Human-readable description"),
|
|
4142
|
+
spritesheet: import_zod27.z.object({
|
|
4143
|
+
columns: import_zod27.z.number().int().positive().describe("Number of columns in the spritesheet grid"),
|
|
4144
|
+
rows: import_zod27.z.number().int().positive().describe("Number of rows in the spritesheet grid"),
|
|
4145
|
+
frameCount: import_zod27.z.number().int().positive().optional().describe("Total frame count (defaults to columns \xD7 rows)"),
|
|
4146
|
+
frameWidth: import_zod27.z.number().positive().describe("Width of each frame in pixels"),
|
|
4147
|
+
frameHeight: import_zod27.z.number().positive().describe("Height of each frame in pixels")
|
|
3976
4148
|
}).optional().describe("Spritesheet metadata (image assets only)")
|
|
3977
4149
|
},
|
|
3978
4150
|
{ readOnlyHint: false, destructiveHint: false },
|
|
@@ -3995,7 +4167,7 @@ function register12(server, store) {
|
|
|
3995
4167
|
"atelier_list_assets",
|
|
3996
4168
|
"List all registered assets with usage info (which layers/states reference them)",
|
|
3997
4169
|
{
|
|
3998
|
-
id:
|
|
4170
|
+
id: import_zod27.z.string().describe("Document ID")
|
|
3999
4171
|
},
|
|
4000
4172
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4001
4173
|
async ({ id }) => {
|
|
@@ -4022,8 +4194,8 @@ function register12(server, store) {
|
|
|
4022
4194
|
"atelier_remove_asset",
|
|
4023
4195
|
"Remove a registered asset. Warns if layers or state audio still reference it.",
|
|
4024
4196
|
{
|
|
4025
|
-
id:
|
|
4026
|
-
assetId:
|
|
4197
|
+
id: import_zod27.z.string().describe("Document ID"),
|
|
4198
|
+
assetId: import_zod27.z.string().describe("Asset ID to remove")
|
|
4027
4199
|
},
|
|
4028
4200
|
{ readOnlyHint: false, destructiveHint: true },
|
|
4029
4201
|
async ({ id, assetId }) => {
|
|
@@ -4047,7 +4219,7 @@ function register12(server, store) {
|
|
|
4047
4219
|
}
|
|
4048
4220
|
|
|
4049
4221
|
// ../mcp/src/tools/variables.ts
|
|
4050
|
-
var
|
|
4222
|
+
var import_zod28 = require("zod");
|
|
4051
4223
|
function getDoc13(store, id) {
|
|
4052
4224
|
const doc = store.get(id);
|
|
4053
4225
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -4064,11 +4236,11 @@ function register13(server, store) {
|
|
|
4064
4236
|
"atelier_add_variable",
|
|
4065
4237
|
"Define a template variable on a document",
|
|
4066
4238
|
{
|
|
4067
|
-
id:
|
|
4068
|
-
variableName:
|
|
4069
|
-
type:
|
|
4070
|
-
description:
|
|
4071
|
-
default:
|
|
4239
|
+
id: import_zod28.z.string().describe("Document ID"),
|
|
4240
|
+
variableName: import_zod28.z.string().describe("Variable name (used in {{variableName}} patterns)"),
|
|
4241
|
+
type: import_zod28.z.enum(["string", "number", "color", "asset", "boolean"]).describe("Variable type"),
|
|
4242
|
+
description: import_zod28.z.string().optional().describe("Human-readable description"),
|
|
4243
|
+
default: import_zod28.z.unknown().optional().describe("Default value")
|
|
4072
4244
|
},
|
|
4073
4245
|
{ readOnlyHint: false, destructiveHint: false },
|
|
4074
4246
|
async (args) => {
|
|
@@ -4089,7 +4261,7 @@ function register13(server, store) {
|
|
|
4089
4261
|
"atelier_list_variables",
|
|
4090
4262
|
"List all declared variables with usage info (which {{references}} exist in the document)",
|
|
4091
4263
|
{
|
|
4092
|
-
id:
|
|
4264
|
+
id: import_zod28.z.string().describe("Document ID")
|
|
4093
4265
|
},
|
|
4094
4266
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4095
4267
|
async ({ id }) => {
|
|
@@ -4113,8 +4285,8 @@ function register13(server, store) {
|
|
|
4113
4285
|
"atelier_remove_variable",
|
|
4114
4286
|
"Remove a declared variable. Warns if {{references}} still exist in the document.",
|
|
4115
4287
|
{
|
|
4116
|
-
id:
|
|
4117
|
-
variableName:
|
|
4288
|
+
id: import_zod28.z.string().describe("Document ID"),
|
|
4289
|
+
variableName: import_zod28.z.string().describe("Variable name to remove")
|
|
4118
4290
|
},
|
|
4119
4291
|
{ readOnlyHint: false, destructiveHint: true },
|
|
4120
4292
|
async ({ id, variableName }) => {
|
|
@@ -4137,7 +4309,7 @@ function register13(server, store) {
|
|
|
4137
4309
|
}
|
|
4138
4310
|
|
|
4139
4311
|
// ../mcp/src/tools/interactions.ts
|
|
4140
|
-
var
|
|
4312
|
+
var import_zod29 = require("zod");
|
|
4141
4313
|
function getDoc14(store, id) {
|
|
4142
4314
|
const doc = store.get(id);
|
|
4143
4315
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -4154,23 +4326,23 @@ function register14(server, store) {
|
|
|
4154
4326
|
"atelier_add_interaction",
|
|
4155
4327
|
"Add a trigger-action interaction to a layer (click, hover, timer, signal \u2192 go-to-state, emit-signal, set-variable, toggle-visibility)",
|
|
4156
4328
|
{
|
|
4157
|
-
id:
|
|
4158
|
-
layerId:
|
|
4159
|
-
interactionId:
|
|
4160
|
-
trigger:
|
|
4161
|
-
type:
|
|
4162
|
-
delay:
|
|
4163
|
-
signal:
|
|
4329
|
+
id: import_zod29.z.string().describe("Document ID"),
|
|
4330
|
+
layerId: import_zod29.z.string().describe("Layer to attach the interaction to"),
|
|
4331
|
+
interactionId: import_zod29.z.string().describe("Unique interaction ID"),
|
|
4332
|
+
trigger: import_zod29.z.object({
|
|
4333
|
+
type: import_zod29.z.enum(["click", "hover", "pointerdown", "pointerup", "timer", "signal"]).describe("Trigger type"),
|
|
4334
|
+
delay: import_zod29.z.number().optional().describe("Delay in ms (timer trigger only)"),
|
|
4335
|
+
signal: import_zod29.z.string().optional().describe("Signal name (signal trigger only)")
|
|
4164
4336
|
}).describe("What triggers the interaction"),
|
|
4165
|
-
action:
|
|
4166
|
-
type:
|
|
4167
|
-
state:
|
|
4168
|
-
signal:
|
|
4169
|
-
variable:
|
|
4170
|
-
value:
|
|
4171
|
-
targetLayer:
|
|
4337
|
+
action: import_zod29.z.object({
|
|
4338
|
+
type: import_zod29.z.enum(["go-to-state", "emit-signal", "set-variable", "toggle-visibility"]).describe("Action type"),
|
|
4339
|
+
state: import_zod29.z.string().optional().describe("Target state (go-to-state only)"),
|
|
4340
|
+
signal: import_zod29.z.string().optional().describe("Signal to emit (emit-signal only)"),
|
|
4341
|
+
variable: import_zod29.z.string().optional().describe("Variable name (set-variable only)"),
|
|
4342
|
+
value: import_zod29.z.unknown().optional().describe("Value to set (set-variable only)"),
|
|
4343
|
+
targetLayer: import_zod29.z.string().optional().describe("Target layer ID (toggle-visibility, defaults to self)")
|
|
4172
4344
|
}).describe("What happens when triggered"),
|
|
4173
|
-
description:
|
|
4345
|
+
description: import_zod29.z.string().optional().describe("Human-readable description")
|
|
4174
4346
|
},
|
|
4175
4347
|
{ readOnlyHint: false, destructiveHint: false },
|
|
4176
4348
|
async ({ id, layerId, interactionId, trigger, action, description }) => {
|
|
@@ -4219,8 +4391,8 @@ function register14(server, store) {
|
|
|
4219
4391
|
"atelier_list_interactions",
|
|
4220
4392
|
"List all interactions across all layers or for a specific layer",
|
|
4221
4393
|
{
|
|
4222
|
-
id:
|
|
4223
|
-
layerId:
|
|
4394
|
+
id: import_zod29.z.string().describe("Document ID"),
|
|
4395
|
+
layerId: import_zod29.z.string().optional().describe("Optional: filter to a specific layer")
|
|
4224
4396
|
},
|
|
4225
4397
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4226
4398
|
async ({ id, layerId }) => {
|
|
@@ -4247,9 +4419,9 @@ function register14(server, store) {
|
|
|
4247
4419
|
"atelier_remove_interaction",
|
|
4248
4420
|
"Remove an interaction from a layer",
|
|
4249
4421
|
{
|
|
4250
|
-
id:
|
|
4251
|
-
layerId:
|
|
4252
|
-
interactionId:
|
|
4422
|
+
id: import_zod29.z.string().describe("Document ID"),
|
|
4423
|
+
layerId: import_zod29.z.string().describe("Layer ID"),
|
|
4424
|
+
interactionId: import_zod29.z.string().describe("Interaction ID to remove")
|
|
4253
4425
|
},
|
|
4254
4426
|
{ readOnlyHint: false, destructiveHint: true },
|
|
4255
4427
|
async ({ id, layerId, interactionId }) => {
|
|
@@ -4271,7 +4443,7 @@ function register14(server, store) {
|
|
|
4271
4443
|
}
|
|
4272
4444
|
|
|
4273
4445
|
// ../mcp/src/tools/refs.ts
|
|
4274
|
-
var
|
|
4446
|
+
var import_zod30 = require("zod");
|
|
4275
4447
|
function getDoc15(store, id) {
|
|
4276
4448
|
const doc = store.get(id);
|
|
4277
4449
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -4288,9 +4460,9 @@ function register15(server, store) {
|
|
|
4288
4460
|
"atelier_set_ref",
|
|
4289
4461
|
"Set the source reference on a ref-type layer. Can point to a file path or another in-memory document ID.",
|
|
4290
4462
|
{
|
|
4291
|
-
id:
|
|
4292
|
-
layerId:
|
|
4293
|
-
src:
|
|
4463
|
+
id: import_zod30.z.string().describe("Document ID"),
|
|
4464
|
+
layerId: import_zod30.z.string().describe("Layer ID (must be a ref visual)"),
|
|
4465
|
+
src: import_zod30.z.string().describe("File path, URL, or in-memory document ID")
|
|
4294
4466
|
},
|
|
4295
4467
|
{ readOnlyHint: false, destructiveHint: false },
|
|
4296
4468
|
async ({ id, layerId, src }) => {
|
|
@@ -4310,7 +4482,7 @@ function register15(server, store) {
|
|
|
4310
4482
|
"atelier_resolve_refs",
|
|
4311
4483
|
"Check which ref layers can be resolved (point to valid in-memory documents)",
|
|
4312
4484
|
{
|
|
4313
|
-
id:
|
|
4485
|
+
id: import_zod30.z.string().describe("Document ID")
|
|
4314
4486
|
},
|
|
4315
4487
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4316
4488
|
async ({ id }) => {
|
|
@@ -4337,7 +4509,7 @@ function register15(server, store) {
|
|
|
4337
4509
|
}
|
|
4338
4510
|
|
|
4339
4511
|
// ../mcp/src/tools/performance.ts
|
|
4340
|
-
var
|
|
4512
|
+
var import_zod31 = require("zod");
|
|
4341
4513
|
function getDoc16(store, id) {
|
|
4342
4514
|
const doc = store.get(id);
|
|
4343
4515
|
if (!doc) return { error: `Document "${id}" not found` };
|
|
@@ -4354,9 +4526,9 @@ function register16(server, store) {
|
|
|
4354
4526
|
"atelier_profile",
|
|
4355
4527
|
"Profile frame resolution performance \u2014 returns timing, layer count, property count, and delta count for a frame",
|
|
4356
4528
|
{
|
|
4357
|
-
id:
|
|
4358
|
-
stateName:
|
|
4359
|
-
frame:
|
|
4529
|
+
id: import_zod31.z.string().describe("Document ID"),
|
|
4530
|
+
stateName: import_zod31.z.string().describe("State name to profile"),
|
|
4531
|
+
frame: import_zod31.z.number().int().min(0).describe("Frame number to resolve")
|
|
4360
4532
|
},
|
|
4361
4533
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4362
4534
|
async ({ id, stateName, frame }) => {
|
|
@@ -4402,10 +4574,10 @@ function register16(server, store) {
|
|
|
4402
4574
|
"atelier_diff_frames",
|
|
4403
4575
|
"Compare two frames and return only the properties that changed between them",
|
|
4404
4576
|
{
|
|
4405
|
-
id:
|
|
4406
|
-
stateName:
|
|
4407
|
-
frameA:
|
|
4408
|
-
frameB:
|
|
4577
|
+
id: import_zod31.z.string().describe("Document ID"),
|
|
4578
|
+
stateName: import_zod31.z.string().describe("State name"),
|
|
4579
|
+
frameA: import_zod31.z.number().int().min(0).describe("First frame number"),
|
|
4580
|
+
frameB: import_zod31.z.number().int().min(0).describe("Second frame number")
|
|
4409
4581
|
},
|
|
4410
4582
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4411
4583
|
async ({ id, stateName, frameA, frameB }) => {
|
|
@@ -4444,9 +4616,9 @@ function register16(server, store) {
|
|
|
4444
4616
|
"atelier_batch_preview",
|
|
4445
4617
|
"Preview multiple frames at once \u2014 reduces round-trips for scrubbing or timeline inspection",
|
|
4446
4618
|
{
|
|
4447
|
-
id:
|
|
4448
|
-
stateName:
|
|
4449
|
-
frames:
|
|
4619
|
+
id: import_zod31.z.string().describe("Document ID"),
|
|
4620
|
+
stateName: import_zod31.z.string().describe("State name to preview"),
|
|
4621
|
+
frames: import_zod31.z.array(import_zod31.z.number().int().min(0)).min(1).max(60).describe("Array of frame numbers to resolve (max 60)")
|
|
4450
4622
|
},
|
|
4451
4623
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4452
4624
|
async ({ id, stateName, frames }) => {
|
|
@@ -4482,7 +4654,7 @@ function register16(server, store) {
|
|
|
4482
4654
|
"atelier_complexity",
|
|
4483
4655
|
"Analyze document complexity \u2014 layer count, delta count, expression usage, state hierarchy depth",
|
|
4484
4656
|
{
|
|
4485
|
-
id:
|
|
4657
|
+
id: import_zod31.z.string().describe("Document ID")
|
|
4486
4658
|
},
|
|
4487
4659
|
{ readOnlyHint: true, destructiveHint: false },
|
|
4488
4660
|
async ({ id }) => {
|
|
@@ -4554,9 +4726,678 @@ function register16(server, store) {
|
|
|
4554
4726
|
);
|
|
4555
4727
|
}
|
|
4556
4728
|
|
|
4729
|
+
// ../mcp/src/tools/overlays.ts
|
|
4730
|
+
var import_zod32 = require("zod");
|
|
4731
|
+
function getDoc17(store, id) {
|
|
4732
|
+
const doc = store.get(id);
|
|
4733
|
+
if (!doc) return { error: `Document "${id}" not found` };
|
|
4734
|
+
return { doc };
|
|
4735
|
+
}
|
|
4736
|
+
function ok17(data) {
|
|
4737
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...data }) }] };
|
|
4738
|
+
}
|
|
4739
|
+
function err17(message) {
|
|
4740
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
4741
|
+
}
|
|
4742
|
+
var AnchorEnum = import_zod32.z.enum(["top-left", "top-right", "bottom-left", "bottom-right"]);
|
|
4743
|
+
var OverlayStyleSchema = import_zod32.z.object({
|
|
4744
|
+
font_family: import_zod32.z.string().optional(),
|
|
4745
|
+
font_size: import_zod32.z.number().positive().optional(),
|
|
4746
|
+
font_weight: import_zod32.z.union([import_zod32.z.number(), import_zod32.z.enum(["normal", "bold"])]).optional(),
|
|
4747
|
+
color: import_zod32.z.string().optional()
|
|
4748
|
+
}).optional();
|
|
4749
|
+
var DEFAULT_OVERLAY_MARGIN = 24;
|
|
4750
|
+
var DEFAULT_TEXT_STYLE = {
|
|
4751
|
+
fontFamily: "Inter",
|
|
4752
|
+
fontSize: 24,
|
|
4753
|
+
fontWeight: 600,
|
|
4754
|
+
color: "#F5F5F7"
|
|
4755
|
+
};
|
|
4756
|
+
function anchorToFrame(anchor, canvas, margin) {
|
|
4757
|
+
switch (anchor) {
|
|
4758
|
+
case "top-left":
|
|
4759
|
+
return { frame: { x: margin, y: margin }, anchorPoint: { x: 0, y: 0 } };
|
|
4760
|
+
case "top-right":
|
|
4761
|
+
return { frame: { x: canvas.width - margin, y: margin }, anchorPoint: { x: 1, y: 0 } };
|
|
4762
|
+
case "bottom-left":
|
|
4763
|
+
return { frame: { x: margin, y: canvas.height - margin }, anchorPoint: { x: 0, y: 1 } };
|
|
4764
|
+
case "bottom-right":
|
|
4765
|
+
return {
|
|
4766
|
+
frame: { x: canvas.width - margin, y: canvas.height - margin },
|
|
4767
|
+
anchorPoint: { x: 1, y: 1 }
|
|
4768
|
+
};
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
function mergeStyle(style) {
|
|
4772
|
+
return {
|
|
4773
|
+
fontFamily: style?.font_family ?? DEFAULT_TEXT_STYLE.fontFamily,
|
|
4774
|
+
fontSize: style?.font_size ?? DEFAULT_TEXT_STYLE.fontSize,
|
|
4775
|
+
fontWeight: style?.font_weight ?? DEFAULT_TEXT_STYLE.fontWeight,
|
|
4776
|
+
color: style?.color ?? DEFAULT_TEXT_STYLE.color
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
function renderPageNumberFormat(format, currentIndex, totalCount) {
|
|
4780
|
+
return format.replace(
|
|
4781
|
+
/\{(current|total)(?::0(\d+)d)?\}/g,
|
|
4782
|
+
(_, name, padWidth) => {
|
|
4783
|
+
const value = name === "current" ? currentIndex : totalCount;
|
|
4784
|
+
const str = String(value);
|
|
4785
|
+
if (padWidth) {
|
|
4786
|
+
const width = parseInt(padWidth, 10);
|
|
4787
|
+
return str.padStart(width, "0");
|
|
4788
|
+
}
|
|
4789
|
+
return str;
|
|
4790
|
+
}
|
|
4791
|
+
);
|
|
4792
|
+
}
|
|
4793
|
+
function register17(server, store) {
|
|
4794
|
+
server.tool(
|
|
4795
|
+
"atelier_add_handle",
|
|
4796
|
+
"Add an anchored creator-handle TextVisual overlay layer (tag: overlay)",
|
|
4797
|
+
{
|
|
4798
|
+
id: import_zod32.z.string().describe("Document ID"),
|
|
4799
|
+
text: import_zod32.z.string().min(1).describe('Handle text, e.g. "@username"'),
|
|
4800
|
+
anchor: AnchorEnum.describe("Anchored corner"),
|
|
4801
|
+
margin: import_zod32.z.number().nonnegative().optional().describe("Px from anchored edges (default 24)"),
|
|
4802
|
+
style: OverlayStyleSchema.describe("Text style overrides (snake_case to match recipe)"),
|
|
4803
|
+
layerId: import_zod32.z.string().optional().describe("Layer ID (default: overlay-handle)")
|
|
4804
|
+
},
|
|
4805
|
+
{ readOnlyHint: false, destructiveHint: false },
|
|
4806
|
+
async ({ id, text, anchor, margin, style, layerId }) => {
|
|
4807
|
+
const result = getDoc17(store, id);
|
|
4808
|
+
if ("error" in result) return err17(result.error);
|
|
4809
|
+
const { doc } = result;
|
|
4810
|
+
const targetId = layerId ?? "overlay-handle";
|
|
4811
|
+
if (doc.layers.some((l) => l.id === targetId)) {
|
|
4812
|
+
return err17(`Layer "${targetId}" already exists in document "${id}"`);
|
|
4813
|
+
}
|
|
4814
|
+
const m = margin ?? DEFAULT_OVERLAY_MARGIN;
|
|
4815
|
+
const { frame, anchorPoint } = anchorToFrame(anchor, doc.canvas, m);
|
|
4816
|
+
const layer = {
|
|
4817
|
+
id: targetId,
|
|
4818
|
+
tags: ["overlay"],
|
|
4819
|
+
visual: { type: "text", content: text, style: mergeStyle(style) },
|
|
4820
|
+
frame,
|
|
4821
|
+
bounds: { width: 600, height: 80 },
|
|
4822
|
+
anchorPoint
|
|
4823
|
+
};
|
|
4824
|
+
doc.layers.push(layer);
|
|
4825
|
+
store.set(id, doc);
|
|
4826
|
+
return ok17({ layerId: targetId, layer });
|
|
4827
|
+
}
|
|
4828
|
+
);
|
|
4829
|
+
server.tool(
|
|
4830
|
+
"atelier_add_page_number",
|
|
4831
|
+
"Add an anchored page-number TextVisual overlay layer (tag: overlay). Substitutes {current} / {total} (and zero-pad forms {current:02d} / {total:02d}) into format.",
|
|
4832
|
+
{
|
|
4833
|
+
id: import_zod32.z.string().describe("Document ID"),
|
|
4834
|
+
format: import_zod32.z.string().min(1).describe('Format string, e.g. "{current}/{total}" or "{current:02d}/{total:02d}"'),
|
|
4835
|
+
anchor: AnchorEnum.describe("Anchored corner"),
|
|
4836
|
+
currentIndex: import_zod32.z.number().int().nonnegative().describe("1-based current index"),
|
|
4837
|
+
totalCount: import_zod32.z.number().int().positive().describe("Total count"),
|
|
4838
|
+
margin: import_zod32.z.number().nonnegative().optional().describe("Px from anchored edges (default 24)"),
|
|
4839
|
+
style: OverlayStyleSchema.describe("Text style overrides (snake_case to match recipe)"),
|
|
4840
|
+
layerId: import_zod32.z.string().optional().describe("Layer ID (default: overlay-page-number)")
|
|
4841
|
+
},
|
|
4842
|
+
{ readOnlyHint: false, destructiveHint: false },
|
|
4843
|
+
async ({ id, format, anchor, currentIndex, totalCount, margin, style, layerId }) => {
|
|
4844
|
+
const result = getDoc17(store, id);
|
|
4845
|
+
if ("error" in result) return err17(result.error);
|
|
4846
|
+
const { doc } = result;
|
|
4847
|
+
const targetId = layerId ?? "overlay-page-number";
|
|
4848
|
+
if (doc.layers.some((l) => l.id === targetId)) {
|
|
4849
|
+
return err17(`Layer "${targetId}" already exists in document "${id}"`);
|
|
4850
|
+
}
|
|
4851
|
+
const content = renderPageNumberFormat(format, currentIndex, totalCount);
|
|
4852
|
+
const m = margin ?? DEFAULT_OVERLAY_MARGIN;
|
|
4853
|
+
const { frame, anchorPoint } = anchorToFrame(anchor, doc.canvas, m);
|
|
4854
|
+
const layer = {
|
|
4855
|
+
id: targetId,
|
|
4856
|
+
tags: ["overlay"],
|
|
4857
|
+
visual: { type: "text", content, style: mergeStyle(style) },
|
|
4858
|
+
frame,
|
|
4859
|
+
bounds: { width: 200, height: 80 },
|
|
4860
|
+
anchorPoint
|
|
4861
|
+
};
|
|
4862
|
+
doc.layers.push(layer);
|
|
4863
|
+
store.set(id, doc);
|
|
4864
|
+
return ok17({ layerId: targetId, layer, rendered: content });
|
|
4865
|
+
}
|
|
4866
|
+
);
|
|
4867
|
+
}
|
|
4868
|
+
|
|
4869
|
+
// ../mcp/src/tools/recipes.ts
|
|
4870
|
+
var import_node_fs = require("fs");
|
|
4871
|
+
var import_node_path = require("path");
|
|
4872
|
+
var import_node_os = require("os");
|
|
4873
|
+
var import_zod33 = require("zod");
|
|
4874
|
+
var import_yaml2 = require("yaml");
|
|
4875
|
+
function getDoc18(store, id) {
|
|
4876
|
+
const doc = store.get(id);
|
|
4877
|
+
if (!doc) return { error: `Document "${id}" not found` };
|
|
4878
|
+
return { doc };
|
|
4879
|
+
}
|
|
4880
|
+
function ok18(data) {
|
|
4881
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...data }) }] };
|
|
4882
|
+
}
|
|
4883
|
+
function err18(message, extra) {
|
|
4884
|
+
return {
|
|
4885
|
+
content: [{ type: "text", text: JSON.stringify({ error: message, ...extra }) }],
|
|
4886
|
+
isError: true
|
|
4887
|
+
};
|
|
4888
|
+
}
|
|
4889
|
+
function resolveRecipePath(pathOrName, projectDir) {
|
|
4890
|
+
if ((0, import_node_path.isAbsolute)(pathOrName) || pathOrName.includes("/") || pathOrName.includes("\\")) {
|
|
4891
|
+
return (0, import_node_path.resolve)(pathOrName);
|
|
4892
|
+
}
|
|
4893
|
+
const candidates = [];
|
|
4894
|
+
const exts = [".recipe.yaml", ".recipe.json", ".yaml", ".yml", ".json"];
|
|
4895
|
+
const projectRecipesDir = (0, import_node_path.join)((0, import_node_path.resolve)(projectDir), ".atelier", "recipes");
|
|
4896
|
+
for (const ext of exts) candidates.push((0, import_node_path.join)(projectRecipesDir, `${pathOrName}${ext}`));
|
|
4897
|
+
const userRecipesDir = (0, import_node_path.join)((0, import_node_os.homedir)(), ".atelier", "recipes");
|
|
4898
|
+
for (const ext of exts) candidates.push((0, import_node_path.join)(userRecipesDir, `${pathOrName}${ext}`));
|
|
4899
|
+
for (const candidate of candidates) {
|
|
4900
|
+
if ((0, import_node_fs.existsSync)(candidate)) return candidate;
|
|
4901
|
+
}
|
|
4902
|
+
throw new Error(
|
|
4903
|
+
`Recipe "${pathOrName}" not found. Looked in:
|
|
4904
|
+
${candidates.map((c) => ` ${c}`).join("\n")}`
|
|
4905
|
+
);
|
|
4906
|
+
}
|
|
4907
|
+
function parseRecipeText(raw, path) {
|
|
4908
|
+
if (path.endsWith(".json")) return JSON.parse(raw);
|
|
4909
|
+
return (0, import_yaml2.parse)(raw);
|
|
4910
|
+
}
|
|
4911
|
+
function loadRecipe(pathOrName, projectDir) {
|
|
4912
|
+
const path = resolveRecipePath(pathOrName, projectDir);
|
|
4913
|
+
const raw = (0, import_node_fs.readFileSync)(path, "utf-8");
|
|
4914
|
+
const parsed = parseRecipeText(raw, path);
|
|
4915
|
+
const result = validateRecipe(parsed);
|
|
4916
|
+
if (!result.success) {
|
|
4917
|
+
const msg = result.errors.map((e) => ` ${e.path}: ${e.message}`).join("\n");
|
|
4918
|
+
throw new Error(`Invalid recipe at ${path}:
|
|
4919
|
+
${msg}`);
|
|
4920
|
+
}
|
|
4921
|
+
return { recipe: result.data, path, warnings: result.warnings ?? [] };
|
|
4922
|
+
}
|
|
4923
|
+
function recipeToYaml(recipe) {
|
|
4924
|
+
return (0, import_yaml2.stringify)(recipe);
|
|
4925
|
+
}
|
|
4926
|
+
var DEFAULT_OVERLAY_MARGIN2 = 24;
|
|
4927
|
+
var DEFAULT_OVERLAY_TEXT_STYLE = {
|
|
4928
|
+
fontFamily: "Inter",
|
|
4929
|
+
fontSize: 24,
|
|
4930
|
+
fontWeight: 600,
|
|
4931
|
+
color: "#F5F5F7"
|
|
4932
|
+
};
|
|
4933
|
+
var HANDLE_LAYER_ID = "overlay-handle";
|
|
4934
|
+
var PAGE_NUMBER_LAYER_ID = "overlay-page-number";
|
|
4935
|
+
function applyRecipeToOverlay(doc, recipe, ctx) {
|
|
4936
|
+
const preserved = doc.layers.filter((l) => !(l.tags ?? []).includes("overlay"));
|
|
4937
|
+
const overlayLayers = [];
|
|
4938
|
+
const warnings = [];
|
|
4939
|
+
const rules = recipe.overlay_rules;
|
|
4940
|
+
if (!rules) {
|
|
4941
|
+
return { doc: { ...doc, layers: preserved }, warnings };
|
|
4942
|
+
}
|
|
4943
|
+
if (rules.handle) {
|
|
4944
|
+
overlayLayers.push(buildHandleLayer(rules.handle, doc.canvas));
|
|
4945
|
+
}
|
|
4946
|
+
if (rules.page_number) {
|
|
4947
|
+
if (ctx?.currentIndex != null && ctx?.totalCount != null) {
|
|
4948
|
+
overlayLayers.push(
|
|
4949
|
+
buildPageNumberLayer(rules.page_number, doc.canvas, ctx.currentIndex, ctx.totalCount)
|
|
4950
|
+
);
|
|
4951
|
+
} else {
|
|
4952
|
+
warnings.push(
|
|
4953
|
+
"recipe.overlay_rules.page_number is present but currentIndex/totalCount were not provided \u2014 the page_number layer was skipped."
|
|
4954
|
+
);
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
return { doc: { ...doc, layers: [...preserved, ...overlayLayers] }, warnings };
|
|
4958
|
+
}
|
|
4959
|
+
function buildHandleLayer(rule, canvas) {
|
|
4960
|
+
const margin = rule.margin ?? DEFAULT_OVERLAY_MARGIN2;
|
|
4961
|
+
const { frame, anchorPoint } = anchorToFrame2(rule.anchor, canvas, margin);
|
|
4962
|
+
return {
|
|
4963
|
+
id: HANDLE_LAYER_ID,
|
|
4964
|
+
tags: ["overlay"],
|
|
4965
|
+
visual: { type: "text", content: rule.text, style: mergeOverlayStyle(rule.style) },
|
|
4966
|
+
frame,
|
|
4967
|
+
bounds: { width: 600, height: 80 },
|
|
4968
|
+
anchorPoint
|
|
4969
|
+
};
|
|
4970
|
+
}
|
|
4971
|
+
function buildPageNumberLayer(rule, canvas, currentIndex, totalCount) {
|
|
4972
|
+
const margin = rule.margin ?? DEFAULT_OVERLAY_MARGIN2;
|
|
4973
|
+
const { frame, anchorPoint } = anchorToFrame2(rule.anchor, canvas, margin);
|
|
4974
|
+
return {
|
|
4975
|
+
id: PAGE_NUMBER_LAYER_ID,
|
|
4976
|
+
tags: ["overlay"],
|
|
4977
|
+
visual: {
|
|
4978
|
+
type: "text",
|
|
4979
|
+
content: renderPageNumberFormat2(rule.format, currentIndex, totalCount),
|
|
4980
|
+
style: mergeOverlayStyle(rule.style)
|
|
4981
|
+
},
|
|
4982
|
+
frame,
|
|
4983
|
+
bounds: { width: 200, height: 80 },
|
|
4984
|
+
anchorPoint
|
|
4985
|
+
};
|
|
4986
|
+
}
|
|
4987
|
+
function anchorToFrame2(anchor, canvas, margin) {
|
|
4988
|
+
switch (anchor) {
|
|
4989
|
+
case "top-left":
|
|
4990
|
+
return { frame: { x: margin, y: margin }, anchorPoint: { x: 0, y: 0 } };
|
|
4991
|
+
case "top-right":
|
|
4992
|
+
return { frame: { x: canvas.width - margin, y: margin }, anchorPoint: { x: 1, y: 0 } };
|
|
4993
|
+
case "bottom-left":
|
|
4994
|
+
return { frame: { x: margin, y: canvas.height - margin }, anchorPoint: { x: 0, y: 1 } };
|
|
4995
|
+
case "bottom-right":
|
|
4996
|
+
return {
|
|
4997
|
+
frame: { x: canvas.width - margin, y: canvas.height - margin },
|
|
4998
|
+
anchorPoint: { x: 1, y: 1 }
|
|
4999
|
+
};
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
function mergeOverlayStyle(style) {
|
|
5003
|
+
return {
|
|
5004
|
+
fontFamily: style?.font_family ?? DEFAULT_OVERLAY_TEXT_STYLE.fontFamily,
|
|
5005
|
+
fontSize: style?.font_size ?? DEFAULT_OVERLAY_TEXT_STYLE.fontSize,
|
|
5006
|
+
fontWeight: style?.font_weight ?? DEFAULT_OVERLAY_TEXT_STYLE.fontWeight,
|
|
5007
|
+
color: style?.color ?? DEFAULT_OVERLAY_TEXT_STYLE.color
|
|
5008
|
+
};
|
|
5009
|
+
}
|
|
5010
|
+
function renderPageNumberFormat2(format, currentIndex, totalCount) {
|
|
5011
|
+
return format.replace(
|
|
5012
|
+
/\{(current|total)(?::0(\d+)d)?\}/g,
|
|
5013
|
+
(_, name, padWidth) => {
|
|
5014
|
+
const value = name === "current" ? currentIndex : totalCount;
|
|
5015
|
+
const str = String(value);
|
|
5016
|
+
if (padWidth) return str.padStart(parseInt(padWidth, 10), "0");
|
|
5017
|
+
return str;
|
|
5018
|
+
}
|
|
5019
|
+
);
|
|
5020
|
+
}
|
|
5021
|
+
var RECIPE_EXTS = [".recipe.yaml", ".recipe.yml", ".recipe.json"];
|
|
5022
|
+
function isRecipeFile(name) {
|
|
5023
|
+
return RECIPE_EXTS.some((ext) => name.endsWith(ext));
|
|
5024
|
+
}
|
|
5025
|
+
function listRecipesIn(dir) {
|
|
5026
|
+
if (!(0, import_node_fs.existsSync)(dir)) return [];
|
|
5027
|
+
let entries;
|
|
5028
|
+
try {
|
|
5029
|
+
entries = (0, import_node_fs.readdirSync)(dir);
|
|
5030
|
+
} catch {
|
|
5031
|
+
return [];
|
|
5032
|
+
}
|
|
5033
|
+
return entries.filter(isRecipeFile).map((name) => ({ name, path: (0, import_node_path.join)(dir, name) })).sort((a, b) => a.name.localeCompare(b.name));
|
|
5034
|
+
}
|
|
5035
|
+
function register18(server, store) {
|
|
5036
|
+
server.tool(
|
|
5037
|
+
"atelier_recipe_list",
|
|
5038
|
+
"List discoverable Studio Recipes \u2014 project-local <projectDir>/.atelier/recipes/*.recipe.* plus ~/.atelier/recipes/*.recipe.*. Returns { name, path } entries with absolute paths.",
|
|
5039
|
+
{
|
|
5040
|
+
projectDir: import_zod33.z.string().optional().describe("Project root to search (default: process.cwd())")
|
|
5041
|
+
},
|
|
5042
|
+
{ readOnlyHint: true, destructiveHint: false },
|
|
5043
|
+
async ({ projectDir }) => {
|
|
5044
|
+
const root = (0, import_node_path.resolve)(projectDir ?? process.cwd());
|
|
5045
|
+
const projectRecipes = listRecipesIn((0, import_node_path.join)(root, ".atelier", "recipes"));
|
|
5046
|
+
const userRecipes = listRecipesIn((0, import_node_path.join)((0, import_node_os.homedir)(), ".atelier", "recipes"));
|
|
5047
|
+
const seen = new Set(projectRecipes.map((r) => r.name));
|
|
5048
|
+
const recipes = [...projectRecipes, ...userRecipes.filter((r) => !seen.has(r.name))];
|
|
5049
|
+
return ok18({ count: recipes.length, recipes });
|
|
5050
|
+
}
|
|
5051
|
+
);
|
|
5052
|
+
server.tool(
|
|
5053
|
+
"atelier_recipe_get",
|
|
5054
|
+
"Load a recipe and return BOTH the parsed object and its serialized YAML text (so the agent can show/explain it), plus any validation warnings.",
|
|
5055
|
+
{
|
|
5056
|
+
path: import_zod33.z.string().describe("Recipe path or bare name (resolved like the CLI)"),
|
|
5057
|
+
projectDir: import_zod33.z.string().optional().describe("Project root for name resolution (default: process.cwd())")
|
|
5058
|
+
},
|
|
5059
|
+
{ readOnlyHint: true, destructiveHint: false },
|
|
5060
|
+
async ({ path, projectDir }) => {
|
|
5061
|
+
const root = (0, import_node_path.resolve)(projectDir ?? process.cwd());
|
|
5062
|
+
try {
|
|
5063
|
+
const loaded = loadRecipe(path, root);
|
|
5064
|
+
return ok18({
|
|
5065
|
+
path: loaded.path,
|
|
5066
|
+
recipe: loaded.recipe,
|
|
5067
|
+
yaml: recipeToYaml(loaded.recipe),
|
|
5068
|
+
warnings: loaded.warnings
|
|
5069
|
+
});
|
|
5070
|
+
} catch (e) {
|
|
5071
|
+
return err18(e.message);
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
);
|
|
5075
|
+
server.tool(
|
|
5076
|
+
"atelier_recipe_validate",
|
|
5077
|
+
"Validate a recipe from a path OR inline YAML text. Returns { success, warnings, errors }.",
|
|
5078
|
+
{
|
|
5079
|
+
path: import_zod33.z.string().optional().describe("Recipe path or bare name to validate"),
|
|
5080
|
+
yaml: import_zod33.z.string().optional().describe("Inline YAML text to validate (alternative to path)"),
|
|
5081
|
+
projectDir: import_zod33.z.string().optional().describe("Project root for name resolution (default: process.cwd())")
|
|
5082
|
+
},
|
|
5083
|
+
{ readOnlyHint: true, destructiveHint: false },
|
|
5084
|
+
async ({ path, yaml, projectDir }) => {
|
|
5085
|
+
if (!path && yaml === void 0) {
|
|
5086
|
+
return err18("Provide either `path` or `yaml` to validate");
|
|
5087
|
+
}
|
|
5088
|
+
const root = (0, import_node_path.resolve)(projectDir ?? process.cwd());
|
|
5089
|
+
let parsed;
|
|
5090
|
+
try {
|
|
5091
|
+
if (yaml !== void 0) {
|
|
5092
|
+
parsed = (0, import_yaml2.parse)(yaml);
|
|
5093
|
+
} else {
|
|
5094
|
+
const resolved = resolveRecipePath(path, root);
|
|
5095
|
+
parsed = parseRecipeText((0, import_node_fs.readFileSync)(resolved, "utf-8"), resolved);
|
|
5096
|
+
}
|
|
5097
|
+
} catch (e) {
|
|
5098
|
+
return ok18({ valid: false, warnings: [], errors: [{ path: "(yaml)", message: e.message }] });
|
|
5099
|
+
}
|
|
5100
|
+
const result = validateRecipe(parsed);
|
|
5101
|
+
if (!result.success) {
|
|
5102
|
+
return ok18({ valid: false, warnings: [], errors: result.errors });
|
|
5103
|
+
}
|
|
5104
|
+
return ok18({ valid: true, warnings: result.warnings ?? [], errors: [] });
|
|
5105
|
+
}
|
|
5106
|
+
);
|
|
5107
|
+
server.tool(
|
|
5108
|
+
"atelier_recipe_save",
|
|
5109
|
+
"Write a recipe to disk. Accepts a recipe object (serialized via YAML) OR raw YAML text. Validates BEFORE writing and REFUSES to write an invalid recipe (returns an error with the validation issues). Creates parent directories as needed.",
|
|
5110
|
+
{
|
|
5111
|
+
path: import_zod33.z.string().describe("Absolute or relative file path to write the recipe to"),
|
|
5112
|
+
recipe: import_zod33.z.record(import_zod33.z.unknown()).optional().describe("Recipe object (will be serialized to YAML)"),
|
|
5113
|
+
yaml: import_zod33.z.string().optional().describe("Raw YAML text (alternative to `recipe`)")
|
|
5114
|
+
},
|
|
5115
|
+
{ readOnlyHint: false, destructiveHint: true },
|
|
5116
|
+
async ({ path, recipe, yaml }) => {
|
|
5117
|
+
if (recipe === void 0 && yaml === void 0) {
|
|
5118
|
+
return err18("Provide either `recipe` (object) or `yaml` (text) to save");
|
|
5119
|
+
}
|
|
5120
|
+
let parsed;
|
|
5121
|
+
let yamlText;
|
|
5122
|
+
if (yaml !== void 0) {
|
|
5123
|
+
yamlText = yaml;
|
|
5124
|
+
try {
|
|
5125
|
+
parsed = (0, import_yaml2.parse)(yaml);
|
|
5126
|
+
} catch (e) {
|
|
5127
|
+
return err18(`YAML parse error: ${e.message}`);
|
|
5128
|
+
}
|
|
5129
|
+
} else {
|
|
5130
|
+
parsed = recipe;
|
|
5131
|
+
yamlText = (0, import_yaml2.stringify)(recipe);
|
|
5132
|
+
}
|
|
5133
|
+
const result = validateRecipe(parsed);
|
|
5134
|
+
if (!result.success) {
|
|
5135
|
+
return err18("Refusing to write an invalid recipe", { errors: result.errors });
|
|
5136
|
+
}
|
|
5137
|
+
const absPath = (0, import_node_path.resolve)(path);
|
|
5138
|
+
try {
|
|
5139
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(absPath), { recursive: true });
|
|
5140
|
+
(0, import_node_fs.writeFileSync)(absPath, yamlText, "utf-8");
|
|
5141
|
+
} catch (e) {
|
|
5142
|
+
return err18(`Failed to write recipe: ${e.message}`);
|
|
5143
|
+
}
|
|
5144
|
+
return ok18({ path: absPath, warnings: result.warnings ?? [] });
|
|
5145
|
+
}
|
|
5146
|
+
);
|
|
5147
|
+
server.tool(
|
|
5148
|
+
"atelier_recipe_apply",
|
|
5149
|
+
`Apply a recipe's overlay_rules to an in-store document (handle + page-number overlays). Accepts a recipe object OR a path/name. The result is stored back with source="llm". NOTE: only overlay_rules are applied here \u2014 silence-trim / transcribe / caption application remain CLI-only. page_number overlays require currentIndex + totalCount; if a recipe requests page_number without them, that layer is skipped and a warning is returned.`,
|
|
5150
|
+
{
|
|
5151
|
+
documentId: import_zod33.z.string().describe("In-store document ID to apply the recipe to"),
|
|
5152
|
+
path: import_zod33.z.string().optional().describe("Recipe path or bare name (alternative to `recipe`)"),
|
|
5153
|
+
recipe: import_zod33.z.record(import_zod33.z.unknown()).optional().describe("Recipe object (alternative to `path`)"),
|
|
5154
|
+
projectDir: import_zod33.z.string().optional().describe("Project root for name resolution (default: process.cwd())"),
|
|
5155
|
+
currentIndex: import_zod33.z.number().int().nonnegative().optional().describe("1-based carousel index for page_number"),
|
|
5156
|
+
totalCount: import_zod33.z.number().int().positive().optional().describe("Total carousel size for page_number")
|
|
5157
|
+
},
|
|
5158
|
+
{ readOnlyHint: false, destructiveHint: false },
|
|
5159
|
+
async ({ documentId, path, recipe, projectDir, currentIndex, totalCount }) => {
|
|
5160
|
+
const result = getDoc18(store, documentId);
|
|
5161
|
+
if ("error" in result) return err18(result.error);
|
|
5162
|
+
const { doc } = result;
|
|
5163
|
+
if (path === void 0 && recipe === void 0) {
|
|
5164
|
+
return err18("Provide either `path` or `recipe` to apply");
|
|
5165
|
+
}
|
|
5166
|
+
let resolvedRecipe;
|
|
5167
|
+
if (recipe !== void 0) {
|
|
5168
|
+
const validated = validateRecipe(recipe);
|
|
5169
|
+
if (!validated.success) {
|
|
5170
|
+
return err18("Invalid recipe", { errors: validated.errors });
|
|
5171
|
+
}
|
|
5172
|
+
resolvedRecipe = validated.data;
|
|
5173
|
+
} else {
|
|
5174
|
+
const root = (0, import_node_path.resolve)(projectDir ?? process.cwd());
|
|
5175
|
+
try {
|
|
5176
|
+
resolvedRecipe = loadRecipe(path, root).recipe;
|
|
5177
|
+
} catch (e) {
|
|
5178
|
+
return err18(e.message);
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
const { doc: updated, warnings } = applyRecipeToOverlay(doc, resolvedRecipe, {
|
|
5182
|
+
currentIndex,
|
|
5183
|
+
totalCount
|
|
5184
|
+
});
|
|
5185
|
+
store.set(documentId, updated, "llm");
|
|
5186
|
+
return ok18({
|
|
5187
|
+
documentId,
|
|
5188
|
+
warnings,
|
|
5189
|
+
layerCount: updated.layers.length,
|
|
5190
|
+
document: updated
|
|
5191
|
+
});
|
|
5192
|
+
}
|
|
5193
|
+
);
|
|
5194
|
+
}
|
|
5195
|
+
|
|
5196
|
+
// ../mcp/src/tools/import-images.ts
|
|
5197
|
+
var import_node_fs2 = require("fs");
|
|
5198
|
+
var import_node_path2 = require("path");
|
|
5199
|
+
var import_zod34 = require("zod");
|
|
5200
|
+
function getDoc19(store, id) {
|
|
5201
|
+
const doc = store.get(id);
|
|
5202
|
+
if (!doc) return { error: `Document "${id}" not found` };
|
|
5203
|
+
return { doc };
|
|
5204
|
+
}
|
|
5205
|
+
function ok19(data) {
|
|
5206
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...data }) }] };
|
|
5207
|
+
}
|
|
5208
|
+
function err19(message) {
|
|
5209
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
5210
|
+
}
|
|
5211
|
+
var IMAGE_EXTS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg"]);
|
|
5212
|
+
function isImageFile(name) {
|
|
5213
|
+
return IMAGE_EXTS.has((0, import_node_path2.extname)(name).toLowerCase());
|
|
5214
|
+
}
|
|
5215
|
+
function matchesGlob(name, glob) {
|
|
5216
|
+
if (!glob) return true;
|
|
5217
|
+
const escaped = glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
5218
|
+
return new RegExp(`^${escaped}$`, "i").test(name);
|
|
5219
|
+
}
|
|
5220
|
+
function deriveAssetId(filename, used) {
|
|
5221
|
+
const stem = (0, import_node_path2.basename)(filename, (0, import_node_path2.extname)(filename));
|
|
5222
|
+
const base = stem.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "image";
|
|
5223
|
+
let candidate = base;
|
|
5224
|
+
let n = 2;
|
|
5225
|
+
while (used.has(candidate)) {
|
|
5226
|
+
candidate = `${base}-${n}`;
|
|
5227
|
+
n++;
|
|
5228
|
+
}
|
|
5229
|
+
used.add(candidate);
|
|
5230
|
+
return candidate;
|
|
5231
|
+
}
|
|
5232
|
+
function nextImageLayerId(existing, seq) {
|
|
5233
|
+
let candidate = `image-${seq}`;
|
|
5234
|
+
let n = seq;
|
|
5235
|
+
while (existing.has(candidate)) {
|
|
5236
|
+
n++;
|
|
5237
|
+
candidate = `image-${n}`;
|
|
5238
|
+
}
|
|
5239
|
+
existing.add(candidate);
|
|
5240
|
+
return candidate;
|
|
5241
|
+
}
|
|
5242
|
+
function register19(server, store) {
|
|
5243
|
+
server.tool(
|
|
5244
|
+
"atelier_import_images",
|
|
5245
|
+
`Import every image in a folder into a document. Registers each as an asset and, unless asLayers is false, creates one fit-to-canvas ImageVisual layer per image (centered). Extensions: .png .jpg .jpeg .webp .gif .svg. Optional glob filters by filename (e.g. "*.png"); results are sorted by name. If the folder has exactly one image AND the doc's layer[0] is the welcome "background" placeholder, that image replaces the placeholder in place. Asset src is the absolute file path. Layer bounds default to a centered min(canvas.w, canvas.h) square because natural image dimensions are not measured (no image-dimension dependency).`,
|
|
5246
|
+
{
|
|
5247
|
+
documentId: import_zod34.z.string().describe("In-store document ID to import into"),
|
|
5248
|
+
dir: import_zod34.z.string().describe("Directory containing the images"),
|
|
5249
|
+
glob: import_zod34.z.string().optional().describe('Optional filename glob, e.g. "*.png" (default: all images)'),
|
|
5250
|
+
asLayers: import_zod34.z.boolean().optional().describe("Create layers per image (default: true). false = register assets only.")
|
|
5251
|
+
},
|
|
5252
|
+
{ readOnlyHint: false, destructiveHint: false },
|
|
5253
|
+
async ({ documentId, dir, glob, asLayers }) => {
|
|
5254
|
+
const result = getDoc19(store, documentId);
|
|
5255
|
+
if ("error" in result) return err19(result.error);
|
|
5256
|
+
const { doc } = result;
|
|
5257
|
+
const absDir = (0, import_node_path2.resolve)(dir);
|
|
5258
|
+
if (!(0, import_node_fs2.existsSync)(absDir)) return err19(`Directory "${absDir}" does not exist`);
|
|
5259
|
+
if (!(0, import_node_fs2.statSync)(absDir).isDirectory()) return err19(`Path "${absDir}" is not a directory`);
|
|
5260
|
+
const files = (0, import_node_fs2.readdirSync)(absDir).filter((name) => isImageFile(name) && matchesGlob(name, glob)).sort((a, b) => a.localeCompare(b));
|
|
5261
|
+
if (files.length === 0) {
|
|
5262
|
+
return err19(`No image files matched in "${absDir}"${glob ? ` (glob: ${glob})` : ""}`);
|
|
5263
|
+
}
|
|
5264
|
+
const makeLayers = asLayers !== false;
|
|
5265
|
+
const canvas = doc.canvas;
|
|
5266
|
+
const square = Math.min(canvas.width, canvas.height);
|
|
5267
|
+
const allowBackgroundSwap = files.length === 1 && doc.layers[0]?.id === "background";
|
|
5268
|
+
const newAssets = { ...doc.assets ?? {} };
|
|
5269
|
+
const newLayers = [...doc.layers];
|
|
5270
|
+
const usedAssetIds = new Set(Object.keys(newAssets));
|
|
5271
|
+
const existingLayerIds = new Set(newLayers.map((l) => l.id));
|
|
5272
|
+
const assetIds = [];
|
|
5273
|
+
const layerIds = [];
|
|
5274
|
+
let layerSeq = newLayers.length + 1;
|
|
5275
|
+
for (const file of files) {
|
|
5276
|
+
const absPath = (0, import_node_path2.join)(absDir, file);
|
|
5277
|
+
const assetId = deriveAssetId(file, usedAssetIds);
|
|
5278
|
+
newAssets[assetId] = { type: "image", src: absPath, description: file };
|
|
5279
|
+
assetIds.push(assetId);
|
|
5280
|
+
if (!makeLayers) continue;
|
|
5281
|
+
const layerId = nextImageLayerId(existingLayerIds, layerSeq);
|
|
5282
|
+
layerSeq++;
|
|
5283
|
+
const layer = {
|
|
5284
|
+
id: layerId,
|
|
5285
|
+
visual: { type: "image", assetId, src: absPath },
|
|
5286
|
+
frame: { x: canvas.width / 2, y: canvas.height / 2 },
|
|
5287
|
+
bounds: { width: square, height: square },
|
|
5288
|
+
anchorPoint: { x: 0.5, y: 0.5 },
|
|
5289
|
+
opacity: 1
|
|
5290
|
+
};
|
|
5291
|
+
if (allowBackgroundSwap) {
|
|
5292
|
+
newLayers[0] = layer;
|
|
5293
|
+
} else {
|
|
5294
|
+
newLayers.unshift(layer);
|
|
5295
|
+
}
|
|
5296
|
+
layerIds.push(layerId);
|
|
5297
|
+
}
|
|
5298
|
+
const newDoc = { ...doc, assets: newAssets, layers: newLayers };
|
|
5299
|
+
store.set(documentId, newDoc, "llm");
|
|
5300
|
+
return ok19({
|
|
5301
|
+
imported: files.length,
|
|
5302
|
+
assetIds,
|
|
5303
|
+
layerIds,
|
|
5304
|
+
asLayers: makeLayers,
|
|
5305
|
+
note: "Layer bounds default to a centered square (min canvas dimension) \u2014 natural image dimensions are not measured."
|
|
5306
|
+
});
|
|
5307
|
+
}
|
|
5308
|
+
);
|
|
5309
|
+
}
|
|
5310
|
+
|
|
5311
|
+
// ../mcp/src/bridge-protocol.ts
|
|
5312
|
+
var BRIDGE_PROTOCOL_VERSION = 1;
|
|
5313
|
+
function isBridgeEnvelope(value) {
|
|
5314
|
+
if (!value || typeof value !== "object") return false;
|
|
5315
|
+
const t = value.type;
|
|
5316
|
+
return t === "hello" || t === "doc:load" || t === "doc:loaded" || t === "doc:patch" || t === "llm:mutation" || t === "error";
|
|
5317
|
+
}
|
|
5318
|
+
|
|
5319
|
+
// ../mcp/src/transports/ws-transport.ts
|
|
5320
|
+
var WebSocketServerTransport = class {
|
|
5321
|
+
constructor(ws) {
|
|
5322
|
+
this.ws = ws;
|
|
5323
|
+
}
|
|
5324
|
+
onclose;
|
|
5325
|
+
onerror;
|
|
5326
|
+
onmessage;
|
|
5327
|
+
sessionId;
|
|
5328
|
+
started = false;
|
|
5329
|
+
closed = false;
|
|
5330
|
+
async start() {
|
|
5331
|
+
if (this.started) {
|
|
5332
|
+
throw new Error(
|
|
5333
|
+
"WebSocketServerTransport already started \u2014 the MCP SDK calls start() automatically; do not call it again"
|
|
5334
|
+
);
|
|
5335
|
+
}
|
|
5336
|
+
this.started = true;
|
|
5337
|
+
this.ws.on("message", (data) => {
|
|
5338
|
+
let text;
|
|
5339
|
+
try {
|
|
5340
|
+
if (typeof data === "string") {
|
|
5341
|
+
text = data;
|
|
5342
|
+
} else if (data instanceof Buffer) {
|
|
5343
|
+
text = data.toString("utf-8");
|
|
5344
|
+
} else if (Array.isArray(data)) {
|
|
5345
|
+
text = Buffer.concat(data).toString("utf-8");
|
|
5346
|
+
} else if (data instanceof ArrayBuffer) {
|
|
5347
|
+
text = Buffer.from(data).toString("utf-8");
|
|
5348
|
+
} else {
|
|
5349
|
+
text = String(data);
|
|
5350
|
+
}
|
|
5351
|
+
} catch (err20) {
|
|
5352
|
+
this.onerror?.(err20 instanceof Error ? err20 : new Error(String(err20)));
|
|
5353
|
+
return;
|
|
5354
|
+
}
|
|
5355
|
+
let parsed;
|
|
5356
|
+
try {
|
|
5357
|
+
parsed = JSON.parse(text);
|
|
5358
|
+
} catch (err20) {
|
|
5359
|
+
this.onerror?.(
|
|
5360
|
+
new Error(
|
|
5361
|
+
`WebSocketServerTransport: failed to parse JSON-RPC message: ${err20 instanceof Error ? err20.message : String(err20)}`
|
|
5362
|
+
)
|
|
5363
|
+
);
|
|
5364
|
+
return;
|
|
5365
|
+
}
|
|
5366
|
+
this.onmessage?.(parsed);
|
|
5367
|
+
});
|
|
5368
|
+
this.ws.on("close", () => {
|
|
5369
|
+
if (this.closed) return;
|
|
5370
|
+
this.closed = true;
|
|
5371
|
+
this.onclose?.();
|
|
5372
|
+
});
|
|
5373
|
+
this.ws.on("error", (err20) => {
|
|
5374
|
+
this.onerror?.(err20);
|
|
5375
|
+
});
|
|
5376
|
+
}
|
|
5377
|
+
async send(message) {
|
|
5378
|
+
if (this.closed) {
|
|
5379
|
+
throw new Error("WebSocketServerTransport: cannot send after close");
|
|
5380
|
+
}
|
|
5381
|
+
if (this.ws.readyState !== 1) {
|
|
5382
|
+
throw new Error(
|
|
5383
|
+
`WebSocketServerTransport: WebSocket is not OPEN (readyState=${this.ws.readyState})`
|
|
5384
|
+
);
|
|
5385
|
+
}
|
|
5386
|
+
this.ws.send(JSON.stringify(message));
|
|
5387
|
+
}
|
|
5388
|
+
async close() {
|
|
5389
|
+
if (this.closed) return;
|
|
5390
|
+
this.closed = true;
|
|
5391
|
+
try {
|
|
5392
|
+
this.ws.close();
|
|
5393
|
+
} catch {
|
|
5394
|
+
}
|
|
5395
|
+
this.onclose?.();
|
|
5396
|
+
}
|
|
5397
|
+
};
|
|
5398
|
+
|
|
4557
5399
|
// ../mcp/src/index.ts
|
|
4558
|
-
function createServer() {
|
|
4559
|
-
const store = new DocumentStore();
|
|
5400
|
+
function createServer(store = new DocumentStore()) {
|
|
4560
5401
|
const server = new import_mcp.McpServer(
|
|
4561
5402
|
{ name: "atelier", version: "0.1.0" },
|
|
4562
5403
|
{ capabilities: { tools: {} } }
|
|
@@ -4577,6 +5418,9 @@ function createServer() {
|
|
|
4577
5418
|
register14(server, store);
|
|
4578
5419
|
register15(server, store);
|
|
4579
5420
|
register16(server, store);
|
|
5421
|
+
register17(server, store);
|
|
5422
|
+
register18(server, store);
|
|
5423
|
+
register19(server, store);
|
|
4580
5424
|
return { server, store };
|
|
4581
5425
|
}
|
|
4582
5426
|
var isMain = typeof process !== "undefined" && process.argv[1] && (process.argv[1].endsWith("/index.js") || process.argv[1].endsWith("/index.cjs") || process.argv[1].includes("atelier-mcp"));
|
|
@@ -4590,18 +5434,24 @@ if (isMain) {
|
|
|
4590
5434
|
}
|
|
4591
5435
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4592
5436
|
0 && (module.exports = {
|
|
5437
|
+
BRIDGE_PROTOCOL_VERSION,
|
|
4593
5438
|
DocumentStore,
|
|
5439
|
+
WebSocketServerTransport,
|
|
4594
5440
|
createServer,
|
|
5441
|
+
isBridgeEnvelope,
|
|
4595
5442
|
registerAssetTools,
|
|
4596
5443
|
registerDeltaTools,
|
|
4597
5444
|
registerDocumentTools,
|
|
4598
5445
|
registerExportTools,
|
|
5446
|
+
registerImportImageTools,
|
|
4599
5447
|
registerInteractionTools,
|
|
4600
5448
|
registerLayerEffectTools,
|
|
4601
5449
|
registerLayerTools,
|
|
5450
|
+
registerOverlayTools,
|
|
4602
5451
|
registerPerformanceTools,
|
|
4603
5452
|
registerPresetTools,
|
|
4604
5453
|
registerPreviewTools,
|
|
5454
|
+
registerRecipeTools,
|
|
4605
5455
|
registerRefTools,
|
|
4606
5456
|
registerShapeTools,
|
|
4607
5457
|
registerStateConfigTools,
|