@ksw8954/git-ai-commit 1.0.4 → 1.0.6

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.
@@ -22,5 +22,10 @@ export declare class GitService {
22
22
  static getLatestTag(): Promise<GitTagResult>;
23
23
  static getCommitSummariesSince(tag?: string): Promise<GitLogResult>;
24
24
  static createAnnotatedTag(tagName: string, message: string): Promise<boolean>;
25
+ static tagExists(tagName: string): Promise<boolean>;
26
+ static remoteTagExists(tagName: string): Promise<boolean>;
27
+ static deleteLocalTag(tagName: string): Promise<boolean>;
28
+ static deleteRemoteTag(tagName: string): Promise<boolean>;
29
+ static forcePushTag(tagName: string): Promise<boolean>;
25
30
  }
26
31
  //# sourceMappingURL=git.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/commands/git.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;WACR,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;WAuBvC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;WA2BpE,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAU/C,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;WAUxB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAU1C,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;WAwBrC,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;WAmC5D,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CASpF"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/commands/git.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAU;WACR,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;WAuBvC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;WA2BpE,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAU/C,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;WAUxB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAU1C,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;WAwBrC,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;WAmC5D,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAUtE,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAS5C,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WASlD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAUjD,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAUlD,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAS7D"}
@@ -145,6 +145,54 @@ class GitService {
145
145
  return false;
146
146
  }
147
147
  }
148
+ static async tagExists(tagName) {
149
+ try {
150
+ await execFileAsync('git', ['rev-parse', `refs/tags/${tagName}`]);
151
+ return true;
152
+ }
153
+ catch {
154
+ return false;
155
+ }
156
+ }
157
+ static async remoteTagExists(tagName) {
158
+ try {
159
+ const { stdout } = await execAsync(`git ls-remote --tags origin refs/tags/${tagName}`);
160
+ return stdout.trim().length > 0;
161
+ }
162
+ catch {
163
+ return false;
164
+ }
165
+ }
166
+ static async deleteLocalTag(tagName) {
167
+ try {
168
+ await execFileAsync('git', ['tag', '-d', tagName]);
169
+ return true;
170
+ }
171
+ catch (error) {
172
+ console.error('Failed to delete local tag:', error instanceof Error ? error.message : error);
173
+ return false;
174
+ }
175
+ }
176
+ static async deleteRemoteTag(tagName) {
177
+ try {
178
+ await execFileAsync('git', ['push', 'origin', '--delete', tagName]);
179
+ return true;
180
+ }
181
+ catch (error) {
182
+ console.error('Failed to delete remote tag:', error instanceof Error ? error.message : error);
183
+ return false;
184
+ }
185
+ }
186
+ static async forcePushTag(tagName) {
187
+ try {
188
+ await execFileAsync('git', ['push', 'origin', tagName, '--force']);
189
+ return true;
190
+ }
191
+ catch (error) {
192
+ console.error('Failed to force push tag to remote:', error instanceof Error ? error.message : error);
193
+ return false;
194
+ }
195
+ }
148
196
  }
149
197
  exports.GitService = GitService;
150
198
  //# sourceMappingURL=git.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/commands/git.ts"],"names":[],"mappings":";;;AAAA,iDAA+C;AAC/C,+BAAiC;AAEjC,MAAM,SAAS,GAAG,IAAA,gBAAS,EAAC,oBAAI,CAAC,CAAC;AAClC,MAAM,aAAa,GAAG,IAAA,gBAAS,EAAC,wBAAQ,CAAC,CAAC;AAoB1C,MAAa,UAAU;IACrB,MAAM,CAAC,KAAK,CAAC,aAAa;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,mBAAmB,CAAC,CAAC;YAExD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,2DAA2D;iBACnE,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,MAAM;aACb,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB;aACzE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,IAAY,EAAE,OAAe;QACtD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,IAAI,MAAM,OAAO,EAAE,CAAC;YAChD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;YAE5C,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,gCAAgC,IAAI,QAAQ,OAAO,GAAG;iBAC9D,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,MAAM;aACb,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;YACrF,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;oBACzC,CAAC,CAAC,0CAA0C,IAAI,OAAO,OAAO,GAAG;oBACjE,CAAC,CAAC,OAAO;aACZ,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,OAAe;QACvC,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC1F,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,IAAI;QACf,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;YACrC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC3F,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,OAAe;QAClC,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC/F,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,YAAY;QACvB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,gCAAgC,CAAC,CAAC;YACrE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;YAE1B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,kCAAkC;iBAC1C,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,GAAG;aACJ,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,qFAAqF;aAC7F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,uBAAuB,CAAC,GAAY;QAC/C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,GAAG;gBACpB,CAAC,CAAC,WAAW,GAAG,2BAA2B;gBAC3C,CAAC,CAAC,4BAA4B,CAAC;YAEjC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,MAAM;iBACnB,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;iBACxB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAEnC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,GAAG;wBACR,CAAC,CAAC,8BAA8B,GAAG,GAAG;wBACtC,CAAC,CAAC,qCAAqC;iBAC1C,CAAC;YACJ,CAAC;YAED,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEnE,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,GAAG,EAAE,YAAY;aAClB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC;aACjF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,OAAe,EAAE,OAAe;QAC9D,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;YAClE,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACvF,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF;AArJD,gCAqJC"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/commands/git.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,9 @@ export declare class TagCommand {
14
14
  private handleTag;
15
15
  private confirmTagPush;
16
16
  private confirmTagCreate;
17
+ private confirmTagDelete;
18
+ private confirmRemoteTagDelete;
19
+ private confirmForcePush;
17
20
  getCommand(): Command;
18
21
  }
19
22
  //# sourceMappingURL=tag.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAU;;IAiBzB,OAAO,CAAC,eAAe;YAoBT,SAAS;YA4IT,cAAc;YAgBd,gBAAgB;IAgB9B,UAAU,IAAI,OAAO;CAGtB"}
1
+ {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAU;;IAiBzB,OAAO,CAAC,eAAe;YAoBT,SAAS;YA+OT,cAAc;YAgBd,gBAAgB;YAgBhB,gBAAgB;YAgBhB,sBAAsB;YAgBtB,gBAAgB;IAgB9B,UAAU,IAAI,OAAO;CAGtB"}
@@ -54,6 +54,63 @@ class TagCommand {
54
54
  process.exit(1);
55
55
  return;
56
56
  }
57
+ // Check if tag already exists locally
58
+ const localTagExists = await git_1.GitService.tagExists(trimmedName);
59
+ let remoteTagExists = false;
60
+ let wasTagReplaced = false;
61
+ if (localTagExists) {
62
+ console.log(`⚠️ Tag ${trimmedName} already exists locally.`);
63
+ const shouldDelete = await this.confirmTagDelete(trimmedName);
64
+ if (!shouldDelete) {
65
+ console.log('Tag creation cancelled by user.');
66
+ await log_1.LogService.append({
67
+ command: 'tag',
68
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
69
+ status: 'cancelled',
70
+ details: 'user declined to replace existing tag'
71
+ });
72
+ return;
73
+ }
74
+ // Check if tag exists on remote
75
+ remoteTagExists = await git_1.GitService.remoteTagExists(trimmedName);
76
+ if (remoteTagExists) {
77
+ console.log(`⚠️ Tag ${trimmedName} also exists on remote.`);
78
+ const shouldDeleteRemote = await this.confirmRemoteTagDelete(trimmedName);
79
+ if (shouldDeleteRemote) {
80
+ console.log(`Deleting remote tag ${trimmedName}...`);
81
+ const remoteDeleted = await git_1.GitService.deleteRemoteTag(trimmedName);
82
+ if (!remoteDeleted) {
83
+ console.error('❌ Failed to delete remote tag');
84
+ await log_1.LogService.append({
85
+ command: 'tag',
86
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
87
+ status: 'failure',
88
+ details: 'remote tag deletion failed'
89
+ });
90
+ process.exit(1);
91
+ return;
92
+ }
93
+ console.log(`✅ Remote tag ${trimmedName} deleted`);
94
+ remoteTagExists = false;
95
+ }
96
+ }
97
+ // Delete local tag
98
+ console.log(`Deleting local tag ${trimmedName}...`);
99
+ const localDeleted = await git_1.GitService.deleteLocalTag(trimmedName);
100
+ if (!localDeleted) {
101
+ console.error('❌ Failed to delete local tag');
102
+ await log_1.LogService.append({
103
+ command: 'tag',
104
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
105
+ status: 'failure',
106
+ details: 'local tag deletion failed'
107
+ });
108
+ process.exit(1);
109
+ return;
110
+ }
111
+ console.log(`✅ Local tag ${trimmedName} deleted`);
112
+ wasTagReplaced = true;
113
+ }
57
114
  let tagMessage = options.message?.trim();
58
115
  if (!tagMessage) {
59
116
  console.log('Collecting commit history for tag notes...');
@@ -141,20 +198,53 @@ class TagCommand {
141
198
  console.log(`✅ Tag ${trimmedName} created successfully!`);
142
199
  const shouldPush = await this.confirmTagPush(trimmedName);
143
200
  if (shouldPush) {
144
- console.log(`Pushing tag ${trimmedName} to remote...`);
145
- const pushSuccess = await git_1.GitService.pushTag(trimmedName);
146
- if (pushSuccess) {
147
- console.log(`✅ Tag ${trimmedName} pushed successfully!`);
201
+ // If tag was replaced or remote tag still exists, use force push
202
+ const needsForcePush = wasTagReplaced || remoteTagExists;
203
+ if (needsForcePush) {
204
+ console.log(`⚠️ Tag ${trimmedName} exists on remote. Force push is required.`);
205
+ const shouldForcePush = await this.confirmForcePush(trimmedName);
206
+ if (!shouldForcePush) {
207
+ console.log('Tag push cancelled by user.');
208
+ await log_1.LogService.append({
209
+ command: 'tag',
210
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
211
+ status: 'cancelled',
212
+ details: 'user declined force push'
213
+ });
214
+ return;
215
+ }
216
+ console.log(`Force pushing tag ${trimmedName} to remote...`);
217
+ const pushSuccess = await git_1.GitService.forcePushTag(trimmedName);
218
+ if (pushSuccess) {
219
+ console.log(`✅ Tag ${trimmedName} force pushed successfully!`);
220
+ }
221
+ else {
222
+ console.error('❌ Failed to force push tag to remote');
223
+ await log_1.LogService.append({
224
+ command: 'tag',
225
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
226
+ status: 'failure',
227
+ details: 'tag force push failed'
228
+ });
229
+ process.exit(1);
230
+ }
148
231
  }
149
232
  else {
150
- console.error('❌ Failed to push tag to remote');
151
- await log_1.LogService.append({
152
- command: 'tag',
153
- args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
154
- status: 'failure',
155
- details: 'tag push failed'
156
- });
157
- process.exit(1);
233
+ console.log(`Pushing tag ${trimmedName} to remote...`);
234
+ const pushSuccess = await git_1.GitService.pushTag(trimmedName);
235
+ if (pushSuccess) {
236
+ console.log(`✅ Tag ${trimmedName} pushed successfully!`);
237
+ }
238
+ else {
239
+ console.error('❌ Failed to push tag to remote');
240
+ await log_1.LogService.append({
241
+ command: 'tag',
242
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
243
+ status: 'failure',
244
+ details: 'tag push failed'
245
+ });
246
+ process.exit(1);
247
+ }
158
248
  }
159
249
  }
160
250
  await log_1.LogService.append({
@@ -187,6 +277,42 @@ class TagCommand {
187
277
  const normalized = answer.trim().toLowerCase();
188
278
  return normalized === 'y' || normalized === 'yes';
189
279
  }
280
+ async confirmTagDelete(tagName) {
281
+ const rl = readline_1.default.createInterface({
282
+ input: process.stdin,
283
+ output: process.stdout
284
+ });
285
+ const answer = await new Promise(resolve => {
286
+ rl.question(`Delete existing tag ${tagName} and create a new one? (y/n): `, resolve);
287
+ });
288
+ rl.close();
289
+ const normalized = answer.trim().toLowerCase();
290
+ return normalized === 'y' || normalized === 'yes';
291
+ }
292
+ async confirmRemoteTagDelete(tagName) {
293
+ const rl = readline_1.default.createInterface({
294
+ input: process.stdin,
295
+ output: process.stdout
296
+ });
297
+ const answer = await new Promise(resolve => {
298
+ rl.question(`Also delete remote tag ${tagName}? (y/n): `, resolve);
299
+ });
300
+ rl.close();
301
+ const normalized = answer.trim().toLowerCase();
302
+ return normalized === 'y' || normalized === 'yes';
303
+ }
304
+ async confirmForcePush(tagName) {
305
+ const rl = readline_1.default.createInterface({
306
+ input: process.stdin,
307
+ output: process.stdout
308
+ });
309
+ const answer = await new Promise(resolve => {
310
+ rl.question(`Force push tag ${tagName} to remote? (y/n): `, resolve);
311
+ });
312
+ rl.close();
313
+ const normalized = answer.trim().toLowerCase();
314
+ return normalized === 'y' || normalized === 'yes';
315
+ }
190
316
  getCommand() {
191
317
  return this.program;
192
318
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/commands/tag.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/prompts/tag.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,EACf,2BAAuB,EACvB,WAAU,iBAAwB,KACjC,MAyCF,CAAC"}
1
+ {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../src/prompts/tag.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,EACf,2BAAuB,EACvB,WAAU,iBAAwB,KACjC,MA2CF,CAAC"}
@@ -3,20 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateTagPrompt = void 0;
4
4
  const generateTagPrompt = (tagName, customInstructions = '', language = 'ko') => {
5
5
  const summaryInstruction = language === 'ko'
6
- ? 'Begin with a short summary sentence (in Korean) that captures the overall impact of the release.'
7
- : 'Begin with a short summary sentence (in English) that captures the overall impact of the release.';
6
+ ? 'Begin with a short summary sentence (in Korean) that captures the overall impact of the release using plain text only.'
7
+ : 'Begin with a short summary sentence (in English) that captures the overall impact of the release using plain text only.';
8
8
  const listInstruction = language === 'ko'
9
- ? 'After the summary, list every change as a markdown bullet (-) grouped by category: 사용자 기능, 버그 수정, 유지 보수.'
10
- : 'After the summary, list every change as a markdown bullet (-) grouped by category: User Features, Bug Fixes, Maintenance.';
9
+ ? 'After the summary, write one line per category 사용자 기능, 버그 수정, 유지 보수 — using the format "사용자 기능: 변경1; 변경2" with plain text only (no bullets, numbers, or markdown symbols).'
10
+ : 'After the summary, write one line per category User Features, Bug Fixes, Maintenance — using the format "User Features: Change 1; Change 2" with plain text only (no bullets, numbers, or markdown symbols).';
11
11
  const emptyCategoryInstruction = language === 'ko'
12
- ? 'If a category has no changes, include a bullet stating - 해당 사항 없음.'
13
- : 'If a category has no changes, include a bullet stating - None.';
12
+ ? 'If a category has no changes, write "사용자 기능: 해당 사항 없음." (or the matching category label) using the same plain text format.'
13
+ : 'If a category has no changes, write "User Features: None." (or the matching category label) using the same plain text format.';
14
14
  const noChangesInstruction = language === 'ko'
15
15
  ? 'If no changes exist at all, state "변경 사항 없음" plainly.'
16
16
  : 'If no changes exist at all, state "No changes to report." plainly.';
17
17
  const outputLanguageLine = language === 'ko'
18
- ? 'Write the release notes in Korean using concise markdown.'
19
- : 'Write the release notes in English using concise markdown.';
18
+ ? 'Write the release notes in Korean using concise plain text without markdown syntax.'
19
+ : 'Write the release notes in English using concise plain text without markdown syntax.';
20
20
  return `You are an experienced release manager. Produce clear, user-facing release notes that describe the differences between the previous tag and ${tagName}.
21
21
 
22
22
  ## Objective
@@ -32,10 +32,12 @@ ${customInstructions}
32
32
  - ${outputLanguageLine}
33
33
  - ${summaryInstruction}
34
34
  - ${listInstruction}
35
- - Use short phrases for each bullet and include scope/component names when helpful, without copying commit messages verbatim.
35
+ - Use short phrases for each change and include scope/component names when helpful, without copying commit messages verbatim.
36
36
  - ${emptyCategoryInstruction}
37
37
  - ${noChangesInstruction}
38
38
  - Do not invent work beyond what appears in the commit log.
39
+ - Do not use markdown syntax such as headings (#), bullets (-), emphasis (**), underscores (_), or backticks (\`).
40
+ - Separate lines using newline characters only; do not use numbering, bullet prefixes, tables, or code blocks.
39
41
  - Return only the release notes content with no surrounding commentary.`;
40
42
  };
41
43
  exports.generateTagPrompt = generateTagPrompt;
@@ -1 +1 @@
1
- {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/prompts/tag.ts"],"names":[],"mappings":";;;AAEO,MAAM,iBAAiB,GAAG,CAC/B,OAAe,EACf,kBAAkB,GAAG,EAAE,EACvB,WAA8B,IAAI,EAC1B,EAAE;IACV,MAAM,kBAAkB,GAAG,QAAQ,KAAK,IAAI;QAC1C,CAAC,CAAC,kGAAkG;QACpG,CAAC,CAAC,mGAAmG,CAAC;IAExG,MAAM,eAAe,GAAG,QAAQ,KAAK,IAAI;QACvC,CAAC,CAAC,0GAA0G;QAC5G,CAAC,CAAC,2HAA2H,CAAC;IAEhI,MAAM,wBAAwB,GAAG,QAAQ,KAAK,IAAI;QAChD,CAAC,CAAC,oEAAoE;QACtE,CAAC,CAAC,gEAAgE,CAAC;IAErE,MAAM,oBAAoB,GAAG,QAAQ,KAAK,IAAI;QAC5C,CAAC,CAAC,uDAAuD;QACzD,CAAC,CAAC,oEAAoE,CAAC;IAEzE,MAAM,kBAAkB,GAAG,QAAQ,KAAK,IAAI;QAC1C,CAAC,CAAC,2DAA2D;QAC7D,CAAC,CAAC,4DAA4D,CAAC;IAEjE,OAAO,+IAA+I,OAAO;;;mFAG5E,OAAO;;;2BAG/D,OAAO;gDACc,OAAO;;EAErD,kBAAkB;;;IAGhB,kBAAkB;IAClB,kBAAkB;IAClB,eAAe;;IAEf,wBAAwB;IACxB,oBAAoB;;wEAEgD,CAAC;AACzE,CAAC,CAAC;AA7CW,QAAA,iBAAiB,qBA6C5B"}
1
+ {"version":3,"file":"tag.js","sourceRoot":"","sources":["../../src/prompts/tag.ts"],"names":[],"mappings":";;;AAEO,MAAM,iBAAiB,GAAG,CAC/B,OAAe,EACf,kBAAkB,GAAG,EAAE,EACvB,WAA8B,IAAI,EAC1B,EAAE;IACV,MAAM,kBAAkB,GAAG,QAAQ,KAAK,IAAI;QAC1C,CAAC,CAAC,wHAAwH;QAC1H,CAAC,CAAC,yHAAyH,CAAC;IAE9H,MAAM,eAAe,GAAG,QAAQ,KAAK,IAAI;QACvC,CAAC,CAAC,8KAA8K;QAChL,CAAC,CAAC,gNAAgN,CAAC;IAErN,MAAM,wBAAwB,GAAG,QAAQ,KAAK,IAAI;QAChD,CAAC,CAAC,4HAA4H;QAC9H,CAAC,CAAC,+HAA+H,CAAC;IAEpI,MAAM,oBAAoB,GAAG,QAAQ,KAAK,IAAI;QAC5C,CAAC,CAAC,uDAAuD;QACzD,CAAC,CAAC,oEAAoE,CAAC;IAEzE,MAAM,kBAAkB,GAAG,QAAQ,KAAK,IAAI;QAC1C,CAAC,CAAC,qFAAqF;QACvF,CAAC,CAAC,sFAAsF,CAAC;IAE3F,OAAO,+IAA+I,OAAO;;;mFAG5E,OAAO;;;2BAG/D,OAAO;gDACc,OAAO;;EAErD,kBAAkB;;;IAGhB,kBAAkB;IAClB,kBAAkB;IAClB,eAAe;;IAEf,wBAAwB;IACxB,oBAAoB;;;;wEAIgD,CAAC;AACzE,CAAC,CAAC;AA/CW,QAAA,iBAAiB,qBA+C5B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ksw8954/git-ai-commit",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "AI-powered git commit message generator",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -7,11 +7,21 @@ jest.mock('../commands/git', () => {
7
7
  diff: 'mock diff'
8
8
  });
9
9
  const createCommit = jest.fn().mockResolvedValue(true);
10
+ const tagExists = jest.fn().mockResolvedValue(false);
11
+ const remoteTagExists = jest.fn().mockResolvedValue(false);
12
+ const deleteLocalTag = jest.fn().mockResolvedValue(true);
13
+ const deleteRemoteTag = jest.fn().mockResolvedValue(true);
14
+ const forcePushTag = jest.fn().mockResolvedValue(true);
10
15
 
11
16
  return {
12
17
  GitService: {
13
18
  getStagedDiff,
14
- createCommit
19
+ createCommit,
20
+ tagExists,
21
+ remoteTagExists,
22
+ deleteLocalTag,
23
+ deleteRemoteTag,
24
+ forcePushTag
15
25
  }
16
26
  };
17
27
  });
@@ -85,4 +95,94 @@ describe('GitService', () => {
85
95
  expect(result).toBe(false);
86
96
  });
87
97
  });
98
+
99
+ describe('tagExists', () => {
100
+ it('should return true when tag exists locally', async () => {
101
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
102
+
103
+ const result = await GitService.tagExists('v1.0.0');
104
+
105
+ expect(result).toBe(true);
106
+ });
107
+
108
+ it('should return false when tag does not exist locally', async () => {
109
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(false);
110
+
111
+ const result = await GitService.tagExists('v1.0.0');
112
+
113
+ expect(result).toBe(false);
114
+ });
115
+ });
116
+
117
+ describe('remoteTagExists', () => {
118
+ it('should return true when tag exists on remote', async () => {
119
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(true);
120
+
121
+ const result = await GitService.remoteTagExists('v1.0.0');
122
+
123
+ expect(result).toBe(true);
124
+ });
125
+
126
+ it('should return false when tag does not exist on remote', async () => {
127
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(false);
128
+
129
+ const result = await GitService.remoteTagExists('v1.0.0');
130
+
131
+ expect(result).toBe(false);
132
+ });
133
+ });
134
+
135
+ describe('deleteLocalTag', () => {
136
+ it('should return true when local tag is deleted successfully', async () => {
137
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(true);
138
+
139
+ const result = await GitService.deleteLocalTag('v1.0.0');
140
+
141
+ expect(result).toBe(true);
142
+ });
143
+
144
+ it('should return false when local tag deletion fails', async () => {
145
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(false);
146
+
147
+ const result = await GitService.deleteLocalTag('v1.0.0');
148
+
149
+ expect(result).toBe(false);
150
+ });
151
+ });
152
+
153
+ describe('deleteRemoteTag', () => {
154
+ it('should return true when remote tag is deleted successfully', async () => {
155
+ (GitService.deleteRemoteTag as jest.Mock).mockResolvedValueOnce(true);
156
+
157
+ const result = await GitService.deleteRemoteTag('v1.0.0');
158
+
159
+ expect(result).toBe(true);
160
+ });
161
+
162
+ it('should return false when remote tag deletion fails', async () => {
163
+ (GitService.deleteRemoteTag as jest.Mock).mockResolvedValueOnce(false);
164
+
165
+ const result = await GitService.deleteRemoteTag('v1.0.0');
166
+
167
+ expect(result).toBe(false);
168
+ });
169
+ });
170
+
171
+ describe('forcePushTag', () => {
172
+ it('should return true when force push is successful', async () => {
173
+ (GitService.forcePushTag as jest.Mock).mockResolvedValueOnce(true);
174
+
175
+ const result = await GitService.forcePushTag('v1.0.0');
176
+
177
+ expect(result).toBe(true);
178
+ });
179
+
180
+ it('should return false when force push fails', async () => {
181
+ (GitService.forcePushTag as jest.Mock).mockResolvedValueOnce(false);
182
+
183
+ const result = await GitService.forcePushTag('v1.0.0');
184
+
185
+ expect(result).toBe(false);
186
+ });
187
+ });
88
188
  });
@@ -8,7 +8,12 @@ jest.mock('../commands/git', () => ({
8
8
  getLatestTag: jest.fn(),
9
9
  getCommitSummariesSince: jest.fn(),
10
10
  createAnnotatedTag: jest.fn(),
11
- pushTag: jest.fn()
11
+ pushTag: jest.fn(),
12
+ tagExists: jest.fn(),
13
+ remoteTagExists: jest.fn(),
14
+ deleteLocalTag: jest.fn(),
15
+ deleteRemoteTag: jest.fn(),
16
+ forcePushTag: jest.fn()
12
17
  }
13
18
  }));
14
19
 
@@ -44,6 +49,10 @@ describe('TagCommand', () => {
44
49
 
45
50
  (ConfigService.validateConfig as jest.Mock).mockReturnValue(undefined);
46
51
 
52
+ // Tag doesn't exist by default
53
+ (GitService.tagExists as jest.Mock).mockResolvedValue(false);
54
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValue(false);
55
+
47
56
  // Confirm creation by default
48
57
  jest
49
58
  .spyOn(TagCommand.prototype as any, 'confirmTagCreate')
@@ -194,4 +203,176 @@ describe('TagCommand', () => {
194
203
  expect(GitService.pushTag).toHaveBeenCalledWith('v3.0.0');
195
204
  expect(exitSpy).toHaveBeenCalledWith(1);
196
205
  });
206
+
207
+ it('should cancel when user declines to replace existing local tag', async () => {
208
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
209
+ jest
210
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
211
+ .mockResolvedValueOnce(false);
212
+
213
+ const command = getTagCommand();
214
+
215
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
216
+
217
+ expect(GitService.tagExists).toHaveBeenCalledWith('v1.0.0');
218
+ expect(GitService.createAnnotatedTag).not.toHaveBeenCalled();
219
+ expect(GitService.pushTag).not.toHaveBeenCalled();
220
+ });
221
+
222
+ it('should delete local tag and create new one when user confirms', async () => {
223
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
224
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(false);
225
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(true);
226
+ (GitService.createAnnotatedTag as jest.Mock).mockResolvedValueOnce(true);
227
+
228
+ jest
229
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
230
+ .mockResolvedValueOnce(true);
231
+
232
+ const command = getTagCommand();
233
+
234
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
235
+
236
+ expect(GitService.tagExists).toHaveBeenCalledWith('v1.0.0');
237
+ expect(GitService.deleteLocalTag).toHaveBeenCalledWith('v1.0.0');
238
+ expect(GitService.createAnnotatedTag).toHaveBeenCalledWith('v1.0.0', 'Release notes');
239
+ });
240
+
241
+ it('should delete both local and remote tag when user confirms', async () => {
242
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
243
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(true);
244
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(true);
245
+ (GitService.deleteRemoteTag as jest.Mock).mockResolvedValueOnce(true);
246
+ (GitService.createAnnotatedTag as jest.Mock).mockResolvedValueOnce(true);
247
+
248
+ jest
249
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
250
+ .mockResolvedValueOnce(true);
251
+ jest
252
+ .spyOn(TagCommand.prototype as any, 'confirmRemoteTagDelete')
253
+ .mockResolvedValueOnce(true);
254
+
255
+ const command = getTagCommand();
256
+
257
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
258
+
259
+ expect(GitService.remoteTagExists).toHaveBeenCalledWith('v1.0.0');
260
+ expect(GitService.deleteRemoteTag).toHaveBeenCalledWith('v1.0.0');
261
+ expect(GitService.deleteLocalTag).toHaveBeenCalledWith('v1.0.0');
262
+ expect(GitService.createAnnotatedTag).toHaveBeenCalledWith('v1.0.0', 'Release notes');
263
+ });
264
+
265
+ it('should exit when local tag deletion fails', async () => {
266
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
267
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(false);
268
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(false);
269
+
270
+ jest
271
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
272
+ .mockResolvedValueOnce(true);
273
+
274
+ const command = getTagCommand();
275
+
276
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
277
+
278
+ expect(GitService.deleteLocalTag).toHaveBeenCalledWith('v1.0.0');
279
+ expect(GitService.createAnnotatedTag).not.toHaveBeenCalled();
280
+ expect(exitSpy).toHaveBeenCalledWith(1);
281
+ });
282
+
283
+ it('should exit when remote tag deletion fails', async () => {
284
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
285
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(true);
286
+ (GitService.deleteRemoteTag as jest.Mock).mockResolvedValueOnce(false);
287
+
288
+ jest
289
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
290
+ .mockResolvedValueOnce(true);
291
+ jest
292
+ .spyOn(TagCommand.prototype as any, 'confirmRemoteTagDelete')
293
+ .mockResolvedValueOnce(true);
294
+
295
+ const command = getTagCommand();
296
+
297
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
298
+
299
+ expect(GitService.deleteRemoteTag).toHaveBeenCalledWith('v1.0.0');
300
+ expect(GitService.deleteLocalTag).not.toHaveBeenCalled();
301
+ expect(GitService.createAnnotatedTag).not.toHaveBeenCalled();
302
+ expect(exitSpy).toHaveBeenCalledWith(1);
303
+ });
304
+
305
+ it('should force push when tag was replaced and user confirms', async () => {
306
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
307
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(false);
308
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(true);
309
+ (GitService.createAnnotatedTag as jest.Mock).mockResolvedValueOnce(true);
310
+ (GitService.forcePushTag as jest.Mock).mockResolvedValueOnce(true);
311
+
312
+ jest
313
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
314
+ .mockResolvedValueOnce(true);
315
+ confirmSpy.mockResolvedValueOnce(true);
316
+ jest
317
+ .spyOn(TagCommand.prototype as any, 'confirmForcePush')
318
+ .mockResolvedValueOnce(true);
319
+
320
+ const command = getTagCommand();
321
+
322
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
323
+
324
+ expect(GitService.deleteLocalTag).toHaveBeenCalledWith('v1.0.0');
325
+ expect(GitService.createAnnotatedTag).toHaveBeenCalledWith('v1.0.0', 'Release notes');
326
+ expect(GitService.forcePushTag).toHaveBeenCalledWith('v1.0.0');
327
+ });
328
+
329
+ it('should cancel push when user declines force push', async () => {
330
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
331
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(false);
332
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(true);
333
+ (GitService.createAnnotatedTag as jest.Mock).mockResolvedValueOnce(true);
334
+
335
+ jest
336
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
337
+ .mockResolvedValueOnce(true);
338
+ confirmSpy.mockResolvedValueOnce(true);
339
+ jest
340
+ .spyOn(TagCommand.prototype as any, 'confirmForcePush')
341
+ .mockResolvedValueOnce(false);
342
+
343
+ const command = getTagCommand();
344
+
345
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
346
+
347
+ expect(GitService.createAnnotatedTag).toHaveBeenCalledWith('v1.0.0', 'Release notes');
348
+ expect(GitService.forcePushTag).not.toHaveBeenCalled();
349
+ expect(GitService.pushTag).not.toHaveBeenCalled();
350
+ });
351
+
352
+ it('should force push when remote tag exists and user confirms', async () => {
353
+ (GitService.tagExists as jest.Mock).mockResolvedValueOnce(true);
354
+ (GitService.remoteTagExists as jest.Mock).mockResolvedValueOnce(true);
355
+ (GitService.deleteRemoteTag as jest.Mock).mockResolvedValueOnce(false); // User declined remote deletion
356
+ (GitService.deleteLocalTag as jest.Mock).mockResolvedValueOnce(true);
357
+ (GitService.createAnnotatedTag as jest.Mock).mockResolvedValueOnce(true);
358
+ (GitService.forcePushTag as jest.Mock).mockResolvedValueOnce(true);
359
+
360
+ jest
361
+ .spyOn(TagCommand.prototype as any, 'confirmTagDelete')
362
+ .mockResolvedValueOnce(true);
363
+ jest
364
+ .spyOn(TagCommand.prototype as any, 'confirmRemoteTagDelete')
365
+ .mockResolvedValueOnce(false); // Decline remote deletion
366
+ confirmSpy.mockResolvedValueOnce(true);
367
+ jest
368
+ .spyOn(TagCommand.prototype as any, 'confirmForcePush')
369
+ .mockResolvedValueOnce(true);
370
+
371
+ const command = getTagCommand();
372
+
373
+ await (command as any).handleTag('v1.0.0', { message: 'Release notes' });
374
+
375
+ expect(GitService.forcePushTag).toHaveBeenCalledWith('v1.0.0');
376
+ expect(GitService.pushTag).not.toHaveBeenCalled();
377
+ });
197
378
  });
@@ -171,4 +171,52 @@ export class GitService {
171
171
  return false;
172
172
  }
173
173
  }
174
+
175
+ static async tagExists(tagName: string): Promise<boolean> {
176
+ try {
177
+ await execFileAsync('git', ['rev-parse', `refs/tags/${tagName}`]);
178
+ return true;
179
+ } catch {
180
+ return false;
181
+ }
182
+ }
183
+
184
+ static async remoteTagExists(tagName: string): Promise<boolean> {
185
+ try {
186
+ const { stdout } = await execAsync(`git ls-remote --tags origin refs/tags/${tagName}`);
187
+ return stdout.trim().length > 0;
188
+ } catch {
189
+ return false;
190
+ }
191
+ }
192
+
193
+ static async deleteLocalTag(tagName: string): Promise<boolean> {
194
+ try {
195
+ await execFileAsync('git', ['tag', '-d', tagName]);
196
+ return true;
197
+ } catch (error) {
198
+ console.error('Failed to delete local tag:', error instanceof Error ? error.message : error);
199
+ return false;
200
+ }
201
+ }
202
+
203
+ static async deleteRemoteTag(tagName: string): Promise<boolean> {
204
+ try {
205
+ await execFileAsync('git', ['push', 'origin', '--delete', tagName]);
206
+ return true;
207
+ } catch (error) {
208
+ console.error('Failed to delete remote tag:', error instanceof Error ? error.message : error);
209
+ return false;
210
+ }
211
+ }
212
+
213
+ static async forcePushTag(tagName: string): Promise<boolean> {
214
+ try {
215
+ await execFileAsync('git', ['push', 'origin', tagName, '--force']);
216
+ return true;
217
+ } catch (error) {
218
+ console.error('Failed to force push tag to remote:', error instanceof Error ? error.message : error);
219
+ return false;
220
+ }
221
+ }
174
222
  }
@@ -67,6 +67,70 @@ export class TagCommand {
67
67
  return;
68
68
  }
69
69
 
70
+ // Check if tag already exists locally
71
+ const localTagExists = await GitService.tagExists(trimmedName);
72
+ let remoteTagExists = false;
73
+ let wasTagReplaced = false;
74
+
75
+ if (localTagExists) {
76
+ console.log(`⚠️ Tag ${trimmedName} already exists locally.`);
77
+ const shouldDelete = await this.confirmTagDelete(trimmedName);
78
+
79
+ if (!shouldDelete) {
80
+ console.log('Tag creation cancelled by user.');
81
+ await LogService.append({
82
+ command: 'tag',
83
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
84
+ status: 'cancelled',
85
+ details: 'user declined to replace existing tag'
86
+ });
87
+ return;
88
+ }
89
+
90
+ // Check if tag exists on remote
91
+ remoteTagExists = await GitService.remoteTagExists(trimmedName);
92
+
93
+ if (remoteTagExists) {
94
+ console.log(`⚠️ Tag ${trimmedName} also exists on remote.`);
95
+ const shouldDeleteRemote = await this.confirmRemoteTagDelete(trimmedName);
96
+
97
+ if (shouldDeleteRemote) {
98
+ console.log(`Deleting remote tag ${trimmedName}...`);
99
+ const remoteDeleted = await GitService.deleteRemoteTag(trimmedName);
100
+ if (!remoteDeleted) {
101
+ console.error('❌ Failed to delete remote tag');
102
+ await LogService.append({
103
+ command: 'tag',
104
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
105
+ status: 'failure',
106
+ details: 'remote tag deletion failed'
107
+ });
108
+ process.exit(1);
109
+ return;
110
+ }
111
+ console.log(`✅ Remote tag ${trimmedName} deleted`);
112
+ remoteTagExists = false;
113
+ }
114
+ }
115
+
116
+ // Delete local tag
117
+ console.log(`Deleting local tag ${trimmedName}...`);
118
+ const localDeleted = await GitService.deleteLocalTag(trimmedName);
119
+ if (!localDeleted) {
120
+ console.error('❌ Failed to delete local tag');
121
+ await LogService.append({
122
+ command: 'tag',
123
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
124
+ status: 'failure',
125
+ details: 'local tag deletion failed'
126
+ });
127
+ process.exit(1);
128
+ return;
129
+ }
130
+ console.log(`✅ Local tag ${trimmedName} deleted`);
131
+ wasTagReplaced = true;
132
+ }
133
+
70
134
  let tagMessage = options.message?.trim();
71
135
 
72
136
  if (!tagMessage) {
@@ -168,20 +232,55 @@ export class TagCommand {
168
232
  const shouldPush = await this.confirmTagPush(trimmedName);
169
233
 
170
234
  if (shouldPush) {
171
- console.log(`Pushing tag ${trimmedName} to remote...`);
172
- const pushSuccess = await GitService.pushTag(trimmedName);
235
+ // If tag was replaced or remote tag still exists, use force push
236
+ const needsForcePush = wasTagReplaced || remoteTagExists;
237
+
238
+ if (needsForcePush) {
239
+ console.log(`⚠️ Tag ${trimmedName} exists on remote. Force push is required.`);
240
+ const shouldForcePush = await this.confirmForcePush(trimmedName);
241
+
242
+ if (!shouldForcePush) {
243
+ console.log('Tag push cancelled by user.');
244
+ await LogService.append({
245
+ command: 'tag',
246
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
247
+ status: 'cancelled',
248
+ details: 'user declined force push'
249
+ });
250
+ return;
251
+ }
173
252
 
174
- if (pushSuccess) {
175
- console.log(`✅ Tag ${trimmedName} pushed successfully!`);
253
+ console.log(`Force pushing tag ${trimmedName} to remote...`);
254
+ const pushSuccess = await GitService.forcePushTag(trimmedName);
255
+
256
+ if (pushSuccess) {
257
+ console.log(`✅ Tag ${trimmedName} force pushed successfully!`);
258
+ } else {
259
+ console.error('❌ Failed to force push tag to remote');
260
+ await LogService.append({
261
+ command: 'tag',
262
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
263
+ status: 'failure',
264
+ details: 'tag force push failed'
265
+ });
266
+ process.exit(1);
267
+ }
176
268
  } else {
177
- console.error('❌ Failed to push tag to remote');
178
- await LogService.append({
179
- command: 'tag',
180
- args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
181
- status: 'failure',
182
- details: 'tag push failed'
183
- });
184
- process.exit(1);
269
+ console.log(`Pushing tag ${trimmedName} to remote...`);
270
+ const pushSuccess = await GitService.pushTag(trimmedName);
271
+
272
+ if (pushSuccess) {
273
+ console.log(`✅ Tag ${trimmedName} pushed successfully!`);
274
+ } else {
275
+ console.error('❌ Failed to push tag to remote');
276
+ await LogService.append({
277
+ command: 'tag',
278
+ args: { name: trimmedName, ...options, apiKey: options.apiKey ? '***' : undefined },
279
+ status: 'failure',
280
+ details: 'tag push failed'
281
+ });
282
+ process.exit(1);
283
+ }
185
284
  }
186
285
  }
187
286
 
@@ -224,6 +323,54 @@ export class TagCommand {
224
323
  return normalized === 'y' || normalized === 'yes';
225
324
  }
226
325
 
326
+ private async confirmTagDelete(tagName: string): Promise<boolean> {
327
+ const rl = readline.createInterface({
328
+ input: process.stdin,
329
+ output: process.stdout
330
+ });
331
+
332
+ const answer: string = await new Promise(resolve => {
333
+ rl.question(`Delete existing tag ${tagName} and create a new one? (y/n): `, resolve);
334
+ });
335
+
336
+ rl.close();
337
+
338
+ const normalized = answer.trim().toLowerCase();
339
+ return normalized === 'y' || normalized === 'yes';
340
+ }
341
+
342
+ private async confirmRemoteTagDelete(tagName: string): Promise<boolean> {
343
+ const rl = readline.createInterface({
344
+ input: process.stdin,
345
+ output: process.stdout
346
+ });
347
+
348
+ const answer: string = await new Promise(resolve => {
349
+ rl.question(`Also delete remote tag ${tagName}? (y/n): `, resolve);
350
+ });
351
+
352
+ rl.close();
353
+
354
+ const normalized = answer.trim().toLowerCase();
355
+ return normalized === 'y' || normalized === 'yes';
356
+ }
357
+
358
+ private async confirmForcePush(tagName: string): Promise<boolean> {
359
+ const rl = readline.createInterface({
360
+ input: process.stdin,
361
+ output: process.stdout
362
+ });
363
+
364
+ const answer: string = await new Promise(resolve => {
365
+ rl.question(`Force push tag ${tagName} to remote? (y/n): `, resolve);
366
+ });
367
+
368
+ rl.close();
369
+
370
+ const normalized = answer.trim().toLowerCase();
371
+ return normalized === 'y' || normalized === 'yes';
372
+ }
373
+
227
374
  getCommand(): Command {
228
375
  return this.program;
229
376
  }
@@ -6,24 +6,24 @@ export const generateTagPrompt = (
6
6
  language: TagPromptLanguage = 'ko'
7
7
  ): string => {
8
8
  const summaryInstruction = language === 'ko'
9
- ? 'Begin with a short summary sentence (in Korean) that captures the overall impact of the release.'
10
- : 'Begin with a short summary sentence (in English) that captures the overall impact of the release.';
9
+ ? 'Begin with a short summary sentence (in Korean) that captures the overall impact of the release using plain text only.'
10
+ : 'Begin with a short summary sentence (in English) that captures the overall impact of the release using plain text only.';
11
11
 
12
12
  const listInstruction = language === 'ko'
13
- ? 'After the summary, list every change as a markdown bullet (-) grouped by category: 사용자 기능, 버그 수정, 유지 보수.'
14
- : 'After the summary, list every change as a markdown bullet (-) grouped by category: User Features, Bug Fixes, Maintenance.';
13
+ ? 'After the summary, write one line per category 사용자 기능, 버그 수정, 유지 보수 — using the format "사용자 기능: 변경1; 변경2" with plain text only (no bullets, numbers, or markdown symbols).'
14
+ : 'After the summary, write one line per category User Features, Bug Fixes, Maintenance — using the format "User Features: Change 1; Change 2" with plain text only (no bullets, numbers, or markdown symbols).';
15
15
 
16
16
  const emptyCategoryInstruction = language === 'ko'
17
- ? 'If a category has no changes, include a bullet stating - 해당 사항 없음.'
18
- : 'If a category has no changes, include a bullet stating - None.';
17
+ ? 'If a category has no changes, write "사용자 기능: 해당 사항 없음." (or the matching category label) using the same plain text format.'
18
+ : 'If a category has no changes, write "User Features: None." (or the matching category label) using the same plain text format.';
19
19
 
20
20
  const noChangesInstruction = language === 'ko'
21
21
  ? 'If no changes exist at all, state "변경 사항 없음" plainly.'
22
22
  : 'If no changes exist at all, state "No changes to report." plainly.';
23
23
 
24
24
  const outputLanguageLine = language === 'ko'
25
- ? 'Write the release notes in Korean using concise markdown.'
26
- : 'Write the release notes in English using concise markdown.';
25
+ ? 'Write the release notes in Korean using concise plain text without markdown syntax.'
26
+ : 'Write the release notes in English using concise plain text without markdown syntax.';
27
27
 
28
28
  return `You are an experienced release manager. Produce clear, user-facing release notes that describe the differences between the previous tag and ${tagName}.
29
29
 
@@ -40,9 +40,11 @@ ${customInstructions}
40
40
  - ${outputLanguageLine}
41
41
  - ${summaryInstruction}
42
42
  - ${listInstruction}
43
- - Use short phrases for each bullet and include scope/component names when helpful, without copying commit messages verbatim.
43
+ - Use short phrases for each change and include scope/component names when helpful, without copying commit messages verbatim.
44
44
  - ${emptyCategoryInstruction}
45
45
  - ${noChangesInstruction}
46
46
  - Do not invent work beyond what appears in the commit log.
47
+ - Do not use markdown syntax such as headings (#), bullets (-), emphasis (**), underscores (_), or backticks (\`).
48
+ - Separate lines using newline characters only; do not use numbering, bullet prefixes, tables, or code blocks.
47
49
  - Return only the release notes content with no surrounding commentary.`;
48
50
  };