@rayburst/cli 0.2.1 → 0.2.3

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 CHANGED
@@ -83,7 +83,16 @@ The generated `analysis.json` contains:
83
83
  - **Branches**: Git branch information
84
84
  - **Files**: Modification timestamps
85
85
 
86
- This data can be visualized using the [Rayburst web application](https://rayburst.app).
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,129 @@
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 path from "path";
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 getUncommittedChanges(projectPath) {
12
+ try {
13
+ if (!isGitRepository(projectPath)) {
14
+ return [];
15
+ }
16
+ const command = "git diff --name-only HEAD && git diff --name-only --cached";
17
+ const output = execSync(command, {
18
+ cwd: projectPath,
19
+ encoding: "utf8",
20
+ stdio: ["pipe", "pipe", "ignore"]
21
+ // Ignore stderr
22
+ });
23
+ const files = output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
24
+ return [...new Set(files)];
25
+ } catch (error) {
26
+ console.error("Failed to get git diff:", error.message);
27
+ return [];
28
+ }
29
+ }
30
+ function isGitRepository(projectPath) {
31
+ try {
32
+ execSync("git rev-parse --is-inside-work-tree", {
33
+ cwd: projectPath,
34
+ encoding: "utf8",
35
+ stdio: ["pipe", "pipe", "ignore"]
36
+ });
37
+ return true;
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+ function getUntrackedFiles(projectPath) {
43
+ try {
44
+ if (!isGitRepository(projectPath)) {
45
+ return [];
46
+ }
47
+ const output = execSync("git ls-files --others --exclude-standard", {
48
+ cwd: projectPath,
49
+ encoding: "utf8",
50
+ stdio: ["pipe", "pipe", "ignore"]
51
+ });
52
+ return output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
53
+ } catch (error) {
54
+ console.error("Failed to get untracked files:", error.message);
55
+ return [];
56
+ }
57
+ }
58
+ function getAllChangedFiles(projectPath) {
59
+ const uncommitted = getUncommittedChanges(projectPath);
60
+ const untracked = getUntrackedFiles(projectPath);
61
+ return [.../* @__PURE__ */ new Set([...uncommitted, ...untracked])];
62
+ }
63
+ function getChangedFilesVsRemote(projectPath, remoteBranch = void 0) {
64
+ try {
65
+ if (!isGitRepository(projectPath)) {
66
+ return [];
67
+ }
68
+ let currentBranch;
69
+ try {
70
+ currentBranch = execSync("git branch --show-current", {
71
+ cwd: projectPath,
72
+ encoding: "utf8",
73
+ stdio: ["pipe", "pipe", "ignore"]
74
+ }).trim();
75
+ } catch {
76
+ const branchOutput = execSync("git rev-parse --abbrev-ref HEAD", {
77
+ cwd: projectPath,
78
+ encoding: "utf8",
79
+ stdio: ["pipe", "pipe", "ignore"]
80
+ }).trim();
81
+ currentBranch = branchOutput;
82
+ }
83
+ const remote = remoteBranch || `origin/${currentBranch}`;
84
+ try {
85
+ execSync("git fetch origin --quiet", {
86
+ cwd: projectPath,
87
+ stdio: "ignore",
88
+ timeout: 5e3
89
+ });
90
+ } catch {
91
+ }
92
+ try {
93
+ execSync(`git rev-parse --verify ${remote}`, {
94
+ cwd: projectPath,
95
+ stdio: "ignore"
96
+ });
97
+ } catch {
98
+ if (remote !== "origin/main") {
99
+ try {
100
+ execSync("git rev-parse --verify origin/main", {
101
+ cwd: projectPath,
102
+ stdio: "ignore"
103
+ });
104
+ return getChangedFilesVsRemote(projectPath, "origin/main");
105
+ } catch {
106
+ console.warn(`No remote branch found (tried ${remote} and origin/main)`);
107
+ return [];
108
+ }
109
+ }
110
+ return [];
111
+ }
112
+ const output = execSync(`git diff --name-only ${remote}...HEAD`, {
113
+ cwd: projectPath,
114
+ encoding: "utf8",
115
+ stdio: ["pipe", "pipe", "ignore"]
116
+ });
117
+ const committedChanges = output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
118
+ const uncommittedChanges = getAllChangedFiles(projectPath);
119
+ return [.../* @__PURE__ */ new Set([...committedChanges, ...uncommittedChanges])];
120
+ } catch (error) {
121
+ console.warn("Failed to get changed files vs remote:", error.message);
122
+ return [];
123
+ }
124
+ }
125
+
126
+ // src/analysis/analyze-project.ts
7
127
  async function analyzeProject(projectPath, projectId, onLog) {
8
128
  const logs = [];
9
129
  const log = (message) => {
@@ -18,7 +138,7 @@ async function analyzeProject(projectPath, projectId, onLog) {
18
138
  const gitInfo = getGitInfo(projectPath);
19
139
  log(` Git hash: ${gitHash}`);
20
140
  log(` Current branch: ${gitInfo.branch}`);
21
- const tsconfigPath = path.join(projectPath, "tsconfig.json");
141
+ const tsconfigPath = path2.join(projectPath, "tsconfig.json");
22
142
  if (!fs.existsSync(tsconfigPath)) {
23
143
  log(` Warning: No tsconfig.json found, skipping TypeScript analysis`);
24
144
  const emptyAnalysis = createEmptyAnalysis(projectPath, gitInfo);
@@ -65,15 +185,15 @@ async function analyzeProject(projectPath, projectId, onLog) {
65
185
  generateEdges(sourceFile, nodeMap, edges);
66
186
  }
67
187
  log(` Generated ${edges.length} edges`);
68
- const packageJsonPath = path.join(projectPath, "package.json");
69
- let packageJson = { name: path.basename(projectPath) };
188
+ const packageJsonPath = path2.join(projectPath, "package.json");
189
+ let packageJson = { name: path2.basename(projectPath) };
70
190
  if (fs.existsSync(packageJsonPath)) {
71
191
  packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
72
192
  }
73
193
  const branchId = gitInfo.branch.replace(/[^a-zA-Z0-9]/g, "-");
74
194
  const projectMetadata = {
75
195
  id: projectId || crypto.createHash("md5").update(projectPath).digest("hex").substring(0, 12),
76
- title: packageJson.name || path.basename(projectPath),
196
+ title: packageJson.name || path2.basename(projectPath),
77
197
  subtitle: (/* @__PURE__ */ new Date()).toLocaleDateString(),
78
198
  value: `${nodes.length} nodes`,
79
199
  trend: 0,
@@ -94,6 +214,9 @@ async function analyzeProject(projectPath, projectId, onLog) {
94
214
  nodes,
95
215
  edges
96
216
  };
217
+ log(" Checking for changed files vs remote...");
218
+ const changedFiles = getChangedFilesVsRemote(projectPath);
219
+ log(` Found ${changedFiles.length} changed files`);
97
220
  const result = {
98
221
  project: projectMetadata,
99
222
  branches: [branchMetadata],
@@ -101,7 +224,10 @@ async function analyzeProject(projectPath, projectId, onLog) {
101
224
  [branchId]: planData
102
225
  },
103
226
  analyzedAt: (/* @__PURE__ */ new Date()).toISOString(),
104
- logs
227
+ logs,
228
+ changedFilesVsRemote: changedFiles.length > 0 ? {
229
+ [branchId]: changedFiles
230
+ } : void 0
105
231
  };
106
232
  return result;
107
233
  } catch (error) {
@@ -113,8 +239,8 @@ async function analyzeProject(projectPath, projectId, onLog) {
113
239
  }
114
240
  }
115
241
  function createEmptyAnalysis(projectPath, gitInfo) {
116
- const packageJsonPath = path.join(projectPath, "package.json");
117
- let packageJson = { name: path.basename(projectPath) };
242
+ const packageJsonPath = path2.join(projectPath, "package.json");
243
+ let packageJson = { name: path2.basename(projectPath) };
118
244
  if (fs.existsSync(packageJsonPath)) {
119
245
  packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
120
246
  }
@@ -122,7 +248,7 @@ function createEmptyAnalysis(projectPath, gitInfo) {
122
248
  return {
123
249
  project: {
124
250
  id: crypto.createHash("md5").update(projectPath).digest("hex").substring(0, 12),
125
- title: packageJson.name || path.basename(projectPath),
251
+ title: packageJson.name || path2.basename(projectPath),
126
252
  subtitle: (/* @__PURE__ */ new Date()).toLocaleDateString(),
127
253
  value: "0 nodes",
128
254
  trend: 0,
@@ -145,17 +271,17 @@ function createEmptyAnalysis(projectPath, gitInfo) {
145
271
  }
146
272
  function getGitHash(projectPath) {
147
273
  try {
148
- return execSync("git rev-parse --short HEAD", { cwd: projectPath, encoding: "utf-8" }).trim();
274
+ return execSync2("git rev-parse --short HEAD", { cwd: projectPath, encoding: "utf-8" }).trim();
149
275
  } catch {
150
276
  return "nogit";
151
277
  }
152
278
  }
153
279
  function getGitInfo(projectPath) {
154
280
  try {
155
- const branch = execSync("git branch --show-current", { cwd: projectPath, encoding: "utf-8" }).trim() || "main";
156
- const lastCommit = execSync("git log -1 --pretty=%s", { cwd: projectPath, encoding: "utf-8" }).trim() || "No commits";
157
- const author = execSync("git log -1 --pretty=%an", { cwd: projectPath, encoding: "utf-8" }).trim() || "Unknown";
158
- const commitCount = parseInt(execSync("git rev-list --count HEAD", { cwd: projectPath, encoding: "utf-8" }).trim() || "0");
281
+ const branch = execSync2("git branch --show-current", { cwd: projectPath, encoding: "utf-8" }).trim() || "main";
282
+ const lastCommit = execSync2("git log -1 --pretty=%s", { cwd: projectPath, encoding: "utf-8" }).trim() || "No commits";
283
+ const author = execSync2("git log -1 --pretty=%an", { cwd: projectPath, encoding: "utf-8" }).trim() || "Unknown";
284
+ const commitCount = parseInt(execSync2("git rev-list --count HEAD", { cwd: projectPath, encoding: "utf-8" }).trim() || "0");
159
285
  return { branch, lastCommit, author, commitCount };
160
286
  } catch {
161
287
  return {
@@ -400,14 +526,14 @@ function generateEdges(sourceFile, nodeMap, edges) {
400
526
 
401
527
  // src/local-storage.ts
402
528
  import { promises as fs2 } from "fs";
403
- import path2 from "path";
529
+ import path3 from "path";
404
530
  async function ensureRayburstDir(projectPath) {
405
- const rayburstDir = path2.join(projectPath, ".rayburst");
531
+ const rayburstDir = path3.join(projectPath, ".rayburst");
406
532
  await fs2.mkdir(rayburstDir, { recursive: true });
407
533
  return rayburstDir;
408
534
  }
409
535
  async function readLocalAnalysis(projectPath) {
410
- const analysisPath = path2.join(projectPath, ".rayburst", "analysis.json");
536
+ const analysisPath = path3.join(projectPath, ".rayburst", "analysis.json");
411
537
  try {
412
538
  const data = await fs2.readFile(analysisPath, "utf-8");
413
539
  return JSON.parse(data);
@@ -417,11 +543,11 @@ async function readLocalAnalysis(projectPath) {
417
543
  }
418
544
  async function writeLocalAnalysis(projectPath, analysis) {
419
545
  await ensureRayburstDir(projectPath);
420
- const analysisPath = path2.join(projectPath, ".rayburst", "analysis.json");
546
+ const analysisPath = path3.join(projectPath, ".rayburst", "analysis.json");
421
547
  await fs2.writeFile(analysisPath, JSON.stringify(analysis, null, 2), "utf-8");
422
548
  }
423
549
  async function readLocalMeta(projectPath) {
424
- const metaPath = path2.join(projectPath, ".rayburst", "meta.json");
550
+ const metaPath = path3.join(projectPath, ".rayburst", "meta.json");
425
551
  try {
426
552
  const data = await fs2.readFile(metaPath, "utf-8");
427
553
  return JSON.parse(data);
@@ -431,11 +557,11 @@ async function readLocalMeta(projectPath) {
431
557
  }
432
558
  async function writeLocalMeta(projectPath, meta) {
433
559
  await ensureRayburstDir(projectPath);
434
- const metaPath = path2.join(projectPath, ".rayburst", "meta.json");
560
+ const metaPath = path3.join(projectPath, ".rayburst", "meta.json");
435
561
  await fs2.writeFile(metaPath, JSON.stringify(meta, null, 2), "utf-8");
436
562
  }
437
563
  async function addGitignoreEntry(projectPath) {
438
- const gitignorePath = path2.join(projectPath, ".gitignore");
564
+ const gitignorePath = path3.join(projectPath, ".gitignore");
439
565
  let gitignoreContent = "";
440
566
  try {
441
567
  gitignoreContent = await fs2.readFile(gitignorePath, "utf-8");
@@ -449,7 +575,7 @@ async function addGitignoreEntry(projectPath) {
449
575
  await fs2.writeFile(gitignorePath, gitignoreContent, "utf-8");
450
576
  }
451
577
  async function isProjectInitialized(projectPath) {
452
- const rayburstDir = path2.join(projectPath, ".rayburst");
578
+ const rayburstDir = path3.join(projectPath, ".rayburst");
453
579
  try {
454
580
  const stats = await fs2.stat(rayburstDir);
455
581
  return stats.isDirectory();
@@ -471,20 +597,20 @@ async function initializeProject(projectPath, projectName, cliVersion) {
471
597
  return meta;
472
598
  }
473
599
  function generateProjectId(projectPath) {
474
- const baseName = path2.basename(projectPath);
600
+ const baseName = path3.basename(projectPath);
475
601
  const timestamp = Date.now().toString(36);
476
602
  return `${baseName}-${timestamp}`;
477
603
  }
478
604
 
479
605
  // src/registry.ts
480
- import path3 from "path";
606
+ import path4 from "path";
481
607
  import { fileURLToPath } from "url";
482
608
  import os from "os";
483
609
  var __filename = fileURLToPath(import.meta.url);
484
- var __dirname = path3.dirname(__filename);
485
- var RAYBURST_DIR = path3.join(os.homedir(), ".rayburst");
486
- var PROJECTS_FILE = path3.join(RAYBURST_DIR, "projects.json");
487
- var ANALYZED_DIR = path3.join(RAYBURST_DIR, "analyzed");
610
+ var __dirname = path4.dirname(__filename);
611
+ var RAYBURST_DIR = path4.join(os.homedir(), ".rayburst");
612
+ var PROJECTS_FILE = path4.join(RAYBURST_DIR, "projects.json");
613
+ var ANALYZED_DIR = path4.join(RAYBURST_DIR, "analyzed");
488
614
 
489
615
  // src/incremental-analyzer.ts
490
616
  import chalk from "chalk";
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-NIOHEIF6.js";
12
+ } from "./chunk-2VW2AH2U.js";
13
13
  export {
14
14
  addGitignoreEntry,
15
15
  analyzeProject,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rayburstPlugin
3
- } from "./chunk-NIOHEIF6.js";
3
+ } from "./chunk-2VW2AH2U.js";
4
4
  export {
5
5
  rayburstPlugin
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rayburst/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
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.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"