gitmaps 1.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 (121) hide show
  1. package/README.md +167 -0
  2. package/app/api/auth/favorites/route.ts +56 -0
  3. package/app/api/auth/github/callback/route.ts +103 -0
  4. package/app/api/auth/github/route.ts +32 -0
  5. package/app/api/auth/me/route.ts +52 -0
  6. package/app/api/auth/positions/route.ts +50 -0
  7. package/app/api/chat/route.ts +101 -0
  8. package/app/api/connections/route.ts +72 -0
  9. package/app/api/github/repos/route.ts +111 -0
  10. package/app/api/positions/route.ts +80 -0
  11. package/app/api/repo/branch-diff/route.ts +201 -0
  12. package/app/api/repo/branches/route.ts +53 -0
  13. package/app/api/repo/browse/route.ts +55 -0
  14. package/app/api/repo/clone/route.ts +78 -0
  15. package/app/api/repo/clone-stream/route.ts +131 -0
  16. package/app/api/repo/file-content/route.ts +28 -0
  17. package/app/api/repo/file-delete/route.ts +62 -0
  18. package/app/api/repo/file-history/route.ts +45 -0
  19. package/app/api/repo/file-rename/route.ts +83 -0
  20. package/app/api/repo/file-save/route.ts +45 -0
  21. package/app/api/repo/files/route.ts +169 -0
  22. package/app/api/repo/git-blame/route.ts +86 -0
  23. package/app/api/repo/git-commit/route.ts +40 -0
  24. package/app/api/repo/git-heatmap/route.ts +55 -0
  25. package/app/api/repo/imports/route.ts +154 -0
  26. package/app/api/repo/load/route.ts +56 -0
  27. package/app/api/repo/mode/route.ts +14 -0
  28. package/app/api/repo/search/route.ts +127 -0
  29. package/app/api/repo/tree/route.ts +104 -0
  30. package/app/api/repo/upload/route.ts +53 -0
  31. package/app/api/repo/validate-path.ts +53 -0
  32. package/app/canvas_users.db +0 -0
  33. package/app/canvas_users.db-shm +0 -0
  34. package/app/canvas_users.db-wal +0 -0
  35. package/app/globals.css +7899 -0
  36. package/app/layout.tsx +493 -0
  37. package/app/lib/auth.ts +193 -0
  38. package/app/lib/auto-save.ts +137 -0
  39. package/app/lib/branch-compare.ts +443 -0
  40. package/app/lib/breadcrumbs.ts +170 -0
  41. package/app/lib/canvas-export.ts +358 -0
  42. package/app/lib/canvas-text.ts +912 -0
  43. package/app/lib/canvas.ts +564 -0
  44. package/app/lib/card-arrangement.ts +188 -0
  45. package/app/lib/card-context-menu.tsx +453 -0
  46. package/app/lib/card-diff-markers.ts +270 -0
  47. package/app/lib/card-expand.ts +189 -0
  48. package/app/lib/card-groups.ts +246 -0
  49. package/app/lib/cards.tsx +914 -0
  50. package/app/lib/chat.tsx +308 -0
  51. package/app/lib/code-editor.ts +508 -0
  52. package/app/lib/command-palette.ts +262 -0
  53. package/app/lib/connections.tsx +1037 -0
  54. package/app/lib/context.ts +94 -0
  55. package/app/lib/cursor-sharing.ts +281 -0
  56. package/app/lib/dependency-graph.ts +438 -0
  57. package/app/lib/events.tsx +1747 -0
  58. package/app/lib/file-card-plugin.ts +134 -0
  59. package/app/lib/file-modal.tsx +849 -0
  60. package/app/lib/file-preview.ts +400 -0
  61. package/app/lib/file-tabs.ts +318 -0
  62. package/app/lib/galaxydraw-bridge.ts +477 -0
  63. package/app/lib/galaxydraw.test.ts +229 -0
  64. package/app/lib/global-search.ts +264 -0
  65. package/app/lib/goto-definition.ts +224 -0
  66. package/app/lib/heatmap.ts +178 -0
  67. package/app/lib/hidden-files.tsx +222 -0
  68. package/app/lib/layers.ts +0 -0
  69. package/app/lib/layers.tsx +365 -0
  70. package/app/lib/loading.tsx +45 -0
  71. package/app/lib/multi-repo.ts +286 -0
  72. package/app/lib/new-file-dialog.tsx +230 -0
  73. package/app/lib/onboarding.tsx +213 -0
  74. package/app/lib/perf-overlay.ts +360 -0
  75. package/app/lib/positions.ts +176 -0
  76. package/app/lib/pr-review.ts +374 -0
  77. package/app/lib/production-mode.ts +47 -0
  78. package/app/lib/repo.tsx +977 -0
  79. package/app/lib/settings-modal.tsx +374 -0
  80. package/app/lib/settings.ts +97 -0
  81. package/app/lib/shortcuts-panel.ts +141 -0
  82. package/app/lib/status-bar.ts +128 -0
  83. package/app/lib/symbol-outline.ts +212 -0
  84. package/app/lib/syntax.ts +177 -0
  85. package/app/lib/tab-diff.ts +238 -0
  86. package/app/lib/user.tsx +133 -0
  87. package/app/lib/utils.ts +78 -0
  88. package/app/lib/viewport-culling.ts +728 -0
  89. package/app/page.client.tsx +215 -0
  90. package/app/page.tsx +291 -0
  91. package/app/state/machine.js +196 -0
  92. package/app/styles/main.css +2168 -0
  93. package/banner.png +0 -0
  94. package/cli.ts +44 -0
  95. package/package.json +75 -0
  96. package/packages/galaxydraw/README.md +296 -0
  97. package/packages/galaxydraw/banner.png +0 -0
  98. package/packages/galaxydraw/demo/build-static.ts +100 -0
  99. package/packages/galaxydraw/demo/client.ts +154 -0
  100. package/packages/galaxydraw/demo/dist/client.js +8 -0
  101. package/packages/galaxydraw/demo/index.html +256 -0
  102. package/packages/galaxydraw/demo/server.ts +96 -0
  103. package/packages/galaxydraw/dist/index.js +984 -0
  104. package/packages/galaxydraw/dist/index.js.map +16 -0
  105. package/packages/galaxydraw/node_modules/.bin/tsc.bunx +0 -0
  106. package/packages/galaxydraw/node_modules/.bin/tsc.exe +0 -0
  107. package/packages/galaxydraw/node_modules/.bin/tsserver.bunx +0 -0
  108. package/packages/galaxydraw/node_modules/.bin/tsserver.exe +0 -0
  109. package/packages/galaxydraw/package.json +49 -0
  110. package/packages/galaxydraw/perf.test.ts +284 -0
  111. package/packages/galaxydraw/src/core/cards.ts +435 -0
  112. package/packages/galaxydraw/src/core/engine.ts +339 -0
  113. package/packages/galaxydraw/src/core/events.ts +81 -0
  114. package/packages/galaxydraw/src/core/layout.ts +136 -0
  115. package/packages/galaxydraw/src/core/minimap.ts +216 -0
  116. package/packages/galaxydraw/src/core/state.ts +177 -0
  117. package/packages/galaxydraw/src/core/viewport.ts +106 -0
  118. package/packages/galaxydraw/src/galaxydraw.css +166 -0
  119. package/packages/galaxydraw/src/index.ts +40 -0
  120. package/packages/galaxydraw/tsconfig.json +30 -0
  121. package/server.ts +62 -0
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Command Palette — Ctrl+K / Ctrl+P file search with fuzzy matching
3
+ *
4
+ * - Ctrl+K or Ctrl+P opens the palette overlay
5
+ * - Type to fuzzy-search file names
6
+ * - Arrow keys to navigate, Enter to jump, Escape to close
7
+ * - Supports both fileCards (DOM) and deferredCards (virtualized)
8
+ */
9
+ import type { CanvasContext } from './context';
10
+ import { jumpToFile } from './canvas';
11
+
12
+ // ── Fuzzy scoring ────────────────────────────────────────
13
+
14
+ interface SearchResult {
15
+ path: string;
16
+ name: string;
17
+ dir: string;
18
+ score: number;
19
+ matchIndices: number[];
20
+ }
21
+
22
+ function fuzzyMatch(query: string, target: string): { score: number; indices: number[] } | null {
23
+ const q = query.toLowerCase();
24
+ const t = target.toLowerCase();
25
+
26
+ let qi = 0;
27
+ let score = 0;
28
+ const indices: number[] = [];
29
+ let lastMatchIdx = -1;
30
+
31
+ for (let ti = 0; ti < t.length && qi < q.length; ti++) {
32
+ if (t[ti] === q[qi]) {
33
+ indices.push(ti);
34
+ // Consecutive match bonus
35
+ if (lastMatchIdx === ti - 1) score += 10;
36
+ // Start-of-word bonus (after / or . or -)
37
+ if (ti === 0 || '/.-_'.includes(t[ti - 1]!)) score += 8;
38
+ // Exact case match bonus
39
+ if (target[ti] === query[qi]) score += 2;
40
+ score += 1;
41
+ lastMatchIdx = ti;
42
+ qi++;
43
+ }
44
+ }
45
+
46
+ if (qi !== q.length) return null;
47
+
48
+ // Prefer shorter targets (more specific matches)
49
+ score -= target.length * 0.1;
50
+ // Prefer matches in filename over full path
51
+ const nameStart = target.lastIndexOf('/') + 1;
52
+ const nameMatches = indices.filter(i => i >= nameStart).length;
53
+ score += nameMatches * 3;
54
+
55
+ return { score, indices };
56
+ }
57
+
58
+ // ── Palette DOM ──────────────────────────────────────────
59
+
60
+ let overlay: HTMLElement | null = null;
61
+ let input: HTMLInputElement | null = null;
62
+ let resultsList: HTMLElement | null = null;
63
+ let selectedIdx = 0;
64
+ let currentResults: SearchResult[] = [];
65
+ let currentCtx: CanvasContext | null = null;
66
+
67
+ function getAllFiles(ctx: CanvasContext): { path: string; name: string; dir: string; isChanged: boolean }[] {
68
+ const files: { path: string; name: string; dir: string; isChanged: boolean }[] = [];
69
+ const seen = new Set<string>();
70
+
71
+ ctx.fileCards.forEach((_card, path) => {
72
+ seen.add(path);
73
+ const parts = path.split('/');
74
+ const name = parts.pop() || path;
75
+ const dir = parts.join('/');
76
+ files.push({ path, name, dir, isChanged: _card.dataset.changed === 'true' });
77
+ });
78
+
79
+ ctx.deferredCards?.forEach((entry, path) => {
80
+ if (seen.has(path)) return;
81
+ const parts = path.split('/');
82
+ const name = parts.pop() || path;
83
+ const dir = parts.join('/');
84
+ files.push({ path, name, dir, isChanged: !!entry.isChanged });
85
+ });
86
+
87
+ return files;
88
+ }
89
+
90
+ function createOverlay(): void {
91
+ overlay = document.createElement('div');
92
+ overlay.id = 'command-palette-overlay';
93
+ overlay.innerHTML = `
94
+ <div id="command-palette">
95
+ <div class="cp-search">
96
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
97
+ <circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>
98
+ </svg>
99
+ <input type="text" id="cp-input" placeholder="Search files…" autocomplete="off" spellcheck="false" />
100
+ <kbd>esc</kbd>
101
+ </div>
102
+ <div id="cp-results"></div>
103
+ <div id="cp-footer">
104
+ <span><kbd>↑↓</kbd> navigate</span>
105
+ <span><kbd>↵</kbd> jump to file</span>
106
+ <span><kbd>esc</kbd> close</span>
107
+ </div>
108
+ </div>
109
+ `;
110
+ document.body.appendChild(overlay);
111
+
112
+ input = overlay.querySelector('#cp-input') as HTMLInputElement;
113
+ resultsList = overlay.querySelector('#cp-results') as HTMLElement;
114
+
115
+ // Close on backdrop click
116
+ overlay.addEventListener('mousedown', (e) => {
117
+ if (e.target === overlay) close();
118
+ });
119
+
120
+ input.addEventListener('input', onInput);
121
+ input.addEventListener('keydown', onKeyDown);
122
+ }
123
+
124
+ function highlightText(text: string, indices: number[]): string {
125
+ const chars = text.split('');
126
+ const set = new Set(indices);
127
+ return chars.map((ch, i) => set.has(i) ? `<mark>${ch}</mark>` : ch).join('');
128
+ }
129
+
130
+ function renderResults(): void {
131
+ if (!resultsList) return;
132
+
133
+ if (currentResults.length === 0 && input?.value) {
134
+ resultsList.innerHTML = '<div class="cp-empty">No files found</div>';
135
+ return;
136
+ }
137
+
138
+ resultsList.innerHTML = currentResults.map((r, i) => {
139
+ const isActive = i === selectedIdx;
140
+ const nameHighlighted = highlightText(r.name, r.matchIndices.filter(idx => idx >= r.path.length - r.name.length).map(idx => idx - (r.path.length - r.name.length)));
141
+ const dirHighlighted = r.dir ? highlightText(r.dir + '/', r.matchIndices.filter(idx => idx < r.path.length - r.name.length)) : '';
142
+
143
+ return `<div class="cp-result${isActive ? ' cp-result--active' : ''}" data-idx="${i}">
144
+ <span class="cp-result-name">${nameHighlighted}</span>
145
+ <span class="cp-result-dir">${dirHighlighted}</span>
146
+ </div>`;
147
+ }).join('');
148
+
149
+ // Scroll active item into view
150
+ const active = resultsList.querySelector('.cp-result--active') as HTMLElement;
151
+ active?.scrollIntoView({ block: 'nearest' });
152
+
153
+ // Click to select
154
+ resultsList.querySelectorAll('.cp-result').forEach(el => {
155
+ el.addEventListener('mousedown', (e) => {
156
+ e.preventDefault();
157
+ const idx = parseInt((el as HTMLElement).dataset.idx || '0');
158
+ selectResult(idx);
159
+ });
160
+ el.addEventListener('mouseenter', () => {
161
+ selectedIdx = parseInt((el as HTMLElement).dataset.idx || '0');
162
+ renderResults();
163
+ });
164
+ });
165
+ }
166
+
167
+ function onInput(): void {
168
+ const query = input?.value || '';
169
+ if (!currentCtx) return;
170
+
171
+ const files = getAllFiles(currentCtx);
172
+
173
+ if (!query) {
174
+ // Show all files sorted by path
175
+ currentResults = files
176
+ .map(f => ({ path: f.path, name: f.name, dir: f.dir, score: 0, matchIndices: [] }))
177
+ .sort((a, b) => a.path.localeCompare(b.path))
178
+ .slice(0, 30);
179
+ } else {
180
+ currentResults = files
181
+ .map(f => {
182
+ const match = fuzzyMatch(query, f.path);
183
+ if (!match) return null;
184
+ return { path: f.path, name: f.name, dir: f.dir, score: match.score, matchIndices: match.indices };
185
+ })
186
+ .filter((r): r is SearchResult => r !== null)
187
+ .sort((a, b) => b.score - a.score)
188
+ .slice(0, 20);
189
+ }
190
+
191
+ selectedIdx = 0;
192
+ renderResults();
193
+ }
194
+
195
+ function onKeyDown(e: KeyboardEvent): void {
196
+ switch (e.key) {
197
+ case 'ArrowDown':
198
+ e.preventDefault();
199
+ selectedIdx = Math.min(selectedIdx + 1, currentResults.length - 1);
200
+ renderResults();
201
+ break;
202
+ case 'ArrowUp':
203
+ e.preventDefault();
204
+ selectedIdx = Math.max(selectedIdx - 1, 0);
205
+ renderResults();
206
+ break;
207
+ case 'Enter':
208
+ e.preventDefault();
209
+ selectResult(selectedIdx);
210
+ break;
211
+ case 'Escape':
212
+ e.preventDefault();
213
+ close();
214
+ break;
215
+ }
216
+ }
217
+
218
+ function selectResult(idx: number): void {
219
+ const result = currentResults[idx];
220
+ if (result && currentCtx) {
221
+ close();
222
+ jumpToFile(currentCtx, result.path);
223
+ }
224
+ }
225
+
226
+ function open(ctx: CanvasContext): void {
227
+ currentCtx = ctx;
228
+ if (!overlay) createOverlay();
229
+ overlay!.style.display = 'flex';
230
+ input!.value = '';
231
+ selectedIdx = 0;
232
+ onInput(); // Show all files
233
+
234
+ // Focus after a tick to avoid the Ctrl+K keystroke appearing
235
+ requestAnimationFrame(() => input?.focus());
236
+ }
237
+
238
+ function close(): void {
239
+ if (overlay) overlay.style.display = 'none';
240
+ currentCtx = null;
241
+ }
242
+
243
+ export function isCommandPaletteOpen(): boolean {
244
+ return overlay?.style.display === 'flex';
245
+ }
246
+
247
+ // ── Init ─────────────────────────────────────────────────
248
+
249
+ export function initCommandPalette(ctx: CanvasContext): void {
250
+ document.addEventListener('keydown', (e) => {
251
+ // Ctrl+K, Ctrl+P, or Cmd+K/Cmd+P
252
+ if ((e.ctrlKey || e.metaKey) && (e.key === 'k' || e.key === 'p')) {
253
+ e.preventDefault();
254
+ e.stopPropagation();
255
+ if (isCommandPaletteOpen()) {
256
+ close();
257
+ } else {
258
+ open(ctx);
259
+ }
260
+ }
261
+ });
262
+ }