@pixerate/editor 0.9.0 → 0.11.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/index.js CHANGED
@@ -27,10 +27,10 @@ function tokenizePrompt(text) {
27
27
  while ((match = varRegex.exec(text)) !== null) {
28
28
  const start = match.index;
29
29
  const end = start + match[0].length;
30
- const overlaps = rawMatches.some(
30
+ const overlaps2 = rawMatches.some(
31
31
  (m) => !(end <= m.start || start >= m.end)
32
32
  );
33
- if (!overlaps) {
33
+ if (!overlaps2) {
34
34
  rawMatches.push({
35
35
  type: "variable",
36
36
  raw: match[0],
@@ -47,10 +47,10 @@ function tokenizePrompt(text) {
47
47
  while ((match = instRegex.exec(text)) !== null) {
48
48
  const start = match.index;
49
49
  const end = start + match[0].length;
50
- const overlaps = rawMatches.some(
50
+ const overlaps2 = rawMatches.some(
51
51
  (m) => !(end <= m.start || start >= m.end)
52
52
  );
53
- if (!overlaps) {
53
+ if (!overlaps2) {
54
54
  rawMatches.push({
55
55
  type: "instruction",
56
56
  raw: match[0],
@@ -4246,11 +4246,1218 @@ var HistoryManager = class {
4246
4246
  function createHistoryManager(options = {}) {
4247
4247
  return new HistoryManager(options);
4248
4248
  }
4249
+
4250
+ // src/canvas/layout.ts
4251
+ import dagre from "@dagrejs/dagre";
4252
+ var DEFAULT_NODE_WIDTH = 200;
4253
+ var DEFAULT_NODE_HEIGHT = 60;
4254
+ var DEFAULT_PLACEMENT_GAP = 48;
4255
+ function getCenteredNodePosition(width = 0, height = 0, screenToFlowPosition, screenDimensions) {
4256
+ const rect = screenDimensions ?? (typeof document !== "undefined" ? { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight } : { width: 1920, height: 1080 });
4257
+ const flowPos = screenToFlowPosition({ x: rect.width / 2, y: rect.height / 2 });
4258
+ return {
4259
+ x: flowPos.x - width / 2,
4260
+ y: flowPos.y - height / 2
4261
+ };
4262
+ }
4263
+ function centerNodes(nodes, screenToFlowPosition, getNodesBounds, screenDimensions) {
4264
+ if (nodes.length === 0) {
4265
+ return [];
4266
+ }
4267
+ const bounds = getNodesBounds(nodes);
4268
+ const boundingBoxOrigin = { x: bounds.x, y: bounds.y };
4269
+ const centeredPosition = getCenteredNodePosition(
4270
+ bounds.width,
4271
+ bounds.height,
4272
+ screenToFlowPosition,
4273
+ screenDimensions
4274
+ );
4275
+ const deltaX = centeredPosition.x - boundingBoxOrigin.x;
4276
+ const deltaY = centeredPosition.y - boundingBoxOrigin.y;
4277
+ return nodes.map((node) => ({
4278
+ ...node,
4279
+ position: {
4280
+ x: node.position.x + deltaX,
4281
+ y: node.position.y + deltaY
4282
+ }
4283
+ }));
4284
+ }
4285
+ function getLayoutedNodes(nodes, edges, getNodesBounds, options = {}) {
4286
+ if (nodes.length === 0) return [];
4287
+ const {
4288
+ direction = "LR",
4289
+ ranksep = 100,
4290
+ nodesep = 25,
4291
+ defaultNodeWidth = DEFAULT_NODE_WIDTH,
4292
+ defaultNodeHeight = DEFAULT_NODE_HEIGHT
4293
+ } = options;
4294
+ const dagreGraph = new dagre.graphlib.Graph();
4295
+ dagreGraph.setDefaultEdgeLabel(() => ({}));
4296
+ dagreGraph.setGraph({ rankdir: direction, ranksep, nodesep });
4297
+ const nodeIds = new Set(nodes.map((node) => node.id));
4298
+ nodes.forEach((node) => {
4299
+ const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
4300
+ const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
4301
+ dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
4302
+ });
4303
+ edges.forEach((edge) => {
4304
+ if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
4305
+ dagreGraph.setEdge(edge.source, edge.target);
4306
+ }
4307
+ });
4308
+ dagre.layout(dagreGraph);
4309
+ return nodes.map((node) => {
4310
+ const nodeWithPosition = dagreGraph.node(node.id);
4311
+ const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
4312
+ const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
4313
+ return {
4314
+ ...node,
4315
+ position: {
4316
+ x: nodeWithPosition.x - nodeWidth / 2,
4317
+ y: nodeWithPosition.y - nodeHeight / 2
4318
+ }
4319
+ };
4320
+ });
4321
+ }
4322
+ function estimateNodeSize(node, defaultWidth = DEFAULT_NODE_WIDTH, defaultHeight = DEFAULT_NODE_HEIGHT) {
4323
+ const label = String(node.data?.label ?? node.data?.title ?? node.id ?? "");
4324
+ const lines = label.split(/\n|<br\s*\/?>/);
4325
+ const longest = Math.max(...lines.map((l) => l.replace(/<[^>]+>/g, "").length), 1);
4326
+ const width = Math.min(480, Math.max(defaultWidth, longest * 8 + 48));
4327
+ const height = Math.max(defaultHeight, lines.length * 20 + 24);
4328
+ return { width, height };
4329
+ }
4330
+ function boundsOf(rects) {
4331
+ if (!rects.length) return null;
4332
+ const minX = Math.min(...rects.map((r) => r.x));
4333
+ const minY = Math.min(...rects.map((r) => r.y));
4334
+ const maxX = Math.max(...rects.map((r) => r.x + r.width));
4335
+ const maxY = Math.max(...rects.map((r) => r.y + r.height));
4336
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
4337
+ }
4338
+ function centre(r) {
4339
+ return { x: r.x + r.width / 2, y: r.y + r.height / 2 };
4340
+ }
4341
+ function overlaps(a, b, pad = 16) {
4342
+ return a.x < b.x + b.width + pad && a.x + a.width + pad > b.x && a.y < b.y + b.height + pad && a.y + a.height + pad > b.y;
4343
+ }
4344
+ function flowSide(direction = "LR") {
4345
+ switch (direction) {
4346
+ case "LR":
4347
+ return "right";
4348
+ case "RL":
4349
+ return "left";
4350
+ case "BT":
4351
+ return "above";
4352
+ case "TB":
4353
+ default:
4354
+ return "below";
4355
+ }
4356
+ }
4357
+ function ensureLayout(nodes, edges, options = {}) {
4358
+ if (nodes.length === 0) return [];
4359
+ const stored = options.storedPositions ?? {};
4360
+ const missing = nodes.filter((n) => !stored[n.id]);
4361
+ if (missing.length === 0) {
4362
+ return nodes.map((n) => ({
4363
+ ...n,
4364
+ position: { ...stored[n.id] }
4365
+ }));
4366
+ }
4367
+ const autoLayouted = getLayoutedNodes(nodes, edges, void 0, options);
4368
+ const autoMap = new Map(
4369
+ autoLayouted.map((n) => [n.id, n.position])
4370
+ );
4371
+ const both = nodes.filter((n) => stored[n.id] && autoMap.has(n.id));
4372
+ if (both.length === 0) {
4373
+ return autoLayouted;
4374
+ }
4375
+ let dx = 0;
4376
+ let dy = 0;
4377
+ for (const n of both) {
4378
+ const s = stored[n.id];
4379
+ const a = autoMap.get(n.id);
4380
+ dx += s.x - a.x;
4381
+ dy += s.y - a.y;
4382
+ }
4383
+ dx /= both.length;
4384
+ dy /= both.length;
4385
+ return nodes.map((node) => {
4386
+ if (stored[node.id]) {
4387
+ return {
4388
+ ...node,
4389
+ position: { ...stored[node.id] }
4390
+ };
4391
+ }
4392
+ const autoPos = autoMap.get(node.id) ?? { x: 0, y: 0 };
4393
+ return {
4394
+ ...node,
4395
+ position: {
4396
+ x: Math.round(autoPos.x + dx),
4397
+ y: Math.round(autoPos.y + dy)
4398
+ }
4399
+ };
4400
+ });
4401
+ }
4402
+ function placeBeside(rects, size, side, nearNodeId, options = {}) {
4403
+ const {
4404
+ gap = DEFAULT_PLACEMENT_GAP,
4405
+ ignore = [],
4406
+ maxAttempts = 32
4407
+ } = options;
4408
+ const skip = new Set([nearNodeId, ...ignore].filter(Boolean));
4409
+ const obstacles = Object.entries(rects).filter(([id]) => !skip.has(id)).map(([, r]) => r);
4410
+ const anchor = nearNodeId && rects[nearNodeId] || boundsOf(Object.values(rects)) || { x: 0, y: 0, width: 0, height: 0 };
4411
+ const anchorCenter = centre(anchor);
4412
+ let baseX;
4413
+ let baseY;
4414
+ switch (side) {
4415
+ case "right":
4416
+ baseX = anchor.x + anchor.width + gap;
4417
+ baseY = anchorCenter.y - size.height / 2;
4418
+ break;
4419
+ case "left":
4420
+ baseX = anchor.x - gap - size.width;
4421
+ baseY = anchorCenter.y - size.height / 2;
4422
+ break;
4423
+ case "above":
4424
+ baseX = anchorCenter.x - size.width / 2;
4425
+ baseY = anchor.y - gap - size.height;
4426
+ break;
4427
+ case "below":
4428
+ default:
4429
+ baseX = anchorCenter.x - size.width / 2;
4430
+ baseY = anchor.y + anchor.height + gap;
4431
+ break;
4432
+ }
4433
+ const isHorizontal = side === "right" || side === "left";
4434
+ const step = (isHorizontal ? size.height : size.width) + 20;
4435
+ for (let i = 0; i < maxAttempts; i++) {
4436
+ const offset = i === 0 ? 0 : Math.ceil(i / 2) * step * (i % 2 === 1 ? 1 : -1);
4437
+ const candidateBox = {
4438
+ x: isHorizontal ? baseX : baseX + offset,
4439
+ y: isHorizontal ? baseY + offset : baseY,
4440
+ width: size.width,
4441
+ height: size.height
4442
+ };
4443
+ if (!obstacles.some((obstacle) => overlaps(candidateBox, obstacle, 8))) {
4444
+ return {
4445
+ x: Math.round(candidateBox.x),
4446
+ y: Math.round(candidateBox.y)
4447
+ };
4448
+ }
4449
+ }
4450
+ return {
4451
+ x: Math.round(baseX),
4452
+ y: Math.round(baseY)
4453
+ };
4454
+ }
4455
+
4456
+ // src/canvas/clock.ts
4457
+ var pageHidden = () => typeof document !== "undefined" && document.hidden;
4458
+ var realClock = {
4459
+ live: true,
4460
+ now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
4461
+ frame: () => new Promise((resolve) => {
4462
+ if (typeof requestAnimationFrame === "function" && !pageHidden()) {
4463
+ requestAnimationFrame(() => resolve());
4464
+ } else {
4465
+ setTimeout(resolve, 16);
4466
+ }
4467
+ }),
4468
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)))
4469
+ };
4470
+ var settle = () => new Promise((resolve) => setTimeout(resolve, 0));
4471
+ var ManualClock = class {
4472
+ live = false;
4473
+ time;
4474
+ frames = [];
4475
+ sleepers = [];
4476
+ seq = 0;
4477
+ constructor(start = 0) {
4478
+ this.time = start;
4479
+ }
4480
+ now() {
4481
+ return this.time;
4482
+ }
4483
+ frame() {
4484
+ return new Promise((resolve) => this.frames.push(resolve));
4485
+ }
4486
+ sleep(ms) {
4487
+ return new Promise(
4488
+ (resolve) => this.sleepers.push({
4489
+ at: this.time + Math.max(0, ms),
4490
+ seq: this.seq++,
4491
+ resolve
4492
+ })
4493
+ );
4494
+ }
4495
+ /** Whether any frames or sleep timers are currently pending. */
4496
+ get pending() {
4497
+ return this.frames.length > 0 || this.sleepers.length > 0;
4498
+ }
4499
+ /** Advances time by `ms`, resolving due sleep timers in order, followed by queued frames. */
4500
+ async advance(ms) {
4501
+ const end = this.time + Math.max(0, ms);
4502
+ await settle();
4503
+ while (true) {
4504
+ let next;
4505
+ for (const s of this.sleepers) {
4506
+ if (s.at <= end && (!next || s.at < next.at || s.at === next.at && s.seq < next.seq)) {
4507
+ next = s;
4508
+ }
4509
+ }
4510
+ if (!next) break;
4511
+ this.sleepers.splice(this.sleepers.indexOf(next), 1);
4512
+ this.time = Math.max(this.time, next.at);
4513
+ next.resolve();
4514
+ await settle();
4515
+ }
4516
+ this.time = end;
4517
+ const dueFrames = this.frames.splice(0, this.frames.length);
4518
+ for (const resolveFrame of dueFrames) {
4519
+ resolveFrame();
4520
+ }
4521
+ await settle();
4522
+ }
4523
+ /** Convenience method to advance by 1 frame at a given fps (default: 60fps = 16.67ms). */
4524
+ async tick(fps = 60) {
4525
+ await this.advance(Math.round(1e3 / fps));
4526
+ }
4527
+ };
4528
+
4529
+ // src/canvas/trajectory.ts
4530
+ var defaultEasing = (t) => --t * t * t + 1;
4531
+ var linearTrajectory = (origin, target, progress) => {
4532
+ return {
4533
+ position: {
4534
+ x: origin.x + (target.x - origin.x) * progress,
4535
+ y: origin.y + (target.y - origin.y) * progress
4536
+ },
4537
+ scale: progress,
4538
+ opacity: Math.min(1, progress * 1.5)
4539
+ };
4540
+ };
4541
+ var linearPositionTrajectory = (origin, target, progress) => {
4542
+ return {
4543
+ position: {
4544
+ x: origin.x + (target.x - origin.x) * progress,
4545
+ y: origin.y + (target.y - origin.y) * progress
4546
+ }
4547
+ };
4548
+ };
4549
+ function createFanOutTrajectory(options = {}) {
4550
+ const {
4551
+ curvature = 0.4,
4552
+ startScale = 0,
4553
+ endScale = 1,
4554
+ startOpacity = 0,
4555
+ endOpacity = 1
4556
+ } = options;
4557
+ return (origin, target, progress, index, total) => {
4558
+ const dx = target.x - origin.x;
4559
+ const dy = target.y - origin.y;
4560
+ const normIndex = total > 1 ? (index - (total - 1) / 2) / ((total - 1) / 2) : 0;
4561
+ const midX = origin.x + dx * 0.4;
4562
+ const midY = origin.y + dy * 0.1 - normIndex * Math.abs(dx) * 0.15 * curvature;
4563
+ const t = progress;
4564
+ const oneMinusT = 1 - t;
4565
+ const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * midX + t * t * target.x;
4566
+ const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * midY + t * t * target.y;
4567
+ const scale = startScale + (endScale - startScale) * progress;
4568
+ const opacity = startOpacity + (endOpacity - startOpacity) * progress;
4569
+ return {
4570
+ position: { x, y },
4571
+ scale,
4572
+ opacity
4573
+ };
4574
+ };
4575
+ }
4576
+ function createBezierTrajectory(getControlPoint) {
4577
+ return (origin, target, progress) => {
4578
+ const cp = getControlPoint(origin, target);
4579
+ const t = progress;
4580
+ const oneMinusT = 1 - t;
4581
+ const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * cp.x + t * t * target.x;
4582
+ const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * cp.y + t * t * target.y;
4583
+ return {
4584
+ position: { x, y },
4585
+ scale: progress,
4586
+ opacity: progress
4587
+ };
4588
+ };
4589
+ }
4590
+ function runMultiNodeTransition(transitions, options = {}) {
4591
+ if (transitions.length === 0) {
4592
+ options.onComplete?.();
4593
+ return () => {
4594
+ };
4595
+ }
4596
+ const {
4597
+ defaultDuration = 400,
4598
+ defaultEasing: easingFunc = defaultEasing,
4599
+ clock = realClock,
4600
+ onUpdate,
4601
+ onComplete
4602
+ } = options;
4603
+ let isCancelled = false;
4604
+ const startTime = clock.now();
4605
+ const items = transitions.map((tr, i) => ({
4606
+ ...tr,
4607
+ index: tr.index ?? i,
4608
+ total: tr.total ?? transitions.length,
4609
+ duration: tr.duration ?? defaultDuration,
4610
+ easing: tr.easing ?? easingFunc,
4611
+ delay: tr.delay ?? 0,
4612
+ trajectory: tr.trajectory ?? linearTrajectory
4613
+ }));
4614
+ function frame() {
4615
+ if (isCancelled) return;
4616
+ const now = clock.now();
4617
+ let allCompleted = true;
4618
+ for (let i = 0; i < items.length; i++) {
4619
+ const item = items[i];
4620
+ const elapsed = now - (startTime + item.delay);
4621
+ if (elapsed < 0) {
4622
+ allCompleted = false;
4623
+ continue;
4624
+ }
4625
+ const rawProgress = item.duration <= 0 ? 1 : Math.min(elapsed / item.duration, 1);
4626
+ const progress = item.duration <= 0 ? 1 : item.easing(rawProgress);
4627
+ const point = item.trajectory(item.from, item.to, progress, item.index, item.total);
4628
+ item.node.position = { ...point.position };
4629
+ if (point.scale !== void 0 || point.opacity !== void 0) {
4630
+ if (!item.node.data) {
4631
+ item.node.data = {};
4632
+ }
4633
+ if (point.scale !== void 0) {
4634
+ item.node.data.scale = point.scale;
4635
+ }
4636
+ if (point.opacity !== void 0) {
4637
+ item.node.data.opacity = point.opacity;
4638
+ const currentStyle = (item.node.style || "").replace(/opacity:\s*[^;]+;?/g, "").trim();
4639
+ item.node.style = `${currentStyle ? currentStyle + "; " : ""}opacity: ${point.opacity};`;
4640
+ }
4641
+ }
4642
+ if (rawProgress < 1) {
4643
+ allCompleted = false;
4644
+ }
4645
+ }
4646
+ onUpdate?.();
4647
+ if (!allCompleted) {
4648
+ clock.frame().then(frame);
4649
+ } else {
4650
+ onComplete?.();
4651
+ }
4652
+ }
4653
+ frame();
4654
+ return () => {
4655
+ isCancelled = true;
4656
+ };
4657
+ }
4658
+
4659
+ // src/canvas/displacement.ts
4660
+ import dagre2 from "@dagrejs/dagre";
4661
+ function computeNodesBoundingBox(nodes, defaultWidth = 200, defaultHeight = 60) {
4662
+ if (nodes.length === 0) {
4663
+ return { x: 0, y: 0, width: 0, height: 0 };
4664
+ }
4665
+ let minX = Infinity;
4666
+ let minY = Infinity;
4667
+ let maxX = -Infinity;
4668
+ let maxY = -Infinity;
4669
+ for (const node of nodes) {
4670
+ const width = node.measured?.width ?? node.width ?? defaultWidth;
4671
+ const height = node.measured?.height ?? node.height ?? defaultHeight;
4672
+ minX = Math.min(minX, node.position.x);
4673
+ minY = Math.min(minY, node.position.y);
4674
+ maxX = Math.max(maxX, node.position.x + width);
4675
+ maxY = Math.max(maxY, node.position.y + height);
4676
+ }
4677
+ return {
4678
+ x: minX,
4679
+ y: minY,
4680
+ width: maxX - minX,
4681
+ height: maxY - minY
4682
+ };
4683
+ }
4684
+ function calculateDirectionalDisplacement(params) {
4685
+ const {
4686
+ existingNodes,
4687
+ originNode,
4688
+ childNodes: childNodes2,
4689
+ getNodesBounds,
4690
+ options = {}
4691
+ } = params;
4692
+ const {
4693
+ direction = "right",
4694
+ gap = 40,
4695
+ spreadSiblingLanes = false,
4696
+ siblingTolerance = 50,
4697
+ minY
4698
+ } = options;
4699
+ const displacedMap = /* @__PURE__ */ new Map();
4700
+ if (childNodes2.length === 0 || existingNodes.length === 0) {
4701
+ return displacedMap;
4702
+ }
4703
+ const childBounds = getNodesBounds ? getNodesBounds(childNodes2) : computeNodesBoundingBox(childNodes2);
4704
+ const originWidth = originNode.measured?.width ?? originNode.width ?? 200;
4705
+ const originHeight = originNode.measured?.height ?? originNode.height ?? 60;
4706
+ const deltaPrimary = direction === "right" || direction === "left" ? childBounds.width + gap : childBounds.height + gap;
4707
+ const deltaUp = Math.max(0, originNode.position.y - childBounds.y + gap);
4708
+ const deltaDown = Math.max(
4709
+ 0,
4710
+ childBounds.y + childBounds.height - (originNode.position.y + originHeight) + gap
4711
+ );
4712
+ const equalDelta = Math.max(deltaUp, deltaDown);
4713
+ for (const node of existingNodes) {
4714
+ if (node.id === originNode.id) continue;
4715
+ const isSiblingRow = Math.abs(node.position.y - originNode.position.y) < siblingTolerance;
4716
+ switch (direction) {
4717
+ case "right": {
4718
+ if (node.position.x > originNode.position.x) {
4719
+ displacedMap.set(node.id, {
4720
+ x: node.position.x + deltaPrimary,
4721
+ y: node.position.y
4722
+ });
4723
+ }
4724
+ break;
4725
+ }
4726
+ case "left": {
4727
+ if (node.position.x < originNode.position.x) {
4728
+ displacedMap.set(node.id, {
4729
+ x: node.position.x - deltaPrimary,
4730
+ y: node.position.y
4731
+ });
4732
+ }
4733
+ break;
4734
+ }
4735
+ case "down": {
4736
+ if (node.position.y > originNode.position.y) {
4737
+ displacedMap.set(node.id, {
4738
+ x: node.position.x,
4739
+ y: node.position.y + deltaPrimary
4740
+ });
4741
+ }
4742
+ break;
4743
+ }
4744
+ case "up": {
4745
+ if (node.position.y < originNode.position.y) {
4746
+ displacedMap.set(node.id, {
4747
+ x: node.position.x,
4748
+ y: node.position.y - deltaPrimary
4749
+ });
4750
+ }
4751
+ break;
4752
+ }
4753
+ case "vertical": {
4754
+ if (isSiblingRow) break;
4755
+ if (node.position.y < originNode.position.y) {
4756
+ displacedMap.set(node.id, {
4757
+ x: node.position.x,
4758
+ y: node.position.y - equalDelta
4759
+ });
4760
+ } else if (node.position.y > originNode.position.y) {
4761
+ displacedMap.set(node.id, {
4762
+ x: node.position.x,
4763
+ y: node.position.y + equalDelta
4764
+ });
4765
+ }
4766
+ break;
4767
+ }
4768
+ }
4769
+ }
4770
+ if (spreadSiblingLanes && (direction === "right" || direction === "left")) {
4771
+ for (const [nodeId, pos] of displacedMap.entries()) {
4772
+ const node = existingNodes.find((n) => n.id === nodeId);
4773
+ if (node && Math.abs(node.position.y - originNode.position.y) < siblingTolerance) {
4774
+ const isAbove = node.position.y < originNode.position.y;
4775
+ displacedMap.set(nodeId, {
4776
+ x: pos.x,
4777
+ y: pos.y + (isAbove ? -deltaUp : deltaDown)
4778
+ });
4779
+ }
4780
+ }
4781
+ }
4782
+ if (minY !== void 0) {
4783
+ for (const [nodeId, pos] of displacedMap.entries()) {
4784
+ if (pos.y < minY) {
4785
+ displacedMap.set(nodeId, { x: pos.x, y: minY });
4786
+ }
4787
+ }
4788
+ }
4789
+ return displacedMap;
4790
+ }
4791
+ function calculateDagreReflowDisplacement(params) {
4792
+ const {
4793
+ currentNodes,
4794
+ futureNodes,
4795
+ futureEdges,
4796
+ options
4797
+ } = params;
4798
+ const {
4799
+ anchorNodeId,
4800
+ direction = "LR",
4801
+ ranksep = 100,
4802
+ nodesep = 25,
4803
+ defaultNodeWidth = 200,
4804
+ defaultNodeHeight = 60
4805
+ } = options;
4806
+ const anchorNode = currentNodes.find((n) => n.id === anchorNodeId);
4807
+ if (!anchorNode) return /* @__PURE__ */ new Map();
4808
+ const g = new dagre2.graphlib.Graph();
4809
+ g.setDefaultEdgeLabel(() => ({}));
4810
+ g.setGraph({ rankdir: direction, ranksep, nodesep });
4811
+ const nodeIds = new Set(futureNodes.map((n) => n.id));
4812
+ futureNodes.forEach((node) => {
4813
+ const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
4814
+ const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
4815
+ g.setNode(node.id, { width: nodeWidth, height: nodeHeight });
4816
+ });
4817
+ futureEdges.forEach((edge) => {
4818
+ if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
4819
+ g.setEdge(edge.source, edge.target);
4820
+ }
4821
+ });
4822
+ dagre2.layout(g);
4823
+ const anchorLayoutPos = g.node(anchorNodeId);
4824
+ if (!anchorLayoutPos) return /* @__PURE__ */ new Map();
4825
+ const anchorWidth = anchorNode.measured?.width ?? anchorNode.width ?? defaultNodeWidth;
4826
+ const anchorHeight = anchorNode.measured?.height ?? anchorNode.height ?? defaultNodeHeight;
4827
+ const anchorLayoutUpperLeft = {
4828
+ x: anchorLayoutPos.x - anchorWidth / 2,
4829
+ y: anchorLayoutPos.y - anchorHeight / 2
4830
+ };
4831
+ const deltaX = anchorNode.position.x - anchorLayoutUpperLeft.x;
4832
+ const deltaY = anchorNode.position.y - anchorLayoutUpperLeft.y;
4833
+ const displacementMap = /* @__PURE__ */ new Map();
4834
+ currentNodes.forEach((node) => {
4835
+ if (node.id === anchorNodeId) return;
4836
+ const layoutNode = g.node(node.id);
4837
+ if (!layoutNode) return;
4838
+ const nodeWidth = node.measured?.width ?? node.width ?? defaultNodeWidth;
4839
+ const nodeHeight = node.measured?.height ?? node.height ?? defaultNodeHeight;
4840
+ const upperLeftX = layoutNode.x - nodeWidth / 2 + deltaX;
4841
+ const upperLeftY = layoutNode.y - nodeHeight / 2 + deltaY;
4842
+ if (Math.abs(upperLeftX - node.position.x) > 1 || Math.abs(upperLeftY - node.position.y) > 1) {
4843
+ displacementMap.set(node.id, { x: upperLeftX, y: upperLeftY });
4844
+ }
4845
+ });
4846
+ return displacementMap;
4847
+ }
4848
+
4849
+ // src/canvas/clipboard.ts
4850
+ function isEventFromTextInput(event) {
4851
+ const target = event.target;
4852
+ if (!target) return false;
4853
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT" || target.isContentEditable || target.closest?.('[contenteditable="true"]') || target.closest?.(".ProseMirror")) {
4854
+ return true;
4855
+ }
4856
+ return false;
4857
+ }
4858
+ function isValidCanvasNode(obj) {
4859
+ return typeof obj === "object" && obj !== null && "id" in obj && typeof obj.id === "string" && "position" in obj && typeof obj.position === "object" && obj.position !== null && "x" in obj.position && "y" in obj.position;
4860
+ }
4861
+ function isValidUrl(url) {
4862
+ try {
4863
+ const parsed = new URL(url);
4864
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
4865
+ } catch {
4866
+ return false;
4867
+ }
4868
+ }
4869
+ function serializeCanvasNodes(nodes, edges) {
4870
+ const payload = {
4871
+ version: 1,
4872
+ nodes,
4873
+ edges
4874
+ };
4875
+ return JSON.stringify(payload);
4876
+ }
4877
+ function parseCanvasClipboardData(raw) {
4878
+ try {
4879
+ const parsed = JSON.parse(raw);
4880
+ if (typeof parsed === "object" && parsed !== null && Array.isArray(parsed.nodes) && parsed.nodes.length > 0 && parsed.nodes.every(isValidCanvasNode)) {
4881
+ return parsed;
4882
+ }
4883
+ } catch {
4884
+ }
4885
+ return null;
4886
+ }
4887
+ function remapPastedNodes(nodes, edges = [], offset = { x: 30, y: 30 }, idGenerator = () => `node-${Math.random().toString(36).substring(2, 9)}`) {
4888
+ const idMap = /* @__PURE__ */ new Map();
4889
+ const newNodes = nodes.map((node) => {
4890
+ const newId = idGenerator();
4891
+ idMap.set(node.id, newId);
4892
+ return {
4893
+ ...node,
4894
+ id: newId,
4895
+ position: {
4896
+ x: node.position.x + offset.x,
4897
+ y: node.position.y + offset.y
4898
+ },
4899
+ selected: true
4900
+ };
4901
+ });
4902
+ const newEdges = edges.filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((edge) => ({
4903
+ ...edge,
4904
+ id: `edge-${Math.random().toString(36).substring(2, 9)}`,
4905
+ source: idMap.get(edge.source),
4906
+ target: idMap.get(edge.target),
4907
+ selected: false
4908
+ }));
4909
+ return { nodes: newNodes, edges: newEdges };
4910
+ }
4911
+ function repositionNodesTo(nodes, targetOrigin) {
4912
+ if (nodes.length === 0) return [];
4913
+ const minX = Math.min(...nodes.map((n) => n.position.x));
4914
+ const minY = Math.min(...nodes.map((n) => n.position.y));
4915
+ const deltaX = targetOrigin.x - minX;
4916
+ const deltaY = targetOrigin.y - minY;
4917
+ return nodes.map((n) => ({
4918
+ ...n,
4919
+ position: {
4920
+ x: n.position.x + deltaX,
4921
+ y: n.position.y + deltaY
4922
+ }
4923
+ }));
4924
+ }
4925
+
4926
+ // src/canvas/view.ts
4927
+ function clampHeight(contentHeight, options = {}) {
4928
+ const { min = 320, max = 560, padding = 48 } = options;
4929
+ return Math.round(Math.min(max, Math.max(min, contentHeight + padding)));
4930
+ }
4931
+ function layoutBounds(nodes) {
4932
+ if (nodes.length === 0) return null;
4933
+ let minX = Infinity;
4934
+ let minY = Infinity;
4935
+ let maxX = -Infinity;
4936
+ let maxY = -Infinity;
4937
+ for (const node of nodes) {
4938
+ const x = node.position.x;
4939
+ const y = node.position.y;
4940
+ const width = node.width ?? 180;
4941
+ const height = node.height ?? 80;
4942
+ minX = Math.min(minX, x);
4943
+ minY = Math.min(minY, y);
4944
+ maxX = Math.max(maxX, x + width);
4945
+ maxY = Math.max(maxY, y + height);
4946
+ }
4947
+ if (minX === Infinity) return null;
4948
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
4949
+ }
4950
+ function canvasHeight(nodes, options) {
4951
+ return clampHeight(layoutBounds(nodes)?.height ?? 0, options);
4952
+ }
4953
+ var DEFAULT_RANK_HEIGHT = 80 + 72;
4954
+ var NODES_PER_RANK = 2;
4955
+ function estimateCanvasHeight(nodes, edges, options) {
4956
+ const ranks = Math.max(1, Math.ceil(nodes.length / NODES_PER_RANK));
4957
+ return clampHeight(ranks * DEFAULT_RANK_HEIGHT, options);
4958
+ }
4959
+ function mix(a, b, t) {
4960
+ return a + (b - a) * t;
4961
+ }
4962
+ function blendLayout(from, to, t) {
4963
+ if (t >= 1) return to;
4964
+ const fromMap = new Map(from.map((n) => [n.id, n]));
4965
+ return to.map((target) => {
4966
+ const origin = fromMap.get(target.id);
4967
+ if (!origin) return target;
4968
+ return {
4969
+ ...target,
4970
+ position: {
4971
+ x: mix(origin.position.x, target.position.x, t),
4972
+ y: mix(origin.position.y, target.position.y, t)
4973
+ },
4974
+ width: origin.width !== void 0 && target.width !== void 0 ? mix(origin.width, target.width, t) : target.width,
4975
+ height: origin.height !== void 0 && target.height !== void 0 ? mix(origin.height, target.height, t) : target.height
4976
+ };
4977
+ });
4978
+ }
4979
+ function connectedOnly(nodes, edges) {
4980
+ if (edges.length === 0) return nodes;
4981
+ const linkedNodeIds = /* @__PURE__ */ new Set();
4982
+ for (const edge of edges) {
4983
+ linkedNodeIds.add(edge.source);
4984
+ linkedNodeIds.add(edge.target);
4985
+ }
4986
+ const filtered = nodes.filter((node) => linkedNodeIds.has(node.id));
4987
+ return filtered.length > 0 ? filtered : nodes;
4988
+ }
4989
+
4990
+ // src/canvas/streaming.ts
4991
+ var StreamingLayoutManager = class {
4992
+ throttleMs;
4993
+ glideDurationMs;
4994
+ connectedOnly;
4995
+ clock;
4996
+ layoutOptions;
4997
+ onLayoutUpdated;
4998
+ pendingTimer = null;
4999
+ activeTransitionCancel = null;
5000
+ targetPositions = /* @__PURE__ */ new Map();
5001
+ constructor(options = {}) {
5002
+ this.throttleMs = options.throttleMs ?? 200;
5003
+ this.glideDurationMs = options.glideDurationMs ?? 300;
5004
+ this.connectedOnly = options.connectedOnly ?? false;
5005
+ this.clock = options.clock ?? realClock;
5006
+ this.layoutOptions = options.layoutOptions ?? { direction: "LR" };
5007
+ this.onLayoutUpdated = options.onLayoutUpdated;
5008
+ }
5009
+ /**
5010
+ * Feed incoming nodes and edges into the streaming manager.
5011
+ * Coalesces rapid streaming bursts and triggers smooth layout gliding.
5012
+ */
5013
+ pushStreamUpdate(nodes, edges, currentPositions) {
5014
+ if (this.pendingTimer) {
5015
+ clearTimeout(this.pendingTimer);
5016
+ }
5017
+ this.pendingTimer = setTimeout(() => {
5018
+ this.pendingTimer = null;
5019
+ this.recalculateAndGlide(nodes, edges, currentPositions);
5020
+ }, this.throttleMs);
5021
+ }
5022
+ /**
5023
+ * Forces immediate calculation and cancels pending throttled timers.
5024
+ */
5025
+ flush(nodes, edges, currentPositions) {
5026
+ if (this.pendingTimer) {
5027
+ clearTimeout(this.pendingTimer);
5028
+ this.pendingTimer = null;
5029
+ }
5030
+ this.recalculateAndGlide(nodes, edges, currentPositions);
5031
+ }
5032
+ recalculateAndGlide(nodes, edges, currentPositions) {
5033
+ const targetNodes = this.connectedOnly ? connectedOnly(nodes, edges) : nodes;
5034
+ if (targetNodes.length === 0) return;
5035
+ if (this.activeTransitionCancel) {
5036
+ this.activeTransitionCancel();
5037
+ this.activeTransitionCancel = null;
5038
+ }
5039
+ const stored = {};
5040
+ for (const [id, pos] of currentPositions.entries()) {
5041
+ stored[id] = pos;
5042
+ }
5043
+ const layouted = ensureLayout(targetNodes, edges, {
5044
+ ...this.layoutOptions,
5045
+ storedPositions: stored
5046
+ });
5047
+ const nextPositions = /* @__PURE__ */ new Map();
5048
+ const transitions = [];
5049
+ for (const node of layouted) {
5050
+ const target = node.position;
5051
+ nextPositions.set(node.id, target);
5052
+ const current = currentPositions.get(node.id) ?? target;
5053
+ const distance = Math.hypot(target.x - current.x, target.y - current.y);
5054
+ if (distance > 2) {
5055
+ transitions.push({
5056
+ node,
5057
+ from: current,
5058
+ to: target,
5059
+ trajectory: linearPositionTrajectory,
5060
+ duration: this.glideDurationMs
5061
+ });
5062
+ }
5063
+ }
5064
+ this.targetPositions = nextPositions;
5065
+ if (transitions.length > 0) {
5066
+ this.activeTransitionCancel = runMultiNodeTransition(transitions, {
5067
+ clock: this.clock,
5068
+ onUpdate: () => {
5069
+ const liveMap = new Map(currentPositions);
5070
+ for (const trans of transitions) {
5071
+ liveMap.set(trans.node.id, { ...trans.node.position });
5072
+ }
5073
+ this.onLayoutUpdated?.(liveMap);
5074
+ },
5075
+ onComplete: () => {
5076
+ this.activeTransitionCancel = null;
5077
+ this.onLayoutUpdated?.(nextPositions);
5078
+ }
5079
+ });
5080
+ } else {
5081
+ this.onLayoutUpdated?.(nextPositions);
5082
+ }
5083
+ }
5084
+ destroy() {
5085
+ if (this.pendingTimer) {
5086
+ clearTimeout(this.pendingTimer);
5087
+ this.pendingTimer = null;
5088
+ }
5089
+ if (this.activeTransitionCancel) {
5090
+ this.activeTransitionCancel();
5091
+ this.activeTransitionCancel = null;
5092
+ }
5093
+ }
5094
+ };
5095
+
5096
+ // src/agent/planner.ts
5097
+ function planAgentCommand(command, snapshot, options = {}) {
5098
+ const defaultNodeSize = options.defaultNodeSize ?? { width: 200, height: 60 };
5099
+ const idGen = options.idGenerator ?? (() => `node-${Math.random().toString(36).substring(2, 9)}`);
5100
+ const edgeIdGen = () => `edge-${Math.random().toString(36).substring(2, 9)}`;
5101
+ const nodes = snapshot.canvas?.nodes ?? [];
5102
+ const edges = snapshot.canvas?.edges ?? [];
5103
+ switch (command.type) {
5104
+ case "canvas:add_node": {
5105
+ let pos = command.node.position;
5106
+ if (!pos) {
5107
+ if (command.nearNodeId) {
5108
+ const rects = {};
5109
+ for (const n of nodes) {
5110
+ rects[n.id] = {
5111
+ x: n.position.x,
5112
+ y: n.position.y,
5113
+ width: n.measured?.width ?? n.width ?? defaultNodeSize.width,
5114
+ height: n.measured?.height ?? n.height ?? defaultNodeSize.height
5115
+ };
5116
+ }
5117
+ pos = placeBeside(
5118
+ rects,
5119
+ defaultNodeSize,
5120
+ command.side ?? "right",
5121
+ command.nearNodeId
5122
+ );
5123
+ } else if (nodes.length > 0) {
5124
+ const lastNode = nodes[nodes.length - 1];
5125
+ const rects = {};
5126
+ for (const n of nodes) {
5127
+ rects[n.id] = {
5128
+ x: n.position.x,
5129
+ y: n.position.y,
5130
+ width: n.measured?.width ?? n.width ?? defaultNodeSize.width,
5131
+ height: n.measured?.height ?? n.height ?? defaultNodeSize.height
5132
+ };
5133
+ }
5134
+ pos = placeBeside(rects, defaultNodeSize, "right", lastNode.id);
5135
+ } else {
5136
+ pos = { x: 100, y: 100 };
5137
+ }
5138
+ }
5139
+ const fullNode = {
5140
+ ...command.node,
5141
+ id: command.node.id || idGen(),
5142
+ position: pos
5143
+ };
5144
+ const steps = [
5145
+ {
5146
+ type: "step:canvas_add_node",
5147
+ node: fullNode
5148
+ }
5149
+ ];
5150
+ if (command.nearNodeId) {
5151
+ steps.push({
5152
+ type: "step:canvas_add_edge",
5153
+ edge: {
5154
+ id: edgeIdGen(),
5155
+ source: command.nearNodeId,
5156
+ target: fullNode.id
5157
+ }
5158
+ });
5159
+ }
5160
+ return steps;
5161
+ }
5162
+ case "canvas:remove_nodes": {
5163
+ return [
5164
+ {
5165
+ type: "step:canvas_remove_nodes",
5166
+ nodeIds: command.nodeIds
5167
+ }
5168
+ ];
5169
+ }
5170
+ case "canvas:connect": {
5171
+ return [
5172
+ {
5173
+ type: "step:canvas_add_edge",
5174
+ edge: {
5175
+ id: edgeIdGen(),
5176
+ source: command.source,
5177
+ target: command.target,
5178
+ label: command.label
5179
+ }
5180
+ }
5181
+ ];
5182
+ }
5183
+ case "canvas:update_node": {
5184
+ return [
5185
+ {
5186
+ type: "step:canvas_update_node",
5187
+ id: command.id,
5188
+ data: command.data
5189
+ }
5190
+ ];
5191
+ }
5192
+ case "canvas:layout": {
5193
+ const dir = command.direction ?? "LR";
5194
+ let layouted;
5195
+ if (command.incremental) {
5196
+ const stored = {};
5197
+ for (const n of nodes) {
5198
+ if (n.position && (n.position.x !== 0 || n.position.y !== 0)) {
5199
+ stored[n.id] = { ...n.position };
5200
+ }
5201
+ }
5202
+ layouted = ensureLayout(nodes, edges, {
5203
+ direction: dir,
5204
+ storedPositions: stored
5205
+ });
5206
+ } else {
5207
+ layouted = getLayoutedNodes(nodes, edges, void 0, { direction: dir });
5208
+ }
5209
+ const positions = {};
5210
+ for (const node of layouted) {
5211
+ positions[node.id] = { ...node.position };
5212
+ }
5213
+ return [
5214
+ {
5215
+ type: "step:canvas_move_nodes",
5216
+ positions
5217
+ }
5218
+ ];
5219
+ }
5220
+ case "canvas:select": {
5221
+ return [
5222
+ {
5223
+ type: "step:canvas_select",
5224
+ nodeIds: command.nodeIds
5225
+ }
5226
+ ];
5227
+ }
5228
+ case "canvas:highlight": {
5229
+ return [
5230
+ {
5231
+ type: "step:canvas_highlight",
5232
+ nodeIds: command.nodeIds,
5233
+ color: command.color ?? "#3b82f6",
5234
+ durationMs: command.durationMs ?? 2e3
5235
+ }
5236
+ ];
5237
+ }
5238
+ case "prompt:insert_text": {
5239
+ return [
5240
+ {
5241
+ type: "step:prompt_insert",
5242
+ text: command.text,
5243
+ at: command.at
5244
+ }
5245
+ ];
5246
+ }
5247
+ case "prompt:replace_range": {
5248
+ return [
5249
+ {
5250
+ type: "step:prompt_replace",
5251
+ from: command.from,
5252
+ to: command.to,
5253
+ text: command.text
5254
+ }
5255
+ ];
5256
+ }
5257
+ case "prompt:set_variable": {
5258
+ return [
5259
+ {
5260
+ type: "step:prompt_set_variable",
5261
+ name: command.name,
5262
+ value: command.value
5263
+ }
5264
+ ];
5265
+ }
5266
+ case "prompt:select": {
5267
+ return [
5268
+ {
5269
+ type: "step:prompt_select",
5270
+ from: command.from,
5271
+ to: command.to
5272
+ }
5273
+ ];
5274
+ }
5275
+ case "choreography:say": {
5276
+ return [
5277
+ {
5278
+ type: "step:say",
5279
+ text: command.text,
5280
+ atNodeId: command.atNodeId,
5281
+ position: command.position
5282
+ }
5283
+ ];
5284
+ }
5285
+ case "choreography:wait": {
5286
+ return [
5287
+ {
5288
+ type: "step:wait",
5289
+ ms: command.ms
5290
+ }
5291
+ ];
5292
+ }
5293
+ default: {
5294
+ return [];
5295
+ }
5296
+ }
5297
+ }
5298
+
5299
+ // src/agent/tools.ts
5300
+ var MCP_TOOL_GET_EDITOR_STATE = {
5301
+ name: "get_editor_state",
5302
+ description: "Retrieves the current state of the document, variables, selection, and canvas graph (nodes and edges).",
5303
+ inputSchema: {
5304
+ type: "object",
5305
+ properties: {
5306
+ includeDocument: {
5307
+ type: "boolean",
5308
+ description: "Whether to include the prompt document text and variables (default: true)."
5309
+ },
5310
+ includeCanvas: {
5311
+ type: "boolean",
5312
+ description: "Whether to include the canvas nodes and edges (default: true)."
5313
+ }
5314
+ }
5315
+ }
5316
+ };
5317
+ var MCP_TOOL_EDIT_CANVAS = {
5318
+ name: "edit_canvas",
5319
+ description: "Applies high-level structural operations to the visual canvas (adding nodes, connecting edges, organizing layout, or moving elements).",
5320
+ inputSchema: {
5321
+ type: "object",
5322
+ properties: {
5323
+ operation: {
5324
+ type: "string",
5325
+ enum: [
5326
+ "add_node",
5327
+ "remove_nodes",
5328
+ "connect",
5329
+ "update_node",
5330
+ "layout",
5331
+ "select",
5332
+ "highlight"
5333
+ ],
5334
+ description: "The canvas operation to execute."
5335
+ },
5336
+ node: {
5337
+ type: "object",
5338
+ description: "Node definition when operation is add_node. Can omit position to auto-place."
5339
+ },
5340
+ nearNodeId: {
5341
+ type: "string",
5342
+ description: "Anchor node ID to position beside using collision-aware placement."
5343
+ },
5344
+ side: {
5345
+ type: "string",
5346
+ enum: ["top", "right", "bottom", "left"],
5347
+ description: "Side of the anchor node to place the new node beside."
5348
+ },
5349
+ nodeIds: {
5350
+ type: "array",
5351
+ items: { type: "string" },
5352
+ description: "Array of node IDs for remove_nodes, select, or highlight."
5353
+ },
5354
+ source: {
5355
+ type: "string",
5356
+ description: "Source node ID for connect operation."
5357
+ },
5358
+ target: {
5359
+ type: "string",
5360
+ description: "Target node ID for connect operation."
5361
+ },
5362
+ label: {
5363
+ type: "string",
5364
+ description: "Optional edge label for connect operation."
5365
+ },
5366
+ direction: {
5367
+ type: "string",
5368
+ enum: ["LR", "TB", "RL", "BT"],
5369
+ description: "Layout direction (default LR)."
5370
+ },
5371
+ incremental: {
5372
+ type: "boolean",
5373
+ description: "Preserve existing node coordinates and blend layout (default true)."
5374
+ }
5375
+ },
5376
+ required: ["operation"]
5377
+ }
5378
+ };
5379
+ var MCP_TOOL_EDIT_PROMPT = {
5380
+ name: "edit_prompt",
5381
+ description: "Applies edits to the prompt template document, including inserting text, replacing ranges, and setting variables.",
5382
+ inputSchema: {
5383
+ type: "object",
5384
+ properties: {
5385
+ operation: {
5386
+ type: "string",
5387
+ enum: ["insert_text", "replace_range", "set_variable", "select"],
5388
+ description: "The prompt operation to execute."
5389
+ },
5390
+ text: {
5391
+ type: "string",
5392
+ description: "Text to insert or replace."
5393
+ },
5394
+ at: {
5395
+ type: "number",
5396
+ description: "Position to insert text at."
5397
+ },
5398
+ from: {
5399
+ type: "number",
5400
+ description: "Start offset for replace_range or select."
5401
+ },
5402
+ to: {
5403
+ type: "number",
5404
+ description: "End offset for replace_range or select."
5405
+ },
5406
+ name: {
5407
+ type: "string",
5408
+ description: "Variable name for set_variable."
5409
+ },
5410
+ value: {
5411
+ description: "Variable value for set_variable."
5412
+ }
5413
+ },
5414
+ required: ["operation"]
5415
+ }
5416
+ };
5417
+ var MCP_TOOL_VIEW_EDITOR = {
5418
+ name: "view_editor",
5419
+ description: "Captures a visual image snapshot (JPEG or PNG) of the editor canvas or viewport for multimodal evaluation. Active agent cursor indicators are automatically excluded from the snapshot.",
5420
+ inputSchema: {
5421
+ type: "object",
5422
+ properties: {
5423
+ scope: {
5424
+ type: "string",
5425
+ enum: ["viewport", "canvas"],
5426
+ description: "Whether to capture only the visible viewport or the full canvas bounding box (default: viewport)."
5427
+ },
5428
+ format: {
5429
+ type: "string",
5430
+ enum: ["jpeg", "png"],
5431
+ description: "Image format of the base64 snapshot (default: jpeg)."
5432
+ },
5433
+ maxEdge: {
5434
+ type: "integer",
5435
+ description: "Maximum width or height dimension in pixels (default: 1024)."
5436
+ }
5437
+ }
5438
+ }
5439
+ };
5440
+ var EXPORT_EXCLUDED_SELECTORS = [
5441
+ ".pixerate-presence",
5442
+ ".agent-presence",
5443
+ ".ursula-presence"
5444
+ ];
5445
+ var EDITOR_MCP_TOOLS = [
5446
+ MCP_TOOL_GET_EDITOR_STATE,
5447
+ MCP_TOOL_EDIT_CANVAS,
5448
+ MCP_TOOL_EDIT_PROMPT,
5449
+ MCP_TOOL_VIEW_EDITOR
5450
+ ];
4249
5451
  export {
4250
5452
  ColorHighlighter,
5453
+ DEFAULT_NODE_HEIGHT,
5454
+ DEFAULT_NODE_WIDTH,
5455
+ DEFAULT_PLACEMENT_GAP,
4251
5456
  DataSourceBinder,
4252
5457
  DependencyGraph,
4253
5458
  DirtyTracker,
5459
+ EDITOR_MCP_TOOLS,
5460
+ EXPORT_EXCLUDED_SELECTORS,
4254
5461
  EditorController,
4255
5462
  FontSize,
4256
5463
  FormulaEvaluator,
@@ -4261,23 +5468,44 @@ export {
4261
5468
  Image2 as Image,
4262
5469
  LoadingNode,
4263
5470
  MARKDOWN_MENTION_SPLIT_REGEX,
5471
+ MCP_TOOL_EDIT_CANVAS,
5472
+ MCP_TOOL_EDIT_PROMPT,
5473
+ MCP_TOOL_GET_EDITOR_STATE,
5474
+ MCP_TOOL_VIEW_EDITOR,
4264
5475
  MENTION_REGEX,
5476
+ ManualClock,
4265
5477
  Markdown2 as Markdown,
4266
5478
  Mention,
4267
5479
  SlashCommands,
4268
5480
  SmilieReplacer,
4269
5481
  SpreadsheetController,
5482
+ StreamingLayoutManager,
4270
5483
  TEMPLATE_REGEX,
4271
5484
  TemplateSuggestions,
4272
5485
  VARIABLE_REGEX,
5486
+ blendLayout,
5487
+ boundsOf,
5488
+ calculateDagreReflowDisplacement,
5489
+ calculateDirectionalDisplacement,
5490
+ canvasHeight,
5491
+ centerNodes,
5492
+ centre,
4273
5493
  colNameToIndex,
5494
+ computeNodesBoundingBox,
5495
+ connectedOnly,
5496
+ createBezierTrajectory,
4274
5497
  createDirtyTracker,
4275
5498
  createEditor,
5499
+ createFanOutTrajectory,
4276
5500
  createHistoryManager,
4277
5501
  createMentionExtension,
4278
5502
  createRichTextPreset,
5503
+ defaultEasing,
4279
5504
  defaultIsEqual,
5505
+ ensureLayout,
4280
5506
  escapeHtml,
5507
+ estimateCanvasHeight,
5508
+ estimateNodeSize,
4281
5509
  extractCellDependencies,
4282
5510
  extractInstructionNames,
4283
5511
  extractMentions,
@@ -4285,29 +5513,48 @@ export {
4285
5513
  extractTemplateNames,
4286
5514
  extractVariableNames,
4287
5515
  findHexColors,
5516
+ flowSide,
5517
+ getCenteredNodePosition,
4288
5518
  getEditorMarkdown,
4289
5519
  getEditorText,
4290
5520
  getLatestVersion,
5521
+ getLayoutedNodes,
4291
5522
  handleImageInsertion,
4292
5523
  htmlToPlainText,
4293
5524
  imagePastePluginKey,
4294
5525
  indexToColName,
4295
5526
  insertImageNode,
4296
5527
  instructionRegex,
5528
+ isEventFromTextInput,
5529
+ isValidCanvasNode,
5530
+ isValidUrl,
5531
+ layoutBounds,
5532
+ linearPositionTrajectory,
5533
+ linearTrajectory,
4297
5534
  mapRawOffsetToResolved,
4298
5535
  mapResolvedOffsetToRaw,
4299
5536
  markdownToTipTapHtml,
5537
+ overlaps,
5538
+ pageHidden,
5539
+ parseCanvasClipboardData,
4300
5540
  parseCellReference,
4301
5541
  parseFormula,
4302
5542
  parseMentionSegments,
4303
5543
  parseRange,
5544
+ placeBeside,
4304
5545
  plainTextToTipTapHtml,
5546
+ planAgentCommand,
4305
5547
  preprocessMarkdownFileLinks,
4306
5548
  preprocessMarkdownMentions,
5549
+ realClock,
5550
+ remapPastedNodes,
4307
5551
  removeImageNode,
5552
+ repositionNodesTo,
4308
5553
  resolveTemplates,
4309
5554
  resolveTemplatesWithMapping,
4310
5555
  resolveVariables,
5556
+ runMultiNodeTransition,
5557
+ serializeCanvasNodes,
4311
5558
  stripMarkdownCode,
4312
5559
  templateRegex,
4313
5560
  tokenizeFormula,