archrip 0.2.9 → 0.2.11

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 (34) hide show
  1. package/dist/install/slash-commands.d.ts +2 -0
  2. package/dist/install/slash-commands.d.ts.map +1 -1
  3. package/dist/install/slash-commands.js +23 -18
  4. package/dist/install/slash-commands.js.map +1 -1
  5. package/dist/schema/architecture.schema.json +0 -1
  6. package/dist/templates/slash-commands/{claude → shared}/archrip-scan.md +9 -9
  7. package/dist/utils/layout.js +3 -2
  8. package/dist/utils/layout.js.map +1 -1
  9. package/dist/utils/layout.spec.js +28 -0
  10. package/dist/utils/layout.spec.js.map +1 -1
  11. package/dist/utils/validate.d.ts +0 -1
  12. package/dist/utils/validate.d.ts.map +1 -1
  13. package/dist/utils/validate.js +0 -3
  14. package/dist/utils/validate.js.map +1 -1
  15. package/dist/utils/validate.spec.js +0 -27
  16. package/dist/utils/validate.spec.js.map +1 -1
  17. package/dist/viewer-template/package.json +0 -1
  18. package/dist/viewer-template/src/App.tsx +6 -11
  19. package/dist/viewer-template/src/components/DetailPanel.tsx +1 -79
  20. package/dist/viewer-template/src/data/loader.ts +1 -14
  21. package/dist/viewer-template/src/hooks/useArchitecture.ts +1 -3
  22. package/dist/viewer-template/src/hooks/useUseCaseFilter.ts +1 -8
  23. package/dist/viewer-template/src/index.css +6 -0
  24. package/dist/viewer-template/src/types.ts +4 -63
  25. package/package.json +1 -1
  26. package/dist/templates/slash-commands/codex/archrip-scan.md +0 -222
  27. package/dist/templates/slash-commands/codex/archrip-update.md +0 -39
  28. package/dist/templates/slash-commands/gemini/archrip-scan.md +0 -222
  29. package/dist/templates/slash-commands/gemini/archrip-update.md +0 -39
  30. package/dist/viewer-template/src/components/DepthFilter.tsx +0 -43
  31. package/dist/viewer-template/src/components/nodes/GroupNode.tsx +0 -62
  32. package/dist/viewer-template/src/hooks/useDepthFilter.ts +0 -192
  33. package/dist/viewer-template/src/utils/layout.ts +0 -229
  34. /package/dist/templates/slash-commands/{claude → shared}/archrip-update.md +0 -0
@@ -1,229 +0,0 @@
1
- import dagre from '@dagrejs/dagre';
2
-
3
- interface LayoutNode {
4
- id: string;
5
- width: number;
6
- height: number;
7
- layer?: number;
8
- category?: string;
9
- }
10
-
11
- interface LayoutEdge {
12
- source: string;
13
- target: string;
14
- }
15
-
16
- const NODE_WIDTH = 180;
17
- const NODE_HEIGHT = 80;
18
- const GROUP_NODE_WIDTH = 200;
19
- const GROUP_NODE_HEIGHT = 90;
20
- const RANK_SEP = 160;
21
- const NODE_SEP = 40;
22
-
23
- // Concentric layout constants
24
- const RING_SPACING = 250;
25
- const MIN_ARC_SPACING = 200;
26
-
27
- /**
28
- * Compute layout positions for a set of nodes and edges.
29
- * Ported from packages/cli/src/utils/layout.ts for use in the viewer
30
- * when depth-filtered graphs need re-layout after merging.
31
- */
32
- export function computeLayout(
33
- nodes: LayoutNode[],
34
- edges: LayoutEdge[],
35
- layoutType: 'dagre' | 'concentric',
36
- ): Map<string, { x: number; y: number }> {
37
- if (nodes.length === 0) return new Map();
38
-
39
- if (layoutType === 'concentric') {
40
- return computeConcentricLayout(nodes, edges);
41
- }
42
- return computeDagreLayout(nodes, edges);
43
- }
44
-
45
- function computeDagreLayout(
46
- nodes: LayoutNode[],
47
- edges: LayoutEdge[],
48
- ): Map<string, { x: number; y: number }> {
49
- const g = new dagre.graphlib.Graph();
50
- g.setGraph({
51
- rankdir: 'TB',
52
- ranksep: RANK_SEP,
53
- nodesep: NODE_SEP,
54
- marginx: 40,
55
- marginy: 40,
56
- });
57
- g.setDefaultEdgeLabel(() => ({}));
58
-
59
- for (const node of nodes) {
60
- g.setNode(node.id, {
61
- width: node.width,
62
- height: node.height,
63
- rank: node.layer,
64
- });
65
- }
66
-
67
- for (const edge of edges) {
68
- g.setEdge(edge.source, edge.target);
69
- }
70
-
71
- dagre.layout(g);
72
-
73
- const result = new Map<string, { x: number; y: number }>();
74
- for (const nodeId of g.nodes()) {
75
- const n = g.node(nodeId);
76
- if (n) {
77
- const layoutNode = nodes.find((ln) => ln.id === nodeId);
78
- const w = layoutNode?.width ?? NODE_WIDTH;
79
- const h = layoutNode?.height ?? NODE_HEIGHT;
80
- result.set(nodeId, { x: n.x - w / 2, y: n.y - h / 2 });
81
- }
82
- }
83
-
84
- return result;
85
- }
86
-
87
- function buildAdjacencyMap(edges: LayoutEdge[]): Map<string, Set<string>> {
88
- const adj = new Map<string, Set<string>>();
89
- for (const edge of edges) {
90
- let srcSet = adj.get(edge.source);
91
- if (!srcSet) {
92
- srcSet = new Set();
93
- adj.set(edge.source, srcSet);
94
- }
95
- srcSet.add(edge.target);
96
-
97
- let tgtSet = adj.get(edge.target);
98
- if (!tgtSet) {
99
- tgtSet = new Set();
100
- adj.set(edge.target, tgtSet);
101
- }
102
- tgtSet.add(edge.source);
103
- }
104
- return adj;
105
- }
106
-
107
- function circularMean(angles: number[]): number {
108
- let sinSum = 0;
109
- let cosSum = 0;
110
- for (const a of angles) {
111
- sinSum += Math.sin(a);
112
- cosSum += Math.cos(a);
113
- }
114
- return Math.atan2(sinSum / angles.length, cosSum / angles.length);
115
- }
116
-
117
- /**
118
- * Category-based ring priority for concentric layout.
119
- * Lower number = closer to center (domain core).
120
- */
121
- const CATEGORY_RING_PRIORITY: Record<string, number> = {
122
- model: 0,
123
- service: 1,
124
- dto: 2,
125
- port: 3,
126
- controller: 4,
127
- adapter: 5,
128
- database: 6,
129
- job: 7,
130
- external: 8,
131
- };
132
-
133
- const DEFAULT_RING_PRIORITY = 4;
134
-
135
- function computeRingKey(category: string, layer: number): number {
136
- const priority = CATEGORY_RING_PRIORITY[category] ?? DEFAULT_RING_PRIORITY;
137
- return priority * 1000 - layer;
138
- }
139
-
140
- function computeConcentricLayout(
141
- nodes: LayoutNode[],
142
- edges: LayoutEdge[],
143
- ): Map<string, { x: number; y: number }> {
144
- const result = new Map<string, { x: number; y: number }>();
145
-
146
- // Group nodes by ring key (category-aware)
147
- const ringGroups = new Map<number, LayoutNode[]>();
148
- for (const node of nodes) {
149
- const ringKey = computeRingKey(node.category ?? '', node.layer ?? 0);
150
- const group = ringGroups.get(ringKey);
151
- if (group) {
152
- group.push(node);
153
- } else {
154
- ringGroups.set(ringKey, [node]);
155
- }
156
- }
157
-
158
- // Sort ring keys ascending: lowest key = ring 0 (center)
159
- const sortedRingKeys = [...ringGroups.keys()].sort((a, b) => a - b);
160
-
161
- const adjacency = buildAdjacencyMap(edges);
162
- const placedAngles = new Map<string, number>();
163
- let prevRingRadius = 0;
164
-
165
- for (let ringIndex = 0; ringIndex < sortedRingKeys.length; ringIndex++) {
166
- const ringKey = sortedRingKeys[ringIndex]!;
167
- const ringNodes = ringGroups.get(ringKey)!;
168
- const count = ringNodes.length;
169
-
170
- if (ringIndex === 0 && count === 1) {
171
- const node = ringNodes[0]!;
172
- placedAngles.set(node.id, 0);
173
- result.set(node.id, { x: -node.width / 2, y: -node.height / 2 });
174
- continue;
175
- }
176
-
177
- // Compute target angle for each node based on placed neighbors
178
- const withAngle: { node: LayoutNode; targetAngle: number }[] = [];
179
- const withoutAngle: LayoutNode[] = [];
180
-
181
- for (const node of ringNodes) {
182
- const neighbors = adjacency.get(node.id);
183
- if (!neighbors) {
184
- withoutAngle.push(node);
185
- continue;
186
- }
187
-
188
- const placedNeighborAngles: number[] = [];
189
- for (const n of neighbors) {
190
- const angle = placedAngles.get(n);
191
- if (angle !== undefined) {
192
- placedNeighborAngles.push(angle);
193
- }
194
- }
195
-
196
- if (placedNeighborAngles.length === 0) {
197
- withoutAngle.push(node);
198
- } else {
199
- withAngle.push({ node, targetAngle: circularMean(placedNeighborAngles) });
200
- }
201
- }
202
-
203
- withAngle.sort((a, b) => a.targetAngle - b.targetAngle);
204
- const sorted = [...withAngle.map((n) => n.node), ...withoutAngle];
205
-
206
- const baseRadius = Math.max(ringIndex * RING_SPACING, RING_SPACING / 2);
207
- const circumference = count * MIN_ARC_SPACING;
208
- const minRadius = circumference / (2 * Math.PI);
209
- // Ensure monotonically increasing: each ring must be outside the previous one
210
- const ringRadius = Math.max(minRadius, baseRadius, prevRingRadius + RING_SPACING / 2);
211
- prevRingRadius = ringRadius;
212
-
213
- const angleStep = (2 * Math.PI) / count;
214
- for (let i = 0; i < count; i++) {
215
- const angle = i * angleStep - Math.PI / 2;
216
- const node = sorted[i]!;
217
- placedAngles.set(node.id, angle);
218
-
219
- const x = ringRadius * Math.cos(angle);
220
- const y = ringRadius * Math.sin(angle);
221
-
222
- result.set(node.id, { x: x - node.width / 2, y: y - node.height / 2 });
223
- }
224
- }
225
-
226
- return result;
227
- }
228
-
229
- export { NODE_WIDTH, NODE_HEIGHT, GROUP_NODE_WIDTH, GROUP_NODE_HEIGHT };