@haposoft/cafekit 0.7.23 → 0.7.24

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.
Files changed (63) hide show
  1. package/README.md +81 -862
  2. package/bin/install.js +4 -3
  3. package/package.json +2 -3
  4. package/src/claude/agents/code-auditor.md +25 -1
  5. package/src/claude/agents/spec-maker.md +17 -2
  6. package/src/claude/agents/test-runner.md +22 -3
  7. package/src/claude/hooks/spec-state.cjs +4 -4
  8. package/src/claude/migration-manifest.json +1 -1
  9. package/src/claude/rules/state-sync.md +7 -5
  10. package/src/claude/skills/code-review/references/spec-compliance-review.md +8 -1
  11. package/src/claude/skills/develop/SKILL.md +25 -4
  12. package/src/claude/skills/develop/references/quality-gate.md +23 -13
  13. package/src/claude/skills/generate-graph/LICENSE +21 -0
  14. package/src/claude/skills/generate-graph/README.md +523 -0
  15. package/src/claude/skills/generate-graph/SKILL.md +427 -0
  16. package/src/claude/skills/generate-graph/agentloop-core.svg +101 -0
  17. package/src/claude/skills/generate-graph/agents/openai.yaml +4 -0
  18. package/src/claude/skills/generate-graph/assets/samples/sample-style1-flat.png +0 -0
  19. package/src/claude/skills/generate-graph/assets/samples/sample-style2-dark.png +0 -0
  20. package/src/claude/skills/generate-graph/assets/samples/sample-style3-blueprint.png +0 -0
  21. package/src/claude/skills/generate-graph/assets/samples/sample-style4-notion.png +0 -0
  22. package/src/claude/skills/generate-graph/assets/samples/sample-style5-glass.png +0 -0
  23. package/src/claude/skills/generate-graph/assets/samples/sample-style6-claude.png +0 -0
  24. package/src/claude/skills/generate-graph/assets/samples/sample-style7-openai.png +0 -0
  25. package/src/claude/skills/generate-graph/fixtures/agent-memory-types-style4.json +181 -0
  26. package/src/claude/skills/generate-graph/fixtures/api-flow-style7.json +40 -0
  27. package/src/claude/skills/generate-graph/fixtures/mem0-style1.json +297 -0
  28. package/src/claude/skills/generate-graph/fixtures/microservices-style3.json +64 -0
  29. package/src/claude/skills/generate-graph/fixtures/multi-agent-style5.json +45 -0
  30. package/src/claude/skills/generate-graph/fixtures/system-architecture-style6.json +48 -0
  31. package/src/claude/skills/generate-graph/fixtures/tool-call-style2.json +182 -0
  32. package/src/claude/skills/generate-graph/package.json +42 -0
  33. package/src/claude/skills/generate-graph/references/icons.md +281 -0
  34. package/src/claude/skills/generate-graph/references/style-1-flat-icon.md +108 -0
  35. package/src/claude/skills/generate-graph/references/style-2-dark-terminal.md +107 -0
  36. package/src/claude/skills/generate-graph/references/style-3-blueprint.md +113 -0
  37. package/src/claude/skills/generate-graph/references/style-4-notion-clean.md +94 -0
  38. package/src/claude/skills/generate-graph/references/style-5-glassmorphism.md +125 -0
  39. package/src/claude/skills/generate-graph/references/style-6-claude-official.md +209 -0
  40. package/src/claude/skills/generate-graph/references/style-7-openai.md +215 -0
  41. package/src/claude/skills/generate-graph/references/style-diagram-matrix.md +135 -0
  42. package/src/claude/skills/generate-graph/references/svg-layout-best-practices.md +100 -0
  43. package/src/claude/skills/generate-graph/scripts/generate-diagram.sh +157 -0
  44. package/src/claude/skills/generate-graph/scripts/generate-from-template.py +1556 -0
  45. package/src/claude/skills/generate-graph/scripts/test-all-styles.sh +135 -0
  46. package/src/claude/skills/generate-graph/scripts/validate-svg.sh +292 -0
  47. package/src/claude/skills/generate-graph/templates/agent-architecture.svg +28 -0
  48. package/src/claude/skills/generate-graph/templates/architecture.svg +23 -0
  49. package/src/claude/skills/generate-graph/templates/comparison-matrix.svg +14 -0
  50. package/src/claude/skills/generate-graph/templates/data-flow.svg +28 -0
  51. package/src/claude/skills/generate-graph/templates/er-diagram.svg +21 -0
  52. package/src/claude/skills/generate-graph/templates/flowchart.svg +21 -0
  53. package/src/claude/skills/generate-graph/templates/sequence.svg +20 -0
  54. package/src/claude/skills/generate-graph/templates/state-machine.svg +20 -0
  55. package/src/claude/skills/generate-graph/templates/timeline.svg +19 -0
  56. package/src/claude/skills/generate-graph/templates/use-case.svg +21 -0
  57. package/src/claude/skills/specs/SKILL.md +35 -5
  58. package/src/claude/skills/specs/references/review.md +1 -1
  59. package/src/claude/skills/specs/rules/tasks-generation.md +17 -0
  60. package/src/claude/skills/specs/templates/design.md +13 -0
  61. package/src/claude/skills/specs/templates/init.json +4 -1
  62. package/src/claude/skills/specs/templates/requirements.md +21 -8
  63. package/src/claude/skills/specs/templates/task.md +16 -3
@@ -0,0 +1,135 @@
1
+ #!/bin/bash
2
+ # Batch Test Script
3
+ # Renders regression fixtures, validates SVGs, and exports PNGs
4
+
5
+ set -euo pipefail
6
+
7
+ # Colors
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ BLUE='\033[0;34m'
12
+ NC='\033[0m'
13
+
14
+ SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
15
+ TEST_DIR="${SKILL_DIR}/test-output"
16
+ TIMESTAMP=$(date +%Y%m%d_%H%M%S)
17
+
18
+ echo -e "${BLUE}=== Fireworks Tech Graph - Batch Test ===${NC}"
19
+ echo "Test directory: $TEST_DIR"
20
+ echo "Timestamp: $TIMESTAMP"
21
+ echo ""
22
+
23
+ # Create test directory
24
+ mkdir -p "$TEST_DIR"
25
+
26
+ # Test configuration
27
+ STYLES=(1 2 3 4 5 6 7)
28
+ STYLE_NAMES=("Flat Icon" "Dark Terminal" "Blueprint" "Notion Clean" "Glassmorphism" "Claude Official" "OpenAI Official")
29
+
30
+ # Summary counters
31
+ TOTAL=0
32
+ PASSED=0
33
+ FAILED=0
34
+
35
+ FIXTURES_DIR="${SKILL_DIR}/fixtures"
36
+
37
+ echo -e "${BLUE}Testing all styles...${NC}"
38
+ echo "----------------------------------------"
39
+
40
+ for i in "${!STYLES[@]}"; do
41
+ STYLE="${STYLES[$i]}"
42
+ STYLE_NAME="${STYLE_NAMES[$i]}"
43
+
44
+ echo -e "\n${YELLOW}Style $STYLE: $STYLE_NAME${NC}"
45
+
46
+ # Check if style reference exists
47
+ STYLE_FILE=$(find "${SKILL_DIR}/references" -maxdepth 1 -type f -name "style-${STYLE}-*.md" | head -n 1)
48
+ if [ -z "${STYLE_FILE:-}" ] || [ ! -f "$STYLE_FILE" ]; then
49
+ echo -e "${RED}✗ Style file not found: $STYLE_FILE${NC}"
50
+ FAILED=$((FAILED + 1))
51
+ TOTAL=$((TOTAL + 1))
52
+ continue
53
+ fi
54
+
55
+ echo -e "${GREEN}✓ Style file found${NC}"
56
+
57
+ if [ ! -d "$FIXTURES_DIR" ]; then
58
+ echo -e "${YELLOW}⚠ Fixtures directory not found: $FIXTURES_DIR${NC}"
59
+ continue
60
+ fi
61
+
62
+ FIXTURE_FILES=$(find "$FIXTURES_DIR" -maxdepth 1 -type f -name "*.json" | sort || true)
63
+ MATCHED_FIXTURES=()
64
+ for FIXTURE in $FIXTURE_FILES; do
65
+ FIXTURE_STYLE=$(python3 - "$FIXTURE" <<'PY'
66
+ import json
67
+ import sys
68
+ from pathlib import Path
69
+ data = json.loads(Path(sys.argv[1]).read_text(encoding='utf-8'))
70
+ print(data.get("style", ""))
71
+ PY
72
+ )
73
+ if [ "$FIXTURE_STYLE" = "$STYLE" ]; then
74
+ MATCHED_FIXTURES+=("$FIXTURE")
75
+ fi
76
+ done
77
+
78
+ if [ "${#MATCHED_FIXTURES[@]}" -eq 0 ]; then
79
+ echo -e "${YELLOW}⚠ No regression fixtures found for style $STYLE${NC}"
80
+ continue
81
+ fi
82
+
83
+ # Render, validate, and export each fixture
84
+ for FIXTURE in "${MATCHED_FIXTURES[@]}"; do
85
+ BASENAME=$(basename "$FIXTURE" .json)
86
+ SVG_FILE="${TEST_DIR}/${BASENAME}_${TIMESTAMP}.svg"
87
+ PNG_FILE="${TEST_DIR}/${BASENAME}_${TIMESTAMP}.png"
88
+ TEMPLATE_TYPE=$(python3 - "$FIXTURE" <<'PY'
89
+ import json
90
+ import sys
91
+ from pathlib import Path
92
+ data = json.loads(Path(sys.argv[1]).read_text(encoding='utf-8'))
93
+ print(data.get("template_type", "architecture"))
94
+ PY
95
+ )
96
+
97
+ echo -n " Rendering $BASENAME... "
98
+ TOTAL=$((TOTAL + 1))
99
+
100
+ if python3 "${SKILL_DIR}/scripts/generate-from-template.py" "$TEMPLATE_TYPE" "$SVG_FILE" "$(cat "$FIXTURE")" > /dev/null 2>&1 \
101
+ && "${SKILL_DIR}/scripts/validate-svg.sh" "$SVG_FILE" > /dev/null 2>&1; then
102
+ if command -v rsvg-convert &> /dev/null \
103
+ && rsvg-convert -w 1920 "$SVG_FILE" -o "$PNG_FILE" 2>/dev/null; then
104
+ PNG_SIZE=$(du -h "$PNG_FILE" | cut -f1)
105
+ echo -e "${GREEN}✓ Pass${NC} (${PNG_SIZE})"
106
+ else
107
+ echo -e "${GREEN}✓ Pass${NC}"
108
+ fi
109
+ PASSED=$((PASSED + 1))
110
+ else
111
+ echo -e "${RED}✗ Fail${NC}"
112
+ FAILED=$((FAILED + 1))
113
+ if [ -f "$SVG_FILE" ]; then
114
+ "${SKILL_DIR}/scripts/validate-svg.sh" "$SVG_FILE" 2>&1 | grep -E "✗|Error" | sed 's/^/ /' || true
115
+ fi
116
+ fi
117
+ done
118
+ done
119
+
120
+ # Print summary
121
+ echo ""
122
+ echo "========================================"
123
+ echo -e "${BLUE}Test Summary${NC}"
124
+ echo "----------------------------------------"
125
+ echo "Total tests: $TOTAL"
126
+ echo -e "${GREEN}Passed: $PASSED${NC}"
127
+ echo -e "${RED}Failed: $FAILED${NC}"
128
+
129
+ if [ "$FAILED" -eq 0 ]; then
130
+ echo -e "\n${GREEN}✓ All tests passed!${NC}"
131
+ exit 0
132
+ else
133
+ echo -e "\n${RED}✗ Some tests failed${NC}"
134
+ exit 1
135
+ fi
@@ -0,0 +1,292 @@
1
+ #!/bin/bash
2
+ # SVG Validation Script
3
+ # Checks SVG syntax and reports detailed errors
4
+
5
+ set -euo pipefail
6
+
7
+ # Colors for output
8
+ RED='\033[0;31m'
9
+ GREEN='\033[0;32m'
10
+ YELLOW='\033[1;33m'
11
+ NC='\033[0m' # No Color
12
+
13
+ if [ $# -eq 0 ]; then
14
+ echo "Usage: $0 <svg-file>"
15
+ exit 1
16
+ fi
17
+
18
+ SVG_FILE="$1"
19
+
20
+ if [ ! -f "$SVG_FILE" ]; then
21
+ echo -e "${RED}Error: File not found: $SVG_FILE${NC}"
22
+ exit 1
23
+ fi
24
+
25
+ echo "Validating SVG: $SVG_FILE"
26
+ echo "----------------------------------------"
27
+
28
+ FAILURES=0
29
+
30
+ # Check 0: XML syntax
31
+ echo -n "Checking XML syntax... "
32
+ if command -v xmllint &> /dev/null; then
33
+ if xmllint --noout "$SVG_FILE" 2>/dev/null; then
34
+ echo -e "${GREEN}✓ Pass${NC}"
35
+ else
36
+ echo -e "${RED}✗ Fail${NC}"
37
+ xmllint --noout "$SVG_FILE" 2>&1 || true
38
+ FAILURES=$((FAILURES + 1))
39
+ fi
40
+ else
41
+ echo -e "${YELLOW}⚠ Skipped${NC} (xmllint not found)"
42
+ fi
43
+
44
+ # Check 1: Tag balance
45
+ echo -n "Checking tag balance... "
46
+ OPEN_TAGS=$( { grep -o '<[A-Za-z][A-Za-z0-9:-]*' "$SVG_FILE" || true; } | { grep -v '</' || true; } | wc -l | tr -d ' ' )
47
+ SELF_CLOSING=$( { grep -o '/>' "$SVG_FILE" || true; } | wc -l | tr -d ' ' )
48
+ CLOSE_TAGS=$( { grep -o '</[A-Za-z][A-Za-z0-9:-]*>' "$SVG_FILE" || true; } | wc -l | tr -d ' ' )
49
+ TOTAL_CLOSE=$((SELF_CLOSING + CLOSE_TAGS))
50
+
51
+ if [ "$OPEN_TAGS" -eq "$TOTAL_CLOSE" ]; then
52
+ echo -e "${GREEN}✓ Pass${NC} (${OPEN_TAGS} tags)"
53
+ else
54
+ echo -e "${RED}✗ Fail${NC} (${OPEN_TAGS} open, ${TOTAL_CLOSE} close)"
55
+ FAILURES=$((FAILURES + 1))
56
+ fi
57
+
58
+ # Check 2: Quote check
59
+ echo -n "Checking attribute quotes... "
60
+ UNQUOTED=$( { grep -oE '[a-z-]+=[^"'\''> ]' "$SVG_FILE" || true; } | wc -l | tr -d ' ' )
61
+ if [ "$UNQUOTED" -eq 0 ]; then
62
+ echo -e "${GREEN}✓ Pass${NC}"
63
+ else
64
+ echo -e "${RED}✗ Fail${NC} (${UNQUOTED} unquoted attributes)"
65
+ grep -n -oE '[a-z-]+=[^"'\''> ]' "$SVG_FILE" | head -5 || true
66
+ FAILURES=$((FAILURES + 1))
67
+ fi
68
+
69
+ # Check 3: Unescaped entities in text
70
+ echo -n "Checking text entities... "
71
+ SPECIAL=$(python3 - "$SVG_FILE" <<'PY'
72
+ from pathlib import Path
73
+ import re
74
+ import sys
75
+
76
+ text = Path(sys.argv[1]).read_text(encoding='utf-8')
77
+ issues = 0
78
+ for chunk in re.findall(r'>([^<]*)<', text, flags=re.S):
79
+ cleaned = re.sub(r'&(amp|lt|gt|quot|apos);', '', chunk)
80
+ if '&' in cleaned:
81
+ issues += 1
82
+ print(issues)
83
+ PY
84
+ )
85
+ if [ "$SPECIAL" -eq 0 ]; then
86
+ echo -e "${GREEN}✓ Pass${NC}"
87
+ else
88
+ echo -e "${YELLOW}⚠ Warning${NC} (${SPECIAL} potential unescaped entities)"
89
+ fi
90
+
91
+ # Check 4: Marker references
92
+ echo -n "Checking marker references... "
93
+ MARKER_REFS=$( { grep -oE 'marker-end="url\(#[^)]+\)"' "$SVG_FILE" || true; } | { grep -oE '#[^)]+' || true; } | tr -d '#' | sort -u )
94
+ MARKER_DEFS=$( { grep -oE '<marker id="[^"]+"' "$SVG_FILE" || true; } | { grep -oE 'id="[^"]+"' || true; } | tr -d 'id="' | sort -u )
95
+
96
+ MISSING=0
97
+ for ref in $MARKER_REFS; do
98
+ if ! echo "$MARKER_DEFS" | grep -q "^${ref}$"; then
99
+ echo -e "${RED}✗ Missing marker: $ref${NC}"
100
+ MISSING=$((MISSING + 1))
101
+ fi
102
+ done
103
+
104
+ if [ "$MISSING" -eq 0 ]; then
105
+ echo -e "${GREEN}✓ Pass${NC}"
106
+ else
107
+ echo -e "${RED}✗ Fail${NC} (${MISSING} missing markers)"
108
+ FAILURES=$((FAILURES + 1))
109
+ fi
110
+
111
+ # Check 5: Arrow-component collision
112
+ echo -n "Checking arrow collisions... "
113
+ COLLISIONS=$(python3 - "$SVG_FILE" <<'PY'
114
+ from pathlib import Path
115
+ import re
116
+ import sys
117
+ import xml.etree.ElementTree as ET
118
+
119
+ SVG_NS = {'svg': 'http://www.w3.org/2000/svg'}
120
+
121
+ def strip(tag):
122
+ return tag.split('}', 1)[-1]
123
+
124
+ def to_float(value, default=0.0):
125
+ try:
126
+ return float(value)
127
+ except (TypeError, ValueError):
128
+ return default
129
+
130
+ def is_container_rect(el):
131
+ if el.get('stroke-dasharray'):
132
+ return True
133
+ width = to_float(el.get('width'))
134
+ height = to_float(el.get('height'))
135
+ if width > 700 or height > 500:
136
+ return True
137
+ if width < 70 or height < 30:
138
+ return True
139
+ return False
140
+
141
+ def shape_bounds(el):
142
+ tag = strip(el.tag)
143
+ if tag == 'rect':
144
+ if is_container_rect(el):
145
+ return None
146
+ x = to_float(el.get('x'))
147
+ y = to_float(el.get('y'))
148
+ w = to_float(el.get('width'))
149
+ h = to_float(el.get('height'))
150
+ return (x, y, x + w, y + h)
151
+ if tag == 'circle':
152
+ r = to_float(el.get('r'))
153
+ if r < 20:
154
+ return None
155
+ cx = to_float(el.get('cx'))
156
+ cy = to_float(el.get('cy'))
157
+ return (cx - r, cy - r, cx + r, cy + r)
158
+ if tag == 'ellipse':
159
+ rx = to_float(el.get('rx'))
160
+ ry = to_float(el.get('ry'))
161
+ if rx < 20 or ry < 20:
162
+ return None
163
+ cx = to_float(el.get('cx'))
164
+ cy = to_float(el.get('cy'))
165
+ return (cx - rx, cy - ry, cx + rx, cy + ry)
166
+ return None
167
+
168
+ def parse_path_points(d):
169
+ tokens = re.findall(r'[ML]|-?\d+(?:\.\d+)?', d or '')
170
+ if not tokens:
171
+ return []
172
+ points = []
173
+ command = None
174
+ index = 0
175
+ while index < len(tokens):
176
+ token = tokens[index]
177
+ if token in {'M', 'L'}:
178
+ command = token
179
+ index += 1
180
+ continue
181
+ if command not in {'M', 'L'} or index + 1 >= len(tokens):
182
+ return []
183
+ x = float(tokens[index])
184
+ y = float(tokens[index + 1])
185
+ points.append((x, y))
186
+ index += 2
187
+ return points
188
+
189
+ def segment_hits_bounds(p1, p2, bounds):
190
+ x1, y1 = p1
191
+ x2, y2 = p2
192
+ left, top, right, bottom = bounds
193
+ eps = 1e-6
194
+
195
+ if abs(y1 - y2) < eps:
196
+ y = y1
197
+ if not (top + eps < y < bottom - eps):
198
+ return False
199
+ seg_left = min(x1, x2)
200
+ seg_right = max(x1, x2)
201
+ overlap_left = max(seg_left, left)
202
+ overlap_right = min(seg_right, right)
203
+ if overlap_right - overlap_left <= eps:
204
+ return False
205
+ if abs(overlap_left - x1) < eps or abs(overlap_right - x2) < eps:
206
+ return False
207
+ if abs(overlap_left - x2) < eps or abs(overlap_right - x1) < eps:
208
+ return False
209
+ return True
210
+
211
+ if abs(x1 - x2) < eps:
212
+ x = x1
213
+ if not (left + eps < x < right - eps):
214
+ return False
215
+ seg_top = min(y1, y2)
216
+ seg_bottom = max(y1, y2)
217
+ overlap_top = max(seg_top, top)
218
+ overlap_bottom = min(seg_bottom, bottom)
219
+ if overlap_bottom - overlap_top <= eps:
220
+ return False
221
+ if abs(overlap_top - y1) < eps or abs(overlap_bottom - y2) < eps:
222
+ return False
223
+ if abs(overlap_top - y2) < eps or abs(overlap_bottom - y1) < eps:
224
+ return False
225
+ return True
226
+
227
+ return False
228
+
229
+ root = ET.fromstring(Path(sys.argv[1]).read_text(encoding='utf-8'))
230
+ obstacles = [bounds for element in root.iter() if (bounds := shape_bounds(element)) is not None]
231
+
232
+ collisions = 0
233
+ for element in root.iter():
234
+ tag = strip(element.tag)
235
+ if tag == 'line' and element.get('marker-end'):
236
+ points = [
237
+ (to_float(element.get('x1')), to_float(element.get('y1'))),
238
+ (to_float(element.get('x2')), to_float(element.get('y2'))),
239
+ ]
240
+ elif tag == 'path' and element.get('marker-end'):
241
+ points = parse_path_points(element.get('d'))
242
+ else:
243
+ continue
244
+
245
+ for p1, p2 in zip(points, points[1:]):
246
+ if any(segment_hits_bounds(p1, p2, bounds) for bounds in obstacles):
247
+ collisions += 1
248
+ break
249
+
250
+ print(collisions)
251
+ PY
252
+ )
253
+ if [ "$COLLISIONS" -eq 0 ]; then
254
+ echo -e "${GREEN}✓ Pass${NC}"
255
+ else
256
+ echo -e "${RED}✗ Fail${NC} (${COLLISIONS} arrow path collision(s))"
257
+ FAILURES=$((FAILURES + 1))
258
+ fi
259
+
260
+ # Check 6: Closing </svg> tag
261
+ echo -n "Checking closing tag... "
262
+ if grep -q '</svg>' "$SVG_FILE"; then
263
+ echo -e "${GREEN}✓ Pass${NC}"
264
+ else
265
+ echo -e "${RED}✗ Fail${NC} (missing </svg>)"
266
+ FAILURES=$((FAILURES + 1))
267
+ fi
268
+
269
+ # Check 7: rsvg-convert validation
270
+ echo -n "Running rsvg-convert validation... "
271
+ if command -v rsvg-convert &> /dev/null; then
272
+ if rsvg-convert "$SVG_FILE" -o /tmp/test-output.png 2>/dev/null; then
273
+ echo -e "${GREEN}✓ Pass${NC}"
274
+ rm -f /tmp/test-output.png
275
+ else
276
+ echo -e "${RED}✗ Fail${NC}"
277
+ echo "rsvg-convert error:"
278
+ rsvg-convert "$SVG_FILE" -o /tmp/test-output.png 2>&1 || true
279
+ FAILURES=$((FAILURES + 1))
280
+ fi
281
+ else
282
+ echo -e "${YELLOW}⚠ Skipped${NC} (rsvg-convert not found)"
283
+ fi
284
+
285
+ echo "----------------------------------------"
286
+ if [ "$FAILURES" -eq 0 ]; then
287
+ echo "Validation complete"
288
+ exit 0
289
+ fi
290
+
291
+ echo -e "${RED}Validation failed (${FAILURES} error(s))${NC}"
292
+ exit 1
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ <marker id="arrowPurple" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
7
+ <polygon points="0 0, 10 3.5, 0 7" fill="#7c3aed"/>
8
+ </marker>
9
+ <marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
10
+ <polygon points="0 0, 10 3.5, 0 7" fill="#059669"/>
11
+ </marker>
12
+ <marker id="arrowOrange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
13
+ <polygon points="0 0, 10 3.5, 0 7" fill="#ea580c"/>
14
+ </marker>
15
+ </defs>
16
+ <style>
17
+ text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
18
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
19
+ .node-label { font-size: 16px; font-weight: 600; fill: #1e293b; }
20
+ .sub-label { font-size: 13px; font-weight: 400; fill: #64748b; }
21
+ .arrow-label { font-size: 12px; font-weight: 400; fill: #475569; }
22
+ </style>
23
+ <rect width="960" height="700" fill="#ffffff"/>
24
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
25
+ <!-- NODES -->
26
+ <!-- ARROWS -->
27
+ <!-- LEGEND -->
28
+ </svg>
@@ -0,0 +1,23 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ <marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
7
+ <polygon points="0 0, 10 3.5, 0 7" fill="#059669"/>
8
+ </marker>
9
+ </defs>
10
+ <style>
11
+ text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
12
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
13
+ .layer-label { font-size: 16px; font-weight: 600; fill: #475569; }
14
+ .node-label { font-size: 16px; font-weight: 600; fill: #1e293b; }
15
+ .sub-label { font-size: 13px; font-weight: 400; fill: #64748b; }
16
+ .arrow-label { font-size: 12px; font-weight: 400; fill: #475569; }
17
+ </style>
18
+ <rect width="960" height="700" fill="#ffffff"/>
19
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
20
+ <!-- NODES -->
21
+ <!-- ARROWS -->
22
+ <!-- LEGEND -->
23
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <style>
3
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
4
+ .title { font-size: 24px; font-weifill: #1e293b; }
5
+ .header { font-size: 14px; font-weight: 600; fill: #1e293b; }
6
+ .row-label { font-size: 13px; font-weight: 500; fill: #475569; }
7
+ .cell-text { font-size: 13px; font-weight: 400; fill: #1e293b; }
8
+ </style>
9
+ <rect width="960" height="700" fill="#ffffff"/>
10
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
11
+ <!-- HEADERS -->
12
+ <!-- ROWS -->
13
+ <!-- CELLS -->
14
+ </svg>
@@ -0,0 +1,28 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ <marker id="arrowPurple" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
7
+ <polygon points="0 0, 10 3.5, 0 7" fill="#7c3aed"/>
8
+ </marker>
9
+ <marker id="arrowGreen" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
10
+ <polygon points="0 0, 10 3.5, 0 7" fill="#059669"/>
11
+ </marker>
12
+ <marker id="arrowOrange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
13
+ <polygon points="0 0, 10 3.5, 0 7" fill="#ea580c"/>
14
+ </marker>
15
+ </defs>
16
+ <style>
17
+ text { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
18
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
19
+ .node-label { font-size: 16px; font-weight: 600; fill: #1e293b; }
20
+ .sub-label { font-size: 13px; font-weight: 400; fill: #64748b; }
21
+ .arrow-label { font-size: 12px; font-weight: 400; fill: #475569; }
22
+ </style>
23
+ <rect width="960" height="700" fill="#ffffff"/>
24
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
25
+ <!-- NODES -->
26
+ <!-- ARROWS -->
27
+ <!-- LEGEND -->
28
+ </svg>
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ </defs>
7
+ <style>
8
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
9
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
10
+ .entity-name { font-size: 15px; font-weight: 700; fill: #1e293b; }
11
+ .attribute { font-size: 12px; font-weight: 400; fill: #475569; }
12
+ .primary-key { font-size: 12px; font-weight: 600; fill: #1e293b; text-decoration: underline; }
13
+ .relationship { font-size: 12px; font-weight: 500; fill: #64748b; }
14
+ .cardinality { font-size: 11px; font-weight: 400; fill: #64748b; }
15
+ </style>
16
+ <rect width="960" height="700" fill="#ffffff"/>
17
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
18
+ <!-- ENTITIES -->
19
+ <!-- RELATIONSHIPS -->
20
+ <!-- CARDINALITY -->
21
+ </svg>
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ </defs>
7
+ <style>
8
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
9
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
10
+ .node-label { font-size: 14px; font-weight: 500; fill: #1e293b; }
11
+ .decision-label { font-size: 13px; font-weight: 500; fill: #1e293b; }
12
+ .arrow-label { font-size: 11px; font-weight: 400; fill: #475569; }
13
+ </style>
14
+ <rect width="960" height="700" fill="#ffffff"/>
15
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
16
+ <!-- START -->
17
+ <!-- PROCESSES -->
18
+ <!-- DECISIONS -->
19
+ <!-- ARROWS -->
20
+ <!-- END -->
21
+ </svg>
@@ -0,0 +1,20 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 800">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ </defs>
7
+ <style>
8
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
9
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
10
+ .participant { font-size: 14px; font-weight: 600; fill: #1e293b; }
11
+ .message { font-size: 12px; font-weight: 400; fill: #475569; }
12
+ .lifeline { stroke: #cbd5e1; stroke-width: 1.5; stroke-dasharray: 5,3; }
13
+ </style>
14
+ <rect width="960" height="800" fill="#ffffff"/>
15
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
16
+ <!-- PARTICIPANTS -->
17
+ <!-- LIFELINES -->
18
+ <!-- MESSAGES -->
19
+ <!-- ACTIVATIONS -->
20
+ </svg>
@@ -0,0 +1,20 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ </defs>
7
+ <style>
8
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
9
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
10
+ .state-name { font-size: 14px; font-weight: 600; fill: #1e293b; }
11
+ .state-activity { font-size: 11px; font-weight: 400; fill: #64748b; }
12
+ . { font-size: 11px; font-weight: 400; fill: #475569; }
13
+ </style>
14
+ <rect width="960" height="700" fill="#ffffff"/>
15
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
16
+ <!-- INITIAL_STATE -->
17
+ <!-- STATES -->
18
+ <!-- TRANSITIONS -->
19
+ <!-- FINAL_STATE -->
20
+ </svg>
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 400">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ </defs>
7
+ <style>
8
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
9
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
10
+ .period-label { font-size: 12px; font-weight: 500; fill: #475569; }
11
+ .task-label { font-size: 13px; font-weight: 500; fill: #1e293b; }
12
+ .milestone-label { font-size: 12px; font-weight: 600; fill: #1e293b; }
13
+ </style>
14
+ <rect width="1200" height="400" fill="#ffffff"/>
15
+ <text x="600" y="50" text-anchor="middle" class="title">{{TITLE}}</text>
16
+ <!-- TIME_AXIS -->
17
+ <!-- TASKS -->
18
+ <!-- MILESTONES -->
19
+ </svg>
@@ -0,0 +1,21 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 700">
2
+ <defs>
3
+ <marker id="arrowBlue" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
4
+ <polygon points="0 0, 10 3.5, 0 7" fill="#2563eb"/>
5
+ </marker>
6
+ </defs>
7
+ <style>
8
+ text { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
9
+ .title { font-size: 24px; font-weight: 700; fill: #1e293b; }
10
+ .actor-label { font-size: 13px; font-weight: 600; fill: #1e293b; }
11
+ .usecaseel { font-size: 13px; font-weight: 500; fill: #1e293b; }
12
+ .system-label { font-size: 16px; font-weight: 600; fill: #475569; }
13
+ .relationship { font-size: 11px; font-weight: 400; fill: #64748b; font-style: italic; }
14
+ </style>
15
+ <rect width="960" height="700" fill="#ffffff"/>
16
+ <text x="480" y="60" text-anchor="middle" class="title">{{TITLE}}</text>
17
+ <!-- SYSTEM_BOUNDARY -->
18
+ <!-- ACTORS -->
19
+ <!-- USECASES -->
20
+ <!-- RELATIONSHIPS -->
21
+ </svg>