gitpadi 2.0.6 → 2.0.7

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 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, getAuthenticatedUser } from './core/github.js';
15
+ import { initGitHub, setRepo, getOwner, getRepo, getOctokit, saveConfig, getToken, getAuthenticatedUser, getRepoPermissions } 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';
@@ -20,6 +20,7 @@ import * as contributors from './commands/contributors.js';
20
20
  import * as releases from './commands/releases.js';
21
21
  import * as contribute from './commands/contribute.js';
22
22
  const VERSION = '2.0.0';
23
+ let targetConfirmed = false;
23
24
  // ── Styling ────────────────────────────────────────────────────────────
24
25
  const cyber = gradient(['#ff00ff', '#00ffff', '#ff00ff']);
25
26
  const neon = gradient(['#00ff87', '#60efff']);
@@ -161,7 +162,18 @@ async function ensureTargetRepo(force = false) {
161
162
  let owner = getOwner();
162
163
  let repo = getRepo();
163
164
  if (!force && owner && repo) {
164
- return;
165
+ if (targetConfirmed)
166
+ return;
167
+ const { confirm } = await inquirer.prompt([{
168
+ type: 'confirm',
169
+ name: 'confirm',
170
+ message: cyan('🎯 Targeting ') + bold(`${owner}/${repo}`) + cyan('. Correct?'),
171
+ default: true
172
+ }]);
173
+ if (confirm) {
174
+ targetConfirmed = true;
175
+ return;
176
+ }
165
177
  }
166
178
  console.log(neon('\n 📦 Project Targeting — which repo are we working on?\n'));
167
179
  // 1. Get the Owner/Org
@@ -213,6 +225,34 @@ async function ensureTargetRepo(force = false) {
213
225
  }
214
226
  setRepo(targetOwner, repo);
215
227
  saveConfig({ token: getToken(), owner: targetOwner, repo: repo });
228
+ targetConfirmed = true;
229
+ // 4. Permission Check (for Maintainer safety)
230
+ const checkSpin = createSpinner(dim('Checking maintainer permissions...')).start();
231
+ try {
232
+ const perms = await getRepoPermissions(targetOwner, repo);
233
+ if (!perms.push && !perms.admin) {
234
+ checkSpin.warn({ text: yellow(`Limited Access → ${cyan(`${targetOwner}/${repo}`)}`) });
235
+ console.log(boxen(chalk.yellow(`🛡️ Maintainer Mode Warning\n\n`) +
236
+ chalk.dim(`You do not have push/admin permissions for this repository.\n`) +
237
+ chalk.dim(`Most maintainer actions (bulk issues, merging PRs) will fail.`), { padding: 1, borderColor: 'yellow', borderStyle: 'round' }));
238
+ const { proceed } = await inquirer.prompt([{
239
+ type: 'confirm',
240
+ name: 'proceed',
241
+ message: 'Continue anyway?',
242
+ default: false
243
+ }]);
244
+ if (!proceed) {
245
+ targetConfirmed = false;
246
+ throw new BackToMenu();
247
+ }
248
+ }
249
+ else {
250
+ checkSpin.success({ text: green(`Permissions verified for ${cyan(`${targetOwner}/${repo}`)}`) });
251
+ }
252
+ }
253
+ catch {
254
+ checkSpin.warn({ text: yellow('Could not verify permissions (API limit or private)') });
255
+ }
216
256
  console.log(green(`\n ✅ Locked in → ${cyan(`${targetOwner}/${repo}`)}\n`));
217
257
  }
218
258
  // ── Mode Selector ──────────────────────────────────────────────────────
@@ -94,6 +94,10 @@ export async function getRepoDetails(owner, repo) {
94
94
  const { data } = await getOctokit().repos.get({ owner, repo });
95
95
  return data;
96
96
  }
97
+ export async function getRepoPermissions(owner, repo) {
98
+ const data = await getRepoDetails(owner, repo);
99
+ return data.permissions || { admin: false, push: false, pull: true };
100
+ }
97
101
  export async function getLatestCheckRuns(owner, repo, ref) {
98
102
  const octokit = getOctokit();
99
103
  const { data: checks } = await octokit.checks.listForRef({ owner, repo, ref });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitpadi",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "GitPadi — Your AI-powered GitHub management CLI. Create repos, manage issues & PRs, score contributors, and automate everything.",
5
5
  "type": "module",
6
6
  "bin": {
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, getAuthenticatedUser } from './core/github.js';
18
+ import { initGitHub, setRepo, getOwner, getRepo, getOctokit, loadConfig, saveConfig, getToken, getAuthenticatedUser, getRepoPermissions } from './core/github.js';
19
19
 
20
20
  import * as issues from './commands/issues.js';
21
21
  import * as prs from './commands/prs.js';
@@ -25,6 +25,7 @@ import * as releases from './commands/releases.js';
25
25
  import * as contribute from './commands/contribute.js';
26
26
 
27
27
  const VERSION = '2.0.0';
28
+ let targetConfirmed = false;
28
29
 
29
30
  // ── Styling ────────────────────────────────────────────────────────────
30
31
  const cyber = gradient(['#ff00ff', '#00ffff', '#ff00ff']);
@@ -183,7 +184,18 @@ async function ensureTargetRepo(force = false) {
183
184
  let repo = getRepo();
184
185
 
185
186
  if (!force && owner && repo) {
186
- return;
187
+ if (targetConfirmed) return;
188
+
189
+ const { confirm } = await inquirer.prompt([{
190
+ type: 'confirm',
191
+ name: 'confirm',
192
+ message: cyan('🎯 Targeting ') + bold(`${owner}/${repo}`) + cyan('. Correct?'),
193
+ default: true
194
+ }]);
195
+ if (confirm) {
196
+ targetConfirmed = true;
197
+ return;
198
+ }
187
199
  }
188
200
 
189
201
  console.log(neon('\n 📦 Project Targeting — which repo are we working on?\n'));
@@ -240,6 +252,38 @@ async function ensureTargetRepo(force = false) {
240
252
 
241
253
  setRepo(targetOwner, repo as string);
242
254
  saveConfig({ token: getToken(), owner: targetOwner, repo: repo as string });
255
+ targetConfirmed = true;
256
+
257
+ // 4. Permission Check (for Maintainer safety)
258
+ const checkSpin = createSpinner(dim('Checking maintainer permissions...')).start();
259
+ try {
260
+ const perms = await getRepoPermissions(targetOwner, repo as string);
261
+ if (!perms.push && !perms.admin) {
262
+ checkSpin.warn({ text: yellow(`Limited Access → ${cyan(`${targetOwner}/${repo}`)}`) });
263
+ console.log(boxen(
264
+ chalk.yellow(`🛡️ Maintainer Mode Warning\n\n`) +
265
+ chalk.dim(`You do not have push/admin permissions for this repository.\n`) +
266
+ chalk.dim(`Most maintainer actions (bulk issues, merging PRs) will fail.`),
267
+ { padding: 1, borderColor: 'yellow', borderStyle: 'round' }
268
+ ));
269
+
270
+ const { proceed } = await inquirer.prompt([{
271
+ type: 'confirm',
272
+ name: 'proceed',
273
+ message: 'Continue anyway?',
274
+ default: false
275
+ }]);
276
+
277
+ if (!proceed) {
278
+ targetConfirmed = false;
279
+ throw new BackToMenu();
280
+ }
281
+ } else {
282
+ checkSpin.success({ text: green(`Permissions verified for ${cyan(`${targetOwner}/${repo}`)}`) });
283
+ }
284
+ } catch {
285
+ checkSpin.warn({ text: yellow('Could not verify permissions (API limit or private)') });
286
+ }
243
287
 
244
288
  console.log(green(`\n ✅ Locked in → ${cyan(`${targetOwner}/${repo}`)}\n`));
245
289
  }
@@ -114,6 +114,11 @@ export async function getRepoDetails(owner: string, repo: string) {
114
114
  return data;
115
115
  }
116
116
 
117
+ export async function getRepoPermissions(owner: string, repo: string) {
118
+ const data = await getRepoDetails(owner, repo);
119
+ return data.permissions || { admin: false, push: false, pull: true };
120
+ }
121
+
117
122
  export async function getLatestCheckRuns(owner: string, repo: string, ref: string) {
118
123
  const octokit = getOctokit();
119
124
  const { data: checks } = await octokit.checks.listForRef({ owner, repo, ref });