@rayburst/cli 0.2.1 → 0.2.2
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 +10 -1
- package/dist/{chunk-NIOHEIF6.js → chunk-ZAT3D23Y.js} +113 -29
- package/dist/index.js +1 -1
- package/dist/vite-plugin.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -83,7 +83,16 @@ The generated `analysis.json` contains:
|
|
|
83
83
|
- **Branches**: Git branch information
|
|
84
84
|
- **Files**: Modification timestamps
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
## Viewing Your Analysis
|
|
87
|
+
|
|
88
|
+
Once analysis is complete, open the [Rayburst web application](https://rayburst.app) in Chrome or Edge:
|
|
89
|
+
|
|
90
|
+
1. Click "Add Project" button
|
|
91
|
+
2. Select your project folder
|
|
92
|
+
3. The app will load `.rayburst/analysis.json` automatically
|
|
93
|
+
4. Explore your codebase visually with interactive dependency graphs
|
|
94
|
+
|
|
95
|
+
The web app uses the File System Access API (Chrome/Edge only) to read your local analysis data.
|
|
87
96
|
|
|
88
97
|
## Example Output
|
|
89
98
|
|
|
@@ -1,9 +1,87 @@
|
|
|
1
1
|
// src/analysis/analyze-project.ts
|
|
2
2
|
import { Project, SyntaxKind, Node } from "ts-morph";
|
|
3
|
-
import { execSync } from "child_process";
|
|
3
|
+
import { execSync as execSync2 } from "child_process";
|
|
4
4
|
import * as fs from "fs";
|
|
5
|
-
import * as
|
|
5
|
+
import * as path2 from "path";
|
|
6
6
|
import crypto from "crypto";
|
|
7
|
+
|
|
8
|
+
// src/git-utils.ts
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
import path from "path";
|
|
11
|
+
function isGitRepository(projectPath) {
|
|
12
|
+
try {
|
|
13
|
+
execSync("git rev-parse --is-inside-work-tree", {
|
|
14
|
+
cwd: projectPath,
|
|
15
|
+
encoding: "utf8",
|
|
16
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
17
|
+
});
|
|
18
|
+
return true;
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function getChangedFilesVsRemote(projectPath, remoteBranch = void 0) {
|
|
24
|
+
try {
|
|
25
|
+
if (!isGitRepository(projectPath)) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
let currentBranch;
|
|
29
|
+
try {
|
|
30
|
+
currentBranch = execSync("git branch --show-current", {
|
|
31
|
+
cwd: projectPath,
|
|
32
|
+
encoding: "utf8",
|
|
33
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
34
|
+
}).trim();
|
|
35
|
+
} catch {
|
|
36
|
+
const branchOutput = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
37
|
+
cwd: projectPath,
|
|
38
|
+
encoding: "utf8",
|
|
39
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
40
|
+
}).trim();
|
|
41
|
+
currentBranch = branchOutput;
|
|
42
|
+
}
|
|
43
|
+
const remote = remoteBranch || `origin/${currentBranch}`;
|
|
44
|
+
try {
|
|
45
|
+
execSync("git fetch origin --quiet", {
|
|
46
|
+
cwd: projectPath,
|
|
47
|
+
stdio: "ignore",
|
|
48
|
+
timeout: 5e3
|
|
49
|
+
});
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
execSync(`git rev-parse --verify ${remote}`, {
|
|
54
|
+
cwd: projectPath,
|
|
55
|
+
stdio: "ignore"
|
|
56
|
+
});
|
|
57
|
+
} catch {
|
|
58
|
+
if (remote !== "origin/main") {
|
|
59
|
+
try {
|
|
60
|
+
execSync("git rev-parse --verify origin/main", {
|
|
61
|
+
cwd: projectPath,
|
|
62
|
+
stdio: "ignore"
|
|
63
|
+
});
|
|
64
|
+
return getChangedFilesVsRemote(projectPath, "origin/main");
|
|
65
|
+
} catch {
|
|
66
|
+
console.warn(`No remote branch found (tried ${remote} and origin/main)`);
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
const output = execSync(`git diff --name-only ${remote}...HEAD`, {
|
|
73
|
+
cwd: projectPath,
|
|
74
|
+
encoding: "utf8",
|
|
75
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
76
|
+
});
|
|
77
|
+
return output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.warn("Failed to get changed files vs remote:", error.message);
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/analysis/analyze-project.ts
|
|
7
85
|
async function analyzeProject(projectPath, projectId, onLog) {
|
|
8
86
|
const logs = [];
|
|
9
87
|
const log = (message) => {
|
|
@@ -18,7 +96,7 @@ async function analyzeProject(projectPath, projectId, onLog) {
|
|
|
18
96
|
const gitInfo = getGitInfo(projectPath);
|
|
19
97
|
log(` Git hash: ${gitHash}`);
|
|
20
98
|
log(` Current branch: ${gitInfo.branch}`);
|
|
21
|
-
const tsconfigPath =
|
|
99
|
+
const tsconfigPath = path2.join(projectPath, "tsconfig.json");
|
|
22
100
|
if (!fs.existsSync(tsconfigPath)) {
|
|
23
101
|
log(` Warning: No tsconfig.json found, skipping TypeScript analysis`);
|
|
24
102
|
const emptyAnalysis = createEmptyAnalysis(projectPath, gitInfo);
|
|
@@ -65,15 +143,15 @@ async function analyzeProject(projectPath, projectId, onLog) {
|
|
|
65
143
|
generateEdges(sourceFile, nodeMap, edges);
|
|
66
144
|
}
|
|
67
145
|
log(` Generated ${edges.length} edges`);
|
|
68
|
-
const packageJsonPath =
|
|
69
|
-
let packageJson = { name:
|
|
146
|
+
const packageJsonPath = path2.join(projectPath, "package.json");
|
|
147
|
+
let packageJson = { name: path2.basename(projectPath) };
|
|
70
148
|
if (fs.existsSync(packageJsonPath)) {
|
|
71
149
|
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
72
150
|
}
|
|
73
151
|
const branchId = gitInfo.branch.replace(/[^a-zA-Z0-9]/g, "-");
|
|
74
152
|
const projectMetadata = {
|
|
75
153
|
id: projectId || crypto.createHash("md5").update(projectPath).digest("hex").substring(0, 12),
|
|
76
|
-
title: packageJson.name ||
|
|
154
|
+
title: packageJson.name || path2.basename(projectPath),
|
|
77
155
|
subtitle: (/* @__PURE__ */ new Date()).toLocaleDateString(),
|
|
78
156
|
value: `${nodes.length} nodes`,
|
|
79
157
|
trend: 0,
|
|
@@ -94,6 +172,9 @@ async function analyzeProject(projectPath, projectId, onLog) {
|
|
|
94
172
|
nodes,
|
|
95
173
|
edges
|
|
96
174
|
};
|
|
175
|
+
log(" Checking for changed files vs remote...");
|
|
176
|
+
const changedFiles = getChangedFilesVsRemote(projectPath);
|
|
177
|
+
log(` Found ${changedFiles.length} changed files`);
|
|
97
178
|
const result = {
|
|
98
179
|
project: projectMetadata,
|
|
99
180
|
branches: [branchMetadata],
|
|
@@ -101,7 +182,10 @@ async function analyzeProject(projectPath, projectId, onLog) {
|
|
|
101
182
|
[branchId]: planData
|
|
102
183
|
},
|
|
103
184
|
analyzedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
104
|
-
logs
|
|
185
|
+
logs,
|
|
186
|
+
changedFilesVsRemote: changedFiles.length > 0 ? {
|
|
187
|
+
[branchId]: changedFiles
|
|
188
|
+
} : void 0
|
|
105
189
|
};
|
|
106
190
|
return result;
|
|
107
191
|
} catch (error) {
|
|
@@ -113,8 +197,8 @@ async function analyzeProject(projectPath, projectId, onLog) {
|
|
|
113
197
|
}
|
|
114
198
|
}
|
|
115
199
|
function createEmptyAnalysis(projectPath, gitInfo) {
|
|
116
|
-
const packageJsonPath =
|
|
117
|
-
let packageJson = { name:
|
|
200
|
+
const packageJsonPath = path2.join(projectPath, "package.json");
|
|
201
|
+
let packageJson = { name: path2.basename(projectPath) };
|
|
118
202
|
if (fs.existsSync(packageJsonPath)) {
|
|
119
203
|
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
120
204
|
}
|
|
@@ -122,7 +206,7 @@ function createEmptyAnalysis(projectPath, gitInfo) {
|
|
|
122
206
|
return {
|
|
123
207
|
project: {
|
|
124
208
|
id: crypto.createHash("md5").update(projectPath).digest("hex").substring(0, 12),
|
|
125
|
-
title: packageJson.name ||
|
|
209
|
+
title: packageJson.name || path2.basename(projectPath),
|
|
126
210
|
subtitle: (/* @__PURE__ */ new Date()).toLocaleDateString(),
|
|
127
211
|
value: "0 nodes",
|
|
128
212
|
trend: 0,
|
|
@@ -145,17 +229,17 @@ function createEmptyAnalysis(projectPath, gitInfo) {
|
|
|
145
229
|
}
|
|
146
230
|
function getGitHash(projectPath) {
|
|
147
231
|
try {
|
|
148
|
-
return
|
|
232
|
+
return execSync2("git rev-parse --short HEAD", { cwd: projectPath, encoding: "utf-8" }).trim();
|
|
149
233
|
} catch {
|
|
150
234
|
return "nogit";
|
|
151
235
|
}
|
|
152
236
|
}
|
|
153
237
|
function getGitInfo(projectPath) {
|
|
154
238
|
try {
|
|
155
|
-
const branch =
|
|
156
|
-
const lastCommit =
|
|
157
|
-
const author =
|
|
158
|
-
const commitCount = parseInt(
|
|
239
|
+
const branch = execSync2("git branch --show-current", { cwd: projectPath, encoding: "utf-8" }).trim() || "main";
|
|
240
|
+
const lastCommit = execSync2("git log -1 --pretty=%s", { cwd: projectPath, encoding: "utf-8" }).trim() || "No commits";
|
|
241
|
+
const author = execSync2("git log -1 --pretty=%an", { cwd: projectPath, encoding: "utf-8" }).trim() || "Unknown";
|
|
242
|
+
const commitCount = parseInt(execSync2("git rev-list --count HEAD", { cwd: projectPath, encoding: "utf-8" }).trim() || "0");
|
|
159
243
|
return { branch, lastCommit, author, commitCount };
|
|
160
244
|
} catch {
|
|
161
245
|
return {
|
|
@@ -400,14 +484,14 @@ function generateEdges(sourceFile, nodeMap, edges) {
|
|
|
400
484
|
|
|
401
485
|
// src/local-storage.ts
|
|
402
486
|
import { promises as fs2 } from "fs";
|
|
403
|
-
import
|
|
487
|
+
import path3 from "path";
|
|
404
488
|
async function ensureRayburstDir(projectPath) {
|
|
405
|
-
const rayburstDir =
|
|
489
|
+
const rayburstDir = path3.join(projectPath, ".rayburst");
|
|
406
490
|
await fs2.mkdir(rayburstDir, { recursive: true });
|
|
407
491
|
return rayburstDir;
|
|
408
492
|
}
|
|
409
493
|
async function readLocalAnalysis(projectPath) {
|
|
410
|
-
const analysisPath =
|
|
494
|
+
const analysisPath = path3.join(projectPath, ".rayburst", "analysis.json");
|
|
411
495
|
try {
|
|
412
496
|
const data = await fs2.readFile(analysisPath, "utf-8");
|
|
413
497
|
return JSON.parse(data);
|
|
@@ -417,11 +501,11 @@ async function readLocalAnalysis(projectPath) {
|
|
|
417
501
|
}
|
|
418
502
|
async function writeLocalAnalysis(projectPath, analysis) {
|
|
419
503
|
await ensureRayburstDir(projectPath);
|
|
420
|
-
const analysisPath =
|
|
504
|
+
const analysisPath = path3.join(projectPath, ".rayburst", "analysis.json");
|
|
421
505
|
await fs2.writeFile(analysisPath, JSON.stringify(analysis, null, 2), "utf-8");
|
|
422
506
|
}
|
|
423
507
|
async function readLocalMeta(projectPath) {
|
|
424
|
-
const metaPath =
|
|
508
|
+
const metaPath = path3.join(projectPath, ".rayburst", "meta.json");
|
|
425
509
|
try {
|
|
426
510
|
const data = await fs2.readFile(metaPath, "utf-8");
|
|
427
511
|
return JSON.parse(data);
|
|
@@ -431,11 +515,11 @@ async function readLocalMeta(projectPath) {
|
|
|
431
515
|
}
|
|
432
516
|
async function writeLocalMeta(projectPath, meta) {
|
|
433
517
|
await ensureRayburstDir(projectPath);
|
|
434
|
-
const metaPath =
|
|
518
|
+
const metaPath = path3.join(projectPath, ".rayburst", "meta.json");
|
|
435
519
|
await fs2.writeFile(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
436
520
|
}
|
|
437
521
|
async function addGitignoreEntry(projectPath) {
|
|
438
|
-
const gitignorePath =
|
|
522
|
+
const gitignorePath = path3.join(projectPath, ".gitignore");
|
|
439
523
|
let gitignoreContent = "";
|
|
440
524
|
try {
|
|
441
525
|
gitignoreContent = await fs2.readFile(gitignorePath, "utf-8");
|
|
@@ -449,7 +533,7 @@ async function addGitignoreEntry(projectPath) {
|
|
|
449
533
|
await fs2.writeFile(gitignorePath, gitignoreContent, "utf-8");
|
|
450
534
|
}
|
|
451
535
|
async function isProjectInitialized(projectPath) {
|
|
452
|
-
const rayburstDir =
|
|
536
|
+
const rayburstDir = path3.join(projectPath, ".rayburst");
|
|
453
537
|
try {
|
|
454
538
|
const stats = await fs2.stat(rayburstDir);
|
|
455
539
|
return stats.isDirectory();
|
|
@@ -471,20 +555,20 @@ async function initializeProject(projectPath, projectName, cliVersion) {
|
|
|
471
555
|
return meta;
|
|
472
556
|
}
|
|
473
557
|
function generateProjectId(projectPath) {
|
|
474
|
-
const baseName =
|
|
558
|
+
const baseName = path3.basename(projectPath);
|
|
475
559
|
const timestamp = Date.now().toString(36);
|
|
476
560
|
return `${baseName}-${timestamp}`;
|
|
477
561
|
}
|
|
478
562
|
|
|
479
563
|
// src/registry.ts
|
|
480
|
-
import
|
|
564
|
+
import path4 from "path";
|
|
481
565
|
import { fileURLToPath } from "url";
|
|
482
566
|
import os from "os";
|
|
483
567
|
var __filename = fileURLToPath(import.meta.url);
|
|
484
|
-
var __dirname =
|
|
485
|
-
var RAYBURST_DIR =
|
|
486
|
-
var PROJECTS_FILE =
|
|
487
|
-
var ANALYZED_DIR =
|
|
568
|
+
var __dirname = path4.dirname(__filename);
|
|
569
|
+
var RAYBURST_DIR = path4.join(os.homedir(), ".rayburst");
|
|
570
|
+
var PROJECTS_FILE = path4.join(RAYBURST_DIR, "projects.json");
|
|
571
|
+
var ANALYZED_DIR = path4.join(RAYBURST_DIR, "analyzed");
|
|
488
572
|
|
|
489
573
|
// src/incremental-analyzer.ts
|
|
490
574
|
import chalk from "chalk";
|
package/dist/index.js
CHANGED
package/dist/vite-plugin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rayburst/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Rayburst - Automatic code analysis for TypeScript/JavaScript projects via Vite plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@rayburst/types": "^0.1.
|
|
45
|
+
"@rayburst/types": "^0.1.3",
|
|
46
46
|
"chalk": "^5.3.0",
|
|
47
47
|
"ts-morph": "^21.0.1",
|
|
48
48
|
"zod": "^4.2.0"
|