geeto 0.1.1 → 0.3.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.
- package/README.md +138 -43
- package/lib/api/copilot-sdk.d.ts.map +1 -1
- package/lib/api/copilot-sdk.js +2 -0
- package/lib/api/copilot-sdk.js.map +1 -1
- package/lib/api/github.d.ts +91 -0
- package/lib/api/github.d.ts.map +1 -0
- package/lib/api/github.js +163 -0
- package/lib/api/github.js.map +1 -0
- package/lib/api/trello.js +1 -1
- package/lib/api/trello.js.map +1 -1
- package/lib/cli/input.d.ts +1 -0
- package/lib/cli/input.d.ts.map +1 -1
- package/lib/cli/input.js +349 -0
- package/lib/cli/input.js.map +1 -1
- package/lib/cli/menu.d.ts +4 -0
- package/lib/cli/menu.d.ts.map +1 -1
- package/lib/cli/menu.js +452 -31
- package/lib/cli/menu.js.map +1 -1
- package/lib/core/github-setup.d.ts +8 -0
- package/lib/core/github-setup.d.ts.map +1 -0
- package/lib/core/github-setup.js +114 -0
- package/lib/core/github-setup.js.map +1 -0
- package/lib/index.js +291 -29
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +16 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/utils/branch-naming.js +1 -1
- package/lib/utils/branch-naming.js.map +1 -1
- package/lib/utils/config.d.ts +17 -1
- package/lib/utils/config.d.ts.map +1 -1
- package/lib/utils/config.js +65 -1
- package/lib/utils/config.js.map +1 -1
- package/lib/utils/display.d.ts +20 -0
- package/lib/utils/display.d.ts.map +1 -1
- package/lib/utils/display.js +84 -21
- package/lib/utils/display.js.map +1 -1
- package/lib/utils/exec.d.ts +1 -1
- package/lib/utils/exec.d.ts.map +1 -1
- package/lib/utils/exec.js +2 -2
- package/lib/utils/exec.js.map +1 -1
- package/lib/utils/git-errors.js +3 -3
- package/lib/utils/git-errors.js.map +1 -1
- package/lib/utils/git.d.ts +9 -0
- package/lib/utils/git.d.ts.map +1 -1
- package/lib/utils/git.js +15 -0
- package/lib/utils/git.js.map +1 -1
- package/lib/utils/logging.d.ts +2 -0
- package/lib/utils/logging.d.ts.map +1 -1
- package/lib/utils/logging.js +7 -1
- package/lib/utils/logging.js.map +1 -1
- package/lib/workflows/amend.d.ts +9 -0
- package/lib/workflows/amend.d.ts.map +1 -0
- package/lib/workflows/amend.js +241 -0
- package/lib/workflows/amend.js.map +1 -0
- package/lib/workflows/branch.d.ts.map +1 -1
- package/lib/workflows/branch.js +46 -1
- package/lib/workflows/branch.js.map +1 -1
- package/lib/workflows/cherry-pick.d.ts +9 -0
- package/lib/workflows/cherry-pick.d.ts.map +1 -0
- package/lib/workflows/cherry-pick.js +237 -0
- package/lib/workflows/cherry-pick.js.map +1 -0
- package/lib/workflows/cleanup.d.ts +1 -1
- package/lib/workflows/cleanup.d.ts.map +1 -1
- package/lib/workflows/cleanup.js +93 -69
- package/lib/workflows/cleanup.js.map +1 -1
- package/lib/workflows/commit.d.ts.map +1 -1
- package/lib/workflows/commit.js +38 -19
- package/lib/workflows/commit.js.map +1 -1
- package/lib/workflows/compare.d.ts +9 -0
- package/lib/workflows/compare.d.ts.map +1 -0
- package/lib/workflows/compare.js +231 -0
- package/lib/workflows/compare.js.map +1 -0
- package/lib/workflows/history.d.ts +9 -0
- package/lib/workflows/history.d.ts.map +1 -0
- package/lib/workflows/history.js +194 -0
- package/lib/workflows/history.js.map +1 -0
- package/lib/workflows/issue.d.ts +9 -0
- package/lib/workflows/issue.d.ts.map +1 -0
- package/lib/workflows/issue.js +211 -0
- package/lib/workflows/issue.js.map +1 -0
- package/lib/workflows/main-steps.d.ts.map +1 -1
- package/lib/workflows/main-steps.js +39 -13
- package/lib/workflows/main-steps.js.map +1 -1
- package/lib/workflows/main.d.ts.map +1 -1
- package/lib/workflows/main.js +30 -39
- package/lib/workflows/main.js.map +1 -1
- package/lib/workflows/pr.d.ts +9 -0
- package/lib/workflows/pr.d.ts.map +1 -0
- package/lib/workflows/pr.js +280 -0
- package/lib/workflows/pr.js.map +1 -0
- package/lib/workflows/release.d.ts +7 -0
- package/lib/workflows/release.d.ts.map +1 -0
- package/lib/workflows/release.js +445 -0
- package/lib/workflows/release.js.map +1 -0
- package/lib/workflows/security-gate.d.ts.map +1 -1
- package/lib/workflows/security-gate.js +91 -7
- package/lib/workflows/security-gate.js.map +1 -1
- package/lib/workflows/settings.d.ts +5 -1
- package/lib/workflows/settings.d.ts.map +1 -1
- package/lib/workflows/settings.js +62 -3
- package/lib/workflows/settings.js.map +1 -1
- package/lib/workflows/stash.d.ts +9 -0
- package/lib/workflows/stash.d.ts.map +1 -0
- package/lib/workflows/stash.js +341 -0
- package/lib/workflows/stash.js.map +1 -0
- package/lib/workflows/stats.d.ts +9 -0
- package/lib/workflows/stats.d.ts.map +1 -0
- package/lib/workflows/stats.js +288 -0
- package/lib/workflows/stats.js.map +1 -0
- package/lib/workflows/switch.d.ts +9 -0
- package/lib/workflows/switch.d.ts.map +1 -0
- package/lib/workflows/switch.js +154 -0
- package/lib/workflows/switch.js.map +1 -0
- package/lib/workflows/trello-menu.d.ts.map +1 -1
- package/lib/workflows/trello-menu.js +59 -19
- package/lib/workflows/trello-menu.js.map +1 -1
- package/lib/workflows/undo.d.ts +9 -0
- package/lib/workflows/undo.d.ts.map +1 -0
- package/lib/workflows/undo.js +464 -0
- package/lib/workflows/undo.js.map +1 -0
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fetchTrelloCards, fetchTrelloLists } from '../api/trello.js';
|
|
7
|
-
import { select } from '../cli/menu.js';
|
|
7
|
+
import { multiSelect, select } from '../cli/menu.js';
|
|
8
8
|
import { colors } from '../utils/colors.js';
|
|
9
9
|
import { getTrelloConfig, hasTrelloConfig } from '../utils/config.js';
|
|
10
10
|
import { commandExists, exec } from '../utils/exec.js';
|
|
@@ -63,12 +63,6 @@ export const handleGenerateTaskInstructions = async () => {
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
spinner.succeed(`Found ${lists.length} lists`);
|
|
66
|
-
// Show tip about creating dedicated agent list
|
|
67
|
-
console.log('');
|
|
68
|
-
log.info(`${colors.cyan}💡 Tip:${colors.reset} For best results with AI agents, create a dedicated Trello list called:`);
|
|
69
|
-
log.info(` ${colors.green}"TODO FOR AGENT"${colors.reset}`);
|
|
70
|
-
log.info(' This helps organize tasks specifically meant for automated execution.');
|
|
71
|
-
console.log('');
|
|
72
66
|
// Let user select a list
|
|
73
67
|
const listChoices = lists.map((list) => ({
|
|
74
68
|
label: list.name,
|
|
@@ -89,13 +83,26 @@ export const handleGenerateTaskInstructions = async () => {
|
|
|
89
83
|
console.log('');
|
|
90
84
|
const spinner2 = log.spinner();
|
|
91
85
|
spinner2.start(`Fetching cards from "${selectedList.name}"...`);
|
|
92
|
-
const
|
|
93
|
-
if (
|
|
86
|
+
const allCards = await fetchTrelloCards(selectedListId);
|
|
87
|
+
if (allCards.length === 0) {
|
|
94
88
|
spinner2.fail('No cards found in this list');
|
|
95
89
|
log.warn('The selected list is empty or all cards are marked as [DONE]/[ARCHIVED].');
|
|
96
90
|
return;
|
|
97
91
|
}
|
|
98
|
-
spinner2.succeed(`Found ${
|
|
92
|
+
spinner2.succeed(`Found ${allCards.length} cards`);
|
|
93
|
+
console.log('');
|
|
94
|
+
const cardChoices = allCards.map((card) => ({
|
|
95
|
+
label: `#${card.idShort} - ${card.name}`,
|
|
96
|
+
value: card.id,
|
|
97
|
+
}));
|
|
98
|
+
const selectedCardIds = await multiSelect('Select cards to include in tasks instruction:', cardChoices);
|
|
99
|
+
if (selectedCardIds.length === 0) {
|
|
100
|
+
log.warn('No cards selected. Cancelled.');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Filter only selected cards (preserve original order)
|
|
104
|
+
const cards = allCards.filter((card) => selectedCardIds.includes(card.id));
|
|
105
|
+
log.success(`Selected ${colors.cyan}${cards.length}${colors.reset} of ${allCards.length} cards`);
|
|
99
106
|
// Generate markdown content
|
|
100
107
|
const now = new Date();
|
|
101
108
|
const dateStr = now.toLocaleDateString('en-US', {
|
|
@@ -116,29 +123,50 @@ Generated from Trello board on ${dateStr}
|
|
|
116
123
|
1. **EXECUTE ONLY ONE TASK AT A TIME** - Never work on multiple tasks simultaneously
|
|
117
124
|
2. **STOP after completing each task** - Do NOT automatically proceed to the next task
|
|
118
125
|
3. **Wait for explicit user confirmation** before moving to the next task
|
|
119
|
-
4. **
|
|
120
|
-
5. **
|
|
126
|
+
4. **Ask the user for validation** after implementation with clear options
|
|
127
|
+
5. **Test & Verify** - Always provide testing steps and ask user to confirm
|
|
121
128
|
|
|
122
129
|
**WORKFLOW:**
|
|
123
130
|
\`\`\`
|
|
124
131
|
Step 1: Read only the FIRST uncompleted task (with - [ ])
|
|
125
132
|
Step 2: Execute ONLY that one task
|
|
126
|
-
Step 3:
|
|
127
|
-
Step 4: STOP and
|
|
128
|
-
Step 5:
|
|
129
|
-
|
|
133
|
+
Step 3: Test the implementation (if applicable)
|
|
134
|
+
Step 4: STOP and present completion summary with options
|
|
135
|
+
Step 5: Ask user with clear choices:
|
|
136
|
+
[ ] Implementation looks good, proceed to next task
|
|
137
|
+
[ ] Has bugs/issues that need fixing
|
|
138
|
+
[ ] Needs more testing
|
|
139
|
+
[ ] Needs more detailed explanation
|
|
140
|
+
Step 6: Wait for user response and act accordingly
|
|
141
|
+
Step 7: If confirmed OK, mark done and proceed to Step 1
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
**AFTER COMPLETING IMPLEMENTATION:**
|
|
145
|
+
Always ask user with structured options using ask_questions tool:
|
|
146
|
+
\`\`\`
|
|
147
|
+
"Implementation completed! How does it look?"
|
|
148
|
+
Options:
|
|
149
|
+
- ✅ Looks good, no bugs found
|
|
150
|
+
- 🐛 Has bugs, needs fixing
|
|
151
|
+
- 🧪 Needs more testing
|
|
152
|
+
- 📝 Needs more detailed explanation
|
|
153
|
+
- ↩️ Needs rollback/revert changes
|
|
130
154
|
\`\`\`
|
|
131
155
|
|
|
132
156
|
**❌ DO NOT:**
|
|
133
157
|
- Execute multiple tasks in one go
|
|
134
158
|
- Continue to next task without confirmation
|
|
135
|
-
- Assume
|
|
159
|
+
- Assume implementation is perfect without user validation
|
|
136
160
|
- Make assumptions about database schema, models, or queries without checking
|
|
161
|
+
- Skip testing or verification steps
|
|
137
162
|
|
|
138
163
|
**✅ DO:**
|
|
139
164
|
- Work on exactly one task
|
|
140
165
|
- Stop and wait after each task
|
|
141
|
-
-
|
|
166
|
+
- Present clear summary of changes
|
|
167
|
+
- Ask for permission to continue with structured options
|
|
168
|
+
- Provide testing steps for user to verify
|
|
169
|
+
- Check both new data and old data compatibility
|
|
142
170
|
|
|
143
171
|
**📋 FOR FULLSTACK/BACKEND PROJECTS:**
|
|
144
172
|
|
|
@@ -207,11 +235,23 @@ Example: If creating a "User Settings" page, find "Account Settings" or similar
|
|
|
207
235
|
`;
|
|
208
236
|
for (const [index, card] of cards.entries()) {
|
|
209
237
|
markdown += `### Task ${index + 1} of ${cards.length}\n\n`;
|
|
210
|
-
markdown += `-
|
|
238
|
+
markdown += `- **${card.name}** (#${card.idShort})\n`;
|
|
211
239
|
markdown += ` - Trello URL: ${card.url}\n`;
|
|
212
240
|
if (card.desc?.trim()) {
|
|
213
241
|
markdown += `\n**Description:**\n${card.desc}\n`;
|
|
214
242
|
}
|
|
243
|
+
// Include Trello checklists (if any)
|
|
244
|
+
if (card.checklists && card.checklists.length > 0) {
|
|
245
|
+
for (const checklist of card.checklists) {
|
|
246
|
+
if (checklist.checkItems && checklist.checkItems.length > 0) {
|
|
247
|
+
markdown += `\n**${checklist.name}:**\n`;
|
|
248
|
+
for (const item of checklist.checkItems) {
|
|
249
|
+
const checked = item.state === 'complete' ? 'x' : ' ';
|
|
250
|
+
markdown += `- [${checked}] ${item.name}\n`;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
215
255
|
markdown += `\n---\n\n`;
|
|
216
256
|
}
|
|
217
257
|
markdown += `
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trello-menu.js","sourceRoot":"","sources":["../../src/workflows/trello-menu.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"trello-menu.js","sourceRoot":"","sources":["../../src/workflows/trello-menu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/workflows/undo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAiFH;;GAEG;AACH,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,IAAI,CAoE/C,CAAA"}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Undo Last Action workflow
|
|
3
|
+
* Safely revert the last git operation
|
|
4
|
+
*/
|
|
5
|
+
import { confirm } from '../cli/input.js';
|
|
6
|
+
import { select } from '../cli/menu.js';
|
|
7
|
+
import { colors } from '../utils/colors.js';
|
|
8
|
+
import { exec, execSilent } from '../utils/exec.js';
|
|
9
|
+
import { getCurrentBranch } from '../utils/git.js';
|
|
10
|
+
import { log } from '../utils/logging.js';
|
|
11
|
+
/**
|
|
12
|
+
* Detect what the last action was using reflog
|
|
13
|
+
*/
|
|
14
|
+
const detectLastAction = () => {
|
|
15
|
+
try {
|
|
16
|
+
const sep = '<<GTO>>';
|
|
17
|
+
const output = execSilent(`git reflog -2 --format="%H${sep}%gd${sep}%gs"`).trim();
|
|
18
|
+
if (!output)
|
|
19
|
+
return null;
|
|
20
|
+
const lines = output.split('\n').filter(Boolean);
|
|
21
|
+
if (lines.length === 0)
|
|
22
|
+
return null;
|
|
23
|
+
const current = lines[0]?.split(sep) ?? [];
|
|
24
|
+
const prev = lines[1]?.split(sep) ?? [];
|
|
25
|
+
const hash = current[0] ?? '';
|
|
26
|
+
const prevHash = prev[0] ?? '';
|
|
27
|
+
const reflogEntry = current[1] ?? '';
|
|
28
|
+
const actionStr = current[2] ?? '';
|
|
29
|
+
let type = 'unknown';
|
|
30
|
+
let description = actionStr;
|
|
31
|
+
if (actionStr.startsWith('commit:')) {
|
|
32
|
+
type = 'commit';
|
|
33
|
+
description = `Commit: ${actionStr.replace('commit: ', '')}`;
|
|
34
|
+
}
|
|
35
|
+
else if (actionStr.startsWith('commit (amend):')) {
|
|
36
|
+
type = 'amend';
|
|
37
|
+
description = `Amend: ${actionStr.replace('commit (amend): ', '')}`;
|
|
38
|
+
}
|
|
39
|
+
else if (actionStr.startsWith('commit (merge):')) {
|
|
40
|
+
type = 'merge-commit';
|
|
41
|
+
description = `Merge commit: ${actionStr.replace('commit (merge): ', '')}`;
|
|
42
|
+
}
|
|
43
|
+
else if (actionStr.startsWith('merge')) {
|
|
44
|
+
type = 'merge';
|
|
45
|
+
description = `Merge: ${actionStr}`;
|
|
46
|
+
}
|
|
47
|
+
else if (actionStr.startsWith('checkout:')) {
|
|
48
|
+
type = 'checkout';
|
|
49
|
+
description = `Checkout: ${actionStr.replace('checkout: ', '')}`;
|
|
50
|
+
}
|
|
51
|
+
else if (actionStr.startsWith('pull')) {
|
|
52
|
+
type = 'pull';
|
|
53
|
+
description = `Pull: ${actionStr}`;
|
|
54
|
+
}
|
|
55
|
+
else if (actionStr.startsWith('rebase')) {
|
|
56
|
+
type = 'rebase';
|
|
57
|
+
description = `Rebase: ${actionStr}`;
|
|
58
|
+
}
|
|
59
|
+
else if (actionStr.startsWith('reset:')) {
|
|
60
|
+
type = 'reset';
|
|
61
|
+
description = `Reset: ${actionStr}`;
|
|
62
|
+
}
|
|
63
|
+
else if (actionStr.startsWith('cherry-pick:')) {
|
|
64
|
+
type = 'cherry-pick';
|
|
65
|
+
description = `Cherry-pick: ${actionStr.replace('cherry-pick: ', '')}`;
|
|
66
|
+
}
|
|
67
|
+
else if (actionStr.startsWith('Branch:')) {
|
|
68
|
+
type = 'branch';
|
|
69
|
+
description = actionStr;
|
|
70
|
+
}
|
|
71
|
+
return { type, description, reflogEntry, hash, prevHash };
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Get short hash
|
|
79
|
+
*/
|
|
80
|
+
const shortHash = (hash) => hash.slice(0, 7);
|
|
81
|
+
/**
|
|
82
|
+
* Interactive undo last action
|
|
83
|
+
*/
|
|
84
|
+
export const handleUndo = async () => {
|
|
85
|
+
log.banner();
|
|
86
|
+
log.step(`${colors.cyan}Undo Last Action${colors.reset}\n`);
|
|
87
|
+
const branch = getCurrentBranch();
|
|
88
|
+
const lastAction = detectLastAction();
|
|
89
|
+
if (!lastAction) {
|
|
90
|
+
log.warn('No action found in reflog to undo.');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Show what happened
|
|
94
|
+
const line = '─'.repeat(56);
|
|
95
|
+
console.log(`${colors.cyan}┌${line}┐${colors.reset}`);
|
|
96
|
+
console.log(`${colors.cyan}│${colors.reset} ${colors.bright}Last action on ${colors.green}${branch}${colors.reset}`);
|
|
97
|
+
console.log(`${colors.cyan}├${line}┤${colors.reset}`);
|
|
98
|
+
console.log(`${colors.cyan}│${colors.reset} ${colors.yellow}${shortHash(lastAction.hash)}${colors.reset} ${colors.bright}${lastAction.description}${colors.reset}`);
|
|
99
|
+
console.log(`${colors.cyan}│${colors.reset} ${colors.gray}Previous: ${shortHash(lastAction.prevHash)}${colors.reset}`);
|
|
100
|
+
console.log(`${colors.cyan}└${line}┘${colors.reset}`);
|
|
101
|
+
// Offer undo options based on action type
|
|
102
|
+
console.log('');
|
|
103
|
+
switch (lastAction.type) {
|
|
104
|
+
case 'commit': {
|
|
105
|
+
await undoCommit(lastAction.prevHash);
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case 'amend': {
|
|
109
|
+
await undoAmend(lastAction.prevHash);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case 'merge':
|
|
113
|
+
case 'merge-commit': {
|
|
114
|
+
await undoMerge();
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case 'checkout': {
|
|
118
|
+
undoCheckout(lastAction.description);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case 'pull': {
|
|
122
|
+
await undoPull(lastAction.prevHash);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'rebase': {
|
|
126
|
+
await undoRebase(lastAction.prevHash);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case 'reset': {
|
|
130
|
+
undoReset(lastAction.prevHash);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
case 'cherry-pick': {
|
|
134
|
+
await undoCommit(lastAction.prevHash);
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
default: {
|
|
138
|
+
await undoGeneric(lastAction.prevHash);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Undo a commit
|
|
144
|
+
*/
|
|
145
|
+
const undoCommit = async (_prevHash) => {
|
|
146
|
+
const action = await select('How to undo this commit?', [
|
|
147
|
+
{
|
|
148
|
+
label: 'Soft reset — keep changes staged',
|
|
149
|
+
value: 'soft',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
label: 'Mixed reset — keep changes unstaged',
|
|
153
|
+
value: 'mixed',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
label: 'Hard reset — discard changes completely',
|
|
157
|
+
value: 'hard',
|
|
158
|
+
},
|
|
159
|
+
{ label: 'Cancel', value: 'cancel' },
|
|
160
|
+
]);
|
|
161
|
+
if (action === 'cancel')
|
|
162
|
+
return;
|
|
163
|
+
if (action === 'hard') {
|
|
164
|
+
log.warn('This will permanently discard your changes!');
|
|
165
|
+
const sure = confirm('Are you sure?');
|
|
166
|
+
if (!sure)
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const flag = action === 'soft' ? '--soft' : action === 'hard' ? '--hard' : '--mixed';
|
|
170
|
+
const spinner = log.spinner();
|
|
171
|
+
spinner.start('Undoing commit...');
|
|
172
|
+
try {
|
|
173
|
+
exec(`git reset ${flag} HEAD~1`, true);
|
|
174
|
+
spinner.succeed(`Commit undone (${action} reset)`);
|
|
175
|
+
showCurrentState();
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
spinner.fail('Failed to undo commit');
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Undo an amend
|
|
183
|
+
*/
|
|
184
|
+
const undoAmend = async (prevHash) => {
|
|
185
|
+
log.info('This will restore the commit to its state before the amend.');
|
|
186
|
+
console.log(` ${colors.gray}Target: ${shortHash(prevHash)}${colors.reset}`);
|
|
187
|
+
const action = await select('How to undo the amend?', [
|
|
188
|
+
{
|
|
189
|
+
label: 'Soft reset — restore pre-amend state, keep changes staged',
|
|
190
|
+
value: 'soft',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
label: 'Mixed reset — restore pre-amend state, keep changes unstaged',
|
|
194
|
+
value: 'mixed',
|
|
195
|
+
},
|
|
196
|
+
{ label: 'Cancel', value: 'cancel' },
|
|
197
|
+
]);
|
|
198
|
+
if (action === 'cancel')
|
|
199
|
+
return;
|
|
200
|
+
const flag = action === 'soft' ? '--soft' : '--mixed';
|
|
201
|
+
const spinner = log.spinner();
|
|
202
|
+
spinner.start('Undoing amend...');
|
|
203
|
+
try {
|
|
204
|
+
exec(`git reset ${flag} ${prevHash}`, true);
|
|
205
|
+
spinner.succeed('Amend undone!');
|
|
206
|
+
showCurrentState();
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
spinner.fail('Failed to undo amend');
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Undo a merge
|
|
214
|
+
*/
|
|
215
|
+
const undoMerge = async () => {
|
|
216
|
+
const action = await select('How to undo this merge?', [
|
|
217
|
+
{
|
|
218
|
+
label: 'Abort merge — if merge is still in progress',
|
|
219
|
+
value: 'abort',
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
label: 'Reset merge commit — undo completed merge',
|
|
223
|
+
value: 'reset',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
label: 'Revert merge — create a new commit that reverses the merge',
|
|
227
|
+
value: 'revert',
|
|
228
|
+
},
|
|
229
|
+
{ label: 'Cancel', value: 'cancel' },
|
|
230
|
+
]);
|
|
231
|
+
if (action === 'cancel')
|
|
232
|
+
return;
|
|
233
|
+
const spinner = log.spinner();
|
|
234
|
+
if (action === 'abort') {
|
|
235
|
+
spinner.start('Aborting merge...');
|
|
236
|
+
try {
|
|
237
|
+
exec('git merge --abort', true);
|
|
238
|
+
spinner.succeed('Merge aborted!');
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
spinner.fail('No merge in progress to abort');
|
|
242
|
+
}
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (action === 'reset') {
|
|
246
|
+
log.warn('This will discard the merge commit!');
|
|
247
|
+
const sure = confirm('Are you sure?');
|
|
248
|
+
if (!sure)
|
|
249
|
+
return;
|
|
250
|
+
spinner.start('Resetting merge...');
|
|
251
|
+
try {
|
|
252
|
+
exec('git reset --hard HEAD~1', true);
|
|
253
|
+
spinner.succeed('Merge commit undone!');
|
|
254
|
+
showCurrentState();
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
spinner.fail('Failed to reset merge');
|
|
258
|
+
}
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (action === 'revert') {
|
|
262
|
+
spinner.start('Reverting merge...');
|
|
263
|
+
try {
|
|
264
|
+
exec('git revert -m 1 HEAD', true);
|
|
265
|
+
spinner.succeed('Merge reverted with new commit!');
|
|
266
|
+
showCurrentState();
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
spinner.fail('Failed to revert merge');
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
/**
|
|
274
|
+
* Undo a checkout
|
|
275
|
+
*/
|
|
276
|
+
const undoCheckout = (description) => {
|
|
277
|
+
// Parse the checkout description to find the previous branch
|
|
278
|
+
const match = description.match(/moving from (.+?) to (.+)/);
|
|
279
|
+
const fromBranch = match?.[1] ?? '';
|
|
280
|
+
if (!fromBranch) {
|
|
281
|
+
log.warn('Could not determine previous branch.');
|
|
282
|
+
log.info(`Try: ${colors.cyan}git checkout -${colors.reset}`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
log.info(`Switch back to ${colors.green}${fromBranch}${colors.reset}?`);
|
|
286
|
+
const doIt = confirm('Proceed?');
|
|
287
|
+
if (!doIt)
|
|
288
|
+
return;
|
|
289
|
+
const spinner = log.spinner();
|
|
290
|
+
spinner.start(`Switching to ${fromBranch}...`);
|
|
291
|
+
try {
|
|
292
|
+
exec(`git checkout ${fromBranch}`, true);
|
|
293
|
+
spinner.succeed(`Switched back to ${fromBranch}`);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
spinner.fail(`Failed to switch to ${fromBranch}`);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Undo a pull
|
|
301
|
+
*/
|
|
302
|
+
const undoPull = async (prevHash) => {
|
|
303
|
+
log.info('This will reset to the state before the pull.');
|
|
304
|
+
console.log(` ${colors.gray}Target: ${shortHash(prevHash)}${colors.reset}`);
|
|
305
|
+
const action = await select('How to undo the pull?', [
|
|
306
|
+
{
|
|
307
|
+
label: 'Hard reset — discard all pulled changes',
|
|
308
|
+
value: 'hard',
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
label: 'Mixed reset — keep pulled changes as unstaged',
|
|
312
|
+
value: 'mixed',
|
|
313
|
+
},
|
|
314
|
+
{ label: 'Cancel', value: 'cancel' },
|
|
315
|
+
]);
|
|
316
|
+
if (action === 'cancel')
|
|
317
|
+
return;
|
|
318
|
+
if (action === 'hard') {
|
|
319
|
+
log.warn('This will discard all pulled changes!');
|
|
320
|
+
const sure = confirm('Are you sure?');
|
|
321
|
+
if (!sure)
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const flag = action === 'hard' ? '--hard' : '--mixed';
|
|
325
|
+
const spinner = log.spinner();
|
|
326
|
+
spinner.start('Undoing pull...');
|
|
327
|
+
try {
|
|
328
|
+
exec(`git reset ${flag} ${prevHash}`, true);
|
|
329
|
+
spinner.succeed('Pull undone!');
|
|
330
|
+
showCurrentState();
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
spinner.fail('Failed to undo pull');
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
/**
|
|
337
|
+
* Undo a rebase
|
|
338
|
+
*/
|
|
339
|
+
const undoRebase = async (prevHash) => {
|
|
340
|
+
// Check if rebase is still in progress
|
|
341
|
+
try {
|
|
342
|
+
execSilent('git rebase --show-current-patch');
|
|
343
|
+
// Rebase in progress
|
|
344
|
+
const action = await select('Rebase is in progress:', [
|
|
345
|
+
{ label: 'Abort rebase — cancel completely', value: 'abort' },
|
|
346
|
+
{ label: 'Cancel', value: 'cancel' },
|
|
347
|
+
]);
|
|
348
|
+
if (action === 'cancel')
|
|
349
|
+
return;
|
|
350
|
+
const spinner = log.spinner();
|
|
351
|
+
spinner.start('Aborting rebase...');
|
|
352
|
+
try {
|
|
353
|
+
exec('git rebase --abort', true);
|
|
354
|
+
spinner.succeed('Rebase aborted!');
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
spinner.fail('Failed to abort rebase');
|
|
358
|
+
}
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
// Not in progress, was completed
|
|
363
|
+
}
|
|
364
|
+
log.info('The rebase has completed. To undo:');
|
|
365
|
+
console.log(` ${colors.gray}Will reset to ${shortHash(prevHash)} (pre-rebase state)${colors.reset}`);
|
|
366
|
+
const doIt = confirm('Undo completed rebase?');
|
|
367
|
+
if (!doIt)
|
|
368
|
+
return;
|
|
369
|
+
const spinner = log.spinner();
|
|
370
|
+
spinner.start('Undoing rebase...');
|
|
371
|
+
try {
|
|
372
|
+
exec(`git reset --hard ${prevHash}`, true);
|
|
373
|
+
spinner.succeed('Rebase undone!');
|
|
374
|
+
showCurrentState();
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
spinner.fail('Failed to undo rebase');
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
/**
|
|
381
|
+
* Undo a reset
|
|
382
|
+
*/
|
|
383
|
+
const undoReset = (prevHash) => {
|
|
384
|
+
log.info('This will reverse the reset operation.');
|
|
385
|
+
console.log(` ${colors.gray}Will restore to ${shortHash(prevHash)}${colors.reset}`);
|
|
386
|
+
const doIt = confirm('Undo the reset?');
|
|
387
|
+
if (!doIt)
|
|
388
|
+
return;
|
|
389
|
+
const spinner = log.spinner();
|
|
390
|
+
spinner.start('Reversing reset...');
|
|
391
|
+
try {
|
|
392
|
+
exec(`git reset --hard ${prevHash}`, true);
|
|
393
|
+
spinner.succeed('Reset reversed!');
|
|
394
|
+
showCurrentState();
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
spinner.fail('Failed to reverse reset');
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* Generic undo using reflog
|
|
402
|
+
*/
|
|
403
|
+
const undoGeneric = async (prevHash) => {
|
|
404
|
+
log.info('Undo by resetting to previous state in reflog.');
|
|
405
|
+
console.log(` ${colors.gray}Target: ${shortHash(prevHash)}${colors.reset}`);
|
|
406
|
+
const action = await select('Reset mode:', [
|
|
407
|
+
{
|
|
408
|
+
label: 'Soft — keep all changes staged',
|
|
409
|
+
value: 'soft',
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
label: 'Mixed — keep changes as unstaged',
|
|
413
|
+
value: 'mixed',
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
label: 'Hard — discard everything',
|
|
417
|
+
value: 'hard',
|
|
418
|
+
},
|
|
419
|
+
{ label: 'Cancel', value: 'cancel' },
|
|
420
|
+
]);
|
|
421
|
+
if (action === 'cancel')
|
|
422
|
+
return;
|
|
423
|
+
if (action === 'hard') {
|
|
424
|
+
log.warn('This will discard all changes!');
|
|
425
|
+
const sure = confirm('Are you sure?');
|
|
426
|
+
if (!sure)
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const flag = action === 'soft' ? '--soft' : action === 'hard' ? '--hard' : '--mixed';
|
|
430
|
+
const spinner = log.spinner();
|
|
431
|
+
spinner.start('Undoing...');
|
|
432
|
+
try {
|
|
433
|
+
exec(`git reset ${flag} ${prevHash}`, true);
|
|
434
|
+
spinner.succeed('Action undone!');
|
|
435
|
+
showCurrentState();
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
spinner.fail('Failed to undo action');
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
/**
|
|
442
|
+
* Show current state after undo
|
|
443
|
+
*/
|
|
444
|
+
const showCurrentState = () => {
|
|
445
|
+
try {
|
|
446
|
+
const status = execSilent('git status --short').trim();
|
|
447
|
+
if (status) {
|
|
448
|
+
console.log('');
|
|
449
|
+
log.info('Current working tree:');
|
|
450
|
+
const lines = status.split('\n').slice(0, 10);
|
|
451
|
+
for (const l of lines) {
|
|
452
|
+
console.log(` ${colors.gray}${l}${colors.reset}`);
|
|
453
|
+
}
|
|
454
|
+
const total = status.split('\n').length;
|
|
455
|
+
if (total > 10) {
|
|
456
|
+
console.log(` ${colors.gray}... and ${total - 10} more${colors.reset}`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
// ignore
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
//# sourceMappingURL=undo.js.map
|