@ksw8954/git-ai-commit 1.1.5 → 1.1.7
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/CHANGELOG.md +25 -0
- package/dist/commands/ai.d.ts +9 -1
- package/dist/commands/ai.d.ts.map +1 -1
- package/dist/commands/ai.js +104 -46
- package/dist/commands/ai.js.map +1 -1
- package/dist/commands/commit.d.ts.map +1 -1
- package/dist/commands/commit.js +2 -0
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/completion.js +1 -1
- package/dist/commands/config.d.ts +6 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +13 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/configCommand.d.ts +2 -0
- package/dist/commands/configCommand.d.ts.map +1 -1
- package/dist/commands/configCommand.js +16 -0
- package/dist/commands/configCommand.js.map +1 -1
- package/dist/commands/git.d.ts +2 -0
- package/dist/commands/git.d.ts.map +1 -1
- package/dist/commands/git.js +30 -0
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/prCommand.d.ts.map +1 -1
- package/dist/commands/prCommand.js +2 -0
- package/dist/commands/prCommand.js.map +1 -1
- package/dist/commands/tag.d.ts +4 -0
- package/dist/commands/tag.d.ts.map +1 -1
- package/dist/commands/tag.js +128 -2
- package/dist/commands/tag.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/ai.test.ts +45 -68
- package/src/__tests__/tagCommand.test.ts +9 -2
- package/src/commands/ai.ts +131 -53
- package/src/commands/commit.ts +2 -0
- package/src/commands/completion.ts +1 -1
- package/src/commands/config.ts +19 -0
- package/src/commands/configCommand.ts +22 -0
- package/src/commands/git.ts +35 -0
- package/src/commands/prCommand.ts +2 -0
- package/src/commands/tag.ts +157 -2
package/src/commands/tag.ts
CHANGED
|
@@ -14,6 +14,13 @@ export interface TagOptions {
|
|
|
14
14
|
prompt?: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
interface TagStyleMismatch {
|
|
18
|
+
newTag: string;
|
|
19
|
+
newPattern: string;
|
|
20
|
+
dominantPattern: string;
|
|
21
|
+
examples: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
export class TagCommand {
|
|
18
25
|
private program: Command;
|
|
19
26
|
|
|
@@ -59,6 +66,8 @@ export class TagCommand {
|
|
|
59
66
|
apiKey: mergedApiKey!,
|
|
60
67
|
baseURL: mergedBaseURL,
|
|
61
68
|
model: mergedModel,
|
|
69
|
+
fallbackModel: storedConfig.fallbackModel,
|
|
70
|
+
reasoningEffort: storedConfig.reasoningEffort,
|
|
62
71
|
language: storedConfig.language
|
|
63
72
|
};
|
|
64
73
|
}
|
|
@@ -106,7 +115,22 @@ export class TagCommand {
|
|
|
106
115
|
trimmedName = newVersion;
|
|
107
116
|
}
|
|
108
117
|
|
|
109
|
-
|
|
118
|
+
const styleMismatch = await this.checkTagStyleMismatch(trimmedName);
|
|
119
|
+
if (styleMismatch) {
|
|
120
|
+
const shouldProceed = await this.confirmStyleMismatch(styleMismatch);
|
|
121
|
+
if (!shouldProceed) {
|
|
122
|
+
console.log('Tag creation cancelled by user.');
|
|
123
|
+
await LogService.append({
|
|
124
|
+
command: 'tag',
|
|
125
|
+
args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
|
|
126
|
+
status: 'cancelled',
|
|
127
|
+
details: `tag style mismatch: "${styleMismatch.newPattern}" vs "${styleMismatch.dominantPattern}"`,
|
|
128
|
+
model: mergedModel
|
|
129
|
+
});
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
110
134
|
const localTagExists = await GitService.tagExists(trimmedName);
|
|
111
135
|
let remoteTagExists = await GitService.remoteTagExists(trimmedName);
|
|
112
136
|
let previousTagMessage: string | null = null;
|
|
@@ -219,7 +243,59 @@ export class TagCommand {
|
|
|
219
243
|
}
|
|
220
244
|
}
|
|
221
245
|
|
|
222
|
-
|
|
246
|
+
let historyResult = await GitService.getCommitSummariesSince(baseTag);
|
|
247
|
+
|
|
248
|
+
if (!historyResult.success && baseTag) {
|
|
249
|
+
console.log(`\n⚠️ No commits found since tag ${baseTag}.`);
|
|
250
|
+
|
|
251
|
+
const shouldDeleteBase = await this.confirmBaseTagDelete(baseTag);
|
|
252
|
+
if (shouldDeleteBase) {
|
|
253
|
+
const olderTagResult = await GitService.getTagBefore(baseTag);
|
|
254
|
+
const olderBase = olderTagResult.success ? olderTagResult.tag : undefined;
|
|
255
|
+
|
|
256
|
+
const localExists = await GitService.tagExists(baseTag);
|
|
257
|
+
if (localExists) {
|
|
258
|
+
const localDeleted = await GitService.deleteLocalTag(baseTag);
|
|
259
|
+
if (localDeleted) {
|
|
260
|
+
console.log(`✅ Local tag ${baseTag} deleted`);
|
|
261
|
+
} else {
|
|
262
|
+
console.error(`❌ Failed to delete local tag ${baseTag}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const remoteExists = await GitService.remoteTagExists(baseTag);
|
|
267
|
+
if (remoteExists) {
|
|
268
|
+
const shouldDeleteRemote = await this.confirmRemoteTagDelete(baseTag);
|
|
269
|
+
if (shouldDeleteRemote) {
|
|
270
|
+
const remoteDeleted = await GitService.deleteRemoteTag(baseTag);
|
|
271
|
+
if (remoteDeleted) {
|
|
272
|
+
console.log(`✅ Remote tag ${baseTag} deleted`);
|
|
273
|
+
} else {
|
|
274
|
+
console.error(`❌ Failed to delete remote tag ${baseTag}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (olderBase) {
|
|
280
|
+
console.log(`Using ${olderBase} as new base tag.`);
|
|
281
|
+
baseTag = olderBase;
|
|
282
|
+
} else {
|
|
283
|
+
console.log('No earlier tag found; using entire commit history.');
|
|
284
|
+
baseTag = undefined;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
styleReferenceMessage = null;
|
|
288
|
+
if (baseTag && baseTag !== trimmedName) {
|
|
289
|
+
styleReferenceMessage = await GitService.getTagMessage(baseTag);
|
|
290
|
+
if (styleReferenceMessage) {
|
|
291
|
+
console.log(`Using ${baseTag} message as style reference.`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
historyResult = await GitService.getCommitSummariesSince(baseTag);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
223
299
|
if (!historyResult.success || !historyResult.log) {
|
|
224
300
|
console.error('Error:', historyResult.error ?? 'Unable to read commit history.');
|
|
225
301
|
await LogService.append({
|
|
@@ -387,6 +463,69 @@ export class TagCommand {
|
|
|
387
463
|
});
|
|
388
464
|
}
|
|
389
465
|
|
|
466
|
+
private extractTagPattern(tagName: string): string {
|
|
467
|
+
return tagName.replace(/[a-zA-Z]+/g, '{word}').replace(/\d+/g, '{n}');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private async checkTagStyleMismatch(newTagName: string): Promise<TagStyleMismatch | null> {
|
|
471
|
+
const recentTags = await GitService.getRecentTags(10);
|
|
472
|
+
if (recentTags.length === 0) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const newPattern = this.extractTagPattern(newTagName);
|
|
477
|
+
|
|
478
|
+
const patternCounts = new Map<string, string[]>();
|
|
479
|
+
for (const tag of recentTags) {
|
|
480
|
+
const pattern = this.extractTagPattern(tag);
|
|
481
|
+
const existing = patternCounts.get(pattern) || [];
|
|
482
|
+
existing.push(tag);
|
|
483
|
+
patternCounts.set(pattern, existing);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
let dominantPattern = '';
|
|
487
|
+
let maxCount = 0;
|
|
488
|
+
let dominantExamples: string[] = [];
|
|
489
|
+
for (const [pattern, tags] of patternCounts) {
|
|
490
|
+
if (tags.length > maxCount) {
|
|
491
|
+
maxCount = tags.length;
|
|
492
|
+
dominantPattern = pattern;
|
|
493
|
+
dominantExamples = tags;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (dominantPattern && dominantPattern !== newPattern && maxCount >= 2) {
|
|
498
|
+
return {
|
|
499
|
+
newTag: newTagName,
|
|
500
|
+
newPattern,
|
|
501
|
+
dominantPattern,
|
|
502
|
+
examples: dominantExamples.slice(0, 3)
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return null;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
private async confirmStyleMismatch(mismatch: TagStyleMismatch): Promise<boolean> {
|
|
510
|
+
const rl = readline.createInterface({
|
|
511
|
+
input: process.stdin,
|
|
512
|
+
output: process.stdout
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
console.log(`\n⚠️ Tag name style mismatch detected.`);
|
|
516
|
+
console.log(` New tag: ${mismatch.newTag} (pattern: ${mismatch.newPattern})`);
|
|
517
|
+
console.log(` Recent tags: ${mismatch.examples.join(', ')} (pattern: ${mismatch.dominantPattern})`);
|
|
518
|
+
|
|
519
|
+
const answer: string = await new Promise(resolve => {
|
|
520
|
+
rl.question(`Proceed with "${mismatch.newTag}" anyway? (y/n): `, resolve);
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
rl.close();
|
|
524
|
+
|
|
525
|
+
const normalized = answer.trim().toLowerCase();
|
|
526
|
+
return normalized === 'y' || normalized === 'yes';
|
|
527
|
+
}
|
|
528
|
+
|
|
390
529
|
private async selectRemotesForPush(tagName: string, remotes: string[]): Promise<string[] | null> {
|
|
391
530
|
const rl = readline.createInterface({
|
|
392
531
|
input: process.stdin,
|
|
@@ -482,6 +621,22 @@ export class TagCommand {
|
|
|
482
621
|
return normalized === 'y' || normalized === 'yes';
|
|
483
622
|
}
|
|
484
623
|
|
|
624
|
+
private async confirmBaseTagDelete(tagName: string): Promise<boolean> {
|
|
625
|
+
const rl = readline.createInterface({
|
|
626
|
+
input: process.stdin,
|
|
627
|
+
output: process.stdout
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
const answer: string = await new Promise(resolve => {
|
|
631
|
+
rl.question(`Delete tag ${tagName} and use an older base? (y/n): `, resolve);
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
rl.close();
|
|
635
|
+
|
|
636
|
+
const normalized = answer.trim().toLowerCase();
|
|
637
|
+
return normalized === 'y' || normalized === 'yes';
|
|
638
|
+
}
|
|
639
|
+
|
|
485
640
|
private async confirmForcePush(tagName: string): Promise<boolean> {
|
|
486
641
|
const rl = readline.createInterface({
|
|
487
642
|
input: process.stdin,
|