@kittiphop_sompuech/git-cli-tools 1.0.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.
Files changed (3) hide show
  1. package/Readme.md +21 -0
  2. package/index.js +420 -0
  3. package/package.json +21 -0
package/Readme.md ADDED
@@ -0,0 +1,21 @@
1
+ # 🚀 Git-Pro CLI
2
+
3
+ **Git-Pro** คือเครื่องมือ Automation CLI (เขียนด้วย Go 100%) ที่ออกแบบมาเพื่อปฏิวัติ Workflow การทำงานกับ Git ของ Developer ช่วยจัดการและแก้ไขปัญหาทุกอย่างในเครื่องได้ในคำสั่งเดียวผ่าน **Keyboard-Driven Flow** โดยไม่ต้องสลับมือไปจับเมาส์คลิกบน Git GUI และไม่ต้องจำคำสั่ง Git ที่ซับซ้อน
4
+
5
+ ---
6
+
7
+ ## ✨ Features & Sub-commands
8
+
9
+ | Command | Description | Flow & Mechanics |
10
+ | :--- | :--- | :--- |
11
+ | `upload` | Deploy ในคลิกเดียว | Stage ไฟล์ $\rightarrow$ เลือกประเภท Semantic Commit $\rightarrow$ Push อัตโนมัติ |
12
+ | `add-remote` | จัดการ Remote | แสดงรายการ Remote ทั้งหมด และเปิดช่องให้เพิ่มอันใหม่ได้ทันที |
13
+ | `squash <N>` | รวม N Commit ล่าสุด | ยุบ Commit ให้เหลือหนึ่งเดียวด้วย Soft-reset (สะอาด ไม่ต้องผ่าน Vim) |
14
+ | `grab` | คัดลอกเฉพาะ Commit | เลือก Branch และ Commit ที่ต้องการ เพื่อทำการ cherry-pick ทันที |
15
+ | `purge-file <path>` | ลบไฟล์/ข้อมูลสำคัญถาวร | ลบไฟล์ขนาดใหญ่หรือความลับออกจาก Git History ถาวร พร้อมรัน git gc |
16
+ | `move-to <branch>` | ย้ายงานไป Branch อื่น | ย้ายโค้ดที่กำลังเขียนไป Branch ใหม่ทันทีผ่านกระบวนการ stash & pop |
17
+ | `undo` | ย้อนสถานะ (Rollback) | เลือกได้ 3 โหมด: Hard (ลบทั้งหมด) / Soft (เก็บใน Staged) / Mixed (เก็บใน Unstaged) |
18
+ | `stash-box` | จัดการงานที่บันทึกไว้ | ดูรายการที่ซ่อนไว้ พร้อมแสดง Colored Diff Preview ก่อน pop หรือ apply |
19
+ | `merge` | รวม Branch (Guided) | เลือกต้นทาง-ปลายทาง $\rightarrow$ ดู Diff $\rightarrow$ เลือก Strategy $\rightarrow$ เช็ก Conflict $\rightarrow$ Push |
20
+
21
+ ---
package/index.js ADDED
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from 'child_process';
4
+ import { Command } from 'commander';
5
+ import * as p from '@clack/prompts';
6
+ import pc from 'picocolors';
7
+
8
+ const program = new Command();
9
+
10
+ // --- Helper ฟังก์ชันสำหรับรันคำสั่ง Terminal ---
11
+ function run(command, { throws = false } = {}) {
12
+ try {
13
+ return execSync(command, { encoding: 'utf8', stdio: 'pipe' }).trim();
14
+ } catch (error) {
15
+ if (throws) throw error;
16
+ return null;
17
+ }
18
+ }
19
+
20
+ // ฟังก์ชันรันคำสั่งแบบยอมให้พ่น Error ออกหน้าจอตรงๆ (สำหรับคำสั่งซับซ้อน)
21
+ function runWithInherit(command) {
22
+ try {
23
+ execSync(command, { stdio: 'inherit' });
24
+ return true;
25
+ } catch (error) {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ // เช็กด่วนว่าเป็น Git Repo หรือไม่
31
+ function checkGitRepo() {
32
+ if (!run('git rev-parse --is-inside-work-tree')) {
33
+ p.log.error(pc.red('❌ โฟลเดอร์นี้ไม่ใช่ Git Repository! กรุณารันในโปรเจกต์ Git'));
34
+ process.exit(1);
35
+ }
36
+ }
37
+
38
+ // --- เริ่มต้นโปรแกรมหลักกำหนดหัวข้อ ---
39
+ program
40
+ .name('git-pro')
41
+ .description('The Ultimate Git Automation CLI Tool written in Node.js')
42
+ .version('1.0.0');
43
+
44
+ // ==========================================
45
+ // 1. COMMAND: upload
46
+ // ==========================================
47
+ program
48
+ .command('upload')
49
+ .description('Stage -> Interactive Semantic Commit -> Auto Push')
50
+ .action(async () => {
51
+ p.intro(pc.inverse(pc.cyan(' 🚀 UPLOAD WORKFLOW ')));
52
+
53
+ // Auto Init
54
+ if (!run('git rev-parse --is-inside-work-tree')) {
55
+ p.log.warn('Not a git repo. Auto initializing...');
56
+ run('git init');
57
+ run('git branch -M main');
58
+ }
59
+
60
+ // Check Remote
61
+ let remotes = run('git remote -v');
62
+ if (!remotes) {
63
+ const url = await p.text({ message: 'ไม่พบ Remote! กรุณากรอก Remote URL:' });
64
+ if (p.isCancel(url) || !url) return p.cancel('ยกเลิกงาน');
65
+ run(`git remote add origin ${url}`);
66
+ }
67
+
68
+ // Check Changes
69
+ if (!run('git status --porcelain')) {
70
+ p.outro(pc.green('✨ ไม่มีไฟล์เปลี่ยนแปลง ทุกอย่างอัปเดตแล้ว!'));
71
+ return;
72
+ }
73
+
74
+ run('git add .');
75
+
76
+ const commitType = await p.select({
77
+ message: 'เลือกประเภทการ Commit (Semantic Commit):',
78
+ options: [
79
+ { value: 'feat', label: '🚀 feat:', hint: 'เพิ่มฟีเจอร์ใหม่' },
80
+ { value: 'fix', label: '🛠️ fix:', hint: 'แก้ไขบั๊ก' },
81
+ { value: 'docs', label: '📝 docs:', hint: 'อัปเดตเอกสาร' },
82
+ { value: 'refactor', label: '♻️ refactor:', hint: 'ปรับปรุงโครงสร้างโค้ด' },
83
+ { value: 'chore', label: '🔩 chore:', hint: 'งานจิปาถะ/ตั้งค่าระบบ' },
84
+ ]
85
+ });
86
+ if (p.isCancel(commitType)) return;
87
+
88
+ const commitMsg = await p.text({ message: 'ระบุข้อความ Commit Message:' });
89
+ if (p.isCancel(commitMsg) || !commitMsg) return;
90
+
91
+ const finalMsg = `${commitType}: ${commitMsg}`;
92
+ run(`git commit -m "${finalMsg}"`);
93
+
94
+ const s = p.spinner();
95
+ const branch = run('git branch --show-current') || 'main';
96
+ s.start(`กำลังดันโค้ดขึ้น origin/${branch}...`);
97
+
98
+ try {
99
+ run(`git push -u origin ${branch}`);
100
+ s.stop('ดันโค้ดเสร็จสมบูรณ์!');
101
+ p.outro(pc.green('🎉 ดันงานขึ้นคลาวด์เรียบร้อยแล้ว!'));
102
+ } catch {
103
+ s.stop(pc.red('Push พัง!'));
104
+ p.log.error('กรุณาเช็กสิทธิ์เน็ตเวิร์กหรือ Link Repository');
105
+ }
106
+ });
107
+
108
+ // ==========================================
109
+ // 2. COMMAND: add-remote
110
+ // ==========================================
111
+ program
112
+ .command('add-remote')
113
+ .description('ดูรายการ Remote และเปิดช่องเพิ่มอันใหม่ทันที')
114
+ .action(async () => {
115
+ checkGitRepo();
116
+ p.intro(pc.cyan('🌐 MANAGING REMOTES'));
117
+
118
+ const existingRemotes = run('git remote -v') || pc.dim('ไม่มี Remote ผูกอยู่');
119
+ p.log.info(`${pc.bold('รายการปัจจุบัน:')}\n${existingRemotes}`);
120
+
121
+ const name = await p.text({ message: 'ระบุชื่อ Remote ใหม่:', placeholder: 'origin หรือ upstream' });
122
+ if (p.isCancel(name) || !name) return;
123
+
124
+ const url = await p.text({ message: 'ระบุ URL ปลายทาง:', placeholder: 'git@github.com:... หรือ https://...' });
125
+ if (p.isCancel(url) || !url) return;
126
+
127
+ run(`git remote add ${name} ${url}`);
128
+ p.outro(pc.green(`✅ เพิ่ม Remote [${name}] สำเร็จเรียบร้อย!`));
129
+ });
130
+
131
+ // ==========================================
132
+ // 3. COMMAND: squash <N>
133
+ // ==========================================
134
+ program
135
+ .command('squash <N>')
136
+ .description('ยุบ N Commit ล่าสุดด้วย Soft-reset (สะอาด ไม่ผ่าน Vim)')
137
+ .action(async (N) => {
138
+ checkGitRepo();
139
+ p.intro(pc.yellow(`🥞 SQUASH COMMITS (หลอมรวม ${N} รายการ)`));
140
+
141
+ const count = parseInt(N, 10);
142
+ if (isNaN(count) || count < 2) {
143
+ p.log.error('❌ จำนวน Commit ที่จะรวมต้องเป็นตัวเลขและมากกว่า 1 ขึ้นไป');
144
+ return;
145
+ }
146
+
147
+ const s = p.spinner();
148
+ s.start('กำลังดึงประวัติกลับมาไว้ที่ Staged (Soft Reset)...');
149
+ const resetResult = run(`git reset --soft HEAD~${count}`);
150
+ s.stop('Soft Reset เรียบร้อย โค้ดทั้งหมดกองรอรวมร่างแล้ว');
151
+
152
+ if (resetResult === null) {
153
+ p.log.error('❌ ไม่สามารถทำ Soft Reset ได้ ประวัติในอดีตอาจไม่ยาวพอ');
154
+ return;
155
+ }
156
+
157
+ const newMsg = await p.text({
158
+ message: 'ระบุข้อความใหม่สำหรับ Commit ที่รวมร่างแล้ว:',
159
+ placeholder: 'feat(core): combined multiple local updates'
160
+ });
161
+ if (p.isCancel(newMsg) || !newMsg) return;
162
+
163
+ run(`git commit -m "${newMsg}"`);
164
+ p.outro(pc.green(`✅ รวมร่างเป็น 1 Commit สะอาดสะอ้านเรียบร้อย!`));
165
+ });
166
+
167
+ // ==========================================
168
+ // 4. COMMAND: grab
169
+ // ==========================================
170
+ program
171
+ .command('grab')
172
+ .description('เลือก Branch และเลือกตัด Commit ข้ามสายพันธุ์ (Cherry-pick)')
173
+ .action(async () => {
174
+ checkGitRepo();
175
+ p.intro(pc.magenta('🍒 CHERRY-PICK WIZARD (ขโมยโค้ด)'));
176
+
177
+ // ดึงรายชื่อ Branch ทั้งหมดในเครื่อง
178
+ const branchesRaw = run('git branch --format="%(refname:short)"') || '';
179
+ const branches = branchesRaw.split('\n').filter(Boolean);
180
+
181
+ const sourceBranch = await p.select({
182
+ message: 'เลือก Branch ต้นทางที่ต้องการไปคัดลอกรอบมา:',
183
+ options: branches.map(b => ({ value: b, label: b }))
184
+ });
185
+ if (p.isCancel(sourceBranch)) return;
186
+
187
+ // ดึง 10 คอมมิตล่าสุดจากบลันช์ต้นทางนั้น
188
+ const commitsRaw = run(`git log ${sourceBranch} -n 10 --oneline`) || '';
189
+ if (!commitsRaw) {
190
+ p.log.error('ไม่พบประวัติ Commit บนบลันช์นั้นเลย');
191
+ return;
192
+ }
193
+
194
+ const commits = commitsRaw.split('\n').filter(Boolean);
195
+
196
+ const selectedCommitLine = await p.select({
197
+ message: 'เลือกรอบคอมมิตที่อยากจะเด็ดหัวมาใส่บลันช์เราปัจจุบัน:',
198
+ options: commits.map(c => {
199
+ const hash = c.split(' ')[0];
200
+ return { value: hash, label: c };
201
+ })
202
+ });
203
+ if (p.isCancel(selectedCommitLine)) return;
204
+
205
+ const s = p.spinner();
206
+ s.start(`กำลังรันกระบวนการสอยโค้ดคอมมิต ${selectedCommitLine}...`);
207
+ try {
208
+ run(`git cherry-pick ${selectedCommitLine}`);
209
+ s.stop('สอยสำเร็จ!');
210
+ p.outro(pc.green(`🎉 ดึงพลังงานโค้ดรอบ ${selectedCommitLine} มาใส่ร่างปัจจุบันสำเร็จ!`));
211
+ } catch {
212
+ s.stop(pc.red('เกิดการชนกัน (Conflict)!'));
213
+ p.log.warn('โค้ดบางจุดอาจชนกันรุนแรง กรุณาพิมพ์แก้ไขหน้างาน หรือสั่งยกเลิกด้วย git cherry-pick --abort');
214
+ }
215
+ });
216
+
217
+ // ==========================================
218
+ // 5. COMMAND: purge-file <path>
219
+ // ==========================================
220
+ program
221
+ .command('purge-file <path>')
222
+ .description('ลบไฟล์ขนาดใหญ่หรือข้อมูลสำคัญออกจาก Git History ย้อนหลังถาวร')
223
+ .action(async (path) => {
224
+ checkGitRepo();
225
+ p.intro(pc.red('🔥 CRIMINAL HISTORY PURGE (ลบล้างประวัติบาป)'));
226
+
227
+ p.log.warn(`⚠️ คำสั่งนี้จะลบไฟล์ [${path}] ออกจาก "ทุกประวัติคอมมิตย้อนหลังในอดีตทั้งหมด" ถาวร!`);
228
+ const confirm = await p.confirm({ message: 'คุณแน่ใจใช่ไหมว่าจะทำลายหลักฐานนี้? (ย้อนกลับไม่ได้)' });
229
+ if (!confirm || p.isCancel(confirm)) return p.cancel('ยกเลิกการกวาดล้าง');
230
+
231
+ const s = p.spinner();
232
+ s.start('กำลังกรองระบบเขียนประวัติศาสตร์ใหม่ย้อนหลัง (Filter-Branch)...');
233
+
234
+ try {
235
+ // -r flag จำเป็นสำหรับ directory เช่น node_modules/
236
+ run(`git filter-branch --force --index-filter "git rm -r --cached --ignore-unmatch ${path}" --prune-empty --tag-name-filter cat -- --all`, { throws: true });
237
+ } catch {
238
+ s.stop(pc.red('Filter-Branch ล้มเหลว!'));
239
+ p.log.error('❌ ไม่สามารถแก้ไข History ได้ กรุณาตรวจสอบ path ที่ระบุ');
240
+ return;
241
+ }
242
+
243
+ s.message('กำลังบีบอัดและทำลายหน่วยความจำขยะ (Garbage Collection)...');
244
+ // ใช้ git command แทน rm -rf เพื่อรองรับ Windows
245
+ run('git for-each-ref --format="%(refname)" refs/original/ | xargs -r git update-ref -d');
246
+ run('git reflog expire --expire=now --all');
247
+ run('git gc --prune=now --aggressive');
248
+
249
+ s.stop('ลบเกลี้ยงเรียบร้อย!');
250
+ p.outro(pc.green(`💀 ไฟล์ [${path}] ถูกลบหายไปจากมิติประวัติศาสตร์ของ Git เรียบร้อย!`));
251
+ });
252
+
253
+ // ==========================================
254
+ // 6. COMMAND: move-to <branch>
255
+ // ==========================================
256
+ program
257
+ .command('move-to <branch>')
258
+ .description('ทำงานผิดบลันช์ช่างมัน! ย้ายงานค้างด่วนไปบลันช์ใหม่ด้วย stash & pop')
259
+ .action(async (branch) => {
260
+ checkGitRepo();
261
+ p.intro(pc.blue('🔄 MOVE WORKSPACE RESCUE'));
262
+
263
+ const s = p.spinner();
264
+ s.start('กำลังซ่อนงานค้างลงถังเก็บสำรอง (Stashing)...');
265
+ run('git stash');
266
+
267
+ s.message(`กำลังสลับไปที่บลันช์ [${branch}] (จะสร้างใหม่ให้ทันทีถ้าไม่เจอ)...`);
268
+ const hasBranch = run(`git branch --list ${branch}`);
269
+ if (hasBranch) {
270
+ run(`git checkout ${branch}`);
271
+ } else {
272
+ run(`git checkout -b ${branch}`);
273
+ }
274
+
275
+ s.message('กำลังคายโค้ดที่แอบเซฟไว้ออกมาวางแผงงานต่อ (Popping)...');
276
+ run('git stash pop');
277
+
278
+ s.stop('ย้ายค่ายย้ายงานสำเร็จ!');
279
+ p.outro(pc.green(`🚀 ย้ายโค้ดทั้งหมดของคุณมาปักหลักที่บลันช์ [${branch}] ให้แล้ว ลุยงานต่อได้!`));
280
+ });
281
+
282
+ // ==========================================
283
+ // 7. COMMAND: undo
284
+ // ==========================================
285
+ program
286
+ .command('undo')
287
+ .description('ย้อนสถานะย้อนเวลาถอยคอมมิต (Rollback) 3 โหมด')
288
+ .action(async () => {
289
+ checkGitRepo();
290
+ p.intro(pc.red('↩️ THE UNDO BUTTON (ย้อนเวลา)'));
291
+
292
+ const mode = await p.select({
293
+ message: 'เลือกโหมดที่คุณต้องการย้อนเวลากลับไป (ถอยจาก Commit ล่าสุดออกไป 1 ก้าว):',
294
+ options: [
295
+ { value: 'soft', label: '🟢 Soft Undo', hint: 'ถอยคอมมิตออก แต่เก็บโค้ดไว้ในสถานะพร้อมคอมมิต (Staged)' },
296
+ { value: 'mixed', label: '🟡 Mixed Undo', hint: 'ถอยคอมมิตออก แต่โค้ดกลับไปรอแก้ปกติ (Unstaged)' },
297
+ { value: 'hard', label: '🔴 Hard Undo (อันตราย!)', hint: 'ลบโค้ดที่ทำทิ้งทั้งหมด ย้อนกลับไปบริสุทธิ์เหมือนคอมมิตล่าสุด' },
298
+ ]
299
+ });
300
+ if (p.isCancel(mode)) return;
301
+
302
+ if (mode === 'hard') {
303
+ const doubleCheck = await p.confirm({ message: '⚠️ โหมด Hard จะลบโค้ดที่คุณเขียนค้างไว้ทิ้งทันที มั่นใจนะ?' });
304
+ if (!doubleCheck || p.isCancel(doubleCheck)) return p.cancel('ยกเลิกการถอย');
305
+ }
306
+
307
+ run(`git reset --${mode} HEAD~1`);
308
+ p.outro(pc.green(`↩️ ถอยทัพย้อนประวัติกลับไป 1 สเต็ปด้วยโหมด [${mode.toUpperCase()}] สำเร็จ!`));
309
+ });
310
+
311
+ // ==========================================
312
+ // 8. COMMAND: stash-box
313
+ // ==========================================
314
+ program
315
+ .command('stash-box')
316
+ .description('กล่องส่องงานค้าง ดูรายการซ่อนพร้อม Diff และนำกลับมาใช้')
317
+ .action(async () => {
318
+ checkGitRepo();
319
+ p.intro(pc.yellow('📦 STASH BOX MANAGER'));
320
+
321
+ const stashListRaw = run('git stash list') || '';
322
+ if (!stashListRaw) {
323
+ p.outro(pc.green('กล่องว่างเปล่า ไม่มีงานเซฟค้างไว้เลยครับ!'));
324
+ return;
325
+ }
326
+
327
+ const stashLines = stashListRaw.split('\n').filter(Boolean);
328
+
329
+ const selectedStash = await p.select({
330
+ message: 'เลือกถังเก็บค้างที่คุณอยากเข้าไปส่องและจัดการ:',
331
+ options: stashLines.map(line => {
332
+ const id = line.match(/stash@\{\d+\}/)[0];
333
+ return { value: id, label: line };
334
+ })
335
+ });
336
+ if (p.isCancel(selectedStash)) return;
337
+
338
+ // ดึง Diff สรุปแบบมีสี พ่นออก Terminal ให้เดฟตรวจงานก่อน
339
+ p.log.info(`${pc.bold('👁️ พรีวิวความเปลี่ยนแปลงในไฟล์:')}`);
340
+ runWithInherit(`git stash show -p ${selectedStash} --color`);
341
+
342
+ const action = await p.select({
343
+ message: '\nเลือกสิ่งที่ต้องการทำกับ Stash นี้ต่อ:',
344
+ options: [
345
+ { value: 'pop', label: '💥 Pop', hint: 'ดึงโค้ดกลับมาใช้งาน และลบถังนี้ทิ้งทันที' },
346
+ { value: 'apply', label: '📋 Apply', hint: 'ดึงโค้ดมาใช้เฉยๆ แต่ยังคงเก็บถังนี้ไว้สำรองอีกรอบ' },
347
+ { value: 'drop', label: '🗑️ Drop', hint: 'ทำลายของข้างในทิ้งถาวร ไม่ดึงโค้ดกลับมา' }
348
+ ]
349
+ });
350
+ if (p.isCancel(action)) return;
351
+
352
+ run(`git stash ${action} ${selectedStash}`);
353
+ p.outro(pc.green(`✅ จัดการ Stash ด้วยคำสั่ง [${action.toUpperCase()}] เรียบร้อยเรียบร้อย!`));
354
+ });
355
+
356
+ // ==========================================
357
+ // 9. COMMAND: merge (Guided Integration)
358
+ // ==========================================
359
+ program
360
+ .command('merge')
361
+ .description('ตัวชี้แนะการรวม Branch แบบเป็นขั้นตอน ปลอดภัย ไม่หลุด')
362
+ .action(async () => {
363
+ checkGitRepo();
364
+ p.intro(pc.cyan('🔀 GUIDED BRANCH MERGE (ตัวนำทางรวมบลันช์)'));
365
+
366
+ const branchesRaw = run('git branch --format="%(refname:short)"') || '';
367
+ const branches = branchesRaw.split('\n').filter(Boolean);
368
+ const currentBranch = run('git branch --show-current') || 'main';
369
+
370
+ const sourceBranch = await p.select({
371
+ message: `คุณต้องการดึงโค้ดจาก Branch ไหน... เข้ามาที่บลันช์ปัจจุบัน [${currentBranch}]?`,
372
+ options: branches.filter(b => b !== currentBranch).map(b => ({ value: b, label: b }))
373
+ });
374
+ if (p.isCancel(sourceBranch)) return;
375
+
376
+ // ส่อง Diff ล่วงหน้าก่อนกดรวมร่างจริง
377
+ p.log.info(pc.yellow(`📊 ไฟล์ที่จะแอบเปลี่ยนแปลงเมื่อนำมาควบรวม (${sourceBranch} -> ${currentBranch}):`));
378
+ const diffSummary = run(`git diff --stat ${currentBranch}..${sourceBranch}`) || pc.dim('ไม่มีอะไรแตกต่างกันเลย');
379
+ p.log.message(diffSummary);
380
+
381
+ const strategy = await p.select({
382
+ message: 'เลือกรูปแบบยุทธวิธีในการ Merge:',
383
+ options: [
384
+ { value: '--no-ff', label: '📦 Create Merge Commit (--no-ff)', hint: 'แบบมาตรฐาน: สร้างจุดตัดผูกปมในแผนภาพ สรุปงานชัดเจน' },
385
+ { value: '--ff-only', label: '⚡ Fast-Forward Only', hint: 'เลื่อนเส้นประวัติไปตรงๆ (จะพังทันทีถ้าประวัติเครื่องไม่ตรงกัน)' },
386
+ { value: '--squash', label: '🗜️ Merge Squash', hint: 'ยุบทุกเม็ดจากฝั่งนู้นมาขมวดปมเป็น 1 ต้อนรับเข้าฝั่งนี้' }
387
+ ]
388
+ });
389
+ if (p.isCancel(strategy)) return;
390
+
391
+ const confirm = await p.confirm({ message: `ยืนยันรันกระบวนการรวมร่างเลยไหม?` });
392
+ if (!confirm || p.isCancel(confirm)) return p.cancel('ยกเลิกแผนการควบรวม');
393
+
394
+ const s = p.spinner();
395
+ s.start(`กำลังรวบรวมพลังคำสั่งเพื่อ Merge...`);
396
+
397
+ try {
398
+ // รันคำสั่ง Merge
399
+ const mergeResult = run(`git merge ${strategy} ${sourceBranch}`);
400
+ s.stop('ดำเนินการสำเร็จ!');
401
+
402
+ p.log.success(pc.green('🎉 รวม Branch สำเร็จเรียบร้อย!'));
403
+ if (mergeResult) p.log.message(pc.dim(mergeResult));
404
+
405
+ const autoPush = await p.confirm({ message: `ต้องการกด Auto Push ขึ้นคลาวด์เลยทันทีไหม?` });
406
+ if (autoPush && !p.isCancel(autoPush)) {
407
+ s.start(`กำลัง Push ขึ้น origin/${currentBranch}...`);
408
+ run(`git push origin ${currentBranch}`);
409
+ s.stop('Push ขึ้นฟ้าเรียบร้อย!');
410
+ }
411
+ } catch {
412
+ s.stop(pc.red('เกิดการชนกันอย่างรุนแรง (Conflict Detected)!'));
413
+ p.log.error('❌ ข้อมูลชนกัน! กรุณาเปิดแอป Code เพื่อไล่เคลียร์จุดสัญลักษณ์หัวลูกศรให้เสร็จ ก่อนจะกดยืนยันเซฟต่อครับ');
414
+ }
415
+
416
+ p.outro(pc.cyan('🔚 เสร็จสิ้นภารกิจนำทางควบรวม'));
417
+ });
418
+
419
+ // สั่งประมวลผลคำสั่งทั้งหมดผ่านหน้า Terminal
420
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@kittiphop_sompuech/git-cli-tools",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "git-pro": "./index.js"
7
+ },
8
+ "description": "**Git-Pro** คือเครื่องมือ Automation CLI (เขียนด้วย Go 100%) ที่ออกแบบมาเพื่อปฏิวัติ Workflow การทำงานกับ Git ของ Developer ช่วยจัดการและแก้ไขปัญหาทุกอย่างในเครื่องได้ในคำสั่งเดียวผ่าน **Keyboard-Driven Flow** โดยไม่ต้องสลับมือไปจับเมาส์คลิกบน Git GUI และไม่ต้องจำคำสั่ง Git ที่ซับซ้อน",
9
+ "main": "index.js",
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "dependencies": {
17
+ "@clack/prompts": "^1.5.1",
18
+ "commander": "^15.0.0",
19
+ "picocolors": "^1.1.1"
20
+ }
21
+ }