@nogataka/smart-edit 1.0.1 → 1.0.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.
@@ -35,3 +35,121 @@ async function hasGitOutput(args, options) {
35
35
  const output = await runGitCommand(args, options);
36
36
  return output.length > 0;
37
37
  }
38
+ /**
39
+ * Get the current HEAD commit hash.
40
+ */
41
+ export async function getCurrentCommit(options = {}) {
42
+ try {
43
+ return await runGitCommand(['rev-parse', 'HEAD'], options);
44
+ }
45
+ catch (error) {
46
+ gitLogger.debug('Failed to get current commit', { error });
47
+ return null;
48
+ }
49
+ }
50
+ /**
51
+ * Parse git diff --stat output to extract statistics.
52
+ */
53
+ function parseDiffStatOutput(output) {
54
+ const lines = output.trim().split('\n').filter((line) => line.length > 0);
55
+ let filesChanged = 0;
56
+ let insertions = 0;
57
+ let deletions = 0;
58
+ let newFiles = 0;
59
+ let hasNewInSrc = false;
60
+ const filePattern = /^\s*(.+?)\s*\|\s*(\d+)/;
61
+ const summaryPattern = /(\d+)\s+files?\s+changed(?:,\s+(\d+)\s+insertions?\(\+\))?(?:,\s+(\d+)\s+deletions?\(-\))?/;
62
+ const plusPattern = /\+/g;
63
+ const minusPattern = /-/g;
64
+ // Parse individual file lines
65
+ for (const line of lines) {
66
+ // Match lines like: "src/file.ts | 10 ++++----"
67
+ const fileMatch = filePattern.exec(line);
68
+ if (fileMatch) {
69
+ filesChanged++;
70
+ const filePath = fileMatch[1].trim();
71
+ // Check if it's a new file in src/
72
+ if (filePath.startsWith('src/') && line.includes('(new)')) {
73
+ newFiles++;
74
+ hasNewInSrc = true;
75
+ }
76
+ // Count insertions and deletions from + and - symbols
77
+ const plusMatches = line.match(plusPattern);
78
+ const minusMatches = line.match(minusPattern);
79
+ insertions += plusMatches?.length ?? 0;
80
+ deletions += minusMatches?.length ?? 0;
81
+ }
82
+ // Parse the summary line: "3 files changed, 10 insertions(+), 5 deletions(-)"
83
+ const summaryMatch = summaryPattern.exec(line);
84
+ if (summaryMatch) {
85
+ filesChanged = parseInt(summaryMatch[1], 10);
86
+ if (summaryMatch[2]) {
87
+ insertions = parseInt(summaryMatch[2], 10);
88
+ }
89
+ if (summaryMatch[3]) {
90
+ deletions = parseInt(summaryMatch[3], 10);
91
+ }
92
+ }
93
+ }
94
+ return { filesChanged, insertions, deletions, newFiles, hasNewInSrc };
95
+ }
96
+ /**
97
+ * Get diff statistics between two commits.
98
+ */
99
+ export async function getGitDiffStats(fromCommit, toCommit = 'HEAD', options = {}) {
100
+ try {
101
+ const output = await runGitCommand(['diff', '--stat', `${fromCommit}..${toCommit}`], options);
102
+ return parseDiffStatOutput(output);
103
+ }
104
+ catch (error) {
105
+ gitLogger.debug('Failed to get git diff stats', { error, fromCommit, toCommit });
106
+ return null;
107
+ }
108
+ }
109
+ /**
110
+ * Check if the new files list contains files in src/ directory.
111
+ */
112
+ export async function hasNewFilesInSrc(fromCommit, toCommit = 'HEAD', options = {}) {
113
+ try {
114
+ const output = await runGitCommand(['diff', '--name-status', '--diff-filter=A', `${fromCommit}..${toCommit}`], options);
115
+ const lines = output.trim().split('\n').filter((line) => line.length > 0);
116
+ return lines.some((line) => {
117
+ const parts = line.split('\t');
118
+ const filePath = parts[1] || '';
119
+ return filePath.startsWith('src/');
120
+ });
121
+ }
122
+ catch (error) {
123
+ gitLogger.debug('Failed to check for new files in src/', { error });
124
+ return false;
125
+ }
126
+ }
127
+ /**
128
+ * Determine if there are significant changes since the last commit.
129
+ * Significant changes are defined as:
130
+ * - More than 10 files changed
131
+ * - More than 5 new files
132
+ * - Any new files in src/ directory
133
+ */
134
+ export async function hasSignificantChanges(lastCommit, options = {}) {
135
+ const diffStats = await getGitDiffStats(lastCommit, 'HEAD', options);
136
+ if (!diffStats) {
137
+ return { significant: false, summary: 'Unable to determine changes' };
138
+ }
139
+ const hasNewInSrc = await hasNewFilesInSrc(lastCommit, 'HEAD', options);
140
+ const reasons = [];
141
+ if (diffStats.filesChanged > 10) {
142
+ reasons.push(`${diffStats.filesChanged} files changed`);
143
+ }
144
+ if (diffStats.newFiles > 5) {
145
+ reasons.push(`${diffStats.newFiles} new files`);
146
+ }
147
+ if (hasNewInSrc) {
148
+ reasons.push('new files in src/ directory');
149
+ }
150
+ const significant = reasons.length > 0;
151
+ const summary = significant
152
+ ? `Significant changes detected: ${reasons.join(', ')}`
153
+ : `Minor changes: ${diffStats.filesChanged} files, +${diffStats.insertions}/-${diffStats.deletions}`;
154
+ return { significant, summary };
155
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nogataka/smart-edit",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Smart Edit is a tool for editing code with AI.",
5
5
  "private": false,
6
6
  "license": "MIT",