commitect 1.0.2 → 1.1.0
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 +4 -4
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +6 -8
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/clear-cache.js +4 -4
- package/dist/commands/clear-cache.js.map +1 -1
- package/dist/commands/commit.js +8 -8
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/copy.js +7 -7
- package/dist/commands/copy.js.map +1 -1
- package/dist/commands/help.js +2 -2
- package/dist/commands/history.js +2 -2
- package/dist/commands/history.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/services/llm.d.ts +6 -1
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +191 -11
- package/dist/services/llm.js.map +1 -1
- package/package.json +1 -1
- package/public/banner.png +0 -0
- package/src/commands/analyze.ts +6 -8
- package/src/commands/clear-cache.ts +4 -4
- package/src/commands/commit.ts +8 -8
- package/src/commands/copy.ts +7 -7
- package/src/commands/help.ts +2 -2
- package/src/commands/history.ts +2 -2
- package/src/index.ts +1 -1
- package/src/services/llm.ts +282 -11
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npm install
|
|
24
|
+
npm install commitect
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
## Usage
|
|
@@ -49,7 +49,7 @@ commitect copy
|
|
|
49
49
|
|
|
50
50
|
**Output:**
|
|
51
51
|
```
|
|
52
|
-
|
|
52
|
+
✓ Commit message copied to clipboard
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
### Auto-Commit
|
|
@@ -62,7 +62,7 @@ commitect commit
|
|
|
62
62
|
|
|
63
63
|
**Output:**
|
|
64
64
|
```
|
|
65
|
-
|
|
65
|
+
✓ Committed: Feature: Add user authentication with JWT tokens
|
|
66
66
|
```
|
|
67
67
|
|
|
68
68
|
### View History
|
|
@@ -100,7 +100,7 @@ commitect clear-cache
|
|
|
100
100
|
|
|
101
101
|
**Output:**
|
|
102
102
|
```
|
|
103
|
-
|
|
103
|
+
✓ Cache cleared (15 entries removed)
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
## How It Works
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAIA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAIA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAqCpD"}
|
package/dist/commands/analyze.js
CHANGED
|
@@ -5,34 +5,32 @@ export async function analyzeCommand() {
|
|
|
5
5
|
try {
|
|
6
6
|
// Validate git repository
|
|
7
7
|
if (!isGitRepository()) {
|
|
8
|
-
console.error(chalk.red('
|
|
8
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
9
9
|
process.exit(1);
|
|
10
10
|
}
|
|
11
11
|
// Check for changes
|
|
12
12
|
if (!hasChanges()) {
|
|
13
|
-
console.log(chalk.yellow('⚠
|
|
13
|
+
console.log(chalk.yellow('⚠ No changes detected'));
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
16
16
|
// Get diff
|
|
17
17
|
const diff = getGitDiff();
|
|
18
18
|
if (!diff.trim()) {
|
|
19
|
-
console.log(chalk.yellow('⚠
|
|
19
|
+
console.log(chalk.yellow('⚠ No changes to analyze'));
|
|
20
20
|
process.exit(0);
|
|
21
21
|
}
|
|
22
22
|
// Generate commit message
|
|
23
|
-
console.log(chalk.blue('
|
|
23
|
+
console.log(chalk.blue('🔎︎ Analyzing changes...'));
|
|
24
24
|
const suggestion = await generateCommitMessage(diff);
|
|
25
25
|
// Print result
|
|
26
|
-
console.log('');
|
|
27
26
|
console.log(chalk.green(`${suggestion.intent}: ${suggestion.message}`));
|
|
28
|
-
console.log('');
|
|
29
27
|
}
|
|
30
28
|
catch (error) {
|
|
31
29
|
if (error instanceof Error) {
|
|
32
|
-
console.error(chalk.red('
|
|
30
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
33
31
|
}
|
|
34
32
|
else {
|
|
35
|
-
console.error(chalk.red('
|
|
33
|
+
console.error(chalk.red('✗ An unexpected error occurred'));
|
|
36
34
|
}
|
|
37
35
|
process.exit(1);
|
|
38
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,oBAAoB;QACpB,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,WAAW;QACX,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAE1B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAErD,eAAe;QACf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAE1E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -4,18 +4,18 @@ export function clearCacheCommand() {
|
|
|
4
4
|
try {
|
|
5
5
|
const stats = commitCache.getStats();
|
|
6
6
|
if (stats.size === 0) {
|
|
7
|
-
console.log(chalk.yellow('ℹ
|
|
7
|
+
console.log(chalk.yellow('ℹ Cache is already empty'));
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
commitCache.clear();
|
|
11
|
-
console.log(chalk.green(
|
|
11
|
+
console.log(chalk.green(`✓ Cache cleared (${stats.size} entries removed)`));
|
|
12
12
|
}
|
|
13
13
|
catch (error) {
|
|
14
14
|
if (error instanceof Error) {
|
|
15
|
-
console.error(chalk.red('
|
|
15
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
16
16
|
}
|
|
17
17
|
else {
|
|
18
|
-
console.error(chalk.red('
|
|
18
|
+
console.error(chalk.red('✗ Failed to clear cache'));
|
|
19
19
|
}
|
|
20
20
|
process.exit(1);
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clear-cache.js","sourceRoot":"","sources":["../../src/commands/clear-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;QAErC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"clear-cache.js","sourceRoot":"","sources":["../../src/commands/clear-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;QAErC,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;YACvD,OAAO;QACT,CAAC;QAED,WAAW,CAAC,KAAK,EAAE,CAAC;QACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,KAAK,CAAC,IAAI,mBAAmB,CAAC,CAAC,CAAC;IAC/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
package/dist/commands/commit.js
CHANGED
|
@@ -5,36 +5,36 @@ export async function commitCommand() {
|
|
|
5
5
|
try {
|
|
6
6
|
// Validate git repository
|
|
7
7
|
if (!isGitRepository()) {
|
|
8
|
-
console.error(chalk.red('
|
|
8
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
9
9
|
process.exit(1);
|
|
10
10
|
}
|
|
11
11
|
// Check for changes
|
|
12
12
|
if (!hasChanges()) {
|
|
13
|
-
console.log(chalk.yellow('⚠
|
|
13
|
+
console.log(chalk.yellow('⚠ No changes to commit'));
|
|
14
14
|
process.exit(0);
|
|
15
15
|
}
|
|
16
16
|
// Get diff
|
|
17
17
|
const diff = getGitDiff();
|
|
18
18
|
if (!diff.trim()) {
|
|
19
|
-
console.log(chalk.yellow('⚠
|
|
19
|
+
console.log(chalk.yellow('⚠ No changes to commit'));
|
|
20
20
|
process.exit(0);
|
|
21
21
|
}
|
|
22
22
|
// Generate commit message
|
|
23
|
-
console.log(chalk.blue('
|
|
23
|
+
console.log(chalk.blue('🔎︎ Generating commit message...'));
|
|
24
24
|
const suggestion = await generateCommitMessage(diff);
|
|
25
25
|
// Build commit message as "intent: message"
|
|
26
26
|
const commitMessage = `${suggestion.intent}: ${suggestion.message}`;
|
|
27
27
|
// Execute git commit
|
|
28
|
-
console.log(chalk.blue('
|
|
28
|
+
console.log(chalk.blue('🖫 Committing changes...'));
|
|
29
29
|
executeCommit(commitMessage);
|
|
30
|
-
console.log(chalk.green('
|
|
30
|
+
console.log(chalk.green('✓ Committed: ') + commitMessage);
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
33
|
if (error instanceof Error) {
|
|
34
|
-
console.error(chalk.red('
|
|
34
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
console.error(chalk.red('
|
|
37
|
+
console.error(chalk.red('✗ An unexpected error occurred'));
|
|
38
38
|
}
|
|
39
39
|
process.exit(1);
|
|
40
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/commands/commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,oBAAoB;QACpB,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,WAAW;QACX,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAE1B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAErD,4CAA4C;QAC5C,MAAM,aAAa,GAAG,GAAG,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC;QAEpE,qBAAqB;QACrB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,aAAa,CAAC,aAAa,CAAC,CAAC;QAE7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,aAAa,CAAC,CAAC;IAE7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
package/dist/commands/copy.js
CHANGED
|
@@ -6,35 +6,35 @@ export async function copyCommand() {
|
|
|
6
6
|
try {
|
|
7
7
|
// Validate git repository
|
|
8
8
|
if (!isGitRepository()) {
|
|
9
|
-
console.error(chalk.red('
|
|
9
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
10
10
|
process.exit(1);
|
|
11
11
|
}
|
|
12
12
|
// Check for changes
|
|
13
13
|
if (!hasChanges()) {
|
|
14
|
-
console.log(chalk.yellow('⚠
|
|
14
|
+
console.log(chalk.yellow('⚠ No changes detected'));
|
|
15
15
|
process.exit(0);
|
|
16
16
|
}
|
|
17
17
|
// Get diff
|
|
18
18
|
const diff = getGitDiff();
|
|
19
19
|
if (!diff.trim()) {
|
|
20
|
-
console.log(chalk.yellow('⚠
|
|
20
|
+
console.log(chalk.yellow('⚠ No changes to analyze'));
|
|
21
21
|
process.exit(0);
|
|
22
22
|
}
|
|
23
23
|
// Generate commit message
|
|
24
|
-
console.log(chalk.blue('
|
|
24
|
+
console.log(chalk.blue('🔎︎ Generating commit message...'));
|
|
25
25
|
const suggestion = await generateCommitMessage(diff);
|
|
26
26
|
// Build commit message as "intent: message"
|
|
27
27
|
const commitMessage = `${suggestion.intent}: ${suggestion.message}`;
|
|
28
28
|
// Copy to clipboard
|
|
29
29
|
await clipboardy.write(commitMessage);
|
|
30
|
-
console.log(chalk.green('
|
|
30
|
+
console.log(chalk.green('✓ Commit message copied to clipboard'));
|
|
31
31
|
}
|
|
32
32
|
catch (error) {
|
|
33
33
|
if (error instanceof Error) {
|
|
34
|
-
console.error(chalk.red('
|
|
34
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
35
35
|
}
|
|
36
36
|
else {
|
|
37
|
-
console.error(chalk.red('
|
|
37
|
+
console.error(chalk.red('✗ An unexpected error occurred'));
|
|
38
38
|
}
|
|
39
39
|
process.exit(1);
|
|
40
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/commands/copy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"copy.js","sourceRoot":"","sources":["../../src/commands/copy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,oBAAoB;QACpB,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,WAAW;QACX,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAE1B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAErD,4CAA4C;QAC5C,MAAM,aAAa,GAAG,GAAG,UAAU,CAAC,MAAM,KAAK,UAAU,CAAC,OAAO,EAAE,CAAC;QAEpE,oBAAoB;QACpB,MAAM,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAEtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAAC;IAEpE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
package/dist/commands/help.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
const VERSION = '1.0
|
|
3
|
-
const GITHUB_REPO = 'https://github.com/
|
|
2
|
+
const VERSION = '1.1.0';
|
|
3
|
+
const GITHUB_REPO = 'https://github.com/Mohammed-3tef/CommiTect_CLI';
|
|
4
4
|
const ISSUES_URL = GITHUB_REPO + '/issues';
|
|
5
5
|
export function helpCommand() {
|
|
6
6
|
console.log('');
|
package/dist/commands/history.js
CHANGED
|
@@ -27,10 +27,10 @@ export function historyCommand() {
|
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
29
29
|
if (error instanceof Error) {
|
|
30
|
-
console.error(chalk.red('
|
|
30
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
|
-
console.error(chalk.red('
|
|
33
|
+
console.error(chalk.red('✗ Failed to load history'));
|
|
34
34
|
}
|
|
35
35
|
process.exit(1);
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/commands/history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;QAEzC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC,CAAC;YAC7F,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAE5C,+CAA+C;YAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACzG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,cAAc,EAAE,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,MAAM,yBAAyB,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC5G,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAElB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/commands/history.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
package/dist/services/llm.d.ts
CHANGED
|
@@ -2,5 +2,10 @@ export interface CommitSuggestion {
|
|
|
2
2
|
intent: string;
|
|
3
3
|
message: string;
|
|
4
4
|
}
|
|
5
|
-
|
|
5
|
+
interface ChangeSummary {
|
|
6
|
+
total?: number;
|
|
7
|
+
renamed?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function generateCommitMessage(diff: string, summary?: ChangeSummary): Promise<CommitSuggestion>;
|
|
10
|
+
export {};
|
|
6
11
|
//# sourceMappingURL=llm.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAyBD,UAAU,aAAa;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsF5G"}
|
package/dist/services/llm.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
+
import crypto from 'crypto';
|
|
2
3
|
import { commitCache } from '../utils/cache.js';
|
|
3
4
|
const API_ENDPOINT = 'http://commitintentdetector.runasp.net/api/Commit/analyze';
|
|
4
|
-
export async function generateCommitMessage(diff) {
|
|
5
|
+
export async function generateCommitMessage(diff, summary) {
|
|
6
|
+
const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
|
|
5
7
|
// Check cache first
|
|
6
|
-
const cached = commitCache.get(
|
|
8
|
+
const cached = commitCache.get(diffHash);
|
|
7
9
|
if (cached) {
|
|
8
10
|
return cached;
|
|
9
11
|
}
|
|
@@ -15,7 +17,7 @@ export async function generateCommitMessage(diff) {
|
|
|
15
17
|
headers: {
|
|
16
18
|
'Content-Type': 'application/json'
|
|
17
19
|
},
|
|
18
|
-
timeout:
|
|
20
|
+
timeout: 10000
|
|
19
21
|
});
|
|
20
22
|
// API returns: { intent: "Intent: Feature\nMessage: Add subtraction support function" }
|
|
21
23
|
const data = response.data;
|
|
@@ -24,7 +26,7 @@ export async function generateCommitMessage(diff) {
|
|
|
24
26
|
}
|
|
25
27
|
const result = parseResponse(data.intent);
|
|
26
28
|
// Cache the result
|
|
27
|
-
commitCache.set(
|
|
29
|
+
commitCache.set(diffHash, result.intent, result.message);
|
|
28
30
|
return result;
|
|
29
31
|
}
|
|
30
32
|
catch (error) {
|
|
@@ -34,25 +36,24 @@ export async function generateCommitMessage(diff) {
|
|
|
34
36
|
// Handle rate limiting (429)
|
|
35
37
|
if (axiosError.response?.status === 429) {
|
|
36
38
|
if (attempt < maxRetries) {
|
|
37
|
-
await sleep(
|
|
39
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
38
40
|
continue;
|
|
39
41
|
}
|
|
40
|
-
|
|
42
|
+
break;
|
|
41
43
|
}
|
|
42
44
|
// Handle server errors (5xx) - retry
|
|
43
45
|
if (axiosError.response?.status && axiosError.response.status >= 500) {
|
|
44
46
|
if (attempt < maxRetries) {
|
|
45
|
-
await sleep(
|
|
47
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
46
48
|
continue;
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
// Handle network errors - retry
|
|
50
52
|
if (axiosError.code === 'ECONNREFUSED' || axiosError.code === 'ETIMEDOUT') {
|
|
51
53
|
if (attempt < maxRetries) {
|
|
52
|
-
await sleep(
|
|
54
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
53
55
|
continue;
|
|
54
56
|
}
|
|
55
|
-
throw new Error('Unable to connect to API. Please check your network connection.');
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
// Don't retry on client errors (4xx) except 429
|
|
@@ -61,12 +62,13 @@ export async function generateCommitMessage(diff) {
|
|
|
61
62
|
}
|
|
62
63
|
// Retry on other errors
|
|
63
64
|
if (attempt < maxRetries) {
|
|
64
|
-
await sleep(
|
|
65
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
65
66
|
continue;
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
+
console.warn('⚠ AI service unavailable, using fallback commit message.');
|
|
71
|
+
return generateFallbackCommit(diff, summary);
|
|
70
72
|
}
|
|
71
73
|
function parseResponse(response) {
|
|
72
74
|
const lines = response.trim().split('\n');
|
|
@@ -88,6 +90,184 @@ function parseResponse(response) {
|
|
|
88
90
|
}
|
|
89
91
|
return { intent, message };
|
|
90
92
|
}
|
|
93
|
+
function extractFilesFromDiff(diff) {
|
|
94
|
+
const files = new Set();
|
|
95
|
+
const regex = /^diff --git a\/(.+?) b\/(.+)$/gm;
|
|
96
|
+
let match;
|
|
97
|
+
while ((match = regex.exec(diff))) {
|
|
98
|
+
files.add(match[2]);
|
|
99
|
+
}
|
|
100
|
+
return [...files];
|
|
101
|
+
}
|
|
102
|
+
function isTrivialWhitespace(lines) {
|
|
103
|
+
return lines.every(l => /^[+-]\s*$/.test(l) ||
|
|
104
|
+
/^[+-]\s*[{}();,]*\s*$/.test(l));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Analyze the diff content for patterns
|
|
108
|
+
* @param diff - The git diff string
|
|
109
|
+
* @param summary - Optional summary with file change counts
|
|
110
|
+
* @returns Analysis results with detected patterns
|
|
111
|
+
*/
|
|
112
|
+
function analyzeDiff(diff, summary = {}) {
|
|
113
|
+
const lines = diff.split('\n');
|
|
114
|
+
const lowerDiff = diff.toLowerCase();
|
|
115
|
+
const files = extractFilesFromDiff(diff);
|
|
116
|
+
const addedLines = lines.filter(l => l.startsWith('+') && !l.startsWith('+++'));
|
|
117
|
+
const removedLines = lines.filter(l => l.startsWith('-') && !l.startsWith('---'));
|
|
118
|
+
const additions = addedLines.length;
|
|
119
|
+
const deletions = removedLines.length;
|
|
120
|
+
const matchesAny = (patterns, text) => patterns.some(p => p.test(text));
|
|
121
|
+
const patterns = {
|
|
122
|
+
bugFix: [/\b(fix(e[ds])?|bug|error|issue|crash|incorrect|fault)\b/i],
|
|
123
|
+
testFix: [/\b(fix|repair|correct).*(test|spec)\b/i],
|
|
124
|
+
refactor: [/\b(refactor|cleanup|simplify|restructure|reorganize)\b/i],
|
|
125
|
+
style: [/\b(format|lint|prettier|indent)\b/i]
|
|
126
|
+
};
|
|
127
|
+
const hasDocsChange = files.some(f => /\.(md|rst|txt)$/i.test(f) || /readme/i.test(f));
|
|
128
|
+
const hasTestChange = files.some(f => /(__tests__|\.test\.|\.spec\.)/i.test(f));
|
|
129
|
+
const hasConfigChange = files.some(f => /\.(json|ya?ml|env|toml)$/i.test(f));
|
|
130
|
+
const hasDependencyChange = files.some(f => /(package(-lock)?\.json|requirements\.txt|go\.mod|pom\.xml)/i.test(f));
|
|
131
|
+
const hasNewFunction = addedLines.some(l => /^\+\s*(export\s+)?(async\s+)?function\s+\w+/.test(l) ||
|
|
132
|
+
/^\+\s*(export\s+)?const\s+\w+\s*=\s*(async\s*)?\(/.test(l));
|
|
133
|
+
const hasNewClass = addedLines.some(l => /^\+\s*(export\s+)?class\s+\w+/.test(l));
|
|
134
|
+
const hasNewEndpoint = addedLines.some(l => /\b(app|router)\.(get|post|put|delete|patch)\b/i.test(l)) ||
|
|
135
|
+
/^\+\s*@(Get|Post|Put|Delete|Patch)\b/m.test(diff);
|
|
136
|
+
const hasNewComponent = files.some(f => /\.(jsx|tsx)$/i.test(f)) &&
|
|
137
|
+
addedLines.some(l => /^\+\s*(export\s+)?(function|const)\s+[A-Z]\w*/.test(l));
|
|
138
|
+
const hasWhitespaceOnly = additions + deletions > 0 &&
|
|
139
|
+
isTrivialWhitespace([...addedLines, ...removedLines]);
|
|
140
|
+
return {
|
|
141
|
+
hasBugFix: matchesAny(patterns.bugFix, diff),
|
|
142
|
+
hasTestFix: hasTestChange && matchesAny(patterns.testFix, diff),
|
|
143
|
+
hasNewFunction,
|
|
144
|
+
hasNewClass,
|
|
145
|
+
hasNewEndpoint,
|
|
146
|
+
hasNewComponent,
|
|
147
|
+
hasRefactor: matchesAny(patterns.refactor, diff),
|
|
148
|
+
hasRename: (summary.renamed ?? 0) > 0,
|
|
149
|
+
hasMovedCode: (summary.renamed ?? 0) > 0 && additions > 0 && deletions > 0,
|
|
150
|
+
hasDocsChange,
|
|
151
|
+
hasCommentChange: addedLines.some(l => /^\+\s*(\/\/|\/\*|\*)/.test(l)),
|
|
152
|
+
hasTestChange,
|
|
153
|
+
hasDeletions: deletions > 0,
|
|
154
|
+
hasStyleChange: matchesAny(patterns.style, diff),
|
|
155
|
+
hasWhitespaceOnly,
|
|
156
|
+
hasConfigChange,
|
|
157
|
+
hasDependencyChange,
|
|
158
|
+
additions,
|
|
159
|
+
deletions,
|
|
160
|
+
hasChanges: additions + deletions > 0
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Determine the commit intent type based on analysis
|
|
165
|
+
* @param analysis - Analysis results from analyzeDiff
|
|
166
|
+
* @param summary - Changes summary
|
|
167
|
+
* @returns The intent type string
|
|
168
|
+
*/
|
|
169
|
+
function determineIntent(analysis, summary = {}) {
|
|
170
|
+
if (!analysis.hasChanges)
|
|
171
|
+
return 'Chore';
|
|
172
|
+
if (analysis.hasBugFix || analysis.hasTestFix)
|
|
173
|
+
return 'Bug Fix';
|
|
174
|
+
if (analysis.hasTestChange && !analysis.hasBugFix)
|
|
175
|
+
return 'Test';
|
|
176
|
+
if (analysis.hasDocsChange)
|
|
177
|
+
return 'Documentation';
|
|
178
|
+
if (analysis.hasRefactor ||
|
|
179
|
+
analysis.hasMovedCode ||
|
|
180
|
+
(analysis.deletions > analysis.additions * 2))
|
|
181
|
+
return 'Refactor';
|
|
182
|
+
if (analysis.hasNewFunction ||
|
|
183
|
+
analysis.hasNewClass ||
|
|
184
|
+
analysis.hasNewComponent ||
|
|
185
|
+
analysis.hasNewEndpoint)
|
|
186
|
+
return 'Feature';
|
|
187
|
+
if (analysis.hasDependencyChange || analysis.hasConfigChange)
|
|
188
|
+
return 'Chore';
|
|
189
|
+
if (analysis.hasStyleChange || analysis.hasWhitespaceOnly)
|
|
190
|
+
return 'Style';
|
|
191
|
+
return 'Update';
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Generate a descriptive commit message based on analysis
|
|
195
|
+
* @param analysis - Analysis results from analyzeDiff
|
|
196
|
+
* @param intent - The determined intent type
|
|
197
|
+
* @returns A commit message string
|
|
198
|
+
*/
|
|
199
|
+
function generateMessage(analysis, intent, summary = {}) {
|
|
200
|
+
const fileCount = summary.total;
|
|
201
|
+
const hasFileCount = typeof fileCount === 'number' && fileCount > 0;
|
|
202
|
+
const fileWord = fileCount === 1 ? 'file' : 'files';
|
|
203
|
+
switch (intent) {
|
|
204
|
+
case 'Bug Fix':
|
|
205
|
+
return analysis.hasTestFix
|
|
206
|
+
? hasFileCount
|
|
207
|
+
? `fix failing tests in ${fileCount} ${fileWord}`
|
|
208
|
+
: 'fix failing tests'
|
|
209
|
+
: hasFileCount
|
|
210
|
+
? `fix issues in ${fileCount} ${fileWord}`
|
|
211
|
+
: 'fix issues';
|
|
212
|
+
case 'Feature':
|
|
213
|
+
if (analysis.hasNewEndpoint)
|
|
214
|
+
return 'add new API endpoints';
|
|
215
|
+
if (analysis.hasNewComponent)
|
|
216
|
+
return 'add new components';
|
|
217
|
+
if (analysis.hasNewClass || analysis.hasNewFunction)
|
|
218
|
+
return hasFileCount
|
|
219
|
+
? `add new functionality to ${fileCount} ${fileWord}`
|
|
220
|
+
: 'add new functionality';
|
|
221
|
+
return hasFileCount
|
|
222
|
+
? `implement new features in ${fileCount} ${fileWord}`
|
|
223
|
+
: 'implement new features';
|
|
224
|
+
case 'Refactor':
|
|
225
|
+
if (analysis.hasMovedCode)
|
|
226
|
+
return hasFileCount
|
|
227
|
+
? `restructure code in ${fileCount} ${fileWord}`
|
|
228
|
+
: 'restructure code';
|
|
229
|
+
if (analysis.deletions > analysis.additions * 2)
|
|
230
|
+
return hasFileCount
|
|
231
|
+
? `remove unused code from ${fileCount} ${fileWord}`
|
|
232
|
+
: 'remove unused code';
|
|
233
|
+
return hasFileCount
|
|
234
|
+
? `refactor code in ${fileCount} ${fileWord}`
|
|
235
|
+
: 'refactor code';
|
|
236
|
+
case 'Test':
|
|
237
|
+
return hasFileCount
|
|
238
|
+
? `add/update tests in ${fileCount} ${fileWord}`
|
|
239
|
+
: 'add/update tests';
|
|
240
|
+
case 'Chore':
|
|
241
|
+
if (analysis.hasDependencyChange)
|
|
242
|
+
return 'update dependencies';
|
|
243
|
+
if (analysis.hasConfigChange)
|
|
244
|
+
return 'update configuration files';
|
|
245
|
+
return 'update project configuration';
|
|
246
|
+
case 'Style':
|
|
247
|
+
return hasFileCount
|
|
248
|
+
? `format and style ${fileCount} ${fileWord}`
|
|
249
|
+
: 'format and style code';
|
|
250
|
+
case 'Documentation':
|
|
251
|
+
return hasFileCount
|
|
252
|
+
? fileCount === 1
|
|
253
|
+
? 'update documentation'
|
|
254
|
+
: `update documentation in ${fileCount} ${fileWord}`
|
|
255
|
+
: 'update documentation';
|
|
256
|
+
default:
|
|
257
|
+
return hasFileCount
|
|
258
|
+
? `update ${fileCount} ${fileWord}`
|
|
259
|
+
: 'update code';
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function generateFallbackCommit(diff, summary) {
|
|
263
|
+
const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
|
|
264
|
+
const analysis = analyzeDiff(diff, summary);
|
|
265
|
+
const intent = determineIntent(analysis, summary);
|
|
266
|
+
const message = generateMessage(analysis, intent, summary);
|
|
267
|
+
const result = { intent, message };
|
|
268
|
+
commitCache.set(diffHash, intent, message);
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
91
271
|
function sleep(ms) {
|
|
92
272
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
93
273
|
}
|
package/dist/services/llm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/services/llm.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
Binary file
|
package/src/commands/analyze.ts
CHANGED
|
@@ -6,13 +6,13 @@ export async function analyzeCommand(): Promise<void> {
|
|
|
6
6
|
try {
|
|
7
7
|
// Validate git repository
|
|
8
8
|
if (!isGitRepository()) {
|
|
9
|
-
console.error(chalk.red('
|
|
9
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
10
10
|
process.exit(1);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// Check for changes
|
|
14
14
|
if (!hasChanges()) {
|
|
15
|
-
console.log(chalk.yellow('⚠
|
|
15
|
+
console.log(chalk.yellow('⚠ No changes detected'));
|
|
16
16
|
process.exit(0);
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -20,24 +20,22 @@ export async function analyzeCommand(): Promise<void> {
|
|
|
20
20
|
const diff = getGitDiff();
|
|
21
21
|
|
|
22
22
|
if (!diff.trim()) {
|
|
23
|
-
console.log(chalk.yellow('⚠
|
|
23
|
+
console.log(chalk.yellow('⚠ No changes to analyze'));
|
|
24
24
|
process.exit(0);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Generate commit message
|
|
28
|
-
console.log(chalk.blue('
|
|
28
|
+
console.log(chalk.blue('🔎︎ Analyzing changes...'));
|
|
29
29
|
const suggestion = await generateCommitMessage(diff);
|
|
30
30
|
|
|
31
31
|
// Print result
|
|
32
|
-
console.log('');
|
|
33
32
|
console.log(chalk.green(`${suggestion.intent}: ${suggestion.message}`));
|
|
34
|
-
console.log('');
|
|
35
33
|
|
|
36
34
|
} catch (error) {
|
|
37
35
|
if (error instanceof Error) {
|
|
38
|
-
console.error(chalk.red('
|
|
36
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
39
37
|
} else {
|
|
40
|
-
console.error(chalk.red('
|
|
38
|
+
console.error(chalk.red('✗ An unexpected error occurred'));
|
|
41
39
|
}
|
|
42
40
|
process.exit(1);
|
|
43
41
|
}
|
|
@@ -6,17 +6,17 @@ export function clearCacheCommand(): void {
|
|
|
6
6
|
const stats = commitCache.getStats();
|
|
7
7
|
|
|
8
8
|
if (stats.size === 0) {
|
|
9
|
-
console.log(chalk.yellow('ℹ
|
|
9
|
+
console.log(chalk.yellow('ℹ Cache is already empty'));
|
|
10
10
|
return;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
commitCache.clear();
|
|
14
|
-
console.log(chalk.green(
|
|
14
|
+
console.log(chalk.green(`✓ Cache cleared (${stats.size} entries removed)`));
|
|
15
15
|
} catch (error) {
|
|
16
16
|
if (error instanceof Error) {
|
|
17
|
-
console.error(chalk.red('
|
|
17
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
18
18
|
} else {
|
|
19
|
-
console.error(chalk.red('
|
|
19
|
+
console.error(chalk.red('✗ Failed to clear cache'));
|
|
20
20
|
}
|
|
21
21
|
process.exit(1);
|
|
22
22
|
}
|
package/src/commands/commit.ts
CHANGED
|
@@ -6,13 +6,13 @@ export async function commitCommand(): Promise<void> {
|
|
|
6
6
|
try {
|
|
7
7
|
// Validate git repository
|
|
8
8
|
if (!isGitRepository()) {
|
|
9
|
-
console.error(chalk.red('
|
|
9
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
10
10
|
process.exit(1);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// Check for changes
|
|
14
14
|
if (!hasChanges()) {
|
|
15
|
-
console.log(chalk.yellow('⚠
|
|
15
|
+
console.log(chalk.yellow('⚠ No changes to commit'));
|
|
16
16
|
process.exit(0);
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -20,28 +20,28 @@ export async function commitCommand(): Promise<void> {
|
|
|
20
20
|
const diff = getGitDiff();
|
|
21
21
|
|
|
22
22
|
if (!diff.trim()) {
|
|
23
|
-
console.log(chalk.yellow('⚠
|
|
23
|
+
console.log(chalk.yellow('⚠ No changes to commit'));
|
|
24
24
|
process.exit(0);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Generate commit message
|
|
28
|
-
console.log(chalk.blue('
|
|
28
|
+
console.log(chalk.blue('🔎︎ Generating commit message...'));
|
|
29
29
|
const suggestion = await generateCommitMessage(diff);
|
|
30
30
|
|
|
31
31
|
// Build commit message as "intent: message"
|
|
32
32
|
const commitMessage = `${suggestion.intent}: ${suggestion.message}`;
|
|
33
33
|
|
|
34
34
|
// Execute git commit
|
|
35
|
-
console.log(chalk.blue('
|
|
35
|
+
console.log(chalk.blue('🖫 Committing changes...'));
|
|
36
36
|
executeCommit(commitMessage);
|
|
37
37
|
|
|
38
|
-
console.log(chalk.green('
|
|
38
|
+
console.log(chalk.green('✓ Committed: ') + commitMessage);
|
|
39
39
|
|
|
40
40
|
} catch (error) {
|
|
41
41
|
if (error instanceof Error) {
|
|
42
|
-
console.error(chalk.red('
|
|
42
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
43
43
|
} else {
|
|
44
|
-
console.error(chalk.red('
|
|
44
|
+
console.error(chalk.red('✗ An unexpected error occurred'));
|
|
45
45
|
}
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
package/src/commands/copy.ts
CHANGED
|
@@ -7,13 +7,13 @@ export async function copyCommand(): Promise<void> {
|
|
|
7
7
|
try {
|
|
8
8
|
// Validate git repository
|
|
9
9
|
if (!isGitRepository()) {
|
|
10
|
-
console.error(chalk.red('
|
|
10
|
+
console.error(chalk.red('✗ Not a git repository'));
|
|
11
11
|
process.exit(1);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
// Check for changes
|
|
15
15
|
if (!hasChanges()) {
|
|
16
|
-
console.log(chalk.yellow('⚠
|
|
16
|
+
console.log(chalk.yellow('⚠ No changes detected'));
|
|
17
17
|
process.exit(0);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -21,12 +21,12 @@ export async function copyCommand(): Promise<void> {
|
|
|
21
21
|
const diff = getGitDiff();
|
|
22
22
|
|
|
23
23
|
if (!diff.trim()) {
|
|
24
|
-
console.log(chalk.yellow('⚠
|
|
24
|
+
console.log(chalk.yellow('⚠ No changes to analyze'));
|
|
25
25
|
process.exit(0);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// Generate commit message
|
|
29
|
-
console.log(chalk.blue('
|
|
29
|
+
console.log(chalk.blue('🔎︎ Generating commit message...'));
|
|
30
30
|
const suggestion = await generateCommitMessage(diff);
|
|
31
31
|
|
|
32
32
|
// Build commit message as "intent: message"
|
|
@@ -35,13 +35,13 @@ export async function copyCommand(): Promise<void> {
|
|
|
35
35
|
// Copy to clipboard
|
|
36
36
|
await clipboardy.write(commitMessage);
|
|
37
37
|
|
|
38
|
-
console.log(chalk.green('
|
|
38
|
+
console.log(chalk.green('✓ Commit message copied to clipboard'));
|
|
39
39
|
|
|
40
40
|
} catch (error) {
|
|
41
41
|
if (error instanceof Error) {
|
|
42
|
-
console.error(chalk.red('
|
|
42
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
43
43
|
} else {
|
|
44
|
-
console.error(chalk.red('
|
|
44
|
+
console.error(chalk.red('✗ An unexpected error occurred'));
|
|
45
45
|
}
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
package/src/commands/help.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
|
|
3
|
-
const VERSION = '1.0
|
|
4
|
-
const GITHUB_REPO = 'https://github.com/
|
|
3
|
+
const VERSION = '1.1.0';
|
|
4
|
+
const GITHUB_REPO = 'https://github.com/Mohammed-3tef/CommiTect_CLI';
|
|
5
5
|
const ISSUES_URL = GITHUB_REPO + '/issues';
|
|
6
6
|
|
|
7
7
|
export function helpCommand(): void {
|
package/src/commands/history.ts
CHANGED
|
@@ -33,9 +33,9 @@ export function historyCommand(): void {
|
|
|
33
33
|
|
|
34
34
|
} catch (error) {
|
|
35
35
|
if (error instanceof Error) {
|
|
36
|
-
console.error(chalk.red('
|
|
36
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
37
37
|
} else {
|
|
38
|
-
console.error(chalk.red('
|
|
38
|
+
console.error(chalk.red('✗ Failed to load history'));
|
|
39
39
|
}
|
|
40
40
|
process.exit(1);
|
|
41
41
|
}
|
package/src/index.ts
CHANGED
package/src/services/llm.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import axios, { AxiosError } from 'axios';
|
|
2
|
+
import crypto from 'crypto';
|
|
2
3
|
import { commitCache } from '../utils/cache.js';
|
|
3
4
|
|
|
4
5
|
export interface CommitSuggestion {
|
|
@@ -6,14 +7,45 @@ export interface CommitSuggestion {
|
|
|
6
7
|
message: string;
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
interface DiffAnalysis {
|
|
11
|
+
hasBugFix: boolean;
|
|
12
|
+
hasTestFix: boolean;
|
|
13
|
+
hasNewFunction: boolean;
|
|
14
|
+
hasNewClass: boolean;
|
|
15
|
+
hasNewEndpoint: boolean;
|
|
16
|
+
hasNewComponent: boolean;
|
|
17
|
+
hasRefactor: boolean;
|
|
18
|
+
hasRename: boolean;
|
|
19
|
+
hasMovedCode: boolean;
|
|
20
|
+
hasDocsChange: boolean;
|
|
21
|
+
hasCommentChange: boolean;
|
|
22
|
+
hasTestChange: boolean;
|
|
23
|
+
hasDeletions: boolean;
|
|
24
|
+
hasStyleChange: boolean;
|
|
25
|
+
hasWhitespaceOnly: boolean;
|
|
26
|
+
hasConfigChange: boolean;
|
|
27
|
+
hasDependencyChange: boolean;
|
|
28
|
+
additions: number;
|
|
29
|
+
deletions: number;
|
|
30
|
+
hasChanges: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface ChangeSummary {
|
|
34
|
+
total?: number;
|
|
35
|
+
renamed?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
9
38
|
const API_ENDPOINT = 'http://commitintentdetector.runasp.net/api/Commit/analyze';
|
|
10
39
|
|
|
11
|
-
export async function generateCommitMessage(diff: string): Promise<CommitSuggestion> {
|
|
40
|
+
export async function generateCommitMessage(diff: string, summary?: ChangeSummary): Promise<CommitSuggestion> {
|
|
41
|
+
const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
|
|
42
|
+
|
|
12
43
|
// Check cache first
|
|
13
|
-
const cached = commitCache.get(
|
|
44
|
+
const cached = commitCache.get(diffHash);
|
|
14
45
|
if (cached) {
|
|
15
46
|
return cached;
|
|
16
47
|
}
|
|
48
|
+
|
|
17
49
|
const maxRetries = 3;
|
|
18
50
|
let lastError: Error | null = null;
|
|
19
51
|
|
|
@@ -26,7 +58,7 @@ export async function generateCommitMessage(diff: string): Promise<CommitSuggest
|
|
|
26
58
|
headers: {
|
|
27
59
|
'Content-Type': 'application/json'
|
|
28
60
|
},
|
|
29
|
-
timeout:
|
|
61
|
+
timeout: 10000
|
|
30
62
|
}
|
|
31
63
|
);
|
|
32
64
|
|
|
@@ -40,7 +72,7 @@ export async function generateCommitMessage(diff: string): Promise<CommitSuggest
|
|
|
40
72
|
const result = parseResponse(data.intent);
|
|
41
73
|
|
|
42
74
|
// Cache the result
|
|
43
|
-
commitCache.set(
|
|
75
|
+
commitCache.set(diffHash, result.intent, result.message);
|
|
44
76
|
|
|
45
77
|
return result;
|
|
46
78
|
|
|
@@ -53,16 +85,16 @@ export async function generateCommitMessage(diff: string): Promise<CommitSuggest
|
|
|
53
85
|
// Handle rate limiting (429)
|
|
54
86
|
if (axiosError.response?.status === 429) {
|
|
55
87
|
if (attempt < maxRetries) {
|
|
56
|
-
await sleep(
|
|
88
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
57
89
|
continue;
|
|
58
90
|
}
|
|
59
|
-
|
|
91
|
+
break;
|
|
60
92
|
}
|
|
61
93
|
|
|
62
94
|
// Handle server errors (5xx) - retry
|
|
63
95
|
if (axiosError.response?.status && axiosError.response.status >= 500) {
|
|
64
96
|
if (attempt < maxRetries) {
|
|
65
|
-
await sleep(
|
|
97
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
66
98
|
continue;
|
|
67
99
|
}
|
|
68
100
|
}
|
|
@@ -70,10 +102,9 @@ export async function generateCommitMessage(diff: string): Promise<CommitSuggest
|
|
|
70
102
|
// Handle network errors - retry
|
|
71
103
|
if (axiosError.code === 'ECONNREFUSED' || axiosError.code === 'ETIMEDOUT') {
|
|
72
104
|
if (attempt < maxRetries) {
|
|
73
|
-
await sleep(
|
|
105
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
74
106
|
continue;
|
|
75
107
|
}
|
|
76
|
-
throw new Error('Unable to connect to API. Please check your network connection.');
|
|
77
108
|
}
|
|
78
109
|
}
|
|
79
110
|
|
|
@@ -84,13 +115,14 @@ export async function generateCommitMessage(diff: string): Promise<CommitSuggest
|
|
|
84
115
|
|
|
85
116
|
// Retry on other errors
|
|
86
117
|
if (attempt < maxRetries) {
|
|
87
|
-
await sleep(
|
|
118
|
+
await sleep(500 * Math.pow(2, attempt));
|
|
88
119
|
continue;
|
|
89
120
|
}
|
|
90
121
|
}
|
|
91
122
|
}
|
|
92
123
|
|
|
93
|
-
|
|
124
|
+
console.warn('⚠ AI service unavailable, using fallback commit message.');
|
|
125
|
+
return generateFallbackCommit(diff, summary);
|
|
94
126
|
}
|
|
95
127
|
|
|
96
128
|
function parseResponse(response: string): CommitSuggestion {
|
|
@@ -118,6 +150,245 @@ function parseResponse(response: string): CommitSuggestion {
|
|
|
118
150
|
return { intent, message };
|
|
119
151
|
}
|
|
120
152
|
|
|
153
|
+
function extractFilesFromDiff(diff: string): string[] {
|
|
154
|
+
const files = new Set<string>();
|
|
155
|
+
const regex = /^diff --git a\/(.+?) b\/(.+)$/gm;
|
|
156
|
+
let match;
|
|
157
|
+
while ((match = regex.exec(diff))) {
|
|
158
|
+
files.add(match[2]);
|
|
159
|
+
}
|
|
160
|
+
return [...files];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function isTrivialWhitespace(lines: string[]): boolean {
|
|
164
|
+
return lines.every(l =>
|
|
165
|
+
/^[+-]\s*$/.test(l) ||
|
|
166
|
+
/^[+-]\s*[{}();,]*\s*$/.test(l)
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Analyze the diff content for patterns
|
|
172
|
+
* @param diff - The git diff string
|
|
173
|
+
* @param summary - Optional summary with file change counts
|
|
174
|
+
* @returns Analysis results with detected patterns
|
|
175
|
+
*/
|
|
176
|
+
function analyzeDiff(diff: string, summary: ChangeSummary = {}): DiffAnalysis {
|
|
177
|
+
const lines = diff.split('\n');
|
|
178
|
+
const lowerDiff = diff.toLowerCase();
|
|
179
|
+
const files = extractFilesFromDiff(diff);
|
|
180
|
+
|
|
181
|
+
const addedLines = lines.filter(l => l.startsWith('+') && !l.startsWith('+++'));
|
|
182
|
+
const removedLines = lines.filter(l => l.startsWith('-') && !l.startsWith('---'));
|
|
183
|
+
|
|
184
|
+
const additions = addedLines.length;
|
|
185
|
+
const deletions = removedLines.length;
|
|
186
|
+
|
|
187
|
+
const matchesAny = (patterns: RegExp[], text: string): boolean =>
|
|
188
|
+
patterns.some(p => p.test(text));
|
|
189
|
+
|
|
190
|
+
const patterns = {
|
|
191
|
+
bugFix: [/\b(fix(e[ds])?|bug|error|issue|crash|incorrect|fault)\b/i],
|
|
192
|
+
testFix: [/\b(fix|repair|correct).*(test|spec)\b/i],
|
|
193
|
+
refactor: [/\b(refactor|cleanup|simplify|restructure|reorganize)\b/i],
|
|
194
|
+
style: [/\b(format|lint|prettier|indent)\b/i]
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const hasDocsChange = files.some(f =>
|
|
198
|
+
/\.(md|rst|txt)$/i.test(f) || /readme/i.test(f)
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
const hasTestChange = files.some(f =>
|
|
202
|
+
/(__tests__|\.test\.|\.spec\.)/i.test(f)
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const hasConfigChange = files.some(f =>
|
|
206
|
+
/\.(json|ya?ml|env|toml)$/i.test(f)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const hasDependencyChange = files.some(f =>
|
|
210
|
+
/(package(-lock)?\.json|requirements\.txt|go\.mod|pom\.xml)/i.test(f)
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
const hasNewFunction =
|
|
214
|
+
addedLines.some(l =>
|
|
215
|
+
/^\+\s*(export\s+)?(async\s+)?function\s+\w+/.test(l) ||
|
|
216
|
+
/^\+\s*(export\s+)?const\s+\w+\s*=\s*(async\s*)?\(/.test(l)
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const hasNewClass =
|
|
220
|
+
addedLines.some(l =>
|
|
221
|
+
/^\+\s*(export\s+)?class\s+\w+/.test(l)
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
const hasNewEndpoint =
|
|
225
|
+
addedLines.some(l =>
|
|
226
|
+
/\b(app|router)\.(get|post|put|delete|patch)\b/i.test(l)
|
|
227
|
+
) ||
|
|
228
|
+
/^\+\s*@(Get|Post|Put|Delete|Patch)\b/m.test(diff);
|
|
229
|
+
|
|
230
|
+
const hasNewComponent =
|
|
231
|
+
files.some(f => /\.(jsx|tsx)$/i.test(f)) &&
|
|
232
|
+
addedLines.some(l =>
|
|
233
|
+
/^\+\s*(export\s+)?(function|const)\s+[A-Z]\w*/.test(l)
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const hasWhitespaceOnly =
|
|
237
|
+
additions + deletions > 0 &&
|
|
238
|
+
isTrivialWhitespace([...addedLines, ...removedLines]);
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
hasBugFix: matchesAny(patterns.bugFix, diff),
|
|
242
|
+
hasTestFix: hasTestChange && matchesAny(patterns.testFix, diff),
|
|
243
|
+
|
|
244
|
+
hasNewFunction,
|
|
245
|
+
hasNewClass,
|
|
246
|
+
hasNewEndpoint,
|
|
247
|
+
hasNewComponent,
|
|
248
|
+
|
|
249
|
+
hasRefactor: matchesAny(patterns.refactor, diff),
|
|
250
|
+
|
|
251
|
+
hasRename: (summary.renamed ?? 0) > 0,
|
|
252
|
+
hasMovedCode: (summary.renamed ?? 0) > 0 && additions > 0 && deletions > 0,
|
|
253
|
+
|
|
254
|
+
hasDocsChange,
|
|
255
|
+
hasCommentChange: addedLines.some(l => /^\+\s*(\/\/|\/\*|\*)/.test(l)),
|
|
256
|
+
hasTestChange,
|
|
257
|
+
|
|
258
|
+
hasDeletions: deletions > 0,
|
|
259
|
+
hasStyleChange: matchesAny(patterns.style, diff),
|
|
260
|
+
|
|
261
|
+
hasWhitespaceOnly,
|
|
262
|
+
hasConfigChange,
|
|
263
|
+
hasDependencyChange,
|
|
264
|
+
|
|
265
|
+
additions,
|
|
266
|
+
deletions,
|
|
267
|
+
hasChanges: additions + deletions > 0
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Determine the commit intent type based on analysis
|
|
273
|
+
* @param analysis - Analysis results from analyzeDiff
|
|
274
|
+
* @param summary - Changes summary
|
|
275
|
+
* @returns The intent type string
|
|
276
|
+
*/
|
|
277
|
+
function determineIntent(analysis: DiffAnalysis, summary: ChangeSummary = {}): string {
|
|
278
|
+
if (!analysis.hasChanges) return 'Chore';
|
|
279
|
+
|
|
280
|
+
if (analysis.hasBugFix || analysis.hasTestFix) return 'Bug Fix';
|
|
281
|
+
if (analysis.hasTestChange && !analysis.hasBugFix) return 'Test';
|
|
282
|
+
if (analysis.hasDocsChange) return 'Documentation';
|
|
283
|
+
|
|
284
|
+
if (
|
|
285
|
+
analysis.hasRefactor ||
|
|
286
|
+
analysis.hasMovedCode ||
|
|
287
|
+
(analysis.deletions > analysis.additions * 2)
|
|
288
|
+
)
|
|
289
|
+
return 'Refactor';
|
|
290
|
+
|
|
291
|
+
if (
|
|
292
|
+
analysis.hasNewFunction ||
|
|
293
|
+
analysis.hasNewClass ||
|
|
294
|
+
analysis.hasNewComponent ||
|
|
295
|
+
analysis.hasNewEndpoint
|
|
296
|
+
)
|
|
297
|
+
return 'Feature';
|
|
298
|
+
|
|
299
|
+
if (analysis.hasDependencyChange || analysis.hasConfigChange) return 'Chore';
|
|
300
|
+
if (analysis.hasStyleChange || analysis.hasWhitespaceOnly) return 'Style';
|
|
301
|
+
|
|
302
|
+
return 'Update';
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Generate a descriptive commit message based on analysis
|
|
307
|
+
* @param analysis - Analysis results from analyzeDiff
|
|
308
|
+
* @param intent - The determined intent type
|
|
309
|
+
* @returns A commit message string
|
|
310
|
+
*/
|
|
311
|
+
function generateMessage(analysis: DiffAnalysis, intent: string, summary: ChangeSummary = {}): string {
|
|
312
|
+
const fileCount = summary.total;
|
|
313
|
+
const hasFileCount = typeof fileCount === 'number' && fileCount > 0;
|
|
314
|
+
const fileWord = fileCount === 1 ? 'file' : 'files';
|
|
315
|
+
|
|
316
|
+
switch (intent) {
|
|
317
|
+
case 'Bug Fix':
|
|
318
|
+
return analysis.hasTestFix
|
|
319
|
+
? hasFileCount
|
|
320
|
+
? `fix failing tests in ${fileCount} ${fileWord}`
|
|
321
|
+
: 'fix failing tests'
|
|
322
|
+
: hasFileCount
|
|
323
|
+
? `fix issues in ${fileCount} ${fileWord}`
|
|
324
|
+
: 'fix issues';
|
|
325
|
+
|
|
326
|
+
case 'Feature':
|
|
327
|
+
if (analysis.hasNewEndpoint) return 'add new API endpoints';
|
|
328
|
+
if (analysis.hasNewComponent) return 'add new components';
|
|
329
|
+
if (analysis.hasNewClass || analysis.hasNewFunction)
|
|
330
|
+
return hasFileCount
|
|
331
|
+
? `add new functionality to ${fileCount} ${fileWord}`
|
|
332
|
+
: 'add new functionality';
|
|
333
|
+
return hasFileCount
|
|
334
|
+
? `implement new features in ${fileCount} ${fileWord}`
|
|
335
|
+
: 'implement new features';
|
|
336
|
+
|
|
337
|
+
case 'Refactor':
|
|
338
|
+
if (analysis.hasMovedCode)
|
|
339
|
+
return hasFileCount
|
|
340
|
+
? `restructure code in ${fileCount} ${fileWord}`
|
|
341
|
+
: 'restructure code';
|
|
342
|
+
if (analysis.deletions > analysis.additions * 2)
|
|
343
|
+
return hasFileCount
|
|
344
|
+
? `remove unused code from ${fileCount} ${fileWord}`
|
|
345
|
+
: 'remove unused code';
|
|
346
|
+
return hasFileCount
|
|
347
|
+
? `refactor code in ${fileCount} ${fileWord}`
|
|
348
|
+
: 'refactor code';
|
|
349
|
+
|
|
350
|
+
case 'Test':
|
|
351
|
+
return hasFileCount
|
|
352
|
+
? `add/update tests in ${fileCount} ${fileWord}`
|
|
353
|
+
: 'add/update tests';
|
|
354
|
+
|
|
355
|
+
case 'Chore':
|
|
356
|
+
if (analysis.hasDependencyChange) return 'update dependencies';
|
|
357
|
+
if (analysis.hasConfigChange) return 'update configuration files';
|
|
358
|
+
return 'update project configuration';
|
|
359
|
+
|
|
360
|
+
case 'Style':
|
|
361
|
+
return hasFileCount
|
|
362
|
+
? `format and style ${fileCount} ${fileWord}`
|
|
363
|
+
: 'format and style code';
|
|
364
|
+
|
|
365
|
+
case 'Documentation':
|
|
366
|
+
return hasFileCount
|
|
367
|
+
? fileCount === 1
|
|
368
|
+
? 'update documentation'
|
|
369
|
+
: `update documentation in ${fileCount} ${fileWord}`
|
|
370
|
+
: 'update documentation';
|
|
371
|
+
|
|
372
|
+
default:
|
|
373
|
+
return hasFileCount
|
|
374
|
+
? `update ${fileCount} ${fileWord}`
|
|
375
|
+
: 'update code';
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function generateFallbackCommit(diff: string, summary?: ChangeSummary): CommitSuggestion {
|
|
380
|
+
const diffHash = crypto.createHash('sha1').update(diff).digest('hex');
|
|
381
|
+
|
|
382
|
+
const analysis = analyzeDiff(diff, summary);
|
|
383
|
+
const intent = determineIntent(analysis, summary);
|
|
384
|
+
const message = generateMessage(analysis, intent, summary);
|
|
385
|
+
|
|
386
|
+
const result = { intent, message };
|
|
387
|
+
commitCache.set(diffHash, intent, message);
|
|
388
|
+
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
|
|
121
392
|
function sleep(ms: number): Promise<void> {
|
|
122
393
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
123
394
|
}
|