@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 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,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 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 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 = path.join(projectPath, "tsconfig.json");
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 = path.join(projectPath, "package.json");
69
- let packageJson = { name: path.basename(projectPath) };
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 || path.basename(projectPath),
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 = path.join(projectPath, "package.json");
117
- let packageJson = { name: path.basename(projectPath) };
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 || path.basename(projectPath),
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 execSync("git rev-parse --short HEAD", { cwd: projectPath, encoding: "utf-8" }).trim();
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 = 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");
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 path2 from "path";
487
+ import path3 from "path";
404
488
  async function ensureRayburstDir(projectPath) {
405
- const rayburstDir = path2.join(projectPath, ".rayburst");
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 = path2.join(projectPath, ".rayburst", "analysis.json");
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 = path2.join(projectPath, ".rayburst", "analysis.json");
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 = path2.join(projectPath, ".rayburst", "meta.json");
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 = path2.join(projectPath, ".rayburst", "meta.json");
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 = path2.join(projectPath, ".gitignore");
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 = path2.join(projectPath, ".rayburst");
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 = path2.basename(projectPath);
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 path3 from "path";
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 = 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");
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
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-NIOHEIF6.js";
12
+ } from "./chunk-ZAT3D23Y.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-ZAT3D23Y.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.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.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"