archrip 0.1.11 → 0.2.1

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.
@@ -1,4 +1,4 @@
1
- import type { ArchNodeData, UseCase } from '../types.ts';
1
+ import type { ArchNodeData, UseCase, MetadataEntry } from '../types.ts';
2
2
  import { getCategoryColors, getCategoryLabel, isGroupNode } from '../types.ts';
3
3
 
4
4
  interface DetailPanelProps {
@@ -287,6 +287,13 @@ export function DetailPanel({ data, useCases, onClose, onUseCaseClick }: DetailP
287
287
  </Section>
288
288
  )}
289
289
 
290
+ {/* Metadata */}
291
+ {data.metadata && data.metadata.length > 0 && data.metadata.map((entry, i) => (
292
+ <Section key={i} title={entry.label}>
293
+ <MetadataValue entry={entry} />
294
+ </Section>
295
+ ))}
296
+
290
297
  {/* Use Cases */}
291
298
  {data.useCases.length > 0 && (
292
299
  <Section title="Use Cases">
@@ -337,3 +344,58 @@ function methodColor(method: string): string {
337
344
  default: return '';
338
345
  }
339
346
  }
347
+
348
+ function isSafeUrl(url: string): boolean {
349
+ try {
350
+ const parsed = new URL(url);
351
+ return parsed.protocol === 'http:' || parsed.protocol === 'https:';
352
+ } catch {
353
+ return false;
354
+ }
355
+ }
356
+
357
+ function MetadataValue({ entry }: { entry: MetadataEntry }) {
358
+ const type = entry.type ?? 'text';
359
+
360
+ if (type === 'code') {
361
+ return (
362
+ <pre
363
+ className="p-2 rounded text-xs overflow-x-auto whitespace-pre-wrap"
364
+ style={{ background: 'var(--color-surface-secondary)', color: 'var(--color-content-secondary)' }}
365
+ >
366
+ {String(entry.value)}
367
+ </pre>
368
+ );
369
+ }
370
+
371
+ if (type === 'link') {
372
+ const url = String(entry.value);
373
+ if (!isSafeUrl(url)) {
374
+ return <span style={{ color: 'var(--color-content-secondary)' }}>{url}</span>;
375
+ }
376
+ return (
377
+ <a
378
+ href={url}
379
+ target="_blank"
380
+ rel="noopener noreferrer"
381
+ className="underline break-all text-xs"
382
+ style={{ color: 'var(--color-interactive-primary)' }}
383
+ >
384
+ {url}
385
+ </a>
386
+ );
387
+ }
388
+
389
+ if (type === 'list' && Array.isArray(entry.value)) {
390
+ return (
391
+ <ul className="text-xs space-y-0.5 list-disc list-inside" style={{ color: 'var(--color-content-secondary)' }}>
392
+ {entry.value.map((item, i) => (
393
+ <li key={i}>{item}</li>
394
+ ))}
395
+ </ul>
396
+ );
397
+ }
398
+
399
+ // text (default)
400
+ return <p style={{ color: 'var(--color-content-secondary)' }}>{String(entry.value)}</p>;
401
+ }
@@ -1,5 +1,5 @@
1
1
  import type { Edge } from '@xyflow/react';
2
- import type { ArchFlowNode, ArchNodeData, UseCase, TableSchema, DepthLevel } from '../types.ts';
2
+ import type { ArchFlowNode, ArchNodeData, UseCase, TableSchema, DepthLevel, MetadataEntry } from '../types.ts';
3
3
  import { computeDepths } from '../types.ts';
4
4
 
5
5
  interface RawArchData {
@@ -34,6 +34,7 @@ interface RawNode {
34
34
  externalService?: string;
35
35
  sqlExamples?: string[];
36
36
  depth?: number;
37
+ metadata?: MetadataEntry[];
37
38
  }
38
39
 
39
40
  interface RawEdge {
@@ -41,6 +42,8 @@ interface RawEdge {
41
42
  target: string;
42
43
  label?: string | null;
43
44
  type?: string;
45
+ description?: string;
46
+ metadata?: MetadataEntry[];
44
47
  }
45
48
 
46
49
  interface RawUseCase {
@@ -118,6 +121,7 @@ export async function loadArchitecture(): Promise<LoadedArchitecture> {
118
121
  implements: n.implements,
119
122
  externalService: n.externalService,
120
123
  sqlExamples: n.sqlExamples,
124
+ metadata: n.metadata,
121
125
  };
122
126
 
123
127
  return {
@@ -136,6 +140,7 @@ export async function loadArchitecture(): Promise<LoadedArchitecture> {
136
140
  label: e.label ?? undefined,
137
141
  style: { stroke: 'var(--color-edge-stroke)', strokeWidth: 1.5 },
138
142
  type: 'smoothstep',
143
+ data: { description: e.description, metadata: e.metadata },
139
144
  }));
140
145
 
141
146
  // Convert use cases
@@ -119,6 +119,13 @@ export interface TableSchema {
119
119
  enumValues?: Record<string, Record<string, string>>;
120
120
  }
121
121
 
122
+ // Keep in sync with packages/cli/src/utils/validate.ts (MetadataEntry)
123
+ export interface MetadataEntry {
124
+ label: string;
125
+ value: string | string[];
126
+ type?: 'text' | 'code' | 'link' | 'list';
127
+ }
128
+
122
129
  export interface MemberNodeSummary {
123
130
  id: string;
124
131
  label: string;
@@ -143,6 +150,7 @@ export interface ArchNodeData {
143
150
  routes?: string[];
144
151
  implements?: string;
145
152
  externalService?: string;
153
+ metadata?: MetadataEntry[];
146
154
  isGroup?: boolean;
147
155
  memberCount?: number;
148
156
  memberNodes?: MemberNodeSummary[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archrip",
3
- "version": "0.1.11",
3
+ "version": "0.2.1",
4
4
  "description": "Generate interactive architecture diagrams from your codebase using AI agents",
5
5
  "type": "module",
6
6
  "bin": {