@spectratools/graphic-designer-cli 0.8.0 → 0.10.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/cli.js +273 -19
- package/dist/index.d.ts +6 -6
- package/dist/index.js +273 -19
- package/dist/qa.d.ts +1 -1
- package/dist/qa.js +18 -0
- package/dist/renderer.d.ts +1 -1
- package/dist/renderer.js +214 -17
- package/dist/{spec.schema-B_Z-KNqt.d.ts → spec.schema-B6sXTTou.d.ts} +1664 -1314
- package/dist/spec.schema.d.ts +1 -1
- package/dist/spec.schema.js +18 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -829,6 +829,21 @@ var drawLineSchema = z2.object({
|
|
|
829
829
|
opacity: z2.number().min(0).max(1).default(1),
|
|
830
830
|
shadow: drawShadowSchema.optional()
|
|
831
831
|
}).strict();
|
|
832
|
+
var drawArcSchema = z2.object({
|
|
833
|
+
type: z2.literal("arc"),
|
|
834
|
+
center: z2.object({
|
|
835
|
+
x: z2.number(),
|
|
836
|
+
y: z2.number()
|
|
837
|
+
}).strict(),
|
|
838
|
+
radius: z2.number().positive(),
|
|
839
|
+
startAngle: z2.number(),
|
|
840
|
+
endAngle: z2.number(),
|
|
841
|
+
color: colorHexSchema2.default("#FFFFFF"),
|
|
842
|
+
width: z2.number().min(0.5).max(32).default(2),
|
|
843
|
+
dash: z2.array(z2.number()).max(6).optional(),
|
|
844
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
845
|
+
shadow: drawShadowSchema.optional()
|
|
846
|
+
}).strict();
|
|
832
847
|
var drawPointSchema = z2.object({
|
|
833
848
|
x: z2.number(),
|
|
834
849
|
y: z2.number()
|
|
@@ -913,6 +928,7 @@ var drawCommandSchema = z2.discriminatedUnion("type", [
|
|
|
913
928
|
drawCircleSchema,
|
|
914
929
|
drawTextSchema,
|
|
915
930
|
drawLineSchema,
|
|
931
|
+
drawArcSchema,
|
|
916
932
|
drawBezierSchema,
|
|
917
933
|
drawPathSchema,
|
|
918
934
|
drawBadgeSchema,
|
|
@@ -1049,6 +1065,8 @@ var connectionElementSchema = z2.object({
|
|
|
1049
1065
|
label: z2.string().min(1).max(200).optional(),
|
|
1050
1066
|
labelPosition: z2.enum(["start", "middle", "end"]).default("middle"),
|
|
1051
1067
|
color: colorHexSchema2.optional(),
|
|
1068
|
+
fromColor: colorHexSchema2.optional(),
|
|
1069
|
+
toColor: colorHexSchema2.optional(),
|
|
1052
1070
|
width: z2.number().min(0.5).max(10).optional(),
|
|
1053
1071
|
strokeWidth: z2.number().min(0.5).max(10).default(2),
|
|
1054
1072
|
arrowSize: z2.number().min(4).max(32).optional(),
|
|
@@ -1880,6 +1898,38 @@ function renderFlowNode(ctx, node, bounds, theme) {
|
|
|
1880
1898
|
ctx.shadowOffsetX = 0;
|
|
1881
1899
|
ctx.shadowOffsetY = 0;
|
|
1882
1900
|
}
|
|
1901
|
+
if (node.accentColor) {
|
|
1902
|
+
const barWidth = node.accentBarWidth ?? 3;
|
|
1903
|
+
const effectiveRadius = node.shape === "box" ? 0 : cornerRadius;
|
|
1904
|
+
ctx.save();
|
|
1905
|
+
ctx.beginPath();
|
|
1906
|
+
ctx.roundRect(bounds.x, bounds.y, bounds.width, bounds.height, effectiveRadius);
|
|
1907
|
+
ctx.clip();
|
|
1908
|
+
ctx.fillStyle = node.accentColor;
|
|
1909
|
+
ctx.fillRect(bounds.x, bounds.y, barWidth, bounds.height);
|
|
1910
|
+
ctx.restore();
|
|
1911
|
+
}
|
|
1912
|
+
if (node.glowColor) {
|
|
1913
|
+
const glowW = node.glowWidth ?? 16;
|
|
1914
|
+
const glowOp = node.glowOpacity ?? 0.15;
|
|
1915
|
+
ctx.save();
|
|
1916
|
+
ctx.beginPath();
|
|
1917
|
+
ctx.roundRect(bounds.x, bounds.y, bounds.width, bounds.height, cornerRadius);
|
|
1918
|
+
ctx.clip();
|
|
1919
|
+
const barOffset = node.accentColor ? node.accentBarWidth ?? 3 : 0;
|
|
1920
|
+
const gradient = ctx.createLinearGradient(
|
|
1921
|
+
bounds.x + barOffset,
|
|
1922
|
+
bounds.y,
|
|
1923
|
+
bounds.x + barOffset + glowW,
|
|
1924
|
+
bounds.y
|
|
1925
|
+
);
|
|
1926
|
+
gradient.addColorStop(0, node.glowColor);
|
|
1927
|
+
gradient.addColorStop(1, "rgba(0,0,0,0)");
|
|
1928
|
+
ctx.globalAlpha = glowOp;
|
|
1929
|
+
ctx.fillStyle = gradient;
|
|
1930
|
+
ctx.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
1931
|
+
ctx.restore();
|
|
1932
|
+
}
|
|
1883
1933
|
const headingFont = resolveFont(theme.fonts.heading, "heading");
|
|
1884
1934
|
const bodyFont = resolveFont(theme.fonts.body, "body");
|
|
1885
1935
|
const monoFont = resolveFont(theme.fonts.mono, "mono");
|
|
@@ -3155,16 +3205,6 @@ function drawBezier(ctx, points, style) {
|
|
|
3155
3205
|
ctx.quadraticCurveTo(penultimate.x, penultimate.y, last.x, last.y);
|
|
3156
3206
|
ctx.stroke();
|
|
3157
3207
|
}
|
|
3158
|
-
function drawOrthogonalPath(ctx, from, to, style) {
|
|
3159
|
-
const midX = (from.x + to.x) / 2;
|
|
3160
|
-
applyLineStyle(ctx, style);
|
|
3161
|
-
ctx.beginPath();
|
|
3162
|
-
ctx.moveTo(from.x, from.y);
|
|
3163
|
-
ctx.lineTo(midX, from.y);
|
|
3164
|
-
ctx.lineTo(midX, to.y);
|
|
3165
|
-
ctx.lineTo(to.x, to.y);
|
|
3166
|
-
ctx.stroke();
|
|
3167
|
-
}
|
|
3168
3208
|
|
|
3169
3209
|
// src/renderers/connection.ts
|
|
3170
3210
|
var ELLIPSE_KAPPA = 4 * (Math.sqrt(2) - 1) / 3;
|
|
@@ -3404,11 +3444,36 @@ function pointAlongPolyline(points, t) {
|
|
|
3404
3444
|
}
|
|
3405
3445
|
return points[points.length - 1];
|
|
3406
3446
|
}
|
|
3407
|
-
function
|
|
3447
|
+
function createConnectionGradient(ctx, start, end, fromColor, baseColor, toColor) {
|
|
3448
|
+
const gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
|
|
3449
|
+
gradient.addColorStop(0, fromColor);
|
|
3450
|
+
gradient.addColorStop(0.5, baseColor);
|
|
3451
|
+
gradient.addColorStop(1, toColor);
|
|
3452
|
+
return gradient;
|
|
3453
|
+
}
|
|
3454
|
+
function resolveConnectionStroke(ctx, start, end, fromColor, baseColor, toColor) {
|
|
3455
|
+
if (!fromColor || !toColor) {
|
|
3456
|
+
return baseColor;
|
|
3457
|
+
}
|
|
3458
|
+
return createConnectionGradient(ctx, start, end, fromColor, baseColor, toColor);
|
|
3459
|
+
}
|
|
3460
|
+
function drawOrthogonalPathWithStroke(ctx, from, to, style, stroke) {
|
|
3461
|
+
const midX = (from.x + to.x) / 2;
|
|
3462
|
+
ctx.strokeStyle = stroke;
|
|
3463
|
+
ctx.lineWidth = style.width;
|
|
3464
|
+
ctx.setLineDash(style.dash ?? []);
|
|
3465
|
+
ctx.beginPath();
|
|
3466
|
+
ctx.moveTo(from.x, from.y);
|
|
3467
|
+
ctx.lineTo(midX, from.y);
|
|
3468
|
+
ctx.lineTo(midX, to.y);
|
|
3469
|
+
ctx.lineTo(to.x, to.y);
|
|
3470
|
+
ctx.stroke();
|
|
3471
|
+
}
|
|
3472
|
+
function drawCubicInterpolatedPath(ctx, points, style, stroke) {
|
|
3408
3473
|
if (points.length < 2) {
|
|
3409
3474
|
return;
|
|
3410
3475
|
}
|
|
3411
|
-
ctx.strokeStyle =
|
|
3476
|
+
ctx.strokeStyle = stroke;
|
|
3412
3477
|
ctx.lineWidth = style.width;
|
|
3413
3478
|
ctx.setLineDash(style.dash ?? []);
|
|
3414
3479
|
ctx.beginPath();
|
|
@@ -3479,7 +3544,8 @@ function renderConnection(ctx, conn, fromBounds, toBounds, theme, edgeRoute, opt
|
|
|
3479
3544
|
conn.fromAnchor,
|
|
3480
3545
|
conn.toAnchor
|
|
3481
3546
|
);
|
|
3482
|
-
ctx.
|
|
3547
|
+
const stroke = resolveConnectionStroke(ctx, p0, p3, conn.fromColor, style.color, conn.toColor);
|
|
3548
|
+
ctx.strokeStyle = stroke;
|
|
3483
3549
|
ctx.lineWidth = style.width;
|
|
3484
3550
|
ctx.setLineDash(style.dash ?? []);
|
|
3485
3551
|
ctx.beginPath();
|
|
@@ -3521,7 +3587,8 @@ function renderConnection(ctx, conn, fromBounds, toBounds, theme, edgeRoute, opt
|
|
|
3521
3587
|
);
|
|
3522
3588
|
const [p0, cp1, cp2, pMid] = first;
|
|
3523
3589
|
const [, cp3, cp4, p3] = second;
|
|
3524
|
-
ctx.
|
|
3590
|
+
const stroke = resolveConnectionStroke(ctx, p0, p3, conn.fromColor, style.color, conn.toColor);
|
|
3591
|
+
ctx.strokeStyle = stroke;
|
|
3525
3592
|
ctx.lineWidth = style.width;
|
|
3526
3593
|
ctx.setLineDash(style.dash ?? []);
|
|
3527
3594
|
ctx.beginPath();
|
|
@@ -3564,10 +3631,18 @@ function renderConnection(ctx, conn, fromBounds, toBounds, theme, edgeRoute, opt
|
|
|
3564
3631
|
endPoint = linePoints[linePoints.length - 1] ?? linePoints[0];
|
|
3565
3632
|
startAngle = Math.atan2(startSegment.y - linePoints[0].y, startSegment.x - linePoints[0].x) + Math.PI;
|
|
3566
3633
|
endAngle = Math.atan2(endPoint.y - endStart.y, endPoint.x - endStart.x);
|
|
3634
|
+
const stroke = resolveConnectionStroke(
|
|
3635
|
+
ctx,
|
|
3636
|
+
startPoint,
|
|
3637
|
+
endPoint,
|
|
3638
|
+
conn.fromColor,
|
|
3639
|
+
style.color,
|
|
3640
|
+
conn.toColor
|
|
3641
|
+
);
|
|
3567
3642
|
if (useElkRoute) {
|
|
3568
|
-
drawCubicInterpolatedPath(ctx, linePoints, style);
|
|
3643
|
+
drawCubicInterpolatedPath(ctx, linePoints, style, stroke);
|
|
3569
3644
|
} else {
|
|
3570
|
-
|
|
3645
|
+
drawOrthogonalPathWithStroke(ctx, startPoint, endPoint, style, stroke);
|
|
3571
3646
|
}
|
|
3572
3647
|
labelPoint = pointAlongPolyline(linePoints, labelT);
|
|
3573
3648
|
}
|
|
@@ -3872,6 +3947,9 @@ function measureTextBounds(ctx, options) {
|
|
|
3872
3947
|
function angleBetween(from, to) {
|
|
3873
3948
|
return Math.atan2(to.y - from.y, to.x - from.x);
|
|
3874
3949
|
}
|
|
3950
|
+
function degreesToRadians(angle) {
|
|
3951
|
+
return angle * Math.PI / 180;
|
|
3952
|
+
}
|
|
3875
3953
|
function pathBounds(operations) {
|
|
3876
3954
|
let minX = Number.POSITIVE_INFINITY;
|
|
3877
3955
|
let minY = Number.POSITIVE_INFINITY;
|
|
@@ -4109,6 +4187,34 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
4109
4187
|
});
|
|
4110
4188
|
break;
|
|
4111
4189
|
}
|
|
4190
|
+
case "arc": {
|
|
4191
|
+
const startAngle = degreesToRadians(command.startAngle);
|
|
4192
|
+
const endAngle = degreesToRadians(command.endAngle);
|
|
4193
|
+
withOpacity(ctx, command.opacity, () => {
|
|
4194
|
+
applyDrawShadow(ctx, command.shadow);
|
|
4195
|
+
ctx.beginPath();
|
|
4196
|
+
ctx.setLineDash(command.dash ?? []);
|
|
4197
|
+
ctx.lineWidth = command.width;
|
|
4198
|
+
ctx.strokeStyle = command.color;
|
|
4199
|
+
ctx.arc(command.center.x, command.center.y, command.radius, startAngle, endAngle);
|
|
4200
|
+
ctx.stroke();
|
|
4201
|
+
});
|
|
4202
|
+
rendered.push({
|
|
4203
|
+
id,
|
|
4204
|
+
kind: "draw",
|
|
4205
|
+
bounds: expandRect(
|
|
4206
|
+
{
|
|
4207
|
+
x: command.center.x - command.radius,
|
|
4208
|
+
y: command.center.y - command.radius,
|
|
4209
|
+
width: command.radius * 2,
|
|
4210
|
+
height: command.radius * 2
|
|
4211
|
+
},
|
|
4212
|
+
command.width / 2
|
|
4213
|
+
),
|
|
4214
|
+
foregroundColor: command.color
|
|
4215
|
+
});
|
|
4216
|
+
break;
|
|
4217
|
+
}
|
|
4112
4218
|
case "bezier": {
|
|
4113
4219
|
const points = command.points;
|
|
4114
4220
|
withOpacity(ctx, command.opacity, () => {
|
|
@@ -4265,6 +4371,84 @@ function renderDrawCommands(ctx, commands, theme) {
|
|
|
4265
4371
|
});
|
|
4266
4372
|
break;
|
|
4267
4373
|
}
|
|
4374
|
+
case "text-row": {
|
|
4375
|
+
const segments = command.segments;
|
|
4376
|
+
if (segments.length === 0) break;
|
|
4377
|
+
const resolveSegment = (seg) => ({
|
|
4378
|
+
text: seg.text,
|
|
4379
|
+
fontSize: seg.fontSize ?? command.defaultFontSize,
|
|
4380
|
+
fontWeight: seg.fontWeight ?? command.defaultFontWeight,
|
|
4381
|
+
fontFamily: resolveDrawFont(theme, seg.fontFamily ?? command.defaultFontFamily),
|
|
4382
|
+
color: seg.color ?? command.defaultColor
|
|
4383
|
+
});
|
|
4384
|
+
const measured = [];
|
|
4385
|
+
let totalWidth = 0;
|
|
4386
|
+
let maxAscent = 0;
|
|
4387
|
+
let maxDescent = 0;
|
|
4388
|
+
for (const seg of segments) {
|
|
4389
|
+
const resolved = resolveSegment(seg);
|
|
4390
|
+
applyFont(ctx, {
|
|
4391
|
+
size: resolved.fontSize,
|
|
4392
|
+
weight: resolved.fontWeight,
|
|
4393
|
+
family: resolved.fontFamily
|
|
4394
|
+
});
|
|
4395
|
+
const metrics = ctx.measureText(resolved.text);
|
|
4396
|
+
const width = metrics.width;
|
|
4397
|
+
const ascent = metrics.actualBoundingBoxAscent || 0;
|
|
4398
|
+
const descent = metrics.actualBoundingBoxDescent || 0;
|
|
4399
|
+
totalWidth += width;
|
|
4400
|
+
maxAscent = Math.max(maxAscent, ascent);
|
|
4401
|
+
maxDescent = Math.max(maxDescent, descent);
|
|
4402
|
+
measured.push({ width, resolved });
|
|
4403
|
+
}
|
|
4404
|
+
let cursorX;
|
|
4405
|
+
if (command.align === "center") {
|
|
4406
|
+
cursorX = command.x - totalWidth / 2;
|
|
4407
|
+
} else if (command.align === "right") {
|
|
4408
|
+
cursorX = command.x - totalWidth;
|
|
4409
|
+
} else {
|
|
4410
|
+
cursorX = command.x;
|
|
4411
|
+
}
|
|
4412
|
+
const startX = cursorX;
|
|
4413
|
+
withOpacity(ctx, command.opacity, () => {
|
|
4414
|
+
ctx.textBaseline = command.baseline;
|
|
4415
|
+
for (const { width, resolved } of measured) {
|
|
4416
|
+
applyFont(ctx, {
|
|
4417
|
+
size: resolved.fontSize,
|
|
4418
|
+
weight: resolved.fontWeight,
|
|
4419
|
+
family: resolved.fontFamily
|
|
4420
|
+
});
|
|
4421
|
+
ctx.fillStyle = resolved.color;
|
|
4422
|
+
ctx.textAlign = "left";
|
|
4423
|
+
ctx.fillText(resolved.text, cursorX, command.y);
|
|
4424
|
+
cursorX += width;
|
|
4425
|
+
}
|
|
4426
|
+
});
|
|
4427
|
+
const height = Math.max(1, maxAscent + maxDescent);
|
|
4428
|
+
let topY;
|
|
4429
|
+
if (command.baseline === "top") {
|
|
4430
|
+
topY = command.y;
|
|
4431
|
+
} else if (command.baseline === "middle") {
|
|
4432
|
+
topY = command.y - height / 2;
|
|
4433
|
+
} else if (command.baseline === "bottom") {
|
|
4434
|
+
topY = command.y - height;
|
|
4435
|
+
} else {
|
|
4436
|
+
topY = command.y - maxAscent;
|
|
4437
|
+
}
|
|
4438
|
+
rendered.push({
|
|
4439
|
+
id,
|
|
4440
|
+
kind: "draw",
|
|
4441
|
+
bounds: {
|
|
4442
|
+
x: startX,
|
|
4443
|
+
y: topY,
|
|
4444
|
+
width: Math.max(1, totalWidth),
|
|
4445
|
+
height
|
|
4446
|
+
},
|
|
4447
|
+
foregroundColor: command.defaultColor,
|
|
4448
|
+
backgroundColor: theme.background
|
|
4449
|
+
});
|
|
4450
|
+
break;
|
|
4451
|
+
}
|
|
4268
4452
|
}
|
|
4269
4453
|
}
|
|
4270
4454
|
return rendered;
|
|
@@ -4674,6 +4858,18 @@ async function renderDesign(input, options = {}) {
|
|
|
4674
4858
|
const specHash = computeSpecHash(spec);
|
|
4675
4859
|
const generatorVersion = options.generatorVersion ?? DEFAULT_GENERATOR_VERSION;
|
|
4676
4860
|
const renderedAt = options.renderedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
4861
|
+
const iteration = options.iteration;
|
|
4862
|
+
if (iteration) {
|
|
4863
|
+
if (!Number.isInteger(iteration.iteration) || iteration.iteration <= 0) {
|
|
4864
|
+
throw new Error("Iteration metadata requires iteration to be a positive integer.");
|
|
4865
|
+
}
|
|
4866
|
+
if (iteration.maxIterations != null && (!Number.isInteger(iteration.maxIterations) || iteration.maxIterations <= 0)) {
|
|
4867
|
+
throw new Error("Iteration metadata requires maxIterations to be a positive integer.");
|
|
4868
|
+
}
|
|
4869
|
+
if (iteration.maxIterations != null && iteration.maxIterations < iteration.iteration) {
|
|
4870
|
+
throw new Error("Iteration metadata requires maxIterations to be >= iteration.");
|
|
4871
|
+
}
|
|
4872
|
+
}
|
|
4677
4873
|
const renderScale = resolveRenderScale(spec);
|
|
4678
4874
|
const canvas = createCanvas(spec.canvas.width * renderScale, spec.canvas.height * renderScale);
|
|
4679
4875
|
const ctx = canvas.getContext("2d");
|
|
@@ -4914,7 +5110,8 @@ async function renderDesign(input, options = {}) {
|
|
|
4914
5110
|
layout: {
|
|
4915
5111
|
safeFrame,
|
|
4916
5112
|
elements
|
|
4917
|
-
}
|
|
5113
|
+
},
|
|
5114
|
+
...iteration ? { iteration } : {}
|
|
4918
5115
|
};
|
|
4919
5116
|
return {
|
|
4920
5117
|
png: pngBuffer,
|
|
@@ -5221,6 +5418,12 @@ var renderOutputSchema = z3.object({
|
|
|
5221
5418
|
artifactHash: z3.string(),
|
|
5222
5419
|
specHash: z3.string(),
|
|
5223
5420
|
layoutMode: z3.string(),
|
|
5421
|
+
iteration: z3.object({
|
|
5422
|
+
current: z3.number().int().positive(),
|
|
5423
|
+
max: z3.number().int().positive(),
|
|
5424
|
+
isLast: z3.boolean(),
|
|
5425
|
+
notes: z3.string().optional()
|
|
5426
|
+
}).optional(),
|
|
5224
5427
|
qa: z3.object({
|
|
5225
5428
|
pass: z3.boolean(),
|
|
5226
5429
|
issueCount: z3.number(),
|
|
@@ -5307,8 +5510,30 @@ function readCodeRange(code, start, end) {
|
|
|
5307
5510
|
const lines = code.split(/\r?\n/u);
|
|
5308
5511
|
return lines.slice(start - 1, end).join("\n");
|
|
5309
5512
|
}
|
|
5513
|
+
function parseIterationMeta(options) {
|
|
5514
|
+
if (options.iteration == null) {
|
|
5515
|
+
if (options.maxIterations != null || options.iterationNotes || options.previousHash) {
|
|
5516
|
+
throw new Error(
|
|
5517
|
+
"--iteration is required when using --max-iterations, --iteration-notes, or --previous-hash."
|
|
5518
|
+
);
|
|
5519
|
+
}
|
|
5520
|
+
return void 0;
|
|
5521
|
+
}
|
|
5522
|
+
if (options.maxIterations != null && options.maxIterations < options.iteration) {
|
|
5523
|
+
throw new Error("--max-iterations must be greater than or equal to --iteration.");
|
|
5524
|
+
}
|
|
5525
|
+
return {
|
|
5526
|
+
iteration: options.iteration,
|
|
5527
|
+
...options.maxIterations != null ? { maxIterations: options.maxIterations } : {},
|
|
5528
|
+
...options.iterationNotes ? { notes: options.iterationNotes } : {},
|
|
5529
|
+
...options.previousHash ? { previousHash: options.previousHash } : {}
|
|
5530
|
+
};
|
|
5531
|
+
}
|
|
5310
5532
|
async function runRenderPipeline(spec, options) {
|
|
5311
|
-
const renderResult = await renderDesign(spec, {
|
|
5533
|
+
const renderResult = await renderDesign(spec, {
|
|
5534
|
+
generatorVersion: pkg.version,
|
|
5535
|
+
...options.iteration ? { iteration: options.iteration } : {}
|
|
5536
|
+
});
|
|
5312
5537
|
const written = await writeRenderArtifacts(renderResult, options.out);
|
|
5313
5538
|
const specPath = options.specOut ? resolve4(options.specOut) : specPathFor(written.metadataPath);
|
|
5314
5539
|
await mkdir2(dirname3(specPath), { recursive: true });
|
|
@@ -5325,6 +5550,14 @@ async function runRenderPipeline(spec, options) {
|
|
|
5325
5550
|
artifactHash: written.metadata.artifactHash,
|
|
5326
5551
|
specHash: written.metadata.specHash,
|
|
5327
5552
|
layoutMode: spec.layout.mode,
|
|
5553
|
+
...written.metadata.iteration ? {
|
|
5554
|
+
iteration: {
|
|
5555
|
+
current: written.metadata.iteration.iteration,
|
|
5556
|
+
max: written.metadata.iteration.maxIterations ?? written.metadata.iteration.iteration,
|
|
5557
|
+
isLast: (written.metadata.iteration.maxIterations ?? written.metadata.iteration.iteration) === written.metadata.iteration.iteration,
|
|
5558
|
+
...written.metadata.iteration.notes ? { notes: written.metadata.iteration.notes } : {}
|
|
5559
|
+
}
|
|
5560
|
+
} : {},
|
|
5328
5561
|
qa: {
|
|
5329
5562
|
pass: qa.pass,
|
|
5330
5563
|
issueCount: qa.issues.length,
|
|
@@ -5338,6 +5571,10 @@ cli.command("render", {
|
|
|
5338
5571
|
spec: z3.string().describe('Path to DesignSpec JSON file (or "-" to read JSON from stdin)'),
|
|
5339
5572
|
out: z3.string().describe("Output file path (.png) or output directory"),
|
|
5340
5573
|
specOut: z3.string().optional().describe("Optional explicit output path for normalized spec JSON"),
|
|
5574
|
+
iteration: z3.number().int().positive().optional().describe("Optional iteration number for iterative workflows (1-indexed)"),
|
|
5575
|
+
iterationNotes: z3.string().optional().describe("Optional notes for the current iteration metadata"),
|
|
5576
|
+
maxIterations: z3.number().int().positive().optional().describe("Optional maximum planned iteration count"),
|
|
5577
|
+
previousHash: z3.string().optional().describe("Optional artifact hash from the previous iteration"),
|
|
5341
5578
|
allowQaFail: z3.boolean().default(false).describe("Allow render success even if QA fails")
|
|
5342
5579
|
}),
|
|
5343
5580
|
output: renderOutputSchema,
|
|
@@ -5352,9 +5589,26 @@ cli.command("render", {
|
|
|
5352
5589
|
],
|
|
5353
5590
|
async run(c) {
|
|
5354
5591
|
const spec = parseDesignSpec(await readJson(c.options.spec));
|
|
5592
|
+
let iteration;
|
|
5593
|
+
try {
|
|
5594
|
+
iteration = parseIterationMeta({
|
|
5595
|
+
...c.options.iteration != null ? { iteration: c.options.iteration } : {},
|
|
5596
|
+
...c.options.maxIterations != null ? { maxIterations: c.options.maxIterations } : {},
|
|
5597
|
+
...c.options.iterationNotes ? { iterationNotes: c.options.iterationNotes } : {},
|
|
5598
|
+
...c.options.previousHash ? { previousHash: c.options.previousHash } : {}
|
|
5599
|
+
});
|
|
5600
|
+
} catch (error) {
|
|
5601
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5602
|
+
return c.error({
|
|
5603
|
+
code: "INVALID_ITERATION_OPTIONS",
|
|
5604
|
+
message,
|
|
5605
|
+
retryable: false
|
|
5606
|
+
});
|
|
5607
|
+
}
|
|
5355
5608
|
const runReport = await runRenderPipeline(spec, {
|
|
5356
5609
|
out: c.options.out,
|
|
5357
|
-
...c.options.specOut ? { specOut: c.options.specOut } : {}
|
|
5610
|
+
...c.options.specOut ? { specOut: c.options.specOut } : {},
|
|
5611
|
+
...iteration ? { iteration } : {}
|
|
5358
5612
|
});
|
|
5359
5613
|
if (!runReport.qa.pass && !c.options.allowQaFail) {
|
|
5360
5614
|
return c.error({
|
package/dist/qa.d.ts
CHANGED
package/dist/qa.js
CHANGED
|
@@ -563,6 +563,21 @@ var drawLineSchema = z2.object({
|
|
|
563
563
|
opacity: z2.number().min(0).max(1).default(1),
|
|
564
564
|
shadow: drawShadowSchema.optional()
|
|
565
565
|
}).strict();
|
|
566
|
+
var drawArcSchema = z2.object({
|
|
567
|
+
type: z2.literal("arc"),
|
|
568
|
+
center: z2.object({
|
|
569
|
+
x: z2.number(),
|
|
570
|
+
y: z2.number()
|
|
571
|
+
}).strict(),
|
|
572
|
+
radius: z2.number().positive(),
|
|
573
|
+
startAngle: z2.number(),
|
|
574
|
+
endAngle: z2.number(),
|
|
575
|
+
color: colorHexSchema2.default("#FFFFFF"),
|
|
576
|
+
width: z2.number().min(0.5).max(32).default(2),
|
|
577
|
+
dash: z2.array(z2.number()).max(6).optional(),
|
|
578
|
+
opacity: z2.number().min(0).max(1).default(1),
|
|
579
|
+
shadow: drawShadowSchema.optional()
|
|
580
|
+
}).strict();
|
|
566
581
|
var drawPointSchema = z2.object({
|
|
567
582
|
x: z2.number(),
|
|
568
583
|
y: z2.number()
|
|
@@ -647,6 +662,7 @@ var drawCommandSchema = z2.discriminatedUnion("type", [
|
|
|
647
662
|
drawCircleSchema,
|
|
648
663
|
drawTextSchema,
|
|
649
664
|
drawLineSchema,
|
|
665
|
+
drawArcSchema,
|
|
650
666
|
drawBezierSchema,
|
|
651
667
|
drawPathSchema,
|
|
652
668
|
drawBadgeSchema,
|
|
@@ -782,6 +798,8 @@ var connectionElementSchema = z2.object({
|
|
|
782
798
|
label: z2.string().min(1).max(200).optional(),
|
|
783
799
|
labelPosition: z2.enum(["start", "middle", "end"]).default("middle"),
|
|
784
800
|
color: colorHexSchema2.optional(),
|
|
801
|
+
fromColor: colorHexSchema2.optional(),
|
|
802
|
+
toColor: colorHexSchema2.optional(),
|
|
785
803
|
width: z2.number().min(0.5).max(10).optional(),
|
|
786
804
|
strokeWidth: z2.number().min(0.5).max(10).default(2),
|
|
787
805
|
arrowSize: z2.number().min(4).max(32).optional(),
|
package/dist/renderer.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { i as DEFAULT_GENERATOR_VERSION, S as LayoutSnapshot, a as Rect, R as RenderMetadata,
|
|
1
|
+
export { i as DEFAULT_GENERATOR_VERSION, S as IterationMeta, V as LayoutSnapshot, a as Rect, Y as RenderDesignOptions, R as RenderMetadata, Z as RenderResult, d as RenderedElement, a4 as WrittenArtifacts, a7 as computeSpecHash, aq as inferSidecarPath, at as renderDesign, av as writeRenderArtifacts } from './spec.schema-B6sXTTou.js';
|
|
2
2
|
import 'zod';
|
|
3
3
|
import '@napi-rs/canvas';
|