@rayburst/cli 0.4.13 → 0.4.15

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.
@@ -30,6 +30,79 @@ function getUncommittedChanges(projectPath) {
30
30
  return [];
31
31
  }
32
32
  }
33
+ function getUnstagedChanges(projectPath) {
34
+ try {
35
+ if (!isGitRepository(projectPath)) {
36
+ return [];
37
+ }
38
+ const output = execSync("git diff --name-only", {
39
+ cwd: projectPath,
40
+ encoding: "utf8",
41
+ stdio: ["pipe", "pipe", "ignore"]
42
+ });
43
+ return output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
44
+ } catch (error) {
45
+ console.error("Failed to get unstaged changes:", error.message);
46
+ return [];
47
+ }
48
+ }
49
+ function getStagedChanges(projectPath) {
50
+ try {
51
+ if (!isGitRepository(projectPath)) {
52
+ return [];
53
+ }
54
+ const output = execSync("git diff --name-only --cached", {
55
+ cwd: projectPath,
56
+ encoding: "utf8",
57
+ stdio: ["pipe", "pipe", "ignore"]
58
+ });
59
+ return output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
60
+ } catch (error) {
61
+ console.error("Failed to get staged changes:", error.message);
62
+ return [];
63
+ }
64
+ }
65
+ function getCommittedChanges(projectPath, remoteBranch = void 0) {
66
+ try {
67
+ if (!isGitRepository(projectPath)) {
68
+ return [];
69
+ }
70
+ let currentBranch;
71
+ try {
72
+ currentBranch = execSync("git branch --show-current", {
73
+ cwd: projectPath,
74
+ encoding: "utf8",
75
+ stdio: ["pipe", "pipe", "ignore"]
76
+ }).trim();
77
+ } catch {
78
+ currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
79
+ cwd: projectPath,
80
+ encoding: "utf8",
81
+ stdio: ["pipe", "pipe", "ignore"]
82
+ }).trim();
83
+ }
84
+ const remote = remoteBranch || `origin/${currentBranch}`;
85
+ try {
86
+ execSync(`git rev-parse --verify ${remote}`, {
87
+ cwd: projectPath,
88
+ stdio: ["pipe", "pipe", "ignore"]
89
+ });
90
+ } catch {
91
+ return [];
92
+ }
93
+ const output = execSync(`git diff --name-only ${remote}...HEAD`, {
94
+ cwd: projectPath,
95
+ encoding: "utf8",
96
+ stdio: ["pipe", "pipe", "ignore"]
97
+ });
98
+ const allChanges = output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
99
+ const uncommitted = new Set(getUncommittedChanges(projectPath));
100
+ return allChanges.filter((file) => !uncommitted.has(file));
101
+ } catch (error) {
102
+ console.error("Failed to get committed changes:", error.message);
103
+ return [];
104
+ }
105
+ }
33
106
  function isGitRepository(projectPath) {
34
107
  try {
35
108
  execSync("git rev-parse --is-inside-work-tree", {
@@ -946,26 +1019,44 @@ async function analyzeProject(projectPath, projectId, onLog) {
946
1019
  nodes,
947
1020
  edges
948
1021
  };
1022
+ const filterAndCollectMetadata = (files) => {
1023
+ const filtered = files.filter((filePath) => {
1024
+ return !filePath.includes("node_modules") && !filePath.includes(".test.") && !filePath.includes(".spec.") && (filePath.endsWith(".ts") || filePath.endsWith(".tsx") || filePath.endsWith(".js") || filePath.endsWith(".jsx"));
1025
+ });
1026
+ const metadata = [];
1027
+ for (const filePath of filtered) {
1028
+ try {
1029
+ const stats = fs.statSync(filePath);
1030
+ metadata.push({
1031
+ filePath,
1032
+ lastModified: stats.mtimeMs
1033
+ });
1034
+ } catch (error) {
1035
+ log(` Warning: Could not get stats for ${filePath}`);
1036
+ }
1037
+ }
1038
+ return { filtered, metadata };
1039
+ };
949
1040
  log(" Checking for changed files vs remote...");
950
1041
  const allChangedFiles = getChangedFilesVsRemote(projectPath);
951
1042
  log(` Found ${allChangedFiles.length} changed files`);
952
- const changedFiles = allChangedFiles.filter((filePath) => {
953
- return !filePath.includes("node_modules") && !filePath.includes(".test.") && !filePath.includes(".spec.") && (filePath.endsWith(".ts") || filePath.endsWith(".tsx") || filePath.endsWith(".js") || filePath.endsWith(".jsx"));
954
- });
1043
+ const { filtered: changedFiles, metadata: changedFilesMetadata } = filterAndCollectMetadata(allChangedFiles);
955
1044
  log(` Filtered to ${changedFiles.length} analyzed source files`);
956
- const changedFilesMetadata = [];
957
- for (const filePath of changedFiles) {
958
- try {
959
- const stats = fs.statSync(filePath);
960
- changedFilesMetadata.push({
961
- filePath,
962
- lastModified: stats.mtimeMs
963
- // Unix timestamp in milliseconds
964
- });
965
- } catch (error) {
966
- log(` Warning: Could not get stats for ${filePath}`);
967
- }
968
- }
1045
+ log(" Checking for unstaged changes...");
1046
+ const allUnstagedFiles = getUnstagedChanges(projectPath);
1047
+ log(` Found ${allUnstagedFiles.length} unstaged files`);
1048
+ const { filtered: unstagedFiles, metadata: unstagedFilesMetadata } = filterAndCollectMetadata(allUnstagedFiles);
1049
+ log(` Filtered to ${unstagedFiles.length} analyzed source files`);
1050
+ log(" Checking for staged changes...");
1051
+ const allStagedFiles = getStagedChanges(projectPath);
1052
+ log(` Found ${allStagedFiles.length} staged files`);
1053
+ const { filtered: stagedFiles, metadata: stagedFilesMetadata } = filterAndCollectMetadata(allStagedFiles);
1054
+ log(` Filtered to ${stagedFiles.length} analyzed source files`);
1055
+ log(" Checking for committed changes...");
1056
+ const allCommittedFiles = getCommittedChanges(projectPath);
1057
+ log(` Found ${allCommittedFiles.length} committed files`);
1058
+ const { filtered: committedFiles, metadata: committedFilesMetadata } = filterAndCollectMetadata(allCommittedFiles);
1059
+ log(` Filtered to ${committedFiles.length} analyzed source files`);
969
1060
  const result = {
970
1061
  project: projectMetadata,
971
1062
  branches: [branchMetadata],
@@ -979,6 +1070,24 @@ async function analyzeProject(projectPath, projectId, onLog) {
979
1070
  } : void 0,
980
1071
  changedFilesMetadata: changedFilesMetadata.length > 0 ? {
981
1072
  [branchId]: changedFilesMetadata
1073
+ } : void 0,
1074
+ unstagedFiles: unstagedFiles.length > 0 ? {
1075
+ [branchId]: unstagedFiles
1076
+ } : void 0,
1077
+ unstagedFilesMetadata: unstagedFilesMetadata.length > 0 ? {
1078
+ [branchId]: unstagedFilesMetadata
1079
+ } : void 0,
1080
+ stagedFiles: stagedFiles.length > 0 ? {
1081
+ [branchId]: stagedFiles
1082
+ } : void 0,
1083
+ stagedFilesMetadata: stagedFilesMetadata.length > 0 ? {
1084
+ [branchId]: stagedFilesMetadata
1085
+ } : void 0,
1086
+ committedFiles: committedFiles.length > 0 ? {
1087
+ [branchId]: committedFiles
1088
+ } : void 0,
1089
+ committedFilesMetadata: committedFilesMetadata.length > 0 ? {
1090
+ [branchId]: committedFilesMetadata
982
1091
  } : void 0
983
1092
  };
984
1093
  return result;
@@ -1809,6 +1918,60 @@ var unpluginFactory = (options = {}) => {
1809
1918
  let isAnalyzing = false;
1810
1919
  let lastGitState = null;
1811
1920
  let gitPollInterval = null;
1921
+ const changeHistoryMap = {};
1922
+ const MAX_HISTORY_ENTRIES = 100;
1923
+ const generateNodeChanges = (branchId, oldNodes, newNodes) => {
1924
+ const changes = [];
1925
+ const timestamp = Date.now();
1926
+ const oldNodesMap = new Map((oldNodes || []).map((n) => [n.id, n]));
1927
+ const newNodesMap = new Map(newNodes.map((n) => [n.id, n]));
1928
+ for (const newNode of newNodes) {
1929
+ const oldNode = oldNodesMap.get(newNode.id);
1930
+ if (!oldNode) {
1931
+ changes.push({
1932
+ timestamp,
1933
+ nodeId: newNode.id,
1934
+ changeType: "added",
1935
+ currentState: newNode,
1936
+ filePath: newNode.id.split("::")[0] || ""
1937
+ });
1938
+ } else {
1939
+ const nodeChanged = JSON.stringify(oldNode) !== JSON.stringify(newNode);
1940
+ if (nodeChanged) {
1941
+ changes.push({
1942
+ timestamp,
1943
+ nodeId: newNode.id,
1944
+ changeType: "modified",
1945
+ previousState: oldNode,
1946
+ currentState: newNode,
1947
+ filePath: newNode.id.split("::")[0] || ""
1948
+ });
1949
+ }
1950
+ }
1951
+ }
1952
+ for (const oldNode of oldNodes || []) {
1953
+ if (!newNodesMap.has(oldNode.id)) {
1954
+ changes.push({
1955
+ timestamp,
1956
+ nodeId: oldNode.id,
1957
+ changeType: "removed",
1958
+ previousState: oldNode,
1959
+ filePath: oldNode.id.split("::")[0] || ""
1960
+ });
1961
+ }
1962
+ }
1963
+ return changes;
1964
+ };
1965
+ const addToChangeHistory = (branchId, changes) => {
1966
+ if (changes.length === 0) return;
1967
+ if (!changeHistoryMap[branchId]) {
1968
+ changeHistoryMap[branchId] = [];
1969
+ }
1970
+ changeHistoryMap[branchId].push(...changes);
1971
+ if (changeHistoryMap[branchId].length > MAX_HISTORY_ENTRIES) {
1972
+ changeHistoryMap[branchId] = changeHistoryMap[branchId].slice(-MAX_HISTORY_ENTRIES);
1973
+ }
1974
+ };
1812
1975
  const checkGitState = (projectPath) => {
1813
1976
  try {
1814
1977
  const gitDir = path4.join(projectPath, ".git");
@@ -1849,6 +2012,18 @@ var unpluginFactory = (options = {}) => {
1849
2012
  const projectPath = config.root;
1850
2013
  const previousAnalysis = await readLocalAnalysis(projectPath);
1851
2014
  const newAnalysis = await analyzeProject(projectPath);
2015
+ if (previousAnalysis) {
2016
+ for (const branchId of Object.keys(newAnalysis.planData)) {
2017
+ const oldNodes = previousAnalysis.planData[branchId]?.nodes;
2018
+ const newNodes = newAnalysis.planData[branchId]?.nodes || [];
2019
+ const changes = generateNodeChanges(branchId, oldNodes, newNodes);
2020
+ addToChangeHistory(branchId, changes);
2021
+ if (changes.length > 0) {
2022
+ console.log(chalk.yellow(`[Rayburst] Detected ${changes.length} node changes in branch ${branchId}`));
2023
+ }
2024
+ }
2025
+ }
2026
+ newAnalysis.changeHistory = { ...changeHistoryMap };
1852
2027
  if (previousAnalysis) {
1853
2028
  console.log(chalk.green("[Rayburst] Analysis updated"));
1854
2029
  } else {
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-CQMSZCXH.js";
12
+ } from "./chunk-TYZZLVC2.js";
13
13
  export {
14
14
  addGitignoreEntry,
15
15
  analyzeProject,
@@ -2,7 +2,7 @@ import {
2
2
  rayburstPlugin,
3
3
  unpluginFactory,
4
4
  vite_plugin_default
5
- } from "./chunk-CQMSZCXH.js";
5
+ } from "./chunk-TYZZLVC2.js";
6
6
  export {
7
7
  vite_plugin_default as default,
8
8
  rayburstPlugin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rayburst/cli",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "description": "Rayburst - Automatic code analysis for TypeScript/JavaScript projects via Vite plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,7 +49,7 @@
49
49
  "zod": "^4.2.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@rayburst/types": "^0.1.10",
52
+ "@rayburst/types": "file:../rayburst-types",
53
53
  "@types/node": "^25.0.2",
54
54
  "tsup": "^8.5.1",
55
55
  "typescript": "^5.9.3",