codesynapt 0.0.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.
Files changed (61) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +686 -0
  3. package/LICENSES.md +141 -0
  4. package/README.md +331 -0
  5. package/electron/main.cjs +2849 -0
  6. package/electron/plugin-loader.cjs +184 -0
  7. package/electron/preload.cjs +108 -0
  8. package/package.json +216 -0
  9. package/packages/core/bin/codesynapt-mcp.cjs +611 -0
  10. package/packages/core/bin/codesynapt.cjs +1933 -0
  11. package/packages/core/legacy.js +300 -0
  12. package/packages/core/lib/control-server.cjs +1539 -0
  13. package/packages/core/lib/embedding.cjs +89 -0
  14. package/packages/core/lib/logger.cjs +63 -0
  15. package/packages/core/lib/search-cache.cjs +140 -0
  16. package/packages/core/lib/search-worker.cjs +255 -0
  17. package/packages/core/lib/search.cjs +211 -0
  18. package/packages/core/lib/symbol-graph.cjs +402 -0
  19. package/packages/core/lib/symbol-parser-js.cjs +542 -0
  20. package/packages/core/lib/symbol-parser-misc.cjs +394 -0
  21. package/packages/core/lib/symbol-parser-py.cjs +215 -0
  22. package/packages/core/lib/symbol-parser-treesitter.cjs +658 -0
  23. package/packages/core/lib/symbol-parser-tsc.cjs +332 -0
  24. package/packages/core/monorepo.js +310 -0
  25. package/packages/core/parser.js +2234 -0
  26. package/packages/core/scanner.js +623 -0
  27. package/plugin-api/LICENSE +21 -0
  28. package/plugin-api/README.md +114 -0
  29. package/plugin-api/docs/01-getting-started.md +197 -0
  30. package/plugin-api/docs/02-concepts.md +269 -0
  31. package/plugin-api/docs/api-reference.md +463 -0
  32. package/plugin-api/docs/troubleshooting.md +332 -0
  33. package/plugin-api/docs/types/exporter.md +377 -0
  34. package/plugin-api/docs/types/theme.md +312 -0
  35. package/plugin-api/examples/hello-world-plugin/README.md +70 -0
  36. package/plugin-api/examples/hello-world-plugin/main.js +36 -0
  37. package/plugin-api/examples/hello-world-plugin/manifest.json +12 -0
  38. package/plugin-api/examples/mermaid-exporter/README.md +125 -0
  39. package/plugin-api/examples/mermaid-exporter/main.js +58 -0
  40. package/plugin-api/examples/mermaid-exporter/manifest.json +12 -0
  41. package/plugin-api/examples/rust-parser/README.md +71 -0
  42. package/plugin-api/examples/rust-parser/main.js +123 -0
  43. package/plugin-api/examples/rust-parser/manifest.json +12 -0
  44. package/plugin-api/examples/sunset-theme/README.md +95 -0
  45. package/plugin-api/examples/sunset-theme/manifest.json +12 -0
  46. package/plugin-api/examples/sunset-theme/theme.css +31 -0
  47. package/plugin-api/package.json +20 -0
  48. package/plugin-api/types.d.ts +395 -0
  49. package/public/app.js +6837 -0
  50. package/public/backend.js +285 -0
  51. package/public/index.html +647 -0
  52. package/public/plugin-host.js +321 -0
  53. package/public/style.css +4359 -0
  54. package/public/vendor/three.module.js +53044 -0
  55. package/scripts/competitor-watch.mjs +144 -0
  56. package/scripts/copy-vendor.js +21 -0
  57. package/scripts/download-bundled-node.cjs +53 -0
  58. package/scripts/fuses-after-pack.cjs +34 -0
  59. package/scripts/license-check.js +119 -0
  60. package/scripts/perf-test.js +200 -0
  61. package/server.js +132 -0
@@ -0,0 +1,647 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' blob: 'sha256-NfHJr+xcDJiAGqHYgFEaR5vX+0YDa2Tbke39iP8L6uY='; img-src 'self' data:; connect-src 'self' ws: wss: blob: http://127.0.0.1:* http://localhost:*; object-src 'none'; base-uri 'self'; frame-ancestors 'none';" />
6
+ <title>CodeSynapt</title>
7
+ <link rel="stylesheet" href="./style.css" />
8
+ </head>
9
+ <body class="no-folder">
10
+ <!-- Top bar -->
11
+ <header id="topbar">
12
+ <div class="drag-region"></div>
13
+ <div class="brand">
14
+ <span class="dot"></span>
15
+ <span class="label">code<span class="accent">synapt</span></span>
16
+ </div>
17
+
18
+ <!-- Group: file ops -->
19
+ <div class="tb-group">
20
+ <button id="openFolderBtn" class="folder-btn" data-i18n-title="topbar.open_folder.title">
21
+ <span class="icon">πŸ“‚</span>
22
+ <span id="pathLabel">Open Folder…</span>
23
+ </button>
24
+ <button id="projectSwitchBtn" class="folder-btn" data-i18n-title="topbar.project_switch.title">
25
+ <span class="icon">β–Ύ</span>
26
+ </button>
27
+ <button id="refreshBtn" class="folder-btn" data-i18n-title="topbar.refresh.title" disabled>
28
+ <span class="icon">↻</span>
29
+ </button>
30
+ </div>
31
+
32
+ <!-- Group: search -->
33
+ <div class="tb-group">
34
+ <div class="search-input-wrap">
35
+ <input id="search" type="text" data-i18n-placeholder="search.placeholder" autocomplete="off" />
36
+ <span id="searchCount" class="search-count"></span>
37
+ </div>
38
+ <button id="searchSyntaxBtn" class="micro-btn" data-i18n-title="search.syntax.title">aA</button>
39
+ <button id="searchModeBtn" class="micro-btn" data-i18n-title="search.mode.title">◐</button>
40
+ </div>
41
+
42
+ <!-- Group: view controls -->
43
+ <div class="tb-group">
44
+ <button id="pause" data-i18n-title="search.pause.title">❚❚</button>
45
+ <button id="recenter" data-i18n-title="search.recenter.title">βŠ•</button>
46
+ </div>
47
+
48
+ <!-- Group: AI tools -->
49
+ <div class="tb-group">
50
+ <button id="changesBtn" data-i18n-title="search.changes.title">πŸ“</button>
51
+ <button id="statsBtn" class="micro-btn" data-i18n-title="search.stats.title">πŸ“Š</button>
52
+ </div>
53
+
54
+ <div id="filterBadges" class="filter-badges"></div>
55
+
56
+ <div class="tb-spacer"></div>
57
+
58
+ <!-- Group: meta + more -->
59
+ <div class="meta">
60
+ <span id="stat-files">β€”</span>
61
+ <span class="sep">Β·</span>
62
+ <span id="stat-edges">β€”</span>
63
+ </div>
64
+ <div class="tb-group">
65
+ <button id="moreBtn" data-i18n-title="search.more.title">β‹―</button>
66
+ </div>
67
+ </header>
68
+
69
+ <canvas id="canvas"></canvas>
70
+
71
+ <!-- View cube β€” small 3D widget showing current viewing angle, syncs with main camera -->
72
+ <canvas id="viewCubeCanvas" width="120" height="120"></canvas>
73
+
74
+
75
+ <!-- More popover β€” opens under the β‹― button -->
76
+ <div id="moreMenu" class="hidden">
77
+ <button id="timelapseBtn" class="more-item" data-i18n-title="search.timelapse.title">
78
+ <span class="more-icon">⏱</span><span class="more-label" data-i18n="more.timelapse">Time-lapse</span>
79
+ </button>
80
+ <button id="packagesBtn" class="more-item" data-i18n-title="search.packages.title">
81
+ <span class="more-icon">πŸ“¦</span><span class="more-label" data-i18n="more.packages">Packages</span>
82
+ </button>
83
+ <button id="legacyBtn" class="more-item" data-i18n-title="search.legacy.title">
84
+ <span class="more-icon">🧹</span><span class="more-label" data-i18n="more.legacy">Legacy audit</span>
85
+ </button>
86
+ <button id="langToggle" class="more-item" data-i18n-title="lang.toggle.title">
87
+ <span class="more-icon" id="langCurrent">Aζ–‡</span><span class="more-label" data-i18n="more.lang">Language</span>
88
+ </button>
89
+ <button id="settingsBtn" class="more-item" data-i18n-title="search.settings.title">
90
+ <span class="more-icon">βš™</span><span class="more-label" data-i18n="more.settings">Settings</span>
91
+ </button>
92
+ </div>
93
+
94
+ <!-- Project switcher popover (anchored under the β–Ύ button) -->
95
+ <div id="projectSwitcher" class="hidden">
96
+ <div class="psw-head">
97
+ <span class="kicker" data-i18n="psw.title">projects</span>
98
+ <button id="pswPinCurrent" class="psw-btn" data-i18n-title="psw.pin_current.title">β˜… +</button>
99
+ <button id="pswClose" class="psw-btn">βœ•</button>
100
+ </div>
101
+ <div id="pswPinnedList" class="psw-section"></div>
102
+ <div class="psw-section-title" data-i18n="psw.recent">recent</div>
103
+ <div id="pswRecentList" class="psw-section"></div>
104
+ <div class="psw-empty hidden" id="pswEmpty" data-i18n="psw.empty">아직 λ“±λ‘λœ ν”„λ‘œμ νŠΈ μ—†μŒ. 폴더 μ—΄κ³  β˜… +둜 μΆ”κ°€</div>
105
+ </div>
106
+
107
+ <!-- AI changes panel β€” files modified this session -->
108
+ <aside id="changes" class="hidden">
109
+ <div class="changes-head">
110
+ <div class="kicker" data-i18n="kicker.ai_work">ai work Β· session changes</div>
111
+ <button id="closeChanges">βœ•</button>
112
+ </div>
113
+ <div id="changesList" class="changes-list"></div>
114
+ </aside>
115
+
116
+
117
+ <!-- Packages panel (monorepo overview) -->
118
+ <aside id="packages" class="hidden">
119
+ <div class="packages-head">
120
+ <div class="kicker" data-i18n="kicker.packages">monorepo Β· packages</div>
121
+ <button id="closePackages">βœ•</button>
122
+ </div>
123
+ <div id="packagesMeta" class="packages-meta">β€”</div>
124
+ <div class="packages-actions">
125
+ <button id="pkgGroupingToggle" class="psw-btn" data-i18n="packages.group_by_package">νŒ¨ν‚€μ§€λ‘œ λ¬ΆκΈ°</button>
126
+ </div>
127
+ <div id="packagesList" class="packages-list"></div>
128
+ <div id="packageDetail" class="package-detail hidden"></div>
129
+ </aside>
130
+
131
+ <!-- Legacy / migration audit panel -->
132
+ <aside id="legacy" class="hidden">
133
+ <div class="legacy-head">
134
+ <div class="kicker" data-i18n="kicker.legacy_audit">cleanup Β· migration audit</div>
135
+ <button id="closeLegacy">βœ•</button>
136
+ </div>
137
+ <div id="legacyMeta" class="legacy-meta">β€”</div>
138
+ <div class="legacy-toolbar">
139
+ <label class="legacy-conf">
140
+ <span data-i18n="legacy.min_conf">min confidence</span>
141
+ <input id="legacyMinConf" type="range" min="0" max="100" value="50">
142
+ <span id="legacyMinConfVal">0.50</span>
143
+ </label>
144
+ <button id="legacyHighlightBtn" class="psw-btn" data-i18n="legacy.highlight">3D ν•˜μ΄λΌμ΄νŠΈ</button>
145
+ </div>
146
+ <div id="legacyTabs" class="legacy-tabs">
147
+ <button data-tab="orphan" class="legacy-tab active" data-i18n="legacy.tab.orphan">orphan</button>
148
+ <button data-tab="path" class="legacy-tab" data-i18n="legacy.tab.path">path</button>
149
+ <button data-tab="filename" class="legacy-tab" data-i18n="legacy.tab.filename">filename</button>
150
+ <button data-tab="duplicate"class="legacy-tab" data-i18n="legacy.tab.duplicate">duplicate</button>
151
+ </div>
152
+ <div id="legacyList" class="legacy-list"></div>
153
+ </aside>
154
+
155
+ <!-- Time-lapse slider overlay -->
156
+ <div id="timelapse" class="hidden">
157
+ <div class="tl-head">
158
+ <span class="kicker" data-i18n="kicker.timelapse">time-lapse</span>
159
+ <span id="tlStamp" class="tl-stamp">β€”</span>
160
+ <button id="tlPlay" class="tl-btn" title="Play">β–Ά</button>
161
+ <button id="tlReset" class="tl-btn" title="Show all">⏏</button>
162
+ <button id="tlClose" class="tl-btn" title="Close">βœ•</button>
163
+ </div>
164
+ <input id="tlSlider" type="range" min="0" max="100" value="100">
165
+ <div id="tlMeta" class="tl-meta">β€” Β· β€” Β· β€”</div>
166
+ </div>
167
+
168
+ <!-- Settings panel -->
169
+ <aside id="settings" class="hidden">
170
+ <div class="settings-head">
171
+ <div class="kicker" data-i18n="kicker.settings">settings</div>
172
+ <button id="closeSettings">βœ•</button>
173
+ </div>
174
+ <div class="settings-body">
175
+ <div class="settings-section" data-i18n="settings.physics.title">physics backend</div>
176
+ <p class="settings-help" data-i18n="settings.physics.help"></p>
177
+ <div class="radio-group" id="backendRadios">
178
+ <label class="radio">
179
+ <input type="radio" name="backend" value="auto" />
180
+ <span class="radio-label">
181
+ <strong data-i18n="settings.physics.auto">Auto</strong>
182
+ <span class="radio-sub" data-i18n="settings.physics.auto.sub"></span>
183
+ </span>
184
+ </label>
185
+ <label class="radio is-disabled" data-i18n-title="settings.physics.gpu.tip">
186
+ <input type="radio" name="backend" value="gpu" disabled />
187
+ <span class="radio-label">
188
+ <strong data-i18n="settings.physics.gpu">GPU only</strong>
189
+ <span class="radio-sub" data-i18n="settings.physics.gpu.sub"></span>
190
+ </span>
191
+ </label>
192
+ <label class="radio">
193
+ <input type="radio" name="backend" value="cpu" />
194
+ <span class="radio-label">
195
+ <strong data-i18n="settings.physics.cpu">CPU only</strong>
196
+ <span class="radio-sub" data-i18n="settings.physics.cpu.sub"></span>
197
+ </span>
198
+ </label>
199
+ </div>
200
+ <div id="backendStatus" class="status-block">
201
+ <div class="status-row"><span class="status-key" data-i18n="settings.physics.active">active</span><span id="statusActive">β€”</span></div>
202
+ <div class="status-row"><span class="status-key" data-i18n="settings.physics.gpu_time">gpu time</span><span id="statusGpuTime">β€”</span></div>
203
+ <div class="status-row"><span class="status-key" data-i18n="settings.physics.status">status</span><span id="statusReason" class="reason">β€”</span></div>
204
+ </div>
205
+
206
+ <div class="settings-section" style="margin-top: 22px;" data-i18n="settings.focus.title">focus propagation</div>
207
+ <p class="settings-help" data-i18n="settings.focus.help"></p>
208
+ <div class="depth-control">
209
+ <label class="depth-input-label">
210
+ <span data-i18n="settings.focus.depth">depth</span>
211
+ <input type="number" id="focusDepthInput" min="1" max="20" step="1" value="3" />
212
+ <span class="depth-hint" data-i18n="settings.focus.hops">hops</span>
213
+ </label>
214
+ <button id="showAllBtn" class="toggle-btn" type="button">
215
+ <span class="toggle-dot"></span>
216
+ <span data-i18n="settings.focus.show_all">Show all connected</span>
217
+ </button>
218
+ </div>
219
+ <div class="depth-legend">
220
+ <div class="depth-row"><span class="depth-swatch" style="opacity:1.0"></span><span data-i18n="settings.focus.legend.selected">selected file</span></div>
221
+ <div class="depth-row"><span class="depth-swatch" style="opacity:0.78"></span><span data-i18n="settings.focus.legend.direct">directly connected</span></div>
222
+ <div class="depth-row"><span class="depth-swatch" style="opacity:0.56"></span><span data-i18n="settings.focus.legend.one">one degree away</span></div>
223
+ <div class="depth-row"><span class="depth-swatch" style="opacity:0.36"></span><span data-i18n="settings.focus.legend.two">two degrees away</span></div>
224
+ <div class="depth-row"><span class="depth-swatch" style="opacity:0.10"></span><span data-i18n="settings.focus.legend.beyond">unrelated / beyond depth</span></div>
225
+ </div>
226
+
227
+ <div class="settings-section" style="margin-top: 22px;" data-i18n="settings.layout.title">layout</div>
228
+ <p class="settings-help" data-i18n="settings.layout.help"></p>
229
+ <button id="folderGroupBtn" class="toggle-btn" type="button">
230
+ <span class="toggle-dot"></span>
231
+ <span data-i18n="settings.layout.cluster">Cluster files by folder</span>
232
+ </button>
233
+
234
+ <div class="slider-row">
235
+ <label class="slider-label">
236
+ <span data-i18n="settings.layout.node_distance">node distance</span>
237
+ <span id="nodeDistanceVal" class="slider-val">1.0Γ—</span>
238
+ </label>
239
+ <input type="range" id="nodeDistanceSlider" min="0.3" max="3" step="0.05" value="1" />
240
+ </div>
241
+ <div class="slider-row">
242
+ <label class="slider-label">
243
+ <span data-i18n="settings.layout.node_size">node size</span>
244
+ <span id="nodeSizeVal" class="slider-val">1.0Γ—</span>
245
+ </label>
246
+ <input type="range" id="nodeSizeSlider" min="0.3" max="3" step="0.05" value="1" />
247
+ </div>
248
+ <div class="slider-row">
249
+ <label class="slider-label">
250
+ <span data-i18n="settings.layout.max_world">max world size</span>
251
+ <span id="maxWorldVal" class="slider-val">200</span>
252
+ </label>
253
+ <input type="range" id="maxWorldSlider" min="60" max="2000" step="20" value="200" />
254
+ </div>
255
+ <div class="slider-row">
256
+ <label class="slider-label">
257
+ <span data-i18n="settings.layout.folder_strength">folder cluster strength</span>
258
+ <span id="folderStrengthVal" class="slider-val">0.30</span>
259
+ </label>
260
+ <input type="range" id="folderStrengthSlider" min="0" max="0.4" step="0.01" value="0.30" />
261
+ </div>
262
+ <div class="slider-row">
263
+ <label class="slider-label">
264
+ <span data-i18n="settings.layout.folder_spread">folder cluster spread</span>
265
+ <span id="folderSpreadVal" class="slider-val">0.85</span>
266
+ </label>
267
+ <input type="range" id="folderSpreadSlider" min="0.3" max="1.0" step="0.05" value="0.85" />
268
+ </div>
269
+ <button id="resetLayoutBtn" class="micro-btn" style="margin-top:6px;" data-i18n="settings.layout.reset">reset to defaults</button>
270
+
271
+ <div class="settings-section" style="margin-top: 22px;" data-i18n="settings.appearance.title">appearance</div>
272
+ <p class="settings-help" data-i18n="settings.appearance.help"></p>
273
+ <div class="theme-grid" id="themeGrid">
274
+ <button class="theme-card" data-theme="observatory" type="button">
275
+ <span class="theme-swatches">
276
+ <span class="theme-sw" style="background:#7ECFCF"></span>
277
+ <span class="theme-sw" style="background:#FFC850"></span>
278
+ <span class="theme-sw" style="background:#E879A6"></span>
279
+ </span>
280
+ <span class="theme-name">Observatory</span>
281
+ <span class="theme-desc">Brutalist + brackets Β· default</span>
282
+ </button>
283
+ <button class="theme-card" data-theme="minimal" type="button">
284
+ <span class="theme-swatches">
285
+ <span class="theme-sw" style="background:#8FB8E0"></span>
286
+ <span class="theme-sw" style="background:#E0B870"></span>
287
+ <span class="theme-sw" style="background:#C088B0"></span>
288
+ </span>
289
+ <span class="theme-name">Minimal</span>
290
+ <span class="theme-desc">Quiet Β· graph-first</span>
291
+ </button>
292
+ <button class="theme-card" data-theme="terminal" type="button">
293
+ <span class="theme-swatches">
294
+ <span class="theme-sw" style="background:#5B9DFF"></span>
295
+ <span class="theme-sw" style="background:#A8A8A8"></span>
296
+ <span class="theme-sw" style="background:#FF6464"></span>
297
+ </span>
298
+ <span class="theme-name">Terminal</span>
299
+ <span class="theme-desc">Monochrome Β· single accent</span>
300
+ </button>
301
+ <button class="theme-card" data-theme="maximal" type="button">
302
+ <span class="theme-swatches">
303
+ <span class="theme-sw" style="background:#FF55BB"></span>
304
+ <span class="theme-sw" style="background:#FFD700"></span>
305
+ <span class="theme-sw" style="background:#66E5FF"></span>
306
+ </span>
307
+ <span class="theme-name">Maximal</span>
308
+ <span class="theme-desc">Expressive Β· vivid</span>
309
+ </button>
310
+ <button class="theme-card" data-theme="carbon" type="button">
311
+ <span class="theme-swatches">
312
+ <span class="theme-sw" style="background:#50DC64"></span>
313
+ <span class="theme-sw" style="background:#FFD24D"></span>
314
+ <span class="theme-sw" style="background:#000000"></span>
315
+ </span>
316
+ <span class="theme-name">Carbon</span>
317
+ <span class="theme-desc">CRT phosphor Β· vim-ish</span>
318
+ </button>
319
+ <button class="theme-card" data-theme="mono" type="button">
320
+ <span class="theme-swatches">
321
+ <span class="theme-sw" style="background:#7AA2F7"></span>
322
+ <span class="theme-sw" style="background:#E0AF68"></span>
323
+ <span class="theme-sw" style="background:#BB9AF7"></span>
324
+ </span>
325
+ <span class="theme-name">Mono</span>
326
+ <span class="theme-desc">Tokyo Night Β· easy on eyes</span>
327
+ </button>
328
+ <button class="theme-card" data-theme="daylight" type="button">
329
+ <span class="theme-swatches">
330
+ <span class="theme-sw" style="background:#0969DA"></span>
331
+ <span class="theme-sw" style="background:#BF8700"></span>
332
+ <span class="theme-sw" style="background:#FFFFFF;border:1px solid rgba(0,0,0,0.1)"></span>
333
+ </span>
334
+ <span class="theme-name">Daylight</span>
335
+ <span class="theme-desc">Light mode Β· clean white</span>
336
+ </button>
337
+ </div>
338
+
339
+ <div class="settings-section" style="margin-top: 22px;" data-i18n="settings.export.title">export</div>
340
+ <p class="settings-help" data-i18n="settings.export.help"></p>
341
+ <div class="export-row">
342
+ <button id="exportPngBtn" class="export-btn" type="button" data-i18n="settings.export.png">πŸ“· PNG screenshot</button>
343
+ <button id="exportJsonBtn" class="export-btn" type="button" data-i18n="settings.export.json">– JSON graph</button>
344
+ <button id="exportCsvBtn" class="export-btn" type="button" data-i18n="settings.export.csv">– CSV edges</button>
345
+ </div>
346
+
347
+ <div class="settings-section" style="margin-top: 22px;" data-i18n="settings.history.title">file history</div>
348
+ <p class="settings-help" data-i18n="history.settings.help"></p>
349
+ <div class="setting-row">
350
+ <label class="setting-toggle">
351
+ <input type="checkbox" id="historyEnabledToggle">
352
+ <span data-i18n="history.settings.toggle"></span>
353
+ </label>
354
+ </div>
355
+
356
+ <div class="settings-section" style="margin-top: 22px;" data-i18n="settings.camera.title">camera presets</div>
357
+ <p class="settings-help" data-i18n="settings.camera.help"></p>
358
+ <div class="preset-row">
359
+ <button class="preset-btn" data-view="default" data-i18n="settings.camera.default">default</button>
360
+ <button class="preset-btn" data-view="top" data-i18n="settings.camera.top">top-down</button>
361
+ <button class="preset-btn" data-view="side" data-i18n="settings.camera.side">side</button>
362
+ </div>
363
+ </div>
364
+ </aside>
365
+
366
+ <!-- Unified left rail: file tree, pipelines, recent, legend
367
+ Each <section> is a `.lp-panel` that can be collapsed (click header)
368
+ and the `.lp-resize` strips between them are draggable vertical grips.
369
+ State persists in localStorage (codesynapt:left-rail). -->
370
+ <!-- Left sidebar with tab strip: files / pipelines / recent / legend.
371
+ Only one tab body is visible at a time. Active tab persists in
372
+ localStorage (codesynapt:left-tab). -->
373
+ <aside id="leftRail">
374
+ <div class="left-tabs" role="tablist">
375
+ <button class="left-tab active" data-tab="files" role="tab" data-i18n="kicker.files">files</button>
376
+ <button class="left-tab" data-tab="pipelines" role="tab" data-i18n="kicker.pipelines">pipelines</button>
377
+ <button class="left-tab" data-tab="recent" role="tab" data-i18n="kicker.recent">recent</button>
378
+ <button class="left-tab" data-tab="legend" role="tab" data-i18n="kicker.legend">extensions</button>
379
+ </div>
380
+ <div class="left-tab-pane" data-pane="files">
381
+ <section id="fileTreePanel">
382
+ <div class="ft-head">
383
+ <span class="kicker" data-i18n="kicker.files">files</span>
384
+ <div class="ft-actions">
385
+ <button id="ftCollapseAll" class="micro-btn" data-i18n-title="ft.collapse_all.title">βŒƒ</button>
386
+ <button id="ftToggle" class="micro-btn" data-i18n-title="ft.hide.title">βˆ’</button>
387
+ </div>
388
+ </div>
389
+ <div id="ftRoot" class="ft-root" title=""></div>
390
+ <div id="fileTreeBody" class="ft-body"></div>
391
+ </section>
392
+ </div>
393
+ <div class="left-tab-pane hidden" data-pane="pipelines">
394
+ <section id="pipelinesPanel">
395
+ <div class="pp-head">
396
+ <span class="kicker" data-i18n="kicker.pipelines">pipelines</span>
397
+ <div class="pp-actions">
398
+ <button id="ppAddBtn" class="micro-btn" data-i18n-title="pp.add.title">+</button>
399
+ <button id="ppModeBtn" class="micro-btn" data-i18n-title="pp.mode.title">◐</button>
400
+ </div>
401
+ </div>
402
+ <div id="pipelinesList" class="pp-list"></div>
403
+ </section>
404
+ </div>
405
+ <div class="left-tab-pane hidden" data-pane="recent">
406
+ <section id="recentFiles">
407
+ <div class="rf-head">
408
+ <span class="kicker" data-i18n="kicker.recent">recent</span>
409
+ <button id="recentClearBtn" class="micro-btn" data-i18n-title="recent.clear.title">βœ•</button>
410
+ </div>
411
+ <div id="recentList-files" class="rf-list"></div>
412
+ </section>
413
+ </div>
414
+ <div class="left-tab-pane hidden" data-pane="legend">
415
+ <section id="legend">
416
+ <div class="legend-title" data-i18n="kicker.legend">extensions</div>
417
+ <div id="legend-items"></div>
418
+ </section>
419
+ </div>
420
+ </aside>
421
+
422
+ <!-- Folder name labels β€” one per cluster when grouping is on -->
423
+ <div id="folderLabels" class="folder-labels"></div>
424
+
425
+ <!-- Full AI trace panel β€” session log, stats, sessions, replay, export -->
426
+ <aside id="traceFull" class="hidden">
427
+ <div class="trace-full-head">
428
+ <div class="kicker" data-i18n="kicker.ai_trace_full">ai trace Β· session</div>
429
+ <button id="closeTraceFull">βœ•</button>
430
+ </div>
431
+ <div id="traceFullMeta" class="trace-full-meta">β€”</div>
432
+ <div class="trace-full-toolbar">
433
+ <select id="traceToolFilter" class="trace-filter">
434
+ <option value="" data-i18n="trace.filter.all">all tools</option>
435
+ </select>
436
+ <button id="traceReplayBtn" class="psw-btn" data-i18n-title="trace.replay.title">β–Ά Replay</button>
437
+ <button id="traceExportBtn" class="psw-btn" data-i18n-title="trace.export.title">⬇ JSON</button>
438
+ <button id="traceClearBtn" class="psw-btn" data-i18n-title="trace.clear.title">πŸ—‘ Clear</button>
439
+ <button id="traceSessionsBtn" class="psw-btn" data-i18n-title="trace.sessions.title">πŸ“‚ Sessions</button>
440
+ </div>
441
+ <div id="traceTabs" class="trace-tabs">
442
+ <button data-tab="log" class="trace-tab active" data-i18n="trace.tab.log">log</button>
443
+ <button data-tab="stats" class="trace-tab" data-i18n="trace.tab.stats">stats</button>
444
+ <button data-tab="sessions" class="trace-tab" data-i18n="trace.tab.sessions">sessions</button>
445
+ </div>
446
+ <div id="traceFullBody" class="trace-full-body"></div>
447
+ </aside>
448
+
449
+
450
+ <!-- Controls hint -->
451
+ <div id="hints">
452
+ <span class="hint-key" data-i18n="hints.drag">drag</span> <span data-i18n="hints.orbit">orbit</span>
453
+ <span class="hint-sep">Β·</span>
454
+ <span class="hint-key" data-i18n="hints.scroll">scroll</span> <span data-i18n="hints.zoom">zoom</span>
455
+ <span class="hint-sep">Β·</span>
456
+ <span class="hint-key" data-i18n="hints.click">click</span> <span data-i18n="hints.inspect">inspect</span>
457
+ <span class="hint-sep">Β·</span>
458
+ <span class="hint-key" data-i18n="hints.hover">hover</span> <span data-i18n="hints.focus">focus</span>
459
+ </div>
460
+
461
+ <!-- Welcome / empty state β€” observatory console -->
462
+ <div id="welcome">
463
+ <div class="welcome-inner">
464
+ <div class="welcome-frame">
465
+ <span class="frame-corner tl"></span>
466
+ <span class="frame-corner tr"></span>
467
+ <span class="frame-corner bl"></span>
468
+ <span class="frame-corner br"></span>
469
+
470
+ <div class="welcome-meta">
471
+ <span class="welcome-coord">CH.001</span>
472
+ <span class="welcome-sep">Β·</span>
473
+ <span class="welcome-coord" data-i18n="welcome.coord.visualizer">visualizer</span>
474
+ <span class="welcome-sep">Β·</span>
475
+ <span class="welcome-coord" data-i18n="welcome.coord.offline">offline</span>
476
+ </div>
477
+
478
+ <div class="welcome-constellation" aria-hidden="true">
479
+ <svg viewBox="0 0 220 90" xmlns="http://www.w3.org/2000/svg">
480
+ <g stroke="currentColor" stroke-width="0.5" fill="none" opacity="0.35">
481
+ <line x1="30" y1="50" x2="80" y2="20"/>
482
+ <line x1="80" y1="20" x2="140" y2="35"/>
483
+ <line x1="140" y1="35" x2="120" y2="70"/>
484
+ <line x1="120" y1="70" x2="60" y2="65"/>
485
+ <line x1="60" y1="65" x2="30" y2="50"/>
486
+ <line x1="80" y1="20" x2="120" y2="70"/>
487
+ <line x1="140" y1="35" x2="190" y2="55"/>
488
+ <line x1="190" y1="55" x2="170" y2="20"/>
489
+ </g>
490
+ <g fill="currentColor">
491
+ <circle cx="30" cy="50" r="1.5"/>
492
+ <circle cx="80" cy="20" r="2.2"/>
493
+ <circle cx="140" cy="35" r="2.8"/>
494
+ <circle cx="120" cy="70" r="1.8"/>
495
+ <circle cx="60" cy="65" r="1.4"/>
496
+ <circle cx="190" cy="55" r="2.0"/>
497
+ <circle cx="170" cy="20" r="1.6"/>
498
+ </g>
499
+ </svg>
500
+ </div>
501
+
502
+ <h1 class="welcome-title">
503
+ <span class="welcome-bracket">[</span>code<span class="accent">synapt</span><span class="welcome-bracket">]</span>
504
+ </h1>
505
+ <p class="welcome-sub" data-i18n="welcome.subtitle">a dependency observatory Β· point at any directory, watch the graph form</p>
506
+
507
+ <div class="welcome-divider">
508
+ <span>──</span><span class="welcome-divider-tick">β–Έ</span><span data-i18n="welcome.begin">begin</span><span class="welcome-divider-tick">β—‚</span><span>──</span>
509
+ </div>
510
+
511
+ <button id="welcomeOpenBtn" class="primary-btn">
512
+ <span class="btn-icon">β”Œβ”€β”</span>
513
+ <span data-i18n="welcome.open_folder">Open Folder</span>
514
+ <span class="btn-key">⌘O</span>
515
+ </button>
516
+
517
+ <div id="recentList"></div>
518
+
519
+ <div class="welcome-hint">
520
+ <span class="hint-dim">└─</span> <span data-i18n="welcome.drag_hint">or drag a folder onto this window</span>
521
+ </div>
522
+ </div>
523
+ </div>
524
+ </div>
525
+
526
+ <!-- Right sidebar: minimap (top) + inspector + project context.
527
+ AI trace stays as a floating panel anchored to the canvas, not here. -->
528
+ <aside id="rightRail">
529
+ <section id="minimapWrap" class="rs-section">
530
+ <canvas id="minimapCanvas" width="280" height="280"></canvas>
531
+ <div class="minimap-corner top-left" data-i18n="kicker.overview">overview</div>
532
+ <button id="minimapToggle" class="minimap-corner top-right" data-i18n-title="minimap.hide.title">βˆ’</button>
533
+ </section>
534
+
535
+ <section id="inspector" class="rs-section">
536
+ <div class="inspector-head rs-head">
537
+ <div class="kicker" data-i18n="kicker.inspector">inspector</div>
538
+ <button id="closeInspector">βœ•</button>
539
+ </div>
540
+ <div id="inspector-body"><div class="rs-empty" data-i18n="inspector.empty">νŒŒμΌμ„ μ„ νƒν•˜λ©΄ 정보가 ν‘œμ‹œλ©λ‹ˆλ‹€</div></div>
541
+ </section>
542
+
543
+ <section id="contextPanel" class="rs-section">
544
+ <div class="ctx-head rs-head">
545
+ <span id="ctxKicker" class="kicker" data-i18n="kicker.project">project</span>
546
+ <button id="ctxEditBtn" class="micro-btn" data-i18n-title="project.edit.title" style="display:none">✎</button>
547
+ </div>
548
+ <div id="ctxBody" class="ctx-body">β€”</div>
549
+ </section>
550
+ </aside>
551
+
552
+ <!-- AI trace panel β€” floats over the canvas at bottom-right
553
+ (pulses when an MCP client / CLI hits the graph) -->
554
+ <aside id="aiTracePanel">
555
+ <div class="ai-trace-head">
556
+ <span class="kicker" data-i18n="kicker.ai_trace">ai trace</span>
557
+ <span class="trace-dot"></span>
558
+ <button id="aiTraceFullBtn" class="ai-trace-mini" data-i18n-title="trace.full.title">β€’</button>
559
+ </div>
560
+ <div id="aiTraceBody"><div class="trace-empty" data-i18n="trace.panel.empty"></div></div>
561
+ </aside>
562
+
563
+ <!-- Project info setup dialog -->
564
+ <div id="projectDialog" class="hidden">
565
+ <div class="dialog-backdrop"></div>
566
+ <div class="dialog-card">
567
+ <div class="dialog-head">
568
+ <div class="kicker" data-i18n="kicker.project_info">project info</div>
569
+ <button id="dialogClose">βœ•</button>
570
+ </div>
571
+ <p class="dialog-help" data-i18n="dialog.help"></p>
572
+ <div class="dialog-form">
573
+ <label class="form-row">
574
+ <span class="form-label" data-i18n="dialog.name">name</span>
575
+ <input type="text" id="pi_name" data-i18n-placeholder="dialog.name.ph" autocomplete="off" />
576
+ </label>
577
+ <label class="form-row">
578
+ <span class="form-label" data-i18n="dialog.version">version</span>
579
+ <input type="text" id="pi_version" placeholder="1.0.0" autocomplete="off" />
580
+ </label>
581
+ <label class="form-row">
582
+ <span class="form-label" data-i18n="dialog.stack">stack</span>
583
+ <input type="text" id="pi_stack" data-i18n-placeholder="dialog.stack.ph" autocomplete="off" />
584
+ </label>
585
+ <label class="form-row form-row-textarea">
586
+ <span class="form-label" data-i18n="dialog.description">description</span>
587
+ <textarea id="pi_description" rows="3" data-i18n-placeholder="dialog.description.ph"></textarea>
588
+ </label>
589
+ <label class="form-row form-row-textarea">
590
+ <span class="form-label" data-i18n="dialog.notes">notes</span>
591
+ <textarea id="pi_notes" rows="3" data-i18n-placeholder="dialog.notes.ph"></textarea>
592
+ </label>
593
+ </div>
594
+ <div class="dialog-actions">
595
+ <button id="dialogSkip" class="secondary-btn" data-i18n="dialog.skip">Skip</button>
596
+ <button id="dialogSave" class="primary-btn" data-i18n="dialog.save">Save</button>
597
+ </div>
598
+ </div>
599
+ </div>
600
+
601
+ <!-- Drop overlay -->
602
+ <div id="dropOverlay" class="hidden">
603
+ <div class="drop-inner" data-i18n="drop.overlay">drop folder to scan</div>
604
+ </div>
605
+
606
+ <!-- Status bar (bottom strip) -->
607
+ <div id="statusBar">
608
+ <div class="status-section status-left">
609
+ <span class="status-cell" id="sb_files" data-i18n-title="status.files.title">β€” <span data-i18n="status.files">files</span></span>
610
+ <span class="status-cell" id="sb_edges" data-i18n-title="status.edges.title">β€” <span data-i18n="status.edges">edges</span></span>
611
+ <span class="status-cell" id="sb_comps" data-i18n-title="status.comp.title">β€” <span data-i18n="status.comp">comp</span></span>
612
+ <span class="status-cell sb-clickable" id="sb_symbols" data-i18n-title="status.symbols.title" title="Click to build the symbol graph (codegraph-equivalent layer)">β€” <span data-i18n="status.symbols">syms</span></span>
613
+ </div>
614
+ <div class="status-section status-center">
615
+ <span class="status-cell" id="sb_state" data-i18n-title="status.state.title">β€”</span>
616
+ <span class="status-cell" id="sb_changed" data-i18n-title="status.changed.title">β€”</span>
617
+ </div>
618
+ <div class="status-section status-right">
619
+ <span class="status-cell" id="sb_backend" data-i18n-title="status.backend.title">CPU</span>
620
+ <span class="status-cell" id="sb_fps" data-i18n-title="status.fps.title">β€” fps</span>
621
+ </div>
622
+ </div>
623
+
624
+ <!-- Scan progress toast -->
625
+ <div id="scanToast" class="hidden">
626
+ <span class="spinner"></span>
627
+ <span class="scan-label"><span data-i18n="scan.scanning">Scanning…</span> <span id="scanCount">0</span> <span data-i18n="scan.files">files</span></span>
628
+ </div>
629
+
630
+ <!-- Stats panel -->
631
+ <aside id="statsPanel" class="hidden">
632
+ <div class="stats-head">
633
+ <div class="kicker" data-i18n="kicker.graph_stats">graph stats</div>
634
+ <button id="closeStats">βœ•</button>
635
+ </div>
636
+ <div class="stats-body" id="statsBody">β€”</div>
637
+ </aside>
638
+
639
+ <!-- Toast (generic notifications) -->
640
+ <div id="toastHost"></div>
641
+
642
+ <script type="importmap">
643
+ { "imports": { "three": "./vendor/three.module.js" } }
644
+ </script>
645
+ <script type="module" src="./app.js"></script>
646
+ </body>
647
+ </html>