sad-mcp 2.3.6 → 2.3.7

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.
@@ -12,7 +12,7 @@ export declare const L: {
12
12
  readonly POOL_VGAP: 16;
13
13
  readonly LANE_MIN_H: 140;
14
14
  readonly LANE_CORRIDOR_H: 56;
15
- readonly EMPTY_POOL_H: 60;
15
+ readonly EMPTY_POOL_H: 96;
16
16
  readonly CANVAS_TOP: 72;
17
17
  readonly CANVAS_LEFT_PAD: 20;
18
18
  readonly CANVAS_RIGHT_PAD: 40;
@@ -31,7 +31,7 @@ export const L = {
31
31
  POOL_VGAP: 16,
32
32
  LANE_MIN_H: 140,
33
33
  LANE_CORRIDOR_H: 56, // bottom band for data stores/objects
34
- EMPTY_POOL_H: 60,
34
+ EMPTY_POOL_H: 96, // tall enough for a wrapped 2-line pool label
35
35
  CANVAS_TOP: 72, // room for header bar above diagram
36
36
  CANVAS_LEFT_PAD: 20,
37
37
  CANVAS_RIGHT_PAD: 40,
@@ -389,10 +389,10 @@ export function layoutModel(m) {
389
389
  // ── Pool ordering ──────────────────────────────────────────────────────
390
390
  //
391
391
  // Heuristic:
392
- // - Identify which external pool initiates the process by sending a
393
- // message to the organization pool's start event.
394
- // - Put that pool first, then the organization pool(s), then the rest.
395
- // - Preserve relative order within each group from the input array.
392
+ // - If an external pool initiates the process by messaging the
393
+ // organization's start event, promote it to the top.
394
+ // - Otherwise preserve the modeler's input order (the natural expectation
395
+ // when the start event is a plain origin with no incoming message).
396
396
  function orderPools(m) {
397
397
  const initiators = new Set();
398
398
  const orgStartEvents = new Set();
@@ -409,16 +409,9 @@ function orderPools(m) {
409
409
  initiators.add(mf.fromPool);
410
410
  }
411
411
  }
412
- const primary = [];
413
- const org = [];
414
- const supporting = [];
415
- for (const p of m.pools) {
416
- if (initiators.has(p.id))
417
- primary.push(p);
418
- else if (p.type === "organization")
419
- org.push(p);
420
- else
421
- supporting.push(p);
422
- }
423
- return [...primary, ...org, ...supporting];
412
+ if (initiators.size === 0)
413
+ return [...m.pools]; // respect input order
414
+ const primary = m.pools.filter((p) => initiators.has(p.id));
415
+ const rest = m.pools.filter((p) => !initiators.has(p.id));
416
+ return [...primary, ...rest];
424
417
  }
package/dist/bpmn/svg.js CHANGED
@@ -80,6 +80,24 @@ export function renderPool(pool) {
80
80
  const contentW = pool.w - headerW;
81
81
  const labelCx = headerX + headerW / 2;
82
82
  const labelCy = pool.y + pool.h / 2;
83
+ // Rotated pool labels run vertically, so their available length is the pool
84
+ // HEIGHT. Short (external-empty) pools clip long names — wrap to fit, and
85
+ // render the lines side by side across the header width.
86
+ const maxChars = Math.max(4, Math.floor((pool.h - 14) / 7));
87
+ const nameLines = wrapLabel(pool.name, maxChars, 3);
88
+ const lines = nameLines.length ? nameLines : [pool.name];
89
+ const nameFont = lines.length >= 3 ? 10 : lines.length === 2 ? 11 : 12;
90
+ const nameGap = nameFont + 1;
91
+ const nameSvg = lines
92
+ .map((ln, i) => {
93
+ const lx = labelCx + (i - (lines.length - 1) / 2) * nameGap;
94
+ return `<text x="${lx}" y="${labelCy}" text-anchor="middle"
95
+ dominant-baseline="middle"
96
+ transform="rotate(-90, ${lx}, ${labelCy})"
97
+ fill="#ffffff" font-size="${nameFont}" font-weight="600"
98
+ direction="rtl">${escapeXml(ln)}</text>`;
99
+ })
100
+ .join("\n ");
83
101
  return `
84
102
  <!-- pool: ${escapeXml(pool.poolId)} -->
85
103
  <g class="bpmn-pool" data-pool="${escapeXml(pool.poolId)}">
@@ -87,11 +105,7 @@ export function renderPool(pool) {
87
105
  fill="${bodyFill}" stroke="${bodyStroke}" stroke-width="1.5"/>
88
106
  <rect x="${headerX}" y="${pool.y}" width="${headerW}" height="${pool.h}"
89
107
  fill="${headerFill}" stroke="${bodyStroke}" stroke-width="1.5"/>
90
- <text x="${labelCx}" y="${labelCy}" text-anchor="middle"
91
- dominant-baseline="middle"
92
- transform="rotate(-90, ${labelCx}, ${labelCy})"
93
- fill="#ffffff" font-size="12" font-weight="600"
94
- direction="rtl">${escapeXml(pool.name)}</text>
108
+ ${nameSvg}
95
109
  <line x1="${contentX}" y1="${pool.y}" x2="${contentX}" y2="${pool.y + pool.h}"
96
110
  stroke="${bodyStroke}" stroke-width="1"/>
97
111
  </g>`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sad-mcp",
3
- "version": "2.3.6",
3
+ "version": "2.3.7",
4
4
  "description": "MCP server for Software Analysis and Design course materials at BGU",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,7 +44,7 @@ Two compartments separated by a horizontal line:
44
44
  - `exit /` actions on leaving
45
45
  - `do /` ongoing activity while in state
46
46
 
47
- Multiple activity lines in one compartment are fine.
47
+ Multiple activity lines in one compartment are fine — but that means different *kinds* of lines (`entry /`, `exit /`, `do /`). Each kind appears **at most once per state**: a state has a single entry behavior, so multiple entry actions are written in the one `entry /` clause separated by `;`, never as a repeated `entry /` line.
48
48
 
49
49
  ## Layout Rules (from lectures)
50
50
 
@@ -51,6 +51,7 @@ The shared files prepended to this prompt define the layout recipes, model shape
51
51
  2. **Activity compartment** — always present; minimum content is `entry / setStatus('SCREAMING_SNAKE_CASE')`
52
52
  - `setStatus()` is required in every state including composite states and archive states — it represents the object's tracked status in the implementation
53
53
  - Additional compartment lines: `entry / action`, `exit / action`, `do / activity`
54
+ - **At most one `entry /` clause per state** (same for `exit /`). UML allows a single entry behavior; multiple entry actions go in that one clause, separated by `;` (wrap to an indented continuation line if too wide) — never write a second `entry /` line
54
55
  - Never produce a state with only a name and no compartment
55
56
 
56
57
  ### Transitions