gitnexus 1.2.6 → 1.2.7

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.
@@ -100,198 +100,198 @@ const BOOK_SVG = '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" st
100
100
  '<path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/>' +
101
101
  '<path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/>' +
102
102
  '</svg>';
103
- const CSS = `
104
- *{margin:0;padding:0;box-sizing:border-box}
105
- :root{
106
- --bg:#ffffff;--sidebar-bg:#f8f9fb;--border:#e5e7eb;
107
- --text:#1e293b;--text-muted:#64748b;--primary:#2563eb;
108
- --primary-soft:#eff6ff;--hover:#f1f5f9;--code-bg:#f1f5f9;
109
- --radius:8px;--shadow:0 1px 3px rgba(0,0,0,.08);
110
- }
111
- body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
112
- line-height:1.65;color:var(--text);background:var(--bg)}
113
-
114
- .layout{display:flex;min-height:100vh}
115
- .sidebar{width:280px;background:var(--sidebar-bg);border-right:1px solid var(--border);
116
- position:fixed;top:0;left:0;bottom:0;overflow-y:auto;padding:24px 16px;
117
- display:flex;flex-direction:column;z-index:10}
118
- .content{margin-left:280px;flex:1;padding:48px 64px;max-width:960px}
119
-
120
- .sidebar-header{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid var(--border)}
121
- .sidebar-title{font-size:16px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px}
122
- .sidebar-title svg{flex-shrink:0}
123
- .sidebar-meta{font-size:11px;color:var(--text-muted);margin-top:6px}
124
- .nav-section{margin-bottom:2px}
125
- .nav-item{display:block;padding:7px 12px;border-radius:var(--radius);cursor:pointer;
126
- font-size:13px;color:var(--text);text-decoration:none;transition:all .15s;
127
- white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
128
- .nav-item:hover{background:var(--hover)}
129
- .nav-item.active{background:var(--primary-soft);color:var(--primary);font-weight:600}
130
- .nav-item.overview{font-weight:600;margin-bottom:4px}
131
- .nav-children{padding-left:14px;border-left:1px solid var(--border);margin-left:12px}
132
- .nav-group-label{font-size:11px;font-weight:600;color:var(--text-muted);
133
- text-transform:uppercase;letter-spacing:.5px;padding:12px 12px 4px;user-select:none}
134
- .sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);
135
- font-size:11px;color:var(--text-muted);text-align:center}
136
-
137
- .content h1{font-size:28px;font-weight:700;margin-bottom:8px;line-height:1.3}
138
- .content h2{font-size:22px;font-weight:600;margin:32px 0 12px;padding-bottom:6px;border-bottom:1px solid var(--border)}
139
- .content h3{font-size:17px;font-weight:600;margin:24px 0 8px}
140
- .content h4{font-size:15px;font-weight:600;margin:20px 0 6px}
141
- .content p{margin:12px 0}
142
- .content ul,.content ol{margin:12px 0 12px 24px}
143
- .content li{margin:4px 0}
144
- .content a{color:var(--primary);text-decoration:none}
145
- .content a:hover{text-decoration:underline}
146
- .content blockquote{border-left:3px solid var(--primary);padding:8px 16px;margin:16px 0;
147
- background:var(--primary-soft);border-radius:0 var(--radius) var(--radius) 0;
148
- color:var(--text-muted);font-size:14px}
149
- .content code{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:13px;
150
- background:var(--code-bg);padding:2px 6px;border-radius:4px}
151
- .content pre{background:#1e293b;color:#e2e8f0;border-radius:var(--radius);padding:16px;
152
- overflow-x:auto;margin:16px 0}
153
- .content pre code{background:none;padding:0;font-size:13px;line-height:1.6;color:inherit}
154
- .content table{border-collapse:collapse;width:100%;margin:16px 0}
155
- .content th,.content td{border:1px solid var(--border);padding:8px 12px;text-align:left;font-size:14px}
156
- .content th{background:var(--sidebar-bg);font-weight:600}
157
- .content img{max-width:100%;border-radius:var(--radius)}
158
- .content hr{border:none;border-top:1px solid var(--border);margin:32px 0}
159
- .content .mermaid{margin:20px 0;text-align:center}
160
-
161
- .menu-toggle{display:none;position:fixed;top:12px;left:12px;z-index:20;
162
- background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);
163
- padding:8px 12px;cursor:pointer;font-size:18px;box-shadow:var(--shadow)}
164
- @media(max-width:768px){
165
- .sidebar{transform:translateX(-100%);transition:transform .2s}
166
- .sidebar.open{transform:translateX(0);box-shadow:2px 0 12px rgba(0,0,0,.1)}
167
- .content{margin-left:0;padding:24px 20px;padding-top:56px}
168
- .menu-toggle{display:block}
169
- }
170
- .empty-state{text-align:center;padding:80px 20px;color:var(--text-muted)}
171
- .empty-state h2{font-size:20px;margin-bottom:8px;border:none}
103
+ const CSS = `
104
+ *{margin:0;padding:0;box-sizing:border-box}
105
+ :root{
106
+ --bg:#ffffff;--sidebar-bg:#f8f9fb;--border:#e5e7eb;
107
+ --text:#1e293b;--text-muted:#64748b;--primary:#2563eb;
108
+ --primary-soft:#eff6ff;--hover:#f1f5f9;--code-bg:#f1f5f9;
109
+ --radius:8px;--shadow:0 1px 3px rgba(0,0,0,.08);
110
+ }
111
+ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
112
+ line-height:1.65;color:var(--text);background:var(--bg)}
113
+
114
+ .layout{display:flex;min-height:100vh}
115
+ .sidebar{width:280px;background:var(--sidebar-bg);border-right:1px solid var(--border);
116
+ position:fixed;top:0;left:0;bottom:0;overflow-y:auto;padding:24px 16px;
117
+ display:flex;flex-direction:column;z-index:10}
118
+ .content{margin-left:280px;flex:1;padding:48px 64px;max-width:960px}
119
+
120
+ .sidebar-header{margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid var(--border)}
121
+ .sidebar-title{font-size:16px;font-weight:700;color:var(--text);display:flex;align-items:center;gap:8px}
122
+ .sidebar-title svg{flex-shrink:0}
123
+ .sidebar-meta{font-size:11px;color:var(--text-muted);margin-top:6px}
124
+ .nav-section{margin-bottom:2px}
125
+ .nav-item{display:block;padding:7px 12px;border-radius:var(--radius);cursor:pointer;
126
+ font-size:13px;color:var(--text);text-decoration:none;transition:all .15s;
127
+ white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
128
+ .nav-item:hover{background:var(--hover)}
129
+ .nav-item.active{background:var(--primary-soft);color:var(--primary);font-weight:600}
130
+ .nav-item.overview{font-weight:600;margin-bottom:4px}
131
+ .nav-children{padding-left:14px;border-left:1px solid var(--border);margin-left:12px}
132
+ .nav-group-label{font-size:11px;font-weight:600;color:var(--text-muted);
133
+ text-transform:uppercase;letter-spacing:.5px;padding:12px 12px 4px;user-select:none}
134
+ .sidebar-footer{margin-top:auto;padding-top:16px;border-top:1px solid var(--border);
135
+ font-size:11px;color:var(--text-muted);text-align:center}
136
+
137
+ .content h1{font-size:28px;font-weight:700;margin-bottom:8px;line-height:1.3}
138
+ .content h2{font-size:22px;font-weight:600;margin:32px 0 12px;padding-bottom:6px;border-bottom:1px solid var(--border)}
139
+ .content h3{font-size:17px;font-weight:600;margin:24px 0 8px}
140
+ .content h4{font-size:15px;font-weight:600;margin:20px 0 6px}
141
+ .content p{margin:12px 0}
142
+ .content ul,.content ol{margin:12px 0 12px 24px}
143
+ .content li{margin:4px 0}
144
+ .content a{color:var(--primary);text-decoration:none}
145
+ .content a:hover{text-decoration:underline}
146
+ .content blockquote{border-left:3px solid var(--primary);padding:8px 16px;margin:16px 0;
147
+ background:var(--primary-soft);border-radius:0 var(--radius) var(--radius) 0;
148
+ color:var(--text-muted);font-size:14px}
149
+ .content code{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:13px;
150
+ background:var(--code-bg);padding:2px 6px;border-radius:4px}
151
+ .content pre{background:#1e293b;color:#e2e8f0;border-radius:var(--radius);padding:16px;
152
+ overflow-x:auto;margin:16px 0}
153
+ .content pre code{background:none;padding:0;font-size:13px;line-height:1.6;color:inherit}
154
+ .content table{border-collapse:collapse;width:100%;margin:16px 0}
155
+ .content th,.content td{border:1px solid var(--border);padding:8px 12px;text-align:left;font-size:14px}
156
+ .content th{background:var(--sidebar-bg);font-weight:600}
157
+ .content img{max-width:100%;border-radius:var(--radius)}
158
+ .content hr{border:none;border-top:1px solid var(--border);margin:32px 0}
159
+ .content .mermaid{margin:20px 0;text-align:center}
160
+
161
+ .menu-toggle{display:none;position:fixed;top:12px;left:12px;z-index:20;
162
+ background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);
163
+ padding:8px 12px;cursor:pointer;font-size:18px;box-shadow:var(--shadow)}
164
+ @media(max-width:768px){
165
+ .sidebar{transform:translateX(-100%);transition:transform .2s}
166
+ .sidebar.open{transform:translateX(0);box-shadow:2px 0 12px rgba(0,0,0,.1)}
167
+ .content{margin-left:0;padding:24px 20px;padding-top:56px}
168
+ .menu-toggle{display:block}
169
+ }
170
+ .empty-state{text-align:center;padding:80px 20px;color:var(--text-muted)}
171
+ .empty-state h2{font-size:20px;margin-bottom:8px;border:none}
172
172
  `;
173
173
  // The client-side JS is kept as a plain string to avoid template literal conflicts
174
- const JS_APP = `
175
- (function() {
176
- var activePage = 'overview';
177
-
178
- document.addEventListener('DOMContentLoaded', function() {
179
- mermaid.initialize({ startOnLoad: false, theme: 'neutral', securityLevel: 'loose' });
180
- renderMeta();
181
- renderNav();
182
- document.getElementById('menu-toggle').addEventListener('click', function() {
183
- document.getElementById('sidebar').classList.toggle('open');
184
- });
185
- if (location.hash && location.hash.length > 1) {
186
- activePage = decodeURIComponent(location.hash.slice(1));
187
- }
188
- navigateTo(activePage);
189
- });
190
-
191
- function renderMeta() {
192
- if (!META) return;
193
- var el = document.getElementById('meta-info');
194
- var parts = [];
195
- if (META.generatedAt) {
196
- parts.push(new Date(META.generatedAt).toLocaleDateString());
197
- }
198
- if (META.model) parts.push(META.model);
199
- if (META.fromCommit) parts.push(META.fromCommit.slice(0, 8));
200
- el.textContent = parts.join(' \\u00b7 ');
201
- }
202
-
203
- function renderNav() {
204
- var container = document.getElementById('nav-tree');
205
- var html = '<div class="nav-section">';
206
- html += '<a class="nav-item overview" data-page="overview" href="#overview">Overview</a>';
207
- html += '</div>';
208
- if (TREE.length > 0) {
209
- html += '<div class="nav-group-label">Modules</div>';
210
- html += buildNavTree(TREE);
211
- }
212
- container.innerHTML = html;
213
- container.addEventListener('click', function(e) {
214
- var target = e.target;
215
- while (target && !target.dataset.page) { target = target.parentElement; }
216
- if (target && target.dataset.page) {
217
- e.preventDefault();
218
- navigateTo(target.dataset.page);
219
- }
220
- });
221
- }
222
-
223
- function buildNavTree(nodes) {
224
- var html = '';
225
- for (var i = 0; i < nodes.length; i++) {
226
- var node = nodes[i];
227
- html += '<div class="nav-section">';
228
- html += '<a class="nav-item" data-page="' + escH(node.slug) + '" href="#' + encodeURIComponent(node.slug) + '">' + escH(node.name) + '</a>';
229
- if (node.children && node.children.length > 0) {
230
- html += '<div class="nav-children">' + buildNavTree(node.children) + '</div>';
231
- }
232
- html += '</div>';
233
- }
234
- return html;
235
- }
236
-
237
- function escH(s) {
238
- var d = document.createElement('div');
239
- d.textContent = s;
240
- return d.innerHTML;
241
- }
242
-
243
- function navigateTo(page) {
244
- activePage = page;
245
- location.hash = encodeURIComponent(page);
246
-
247
- var items = document.querySelectorAll('.nav-item');
248
- for (var i = 0; i < items.length; i++) {
249
- if (items[i].dataset.page === page) {
250
- items[i].classList.add('active');
251
- } else {
252
- items[i].classList.remove('active');
253
- }
254
- }
255
-
256
- var contentEl = document.getElementById('content');
257
- var md = PAGES[page];
258
-
259
- if (!md) {
260
- contentEl.innerHTML = '<div class="empty-state"><h2>Page not found</h2><p>' + escH(page) + '.md does not exist.</p></div>';
261
- return;
262
- }
263
-
264
- contentEl.innerHTML = marked.parse(md);
265
-
266
- // Rewrite .md links to hash navigation
267
- var links = contentEl.querySelectorAll('a[href]');
268
- for (var i = 0; i < links.length; i++) {
269
- var href = links[i].getAttribute('href');
270
- if (href && href.endsWith('.md') && href.indexOf('://') === -1) {
271
- var slug = href.replace(/\\.md$/, '');
272
- links[i].setAttribute('href', '#' + encodeURIComponent(slug));
273
- (function(s) {
274
- links[i].addEventListener('click', function(e) {
275
- e.preventDefault();
276
- navigateTo(s);
277
- });
278
- })(slug);
279
- }
280
- }
281
-
282
- // Convert mermaid code blocks into mermaid divs
283
- var mermaidBlocks = contentEl.querySelectorAll('pre code.language-mermaid');
284
- for (var i = 0; i < mermaidBlocks.length; i++) {
285
- var pre = mermaidBlocks[i].parentElement;
286
- var div = document.createElement('div');
287
- div.className = 'mermaid';
288
- div.textContent = mermaidBlocks[i].textContent;
289
- pre.parentNode.replaceChild(div, pre);
290
- }
291
- try { mermaid.run({ querySelector: '.mermaid' }); } catch(e) {}
292
-
293
- window.scrollTo(0, 0);
294
- document.getElementById('sidebar').classList.remove('open');
295
- }
296
- })();
174
+ const JS_APP = `
175
+ (function() {
176
+ var activePage = 'overview';
177
+
178
+ document.addEventListener('DOMContentLoaded', function() {
179
+ mermaid.initialize({ startOnLoad: false, theme: 'neutral', securityLevel: 'loose' });
180
+ renderMeta();
181
+ renderNav();
182
+ document.getElementById('menu-toggle').addEventListener('click', function() {
183
+ document.getElementById('sidebar').classList.toggle('open');
184
+ });
185
+ if (location.hash && location.hash.length > 1) {
186
+ activePage = decodeURIComponent(location.hash.slice(1));
187
+ }
188
+ navigateTo(activePage);
189
+ });
190
+
191
+ function renderMeta() {
192
+ if (!META) return;
193
+ var el = document.getElementById('meta-info');
194
+ var parts = [];
195
+ if (META.generatedAt) {
196
+ parts.push(new Date(META.generatedAt).toLocaleDateString());
197
+ }
198
+ if (META.model) parts.push(META.model);
199
+ if (META.fromCommit) parts.push(META.fromCommit.slice(0, 8));
200
+ el.textContent = parts.join(' \\u00b7 ');
201
+ }
202
+
203
+ function renderNav() {
204
+ var container = document.getElementById('nav-tree');
205
+ var html = '<div class="nav-section">';
206
+ html += '<a class="nav-item overview" data-page="overview" href="#overview">Overview</a>';
207
+ html += '</div>';
208
+ if (TREE.length > 0) {
209
+ html += '<div class="nav-group-label">Modules</div>';
210
+ html += buildNavTree(TREE);
211
+ }
212
+ container.innerHTML = html;
213
+ container.addEventListener('click', function(e) {
214
+ var target = e.target;
215
+ while (target && !target.dataset.page) { target = target.parentElement; }
216
+ if (target && target.dataset.page) {
217
+ e.preventDefault();
218
+ navigateTo(target.dataset.page);
219
+ }
220
+ });
221
+ }
222
+
223
+ function buildNavTree(nodes) {
224
+ var html = '';
225
+ for (var i = 0; i < nodes.length; i++) {
226
+ var node = nodes[i];
227
+ html += '<div class="nav-section">';
228
+ html += '<a class="nav-item" data-page="' + escH(node.slug) + '" href="#' + encodeURIComponent(node.slug) + '">' + escH(node.name) + '</a>';
229
+ if (node.children && node.children.length > 0) {
230
+ html += '<div class="nav-children">' + buildNavTree(node.children) + '</div>';
231
+ }
232
+ html += '</div>';
233
+ }
234
+ return html;
235
+ }
236
+
237
+ function escH(s) {
238
+ var d = document.createElement('div');
239
+ d.textContent = s;
240
+ return d.innerHTML;
241
+ }
242
+
243
+ function navigateTo(page) {
244
+ activePage = page;
245
+ location.hash = encodeURIComponent(page);
246
+
247
+ var items = document.querySelectorAll('.nav-item');
248
+ for (var i = 0; i < items.length; i++) {
249
+ if (items[i].dataset.page === page) {
250
+ items[i].classList.add('active');
251
+ } else {
252
+ items[i].classList.remove('active');
253
+ }
254
+ }
255
+
256
+ var contentEl = document.getElementById('content');
257
+ var md = PAGES[page];
258
+
259
+ if (!md) {
260
+ contentEl.innerHTML = '<div class="empty-state"><h2>Page not found</h2><p>' + escH(page) + '.md does not exist.</p></div>';
261
+ return;
262
+ }
263
+
264
+ contentEl.innerHTML = marked.parse(md);
265
+
266
+ // Rewrite .md links to hash navigation
267
+ var links = contentEl.querySelectorAll('a[href]');
268
+ for (var i = 0; i < links.length; i++) {
269
+ var href = links[i].getAttribute('href');
270
+ if (href && href.endsWith('.md') && href.indexOf('://') === -1) {
271
+ var slug = href.replace(/\\.md$/, '');
272
+ links[i].setAttribute('href', '#' + encodeURIComponent(slug));
273
+ (function(s) {
274
+ links[i].addEventListener('click', function(e) {
275
+ e.preventDefault();
276
+ navigateTo(s);
277
+ });
278
+ })(slug);
279
+ }
280
+ }
281
+
282
+ // Convert mermaid code blocks into mermaid divs
283
+ var mermaidBlocks = contentEl.querySelectorAll('pre code.language-mermaid');
284
+ for (var i = 0; i < mermaidBlocks.length; i++) {
285
+ var pre = mermaidBlocks[i].parentElement;
286
+ var div = document.createElement('div');
287
+ div.className = 'mermaid';
288
+ div.textContent = mermaidBlocks[i].textContent;
289
+ pre.parentNode.replaceChild(div, pre);
290
+ }
291
+ try { mermaid.run({ querySelector: '.mermaid' }); } catch(e) {}
292
+
293
+ window.scrollTo(0, 0);
294
+ document.getElementById('sidebar').classList.remove('open');
295
+ }
296
+ })();
297
297
  `;
@@ -34,6 +34,12 @@ export declare class LocalBackend {
34
34
  * Returns true if at least one repo is available.
35
35
  */
36
36
  init(): Promise<boolean>;
37
+ /**
38
+ * Re-read the global registry and update the in-memory repo map.
39
+ * New repos are added, existing repos are updated, removed repos are pruned.
40
+ * KuzuDB connections for removed repos are NOT closed (they idle-timeout naturally).
41
+ */
42
+ private refreshRepos;
37
43
  /**
38
44
  * Generate a stable repo ID from name + path.
39
45
  * If names collide, append a hash of the path.
@@ -44,8 +50,15 @@ export declare class LocalBackend {
44
50
  * - If repoParam is given, match by name or path
45
51
  * - If only 1 repo, use it
46
52
  * - If 0 or multiple without param, throw with helpful message
53
+ *
54
+ * On a miss, re-reads the registry once in case a new repo was indexed
55
+ * while the MCP server was running.
47
56
  */
48
- resolveRepo(repoParam?: string): RepoHandle;
57
+ resolveRepo(repoParam?: string): Promise<RepoHandle>;
58
+ /**
59
+ * Try to resolve a repo from the in-memory cache. Returns null on miss.
60
+ */
61
+ private resolveRepoFromCache;
49
62
  private ensureInitialized;
50
63
  /**
51
64
  * Get context for a specific repo (or the single repo if only one).
@@ -53,14 +66,16 @@ export declare class LocalBackend {
53
66
  getContext(repoId?: string): CodebaseContext | null;
54
67
  /**
55
68
  * List all registered repos with their metadata.
69
+ * Re-reads the global registry so newly indexed repos are discovered
70
+ * without restarting the MCP server.
56
71
  */
57
- listRepos(): Array<{
72
+ listRepos(): Promise<Array<{
58
73
  name: string;
59
74
  path: string;
60
75
  indexedAt: string;
61
76
  lastCommit: string;
62
77
  stats?: any;
63
- }>;
78
+ }>>;
64
79
  callTool(method: string, params: any): Promise<any>;
65
80
  /**
66
81
  * Query tool — process-grouped search.