gitpadi 2.0.5 → 2.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.
- package/dist/cli.js +51 -32
- package/dist/commands/repos.js +17 -3
- package/package.json +1 -1
- package/src/cli.ts +54 -33
- package/src/commands/repos.ts +17 -4
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import { execSync } from 'child_process';
|
|
|
12
12
|
import boxen from 'boxen';
|
|
13
13
|
import { createSpinner } from 'nanospinner';
|
|
14
14
|
import { Octokit } from '@octokit/rest';
|
|
15
|
-
import { initGitHub, setRepo, getOwner, getRepo, getOctokit, saveConfig, getToken } from './core/github.js';
|
|
15
|
+
import { initGitHub, setRepo, getOwner, getRepo, getOctokit, saveConfig, getToken, getAuthenticatedUser } from './core/github.js';
|
|
16
16
|
import * as issues from './commands/issues.js';
|
|
17
17
|
import * as prs from './commands/prs.js';
|
|
18
18
|
import * as repos from './commands/repos.js';
|
|
@@ -157,35 +157,63 @@ async function ensureAuthenticated() {
|
|
|
157
157
|
/**
|
|
158
158
|
* Ensures we have a target repository (Owner/Repo)
|
|
159
159
|
*/
|
|
160
|
-
async function ensureTargetRepo() {
|
|
160
|
+
async function ensureTargetRepo(force = false) {
|
|
161
161
|
let owner = getOwner();
|
|
162
162
|
let repo = getRepo();
|
|
163
|
-
if (owner && repo) {
|
|
163
|
+
if (!force && owner && repo) {
|
|
164
164
|
return;
|
|
165
165
|
}
|
|
166
166
|
console.log(neon('\n 📦 Project Targeting — which repo are we working on?\n'));
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
// 1. Get the Owner/Org
|
|
168
|
+
const { targetOwner } = await inquirer.prompt([{
|
|
169
169
|
type: 'input',
|
|
170
|
-
name: '
|
|
170
|
+
name: 'targetOwner',
|
|
171
171
|
message: cyan('👤 GitHub Owner/Org:'),
|
|
172
|
-
default: owner ||
|
|
172
|
+
default: owner || await getAuthenticatedUser(),
|
|
173
173
|
validate: (v) => v.length > 0 || 'Required',
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
174
|
+
}]);
|
|
175
|
+
// 2. Fetch Repos for that Owner
|
|
176
|
+
const spin = createSpinner(dim(`Fetching repositories for ${targetOwner}...`)).start();
|
|
177
|
+
const fetchedRepos = await repos.listRepos({ owner: targetOwner, silent: true });
|
|
178
|
+
if (fetchedRepos.length > 0) {
|
|
179
|
+
spin.success({ text: green(`Found ${fetchedRepos.length} repositories for ${targetOwner}`) });
|
|
180
|
+
const { selectedRepo } = await inquirer.prompt([{
|
|
181
|
+
type: 'list',
|
|
182
|
+
name: 'selectedRepo',
|
|
183
|
+
message: cyan('📦 Select Repository:'),
|
|
184
|
+
choices: [
|
|
185
|
+
...fetchedRepos.map((r) => ({ name: r.name, value: r.name })),
|
|
186
|
+
new inquirer.Separator(),
|
|
187
|
+
{ name: '✍️ Enter manually...', value: '__manual__' }
|
|
188
|
+
],
|
|
189
|
+
loop: false
|
|
190
|
+
}]);
|
|
191
|
+
if (selectedRepo !== '__manual__') {
|
|
192
|
+
repo = selectedRepo;
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
const { manualRepo } = await inquirer.prompt([{
|
|
196
|
+
type: 'input',
|
|
197
|
+
name: 'manualRepo',
|
|
198
|
+
message: cyan('📦 Repository name:'),
|
|
199
|
+
validate: (v) => v.length > 0 || 'Required',
|
|
200
|
+
}]);
|
|
201
|
+
repo = manualRepo;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
spin.warn({ text: yellow(`No public repositories found for ${targetOwner}.`) });
|
|
206
|
+
const { manualRepo } = await inquirer.prompt([{
|
|
207
|
+
type: 'input',
|
|
208
|
+
name: 'manualRepo',
|
|
209
|
+
message: cyan('📦 Enter Repository name manually:'),
|
|
210
|
+
validate: (v) => v.length > 0 || 'Required',
|
|
211
|
+
}]);
|
|
212
|
+
repo = manualRepo;
|
|
213
|
+
}
|
|
214
|
+
setRepo(targetOwner, repo);
|
|
215
|
+
saveConfig({ token: getToken(), owner: targetOwner, repo: repo });
|
|
216
|
+
console.log(green(`\n ✅ Locked in → ${cyan(`${targetOwner}/${repo}`)}\n`));
|
|
189
217
|
}
|
|
190
218
|
// ── Mode Selector ──────────────────────────────────────────────────────
|
|
191
219
|
async function mainMenu() {
|
|
@@ -333,16 +361,7 @@ async function maintainerMenu() {
|
|
|
333
361
|
if (category === 'back')
|
|
334
362
|
break;
|
|
335
363
|
if (category === 'switch') {
|
|
336
|
-
await
|
|
337
|
-
const a = await inquirer.prompt([
|
|
338
|
-
{ type: 'input', name: 'owner', message: cyan('👤 New Owner/Org:'), default: getOwner() },
|
|
339
|
-
{ type: 'input', name: 'repo', message: cyan('📦 New Repo:'), default: getRepo() },
|
|
340
|
-
]);
|
|
341
|
-
setRepo(a.owner, a.repo);
|
|
342
|
-
const s = createSpinner(dim('Switching...')).start();
|
|
343
|
-
await sleep(400);
|
|
344
|
-
s.success({ text: green(`Now targeting ${cyan(`${a.owner}/${a.repo}`)}`) });
|
|
345
|
-
});
|
|
364
|
+
await ensureTargetRepo(true);
|
|
346
365
|
continue;
|
|
347
366
|
}
|
|
348
367
|
if (category === 'issues')
|
package/dist/commands/repos.js
CHANGED
|
@@ -91,9 +91,23 @@ export async function listRepos(opts) {
|
|
|
91
91
|
const spinner = !opts.silent ? ora('Fetching repos...').start() : null;
|
|
92
92
|
const octokit = getOctokit();
|
|
93
93
|
try {
|
|
94
|
-
let repos;
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
let repos = [];
|
|
95
|
+
const owner = opts.org || opts.owner;
|
|
96
|
+
if (owner) {
|
|
97
|
+
// Check if it's an org or user
|
|
98
|
+
try {
|
|
99
|
+
const { data: entity } = await octokit.users.getByUsername({ username: owner });
|
|
100
|
+
if (entity.type === 'Organization') {
|
|
101
|
+
({ data: repos } = await octokit.repos.listForOrg({ org: owner, per_page: opts.limit || 100, sort: 'updated' }));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
({ data: repos } = await octokit.repos.listForUser({ username: owner, per_page: opts.limit || 100, sort: 'updated' }));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Fallback to org if lookup fails (might be a private org only visible to token)
|
|
109
|
+
({ data: repos } = await octokit.repos.listForOrg({ org: owner, per_page: opts.limit || 100, sort: 'updated' }));
|
|
110
|
+
}
|
|
97
111
|
}
|
|
98
112
|
else {
|
|
99
113
|
({ data: repos } = await octokit.repos.listForAuthenticatedUser({ per_page: opts.limit || 100, sort: 'updated' }));
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { execSync } from 'child_process';
|
|
|
15
15
|
import boxen from 'boxen';
|
|
16
16
|
import { createSpinner } from 'nanospinner';
|
|
17
17
|
import { Octokit } from '@octokit/rest';
|
|
18
|
-
import { initGitHub, setRepo, getOwner, getRepo, getOctokit, loadConfig, saveConfig, getToken } from './core/github.js';
|
|
18
|
+
import { initGitHub, setRepo, getOwner, getRepo, getOctokit, loadConfig, saveConfig, getToken, getAuthenticatedUser } from './core/github.js';
|
|
19
19
|
|
|
20
20
|
import * as issues from './commands/issues.js';
|
|
21
21
|
import * as prs from './commands/prs.js';
|
|
@@ -178,40 +178,70 @@ async function ensureAuthenticated() {
|
|
|
178
178
|
/**
|
|
179
179
|
* Ensures we have a target repository (Owner/Repo)
|
|
180
180
|
*/
|
|
181
|
-
async function ensureTargetRepo() {
|
|
181
|
+
async function ensureTargetRepo(force = false) {
|
|
182
182
|
let owner = getOwner();
|
|
183
183
|
let repo = getRepo();
|
|
184
184
|
|
|
185
|
-
if (owner && repo) {
|
|
185
|
+
if (!force && owner && repo) {
|
|
186
186
|
return;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
console.log(neon('\n 📦 Project Targeting — which repo are we working on?\n'));
|
|
190
190
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
191
|
+
// 1. Get the Owner/Org
|
|
192
|
+
const { targetOwner } = await inquirer.prompt([{
|
|
193
|
+
type: 'input',
|
|
194
|
+
name: 'targetOwner',
|
|
195
|
+
message: cyan('👤 GitHub Owner/Org:'),
|
|
196
|
+
default: owner || await getAuthenticatedUser(),
|
|
197
|
+
validate: (v: string) => v.length > 0 || 'Required',
|
|
198
|
+
}]);
|
|
199
|
+
|
|
200
|
+
// 2. Fetch Repos for that Owner
|
|
201
|
+
const spin = createSpinner(dim(`Fetching repositories for ${targetOwner}...`)).start();
|
|
202
|
+
const fetchedRepos = await repos.listRepos({ owner: targetOwner, silent: true });
|
|
203
|
+
|
|
204
|
+
if (fetchedRepos.length > 0) {
|
|
205
|
+
spin.success({ text: green(`Found ${fetchedRepos.length} repositories for ${targetOwner}`) });
|
|
206
|
+
|
|
207
|
+
const { selectedRepo } = await inquirer.prompt([{
|
|
208
|
+
type: 'list',
|
|
209
|
+
name: 'selectedRepo',
|
|
210
|
+
message: cyan('📦 Select Repository:'),
|
|
211
|
+
choices: [
|
|
212
|
+
...fetchedRepos.map((r: any) => ({ name: r.name, value: r.name })),
|
|
213
|
+
new inquirer.Separator(),
|
|
214
|
+
{ name: '✍️ Enter manually...', value: '__manual__' }
|
|
215
|
+
],
|
|
216
|
+
loop: false
|
|
217
|
+
}]);
|
|
218
|
+
|
|
219
|
+
if (selectedRepo !== '__manual__') {
|
|
220
|
+
repo = selectedRepo;
|
|
221
|
+
} else {
|
|
222
|
+
const { manualRepo } = await inquirer.prompt([{
|
|
223
|
+
type: 'input',
|
|
224
|
+
name: 'manualRepo',
|
|
225
|
+
message: cyan('📦 Repository name:'),
|
|
226
|
+
validate: (v: string) => v.length > 0 || 'Required',
|
|
227
|
+
}]);
|
|
228
|
+
repo = manualRepo;
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
spin.warn({ text: yellow(`No public repositories found for ${targetOwner}.`) });
|
|
232
|
+
const { manualRepo } = await inquirer.prompt([{
|
|
200
233
|
type: 'input',
|
|
201
|
-
name: '
|
|
202
|
-
message: cyan('📦 Repository name:'),
|
|
203
|
-
default: repo || '',
|
|
234
|
+
name: 'manualRepo',
|
|
235
|
+
message: cyan('📦 Enter Repository name manually:'),
|
|
204
236
|
validate: (v: string) => v.length > 0 || 'Required',
|
|
205
|
-
}
|
|
206
|
-
|
|
237
|
+
}]);
|
|
238
|
+
repo = manualRepo;
|
|
239
|
+
}
|
|
207
240
|
|
|
208
|
-
setRepo(
|
|
209
|
-
saveConfig({ token: getToken(), owner:
|
|
241
|
+
setRepo(targetOwner, repo as string);
|
|
242
|
+
saveConfig({ token: getToken(), owner: targetOwner, repo: repo as string });
|
|
210
243
|
|
|
211
|
-
|
|
212
|
-
await sleep(400);
|
|
213
|
-
spinner.success({ text: green(`Locked in → ${cyan(`${answers.owner}/${answers.repo}`)}`) });
|
|
214
|
-
console.log('');
|
|
244
|
+
console.log(green(`\n ✅ Locked in → ${cyan(`${targetOwner}/${repo}`)}\n`));
|
|
215
245
|
}
|
|
216
246
|
|
|
217
247
|
// ── Mode Selector ──────────────────────────────────────────────────────
|
|
@@ -365,16 +395,7 @@ async function maintainerMenu() {
|
|
|
365
395
|
if (category === 'back') break;
|
|
366
396
|
|
|
367
397
|
if (category === 'switch') {
|
|
368
|
-
await
|
|
369
|
-
const a = await inquirer.prompt([
|
|
370
|
-
{ type: 'input', name: 'owner', message: cyan('👤 New Owner/Org:'), default: getOwner() },
|
|
371
|
-
{ type: 'input', name: 'repo', message: cyan('📦 New Repo:'), default: getRepo() },
|
|
372
|
-
]);
|
|
373
|
-
setRepo(a.owner, a.repo);
|
|
374
|
-
const s = createSpinner(dim('Switching...')).start();
|
|
375
|
-
await sleep(400);
|
|
376
|
-
s.success({ text: green(`Now targeting ${cyan(`${a.owner}/${a.repo}`)}`) });
|
|
377
|
-
});
|
|
398
|
+
await ensureTargetRepo(true);
|
|
378
399
|
continue;
|
|
379
400
|
}
|
|
380
401
|
|
package/src/commands/repos.ts
CHANGED
|
@@ -101,14 +101,27 @@ export async function setTopics(name: string, topics: string[], opts: { org?: st
|
|
|
101
101
|
} catch (e: any) { spinner.fail(e.message); }
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
export async function listRepos(opts: { org?: string; limit?: number; silent?: boolean }) {
|
|
104
|
+
export async function listRepos(opts: { org?: string; owner?: string; limit?: number; silent?: boolean }) {
|
|
105
105
|
const spinner = !opts.silent ? ora('Fetching repos...').start() : null;
|
|
106
106
|
const octokit = getOctokit();
|
|
107
107
|
|
|
108
108
|
try {
|
|
109
|
-
let repos: any[];
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
let repos: any[] = [];
|
|
110
|
+
const owner = opts.org || opts.owner;
|
|
111
|
+
|
|
112
|
+
if (owner) {
|
|
113
|
+
// Check if it's an org or user
|
|
114
|
+
try {
|
|
115
|
+
const { data: entity } = await octokit.users.getByUsername({ username: owner });
|
|
116
|
+
if (entity.type === 'Organization') {
|
|
117
|
+
({ data: repos } = await octokit.repos.listForOrg({ org: owner, per_page: opts.limit || 100, sort: 'updated' }));
|
|
118
|
+
} else {
|
|
119
|
+
({ data: repos } = await octokit.repos.listForUser({ username: owner, per_page: opts.limit || 100, sort: 'updated' }));
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
// Fallback to org if lookup fails (might be a private org only visible to token)
|
|
123
|
+
({ data: repos } = await octokit.repos.listForOrg({ org: owner, per_page: opts.limit || 100, sort: 'updated' }));
|
|
124
|
+
}
|
|
112
125
|
} else {
|
|
113
126
|
({ data: repos } = await octokit.repos.listForAuthenticatedUser({ per_page: opts.limit || 100, sort: 'updated' }));
|
|
114
127
|
}
|