dodraw-mcp-server 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/tools/diagramTools.js +179 -9
- package/package.json +1 -1
- package/src/tools/diagramTools.ts +164 -9
|
@@ -140,7 +140,7 @@ exports.toolDefinitions = [
|
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
142
|
name: "add_directional_node",
|
|
143
|
-
description: "Add a new node relative to an existing node and connect them. PRIMARY method for creating diagrams.",
|
|
143
|
+
description: "Add a new node relative to an existing node and connect them. PRIMARY method for creating diagrams, including Class and Database diagrams. Supports 'columns' for DB tables.",
|
|
144
144
|
inputSchema: {
|
|
145
145
|
type: "object",
|
|
146
146
|
properties: {
|
|
@@ -154,14 +154,28 @@ exports.toolDefinitions = [
|
|
|
154
154
|
color: { type: "string" },
|
|
155
155
|
edgeLabel: { type: "string", description: "Optional label for the connecting edge" },
|
|
156
156
|
attributes: { type: "array", items: { type: "string" }, description: "Optional list of attributes for Class nodes" },
|
|
157
|
-
methods: { type: "array", items: { type: "string" }, description: "Optional list of methods for Class nodes" }
|
|
157
|
+
methods: { type: "array", items: { type: "string" }, description: "Optional list of methods for Class nodes" },
|
|
158
|
+
columns: {
|
|
159
|
+
type: "array",
|
|
160
|
+
description: "Optional list of columns for Table nodes",
|
|
161
|
+
items: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
name: { type: "string" },
|
|
165
|
+
type: { type: "string" },
|
|
166
|
+
isPk: { type: "boolean" },
|
|
167
|
+
isFk: { type: "boolean" }
|
|
168
|
+
},
|
|
169
|
+
required: ["name", "type"]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
158
172
|
},
|
|
159
173
|
required: ["filePath", "sourceNodeId", "direction", "label"]
|
|
160
174
|
}
|
|
161
175
|
},
|
|
162
176
|
{
|
|
163
177
|
name: "create_uml_class",
|
|
164
|
-
description: "Create a UML Class node
|
|
178
|
+
description: "Create a UML Class node. Use this for the FIRST class. For connected classes, use 'add_directional_node' to ensure correct relative positioning.",
|
|
165
179
|
inputSchema: {
|
|
166
180
|
type: "object",
|
|
167
181
|
properties: {
|
|
@@ -178,7 +192,7 @@ exports.toolDefinitions = [
|
|
|
178
192
|
},
|
|
179
193
|
{
|
|
180
194
|
name: "create_db_table",
|
|
181
|
-
description: "Create a Database Entity (ERD Table)",
|
|
195
|
+
description: "Create a Database Entity (ERD Table). Supports absolute positioning (x,y) OR relative positioning (referenceNodeId, direction). Can also auto-connect.",
|
|
182
196
|
inputSchema: {
|
|
183
197
|
type: "object",
|
|
184
198
|
properties: {
|
|
@@ -199,7 +213,19 @@ exports.toolDefinitions = [
|
|
|
199
213
|
},
|
|
200
214
|
x: { type: "number" },
|
|
201
215
|
y: { type: "number" },
|
|
202
|
-
id: { type: "string", description: "Optional explicit ID" }
|
|
216
|
+
id: { type: "string", description: "Optional explicit ID" },
|
|
217
|
+
referenceNodeId: { type: "string", description: "Optional. ID of an existing node to place this new table relative to." },
|
|
218
|
+
direction: { type: "string", enum: ["UP", "DOWN", "LEFT", "RIGHT"], description: "Optional. Direction to place relative to referenceNodeId." },
|
|
219
|
+
connection: {
|
|
220
|
+
type: "object",
|
|
221
|
+
description: "Optional. If provided, creates an edge connecting the reference node to this new table.",
|
|
222
|
+
properties: {
|
|
223
|
+
type: { type: "string", enum: ["one-to-one", "one-to-many", "many-to-many"], description: "Relationship type" },
|
|
224
|
+
label: { type: "string" },
|
|
225
|
+
direction: { type: "string", enum: ["source-to-target", "target-to-source", "bi-directional"], description: "Edge direction flow" }
|
|
226
|
+
},
|
|
227
|
+
required: ["type"]
|
|
228
|
+
}
|
|
203
229
|
},
|
|
204
230
|
required: ["filePath", "tableName", "columns"]
|
|
205
231
|
}
|
|
@@ -402,6 +428,14 @@ async function handleToolCall(name, args) {
|
|
|
402
428
|
attributes: args.attributes || [],
|
|
403
429
|
methods: args.methods || []
|
|
404
430
|
} : undefined,
|
|
431
|
+
dbTableData: args.columns ? {
|
|
432
|
+
columns: args.columns.map((c) => ({
|
|
433
|
+
name: c.name,
|
|
434
|
+
type: c.type,
|
|
435
|
+
isPk: !!c.isPk,
|
|
436
|
+
isFk: !!c.isFk
|
|
437
|
+
}))
|
|
438
|
+
} : undefined,
|
|
405
439
|
textAlignVertical: 'center',
|
|
406
440
|
textAlignHorizontal: 'center'
|
|
407
441
|
};
|
|
@@ -528,11 +562,19 @@ async function handleToolCall(name, args) {
|
|
|
528
562
|
const methodCount = (args.methods || []).length;
|
|
529
563
|
const estimatedHeight = 0.8 + (attrCount + methodCount) * 0.4;
|
|
530
564
|
const height = Math.max(2, estimatedHeight);
|
|
565
|
+
// Auto-placement logic if X/Y not provided
|
|
566
|
+
let x = args.x !== undefined ? Number(args.x) : 0;
|
|
567
|
+
let z = args.y !== undefined ? Number(args.y) : 0;
|
|
568
|
+
if (args.x === undefined && args.y === undefined && state.nodes.length > 0) {
|
|
569
|
+
const lastNode = state.nodes[state.nodes.length - 1];
|
|
570
|
+
x = lastNode.x + 5;
|
|
571
|
+
z = lastNode.z;
|
|
572
|
+
}
|
|
531
573
|
const newNode = {
|
|
532
574
|
id: newNodeId,
|
|
533
|
-
x:
|
|
575
|
+
x: x,
|
|
534
576
|
y: 0,
|
|
535
|
-
z:
|
|
577
|
+
z: z,
|
|
536
578
|
width: width,
|
|
537
579
|
height: height,
|
|
538
580
|
label: args.className,
|
|
@@ -556,11 +598,74 @@ async function handleToolCall(name, args) {
|
|
|
556
598
|
const estimatedHeight = 0.8 + cols.length * 0.4;
|
|
557
599
|
const height = Math.max(2, estimatedHeight);
|
|
558
600
|
const width = 3;
|
|
601
|
+
// Auto-placement logic if X/Y not provided
|
|
602
|
+
let x = args.x !== undefined ? Number(args.x) : 0;
|
|
603
|
+
let z = args.y !== undefined ? Number(args.y) : 0;
|
|
604
|
+
// Relative Placement Logic
|
|
605
|
+
if (args.referenceNodeId && args.direction) {
|
|
606
|
+
const sourceNode = state.nodes.find(n => n.id === args.referenceNodeId);
|
|
607
|
+
if (!sourceNode)
|
|
608
|
+
throw new Error(`Reference node ${args.referenceNodeId} not found`);
|
|
609
|
+
const INITIAL_SPACING = 2.0;
|
|
610
|
+
let dirX = 0;
|
|
611
|
+
let dirZ = 0;
|
|
612
|
+
const srcW = Number(sourceNode.width) || 2;
|
|
613
|
+
const srcH = Number(sourceNode.height) || 1.5;
|
|
614
|
+
switch (args.direction) {
|
|
615
|
+
case "RIGHT":
|
|
616
|
+
dirX = 1;
|
|
617
|
+
break;
|
|
618
|
+
case "LEFT":
|
|
619
|
+
dirX = -1;
|
|
620
|
+
break;
|
|
621
|
+
case "DOWN":
|
|
622
|
+
dirZ = 1;
|
|
623
|
+
break;
|
|
624
|
+
case "UP":
|
|
625
|
+
dirZ = -1;
|
|
626
|
+
break;
|
|
627
|
+
}
|
|
628
|
+
x = sourceNode.x + (dirX * (srcW + INITIAL_SPACING));
|
|
629
|
+
z = sourceNode.z + (dirZ * (srcH + INITIAL_SPACING));
|
|
630
|
+
// Collision Avoidance reuse
|
|
631
|
+
const COLLISION_SPACING = 0.5;
|
|
632
|
+
const shiftStepX = srcW + COLLISION_SPACING;
|
|
633
|
+
const shiftStepZ = srcH + COLLISION_SPACING;
|
|
634
|
+
const newW = width;
|
|
635
|
+
const newH = height;
|
|
636
|
+
const checkCollision = (cx, cz) => {
|
|
637
|
+
return state.nodes.some(n => {
|
|
638
|
+
if (n.layerId !== sourceNode.layerId)
|
|
639
|
+
return false;
|
|
640
|
+
const dx = Math.abs(n.x - cx);
|
|
641
|
+
const dz = Math.abs(n.z - cz);
|
|
642
|
+
const otherW = Number(n.width) || 2;
|
|
643
|
+
const otherH = Number(n.height) || 1.5;
|
|
644
|
+
const combinedHalfWidth = (otherW + newW) / 2;
|
|
645
|
+
const combinedHalfHeight = (otherH + newH) / 2;
|
|
646
|
+
return dx < combinedHalfWidth && dz < combinedHalfHeight;
|
|
647
|
+
});
|
|
648
|
+
};
|
|
649
|
+
let iterations = 0;
|
|
650
|
+
while (checkCollision(x, z) && iterations < 50) {
|
|
651
|
+
iterations++;
|
|
652
|
+
if (dirX !== 0)
|
|
653
|
+
z += shiftStepZ;
|
|
654
|
+
else
|
|
655
|
+
x += shiftStepX;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
else if (args.x === undefined && args.y === undefined && state.nodes.length > 0) {
|
|
659
|
+
// Fallback to "next to last" if no explicit relative info
|
|
660
|
+
const lastNode = state.nodes[state.nodes.length - 1];
|
|
661
|
+
x = lastNode.x + 5;
|
|
662
|
+
z = lastNode.z;
|
|
663
|
+
}
|
|
559
664
|
const newNode = {
|
|
560
665
|
id: newNodeId,
|
|
561
|
-
x:
|
|
666
|
+
x: x,
|
|
562
667
|
y: 0,
|
|
563
|
-
z:
|
|
668
|
+
z: z,
|
|
564
669
|
width: width,
|
|
565
670
|
height: height,
|
|
566
671
|
label: args.tableName,
|
|
@@ -577,6 +682,71 @@ async function handleToolCall(name, args) {
|
|
|
577
682
|
}
|
|
578
683
|
};
|
|
579
684
|
state.nodes.push(newNode);
|
|
685
|
+
// Auto-Connect logic
|
|
686
|
+
if (args.connection && args.referenceNodeId) {
|
|
687
|
+
let termStart = 'none';
|
|
688
|
+
let termEnd = 'none';
|
|
689
|
+
// Simplified mapping for DB
|
|
690
|
+
if (args.connection.type === 'one-to-many') {
|
|
691
|
+
// Source (Reference) -> Target (New)
|
|
692
|
+
// If Reference is "Users" (1) and New is "Orders" (N)
|
|
693
|
+
// termStart = one, termEnd = many
|
|
694
|
+
termStart = 'crows-one';
|
|
695
|
+
termEnd = 'crows-many';
|
|
696
|
+
}
|
|
697
|
+
else if (args.connection.type === 'one-to-one') {
|
|
698
|
+
termStart = 'crows-one';
|
|
699
|
+
termEnd = 'crows-one';
|
|
700
|
+
}
|
|
701
|
+
else if (args.connection.type === 'many-to-many') {
|
|
702
|
+
termStart = 'crows-many';
|
|
703
|
+
termEnd = 'crows-many';
|
|
704
|
+
}
|
|
705
|
+
// Points? Simple defaults based on direction or just center-ish
|
|
706
|
+
// Let's use the logic from add_directional_node for cleaner ports if possible
|
|
707
|
+
// But simple 0-3 logic:
|
|
708
|
+
let sp = 0;
|
|
709
|
+
let tp = 0;
|
|
710
|
+
switch (args.direction) {
|
|
711
|
+
case "RIGHT":
|
|
712
|
+
sp = 1;
|
|
713
|
+
tp = 3;
|
|
714
|
+
break;
|
|
715
|
+
case "LEFT":
|
|
716
|
+
sp = 3;
|
|
717
|
+
tp = 1;
|
|
718
|
+
break;
|
|
719
|
+
case "DOWN":
|
|
720
|
+
sp = 2;
|
|
721
|
+
tp = 0;
|
|
722
|
+
break;
|
|
723
|
+
case "UP":
|
|
724
|
+
sp = 0;
|
|
725
|
+
tp = 2;
|
|
726
|
+
break;
|
|
727
|
+
default:
|
|
728
|
+
sp = 2;
|
|
729
|
+
tp = 0;
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
const newEdge = {
|
|
733
|
+
id: (0, crypto_1.randomUUID)(),
|
|
734
|
+
sourceId: args.referenceNodeId,
|
|
735
|
+
targetId: newNodeId,
|
|
736
|
+
sourcePointIndex: sp,
|
|
737
|
+
targetPointIndex: tp,
|
|
738
|
+
label: args.connection.label,
|
|
739
|
+
style: 'line',
|
|
740
|
+
routingType: 'orthogonal',
|
|
741
|
+
color: '#000000',
|
|
742
|
+
thickness: 0.01,
|
|
743
|
+
fontSize: 20,
|
|
744
|
+
borderStyle: 'solid',
|
|
745
|
+
terminationStart: termStart,
|
|
746
|
+
terminationEnd: termEnd
|
|
747
|
+
};
|
|
748
|
+
state.edges.push(newEdge);
|
|
749
|
+
}
|
|
580
750
|
await (0, fileHandler_1.saveDiagramFile)(args.filePath, state);
|
|
581
751
|
return { content: [{ type: "text", text: `Created DB Table '${args.tableName}'` }] };
|
|
582
752
|
}
|
package/package.json
CHANGED
|
@@ -140,7 +140,7 @@ export const toolDefinitions: Tool[] = [
|
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
142
|
name: "add_directional_node",
|
|
143
|
-
description: "Add a new node relative to an existing node and connect them. PRIMARY method for creating diagrams.",
|
|
143
|
+
description: "Add a new node relative to an existing node and connect them. PRIMARY method for creating diagrams, including Class and Database diagrams. Supports 'columns' for DB tables.",
|
|
144
144
|
inputSchema: {
|
|
145
145
|
type: "object",
|
|
146
146
|
properties: {
|
|
@@ -154,14 +154,28 @@ export const toolDefinitions: Tool[] = [
|
|
|
154
154
|
color: { type: "string" },
|
|
155
155
|
edgeLabel: { type: "string", description: "Optional label for the connecting edge" },
|
|
156
156
|
attributes: { type: "array", items: { type: "string" }, description: "Optional list of attributes for Class nodes" },
|
|
157
|
-
methods: { type: "array", items: { type: "string" }, description: "Optional list of methods for Class nodes" }
|
|
157
|
+
methods: { type: "array", items: { type: "string" }, description: "Optional list of methods for Class nodes" },
|
|
158
|
+
columns: {
|
|
159
|
+
type: "array",
|
|
160
|
+
description: "Optional list of columns for Table nodes",
|
|
161
|
+
items: {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
name: { type: "string" },
|
|
165
|
+
type: { type: "string" },
|
|
166
|
+
isPk: { type: "boolean" },
|
|
167
|
+
isFk: { type: "boolean" }
|
|
168
|
+
},
|
|
169
|
+
required: ["name", "type"]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
158
172
|
},
|
|
159
173
|
required: ["filePath", "sourceNodeId", "direction", "label"]
|
|
160
174
|
}
|
|
161
175
|
},
|
|
162
176
|
{
|
|
163
177
|
name: "create_uml_class",
|
|
164
|
-
description: "Create a UML Class node
|
|
178
|
+
description: "Create a UML Class node. Use this for the FIRST class. For connected classes, use 'add_directional_node' to ensure correct relative positioning.",
|
|
165
179
|
inputSchema: {
|
|
166
180
|
type: "object",
|
|
167
181
|
properties: {
|
|
@@ -178,7 +192,8 @@ export const toolDefinitions: Tool[] = [
|
|
|
178
192
|
},
|
|
179
193
|
{
|
|
180
194
|
name: "create_db_table",
|
|
181
|
-
|
|
195
|
+
|
|
196
|
+
description: "Create a Database Entity (ERD Table). Supports absolute positioning (x,y) OR relative positioning (referenceNodeId, direction). Can also auto-connect.",
|
|
182
197
|
inputSchema: {
|
|
183
198
|
type: "object",
|
|
184
199
|
properties: {
|
|
@@ -199,7 +214,19 @@ export const toolDefinitions: Tool[] = [
|
|
|
199
214
|
},
|
|
200
215
|
x: { type: "number" },
|
|
201
216
|
y: { type: "number" },
|
|
202
|
-
id: { type: "string", description: "Optional explicit ID" }
|
|
217
|
+
id: { type: "string", description: "Optional explicit ID" },
|
|
218
|
+
referenceNodeId: { type: "string", description: "Optional. ID of an existing node to place this new table relative to." },
|
|
219
|
+
direction: { type: "string", enum: ["UP", "DOWN", "LEFT", "RIGHT"], description: "Optional. Direction to place relative to referenceNodeId." },
|
|
220
|
+
connection: {
|
|
221
|
+
type: "object",
|
|
222
|
+
description: "Optional. If provided, creates an edge connecting the reference node to this new table.",
|
|
223
|
+
properties: {
|
|
224
|
+
type: { type: "string", enum: ["one-to-one", "one-to-many", "many-to-many"], description: "Relationship type" },
|
|
225
|
+
label: { type: "string" },
|
|
226
|
+
direction: { type: "string", enum: ["source-to-target", "target-to-source", "bi-directional"], description: "Edge direction flow" }
|
|
227
|
+
},
|
|
228
|
+
required: ["type"]
|
|
229
|
+
}
|
|
203
230
|
},
|
|
204
231
|
required: ["filePath", "tableName", "columns"]
|
|
205
232
|
}
|
|
@@ -417,6 +444,14 @@ export async function handleToolCall(name: string, args: any): Promise<any> {
|
|
|
417
444
|
attributes: args.attributes || [],
|
|
418
445
|
methods: args.methods || []
|
|
419
446
|
} : undefined,
|
|
447
|
+
dbTableData: args.columns ? {
|
|
448
|
+
columns: args.columns.map((c: any) => ({
|
|
449
|
+
name: c.name,
|
|
450
|
+
type: c.type,
|
|
451
|
+
isPk: !!c.isPk,
|
|
452
|
+
isFk: !!c.isFk
|
|
453
|
+
}))
|
|
454
|
+
} : undefined,
|
|
420
455
|
textAlignVertical: 'center',
|
|
421
456
|
textAlignHorizontal: 'center'
|
|
422
457
|
};
|
|
@@ -544,11 +579,21 @@ export async function handleToolCall(name: string, args: any): Promise<any> {
|
|
|
544
579
|
const estimatedHeight = 0.8 + (attrCount + methodCount) * 0.4;
|
|
545
580
|
const height = Math.max(2, estimatedHeight);
|
|
546
581
|
|
|
582
|
+
// Auto-placement logic if X/Y not provided
|
|
583
|
+
let x = args.x !== undefined ? Number(args.x) : 0;
|
|
584
|
+
let z = args.y !== undefined ? Number(args.y) : 0;
|
|
585
|
+
|
|
586
|
+
if (args.x === undefined && args.y === undefined && state.nodes.length > 0) {
|
|
587
|
+
const lastNode = state.nodes[state.nodes.length - 1];
|
|
588
|
+
x = lastNode.x + 5;
|
|
589
|
+
z = lastNode.z;
|
|
590
|
+
}
|
|
591
|
+
|
|
547
592
|
const newNode: NodeData = {
|
|
548
593
|
id: newNodeId,
|
|
549
|
-
x:
|
|
594
|
+
x: x,
|
|
550
595
|
y: 0,
|
|
551
|
-
z:
|
|
596
|
+
z: z,
|
|
552
597
|
width: width,
|
|
553
598
|
height: height,
|
|
554
599
|
label: args.className,
|
|
@@ -573,13 +618,72 @@ export async function handleToolCall(name: string, args: any): Promise<any> {
|
|
|
573
618
|
// Header + items
|
|
574
619
|
const estimatedHeight = 0.8 + cols.length * 0.4;
|
|
575
620
|
const height = Math.max(2, estimatedHeight);
|
|
621
|
+
|
|
576
622
|
const width = 3;
|
|
577
623
|
|
|
624
|
+
// Auto-placement logic if X/Y not provided
|
|
625
|
+
let x = args.x !== undefined ? Number(args.x) : 0;
|
|
626
|
+
let z = args.y !== undefined ? Number(args.y) : 0;
|
|
627
|
+
|
|
628
|
+
// Relative Placement Logic
|
|
629
|
+
if (args.referenceNodeId && args.direction) {
|
|
630
|
+
const sourceNode = state.nodes.find(n => n.id === args.referenceNodeId);
|
|
631
|
+
if (!sourceNode) throw new Error(`Reference node ${args.referenceNodeId} not found`);
|
|
632
|
+
|
|
633
|
+
const INITIAL_SPACING = 2.0;
|
|
634
|
+
let dirX = 0;
|
|
635
|
+
let dirZ = 0;
|
|
636
|
+
const srcW = Number(sourceNode.width) || 2;
|
|
637
|
+
const srcH = Number(sourceNode.height) || 1.5;
|
|
638
|
+
|
|
639
|
+
switch (args.direction) {
|
|
640
|
+
case "RIGHT": dirX = 1; break;
|
|
641
|
+
case "LEFT": dirX = -1; break;
|
|
642
|
+
case "DOWN": dirZ = 1; break;
|
|
643
|
+
case "UP": dirZ = -1; break;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
x = sourceNode.x + (dirX * (srcW + INITIAL_SPACING));
|
|
647
|
+
z = sourceNode.z + (dirZ * (srcH + INITIAL_SPACING));
|
|
648
|
+
|
|
649
|
+
// Collision Avoidance reuse
|
|
650
|
+
const COLLISION_SPACING = 0.5;
|
|
651
|
+
const shiftStepX = srcW + COLLISION_SPACING;
|
|
652
|
+
const shiftStepZ = srcH + COLLISION_SPACING;
|
|
653
|
+
const newW = width;
|
|
654
|
+
const newH = height;
|
|
655
|
+
|
|
656
|
+
const checkCollision = (cx: number, cz: number) => {
|
|
657
|
+
return state.nodes.some(n => {
|
|
658
|
+
if (n.layerId !== sourceNode.layerId) return false;
|
|
659
|
+
const dx = Math.abs(n.x - cx);
|
|
660
|
+
const dz = Math.abs(n.z - cz);
|
|
661
|
+
const otherW = Number(n.width) || 2;
|
|
662
|
+
const otherH = Number(n.height) || 1.5;
|
|
663
|
+
const combinedHalfWidth = (otherW + newW) / 2;
|
|
664
|
+
const combinedHalfHeight = (otherH + newH) / 2;
|
|
665
|
+
return dx < combinedHalfWidth && dz < combinedHalfHeight;
|
|
666
|
+
});
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
let iterations = 0;
|
|
670
|
+
while (checkCollision(x, z) && iterations < 50) {
|
|
671
|
+
iterations++;
|
|
672
|
+
if (dirX !== 0) z += shiftStepZ;
|
|
673
|
+
else x += shiftStepX;
|
|
674
|
+
}
|
|
675
|
+
} else if (args.x === undefined && args.y === undefined && state.nodes.length > 0) {
|
|
676
|
+
// Fallback to "next to last" if no explicit relative info
|
|
677
|
+
const lastNode = state.nodes[state.nodes.length - 1];
|
|
678
|
+
x = lastNode.x + 5;
|
|
679
|
+
z = lastNode.z;
|
|
680
|
+
}
|
|
681
|
+
|
|
578
682
|
const newNode: NodeData = {
|
|
579
683
|
id: newNodeId,
|
|
580
|
-
x:
|
|
684
|
+
x: x,
|
|
581
685
|
y: 0,
|
|
582
|
-
z:
|
|
686
|
+
z: z,
|
|
583
687
|
width: width,
|
|
584
688
|
height: height,
|
|
585
689
|
label: args.tableName,
|
|
@@ -597,6 +701,57 @@ export async function handleToolCall(name: string, args: any): Promise<any> {
|
|
|
597
701
|
};
|
|
598
702
|
|
|
599
703
|
state.nodes.push(newNode);
|
|
704
|
+
|
|
705
|
+
// Auto-Connect logic
|
|
706
|
+
if (args.connection && args.referenceNodeId) {
|
|
707
|
+
let termStart = 'none';
|
|
708
|
+
let termEnd = 'none';
|
|
709
|
+
// Simplified mapping for DB
|
|
710
|
+
if (args.connection.type === 'one-to-many') {
|
|
711
|
+
// Source (Reference) -> Target (New)
|
|
712
|
+
// If Reference is "Users" (1) and New is "Orders" (N)
|
|
713
|
+
// termStart = one, termEnd = many
|
|
714
|
+
termStart = 'crows-one';
|
|
715
|
+
termEnd = 'crows-many';
|
|
716
|
+
} else if (args.connection.type === 'one-to-one') {
|
|
717
|
+
termStart = 'crows-one';
|
|
718
|
+
termEnd = 'crows-one';
|
|
719
|
+
} else if (args.connection.type === 'many-to-many') {
|
|
720
|
+
termStart = 'crows-many';
|
|
721
|
+
termEnd = 'crows-many';
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Points? Simple defaults based on direction or just center-ish
|
|
725
|
+
// Let's use the logic from add_directional_node for cleaner ports if possible
|
|
726
|
+
// But simple 0-3 logic:
|
|
727
|
+
let sp = 0;
|
|
728
|
+
let tp = 0;
|
|
729
|
+
switch(args.direction) {
|
|
730
|
+
case "RIGHT": sp=1; tp=3; break;
|
|
731
|
+
case "LEFT": sp=3; tp=1; break;
|
|
732
|
+
case "DOWN": sp=2; tp=0; break;
|
|
733
|
+
case "UP": sp=0; tp=2; break;
|
|
734
|
+
default: sp=2; tp=0; break;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const newEdge: EdgeData = {
|
|
738
|
+
id: randomUUID(),
|
|
739
|
+
sourceId: args.referenceNodeId,
|
|
740
|
+
targetId: newNodeId,
|
|
741
|
+
sourcePointIndex: sp,
|
|
742
|
+
targetPointIndex: tp,
|
|
743
|
+
label: args.connection.label,
|
|
744
|
+
style: 'line',
|
|
745
|
+
routingType: 'orthogonal',
|
|
746
|
+
color: '#000000',
|
|
747
|
+
thickness: 0.01,
|
|
748
|
+
fontSize: 20,
|
|
749
|
+
borderStyle: 'solid',
|
|
750
|
+
terminationStart: termStart as any,
|
|
751
|
+
terminationEnd: termEnd as any
|
|
752
|
+
};
|
|
753
|
+
state.edges.push(newEdge);
|
|
754
|
+
}
|
|
600
755
|
await saveDiagramFile(args.filePath, state);
|
|
601
756
|
return { content: [{ type: "text", text: `Created DB Table '${args.tableName}'` }] };
|
|
602
757
|
}
|