@psnext/lscg 0.1.2 → 0.1.4

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 (48) hide show
  1. package/README.md +69 -3
  2. package/dist/src/cli.js +68 -13
  3. package/dist/src/graph/repository.d.ts +4 -1
  4. package/dist/src/graph/repository.js +106 -6
  5. package/dist/src/index.d.ts +3 -0
  6. package/dist/src/index.js +2 -0
  7. package/dist/src/mcp/server.js +2 -2
  8. package/dist/src/scanner/discover.js +0 -2
  9. package/dist/src/scanner/packagePlugin.d.ts +3 -0
  10. package/dist/src/scanner/packagePlugin.js +168 -0
  11. package/dist/src/scanner/plugins.d.ts +86 -0
  12. package/dist/src/scanner/plugins.js +503 -0
  13. package/dist/src/storage/connection.d.ts +6 -0
  14. package/dist/src/storage/connection.js +133 -0
  15. package/dist/src/storage/context-queries.d.ts +20 -0
  16. package/dist/src/storage/context-queries.js +137 -0
  17. package/dist/src/storage/database.d.ts +12 -71
  18. package/dist/src/storage/database.js +12 -562
  19. package/dist/src/storage/graph-writes.d.ts +17 -0
  20. package/dist/src/storage/graph-writes.js +126 -0
  21. package/dist/src/storage/plugin-contributions.d.ts +15 -0
  22. package/dist/src/storage/plugin-contributions.js +28 -0
  23. package/dist/src/storage/plugin-graph.d.ts +6 -0
  24. package/dist/src/storage/plugin-graph.js +81 -0
  25. package/dist/src/storage/queries.d.ts +25 -0
  26. package/dist/src/storage/queries.js +129 -0
  27. package/dist/src/storage/row-decoders.d.ts +8 -0
  28. package/dist/src/storage/row-decoders.js +37 -0
  29. package/dist/src/storage/schema.d.ts +2 -2
  30. package/dist/src/storage/schema.js +13 -2
  31. package/dist/src/storage/traversal-queries.d.ts +15 -0
  32. package/dist/src/storage/traversal-queries.js +87 -0
  33. package/dist/src/types.d.ts +10 -4
  34. package/dist/src/view/index.d.ts +1 -1
  35. package/dist/src/view/index.js +2 -2
  36. package/dist/src/view/model.d.ts +2 -0
  37. package/dist/src/view/render.d.ts +5 -2
  38. package/dist/src/view/render.js +81 -13
  39. package/dist/src/view/templates/icons/call.svg +13 -0
  40. package/dist/src/view/templates/icons/export.svg +1 -0
  41. package/dist/src/view/templates/icons/file.svg +9 -0
  42. package/dist/src/view/templates/icons/import.svg +1 -0
  43. package/dist/src/view/templates/icons/package.svg +1 -0
  44. package/dist/src/view/templates/icons/symbol.svg +7 -0
  45. package/dist/src/view/templates/icons/user.svg +15 -0
  46. package/dist/src/view/templates/interactive.css +17 -11
  47. package/dist/src/view/templates/interactive.html +236 -52
  48. package/package.json +1 -1
@@ -21,7 +21,7 @@ export interface ViewRunDependencies {
21
21
  }
22
22
  export declare function viewGraph(options?: ViewCommandOptions, dependencies?: ViewRunDependencies): Promise<ViewRunResult>;
23
23
  export { buildViewModel, loadViewSnapshot } from './model.js';
24
- export type { ViewSnapshot, ViewNode, ViewEdge, ViewBox, ViewModel } from './model.js';
24
+ export type { DisplayMode, ViewSnapshot, ViewNode, ViewEdge, ViewBox, ViewModel } from './model.js';
25
25
  export { renderInteractiveHtml, renderSvgMarkup, writeSvgSnapshot } from './render.js';
26
26
  export { openHtmlArtifactInBrowser, openInDefaultBrowser, writeTemporaryHtmlArtifact } from './open.js';
27
27
  //# sourceMappingURL=index.d.ts.map
@@ -7,7 +7,7 @@ export async function viewGraph(options = {}, dependencies = {}) {
7
7
  const snapshot = loadViewSnapshot(options);
8
8
  const model = buildViewModel(snapshot, options);
9
9
  if (options.output) {
10
- const svg = renderSvgMarkup(model, { includeHiddenNodes: false, interactive: false });
10
+ const svg = renderSvgMarkup(model, { includeHiddenNodes: false, interactive: false, display: options.display });
11
11
  mkdirSync(path.dirname(options.output), { recursive: true });
12
12
  writeSvgSnapshot(options.output, svg);
13
13
  return {
@@ -21,7 +21,7 @@ export async function viewGraph(options = {}, dependencies = {}) {
21
21
  edgeCount: model.edges.length
22
22
  };
23
23
  }
24
- const html = renderInteractiveHtml(model);
24
+ const html = renderInteractiveHtml(model, { display: options.display });
25
25
  const opened = openHtmlArtifactInBrowser(html, dependencies.opener);
26
26
  return {
27
27
  mode: 'interactive',
@@ -43,11 +43,13 @@ export interface ViewModel extends ViewSnapshot {
43
43
  graphBounds: LayoutBounds;
44
44
  startWithFullGraph: boolean;
45
45
  }
46
+ export type DisplayMode = 'simple' | 'shape' | 'icon';
46
47
  export interface ViewModelOptions {
47
48
  root?: string | undefined;
48
49
  scope?: StorageScope | 'both' | undefined;
49
50
  anchor?: string | undefined;
50
51
  search?: string | undefined;
52
+ display?: DisplayMode | undefined;
51
53
  }
52
54
  export declare function loadViewSnapshot({ root, scope }?: ViewModelOptions): ViewSnapshot;
53
55
  export declare function buildViewModel(snapshot: ViewSnapshot, { anchor, search }?: ViewModelOptions): ViewModel;
@@ -1,9 +1,12 @@
1
- import type { ViewModel } from './model.js';
1
+ import type { DisplayMode, ViewModel } from './model.js';
2
2
  export interface RenderSvgOptions {
3
3
  includeHiddenNodes?: boolean | undefined;
4
4
  interactive?: boolean | undefined;
5
+ display?: DisplayMode | undefined;
5
6
  }
6
7
  export declare function renderSvgMarkup(model: ViewModel, options?: RenderSvgOptions): string;
7
- export declare function renderInteractiveHtml(model: ViewModel): string;
8
+ export declare function renderInteractiveHtml(model: ViewModel, options?: {
9
+ display?: DisplayMode | undefined;
10
+ }): string;
8
11
  export declare function writeSvgSnapshot(filePath: string, svgMarkup: string): void;
9
12
  //# sourceMappingURL=render.d.ts.map
@@ -15,6 +15,8 @@ export function renderSvgMarkup(model, options = {}) {
15
15
  const graphLabel = `${model.repository.name} store graph`;
16
16
  const title = options.includeHiddenNodes ? `${graphLabel} · full graph` : graphLabel;
17
17
  const mode = options.interactive ? 'interactive' : 'snapshot';
18
+ const display = options.display ?? 'shape';
19
+ const icons = display === 'icon' ? loadIconAssets() : null;
18
20
  const renderedEdges = edges
19
21
  .map((edge) => {
20
22
  const source = nodes.find((node) => node.id === edge.sourceId);
@@ -28,10 +30,10 @@ export function renderSvgMarkup(model, options = {}) {
28
30
  const renderedNodes = nodes
29
31
  .map((node) => {
30
32
  const presentation = nodePresentation(node);
31
- const labelY = node.kind === 'file' ? 0 : presentation.height / 2 + 14;
33
+ const labelY = display === 'shape' && node.kind === 'file' ? 0 : presentation.height / 2 + 14;
32
34
  return `
33
35
  <g class="node node--${escapeHtml(node.kind)}" data-node-id="${escapeHtml(node.id)}" data-node-kind="${escapeHtml(node.kind)}" data-node-shape="${escapeHtml(presentation.shape)}" transform="translate(${formatNumber(node.x)},${formatNumber(node.y)})">
34
- ${renderNodeShapeMarkup(node, presentation)}
36
+ ${renderNodeShapeMarkup(node, presentation, display, icons)}
35
37
  <text class="node-label" text-anchor="middle" dominant-baseline="${node.kind === 'file' ? 'middle' : 'hanging'}" y="${formatNumber(labelY)}">${escapeHtml(node.label)}</text>
36
38
  <title>${escapeHtml(node.label)} (${escapeHtml(node.id)})</title>
37
39
  </g>`;
@@ -70,8 +72,8 @@ export function renderSvgMarkup(model, options = {}) {
70
72
  }
71
73
  const interactiveHtmlTemplate = loadTemplateAsset('interactive.html');
72
74
  const interactiveCss = loadTemplateAsset('interactive.css');
73
- export function renderInteractiveHtml(model) {
74
- const data = serializeInteractiveGraph(model);
75
+ export function renderInteractiveHtml(model, options = {}) {
76
+ const data = serializeInteractiveGraph(model, options.display ?? 'shape');
75
77
  const graphTitle = `${model.repository.name} store graph`;
76
78
  const subtitle = model.anchorNodeId
77
79
  ? `Anchored on ${model.nodes.find((node) => node.id === model.anchorNodeId)?.label ?? model.anchorNodeId}`
@@ -103,8 +105,19 @@ export function writeSvgSnapshot(filePath, svgMarkup) {
103
105
  mkdirSync(path.dirname(filePath), { recursive: true });
104
106
  writeFileSync(filePath, svgMarkup, 'utf8');
105
107
  }
106
- function serializeInteractiveGraph(model) {
107
- const nodes = model.fullNodes.map((node) => {
108
+ function serializeInteractiveGraph(model, display) {
109
+ const serializedGraph = model.anchorNodeId
110
+ ? downstreamGraph(model.fullNodes, model.fullEdges, model.anchorNodeId)
111
+ : { nodes: model.fullNodes, edges: model.fullEdges };
112
+ const serializedNodeIds = new Set(serializedGraph.nodes.map((node) => node.id));
113
+ const serializedEdgeIds = new Set(serializedGraph.edges.map((edge) => edge.id));
114
+ const neighborhoods = Object.fromEntries(Object.entries(model.fullNeighborhoods)
115
+ .filter(([nodeId]) => serializedNodeIds.has(nodeId))
116
+ .map(([nodeId, neighborhood]) => [nodeId, {
117
+ nodeIds: neighborhood.nodeIds.filter((id) => serializedNodeIds.has(id)),
118
+ edgeIds: neighborhood.edgeIds.filter((id) => serializedEdgeIds.has(id))
119
+ }]));
120
+ const nodes = serializedGraph.nodes.map((node) => {
108
121
  const presentation = nodePresentation(node);
109
122
  return {
110
123
  id: node.id,
@@ -122,7 +135,7 @@ function serializeInteractiveGraph(model) {
122
135
  presentationRadius: presentation.presentationRadius
123
136
  };
124
137
  });
125
- const edges = model.fullEdges.map((edge) => ({
138
+ const edges = serializedGraph.edges.map((edge) => ({
126
139
  id: edge.id,
127
140
  kind: edge.kind,
128
141
  source: edge.sourceId,
@@ -135,12 +148,56 @@ function serializeInteractiveGraph(model) {
135
148
  scope: model.scope,
136
149
  search: model.search,
137
150
  anchorNodeId: model.anchorNodeId,
138
- fullNeighborhoods: model.fullNeighborhoods,
151
+ display,
152
+ icons: loadIconAssets(),
153
+ fullNeighborhoods: neighborhoods,
139
154
  nodes,
140
155
  edges
141
156
  }));
142
157
  }
143
- function renderNodeShapeMarkup(node, presentation) {
158
+ function downstreamGraph(nodes, edges, anchorNodeId) {
159
+ const downstreamByNodeId = new Map();
160
+ for (const edge of edges) {
161
+ const downstream = downstreamByNodeId.get(edge.sourceId) ?? [];
162
+ downstream.push(edge.targetId);
163
+ downstreamByNodeId.set(edge.sourceId, downstream);
164
+ }
165
+ const selectedNodeIds = new Set([anchorNodeId]);
166
+ const queue = [anchorNodeId];
167
+ for (let index = 0; index < queue.length; index += 1) {
168
+ const nodeId = queue[index];
169
+ for (const downstreamNodeId of downstreamByNodeId.get(nodeId) ?? []) {
170
+ if (selectedNodeIds.has(downstreamNodeId))
171
+ continue;
172
+ selectedNodeIds.add(downstreamNodeId);
173
+ queue.push(downstreamNodeId);
174
+ }
175
+ }
176
+ return {
177
+ nodes: nodes.filter((node) => selectedNodeIds.has(node.id)),
178
+ edges: edges.filter((edge) => selectedNodeIds.has(edge.sourceId) && selectedNodeIds.has(edge.targetId))
179
+ };
180
+ }
181
+ const iconKinds = ['file', 'symbol', 'import', 'export', 'call', 'user', 'package'];
182
+ function loadIconAssets() {
183
+ return Object.fromEntries(iconKinds.map((kind) => {
184
+ const source = loadTemplateAsset(`icons/${kind}.svg`);
185
+ const match = source.match(/<svg[^>]*viewBox="([^"]+)"[^>]*>([\s\S]*)<\/svg>/);
186
+ if (!match)
187
+ throw new Error(`Invalid icon asset for ${kind}`);
188
+ return [kind, { viewBox: match[1], markup: match[2] }];
189
+ }));
190
+ }
191
+ function renderNodeShapeMarkup(node, presentation, display, icons) {
192
+ if (display === 'simple') {
193
+ return `<circle class="node-shape node-shape--simple" cx="0" cy="0" r="${formatNumber(Math.min(presentation.width, presentation.height) / 2)}" fill="${colorForKind(node.kind)}" />`;
194
+ }
195
+ if (display === 'icon') {
196
+ const icon = icons?.[node.kind];
197
+ if (!icon)
198
+ throw new Error(`Missing icon asset for ${node.kind}`);
199
+ return `<svg class="node-shape node-shape--icon" x="${formatNumber(-presentation.width / 2)}" y="${formatNumber(-presentation.height / 2)}" width="${formatNumber(presentation.width)}" height="${formatNumber(presentation.height)}" viewBox="${escapeHtml(icon.viewBox)}" color="${colorForKind(node.kind)}" aria-hidden="true">${icon.markup}</svg>`;
200
+ }
144
201
  const fill = colorForKind(node.kind);
145
202
  switch (presentation.shape) {
146
203
  case 'rounded-rect':
@@ -155,6 +212,8 @@ function renderNodeShapeMarkup(node, presentation) {
155
212
  return `<polygon class="node-shape node-shape--hexagon" points="${shapePoints(presentation, 'hexagon')}" fill="${fill}" />`;
156
213
  case 'user':
157
214
  return renderUserNodeShapeMarkup(presentation, fill);
215
+ case 'package':
216
+ return renderPackageNodeShapeMarkup(presentation);
158
217
  default:
159
218
  return `<rect class="node-shape" x="${formatNumber(-presentation.width / 2)}" y="${formatNumber(-presentation.height / 2)}" width="${formatNumber(presentation.width)}" height="${formatNumber(presentation.height)}" rx="6" ry="6" fill="${fill}" />`;
160
219
  }
@@ -173,12 +232,12 @@ function nodePresentation(node) {
173
232
  const shape = shapeForKind(node.kind);
174
233
  const width = node.kind === 'file'
175
234
  ? shapeWidthForKind(node.kind, labelLength)
176
- : node.kind === 'user'
235
+ : node.kind === 'user' || node.kind === 'package'
177
236
  ? 72
178
237
  : 16;
179
238
  const height = node.kind === 'file'
180
239
  ? shapeHeightForKind(node.kind, labelLength)
181
- : node.kind === 'user'
240
+ : node.kind === 'user' || node.kind === 'package'
182
241
  ? 72
183
242
  : 16;
184
243
  const presentationRadius = Math.max(width, height) / 2 + 10;
@@ -204,6 +263,8 @@ function shapeForKind(kind) {
204
263
  return 'hexagon';
205
264
  case 'user':
206
265
  return 'user';
266
+ case 'package':
267
+ return 'hexagon';
207
268
  default:
208
269
  return 'box';
209
270
  }
@@ -226,7 +287,8 @@ function shapeSquareSizeForKind(kind, labelLength) {
226
287
  import: { base: 68, perChar: 7, min: 96, max: 220 },
227
288
  export: { base: 68, perChar: 7, min: 96, max: 220 },
228
289
  call: { base: 68, perChar: 7, min: 96, max: 220 },
229
- user: { base: 68, perChar: 7, min: 72, max: 180 }
290
+ user: { base: 68, perChar: 7, min: 72, max: 180 },
291
+ package: { base: 72, perChar: 7, min: 96, max: 220 }
230
292
  };
231
293
  const spec = sizeByKind[kind];
232
294
  return Math.max(spec.min, Math.min(spec.max, Math.round(spec.base + labelLength * spec.perChar)));
@@ -239,6 +301,9 @@ function expandViewBox(viewBox, padding) {
239
301
  height: viewBox.height + padding * 2
240
302
  };
241
303
  }
304
+ function renderPackageNodeShapeMarkup(presentation) {
305
+ return `<svg class="node-shape node-shape--package" x="${formatNumber(-presentation.width / 2)}" y="${formatNumber(-presentation.height / 2)}" width="${formatNumber(presentation.width)}" height="${formatNumber(presentation.height)}" viewBox="0 0 512 512" aria-hidden="true"><polygon fill="#7E4F1F" points="511.516,107.105 511.788,107.036 264.065,31.004 0.479,106.898 0,106.759 0,411.849 238.676,480.721 238.676,480.159 238.888,480.996 512,412.125 512,107.036"/><polygon fill="#EDA637" points="264.065,31.004 0,107.036 238.676,175.907 511.788,107.036"/><polygon fill="#C27526" points="238.888,480.996 512,412.125 512,107.036 238.888,175.907"/><path fill="#FFEC99" d="M193.016 51.462 78.638 84.393l230.233 73.866v50.416c0 3.323 1.541 6.458 4.172 8.487 2.631 2.029 6.053 2.725 9.268 1.881l99.058-25.986c4.713-1.237 7.999-5.495 7.999-10.369v-54.816L193.016 51.462Z"/><path fill="#FFDC35" d="M486.158 374.572c0 6.29-4.278 11.775-10.378 13.307l-52.647 13.55c-2.779.698-5.736.663-8.41-.367-5.363-2.066-8.677-7.119-8.677-12.576V332.26c0-6.29 4.278-11.775 10.378-13.307l52.647-13.55c2.779-.698 5.736-.663 8.41.367 5.363 2.066 8.677 7.119 8.677 12.576v56.226Z"/><path fill="#FFDC35" d="M429.367 182.689c0 4.872-3.287 9.132-7.999 10.368l-99.058 25.986c-3.214.843-6.637.148-9.268-1.881-2.631-2.029-4.172-5.164-4.172-8.487v-50.416l120.497-30.386v54.816Z"/><path fill="#DF7400" d="m186.692 292.407-40.804-11.978c-5.273-1.548-8.895-6.385-8.895-11.881v-39.76c0-8.263 7.941-14.208 15.87-11.881l40.804 11.978c5.273 1.548 8.895 6.385 8.895 11.881v39.76c0 8.263-7.941 14.208-15.87 11.881Z"/></svg>`;
306
+ }
242
307
  function renderUserNodeShapeMarkup(presentation, fill) {
243
308
  const scale = Math.max(presentation.width, presentation.height) / 24;
244
309
  return `<g class="node-shape node-shape--user" transform="scale(${formatNumber(scale)}) translate(-12,-12)" fill="none" stroke="${fill}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
@@ -261,6 +326,8 @@ function colorForKind(kind) {
261
326
  return '#fb7185';
262
327
  case 'user':
263
328
  return '#14b8a6';
329
+ case 'package':
330
+ return '#f97316';
264
331
  default:
265
332
  return '#94a3b8';
266
333
  }
@@ -296,7 +363,8 @@ function legendItems() {
296
363
  ['import', 'Import'],
297
364
  ['export', 'Export'],
298
365
  ['call', 'Call'],
299
- ['user', 'Contributor']
366
+ ['user', 'Contributor'],
367
+ ['package', 'Package']
300
368
  ];
301
369
  return items
302
370
  .map(([kind, label]) => `
@@ -0,0 +1,13 @@
1
+ <svg viewBox="0 0 48 48" fill="none" stroke="#3a3a3a" xmlns="http://www.w3.org/2000/svg">
2
+ <g id="call_icon" >
3
+ <circle cx="24" cy="24" r="21" fill="#fb7185" stroke="inherit" stroke-width="2"></circle>
4
+ <path d="M37 22.0001L34 25.0001L23 14.0001L26 11.0001C27.5 9.50002 33 7.00005 37 11.0001C41 15.0001 38.5 20.5 37 22.0001Z"
5
+ fill="#fb7185" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
6
+ <path d="M42 6L37 11" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
7
+ <path d="M11 25.9999L14 22.9999L25 33.9999L22 36.9999C20.5 38.5 15 41 11 36.9999C7 32.9999 9.5 27.5 11 25.9999Z"
8
+ fill="#fb7185" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
9
+ <path d="M23 32L27 28" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
10
+ <path d="M6 42L11 37" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
11
+ <path d="M16 25L20 21" stroke="inherit" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
12
+ </g>
13
+ </svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 21V8M7 13l5-5 5 5M5 3h14"/></svg>
@@ -0,0 +1,9 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" >
2
+ <g id="file_icon" fill="#9ed2ff" stroke="#1d97e2" stroke-width="1" stroke-linecap="round" stroke-linejoin="miter">
3
+ <polygon points="14 2 3 2 3 22 21 22 21 9 14 9 14 2" fill="#059cf7" opacity="0.1" stroke-width="0"></polygon>
4
+ <polygon points="3 2 3 22 21 22 21 9 14 2 3 2"></polygon>
5
+ <polyline points="20.6 9 14 9 14 2.4" stroke-linecap="round"></polyline>
6
+ <line x1="16" y1="13" x2="8" y2="13"></line><line x1="10" y1="9" x2="8" y2="9"></line>
7
+ <line x1="16" y1="17" x2="8" y2="17"></line>
8
+ </g>
9
+ </svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v13M7 11l5 5 5-5M5 21h14"/></svg>
@@ -0,0 +1 @@
1
+ <svg viewBox="0 0 512 512"><polygon fill="#7E4F1F" points="511.516,107.105 511.788,107.036 264.065,31.004 0.479,106.898 0,106.759 0,411.849 238.676,480.721 238.676,480.159 238.888,480.996 512,412.125 512,107.036"/><polygon fill="#EDA637" points="264.065,31.004 0,107.036 238.676,175.907 511.788,107.036"/><polygon fill="#C27526" points="238.888,480.996 512,412.125 512,107.036 238.888,175.907"/><path fill="#FFEC99" d="M193.016 51.462 78.638 84.393l230.233 73.866v50.416c0 3.323 1.541 6.458 4.172 8.487 2.631 2.029 6.053 2.725 9.268 1.881l99.058-25.986c4.713-1.237 7.999-5.495 7.999-10.369v-54.816L193.016 51.462Z"/><path fill="#FFDC35" d="M486.158 374.572c0 6.29-4.278 11.775-10.378 13.307l-52.647 13.55c-2.779.698-5.736.663-8.41-.367-5.363-2.066-8.677-7.119-8.677-12.576V332.26c0-6.29 4.278-11.775 10.378-13.307l52.647-13.55c2.779-.698 5.736-.663 8.41.367 5.363 2.066 8.677 7.119 8.677 12.576v56.226Z"/><path fill="#FFDC35" d="M429.367 182.689c0 4.872-3.287 9.132-7.999 10.368l-99.058 25.986c-3.214.843-6.637.148-9.268-1.881-2.631-2.029-4.172-5.164-4.172-8.487v-50.416l120.497-30.386v54.816Z"/><path fill="#DF7400" d="m186.692 292.407-40.804-11.978c-5.273-1.548-8.895-6.385-8.895-11.881v-39.76c0-8.263 7.941-14.208 15.87-11.881l40.804 11.978c5.273 1.548 8.895 6.385 8.895 11.881v39.76c0 8.263-7.941 14.208-15.87 11.881Z"/></svg>
@@ -0,0 +1,7 @@
1
+ <svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" preserveAspectRatio="xMidYMid meet">
2
+ <g id="symbol_icon" fill="none" fill-rule="evenodd">
3
+ <path fill="#d5c007" d="M17 36a1.99 1.99 0 0 1-1.414-.586l-11-11A2 2 0 0 1 4 23V2A2 2 0 0 1 7.414.586L17 10.171L26.586.586A1.998 1.998 0 0 1 30 2v21a2 2 0 0 1-.586 1.414l-11 11A1.99 1.99 0 0 1 17 36z"></path>
4
+ <path fill="#47DED4" d="M17 13L28 2v21L17 34z"></path>
5
+ <path fill="#FFFF87" d="M6 2l11 11v21L6 23z"></path>
6
+ </g>
7
+ </svg>
@@ -0,0 +1,15 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" >
2
+ <g id="user_icon" fill="#c7e2f9" stroke="#1995d8"
3
+ stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round">
4
+ <defs>
5
+ <style>.cls-1{fill:#c7e2f9;}.cls-1,.cls-2{fill-rule:evenodd;}.cls-2{fill:#4285f4;}</style>
6
+ </defs>
7
+ <g data-name="Product Icons">
8
+ <g>
9
+ <rect fill="#234cbc" x="6" y="4" width="12" height="16" rx="4"></rect>
10
+ <path class="cls-1" d="M12,2,3.79,5.42v5.63c0,5.06,3.5,9.8,8.21,11,4.71-1.15,8.21-5.89,8.21-10.95V5.42Zm0,3.79a2.63,2.63,0,1,1-1.86.77A2.63,2.63,0,0,1,12,5.79Zm4.11,11.15A8.64,8.64,0,0,1,12,19.87a8.64,8.64,0,0,1-4.11-2.93V14.69c0-1.67,2.74-2.52,4.11-2.52s4.11.85,4.11,2.52v2.25Z"></path>
11
+ <path class="cls-2" d="M12,2V5.79a2.63,2.63,0,1,1,0,5.26v1.12c1.37,0,4.11.85,4.11,2.52v2.25A8.64,8.64,0,0,1,12,19.87V22c4.71-1.15,8.21-5.89,8.21-10.95V5.42Z"></path>
12
+ </g>
13
+ </g>
14
+ </g>
15
+ </svg>
@@ -38,6 +38,7 @@ html, body {
38
38
  border: 1px solid var(--panel-border);
39
39
  border-radius: 16px;
40
40
  background: var(--panel);
41
+ -webkit-backdrop-filter: blur(16px);
41
42
  backdrop-filter: blur(16px);
42
43
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.35);
43
44
  overflow: auto;
@@ -107,7 +108,8 @@ html, body {
107
108
  color: var(--muted);
108
109
  font-size: 13px;
109
110
  }
110
- .hud input {
111
+ .hud input,
112
+ .hud select {
111
113
  width: 100%;
112
114
  box-sizing: border-box;
113
115
  padding: 10px 12px;
@@ -187,23 +189,27 @@ html, body {
187
189
  }
188
190
  .node-label {
189
191
  fill: var(--text);
190
- font-size: 11px;
191
- font-weight: 600;
192
+ font-size: 8px;
193
+ font-weight: 200;
192
194
  paint-order: stroke;
193
195
  stroke: #020617;
194
- stroke-width: 3px;
196
+ stroke-width: 2px;
195
197
  stroke-linejoin: round;
198
+ -webkit-user-select: none;
196
199
  user-select: none;
197
200
  pointer-events: none;
198
201
  }
199
- .node.is-highlighted .node-shape,
200
202
  .node.is-selected .node-shape {
201
- stroke: white;
202
- stroke-width: 2.5;
203
- }
204
- .node.is-hidden,
205
- .edge.is-hidden {
206
- display: none;
203
+ stroke: rgb(255, 255, 255);
204
+ stroke-width: 1;
205
+ filter:
206
+ drop-shadow(0px 0px 12px #00a2ff)
207
+ drop-shadow(0px 0px 24px #00a2ff)
208
+ drop-shadow(0px 0px 36px #00a2ff);
209
+ }
210
+ .node.is-highlighted .node.is-selected .node-shape {
211
+ stroke: rgb(193, 193, 193);
212
+ stroke-width: 2;
207
213
  }
208
214
  .node.is-dimmed {
209
215
  opacity: 0.18;