gitmaps 1.1.0 → 1.1.1
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 +267 -118
- package/app/[...slug]/page.client.tsx +1 -0
- package/app/[...slug]/page.tsx +6 -0
- package/app/analytics.db +0 -0
- package/app/api/analytics/route.ts +64 -0
- package/app/api/auth/positions/route.ts +95 -33
- package/app/api/build-info/route.ts +19 -0
- package/app/api/chat/route.ts +13 -2
- package/app/api/og-image/route.ts +14 -0
- package/app/api/repo/file-content/route.ts +73 -20
- package/app/api/repo/load/route.test.ts +62 -0
- package/app/api/repo/load/route.ts +41 -1
- package/app/api/repo/pdf-thumb/route.ts +127 -0
- package/app/api/repo/resolve-slug/route.ts +51 -0
- package/app/api/repo/tree/route.ts +188 -104
- package/app/api/version/route.ts +26 -0
- package/app/globals.css +5706 -4938
- package/app/layout.tsx +1279 -490
- package/app/lib/auto-arrange.test.ts +158 -0
- package/app/lib/auto-arrange.ts +147 -0
- package/app/lib/canvas-export.ts +358 -358
- package/app/lib/canvas.ts +625 -564
- package/app/lib/cards.tsx +1361 -916
- package/app/lib/chat.tsx +65 -9
- package/app/lib/code-editor.ts +86 -2
- package/app/lib/context.test.ts +32 -0
- package/app/lib/context.ts +19 -3
- package/app/lib/cursor-sharing.ts +34 -0
- package/app/lib/events.tsx +71 -93
- package/app/lib/export-canvas.ts +287 -0
- package/app/lib/file-card-plugin.ts +148 -148
- package/app/lib/file-modal.tsx +49 -0
- package/app/lib/file-preview.ts +486 -427
- package/app/lib/github-import.test.ts +424 -0
- package/app/lib/initial-route-hydration.test.ts +283 -0
- package/app/lib/initial-route-hydration.ts +202 -0
- package/app/lib/landing-reset.test.ts +99 -0
- package/app/lib/landing-reset.ts +106 -0
- package/app/lib/landing-shell.test.ts +75 -0
- package/app/lib/large-repo-optimization.ts +37 -0
- package/app/lib/layout-snapshots.ts +320 -0
- package/app/lib/loading.test.ts +69 -0
- package/app/lib/loading.tsx +160 -45
- package/app/lib/mount-cleanup.test.ts +52 -0
- package/app/lib/mount-cleanup.ts +34 -0
- package/app/lib/mount-init.test.ts +123 -0
- package/app/lib/mount-init.ts +107 -0
- package/app/lib/mount-lifecycle.test.ts +39 -0
- package/app/lib/mount-lifecycle.ts +12 -0
- package/app/lib/mount-route-wiring.test.ts +87 -0
- package/app/lib/mount-route-wiring.ts +84 -0
- package/app/lib/multi-repo.ts +14 -0
- package/app/lib/onboarding-tutorial.ts +278 -0
- package/app/lib/positions.ts +190 -121
- package/app/lib/recent-commits.test.ts +869 -0
- package/app/lib/recent-commits.ts +227 -0
- package/app/lib/repo-handoff.test.ts +23 -0
- package/app/lib/repo-handoff.ts +16 -0
- package/app/lib/repo-progressive.ts +119 -0
- package/app/lib/repo-select.test.ts +61 -0
- package/app/lib/repo-select.ts +74 -0
- package/app/lib/repo.tsx +1383 -987
- package/app/lib/role.ts +228 -0
- package/app/lib/route-catchall.test.ts +27 -0
- package/app/lib/route-repo-entry.test.ts +95 -0
- package/app/lib/route-repo-entry.ts +36 -0
- package/app/lib/router-contract.test.ts +22 -0
- package/app/lib/router-contract.ts +19 -0
- package/app/lib/shared-layout.test.ts +86 -0
- package/app/lib/shared-layout.ts +82 -0
- package/app/lib/status-bar.test.ts +118 -0
- package/app/lib/status-bar.ts +365 -128
- package/app/lib/sync-controls.test.ts +43 -0
- package/app/lib/sync-controls.tsx +303 -0
- package/app/lib/test-dom.ts +145 -0
- package/app/lib/test-fixtures/router-contract/[...slug]/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/api/health/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/api/version/route.ts +3 -0
- package/app/lib/test-fixtures/router-contract/galaxy-canvas/page.tsx +3 -0
- package/app/lib/test-fixtures/router-contract/page.tsx +3 -0
- package/app/lib/transclusion-smoke.test.ts +163 -0
- package/app/lib/tutorial.ts +301 -0
- package/app/lib/version.ts +93 -0
- package/app/lib/viewport-culling.ts +740 -735
- package/app/lib/virtual-files.ts +456 -0
- package/app/lib/webgl-text.ts +189 -0
- package/app/lib/{galaxydraw-bridge.ts → xydraw-bridge.ts} +485 -482
- package/app/lib/{galaxydraw.test.ts → xydraw.test.ts} +228 -229
- package/app/og-image.png +0 -0
- package/app/page.client.tsx +70 -269
- package/app/page.tsx +15 -16
- package/app/state/machine.js +13 -0
- package/package.json +16 -7
- package/server.ts +10 -0
- package/app/[owner]/[repo]/page.tsx +0 -6
- package/app/[slug]/page.tsx +0 -6
- package/packages/galaxydraw/README.md +0 -296
- package/packages/galaxydraw/banner.png +0 -0
- package/packages/galaxydraw/demo/build-static.ts +0 -100
- package/packages/galaxydraw/demo/client.ts +0 -154
- package/packages/galaxydraw/demo/dist/client.js +0 -8
- package/packages/galaxydraw/demo/index.html +0 -256
- package/packages/galaxydraw/demo/server.ts +0 -96
- package/packages/galaxydraw/dist/index.js +0 -984
- package/packages/galaxydraw/dist/index.js.map +0 -16
- package/packages/galaxydraw/node_modules/.bin/tsc.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsc.exe +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/galaxydraw/node_modules/.bin/tsserver.exe +0 -0
- package/packages/galaxydraw/package.json +0 -49
- package/packages/galaxydraw/perf.test.ts +0 -284
- package/packages/galaxydraw/src/core/cards.ts +0 -435
- package/packages/galaxydraw/src/core/engine.ts +0 -339
- package/packages/galaxydraw/src/core/events.ts +0 -81
- package/packages/galaxydraw/src/core/layout.ts +0 -136
- package/packages/galaxydraw/src/core/minimap.ts +0 -216
- package/packages/galaxydraw/src/core/state.ts +0 -177
- package/packages/galaxydraw/src/core/viewport.ts +0 -106
- package/packages/galaxydraw/src/galaxydraw.css +0 -166
- package/packages/galaxydraw/src/index.ts +0 -40
- package/packages/galaxydraw/tsconfig.json +0 -30
|
@@ -1,104 +1,188 @@
|
|
|
1
|
-
import { measure } from 'measure-fn';
|
|
2
|
-
import simpleGit from 'simple-git';
|
|
3
|
-
import { readFileSync, existsSync } from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { validateRepoPath } from '../validate-path';
|
|
6
|
-
|
|
7
|
-
const BINARY_EXTS = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'svg', 'webp', 'mp3', 'mp4', 'wav', 'ogg', 'avi', 'mov', 'zip', 'tar', 'gz', 'rar', '7z', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'exe', 'dll', 'so', 'dylib', 'woff', 'woff2', 'ttf', 'eot', 'otf', 'lock']);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
import { measure } from 'measure-fn';
|
|
2
|
+
import simpleGit from 'simple-git';
|
|
3
|
+
import { readFileSync, existsSync, readdirSync, statSync } from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { validateRepoPath } from '../validate-path';
|
|
6
|
+
|
|
7
|
+
const BINARY_EXTS = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'svg', 'webp', 'mp3', 'mp4', 'wav', 'ogg', 'avi', 'mov', 'zip', 'tar', 'gz', 'rar', '7z', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'exe', 'dll', 'so', 'dylib', 'woff', 'woff2', 'ttf', 'eot', 'otf', 'lock']);
|
|
8
|
+
const IMAGE_EXTS = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'svg', 'webp']);
|
|
9
|
+
const PDF_EXTS = new Set(['pdf']);
|
|
10
|
+
const MAX_READ_SIZE = 2 * 1024 * 1024;
|
|
11
|
+
|
|
12
|
+
export async function POST(req: Request) {
|
|
13
|
+
return measure('api:repo:tree', async () => {
|
|
14
|
+
try {
|
|
15
|
+
const body = await req.json();
|
|
16
|
+
const repoPath = body.path;
|
|
17
|
+
const stream = body.stream === true;
|
|
18
|
+
const includeAll = body.includeAll === true;
|
|
19
|
+
|
|
20
|
+
if (!repoPath) {
|
|
21
|
+
return new Response('Repository path is required', { status: 400 });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const blocked = validateRepoPath(repoPath);
|
|
25
|
+
if (blocked) return blocked;
|
|
26
|
+
|
|
27
|
+
const ignoreDirs = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.cache', 'coverage', '.turbo', '__pycache__', '.tsbuildinfo']);
|
|
28
|
+
|
|
29
|
+
// Recursively scan filesystem for all files (ignoring standard dirs)
|
|
30
|
+
function scanDir(dir: string, prefix: string): string[] {
|
|
31
|
+
const results: string[] = [];
|
|
32
|
+
try {
|
|
33
|
+
const entries = readdirSync(dir);
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
if (ignoreDirs.has(entry)) continue;
|
|
36
|
+
const fullPath = path.join(dir, entry);
|
|
37
|
+
const relativePath = prefix ? `${prefix}/${entry}` : entry;
|
|
38
|
+
try {
|
|
39
|
+
const stats = statSync(fullPath);
|
|
40
|
+
if (stats.isDirectory()) {
|
|
41
|
+
results.push(...scanDir(fullPath, relativePath));
|
|
42
|
+
} else if (stats.isFile()) {
|
|
43
|
+
results.push(relativePath);
|
|
44
|
+
}
|
|
45
|
+
} catch (e: any) {
|
|
46
|
+
console.warn(`[tree:scanDir] stat error: ${fullPath}: ${e.message}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch (e: any) {
|
|
50
|
+
console.warn(`[tree:scanDir] readdir error: ${dir}: ${e.message}`);
|
|
51
|
+
}
|
|
52
|
+
return results;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let filePaths: string[];
|
|
56
|
+
|
|
57
|
+
const git = simpleGit(repoPath);
|
|
58
|
+
const isRepo = await git.checkIsRepo().catch(() => false);
|
|
59
|
+
|
|
60
|
+
if (!isRepo || includeAll) {
|
|
61
|
+
// Not a git repo or explicit all-files mode: scan filesystem
|
|
62
|
+
filePaths = scanDir(repoPath, '');
|
|
63
|
+
} else {
|
|
64
|
+
// Get tracked files
|
|
65
|
+
const result = await git.raw(['ls-files']);
|
|
66
|
+
const trackedPaths = result.trim().split('\n').filter(fp => {
|
|
67
|
+
if (!fp) return false;
|
|
68
|
+
if (Array.from(ignoreDirs).some(d => fp.startsWith(d + '/') || fp.startsWith(d + '\\'))) return false;
|
|
69
|
+
return true;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// If very few tracked files, also scan filesystem for untracked content
|
|
73
|
+
// This catches repos where most content (PDFs, images) is gitignored
|
|
74
|
+
if (trackedPaths.length < 50) {
|
|
75
|
+
const allPaths = scanDir(repoPath, '');
|
|
76
|
+
console.log(`[tree] ${trackedPaths.length} tracked, ${allPaths.length} on disk`);
|
|
77
|
+
if (allPaths.length > trackedPaths.length * 5) {
|
|
78
|
+
// Lots of untracked content — include everything
|
|
79
|
+
const trackedSet = new Set(trackedPaths);
|
|
80
|
+
filePaths = allPaths;
|
|
81
|
+
// But still filter out obvious junk from non-tracked scan
|
|
82
|
+
filePaths = filePaths.filter(fp => {
|
|
83
|
+
if (Array.from(ignoreDirs).some(d => fp.startsWith(d + '/') || fp.startsWith(d + '\\'))) return false;
|
|
84
|
+
return true;
|
|
85
|
+
});
|
|
86
|
+
console.log(`[tree] ${trackedPaths.length} tracked, ${allPaths.length} on disk → including all ${filePaths.length} files`);
|
|
87
|
+
} else {
|
|
88
|
+
filePaths = trackedPaths;
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
filePaths = trackedPaths;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readFile(filePath: string) {
|
|
96
|
+
const parts = filePath.split('/');
|
|
97
|
+
const name = parts[parts.length - 1];
|
|
98
|
+
const ext = name.includes('.') ? name.split('.').pop()!.toLowerCase() : '';
|
|
99
|
+
|
|
100
|
+
let content = null;
|
|
101
|
+
let lines = 0;
|
|
102
|
+
let size = 0;
|
|
103
|
+
let isBinary = BINARY_EXTS.has(ext);
|
|
104
|
+
const isImage = IMAGE_EXTS.has(ext);
|
|
105
|
+
const isPdf = PDF_EXTS.has(ext);
|
|
106
|
+
|
|
107
|
+
if (!isBinary) {
|
|
108
|
+
try {
|
|
109
|
+
const fullPath = path.join(repoPath, filePath);
|
|
110
|
+
const file = Bun.file(fullPath);
|
|
111
|
+
size = file.size;
|
|
112
|
+
|
|
113
|
+
// Skip reading content for very large files
|
|
114
|
+
if (size > MAX_READ_SIZE) {
|
|
115
|
+
isBinary = true;
|
|
116
|
+
} else {
|
|
117
|
+
const raw = readFileSync(fullPath, 'utf-8');
|
|
118
|
+
size = raw.length;
|
|
119
|
+
const allLines = raw.split('\n');
|
|
120
|
+
lines = allLines.length;
|
|
121
|
+
if (allLines.length > 10000) {
|
|
122
|
+
content = allLines.slice(0, 10000).join('\n');
|
|
123
|
+
} else {
|
|
124
|
+
content = raw;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (e) {
|
|
128
|
+
content = null;
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// For binary files, at least get the file size
|
|
132
|
+
try {
|
|
133
|
+
const fullPath = path.join(repoPath, filePath);
|
|
134
|
+
size = Bun.file(fullPath).size;
|
|
135
|
+
} catch (_) {}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { path: filePath, name, ext, type: 'file', content, lines, size, isBinary, isImage, isPdf };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ── Streaming mode: NDJSON with total header ──
|
|
142
|
+
if (stream) {
|
|
143
|
+
const total = filePaths.length;
|
|
144
|
+
const BATCH_SIZE = 20;
|
|
145
|
+
const encoder = new TextEncoder();
|
|
146
|
+
|
|
147
|
+
const readable = new ReadableStream({
|
|
148
|
+
start(controller) {
|
|
149
|
+
// First line: total count
|
|
150
|
+
controller.enqueue(encoder.encode(JSON.stringify({ total }) + '\n'));
|
|
151
|
+
|
|
152
|
+
let i = 0;
|
|
153
|
+
function nextBatch() {
|
|
154
|
+
const end = Math.min(i + BATCH_SIZE, total);
|
|
155
|
+
const batch: any[] = [];
|
|
156
|
+
for (; i < end; i++) {
|
|
157
|
+
batch.push(readFile(filePaths[i]));
|
|
158
|
+
}
|
|
159
|
+
controller.enqueue(encoder.encode(JSON.stringify({ files: batch, loaded: i }) + '\n'));
|
|
160
|
+
|
|
161
|
+
if (i < total) {
|
|
162
|
+
// Yield to event loop between batches
|
|
163
|
+
setTimeout(nextBatch, 0);
|
|
164
|
+
} else {
|
|
165
|
+
controller.close();
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
nextBatch();
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return new Response(readable, {
|
|
173
|
+
headers: {
|
|
174
|
+
'Content-Type': 'application/x-ndjson',
|
|
175
|
+
'Cache-Control': 'no-cache',
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ── Legacy non-streaming mode ──
|
|
181
|
+
const files = filePaths.map(readFile);
|
|
182
|
+
return Response.json({ files, total: files.length });
|
|
183
|
+
} catch (error: any) {
|
|
184
|
+
console.error('api:repo:tree:error', error);
|
|
185
|
+
return new Response(`Error: ${error.message}`, { status: 500 });
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
function runGit(args: string[]): string {
|
|
4
|
+
const repoRoot = path.resolve(import.meta.dir, '../../..');
|
|
5
|
+
const proc = Bun.spawnSync(['git', ...args], {
|
|
6
|
+
cwd: repoRoot,
|
|
7
|
+
stdout: 'pipe',
|
|
8
|
+
stderr: 'pipe',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
if (proc.exitCode !== 0) {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return proc.stdout.toString().trim();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function GET() {
|
|
19
|
+
const commit = process.env.GIT_COMMIT_HASH || runGit(['rev-parse', '--short', 'HEAD']) || 'unknown';
|
|
20
|
+
const commitDate = process.env.GIT_COMMIT_DATE || runGit(['log', '-1', '--format=%cs']) || '';
|
|
21
|
+
|
|
22
|
+
return Response.json({
|
|
23
|
+
commit,
|
|
24
|
+
commitDate,
|
|
25
|
+
});
|
|
26
|
+
}
|