archtracker-mcp 0.4.3 → 0.5.0

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.
package/README.md CHANGED
@@ -16,6 +16,7 @@
16
16
  <p align="center">
17
17
  <a href="#quick-start">Quick Start</a> &bull;
18
18
  <a href="#features">Features</a> &bull;
19
+ <a href="#multi-layer-architecture">Multi-Layer</a> &bull;
19
20
  <a href="#web-viewer">Web Viewer</a> &bull;
20
21
  <a href="#mcp-tools">MCP Tools</a> &bull;
21
22
  <a href="#cli-commands">CLI</a> &bull;
@@ -34,17 +35,19 @@ When AI agents modify code, they **miss cascading impacts**:
34
35
  | File renamed during refactor | AI references stale paths next session | `context` command gives current valid paths |
35
36
  | New dependency added | No visibility into coupling increase | Diff report flags the architectural change |
36
37
  | PR review | Manual dependency tracing | CI auto-checks for architecture drift |
38
+ | Multi-service project | No cross-boundary visibility | Layer-aware analysis with cross-layer link detection |
37
39
 
38
40
  **archtracker-mcp** provides dependency analysis, snapshot diffing, impact simulation, and interactive visualization — all accessible via MCP tools, CLI, web UI, or Claude Code Skills.
39
41
 
40
42
  ## Features
41
43
 
42
44
  - **Dependency Graph Analysis** — Regex-based static analysis for **13 languages** (JS/TS, Python, Rust, Go, Java, C/C++, C#, Ruby, PHP, Swift, Kotlin, Dart, Scala)
43
- - **Interactive Web Viewer** — Force-directed graph, hierarchy diagram, diff view with D3.js
45
+ - **Multi-Layer Architecture** — Analyze multiple services/layers as a unified graph with cross-layer connection detection (NEW in v0.5.0)
46
+ - **Interactive Web Viewer** — Force-directed graph with convex hull layer grouping, hierarchy diagram, diff view with D3.js
44
47
  - **Impact Simulation** — Click any file to visualize transitive dependents (BFS traversal)
45
48
  - **Snapshot Diffing** — Save architecture snapshots and detect drift over time
46
49
  - **MCP Server** — 5 tools for Claude Code / AI agents via Model Context Protocol
47
- - **Claude Code Skills** — 5 slash commands (`/arch-check`, `/arch-snapshot`, etc.)
50
+ - **Claude Code Skills** — 6 slash commands (`/arch-check`, `/arch-snapshot`, `/arch-serve`, etc.)
48
51
  - **CI Integration** — `--ci` mode + auto-generated GitHub Actions workflow
49
52
  - **Bilingual** — Full English/Japanese support (auto-detected from `LANG` env)
50
53
  - **Dark/Light Theme** — Settings persist via localStorage
@@ -83,6 +86,72 @@ archtracker serve --target src --watch
83
86
  archtracker check --target src
84
87
  ```
85
88
 
89
+ ## Multi-Layer Architecture
90
+
91
+ For projects with multiple services or layers (e.g. frontend + backend + shared libraries), archtracker can analyze them as a unified graph.
92
+
93
+ ### Setup
94
+
95
+ Create `.archtracker/layers.json` in your project root:
96
+
97
+ ```json
98
+ {
99
+ "version": "1.0",
100
+ "layers": [
101
+ {
102
+ "name": "Frontend",
103
+ "targetDir": "frontend/src",
104
+ "language": "javascript",
105
+ "color": "#58a6ff",
106
+ "description": "React Web App"
107
+ },
108
+ {
109
+ "name": "Backend",
110
+ "targetDir": "backend/app",
111
+ "language": "python",
112
+ "color": "#3fb950",
113
+ "description": "FastAPI Server"
114
+ }
115
+ ],
116
+ "connections": [
117
+ {
118
+ "fromLayer": "Frontend",
119
+ "fromFile": "api/client.ts",
120
+ "toLayer": "Backend",
121
+ "toFile": "main.py",
122
+ "type": "api-call",
123
+ "label": "REST API"
124
+ }
125
+ ]
126
+ }
127
+ ```
128
+
129
+ Or generate a template:
130
+
131
+ ```bash
132
+ archtracker layers init
133
+ ```
134
+
135
+ ### Usage
136
+
137
+ When `layers.json` exists, all commands automatically use multi-layer mode:
138
+
139
+ ```bash
140
+ archtracker analyze --root . # Analyzes all layers
141
+ archtracker serve --root . --watch # Web viewer with layer tabs and convex hulls
142
+ archtracker check --root . # Cross-layer diff check
143
+ ```
144
+
145
+ Each layer is analyzed independently with its own language setting, then merged into a unified graph with prefixed paths (e.g. `Backend/worker.py`).
146
+
147
+ ### Web Viewer with Layers
148
+
149
+ - **Layer tabs**: Multi-select toggle to focus on specific layers (Shift+click for solo mode)
150
+ - **Convex hulls**: Each layer is visually grouped with a colored boundary
151
+ - **Cross-layer links**: Dashed lines showing connections between layers (toggleable in settings)
152
+ - **Layer Cohesion slider**: Adjust how tightly nodes cluster within their layer
153
+ - **Diff highlighting**: Layer boundaries are highlighted when they contain changed files
154
+
86
155
  ## Web Viewer
87
156
 
88
157
  The interactive web viewer provides three visualization modes:
@@ -93,8 +162,8 @@ The interactive web viewer provides three visualization modes:
93
162
 
94
163
  - Drag, zoom, and click nodes to explore dependencies
95
164
  - Click a node to **pin** its highlight — hover other nodes to compare
96
- - Filter by directory with bottom pills
97
- - Adjust gravity, node size, font size, link opacity
165
+ - Filter by directory with bottom pills, by layer with top tabs
166
+ - Adjust gravity, layer cohesion, node size, font size, link opacity
98
167
  - **Impact mode**: click any file to see all transitively affected files
99
168
 
100
169
  ![Impact Simulation](docs/screenshots/impact-simulation.png)
@@ -105,7 +174,7 @@ The interactive web viewer provides three visualization modes:
105
174
 
106
175
  - Layered top-down layout showing dependency depth
107
176
  - Click-to-pin highlighting with detail panel
108
- - Directory-based color coding with legend
177
+ - Layer-aware filtering with compact relayout
109
178
 
110
179
  ### Diff View
111
180
 
@@ -113,6 +182,7 @@ The interactive web viewer provides three visualization modes:
113
182
 
114
183
  - Color-coded visualization of architecture changes
115
184
  - Green = added, Red = removed, Yellow = modified, Blue = affected
185
+ - Layer grouping with highlighted boundaries for changed layers
116
186
  - Available when a snapshot exists for comparison
117
187
 
118
188
  ```bash
@@ -137,12 +207,15 @@ Add archtracker as an MCP server for Claude Code or any MCP-compatible AI agent:
137
207
 
138
208
  | Tool | Description |
139
209
  |------|-------------|
140
- | `generate_map` | Analyze dependency graph and return structured JSON |
210
+ | `generate_map` | Analyze dependency graph and return raw JSON (for programmatic use) |
211
+ | `analyze_existing_architecture` | Comprehensive human-readable analysis report |
141
212
  | `save_architecture_snapshot` | Save snapshot to `.archtracker/snapshot.json` |
142
213
  | `check_architecture_diff` | Compare snapshot with current code, show impacts |
143
214
  | `get_current_context` | Get valid file paths and architecture summary |
144
215
  | `search_architecture` | Search by path, impact, criticality, or orphans |
145
216
 
217
+ All tools auto-detect multi-layer projects when `.archtracker/layers.json` exists.
218
+
146
219
  ## CLI Commands
147
220
 
148
221
  ```
@@ -152,6 +225,8 @@ archtracker check [options] Compare snapshot with current code
152
225
  archtracker context [options] Show architecture context (for AI sessions)
153
226
  archtracker serve [options] Launch interactive web viewer
154
227
  archtracker ci-setup [options] Generate GitHub Actions workflow
228
+ archtracker layers init Create template layers.json
229
+ archtracker layers list List configured layers
155
230
 
156
231
  Options:
157
232
  -t, --target <dir> Target directory (default: "src")
@@ -167,6 +242,8 @@ Options:
167
242
  --lang <locale> Language: en | ja (auto-detected from LANG)
168
243
  ```
169
244
 
245
+ > **Multi-layer note**: When `.archtracker/layers.json` exists and `--target` is not explicitly set, all commands automatically use multi-layer analysis. Use `--root` to specify the project root.
246
+
170
247
  ## Claude Code Skills
171
248
 
172
249
  Copy the `skills/` directory to your project:
@@ -182,12 +259,16 @@ cp -r node_modules/archtracker-mcp/skills/ .claude/skills/
182
259
  | `/arch-snapshot` | Save current architecture snapshot |
183
260
  | `/arch-context` | Initialize AI session with valid paths |
184
261
  | `/arch-search` | Search architecture (path, impact, critical, orphan) |
262
+ | `/arch-serve` | Launch interactive web viewer in browser |
263
+
264
+ All skills support multi-layer projects automatically.
185
265
 
186
266
  ## Programmatic API
187
267
 
188
268
  ```typescript
189
269
  import {
190
270
  analyzeProject,
271
+ analyzeMultiLayer,
191
272
  saveSnapshot,
192
273
  loadSnapshot,
193
274
  computeDiff,
@@ -195,9 +276,16 @@ import {
195
276
  formatAnalysisReport,
196
277
  } from "archtracker-mcp";
197
278
 
198
- // Analyze
279
+ // Single-directory analysis
199
280
  const graph = await analyzeProject("src", { exclude: ["__tests__"] });
200
281
 
282
+ // Multi-layer analysis
283
+ const layers = [
284
+ { name: "Frontend", targetDir: "frontend/src", language: "javascript" },
285
+ { name: "Backend", targetDir: "backend/app", language: "python" },
286
+ ];
287
+ const multi = await analyzeMultiLayer(".", layers);
288
+
201
289
  // Snapshot
202
290
  const snapshot = await saveSnapshot(".", graph);
203
291
 
@@ -284,17 +372,19 @@ AI エージェントがコードを修正する際、**波及的な影響を見
284
372
  | リファクタでファイル名変更 | 次のセッションで古いパスを参照 | `context` コマンドで現在の有効パスを取得 |
285
373
  | 新しい依存関係を追加 | 結合度の増加が見えない | 差分レポートがアーキテクチャ変更を検出 |
286
374
  | PRレビュー | 手動で依存関係を追跡 | CIが自動でアーキテクチャドリフトをチェック |
375
+ | マルチサービス構成 | サービス境界を跨ぐ影響が見えない | レイヤー対応分析でクロスレイヤー接続を検出 |
287
376
 
288
377
  **archtracker-mcp** は依存関係分析、スナップショット差分、影響シミュレーション、インタラクティブな可視化を提供します。MCP ツール、CLI、Web UI、Claude Code Skills からアクセス可能です。
289
378
 
290
379
  ## 機能
291
380
 
292
381
  - **依存関係グラフ分析** — 正規表現ベースの静的解析、**13言語**対応(JS/TS, Python, Rust, Go, Java, C/C++, C#, Ruby, PHP, Swift, Kotlin, Dart, Scala)
293
- - **インタラクティブ Web ビューア** D3.js による力学モデルグラフ、階層図、差分ビュー
382
+ - **マルチレイヤーアーキテクチャ**複数サービス/レイヤーを統合グラフとして分析、クロスレイヤー接続の自動検出(v0.5.0 新機能)
383
+ - **インタラクティブ Web ビューア** — D3.js による力学モデルグラフ(凸包レイヤーグループ表示)、階層図、差分ビュー
294
384
  - **影響シミュレーション** — ファイルをクリックして推移的な被依存ファイルを可視化(BFS探索)
295
385
  - **スナップショット差分** — アーキテクチャスナップショットを保存し、ドリフトを検出
296
386
  - **MCP サーバー** — Model Context Protocol 経由で5つのツールを提供
297
- - **Claude Code Skills** — 5つのスラッシュコマンド(`/arch-check`、`/arch-snapshot` 等)
387
+ - **Claude Code Skills** — 6つのスラッシュコマンド(`/arch-check`、`/arch-snapshot`、`/arch-serve` 等)
298
388
  - **CI 統合** — `--ci` モード + GitHub Actions ワークフロー自動生成
299
389
  - **多言語対応** — 日本語・英語完全対応(`LANG` 環境変数から自動検出)
300
390
  - **ダーク/ライトテーマ** — localStorage で設定を永続化
@@ -333,6 +423,72 @@ archtracker serve --target src --watch
333
423
  archtracker check --target src
334
424
  ```
335
425
 
426
+ ## マルチレイヤーアーキテクチャ
427
+
428
+ フロントエンド + バックエンド + 共有ライブラリなど、複数のサービスやレイヤーを持つプロジェクトを統合的に分析できます。
429
+
430
+ ### セットアップ
431
+
432
+ プロジェクトルートに `.archtracker/layers.json` を作成:
433
+
434
+ ```json
435
+ {
436
+ "version": "1.0",
437
+ "layers": [
438
+ {
439
+ "name": "Frontend",
440
+ "targetDir": "frontend/src",
441
+ "language": "javascript",
442
+ "color": "#58a6ff",
443
+ "description": "React Web App"
444
+ },
445
+ {
446
+ "name": "Backend",
447
+ "targetDir": "backend/app",
448
+ "language": "python",
449
+ "color": "#3fb950",
450
+ "description": "FastAPI Server"
451
+ }
452
+ ],
453
+ "connections": [
454
+ {
455
+ "fromLayer": "Frontend",
456
+ "fromFile": "api/client.ts",
457
+ "toLayer": "Backend",
458
+ "toFile": "main.py",
459
+ "type": "api-call",
460
+ "label": "REST API"
461
+ }
462
+ ]
463
+ }
464
+ ```
465
+
466
+ テンプレートの自動生成:
467
+
468
+ ```bash
469
+ archtracker layers init
470
+ ```
471
+
472
+ ### 使い方
473
+
474
+ `layers.json` が存在する場合、全コマンドが自動的にマルチレイヤーモードで動作します:
475
+
476
+ ```bash
477
+ archtracker analyze --root . # 全レイヤーを分析
478
+ archtracker serve --root . --watch # レイヤータブ・凸包表示付き Web ビューア
479
+ archtracker check --root . # クロスレイヤー差分チェック
480
+ ```
481
+
482
+ 各レイヤーは独立した言語設定で個別に分析され、プレフィックス付きパス(例: `Backend/worker.py`)で統合グラフにマージされます。
483
+
484
+ ### Web ビューアでのレイヤー表示
485
+
486
+ - **レイヤータブ**: 複数選択トグルで特定レイヤーにフォーカス(Shift+クリックでソロモード)
487
+ - **凸包グループ**: 各レイヤーが色付きの境界で視覚的にグループ化
488
+ - **クロスレイヤーリンク**: レイヤー間接続を点線で表示(設定で切替可能)
489
+ - **Layer Cohesion スライダー**: レイヤー内ノードの凝集度を調整
490
+ - **差分ハイライト**: 変更を含むレイヤーの境界がハイライト
491
+
336
492
  ## Web ビューア
337
493
 
338
494
  インタラクティブな Web ビューアは3つの可視化モードを提供します:
@@ -343,8 +499,8 @@ archtracker check --target src
343
499
 
344
500
  - ドラッグ、ズーム、クリックでノードの依存関係を探索
345
501
  - ノードをクリックでハイライトを**ピン固定** — 他のノードをホバーして比較
346
- - 下部のピルでディレクトリごとにフィルタリング
347
- - 重力、ノードサイズ、フォントサイズ、リンク透明度を調整可能
502
+ - 下部のピルでディレクトリごと、上部のタブでレイヤーごとにフィルタリング
503
+ - 重力、レイヤー凝集力、ノードサイズ、フォントサイズ、リンク透明度を調整可能
348
504
  - **影響モード**: ファイルをクリックして推移的に影響を受ける全ファイルを表示
349
505
 
350
506
  ![影響シミュレーション](docs/screenshots/impact-simulation.png)
@@ -355,7 +511,7 @@ archtracker check --target src
355
511
 
356
512
  - 依存の深さを示すレイヤー型トップダウンレイアウト
357
513
  - クリックでピン固定 + 詳細パネル
358
- - ディレクトリベースの色分け + 凡例
514
+ - レイヤー対応フィルタリング + コンパクト再配置
359
515
 
360
516
  ### 差分ビュー
361
517
 
@@ -363,6 +519,7 @@ archtracker check --target src
363
519
 
364
520
  - アーキテクチャ変更の色分け可視化
365
521
  - 緑=追加、赤=削除、黄=変更、青=影響
522
+ - 変更を含むレイヤー境界のハイライト表示
366
523
  - スナップショットが存在する場合に利用可能
367
524
 
368
525
  ```bash
@@ -387,12 +544,15 @@ archtracker を MCP サーバーとして Claude Code や MCP 互換 AI エー
387
544
 
388
545
  | ツール | 説明 |
389
546
  |--------|------|
390
- | `generate_map` | 依存関係グラフを解析し構造化JSONで返す |
547
+ | `generate_map` | 依存関係グラフを解析し構造化JSONで返す(プログラム用) |
548
+ | `analyze_existing_architecture` | 包括的な人間向け分析レポート |
391
549
  | `save_architecture_snapshot` | `.archtracker/snapshot.json` にスナップショットを保存 |
392
550
  | `check_architecture_diff` | スナップショットと現在のコードを比較し影響を表示 |
393
551
  | `get_current_context` | 有効なファイルパスとアーキテクチャサマリーを取得 |
394
552
  | `search_architecture` | パス、影響範囲、重要度、孤立ファイルで検索 |
395
553
 
554
+ `.archtracker/layers.json` が存在する場合、全ツールがマルチレイヤーモードを自動検出します。
555
+
396
556
  ## CLI コマンド
397
557
 
398
558
  ```
@@ -402,6 +562,8 @@ archtracker check [options] スナップショットと現在のコード
402
562
  archtracker context [options] アーキテクチャコンテキストを表示(AIセッション用)
403
563
  archtracker serve [options] インタラクティブ Web ビューアを起動
404
564
  archtracker ci-setup [options] GitHub Actions ワークフローを生成
565
+ archtracker layers init テンプレート layers.json を作成
566
+ archtracker layers list 設定済みレイヤーを一覧表示
405
567
 
406
568
  オプション:
407
569
  -t, --target <dir> 対象ディレクトリ(デフォルト: "src")
@@ -417,6 +579,8 @@ archtracker ci-setup [options] GitHub Actions ワークフローを生成
417
579
  --lang <locale> 言語: en | ja(LANG から自動検出)
418
580
  ```
419
581
 
582
+ > **マルチレイヤー**: `.archtracker/layers.json` が存在し `--target` が明示指定されていない場合、全コマンドが自動的にマルチレイヤー分析を使用します。`--root` でプロジェクトルートを指定してください。
583
+
420
584
  ## Claude Code Skills
421
585
 
422
586
  `skills/` ディレクトリをプロジェクトにコピー:
@@ -432,12 +596,16 @@ cp -r node_modules/archtracker-mcp/skills/ .claude/skills/
432
596
  | `/arch-snapshot` | 現在のアーキテクチャスナップショットを保存 |
433
597
  | `/arch-context` | 有効なファイルパスでAIセッションを初期化 |
434
598
  | `/arch-search` | アーキテクチャ検索(パス、影響、重要度、孤立) |
599
+ | `/arch-serve` | インタラクティブ Web ビューアを起動 |
600
+
601
+ 全スキルがマルチレイヤープロジェクトに自動対応します。
435
602
 
436
603
  ## プログラマティック API
437
604
 
438
605
  ```typescript
439
606
  import {
440
607
  analyzeProject,
608
+ analyzeMultiLayer,
441
609
  saveSnapshot,
442
610
  loadSnapshot,
443
611
  computeDiff,
@@ -445,9 +613,16 @@ import {
445
613
  formatAnalysisReport,
446
614
  } from "archtracker-mcp";
447
615
 
448
- // 分析
616
+ // 単一ディレクトリ分析
449
617
  const graph = await analyzeProject("src", { exclude: ["__tests__"] });
450
618
 
619
+ // マルチレイヤー分析
620
+ const layers = [
621
+ { name: "Frontend", targetDir: "frontend/src", language: "javascript" },
622
+ { name: "Backend", targetDir: "backend/app", language: "python" },
623
+ ];
624
+ const multi = await analyzeMultiLayer(".", layers);
625
+
451
626
  // スナップショット
452
627
  const snapshot = await saveSnapshot(".", graph);
453
628
 
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/bin.ts
4
- var CLI_COMMANDS = ["init", "analyze", "check", "context", "serve", "ci-setup", "help"];
4
+ var CLI_COMMANDS = ["init", "analyze", "check", "context", "serve", "ci-setup", "layers", "help"];
5
5
  var CLI_FLAGS = ["--help", "-h", "--version", "-V"];
6
6
  var args = process.argv.slice(2);
7
7
  var hasCommand = args.some((arg) => CLI_COMMANDS.includes(arg));
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin.ts"],"sourcesContent":["/**\n * Smart entry point for `archtracker-mcp` binary.\n *\n * - If CLI subcommands are detected (serve, analyze, init, etc.) → run CLI\n * - Otherwise → start MCP server on stdio\n *\n * This allows both:\n * npx archtracker-mcp → MCP server\n * npx archtracker-mcp serve --target src → Web viewer (CLI mode)\n * npx archtracker-mcp analyze --target src → Analysis report (CLI mode)\n */\n\nconst CLI_COMMANDS = [\"init\", \"analyze\", \"check\", \"context\", \"serve\", \"ci-setup\", \"help\"];\nconst CLI_FLAGS = [\"--help\", \"-h\", \"--version\", \"-V\"];\n\nconst args = process.argv.slice(2);\nconst hasCommand = args.some((arg) => CLI_COMMANDS.includes(arg));\nconst hasFlag = args.some((arg) => CLI_FLAGS.includes(arg));\n\nif (hasCommand || hasFlag) {\n await import(\"./cli/index.js\");\n} else {\n await import(\"./mcp/index.js\");\n}\n\nexport {};\n"],"mappings":";;;AAYA,IAAM,eAAe,CAAC,QAAQ,WAAW,SAAS,WAAW,SAAS,YAAY,MAAM;AACxF,IAAM,YAAY,CAAC,UAAU,MAAM,aAAa,IAAI;AAEpD,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,aAAa,KAAK,KAAK,CAAC,QAAQ,aAAa,SAAS,GAAG,CAAC;AAChE,IAAM,UAAU,KAAK,KAAK,CAAC,QAAQ,UAAU,SAAS,GAAG,CAAC;AAE1D,IAAI,cAAc,SAAS;AACzB,QAAM,OAAO,gBAAgB;AAC/B,OAAO;AACL,QAAM,OAAO,gBAAgB;AAC/B;","names":[]}
1
+ {"version":3,"sources":["../src/bin.ts"],"sourcesContent":["/**\n * Smart entry point for `archtracker-mcp` binary.\n *\n * - If CLI subcommands are detected (serve, analyze, init, etc.) → run CLI\n * - Otherwise → start MCP server on stdio\n *\n * This allows both:\n * npx archtracker-mcp → MCP server\n * npx archtracker-mcp serve --target src → Web viewer (CLI mode)\n * npx archtracker-mcp analyze --target src → Analysis report (CLI mode)\n */\n\nconst CLI_COMMANDS = [\"init\", \"analyze\", \"check\", \"context\", \"serve\", \"ci-setup\", \"layers\", \"help\"];\nconst CLI_FLAGS = [\"--help\", \"-h\", \"--version\", \"-V\"];\n\nconst args = process.argv.slice(2);\nconst hasCommand = args.some((arg) => CLI_COMMANDS.includes(arg));\nconst hasFlag = args.some((arg) => CLI_FLAGS.includes(arg));\n\nif (hasCommand || hasFlag) {\n await import(\"./cli/index.js\");\n} else {\n await import(\"./mcp/index.js\");\n}\n\nexport {};\n"],"mappings":";;;AAYA,IAAM,eAAe,CAAC,QAAQ,WAAW,SAAS,WAAW,SAAS,YAAY,UAAU,MAAM;AAClG,IAAM,YAAY,CAAC,UAAU,MAAM,aAAa,IAAI;AAEpD,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,aAAa,KAAK,KAAK,CAAC,QAAQ,aAAa,SAAS,GAAG,CAAC;AAChE,IAAM,UAAU,KAAK,KAAK,CAAC,QAAQ,UAAU,SAAS,GAAG,CAAC;AAE1D,IAAI,cAAc,SAAS;AACzB,QAAM,OAAO,gBAAgB;AAC/B,OAAO;AACL,QAAM,OAAO,gBAAgB;AAC/B;","names":[]}