lance-context 0.1.0 → 1.1.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 +232 -23
- package/dist/__tests__/ast-chunker.test.d.ts +2 -0
- package/dist/__tests__/ast-chunker.test.d.ts.map +1 -0
- package/dist/__tests__/ast-chunker.test.js +307 -0
- package/dist/__tests__/ast-chunker.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +242 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/dashboard/beads.test.d.ts +2 -0
- package/dist/__tests__/dashboard/beads.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard/beads.test.js +151 -0
- package/dist/__tests__/dashboard/beads.test.js.map +1 -0
- package/dist/__tests__/dashboard/index.test.d.ts +2 -0
- package/dist/__tests__/dashboard/index.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard/index.test.js +116 -0
- package/dist/__tests__/dashboard/index.test.js.map +1 -0
- package/dist/__tests__/dashboard/routes.test.d.ts +2 -0
- package/dist/__tests__/dashboard/routes.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard/routes.test.js +125 -0
- package/dist/__tests__/dashboard/routes.test.js.map +1 -0
- package/dist/__tests__/dashboard/server.test.d.ts +2 -0
- package/dist/__tests__/dashboard/server.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard/server.test.js +75 -0
- package/dist/__tests__/dashboard/server.test.js.map +1 -0
- package/dist/__tests__/dashboard/state.test.d.ts +2 -0
- package/dist/__tests__/dashboard/state.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard/state.test.js +124 -0
- package/dist/__tests__/dashboard/state.test.js.map +1 -0
- package/dist/__tests__/embeddings/factory.test.d.ts +2 -0
- package/dist/__tests__/embeddings/factory.test.d.ts.map +1 -0
- package/dist/__tests__/embeddings/factory.test.js +100 -0
- package/dist/__tests__/embeddings/factory.test.js.map +1 -0
- package/dist/__tests__/embeddings/jina.test.d.ts +2 -0
- package/dist/__tests__/embeddings/jina.test.d.ts.map +1 -0
- package/dist/__tests__/embeddings/jina.test.js +156 -0
- package/dist/__tests__/embeddings/jina.test.js.map +1 -0
- package/dist/__tests__/embeddings/ollama.test.d.ts +2 -0
- package/dist/__tests__/embeddings/ollama.test.d.ts.map +1 -0
- package/dist/__tests__/embeddings/ollama.test.js +172 -0
- package/dist/__tests__/embeddings/ollama.test.js.map +1 -0
- package/dist/__tests__/embeddings/rate-limiter.test.d.ts +2 -0
- package/dist/__tests__/embeddings/rate-limiter.test.d.ts.map +1 -0
- package/dist/__tests__/embeddings/rate-limiter.test.js +163 -0
- package/dist/__tests__/embeddings/rate-limiter.test.js.map +1 -0
- package/dist/__tests__/embeddings/retry.test.d.ts +2 -0
- package/dist/__tests__/embeddings/retry.test.d.ts.map +1 -0
- package/dist/__tests__/embeddings/retry.test.js +260 -0
- package/dist/__tests__/embeddings/retry.test.js.map +1 -0
- package/dist/__tests__/embeddings/types.test.d.ts +2 -0
- package/dist/__tests__/embeddings/types.test.d.ts.map +1 -0
- package/dist/__tests__/embeddings/types.test.js +31 -0
- package/dist/__tests__/embeddings/types.test.js.map +1 -0
- package/dist/__tests__/mocks/embedding-backend.mock.d.ts +10 -0
- package/dist/__tests__/mocks/embedding-backend.mock.d.ts.map +1 -0
- package/dist/__tests__/mocks/embedding-backend.mock.js +39 -0
- package/dist/__tests__/mocks/embedding-backend.mock.js.map +1 -0
- package/dist/__tests__/mocks/fetch.mock.d.ts +38 -0
- package/dist/__tests__/mocks/fetch.mock.d.ts.map +1 -0
- package/dist/__tests__/mocks/fetch.mock.js +74 -0
- package/dist/__tests__/mocks/fetch.mock.js.map +1 -0
- package/dist/__tests__/mocks/lancedb.mock.d.ts +38 -0
- package/dist/__tests__/mocks/lancedb.mock.d.ts.map +1 -0
- package/dist/__tests__/mocks/lancedb.mock.js +63 -0
- package/dist/__tests__/mocks/lancedb.mock.js.map +1 -0
- package/dist/__tests__/search/clustering.test.d.ts +2 -0
- package/dist/__tests__/search/clustering.test.d.ts.map +1 -0
- package/dist/__tests__/search/clustering.test.js +230 -0
- package/dist/__tests__/search/clustering.test.js.map +1 -0
- package/dist/__tests__/search/hybrid-search.test.d.ts +2 -0
- package/dist/__tests__/search/hybrid-search.test.d.ts.map +1 -0
- package/dist/__tests__/search/hybrid-search.test.js +186 -0
- package/dist/__tests__/search/hybrid-search.test.js.map +1 -0
- package/dist/__tests__/search/indexer.test.d.ts +2 -0
- package/dist/__tests__/search/indexer.test.d.ts.map +1 -0
- package/dist/__tests__/search/indexer.test.js +878 -0
- package/dist/__tests__/search/indexer.test.js.map +1 -0
- package/dist/__tests__/search/tree-sitter-chunker.test.d.ts +2 -0
- package/dist/__tests__/search/tree-sitter-chunker.test.d.ts.map +1 -0
- package/dist/__tests__/search/tree-sitter-chunker.test.js +228 -0
- package/dist/__tests__/search/tree-sitter-chunker.test.js.map +1 -0
- package/dist/__tests__/setup.d.ts +2 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +11 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/__tests__/utils/concurrency.test.d.ts +2 -0
- package/dist/__tests__/utils/concurrency.test.d.ts.map +1 -0
- package/dist/__tests__/utils/concurrency.test.js +83 -0
- package/dist/__tests__/utils/concurrency.test.js.map +1 -0
- package/dist/__tests__/utils/errors.test.d.ts +2 -0
- package/dist/__tests__/utils/errors.test.d.ts.map +1 -0
- package/dist/__tests__/utils/errors.test.js +136 -0
- package/dist/__tests__/utils/errors.test.js.map +1 -0
- package/dist/__tests__/utils/type-guards.test.d.ts +2 -0
- package/dist/__tests__/utils/type-guards.test.d.ts.map +1 -0
- package/dist/__tests__/utils/type-guards.test.js +80 -0
- package/dist/__tests__/utils/type-guards.test.js.map +1 -0
- package/dist/__tests__/worktree/worktree-manager.test.d.ts +2 -0
- package/dist/__tests__/worktree/worktree-manager.test.d.ts.map +1 -0
- package/dist/__tests__/worktree/worktree-manager.test.js +403 -0
- package/dist/__tests__/worktree/worktree-manager.test.js.map +1 -0
- package/dist/config.d.ts +122 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +508 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/beads.d.ts +35 -0
- package/dist/dashboard/beads.d.ts.map +1 -0
- package/dist/dashboard/beads.js +102 -0
- package/dist/dashboard/beads.js.map +1 -0
- package/dist/dashboard/events.d.ts +46 -0
- package/dist/dashboard/events.d.ts.map +1 -0
- package/dist/dashboard/events.js +141 -0
- package/dist/dashboard/events.js.map +1 -0
- package/dist/dashboard/index.d.ts +69 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +93 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/routes.d.ts +6 -0
- package/dist/dashboard/routes.d.ts.map +1 -0
- package/dist/dashboard/routes.js +245 -0
- package/dist/dashboard/routes.js.map +1 -0
- package/dist/dashboard/server.d.ts +27 -0
- package/dist/dashboard/server.d.ts.map +1 -0
- package/dist/dashboard/server.js +72 -0
- package/dist/dashboard/server.js.map +1 -0
- package/dist/dashboard/state.d.ts +125 -0
- package/dist/dashboard/state.d.ts.map +1 -0
- package/dist/dashboard/state.js +264 -0
- package/dist/dashboard/state.js.map +1 -0
- package/dist/dashboard/ui.d.ts +6 -0
- package/dist/dashboard/ui.d.ts.map +1 -0
- package/dist/dashboard/ui.js +1421 -0
- package/dist/dashboard/ui.js.map +1 -0
- package/dist/embeddings/index.d.ts +20 -2
- package/dist/embeddings/index.d.ts.map +1 -1
- package/dist/embeddings/index.js +49 -6
- package/dist/embeddings/index.js.map +1 -1
- package/dist/embeddings/jina.d.ts +9 -0
- package/dist/embeddings/jina.d.ts.map +1 -1
- package/dist/embeddings/jina.js +42 -2
- package/dist/embeddings/jina.js.map +1 -1
- package/dist/embeddings/ollama.d.ts +2 -0
- package/dist/embeddings/ollama.d.ts.map +1 -1
- package/dist/embeddings/ollama.js +21 -5
- package/dist/embeddings/ollama.js.map +1 -1
- package/dist/embeddings/rate-limiter.d.ts +75 -0
- package/dist/embeddings/rate-limiter.d.ts.map +1 -0
- package/dist/embeddings/rate-limiter.js +145 -0
- package/dist/embeddings/rate-limiter.js.map +1 -0
- package/dist/embeddings/retry.d.ts +14 -0
- package/dist/embeddings/retry.d.ts.map +1 -0
- package/dist/embeddings/retry.js +89 -0
- package/dist/embeddings/retry.js.map +1 -0
- package/dist/embeddings/types.d.ts +56 -2
- package/dist/embeddings/types.d.ts.map +1 -1
- package/dist/embeddings/types.js +16 -0
- package/dist/embeddings/types.js.map +1 -1
- package/dist/index.js +1871 -44
- package/dist/index.js.map +1 -1
- package/dist/memory/index.d.ts +63 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +168 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/search/ast-chunker.d.ts +34 -0
- package/dist/search/ast-chunker.d.ts.map +1 -0
- package/dist/search/ast-chunker.js +261 -0
- package/dist/search/ast-chunker.js.map +1 -0
- package/dist/search/clustering.d.ts +77 -0
- package/dist/search/clustering.d.ts.map +1 -0
- package/dist/search/clustering.js +455 -0
- package/dist/search/clustering.js.map +1 -0
- package/dist/search/indexer.d.ts +239 -3
- package/dist/search/indexer.d.ts.map +1 -1
- package/dist/search/indexer.js +941 -45
- package/dist/search/indexer.js.map +1 -1
- package/dist/search/tree-sitter-chunker.d.ts +69 -0
- package/dist/search/tree-sitter-chunker.d.ts.map +1 -0
- package/dist/search/tree-sitter-chunker.js +436 -0
- package/dist/search/tree-sitter-chunker.js.map +1 -0
- package/dist/symbols/index.d.ts +14 -0
- package/dist/symbols/index.d.ts.map +1 -0
- package/dist/symbols/index.js +19 -0
- package/dist/symbols/index.js.map +1 -0
- package/dist/symbols/name-path.d.ts +113 -0
- package/dist/symbols/name-path.d.ts.map +1 -0
- package/dist/symbols/name-path.js +194 -0
- package/dist/symbols/name-path.js.map +1 -0
- package/dist/symbols/pattern-search.d.ts +14 -0
- package/dist/symbols/pattern-search.d.ts.map +1 -0
- package/dist/symbols/pattern-search.js +224 -0
- package/dist/symbols/pattern-search.js.map +1 -0
- package/dist/symbols/reference-finder.d.ts +38 -0
- package/dist/symbols/reference-finder.d.ts.map +1 -0
- package/dist/symbols/reference-finder.js +376 -0
- package/dist/symbols/reference-finder.js.map +1 -0
- package/dist/symbols/symbol-editor.d.ts +81 -0
- package/dist/symbols/symbol-editor.d.ts.map +1 -0
- package/dist/symbols/symbol-editor.js +257 -0
- package/dist/symbols/symbol-editor.js.map +1 -0
- package/dist/symbols/symbol-extractor.d.ts +49 -0
- package/dist/symbols/symbol-extractor.d.ts.map +1 -0
- package/dist/symbols/symbol-extractor.js +593 -0
- package/dist/symbols/symbol-extractor.js.map +1 -0
- package/dist/symbols/symbol-renamer.d.ts +81 -0
- package/dist/symbols/symbol-renamer.d.ts.map +1 -0
- package/dist/symbols/symbol-renamer.js +204 -0
- package/dist/symbols/symbol-renamer.js.map +1 -0
- package/dist/symbols/types.d.ts +234 -0
- package/dist/symbols/types.d.ts.map +1 -0
- package/dist/symbols/types.js +106 -0
- package/dist/symbols/types.js.map +1 -0
- package/dist/utils/concurrency.d.ts +32 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +57 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/errors.d.ts +36 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +91 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/type-guards.d.ts +17 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +25 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/dist/worktree/index.d.ts +6 -0
- package/dist/worktree/index.d.ts.map +1 -0
- package/dist/worktree/index.js +6 -0
- package/dist/worktree/index.js.map +1 -0
- package/dist/worktree/types.d.ts +101 -0
- package/dist/worktree/types.d.ts.map +1 -0
- package/dist/worktree/types.js +6 -0
- package/dist/worktree/types.js.map +1 -0
- package/dist/worktree/worktree-manager.d.ts +80 -0
- package/dist/worktree/worktree-manager.d.ts.map +1 -0
- package/dist/worktree/worktree-manager.js +407 -0
- package/dist/worktree/worktree-manager.js.map +1 -0
- package/package.json +39 -5
- package/scripts/postinstall.js +48 -0
|
@@ -0,0 +1,1421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lance logo SVG (embedded)
|
|
3
|
+
*/
|
|
4
|
+
const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" width="40" height="40">
|
|
5
|
+
<circle cx="100" cy="100" r="95" fill="#1a1a2e"/>
|
|
6
|
+
<rect x="45" y="55" width="110" height="100" rx="15" ry="15" fill="#4a90d9"/>
|
|
7
|
+
<line x1="100" y1="55" x2="100" y2="30" stroke="#4a90d9" stroke-width="6" stroke-linecap="round"/>
|
|
8
|
+
<circle cx="100" cy="25" r="10" fill="#ff6b6b"/>
|
|
9
|
+
<rect x="30" y="80" width="15" height="40" rx="5" ry="5" fill="#357abd"/>
|
|
10
|
+
<rect x="155" y="80" width="15" height="40" rx="5" ry="5" fill="#357abd"/>
|
|
11
|
+
<rect x="55" y="70" width="90" height="70" rx="10" ry="10" fill="#5ba3ec"/>
|
|
12
|
+
<rect x="50" y="82" width="45" height="35" rx="8" ry="8" fill="none" stroke="#1a1a2e" stroke-width="6"/>
|
|
13
|
+
<rect x="105" y="82" width="45" height="35" rx="8" ry="8" fill="none" stroke="#1a1a2e" stroke-width="6"/>
|
|
14
|
+
<line x1="95" y1="100" x2="105" y2="100" stroke="#1a1a2e" stroke-width="6"/>
|
|
15
|
+
<line x1="50" y1="95" x2="35" y2="90" stroke="#1a1a2e" stroke-width="5" stroke-linecap="round"/>
|
|
16
|
+
<line x1="150" y1="95" x2="165" y2="90" stroke="#1a1a2e" stroke-width="5" stroke-linecap="round"/>
|
|
17
|
+
<ellipse cx="62" cy="92" rx="8" ry="5" fill="rgba(255,255,255,0.3)"/>
|
|
18
|
+
<ellipse cx="117" cy="92" rx="8" ry="5" fill="rgba(255,255,255,0.3)"/>
|
|
19
|
+
<circle cx="72" cy="100" r="12" fill="#1a1a2e"/>
|
|
20
|
+
<circle cx="128" cy="100" r="12" fill="#1a1a2e"/>
|
|
21
|
+
<circle cx="75" cy="97" r="5" fill="#ffffff"/>
|
|
22
|
+
<circle cx="131" cy="97" r="5" fill="#ffffff"/>
|
|
23
|
+
<path d="M 75 130 Q 100 145 125 130" fill="none" stroke="#1a1a2e" stroke-width="4" stroke-linecap="round"/>
|
|
24
|
+
<ellipse cx="60" cy="120" rx="8" ry="5" fill="rgba(255,107,107,0.4)"/>
|
|
25
|
+
<ellipse cx="140" cy="120" rx="8" ry="5" fill="rgba(255,107,107,0.4)"/>
|
|
26
|
+
<circle cx="55" cy="145" r="5" fill="#357abd"/>
|
|
27
|
+
<circle cx="145" cy="145" r="5" fill="#357abd"/>
|
|
28
|
+
</svg>`;
|
|
29
|
+
/**
|
|
30
|
+
* Favicon as base64 data URL
|
|
31
|
+
*/
|
|
32
|
+
const FAVICON_SVG = `data:image/svg+xml,${encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><circle cx="100" cy="100" r="95" fill="#1a1a2e"/><rect x="45" y="55" width="110" height="100" rx="15" ry="15" fill="#4a90d9"/><line x1="100" y1="55" x2="100" y2="30" stroke="#4a90d9" stroke-width="6" stroke-linecap="round"/><circle cx="100" cy="25" r="10" fill="#ff6b6b"/><rect x="30" y="80" width="15" height="40" rx="5" ry="5" fill="#357abd"/><rect x="155" y="80" width="15" height="40" rx="5" ry="5" fill="#357abd"/><rect x="55" y="70" width="90" height="70" rx="10" ry="10" fill="#5ba3ec"/><rect x="50" y="82" width="45" height="35" rx="8" ry="8" fill="none" stroke="#1a1a2e" stroke-width="6"/><rect x="105" y="82" width="45" height="35" rx="8" ry="8" fill="none" stroke="#1a1a2e" stroke-width="6"/><line x1="95" y1="100" x2="105" y2="100" stroke="#1a1a2e" stroke-width="6"/><circle cx="72" cy="100" r="12" fill="#1a1a2e"/><circle cx="128" cy="100" r="12" fill="#1a1a2e"/><circle cx="75" cy="97" r="5" fill="#fff"/><circle cx="131" cy="97" r="5" fill="#fff"/><path d="M 75 130 Q 100 145 125 130" fill="none" stroke="#1a1a2e" stroke-width="4" stroke-linecap="round"/></svg>`)}`;
|
|
33
|
+
/**
|
|
34
|
+
* Generate the dashboard HTML page.
|
|
35
|
+
* This is a self-contained HTML page with embedded CSS and JavaScript.
|
|
36
|
+
*/
|
|
37
|
+
export function getDashboardHTML() {
|
|
38
|
+
return `<!DOCTYPE html>
|
|
39
|
+
<html lang="en" data-theme="dark">
|
|
40
|
+
<head>
|
|
41
|
+
<meta charset="UTF-8">
|
|
42
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
43
|
+
<title>lance-context Dashboard</title>
|
|
44
|
+
<link rel="icon" type="image/svg+xml" href="${FAVICON_SVG}">
|
|
45
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/charts.css/dist/charts.min.css">
|
|
46
|
+
<style>
|
|
47
|
+
:root {
|
|
48
|
+
/* Light theme */
|
|
49
|
+
--bg-primary-light: #ffffff;
|
|
50
|
+
--bg-secondary-light: #f6f8fa;
|
|
51
|
+
--bg-tertiary-light: #eaeef2;
|
|
52
|
+
--border-color-light: #d0d7de;
|
|
53
|
+
--text-primary-light: #1f2328;
|
|
54
|
+
--text-secondary-light: #656d76;
|
|
55
|
+
--text-muted-light: #8c959f;
|
|
56
|
+
--accent-blue: #0969da;
|
|
57
|
+
--accent-green: #1a7f37;
|
|
58
|
+
--accent-yellow: #9a6700;
|
|
59
|
+
--accent-red: #cf222e;
|
|
60
|
+
--accent-purple: #8250df;
|
|
61
|
+
|
|
62
|
+
/* Dark theme */
|
|
63
|
+
--bg-primary-dark: #0d1117;
|
|
64
|
+
--bg-secondary-dark: #161b22;
|
|
65
|
+
--bg-tertiary-dark: #21262d;
|
|
66
|
+
--border-color-dark: #30363d;
|
|
67
|
+
--text-primary-dark: #e6edf3;
|
|
68
|
+
--text-secondary-dark: #8b949e;
|
|
69
|
+
--text-muted-dark: #6e7681;
|
|
70
|
+
--accent-blue-dark: #58a6ff;
|
|
71
|
+
--accent-green-dark: #3fb950;
|
|
72
|
+
--accent-yellow-dark: #d29922;
|
|
73
|
+
--accent-red-dark: #f85149;
|
|
74
|
+
--accent-purple-dark: #a371f7;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
[data-theme="dark"] {
|
|
78
|
+
--bg-primary: var(--bg-primary-dark);
|
|
79
|
+
--bg-secondary: var(--bg-secondary-dark);
|
|
80
|
+
--bg-tertiary: var(--bg-tertiary-dark);
|
|
81
|
+
--border-color: var(--border-color-dark);
|
|
82
|
+
--text-primary: var(--text-primary-dark);
|
|
83
|
+
--text-secondary: var(--text-secondary-dark);
|
|
84
|
+
--text-muted: var(--text-muted-dark);
|
|
85
|
+
--accent-blue: var(--accent-blue-dark);
|
|
86
|
+
--accent-green: var(--accent-green-dark);
|
|
87
|
+
--accent-yellow: var(--accent-yellow-dark);
|
|
88
|
+
--accent-red: var(--accent-red-dark);
|
|
89
|
+
--accent-purple: var(--accent-purple-dark);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
[data-theme="light"] {
|
|
93
|
+
--bg-primary: var(--bg-primary-light);
|
|
94
|
+
--bg-secondary: var(--bg-secondary-light);
|
|
95
|
+
--bg-tertiary: var(--bg-tertiary-light);
|
|
96
|
+
--border-color: var(--border-color-light);
|
|
97
|
+
--text-primary: var(--text-primary-light);
|
|
98
|
+
--text-secondary: var(--text-secondary-light);
|
|
99
|
+
--text-muted: var(--text-muted-light);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
* {
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
margin: 0;
|
|
105
|
+
padding: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
body {
|
|
109
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
|
|
110
|
+
background-color: var(--bg-primary);
|
|
111
|
+
color: var(--text-primary);
|
|
112
|
+
line-height: 1.5;
|
|
113
|
+
min-height: 100vh;
|
|
114
|
+
transition: background-color 0.3s ease, color 0.3s ease;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.container {
|
|
118
|
+
max-width: 1200px;
|
|
119
|
+
margin: 0 auto;
|
|
120
|
+
padding: 24px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
header {
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
justify-content: space-between;
|
|
127
|
+
margin-bottom: 32px;
|
|
128
|
+
padding-bottom: 16px;
|
|
129
|
+
border-bottom: 1px solid var(--border-color);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.header-left {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 12px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.header-right {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 16px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
h1 {
|
|
145
|
+
font-size: 24px;
|
|
146
|
+
font-weight: 600;
|
|
147
|
+
display: flex;
|
|
148
|
+
align-items: center;
|
|
149
|
+
gap: 12px;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.logo {
|
|
153
|
+
width: 40px;
|
|
154
|
+
height: 40px;
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
justify-content: center;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.logo svg {
|
|
161
|
+
width: 40px;
|
|
162
|
+
height: 40px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.version-badge {
|
|
166
|
+
font-size: 12px;
|
|
167
|
+
font-weight: 400;
|
|
168
|
+
color: var(--text-muted);
|
|
169
|
+
margin-left: 4px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.theme-toggle {
|
|
173
|
+
display: flex;
|
|
174
|
+
align-items: center;
|
|
175
|
+
gap: 8px;
|
|
176
|
+
padding: 6px 12px;
|
|
177
|
+
background-color: var(--bg-tertiary);
|
|
178
|
+
border: 1px solid var(--border-color);
|
|
179
|
+
border-radius: 6px;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
color: var(--text-secondary);
|
|
182
|
+
font-size: 14px;
|
|
183
|
+
transition: all 0.2s ease;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.theme-toggle:hover {
|
|
187
|
+
background-color: var(--bg-secondary);
|
|
188
|
+
color: var(--text-primary);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.theme-toggle svg {
|
|
192
|
+
width: 16px;
|
|
193
|
+
height: 16px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.sun-icon, .moon-icon {
|
|
197
|
+
display: none;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
[data-theme="dark"] .moon-icon {
|
|
201
|
+
display: block;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
[data-theme="light"] .sun-icon {
|
|
205
|
+
display: block;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.connection-status {
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
gap: 8px;
|
|
212
|
+
font-size: 14px;
|
|
213
|
+
color: var(--text-secondary);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.status-dot {
|
|
217
|
+
width: 8px;
|
|
218
|
+
height: 8px;
|
|
219
|
+
border-radius: 50%;
|
|
220
|
+
background-color: var(--accent-red);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.status-dot.connected {
|
|
224
|
+
background-color: var(--accent-green);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.grid {
|
|
228
|
+
display: grid;
|
|
229
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
230
|
+
gap: 16px;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.card {
|
|
234
|
+
background-color: var(--bg-secondary);
|
|
235
|
+
border: 1px solid var(--border-color);
|
|
236
|
+
border-radius: 8px;
|
|
237
|
+
padding: 20px;
|
|
238
|
+
transition: background-color 0.3s ease, border-color 0.3s ease;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.card-header {
|
|
242
|
+
display: flex;
|
|
243
|
+
align-items: center;
|
|
244
|
+
justify-content: space-between;
|
|
245
|
+
margin-bottom: 16px;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.card-title {
|
|
249
|
+
font-size: 14px;
|
|
250
|
+
font-weight: 600;
|
|
251
|
+
color: var(--text-secondary);
|
|
252
|
+
text-transform: uppercase;
|
|
253
|
+
letter-spacing: 0.5px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.badge {
|
|
257
|
+
display: inline-flex;
|
|
258
|
+
align-items: center;
|
|
259
|
+
padding: 2px 8px;
|
|
260
|
+
font-size: 12px;
|
|
261
|
+
font-weight: 500;
|
|
262
|
+
border-radius: 12px;
|
|
263
|
+
background-color: var(--bg-tertiary);
|
|
264
|
+
color: var(--text-secondary);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.badge.success {
|
|
268
|
+
background-color: rgba(63, 185, 80, 0.15);
|
|
269
|
+
color: var(--accent-green);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.badge.warning {
|
|
273
|
+
background-color: rgba(210, 153, 34, 0.15);
|
|
274
|
+
color: var(--accent-yellow);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.badge.error {
|
|
278
|
+
background-color: rgba(248, 81, 73, 0.15);
|
|
279
|
+
color: var(--accent-red);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Form styles */
|
|
283
|
+
.settings-form {
|
|
284
|
+
margin-top: 16px;
|
|
285
|
+
padding-top: 16px;
|
|
286
|
+
border-top: 1px solid var(--border-color);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.form-group {
|
|
290
|
+
margin-bottom: 12px;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.form-group label {
|
|
294
|
+
display: block;
|
|
295
|
+
font-size: 12px;
|
|
296
|
+
color: var(--text-muted);
|
|
297
|
+
margin-bottom: 6px;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.form-select,
|
|
301
|
+
.form-input {
|
|
302
|
+
width: 100%;
|
|
303
|
+
padding: 8px 12px;
|
|
304
|
+
font-size: 14px;
|
|
305
|
+
font-family: inherit;
|
|
306
|
+
background-color: var(--bg-tertiary);
|
|
307
|
+
border: 1px solid var(--border-color);
|
|
308
|
+
border-radius: 6px;
|
|
309
|
+
color: var(--text-primary);
|
|
310
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.form-select:focus,
|
|
314
|
+
.form-input:focus {
|
|
315
|
+
outline: none;
|
|
316
|
+
border-color: var(--accent-blue);
|
|
317
|
+
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.2);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.form-hint {
|
|
321
|
+
font-size: 11px;
|
|
322
|
+
color: var(--text-muted);
|
|
323
|
+
margin-top: 4px;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.form-hint a {
|
|
327
|
+
color: var(--accent-blue);
|
|
328
|
+
text-decoration: none;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.form-hint a:hover {
|
|
332
|
+
text-decoration: underline;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.form-actions {
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
gap: 12px;
|
|
339
|
+
margin-top: 16px;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.btn {
|
|
343
|
+
padding: 8px 16px;
|
|
344
|
+
font-size: 14px;
|
|
345
|
+
font-weight: 500;
|
|
346
|
+
border-radius: 6px;
|
|
347
|
+
border: 1px solid transparent;
|
|
348
|
+
cursor: pointer;
|
|
349
|
+
transition: all 0.2s ease;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.btn-primary {
|
|
353
|
+
background-color: var(--accent-blue);
|
|
354
|
+
color: white;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.btn-primary:hover {
|
|
358
|
+
opacity: 0.9;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.btn-primary:disabled {
|
|
362
|
+
opacity: 0.5;
|
|
363
|
+
cursor: not-allowed;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
.save-status {
|
|
367
|
+
font-size: 13px;
|
|
368
|
+
color: var(--text-secondary);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.save-status.success {
|
|
372
|
+
color: var(--accent-green);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.save-status.error {
|
|
376
|
+
color: var(--accent-red);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.stat {
|
|
380
|
+
margin-bottom: 12px;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.stat:last-child {
|
|
384
|
+
margin-bottom: 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.stat-label {
|
|
388
|
+
font-size: 12px;
|
|
389
|
+
color: var(--text-muted);
|
|
390
|
+
margin-bottom: 4px;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.stat-value {
|
|
394
|
+
font-size: 24px;
|
|
395
|
+
font-weight: 600;
|
|
396
|
+
color: var(--text-primary);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.stat-value.small {
|
|
400
|
+
font-size: 14px;
|
|
401
|
+
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
|
402
|
+
color: var(--text-secondary);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.progress-container {
|
|
406
|
+
margin-top: 16px;
|
|
407
|
+
display: none;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.progress-container.active {
|
|
411
|
+
display: block;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.progress-bar {
|
|
415
|
+
height: 8px;
|
|
416
|
+
background-color: var(--bg-tertiary);
|
|
417
|
+
border-radius: 4px;
|
|
418
|
+
overflow: hidden;
|
|
419
|
+
margin-bottom: 8px;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.progress-fill {
|
|
423
|
+
height: 100%;
|
|
424
|
+
background: linear-gradient(90deg, var(--accent-blue), var(--accent-purple));
|
|
425
|
+
border-radius: 4px;
|
|
426
|
+
transition: width 0.3s ease;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.progress-text {
|
|
430
|
+
font-size: 12px;
|
|
431
|
+
color: var(--text-secondary);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.patterns-list {
|
|
435
|
+
display: flex;
|
|
436
|
+
flex-wrap: wrap;
|
|
437
|
+
gap: 6px;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
.pattern-tag {
|
|
441
|
+
display: inline-block;
|
|
442
|
+
padding: 2px 8px;
|
|
443
|
+
font-size: 12px;
|
|
444
|
+
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
|
445
|
+
background-color: var(--bg-tertiary);
|
|
446
|
+
border-radius: 4px;
|
|
447
|
+
color: var(--text-secondary);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.pattern-tag.exclude {
|
|
451
|
+
color: var(--accent-red);
|
|
452
|
+
text-decoration: line-through;
|
|
453
|
+
opacity: 0.7;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.card.full-width {
|
|
457
|
+
grid-column: 1 / -1;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.card.double-width {
|
|
461
|
+
grid-column: span 2;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.empty-state {
|
|
465
|
+
text-align: center;
|
|
466
|
+
padding: 40px 20px;
|
|
467
|
+
color: var(--text-secondary);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.empty-state-icon {
|
|
471
|
+
font-size: 48px;
|
|
472
|
+
margin-bottom: 16px;
|
|
473
|
+
opacity: 0.5;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
@keyframes pulse {
|
|
477
|
+
0%, 100% { opacity: 1; }
|
|
478
|
+
50% { opacity: 0.5; }
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.pulsing {
|
|
482
|
+
animation: pulse 2s ease-in-out infinite;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* Charts.css Customization */
|
|
486
|
+
.charts-css {
|
|
487
|
+
--color-1: #58a6ff;
|
|
488
|
+
--color-2: #3fb950;
|
|
489
|
+
--color-3: #a371f7;
|
|
490
|
+
--color-4: #f85149;
|
|
491
|
+
--color-5: #d29922;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
#chartWrapper {
|
|
495
|
+
width: 100%;
|
|
496
|
+
max-width: 100%;
|
|
497
|
+
overflow: hidden;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
#chartWrapper #usage-chart {
|
|
501
|
+
--aspect-ratio: 21 / 9;
|
|
502
|
+
width: 100%;
|
|
503
|
+
max-width: 100%;
|
|
504
|
+
margin: 0 auto;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
#usage-chart th {
|
|
508
|
+
font-size: 11px;
|
|
509
|
+
color: var(--text-secondary);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
#usage-chart td {
|
|
513
|
+
border-top-left-radius: 6px;
|
|
514
|
+
border-top-right-radius: 6px;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* Charts.css legend overrides */
|
|
518
|
+
#usageChartContainer .legend {
|
|
519
|
+
margin-top: 16px;
|
|
520
|
+
padding-top: 12px;
|
|
521
|
+
justify-content: center;
|
|
522
|
+
border-radius: 4px;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
#usageChartContainer .legend li {
|
|
526
|
+
font-size: 12px;
|
|
527
|
+
color: var(--text-secondary);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.usage-total {
|
|
531
|
+
display: flex;
|
|
532
|
+
justify-content: space-between;
|
|
533
|
+
align-items: center;
|
|
534
|
+
padding-top: 12px;
|
|
535
|
+
border-top: 1px solid var(--border-color);
|
|
536
|
+
margin-top: 16px;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.usage-total-label {
|
|
540
|
+
font-size: 12px;
|
|
541
|
+
color: var(--text-muted);
|
|
542
|
+
text-transform: uppercase;
|
|
543
|
+
letter-spacing: 0.5px;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.usage-total-count {
|
|
547
|
+
font-size: 18px;
|
|
548
|
+
font-weight: 600;
|
|
549
|
+
color: var(--text-primary);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.usage-empty {
|
|
553
|
+
text-align: center;
|
|
554
|
+
padding: 20px;
|
|
555
|
+
color: var(--text-muted);
|
|
556
|
+
font-size: 14px;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* Beads Section Styles */
|
|
560
|
+
.beads-section {
|
|
561
|
+
margin-top: 32px;
|
|
562
|
+
padding-top: 24px;
|
|
563
|
+
border-top: 1px solid var(--border-color);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.beads-header {
|
|
567
|
+
display: flex;
|
|
568
|
+
align-items: center;
|
|
569
|
+
gap: 12px;
|
|
570
|
+
margin-bottom: 16px;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.beads-logo {
|
|
574
|
+
width: 24px;
|
|
575
|
+
height: 24px;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.beads-title {
|
|
579
|
+
font-size: 18px;
|
|
580
|
+
font-weight: 600;
|
|
581
|
+
color: var(--text-primary);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.beads-unavailable {
|
|
585
|
+
text-align: center;
|
|
586
|
+
padding: 40px 20px;
|
|
587
|
+
color: var(--text-muted);
|
|
588
|
+
font-size: 14px;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.beads-stats {
|
|
592
|
+
display: flex;
|
|
593
|
+
gap: 24px;
|
|
594
|
+
margin-bottom: 16px;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.beads-stat {
|
|
598
|
+
display: flex;
|
|
599
|
+
flex-direction: column;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.beads-stat-value {
|
|
603
|
+
font-size: 24px;
|
|
604
|
+
font-weight: 600;
|
|
605
|
+
color: var(--text-primary);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.beads-stat-label {
|
|
609
|
+
font-size: 12px;
|
|
610
|
+
color: var(--text-muted);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.beads-issues {
|
|
614
|
+
display: flex;
|
|
615
|
+
flex-direction: column;
|
|
616
|
+
gap: 8px;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.beads-issue {
|
|
620
|
+
display: flex;
|
|
621
|
+
align-items: flex-start;
|
|
622
|
+
gap: 12px;
|
|
623
|
+
padding: 12px;
|
|
624
|
+
background-color: var(--bg-tertiary);
|
|
625
|
+
border-radius: 6px;
|
|
626
|
+
border: 1px solid var(--border-color);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.beads-issue-id {
|
|
630
|
+
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
|
631
|
+
font-size: 12px;
|
|
632
|
+
color: var(--accent-blue);
|
|
633
|
+
white-space: nowrap;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.beads-issue-content {
|
|
637
|
+
flex: 1;
|
|
638
|
+
min-width: 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
.beads-issue-title {
|
|
642
|
+
font-size: 14px;
|
|
643
|
+
font-weight: 500;
|
|
644
|
+
color: var(--text-primary);
|
|
645
|
+
margin-bottom: 4px;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.beads-issue-meta {
|
|
649
|
+
display: flex;
|
|
650
|
+
gap: 12px;
|
|
651
|
+
font-size: 12px;
|
|
652
|
+
color: var(--text-muted);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.beads-issue-type {
|
|
656
|
+
display: inline-flex;
|
|
657
|
+
padding: 2px 6px;
|
|
658
|
+
background-color: var(--bg-secondary);
|
|
659
|
+
border-radius: 4px;
|
|
660
|
+
font-size: 11px;
|
|
661
|
+
text-transform: uppercase;
|
|
662
|
+
letter-spacing: 0.5px;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
.beads-issue-priority {
|
|
666
|
+
display: inline-flex;
|
|
667
|
+
align-items: center;
|
|
668
|
+
gap: 4px;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.priority-dot {
|
|
672
|
+
width: 6px;
|
|
673
|
+
height: 6px;
|
|
674
|
+
border-radius: 50%;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.priority-1 { background-color: var(--accent-red); }
|
|
678
|
+
.priority-2 { background-color: var(--accent-yellow); }
|
|
679
|
+
.priority-3 { background-color: var(--accent-green); }
|
|
680
|
+
|
|
681
|
+
.beads-daemon-status {
|
|
682
|
+
display: flex;
|
|
683
|
+
align-items: center;
|
|
684
|
+
gap: 8px;
|
|
685
|
+
font-size: 12px;
|
|
686
|
+
color: var(--text-secondary);
|
|
687
|
+
margin-top: 12px;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.beads-empty {
|
|
691
|
+
text-align: center;
|
|
692
|
+
padding: 20px;
|
|
693
|
+
color: var(--text-muted);
|
|
694
|
+
font-size: 14px;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
.beads-issue {
|
|
698
|
+
cursor: pointer;
|
|
699
|
+
transition: background-color 0.2s ease;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.beads-issue:hover {
|
|
703
|
+
background-color: var(--bg-secondary);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.beads-issue-title {
|
|
707
|
+
display: flex;
|
|
708
|
+
align-items: center;
|
|
709
|
+
gap: 8px;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.beads-issue-expand {
|
|
713
|
+
width: 16px;
|
|
714
|
+
height: 16px;
|
|
715
|
+
color: var(--text-muted);
|
|
716
|
+
transition: transform 0.2s ease;
|
|
717
|
+
flex-shrink: 0;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.beads-issue.expanded .beads-issue-expand {
|
|
721
|
+
transform: rotate(90deg);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.beads-issue-description {
|
|
725
|
+
display: none;
|
|
726
|
+
margin-top: 8px;
|
|
727
|
+
padding: 12px;
|
|
728
|
+
background-color: var(--bg-secondary);
|
|
729
|
+
border-radius: 4px;
|
|
730
|
+
font-size: 13px;
|
|
731
|
+
color: var(--text-secondary);
|
|
732
|
+
white-space: pre-wrap;
|
|
733
|
+
word-break: break-word;
|
|
734
|
+
border-left: 3px solid var(--accent-blue);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.beads-issue.expanded .beads-issue-description {
|
|
738
|
+
display: block;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
.beads-issue-no-description {
|
|
742
|
+
font-style: italic;
|
|
743
|
+
color: var(--text-muted);
|
|
744
|
+
}
|
|
745
|
+
</style>
|
|
746
|
+
</head>
|
|
747
|
+
<body>
|
|
748
|
+
<div class="container">
|
|
749
|
+
<header>
|
|
750
|
+
<div class="header-left">
|
|
751
|
+
<h1>
|
|
752
|
+
<div class="logo">${LOGO_SVG}</div>
|
|
753
|
+
lance-context
|
|
754
|
+
<span class="version-badge" id="versionBadge"></span>
|
|
755
|
+
</h1>
|
|
756
|
+
</div>
|
|
757
|
+
<div class="header-right">
|
|
758
|
+
<button class="theme-toggle" id="themeToggle" title="Toggle theme">
|
|
759
|
+
<svg class="sun-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
760
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
761
|
+
</svg>
|
|
762
|
+
<svg class="moon-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
763
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
764
|
+
</svg>
|
|
765
|
+
<span class="theme-label">Theme</span>
|
|
766
|
+
</button>
|
|
767
|
+
<div class="connection-status">
|
|
768
|
+
<div class="status-dot" id="connectionDot"></div>
|
|
769
|
+
<span id="connectionText">Connecting...</span>
|
|
770
|
+
</div>
|
|
771
|
+
</div>
|
|
772
|
+
</header>
|
|
773
|
+
|
|
774
|
+
<div class="grid">
|
|
775
|
+
<!-- Index Status Card -->
|
|
776
|
+
<div class="card">
|
|
777
|
+
<div class="card-header">
|
|
778
|
+
<span class="card-title">Index Status</span>
|
|
779
|
+
<span class="badge" id="indexBadge">Loading...</span>
|
|
780
|
+
</div>
|
|
781
|
+
<div class="stat">
|
|
782
|
+
<div class="stat-label">Files Indexed</div>
|
|
783
|
+
<div class="stat-value" id="fileCount">-</div>
|
|
784
|
+
</div>
|
|
785
|
+
<div class="stat">
|
|
786
|
+
<div class="stat-label">Total Chunks</div>
|
|
787
|
+
<div class="stat-value" id="chunkCount">-</div>
|
|
788
|
+
</div>
|
|
789
|
+
<div class="stat">
|
|
790
|
+
<div class="stat-label">Last Updated</div>
|
|
791
|
+
<div class="stat-value small" id="lastUpdated">-</div>
|
|
792
|
+
</div>
|
|
793
|
+
<div class="progress-container" id="progressContainer">
|
|
794
|
+
<div class="progress-bar">
|
|
795
|
+
<div class="progress-fill" id="progressFill" style="width: 0%"></div>
|
|
796
|
+
</div>
|
|
797
|
+
<div class="progress-text" id="progressText">Initializing...</div>
|
|
798
|
+
</div>
|
|
799
|
+
</div>
|
|
800
|
+
|
|
801
|
+
<!-- Embedding Backend Card -->
|
|
802
|
+
<div class="card">
|
|
803
|
+
<div class="card-header">
|
|
804
|
+
<span class="card-title">Embedding Backend</span>
|
|
805
|
+
<span class="badge" id="embeddingStatus">-</span>
|
|
806
|
+
</div>
|
|
807
|
+
<div class="stat">
|
|
808
|
+
<div class="stat-label">Current Backend</div>
|
|
809
|
+
<div class="stat-value small" id="embeddingBackend">-</div>
|
|
810
|
+
</div>
|
|
811
|
+
<div class="stat">
|
|
812
|
+
<div class="stat-label">Index Path</div>
|
|
813
|
+
<div class="stat-value small" id="indexPath">-</div>
|
|
814
|
+
</div>
|
|
815
|
+
<div class="settings-form" id="embeddingSettingsForm">
|
|
816
|
+
<div class="form-group">
|
|
817
|
+
<label for="backendSelect">Select Backend</label>
|
|
818
|
+
<select id="backendSelect" class="form-select">
|
|
819
|
+
<option value="auto">Auto (detect available)</option>
|
|
820
|
+
<option value="jina">Jina AI (cloud)</option>
|
|
821
|
+
<option value="ollama">Ollama (local)</option>
|
|
822
|
+
</select>
|
|
823
|
+
</div>
|
|
824
|
+
<div class="form-group" id="apiKeyGroup" style="display: none;">
|
|
825
|
+
<label for="apiKeyInput">Jina API Key</label>
|
|
826
|
+
<input type="password" id="apiKeyInput" class="form-input" placeholder="jina_..." />
|
|
827
|
+
<div class="form-hint">Get your free API key at <a href="https://jina.ai/" target="_blank">jina.ai</a></div>
|
|
828
|
+
</div>
|
|
829
|
+
<div class="form-actions">
|
|
830
|
+
<button type="button" id="saveEmbeddingBtn" class="btn btn-primary">Save Settings</button>
|
|
831
|
+
<span id="saveStatus" class="save-status"></span>
|
|
832
|
+
</div>
|
|
833
|
+
</div>
|
|
834
|
+
</div>
|
|
835
|
+
|
|
836
|
+
<!-- Configuration Card -->
|
|
837
|
+
<div class="card">
|
|
838
|
+
<div class="card-header">
|
|
839
|
+
<span class="card-title">Configuration</span>
|
|
840
|
+
</div>
|
|
841
|
+
<div class="stat">
|
|
842
|
+
<div class="stat-label">Project Path</div>
|
|
843
|
+
<div class="stat-value small" id="projectPath">-</div>
|
|
844
|
+
</div>
|
|
845
|
+
<div class="stat">
|
|
846
|
+
<div class="stat-label">Chunk Size</div>
|
|
847
|
+
<div class="stat-value small" id="chunkSize">-</div>
|
|
848
|
+
</div>
|
|
849
|
+
<div class="stat">
|
|
850
|
+
<div class="stat-label">Search Weights</div>
|
|
851
|
+
<div class="stat-value small" id="searchWeights">-</div>
|
|
852
|
+
</div>
|
|
853
|
+
</div>
|
|
854
|
+
|
|
855
|
+
<!-- Patterns Card -->
|
|
856
|
+
<div class="card">
|
|
857
|
+
<div class="card-header">
|
|
858
|
+
<span class="card-title">File Patterns</span>
|
|
859
|
+
</div>
|
|
860
|
+
<div class="stat">
|
|
861
|
+
<div class="stat-label">Include</div>
|
|
862
|
+
<div class="patterns-list" id="includePatterns">
|
|
863
|
+
<span class="pattern-tag">Loading...</span>
|
|
864
|
+
</div>
|
|
865
|
+
</div>
|
|
866
|
+
<div class="stat" style="margin-top: 12px;">
|
|
867
|
+
<div class="stat-label">Exclude</div>
|
|
868
|
+
<div class="patterns-list" id="excludePatterns">
|
|
869
|
+
<span class="pattern-tag exclude">Loading...</span>
|
|
870
|
+
</div>
|
|
871
|
+
</div>
|
|
872
|
+
</div>
|
|
873
|
+
|
|
874
|
+
<!-- Command Usage Card -->
|
|
875
|
+
<div class="card double-width">
|
|
876
|
+
<div class="card-header">
|
|
877
|
+
<span class="card-title">Command Usage</span>
|
|
878
|
+
<span class="badge" id="sessionBadge">This Session</span>
|
|
879
|
+
</div>
|
|
880
|
+
<div id="usageChartContainer">
|
|
881
|
+
<div class="usage-empty" id="usageEmpty">No commands executed yet</div>
|
|
882
|
+
<div id="chartWrapper">
|
|
883
|
+
<table class="charts-css column show-labels show-primary-axis show-data data-spacing-20" id="usage-chart" style="display: none;">
|
|
884
|
+
<tbody id="usageChartBody"></tbody>
|
|
885
|
+
</table>
|
|
886
|
+
</div>
|
|
887
|
+
<ul class="charts-css legend legend-inline legend-square" id="chartLegend" style="display: none;">
|
|
888
|
+
<li style="--color: #58a6ff;">Search Code</li>
|
|
889
|
+
<li style="--color: #3fb950;">Index Codebase</li>
|
|
890
|
+
<li style="--color: #a371f7;">Get Status</li>
|
|
891
|
+
<li style="--color: #f85149;">Clear Index</li>
|
|
892
|
+
<li style="--color: #d29922;">Get Instructions</li>
|
|
893
|
+
</ul>
|
|
894
|
+
<div class="usage-total" id="usageTotal" style="display: none;">
|
|
895
|
+
<span class="usage-total-label">Total Commands</span>
|
|
896
|
+
<span class="usage-total-count" id="totalCount">0</span>
|
|
897
|
+
</div>
|
|
898
|
+
</div>
|
|
899
|
+
</div>
|
|
900
|
+
</div>
|
|
901
|
+
|
|
902
|
+
<!-- Beads Section -->
|
|
903
|
+
<div class="beads-section" id="beadsSection" style="display: none;">
|
|
904
|
+
<div class="beads-header">
|
|
905
|
+
<svg class="beads-logo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
906
|
+
<circle cx="12" cy="5" r="3"/>
|
|
907
|
+
<circle cx="12" cy="12" r="3"/>
|
|
908
|
+
<circle cx="12" cy="19" r="3"/>
|
|
909
|
+
<line x1="12" y1="8" x2="12" y2="9"/>
|
|
910
|
+
<line x1="12" y1="15" x2="12" y2="16"/>
|
|
911
|
+
</svg>
|
|
912
|
+
<span class="beads-title">Beads Issue Tracker</span>
|
|
913
|
+
</div>
|
|
914
|
+
<div class="grid">
|
|
915
|
+
<div class="card">
|
|
916
|
+
<div class="card-header">
|
|
917
|
+
<span class="card-title">Status</span>
|
|
918
|
+
<span class="badge success" id="beadsBadge">Active</span>
|
|
919
|
+
</div>
|
|
920
|
+
<div class="beads-stats">
|
|
921
|
+
<div class="beads-stat">
|
|
922
|
+
<span class="beads-stat-value" id="beadsReadyCount">0</span>
|
|
923
|
+
<span class="beads-stat-label">Ready</span>
|
|
924
|
+
</div>
|
|
925
|
+
<div class="beads-stat">
|
|
926
|
+
<span class="beads-stat-value" id="beadsOpenCount">0</span>
|
|
927
|
+
<span class="beads-stat-label">Open</span>
|
|
928
|
+
</div>
|
|
929
|
+
<div class="beads-stat">
|
|
930
|
+
<span class="beads-stat-value" id="beadsTotalCount">0</span>
|
|
931
|
+
<span class="beads-stat-label">Total</span>
|
|
932
|
+
</div>
|
|
933
|
+
</div>
|
|
934
|
+
<div class="beads-daemon-status" id="beadsDaemonStatus">
|
|
935
|
+
<div class="status-dot" id="beadsDaemonDot"></div>
|
|
936
|
+
<span id="beadsDaemonText">Daemon status unknown</span>
|
|
937
|
+
</div>
|
|
938
|
+
<div class="stat" style="margin-top: 12px;" id="beadsSyncBranchStat">
|
|
939
|
+
<div class="stat-label">Sync Branch</div>
|
|
940
|
+
<div class="stat-value small" id="beadsSyncBranch">-</div>
|
|
941
|
+
</div>
|
|
942
|
+
</div>
|
|
943
|
+
|
|
944
|
+
<div class="card" style="grid-column: span 2;">
|
|
945
|
+
<div class="card-header">
|
|
946
|
+
<span class="card-title">Ready Tasks</span>
|
|
947
|
+
<span class="badge" id="readyTasksBadge">0 tasks</span>
|
|
948
|
+
</div>
|
|
949
|
+
<div class="beads-issues" id="beadsIssuesList">
|
|
950
|
+
<div class="beads-empty">No ready tasks</div>
|
|
951
|
+
</div>
|
|
952
|
+
</div>
|
|
953
|
+
</div>
|
|
954
|
+
</div>
|
|
955
|
+
</div>
|
|
956
|
+
|
|
957
|
+
<script>
|
|
958
|
+
// Theme management
|
|
959
|
+
function getStoredTheme() {
|
|
960
|
+
return localStorage.getItem('lance-context-theme') || 'dark';
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
function setTheme(theme) {
|
|
964
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
965
|
+
localStorage.setItem('lance-context-theme', theme);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function toggleTheme() {
|
|
969
|
+
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
970
|
+
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
|
971
|
+
setTheme(newTheme);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
// Initialize theme
|
|
975
|
+
setTheme(getStoredTheme());
|
|
976
|
+
|
|
977
|
+
// Theme toggle button
|
|
978
|
+
document.getElementById('themeToggle').addEventListener('click', toggleTheme);
|
|
979
|
+
|
|
980
|
+
// State
|
|
981
|
+
let isConnected = false;
|
|
982
|
+
let eventSource = null;
|
|
983
|
+
|
|
984
|
+
// DOM elements
|
|
985
|
+
const connectionDot = document.getElementById('connectionDot');
|
|
986
|
+
const connectionText = document.getElementById('connectionText');
|
|
987
|
+
const versionBadge = document.getElementById('versionBadge');
|
|
988
|
+
const indexBadge = document.getElementById('indexBadge');
|
|
989
|
+
const fileCount = document.getElementById('fileCount');
|
|
990
|
+
const chunkCount = document.getElementById('chunkCount');
|
|
991
|
+
const lastUpdated = document.getElementById('lastUpdated');
|
|
992
|
+
const embeddingBackend = document.getElementById('embeddingBackend');
|
|
993
|
+
const embeddingStatus = document.getElementById('embeddingStatus');
|
|
994
|
+
const indexPath = document.getElementById('indexPath');
|
|
995
|
+
const projectPath = document.getElementById('projectPath');
|
|
996
|
+
const chunkSize = document.getElementById('chunkSize');
|
|
997
|
+
const searchWeights = document.getElementById('searchWeights');
|
|
998
|
+
const includePatterns = document.getElementById('includePatterns');
|
|
999
|
+
const excludePatterns = document.getElementById('excludePatterns');
|
|
1000
|
+
const progressContainer = document.getElementById('progressContainer');
|
|
1001
|
+
const progressFill = document.getElementById('progressFill');
|
|
1002
|
+
const progressText = document.getElementById('progressText');
|
|
1003
|
+
|
|
1004
|
+
// Embedding settings form elements
|
|
1005
|
+
const backendSelect = document.getElementById('backendSelect');
|
|
1006
|
+
const apiKeyGroup = document.getElementById('apiKeyGroup');
|
|
1007
|
+
const apiKeyInput = document.getElementById('apiKeyInput');
|
|
1008
|
+
const saveEmbeddingBtn = document.getElementById('saveEmbeddingBtn');
|
|
1009
|
+
const saveStatus = document.getElementById('saveStatus');
|
|
1010
|
+
|
|
1011
|
+
// Toggle API key input visibility based on backend selection
|
|
1012
|
+
backendSelect.addEventListener('change', function() {
|
|
1013
|
+
apiKeyGroup.style.display = this.value === 'jina' ? 'block' : 'none';
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
// Load current embedding settings
|
|
1017
|
+
async function loadEmbeddingSettings() {
|
|
1018
|
+
try {
|
|
1019
|
+
const response = await fetch('/api/settings/embedding');
|
|
1020
|
+
if (response.ok) {
|
|
1021
|
+
const settings = await response.json();
|
|
1022
|
+
backendSelect.value = settings.backend || 'auto';
|
|
1023
|
+
apiKeyGroup.style.display = settings.backend === 'jina' ? 'block' : 'none';
|
|
1024
|
+
|
|
1025
|
+
// Update status badge
|
|
1026
|
+
if (settings.hasApiKey) {
|
|
1027
|
+
embeddingStatus.textContent = 'API Key Set';
|
|
1028
|
+
embeddingStatus.className = 'badge success';
|
|
1029
|
+
} else if (settings.backend === 'ollama') {
|
|
1030
|
+
embeddingStatus.textContent = 'Local';
|
|
1031
|
+
embeddingStatus.className = 'badge';
|
|
1032
|
+
} else {
|
|
1033
|
+
embeddingStatus.textContent = 'Not Configured';
|
|
1034
|
+
embeddingStatus.className = 'badge warning';
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
} catch (error) {
|
|
1038
|
+
console.error('Failed to load embedding settings:', error);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// Save embedding settings
|
|
1043
|
+
saveEmbeddingBtn.addEventListener('click', async function() {
|
|
1044
|
+
const backend = backendSelect.value;
|
|
1045
|
+
const apiKey = apiKeyInput.value.trim();
|
|
1046
|
+
|
|
1047
|
+
if (backend === 'jina' && !apiKey) {
|
|
1048
|
+
saveStatus.textContent = 'API key required for Jina';
|
|
1049
|
+
saveStatus.className = 'save-status error';
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
saveEmbeddingBtn.disabled = true;
|
|
1054
|
+
saveStatus.textContent = 'Saving...';
|
|
1055
|
+
saveStatus.className = 'save-status';
|
|
1056
|
+
|
|
1057
|
+
try {
|
|
1058
|
+
const response = await fetch('/api/settings/embedding', {
|
|
1059
|
+
method: 'POST',
|
|
1060
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1061
|
+
body: JSON.stringify({
|
|
1062
|
+
backend: backend === 'auto' ? 'ollama' : backend,
|
|
1063
|
+
apiKey: backend === 'jina' ? apiKey : undefined
|
|
1064
|
+
})
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
const result = await response.json();
|
|
1068
|
+
|
|
1069
|
+
if (response.ok) {
|
|
1070
|
+
saveStatus.textContent = 'Saved! Restart server to apply.';
|
|
1071
|
+
saveStatus.className = 'save-status success';
|
|
1072
|
+
apiKeyInput.value = ''; // Clear the input
|
|
1073
|
+
loadEmbeddingSettings(); // Reload to update status
|
|
1074
|
+
} else {
|
|
1075
|
+
saveStatus.textContent = result.error || 'Failed to save';
|
|
1076
|
+
saveStatus.className = 'save-status error';
|
|
1077
|
+
}
|
|
1078
|
+
} catch (error) {
|
|
1079
|
+
saveStatus.textContent = 'Network error';
|
|
1080
|
+
saveStatus.className = 'save-status error';
|
|
1081
|
+
} finally {
|
|
1082
|
+
saveEmbeddingBtn.disabled = false;
|
|
1083
|
+
}
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// Load embedding settings on page load
|
|
1087
|
+
loadEmbeddingSettings();
|
|
1088
|
+
|
|
1089
|
+
// Format date
|
|
1090
|
+
function formatDate(isoString) {
|
|
1091
|
+
if (!isoString) return 'Never';
|
|
1092
|
+
const date = new Date(isoString);
|
|
1093
|
+
return date.toLocaleString();
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// Update connection status
|
|
1097
|
+
function setConnected(connected) {
|
|
1098
|
+
isConnected = connected;
|
|
1099
|
+
connectionDot.className = 'status-dot' + (connected ? ' connected' : '');
|
|
1100
|
+
connectionText.textContent = connected ? 'Connected' : 'Disconnected';
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
// Update index status
|
|
1104
|
+
function updateStatus(status) {
|
|
1105
|
+
if (status.indexed) {
|
|
1106
|
+
indexBadge.textContent = 'Indexed';
|
|
1107
|
+
indexBadge.className = 'badge success';
|
|
1108
|
+
} else {
|
|
1109
|
+
indexBadge.textContent = 'Not Indexed';
|
|
1110
|
+
indexBadge.className = 'badge warning';
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if (status.isIndexing) {
|
|
1114
|
+
indexBadge.textContent = 'Indexing...';
|
|
1115
|
+
indexBadge.className = 'badge warning pulsing';
|
|
1116
|
+
progressContainer.className = 'progress-container active';
|
|
1117
|
+
} else {
|
|
1118
|
+
progressContainer.className = 'progress-container';
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
fileCount.textContent = status.fileCount.toLocaleString();
|
|
1122
|
+
chunkCount.textContent = status.chunkCount.toLocaleString();
|
|
1123
|
+
lastUpdated.textContent = formatDate(status.lastUpdated);
|
|
1124
|
+
embeddingBackend.textContent = status.embeddingBackend || 'Not configured';
|
|
1125
|
+
indexPath.textContent = status.indexPath || '-';
|
|
1126
|
+
|
|
1127
|
+
// Update version badge
|
|
1128
|
+
if (status.version) {
|
|
1129
|
+
versionBadge.textContent = 'v' + status.version;
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// Update config display
|
|
1134
|
+
function updateConfig(config) {
|
|
1135
|
+
projectPath.textContent = config.projectPath || '-';
|
|
1136
|
+
|
|
1137
|
+
if (config.chunking) {
|
|
1138
|
+
chunkSize.textContent = config.chunking.maxLines + ' lines (overlap: ' + config.chunking.overlap + ')';
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
if (config.search) {
|
|
1142
|
+
searchWeights.textContent = 'Semantic: ' + (config.search.semanticWeight * 100) + '%, Keyword: ' + (config.search.keywordWeight * 100) + '%';
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// Update patterns
|
|
1146
|
+
if (config.patterns) {
|
|
1147
|
+
includePatterns.innerHTML = config.patterns
|
|
1148
|
+
.slice(0, 10)
|
|
1149
|
+
.map(p => '<span class="pattern-tag">' + escapeHtml(p) + '</span>')
|
|
1150
|
+
.join('');
|
|
1151
|
+
if (config.patterns.length > 10) {
|
|
1152
|
+
includePatterns.innerHTML += '<span class="pattern-tag">+' + (config.patterns.length - 10) + ' more</span>';
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
if (config.excludePatterns) {
|
|
1157
|
+
excludePatterns.innerHTML = config.excludePatterns
|
|
1158
|
+
.slice(0, 6)
|
|
1159
|
+
.map(p => '<span class="pattern-tag exclude">' + escapeHtml(p) + '</span>')
|
|
1160
|
+
.join('');
|
|
1161
|
+
if (config.excludePatterns.length > 6) {
|
|
1162
|
+
excludePatterns.innerHTML += '<span class="pattern-tag exclude">+' + (config.excludePatterns.length - 6) + ' more</span>';
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
// Update progress
|
|
1168
|
+
function updateProgress(progress) {
|
|
1169
|
+
const percent = progress.total > 0 ? Math.round((progress.current / progress.total) * 100) : 0;
|
|
1170
|
+
progressFill.style.width = percent + '%';
|
|
1171
|
+
progressText.textContent = progress.message;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// Charts.css color mapping
|
|
1175
|
+
const commandColors = {
|
|
1176
|
+
'search_code': '#58a6ff',
|
|
1177
|
+
'search_similar': '#79c0ff',
|
|
1178
|
+
'index_codebase': '#3fb950',
|
|
1179
|
+
'get_index_status': '#a371f7',
|
|
1180
|
+
'clear_index': '#f85149',
|
|
1181
|
+
'get_project_instructions': '#d29922',
|
|
1182
|
+
'commit': '#56d364'
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
// Update usage chart using charts.css
|
|
1186
|
+
const usageEmpty = document.getElementById('usageEmpty');
|
|
1187
|
+
const usageChartEl = document.getElementById('usage-chart');
|
|
1188
|
+
const usageChartBody = document.getElementById('usageChartBody');
|
|
1189
|
+
const chartLegend = document.getElementById('chartLegend');
|
|
1190
|
+
const usageTotal = document.getElementById('usageTotal');
|
|
1191
|
+
const totalCount = document.getElementById('totalCount');
|
|
1192
|
+
|
|
1193
|
+
function updateUsage(data) {
|
|
1194
|
+
const { usage, total } = data;
|
|
1195
|
+
|
|
1196
|
+
if (total === 0) {
|
|
1197
|
+
usageEmpty.style.display = 'block';
|
|
1198
|
+
usageChartEl.style.display = 'none';
|
|
1199
|
+
chartLegend.style.display = 'none';
|
|
1200
|
+
usageTotal.style.display = 'none';
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
usageEmpty.style.display = 'none';
|
|
1205
|
+
usageChartEl.style.display = 'block';
|
|
1206
|
+
chartLegend.style.display = 'flex';
|
|
1207
|
+
usageTotal.style.display = 'flex';
|
|
1208
|
+
|
|
1209
|
+
const maxCount = Math.max(...usage.map(u => u.count));
|
|
1210
|
+
|
|
1211
|
+
let html = '';
|
|
1212
|
+
for (const item of usage) {
|
|
1213
|
+
if (item.count === 0) continue;
|
|
1214
|
+
|
|
1215
|
+
const percent = maxCount > 0 ? (item.count / maxCount) : 0;
|
|
1216
|
+
const color = commandColors[item.command] || '#58a6ff';
|
|
1217
|
+
|
|
1218
|
+
html += '<tr>';
|
|
1219
|
+
html += '<th scope="row">' + escapeHtml(item.label) + '</th>';
|
|
1220
|
+
html += '<td style="--size: ' + percent + '; --color: ' + color + ';"><span class="data">' + item.count + '</span></td>';
|
|
1221
|
+
html += '</tr>';
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
usageChartBody.innerHTML = html;
|
|
1225
|
+
totalCount.textContent = total;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// Beads section elements
|
|
1229
|
+
const beadsSection = document.getElementById('beadsSection');
|
|
1230
|
+
const beadsReadyCount = document.getElementById('beadsReadyCount');
|
|
1231
|
+
const beadsOpenCount = document.getElementById('beadsOpenCount');
|
|
1232
|
+
const beadsTotalCount = document.getElementById('beadsTotalCount');
|
|
1233
|
+
const beadsDaemonDot = document.getElementById('beadsDaemonDot');
|
|
1234
|
+
const beadsDaemonText = document.getElementById('beadsDaemonText');
|
|
1235
|
+
const beadsSyncBranch = document.getElementById('beadsSyncBranch');
|
|
1236
|
+
const beadsIssuesList = document.getElementById('beadsIssuesList');
|
|
1237
|
+
const readyTasksBadge = document.getElementById('readyTasksBadge');
|
|
1238
|
+
|
|
1239
|
+
function updateBeads(data) {
|
|
1240
|
+
if (!data.available) {
|
|
1241
|
+
beadsSection.style.display = 'none';
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
beadsSection.style.display = 'block';
|
|
1246
|
+
beadsReadyCount.textContent = data.readyCount;
|
|
1247
|
+
beadsOpenCount.textContent = data.openCount;
|
|
1248
|
+
beadsTotalCount.textContent = data.issueCount;
|
|
1249
|
+
readyTasksBadge.textContent = data.readyCount + ' task' + (data.readyCount !== 1 ? 's' : '');
|
|
1250
|
+
|
|
1251
|
+
// Daemon status
|
|
1252
|
+
if (data.daemonRunning) {
|
|
1253
|
+
beadsDaemonDot.className = 'status-dot connected';
|
|
1254
|
+
beadsDaemonText.textContent = 'Daemon running';
|
|
1255
|
+
} else {
|
|
1256
|
+
beadsDaemonDot.className = 'status-dot';
|
|
1257
|
+
beadsDaemonText.textContent = 'Daemon not running';
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// Sync branch
|
|
1261
|
+
beadsSyncBranch.textContent = data.syncBranch || 'Not configured';
|
|
1262
|
+
|
|
1263
|
+
// Issues list
|
|
1264
|
+
if (data.issues && data.issues.length > 0) {
|
|
1265
|
+
let html = '';
|
|
1266
|
+
for (const issue of data.issues) {
|
|
1267
|
+
const hasDescription = issue.description && issue.description.trim();
|
|
1268
|
+
html += '<div class="beads-issue" onclick="toggleBeadsIssue(this)">';
|
|
1269
|
+
html += '<span class="beads-issue-id">' + escapeHtml(issue.id) + '</span>';
|
|
1270
|
+
html += '<div class="beads-issue-content">';
|
|
1271
|
+
html += '<div class="beads-issue-title">';
|
|
1272
|
+
html += '<svg class="beads-issue-expand" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18l6-6-6-6"/></svg>';
|
|
1273
|
+
html += '<span>' + escapeHtml(issue.title) + '</span>';
|
|
1274
|
+
html += '</div>';
|
|
1275
|
+
html += '<div class="beads-issue-meta">';
|
|
1276
|
+
if (issue.issue_type) {
|
|
1277
|
+
html += '<span class="beads-issue-type">' + escapeHtml(issue.issue_type) + '</span>';
|
|
1278
|
+
}
|
|
1279
|
+
if (issue.priority) {
|
|
1280
|
+
html += '<span class="beads-issue-priority">';
|
|
1281
|
+
html += '<span class="priority-dot priority-' + issue.priority + '"></span>';
|
|
1282
|
+
html += 'P' + issue.priority;
|
|
1283
|
+
html += '</span>';
|
|
1284
|
+
}
|
|
1285
|
+
html += '</div>';
|
|
1286
|
+
if (hasDescription) {
|
|
1287
|
+
html += '<div class="beads-issue-description">' + escapeHtml(issue.description) + '</div>';
|
|
1288
|
+
} else {
|
|
1289
|
+
html += '<div class="beads-issue-description beads-issue-no-description">No description available</div>';
|
|
1290
|
+
}
|
|
1291
|
+
html += '</div>';
|
|
1292
|
+
html += '</div>';
|
|
1293
|
+
}
|
|
1294
|
+
beadsIssuesList.innerHTML = html;
|
|
1295
|
+
} else {
|
|
1296
|
+
beadsIssuesList.innerHTML = '<div class="beads-empty">No ready tasks</div>';
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// Toggle beads issue expansion
|
|
1301
|
+
function toggleBeadsIssue(element) {
|
|
1302
|
+
element.classList.toggle('expanded');
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// Escape HTML to prevent XSS
|
|
1306
|
+
function escapeHtml(text) {
|
|
1307
|
+
const div = document.createElement('div');
|
|
1308
|
+
div.textContent = text;
|
|
1309
|
+
return div.innerHTML;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
// Fetch initial data
|
|
1313
|
+
async function fetchData() {
|
|
1314
|
+
try {
|
|
1315
|
+
const [statusRes, configRes, usageRes, beadsRes] = await Promise.all([
|
|
1316
|
+
fetch('/api/status'),
|
|
1317
|
+
fetch('/api/config'),
|
|
1318
|
+
fetch('/api/usage'),
|
|
1319
|
+
fetch('/api/beads')
|
|
1320
|
+
]);
|
|
1321
|
+
|
|
1322
|
+
let currentStatus = null;
|
|
1323
|
+
let currentConfig = null;
|
|
1324
|
+
|
|
1325
|
+
if (statusRes.ok) {
|
|
1326
|
+
currentStatus = await statusRes.json();
|
|
1327
|
+
updateStatus(currentStatus);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
if (configRes.ok) {
|
|
1331
|
+
currentConfig = await configRes.json();
|
|
1332
|
+
updateConfig(currentConfig);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// Check if configured backend differs from running backend
|
|
1336
|
+
if (currentStatus && currentConfig) {
|
|
1337
|
+
const runningBackend = currentStatus.embeddingBackend;
|
|
1338
|
+
const configuredBackend = currentConfig.embedding?.backend;
|
|
1339
|
+
if (configuredBackend && runningBackend && configuredBackend !== runningBackend) {
|
|
1340
|
+
embeddingBackend.innerHTML = runningBackend + ' <span class="badge warning" title="Restart required to use ' + configuredBackend + '">\u26a0 restart needed</span>';
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
if (usageRes.ok) {
|
|
1345
|
+
const usage = await usageRes.json();
|
|
1346
|
+
updateUsage(usage);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
if (beadsRes.ok) {
|
|
1350
|
+
const beads = await beadsRes.json();
|
|
1351
|
+
updateBeads(beads);
|
|
1352
|
+
}
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
console.error('Failed to fetch data:', error);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// Connect to SSE
|
|
1359
|
+
function connectSSE() {
|
|
1360
|
+
if (eventSource) {
|
|
1361
|
+
eventSource.close();
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
eventSource = new EventSource('/api/events');
|
|
1365
|
+
|
|
1366
|
+
eventSource.addEventListener('connected', (e) => {
|
|
1367
|
+
setConnected(true);
|
|
1368
|
+
fetchData();
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
eventSource.addEventListener('indexing:progress', (e) => {
|
|
1372
|
+
const progress = JSON.parse(e.data);
|
|
1373
|
+
progressContainer.className = 'progress-container active';
|
|
1374
|
+
indexBadge.textContent = 'Indexing...';
|
|
1375
|
+
indexBadge.className = 'badge warning pulsing';
|
|
1376
|
+
updateProgress(progress);
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
eventSource.addEventListener('indexing:start', () => {
|
|
1380
|
+
progressContainer.className = 'progress-container active';
|
|
1381
|
+
indexBadge.textContent = 'Indexing...';
|
|
1382
|
+
indexBadge.className = 'badge warning pulsing';
|
|
1383
|
+
progressFill.style.width = '0%';
|
|
1384
|
+
progressText.textContent = 'Starting...';
|
|
1385
|
+
});
|
|
1386
|
+
|
|
1387
|
+
eventSource.addEventListener('indexing:complete', () => {
|
|
1388
|
+
progressContainer.className = 'progress-container';
|
|
1389
|
+
fetchData();
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
eventSource.addEventListener('status:change', (e) => {
|
|
1393
|
+
const status = JSON.parse(e.data);
|
|
1394
|
+
updateStatus(status);
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
eventSource.addEventListener('usage:update', (e) => {
|
|
1398
|
+
const usage = JSON.parse(e.data);
|
|
1399
|
+
// The event data is the usage array, need to compute total
|
|
1400
|
+
const total = usage.reduce((sum, u) => sum + u.count, 0);
|
|
1401
|
+
updateUsage({ usage, total });
|
|
1402
|
+
});
|
|
1403
|
+
|
|
1404
|
+
eventSource.addEventListener('heartbeat', () => {
|
|
1405
|
+
// Just keep connection alive
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
eventSource.onerror = () => {
|
|
1409
|
+
setConnected(false);
|
|
1410
|
+
// EventSource will automatically reconnect
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// Initialize
|
|
1415
|
+
fetchData();
|
|
1416
|
+
connectSSE();
|
|
1417
|
+
</script>
|
|
1418
|
+
</body>
|
|
1419
|
+
</html>`;
|
|
1420
|
+
}
|
|
1421
|
+
//# sourceMappingURL=ui.js.map
|