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
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Elegant commit history viewer
|
|
3
|
+
* Display commit log with a beautiful timeline UI
|
|
4
|
+
*/
|
|
5
|
+
import { select } from '../cli/menu.js';
|
|
6
|
+
import { colors } from '../utils/colors.js';
|
|
7
|
+
import { execSilent } from '../utils/exec.js';
|
|
8
|
+
import { getCurrentBranch } from '../utils/git.js';
|
|
9
|
+
import { log } from '../utils/logging.js';
|
|
10
|
+
/**
|
|
11
|
+
* Fetch commits with full details
|
|
12
|
+
*/
|
|
13
|
+
const getCommits = (limit, offset = 0) => {
|
|
14
|
+
try {
|
|
15
|
+
const fieldSep = '<<GTO>>';
|
|
16
|
+
const recordSep = '<<END>>';
|
|
17
|
+
const format = [
|
|
18
|
+
'%H', // full hash
|
|
19
|
+
'%h', // short hash
|
|
20
|
+
'%s', // subject
|
|
21
|
+
'%b', // body (may contain newlines)
|
|
22
|
+
'%an', // author name
|
|
23
|
+
'%ci', // date ISO
|
|
24
|
+
'%cr', // relative date
|
|
25
|
+
'%D', // ref names
|
|
26
|
+
'%P', // parent hashes (multiple = merge)
|
|
27
|
+
].join(fieldSep);
|
|
28
|
+
const output = execSilent(`git log --format="${format}${recordSep}" --skip=${offset} -${limit}`).trim();
|
|
29
|
+
if (!output)
|
|
30
|
+
return [];
|
|
31
|
+
// Split on record separator first (handles multi-line body)
|
|
32
|
+
return output
|
|
33
|
+
.split(recordSep)
|
|
34
|
+
.map((record) => record.trim())
|
|
35
|
+
.filter(Boolean)
|
|
36
|
+
.map((record) => {
|
|
37
|
+
const parts = record.split(fieldSep);
|
|
38
|
+
const parents = (parts[8] ?? '').trim().split(' ').filter(Boolean);
|
|
39
|
+
return {
|
|
40
|
+
hash: parts[0] ?? '',
|
|
41
|
+
shortHash: parts[1] ?? '',
|
|
42
|
+
subject: parts[2] ?? '',
|
|
43
|
+
body: (parts[3] ?? '').trim(),
|
|
44
|
+
author: parts[4] ?? '',
|
|
45
|
+
date: parts[5] ?? '',
|
|
46
|
+
relativeDate: parts[6] ?? '',
|
|
47
|
+
refs: parts[7] ?? '',
|
|
48
|
+
isMerge: parents.length > 1,
|
|
49
|
+
};
|
|
50
|
+
})
|
|
51
|
+
.filter((c) => c.hash !== '');
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Format ref tags (HEAD, branches, tags)
|
|
59
|
+
*/
|
|
60
|
+
const formatRefs = (refs) => {
|
|
61
|
+
if (!refs.trim())
|
|
62
|
+
return '';
|
|
63
|
+
const parts = refs.split(',').map((r) => r.trim());
|
|
64
|
+
const formatted = parts.map((ref) => {
|
|
65
|
+
if (ref.startsWith('HEAD')) {
|
|
66
|
+
return `${colors.red}${colors.bright}HEAD${colors.reset}`;
|
|
67
|
+
}
|
|
68
|
+
if (ref.startsWith('tag:')) {
|
|
69
|
+
return `${colors.yellow}🏷 ${ref.replace('tag: ', '')}${colors.reset}`;
|
|
70
|
+
}
|
|
71
|
+
if (ref.includes('origin/')) {
|
|
72
|
+
return `${colors.cyan}${ref}${colors.reset}`;
|
|
73
|
+
}
|
|
74
|
+
return `${colors.green}${ref}${colors.reset}`;
|
|
75
|
+
});
|
|
76
|
+
return ` (${formatted.join(', ')})`;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Render a single commit in timeline style
|
|
80
|
+
*/
|
|
81
|
+
const renderCommit = (commit, isLast) => {
|
|
82
|
+
const connector = isLast ? '╰' : '├';
|
|
83
|
+
const pipe = isLast ? ' ' : '│';
|
|
84
|
+
// Merge indicator
|
|
85
|
+
const mergeIcon = commit.isMerge ? `${colors.cyan}⤵${colors.reset} ` : '';
|
|
86
|
+
// Hash + refs
|
|
87
|
+
const hashStr = `${colors.yellow}${commit.shortHash}${colors.reset}`;
|
|
88
|
+
const refStr = formatRefs(commit.refs);
|
|
89
|
+
// Subject line
|
|
90
|
+
console.log(` ${colors.gray}${connector}─${colors.reset} ${mergeIcon}${hashStr}${refStr} ${colors.bright}${commit.subject}${colors.reset}`);
|
|
91
|
+
// Author + date
|
|
92
|
+
console.log(` ${colors.gray}${pipe}${colors.reset} ${colors.blue}${commit.author}${colors.reset} ${colors.gray}· ${commit.relativeDate}${colors.reset}`);
|
|
93
|
+
// Body (if present, show first 2 lines)
|
|
94
|
+
if (commit.body) {
|
|
95
|
+
const bodyLines = commit.body.split('\n').filter(Boolean).slice(0, 2);
|
|
96
|
+
for (const bodyLine of bodyLines) {
|
|
97
|
+
const trimmed = bodyLine.length > 80 ? bodyLine.slice(0, 77) + '...' : bodyLine;
|
|
98
|
+
console.log(` ${colors.gray}${pipe}${colors.reset} ${colors.gray}${trimmed}${colors.reset}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Spacer between commits
|
|
102
|
+
if (!isLast) {
|
|
103
|
+
console.log(` ${colors.gray}│${colors.reset}`);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Get summary statistics
|
|
108
|
+
*/
|
|
109
|
+
const getStats = () => {
|
|
110
|
+
try {
|
|
111
|
+
const total = Number.parseInt(execSilent('git rev-list --count HEAD').trim(), 10);
|
|
112
|
+
const authorsOutput = execSilent('git shortlog -sn HEAD | wc -l').trim();
|
|
113
|
+
const authors = Number.parseInt(authorsOutput, 10);
|
|
114
|
+
const firstDate = execSilent('git log --reverse --format="%cr" -1').trim();
|
|
115
|
+
return { totalCommits: total, authors, firstDate };
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return { totalCommits: 0, authors: 0, firstDate: '' };
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Interactive commit history viewer
|
|
123
|
+
*/
|
|
124
|
+
export const handleHistory = async () => {
|
|
125
|
+
log.banner();
|
|
126
|
+
log.step(`${colors.cyan}Commit History${colors.reset}\n`);
|
|
127
|
+
const current = getCurrentBranch();
|
|
128
|
+
const stats = getStats();
|
|
129
|
+
// Header info box
|
|
130
|
+
const line = '─'.repeat(56);
|
|
131
|
+
console.log(`${colors.cyan}┌${line}┐${colors.reset}`);
|
|
132
|
+
console.log(`${colors.cyan}│${colors.reset} Branch: ${colors.green}${colors.bright}${current}${colors.reset}`);
|
|
133
|
+
console.log(`${colors.cyan}│${colors.reset} Commits: ${colors.yellow}${stats.totalCommits}${colors.reset}` +
|
|
134
|
+
` Authors: ${colors.blue}${stats.authors}${colors.reset}` +
|
|
135
|
+
(stats.firstDate ? ` Since: ${colors.gray}${stats.firstDate}${colors.reset}` : ''));
|
|
136
|
+
console.log(`${colors.cyan}└${line}┘${colors.reset}`);
|
|
137
|
+
const PAGE_SIZE = 15;
|
|
138
|
+
let offset = 0;
|
|
139
|
+
let keepGoing = true;
|
|
140
|
+
while (keepGoing) {
|
|
141
|
+
const commits = getCommits(PAGE_SIZE, offset);
|
|
142
|
+
if (commits.length === 0 && offset === 0) {
|
|
143
|
+
console.log('');
|
|
144
|
+
log.warn('No commits found.');
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (commits.length === 0) {
|
|
148
|
+
console.log('');
|
|
149
|
+
log.info('No more commits.');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// Timeline header
|
|
153
|
+
console.log('');
|
|
154
|
+
if (offset === 0) {
|
|
155
|
+
console.log(` ${colors.gray}╭── Timeline ──${colors.reset}`);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
console.log(` ${colors.gray}│ ... continued${colors.reset}`);
|
|
159
|
+
}
|
|
160
|
+
console.log(` ${colors.gray}│${colors.reset}`);
|
|
161
|
+
// Render each commit
|
|
162
|
+
const isLastPage = commits.length < PAGE_SIZE;
|
|
163
|
+
for (const [i, commit] of commits.entries()) {
|
|
164
|
+
const isLast = isLastPage && i === commits.length - 1;
|
|
165
|
+
renderCommit(commit, isLast);
|
|
166
|
+
}
|
|
167
|
+
if (isLastPage) {
|
|
168
|
+
console.log(` ${colors.gray} (end of history)${colors.reset}`);
|
|
169
|
+
console.log('');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
// Pagination menu
|
|
173
|
+
console.log('');
|
|
174
|
+
const action = await select('', [
|
|
175
|
+
{
|
|
176
|
+
label: `Load more (${offset + PAGE_SIZE + 1}-${offset + PAGE_SIZE * 2})`,
|
|
177
|
+
value: 'more',
|
|
178
|
+
},
|
|
179
|
+
{ label: 'Done', value: 'done' },
|
|
180
|
+
]);
|
|
181
|
+
switch (action) {
|
|
182
|
+
case 'more': {
|
|
183
|
+
offset += PAGE_SIZE;
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
default: {
|
|
187
|
+
keepGoing = false;
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
console.log('');
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/workflows/history.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AAczC;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,KAAa,EAAE,MAAM,GAAG,CAAC,EAAiB,EAAE;IAC9D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,SAAS,CAAA;QAC1B,MAAM,SAAS,GAAG,SAAS,CAAA;QAC3B,MAAM,MAAM,GAAG;YACb,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,8BAA8B;YACpC,KAAK,EAAE,cAAc;YACrB,KAAK,EAAE,WAAW;YAClB,KAAK,EAAE,gBAAgB;YACvB,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,mCAAmC;SAC1C,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAEhB,MAAM,MAAM,GAAG,UAAU,CACvB,qBAAqB,MAAM,GAAG,SAAS,YAAY,MAAM,KAAK,KAAK,EAAE,CACtE,CAAC,IAAI,EAAE,CAAA;QACR,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAEtB,4DAA4D;QAC5D,OAAO,MAAM;aACV,KAAK,CAAC,SAAS,CAAC;aAChB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;aAC9B,MAAM,CAAC,OAAO,CAAC;aACf,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YACd,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;YACpC,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;YAClE,OAAO;gBACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpB,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACzB,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACvB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;gBAC7B,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACtB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpB,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBAC5B,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpB,OAAO,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC;aAC5B,CAAA;QACH,CAAC,CAAC;aACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAA;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,UAAU,GAAG,CAAC,IAAY,EAAU,EAAE;IAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAA;IAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAClC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,OAAO,MAAM,CAAC,KAAK,EAAE,CAAA;QAC3D,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO,GAAG,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,CAAA;QACxE,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,OAAO,GAAG,MAAM,CAAC,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,CAAA;QAC9C,CAAC;QACD,OAAO,GAAG,MAAM,CAAC,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,OAAO,KAAK,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAA;AACrC,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,MAAmB,EAAE,MAAe,EAAQ,EAAE;IAClE,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;IACpC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAA;IAE/B,kBAAkB;IAClB,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IAEzE,cAAc;IACd,MAAM,OAAO,GAAG,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,KAAK,EAAE,CAAA;IACpE,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAEtC,eAAe;IACf,OAAO,CAAC,GAAG,CACT,KAAK,MAAM,CAAC,IAAI,GAAG,SAAS,IAAI,MAAM,CAAC,KAAK,IAAI,SAAS,GAAG,OAAO,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAChI,CAAA;IAED,gBAAgB;IAChB,OAAO,CAAC,GAAG,CACT,KAAK,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,KAAK,EAAE,CAC/I,CAAA;IAED,wCAAwC;IACxC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QACrE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAA;YAC/E,OAAO,CAAC,GAAG,CACT,KAAK,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,MAAM,MAAM,CAAC,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CACnF,CAAA;QACH,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;IACjD,CAAC;AACH,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,QAAQ,GAAG,GAAiE,EAAE;IAClF,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;QACjF,MAAM,aAAa,GAAG,UAAU,CAAC,+BAA+B,CAAC,CAAC,IAAI,EAAE,CAAA;QACxE,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,CAAC,CAAA;QAClD,MAAM,SAAS,GAAG,UAAU,CAAC,qCAAqC,CAAC,CAAC,IAAI,EAAE,CAAA;QAC1E,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAA;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;IACvD,CAAC;AACH,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,IAAmB,EAAE;IACrD,GAAG,CAAC,MAAM,EAAE,CAAA;IACZ,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,iBAAiB,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;IAEzD,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAA;IAClC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IAExB,kBAAkB;IAClB,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;IAC3B,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;IACrD,OAAO,CAAC,GAAG,CACT,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,YAAY,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE,CAClG,CAAA;IACD,OAAO,CAAC,GAAG,CACT,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,aAAa,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,KAAK,EAAE;QAC5F,cAAc,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,EAAE;QAC1D,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,SAAS,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACtF,CAAA;IACD,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;IAErD,MAAM,SAAS,GAAG,EAAE,CAAA;IACpB,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,IAAI,SAAS,GAAG,IAAI,CAAA;IAEpB,OAAO,SAAS,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;QAE7C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACf,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACf,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;YAC5B,OAAM;QACR,CAAC;QAED,kBAAkB;QAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,kBAAkB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;QAC/D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,oBAAoB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;QACjE,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;QAE/C,qBAAqB;QACrB,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAA;QAC7C,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,UAAU,IAAI,CAAC,KAAK,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;YACrD,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAC9B,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,IAAI,qBAAqB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;YAChE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACf,OAAM;QACR,CAAC;QAED,kBAAkB;QAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACf,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,EAAE;YAC9B;gBACE,KAAK,EAAE,cAAc,MAAM,GAAG,SAAS,GAAG,CAAC,IAAI,MAAM,GAAG,SAAS,GAAG,CAAC,GAAG;gBACxE,KAAK,EAAE,MAAM;aACd;YACD,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;SACjC,CAAC,CAAA;QAEF,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,IAAI,SAAS,CAAA;gBACnB,MAAK;YACP,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACR,SAAS,GAAG,KAAK,CAAA;gBACjB,MAAK;YACP,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACjB,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue.d.ts","sourceRoot":"","sources":["../../src/workflows/issue.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,IAAI,CA0NtD,CAAA"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create GitHub Issue workflow
|
|
3
|
+
* Interactive issue creation from CLI
|
|
4
|
+
*/
|
|
5
|
+
import { createIssue, listLabels, parseRepoFromUrl } from '../api/github.js';
|
|
6
|
+
import { askQuestion, confirm } from '../cli/input.js';
|
|
7
|
+
import { multiSelect, select } from '../cli/menu.js';
|
|
8
|
+
import { setupGithubConfigInteractive } from '../core/github-setup.js';
|
|
9
|
+
import { colors } from '../utils/colors.js';
|
|
10
|
+
import { hasGithubConfig } from '../utils/config.js';
|
|
11
|
+
import { execSilent } from '../utils/exec.js';
|
|
12
|
+
import { log } from '../utils/logging.js';
|
|
13
|
+
/**
|
|
14
|
+
* Interactive Create Issue workflow
|
|
15
|
+
*/
|
|
16
|
+
export const handleCreateIssue = async () => {
|
|
17
|
+
log.banner();
|
|
18
|
+
log.step(`${colors.cyan}Create GitHub Issue${colors.reset}\n`);
|
|
19
|
+
// Check GitHub config
|
|
20
|
+
if (!hasGithubConfig()) {
|
|
21
|
+
const ok = setupGithubConfigInteractive();
|
|
22
|
+
if (!ok) {
|
|
23
|
+
log.info('Setup cancelled. Run --setup-github later.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
console.log('');
|
|
27
|
+
}
|
|
28
|
+
// Resolve repo info from remote
|
|
29
|
+
let remoteUrl = '';
|
|
30
|
+
try {
|
|
31
|
+
remoteUrl = execSilent('git remote get-url origin').trim();
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
log.error('No git remote "origin" found.');
|
|
35
|
+
log.info('Add a remote: git remote add origin <url>');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const repoInfo = parseRepoFromUrl(remoteUrl);
|
|
39
|
+
if (!repoInfo) {
|
|
40
|
+
log.error('Could not parse GitHub owner/repo from remote URL.');
|
|
41
|
+
log.info(`Remote: ${remoteUrl}`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
log.info(`Repo: ${colors.cyan}${repoInfo.owner}/${repoInfo.repo}${colors.reset}\n`);
|
|
45
|
+
// Issue Title
|
|
46
|
+
if (process.stdin.isTTY) {
|
|
47
|
+
process.stdin.setRawMode(false);
|
|
48
|
+
}
|
|
49
|
+
const title = askQuestion('Issue title: ').trim();
|
|
50
|
+
if (!title) {
|
|
51
|
+
log.error('Title is required.');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Issue Body
|
|
55
|
+
console.log('');
|
|
56
|
+
const bodyChoice = await select('Issue description:', [
|
|
57
|
+
{ label: 'Write description', value: 'write' },
|
|
58
|
+
{ label: 'Use template (Bug Report)', value: 'bug' },
|
|
59
|
+
{ label: 'Use template (Feature Request)', value: 'feature' },
|
|
60
|
+
{ label: 'Empty (no description)', value: 'empty' },
|
|
61
|
+
]);
|
|
62
|
+
let body = '';
|
|
63
|
+
switch (bodyChoice) {
|
|
64
|
+
case 'write': {
|
|
65
|
+
if (process.stdin.isTTY) {
|
|
66
|
+
process.stdin.setRawMode(false);
|
|
67
|
+
}
|
|
68
|
+
body = askQuestion('Description: ').trim();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case 'bug': {
|
|
72
|
+
body = [
|
|
73
|
+
'## Bug Report',
|
|
74
|
+
'',
|
|
75
|
+
'### Description',
|
|
76
|
+
'A clear description of what the bug is.',
|
|
77
|
+
'',
|
|
78
|
+
'### Steps to Reproduce',
|
|
79
|
+
'1. ',
|
|
80
|
+
'2. ',
|
|
81
|
+
'3. ',
|
|
82
|
+
'',
|
|
83
|
+
'### Expected Behavior',
|
|
84
|
+
'',
|
|
85
|
+
'',
|
|
86
|
+
'### Actual Behavior',
|
|
87
|
+
'',
|
|
88
|
+
'',
|
|
89
|
+
'### Environment',
|
|
90
|
+
`- OS: ${process.platform}`,
|
|
91
|
+
`- Node: ${process.version}`,
|
|
92
|
+
].join('\n');
|
|
93
|
+
log.info('Bug report template applied. Edit in GitHub after creation.');
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case 'feature': {
|
|
97
|
+
body = [
|
|
98
|
+
'## Feature Request',
|
|
99
|
+
'',
|
|
100
|
+
'### Description',
|
|
101
|
+
'A clear description of the feature you want.',
|
|
102
|
+
'',
|
|
103
|
+
'### Motivation',
|
|
104
|
+
'Why is this feature needed?',
|
|
105
|
+
'',
|
|
106
|
+
'### Proposed Solution',
|
|
107
|
+
'',
|
|
108
|
+
'',
|
|
109
|
+
'### Alternatives Considered',
|
|
110
|
+
'',
|
|
111
|
+
].join('\n');
|
|
112
|
+
log.info('Feature request template applied. Edit in GitHub after creation.');
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
default: {
|
|
116
|
+
body = '';
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Labels
|
|
121
|
+
console.log('');
|
|
122
|
+
const spinner = log.spinner();
|
|
123
|
+
spinner.start('Fetching labels...');
|
|
124
|
+
const labels = await listLabels(repoInfo.owner, repoInfo.repo);
|
|
125
|
+
spinner.stop();
|
|
126
|
+
let selectedLabels = [];
|
|
127
|
+
if (labels.length > 0) {
|
|
128
|
+
const labelOptions = labels.map((l) => ({
|
|
129
|
+
label: `${l.name}${l.description ? ` ${colors.gray}— ${l.description}${colors.reset}` : ''}`,
|
|
130
|
+
value: l.name,
|
|
131
|
+
}));
|
|
132
|
+
selectedLabels = await multiSelect('Add labels (optional):', labelOptions);
|
|
133
|
+
}
|
|
134
|
+
// Assignees
|
|
135
|
+
console.log('');
|
|
136
|
+
const assignChoice = await select('Assign to:', [
|
|
137
|
+
{ label: 'No one', value: 'none' },
|
|
138
|
+
{ label: 'Me (repo owner)', value: 'me' },
|
|
139
|
+
{ label: 'Custom username', value: 'custom' },
|
|
140
|
+
]);
|
|
141
|
+
let assignees = [];
|
|
142
|
+
switch (assignChoice) {
|
|
143
|
+
case 'me': {
|
|
144
|
+
assignees = [repoInfo.owner];
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case 'custom': {
|
|
148
|
+
if (process.stdin.isTTY) {
|
|
149
|
+
process.stdin.setRawMode(false);
|
|
150
|
+
}
|
|
151
|
+
const username = askQuestion('GitHub username: ').trim();
|
|
152
|
+
if (username)
|
|
153
|
+
assignees = [username];
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
default: {
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Summary
|
|
161
|
+
console.log('');
|
|
162
|
+
console.log(`${colors.cyan}┌──────────────────────────────────────────────┐${colors.reset}`);
|
|
163
|
+
console.log(`${colors.cyan}│${colors.reset} ${colors.bright}Issue Summary${colors.reset}`);
|
|
164
|
+
console.log(`${colors.cyan}├──────────────────────────────────────────────┤${colors.reset}`);
|
|
165
|
+
console.log(`${colors.cyan}│${colors.reset} Title: ${colors.bright}${title}${colors.reset}`);
|
|
166
|
+
if (body) {
|
|
167
|
+
const bodyPreview = body.length > 50 ? body.slice(0, 50) + '...' : body;
|
|
168
|
+
const cleanPreview = bodyPreview.replaceAll('\n', ' ');
|
|
169
|
+
console.log(`${colors.cyan}│${colors.reset} Body: ${colors.gray}${cleanPreview}${colors.reset}`);
|
|
170
|
+
}
|
|
171
|
+
if (selectedLabels.length > 0) {
|
|
172
|
+
console.log(`${colors.cyan}│${colors.reset} Labels: ${colors.yellow}${selectedLabels.join(', ')}${colors.reset}`);
|
|
173
|
+
}
|
|
174
|
+
if (assignees.length > 0) {
|
|
175
|
+
console.log(`${colors.cyan}│${colors.reset} Assignee: ${colors.green}${assignees.join(', ')}${colors.reset}`);
|
|
176
|
+
}
|
|
177
|
+
console.log(`${colors.cyan}└──────────────────────────────────────────────┘${colors.reset}`);
|
|
178
|
+
console.log('');
|
|
179
|
+
const proceed = confirm('Create this issue?');
|
|
180
|
+
if (!proceed) {
|
|
181
|
+
log.info('Cancelled.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
console.log('');
|
|
185
|
+
// Create Issue
|
|
186
|
+
const issueSpinner = log.spinner();
|
|
187
|
+
issueSpinner.start('Creating issue...');
|
|
188
|
+
const issue = await createIssue({
|
|
189
|
+
owner: repoInfo.owner,
|
|
190
|
+
repo: repoInfo.repo,
|
|
191
|
+
title,
|
|
192
|
+
body,
|
|
193
|
+
labels: selectedLabels,
|
|
194
|
+
assignees,
|
|
195
|
+
});
|
|
196
|
+
if (issue) {
|
|
197
|
+
issueSpinner.succeed('Issue created!');
|
|
198
|
+
console.log('');
|
|
199
|
+
console.log(` ${colors.green}#${issue.number}${colors.reset} ${issue.title}`);
|
|
200
|
+
console.log(` ${colors.cyan}${issue.html_url}${colors.reset}`);
|
|
201
|
+
// OSC 8 clickable link
|
|
202
|
+
console.log('');
|
|
203
|
+
console.log(` \u001B]8;;${issue.html_url}\u0007` +
|
|
204
|
+
`${colors.cyan}Open in browser →${colors.reset}` +
|
|
205
|
+
`\u001B]8;;\u0007`);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
issueSpinner.fail('Failed to create issue');
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
//# sourceMappingURL=issue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../src/workflows/issue.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main-steps.d.ts","sourceRoot":"","sources":["../../src/workflows/main-steps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"main-steps.d.ts","sourceRoot":"","sources":["../../src/workflows/main-steps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AA+CnD,wBAAsB,UAAU,CAC9B,KAAK,EAAE,UAAU,EACjB,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACzE,OAAO,CAAC,IAAI,CAAC,CA6Hf;AAED,wBAAsB,WAAW,CAC/B,KAAK,EAAE,UAAU,EACjB,IAAI,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACxD,OAAO,CAAC,MAAM,CAAC,CAoOjB;AAED,wBAAsB,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA6F3F"}
|
|
@@ -2,15 +2,41 @@ import { handleCommitWorkflow } from './commit.js';
|
|
|
2
2
|
import { confirm, ProgressBar } from '../cli/input.js';
|
|
3
3
|
import { select } from '../cli/menu.js';
|
|
4
4
|
import { STEP } from '../core/constants.js';
|
|
5
|
+
import { colors } from '../utils/colors.js';
|
|
6
|
+
import { getStepProgress } from '../utils/display.js';
|
|
5
7
|
import { exec, execAsync } from '../utils/exec.js';
|
|
6
8
|
import { safeCheckout, safeMerge } from '../utils/git-errors.js';
|
|
7
9
|
import { getCurrentBranch, pushWithRetry } from '../utils/git.js';
|
|
8
10
|
import { log } from '../utils/logging.js';
|
|
9
11
|
import { saveState } from '../utils/state.js';
|
|
12
|
+
/** Extract a user-friendly message from a push error. */
|
|
13
|
+
function describePushError(error) {
|
|
14
|
+
const stderr = error?.stderr ?? error?.message ?? String(error);
|
|
15
|
+
const lower = stderr.toLowerCase();
|
|
16
|
+
if (lower.includes('non-fast-forward') ||
|
|
17
|
+
lower.includes('tip of your current branch is behind')) {
|
|
18
|
+
return ('Your local branch is behind the remote. Run `git pull` (or `git pull --rebase`)' +
|
|
19
|
+
' to integrate remote changes, then try again.');
|
|
20
|
+
}
|
|
21
|
+
if (lower.includes('permission denied') || lower.includes('403')) {
|
|
22
|
+
return 'Permission denied. Check that you have write access to this repository.';
|
|
23
|
+
}
|
|
24
|
+
if (lower.includes('authentication failed') ||
|
|
25
|
+
lower.includes('http basic: access denied') ||
|
|
26
|
+
lower.includes('could not read from remote')) {
|
|
27
|
+
return 'Authentication failed. Verify your SSH key, credential helper, or personal access token.';
|
|
28
|
+
}
|
|
29
|
+
if (lower.includes('does not appear to be a git repository')) {
|
|
30
|
+
return "Remote 'origin' is not configured. Add a remote with `git remote add origin <url>`.";
|
|
31
|
+
}
|
|
32
|
+
// Fallback: show first meaningful line of stderr
|
|
33
|
+
const firstLine = stderr.split('\n').find((l) => l.trim() && !l.startsWith('hint:'));
|
|
34
|
+
return firstLine?.trim() ?? 'Push failed. Run `git push` manually for details.';
|
|
35
|
+
}
|
|
10
36
|
export async function handlePush(state, opts) {
|
|
11
37
|
if (state.step < STEP.PUSHED || opts?.force) {
|
|
12
38
|
if (!opts?.suppressStep) {
|
|
13
|
-
log.step(
|
|
39
|
+
log.step(`Step 4: Push to Remote ${getStepProgress(4)}`);
|
|
14
40
|
}
|
|
15
41
|
let shouldPush;
|
|
16
42
|
if (opts?.suppressLogs) {
|
|
@@ -60,7 +86,7 @@ export async function handlePush(state, opts) {
|
|
|
60
86
|
catch (error) {
|
|
61
87
|
progressBar.complete();
|
|
62
88
|
console.log('');
|
|
63
|
-
log.error(
|
|
89
|
+
log.error(describePushError(error));
|
|
64
90
|
throw error;
|
|
65
91
|
}
|
|
66
92
|
}
|
|
@@ -103,7 +129,7 @@ export async function handlePush(state, opts) {
|
|
|
103
129
|
catch (error) {
|
|
104
130
|
progressBar.complete();
|
|
105
131
|
console.log('');
|
|
106
|
-
log.error(
|
|
132
|
+
log.error(describePushError(error));
|
|
107
133
|
throw error;
|
|
108
134
|
}
|
|
109
135
|
}
|
|
@@ -122,7 +148,7 @@ export async function handleMerge(state, opts) {
|
|
|
122
148
|
// Return the feature branch name used for later cleanup
|
|
123
149
|
if (state.step < STEP.MERGED) {
|
|
124
150
|
if (!opts?.suppressStep) {
|
|
125
|
-
log.step(
|
|
151
|
+
log.step(`Step 5: Merge to Target ${getStepProgress(5)}`);
|
|
126
152
|
}
|
|
127
153
|
const featureBranch = getCurrentBranch();
|
|
128
154
|
// Gather local branches and offer them as merge targets (exclude current branch)
|
|
@@ -213,7 +239,7 @@ export async function handleMerge(state, opts) {
|
|
|
213
239
|
await safeCheckout(featureBranch);
|
|
214
240
|
return featureBranch;
|
|
215
241
|
}
|
|
216
|
-
log.success(
|
|
242
|
+
log.success(`${colors.cyan}${featureBranch}${colors.reset} → merged into ${colors.cyan}${targetBranch}${colors.reset}`);
|
|
217
243
|
}
|
|
218
244
|
else {
|
|
219
245
|
// Squash commits on feature branch first
|
|
@@ -234,7 +260,7 @@ export async function handleMerge(state, opts) {
|
|
|
234
260
|
await safeCheckout(featureBranch);
|
|
235
261
|
return featureBranch;
|
|
236
262
|
}
|
|
237
|
-
log.success(
|
|
263
|
+
log.success(`${colors.cyan}${featureBranch}${colors.reset} → squashed & merged into ${colors.cyan}${targetBranch}${colors.reset}`);
|
|
238
264
|
}
|
|
239
265
|
console.log('');
|
|
240
266
|
// Push the updated target branch back to remote
|
|
@@ -251,10 +277,10 @@ export async function handleMerge(state, opts) {
|
|
|
251
277
|
/* ignore */
|
|
252
278
|
}
|
|
253
279
|
if (remoteUrl) {
|
|
254
|
-
|
|
280
|
+
// remote URL available for push
|
|
255
281
|
}
|
|
256
282
|
else {
|
|
257
|
-
|
|
283
|
+
// push to default remote
|
|
258
284
|
}
|
|
259
285
|
console.log('');
|
|
260
286
|
const progressBar = new ProgressBar(100, `Pushing ${targetBranch} to remote`);
|
|
@@ -297,7 +323,7 @@ export async function handleMerge(state, opts) {
|
|
|
297
323
|
catch (error) {
|
|
298
324
|
progressBar.complete();
|
|
299
325
|
console.log('');
|
|
300
|
-
log.error(
|
|
326
|
+
log.error(describePushError(error));
|
|
301
327
|
throw error;
|
|
302
328
|
}
|
|
303
329
|
}
|
|
@@ -314,10 +340,10 @@ export async function handleMerge(state, opts) {
|
|
|
314
340
|
}
|
|
315
341
|
export async function handleCleanup(featureBranch, state) {
|
|
316
342
|
if (state.step < STEP.CLEANUP) {
|
|
317
|
-
log.step(
|
|
343
|
+
log.step(`Step 6: Cleanup ${getStepProgress(6)}`);
|
|
318
344
|
if (featureBranch && featureBranch !== state.targetBranch) {
|
|
319
345
|
// Protect canonical branches from accidental deletion
|
|
320
|
-
const protectedBranches = new Set(['main', 'master', 'development', 'develop'
|
|
346
|
+
const protectedBranches = new Set(['main', 'master', 'development', 'develop']);
|
|
321
347
|
if (protectedBranches.has(featureBranch.toLowerCase())) {
|
|
322
348
|
log.info(`Skipping deletion of protected branch '${featureBranch}'`);
|
|
323
349
|
}
|
|
@@ -326,7 +352,7 @@ export async function handleCleanup(featureBranch, state) {
|
|
|
326
352
|
const deleteAnswer = confirm(`Delete branch '${featureBranch}'?`);
|
|
327
353
|
if (deleteAnswer) {
|
|
328
354
|
try {
|
|
329
|
-
exec(`git branch -d ${featureBranch}
|
|
355
|
+
exec(`git branch -d ${featureBranch}`, true);
|
|
330
356
|
log.success(`Local branch '${featureBranch}' deleted`);
|
|
331
357
|
// Also delete remote branch if it exists
|
|
332
358
|
try {
|
|
@@ -363,7 +389,7 @@ export async function handleCleanup(featureBranch, state) {
|
|
|
363
389
|
]);
|
|
364
390
|
if (forceDeleteChoice === 'force') {
|
|
365
391
|
try {
|
|
366
|
-
exec(`git branch -D ${featureBranch}
|
|
392
|
+
exec(`git branch -D ${featureBranch}`, true);
|
|
367
393
|
log.success(`Local branch '${featureBranch}' deleted`);
|
|
368
394
|
// Also delete remote branch if it exists
|
|
369
395
|
try {
|