gitpadi 2.0.0 → 2.0.2

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.
@@ -1,36 +1,88 @@
1
- // core/github.ts — Shared Octokit client + auth for GitPadi
2
-
3
1
  import { Octokit } from '@octokit/rest';
4
2
  import chalk from 'chalk';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import os from 'node:os';
6
+ import { execSync } from 'child_process';
7
+
8
+
9
+ const CONFIG_DIR = path.join(os.homedir(), '.gitpadi');
10
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
5
11
 
6
12
  let _octokit: Octokit | null = null;
7
13
  let _owner: string = '';
8
14
  let _repo: string = '';
15
+ let _token: string = '';
9
16
 
10
- export function initGitHub(token?: string, owner?: string, repo?: string): void {
11
- const t = token || process.env.GITHUB_TOKEN || process.env.GITPADI_TOKEN || '';
12
- if (!t) {
13
- console.error(chalk.red('\n❌ GitHub token required.'));
14
- console.error(chalk.dim(' Set it: export GITHUB_TOKEN=ghp_xxx'));
15
- console.error(chalk.dim(' Or: export GITPADI_TOKEN=ghp_xxx\n'));
16
- process.exit(1);
17
+ export interface GitPadiConfig {
18
+ token: string;
19
+ owner: string;
20
+ repo: string;
21
+ }
22
+
23
+ export function loadConfig(): GitPadiConfig | null {
24
+ if (!fs.existsSync(CONFIG_FILE)) return null;
25
+ try {
26
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
27
+ } catch {
28
+ return null;
17
29
  }
30
+ }
31
+
32
+ export function saveConfig(config: GitPadiConfig): void {
33
+ if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
34
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
35
+ }
36
+
37
+ /**
38
+ * Attempts to detect owner/repo from local git remotes
39
+ */
40
+ export function detectLocalRepo(): { owner: string, repo: string } | null {
41
+ try {
42
+ const remotes = execSync('git remote -v', { encoding: 'utf-8', stdio: 'pipe' });
43
+ const match = remotes.match(/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?/);
44
+ if (match) {
45
+ return { owner: match[1], repo: match[2] };
46
+ }
47
+ } catch {
48
+ // Not a git repo or git not found
49
+ }
50
+ return null;
51
+ }
52
+
53
+ export function initGitHub(token?: string, owner?: string, repo?: string): void {
54
+ const config = loadConfig();
55
+ const detected = detectLocalRepo();
18
56
 
19
- _octokit = new Octokit({ auth: t });
20
- _owner = owner || process.env.GITHUB_OWNER || process.env.GITHUB_REPOSITORY?.split('/')[0] || '';
21
- _repo = repo || process.env.GITHUB_REPO || process.env.GITHUB_REPOSITORY?.split('/')[1] || '';
57
+ _token = token || process.env.GITHUB_TOKEN || process.env.GITPADI_TOKEN || config?.token || '';
58
+
59
+ // Priority: Explicit > Env > Config > Local Git detection
60
+ _owner = owner || process.env.GITHUB_OWNER || config?.owner || detected?.owner || process.env.GITHUB_REPOSITORY?.split('/')[0] || '';
61
+ _repo = repo || process.env.GITHUB_REPO || config?.repo || detected?.repo || process.env.GITHUB_REPOSITORY?.split('/')[1] || '';
62
+
63
+ if (_token) {
64
+ _octokit = new Octokit({ auth: _token });
65
+ }
22
66
  }
23
67
 
24
68
  export function getOctokit(): Octokit {
25
69
  if (!_octokit) {
26
- initGitHub();
70
+ throw new Error('GitHub client not initialized. Call initGitHub() first.');
27
71
  }
28
- return _octokit!;
72
+ return _octokit;
29
73
  }
30
74
 
31
75
  export function getOwner(): string { return _owner; }
32
76
  export function getRepo(): string { return _repo; }
33
- export function setRepo(owner: string, repo: string): void { _owner = owner; _repo = repo; }
77
+ export function getToken(): string { return _token; }
78
+ export function setRepo(owner: string, repo: string): void {
79
+ _owner = owner;
80
+ _repo = repo;
81
+ // If we have a token, PERSIST the new repo selection
82
+ if (_token) {
83
+ saveConfig({ token: _token, owner, repo });
84
+ }
85
+ }
34
86
  export function getFullRepo(): string { return `${_owner}/${_repo}`; }
35
87
 
36
88
  export function requireRepo(): void {
@@ -41,3 +93,35 @@ export function requireRepo(): void {
41
93
  process.exit(1);
42
94
  }
43
95
  }
96
+
97
+ /**
98
+ * ── Phase 1: Contributor Support Helpers ──
99
+ */
100
+
101
+ export async function getAuthenticatedUser(): Promise<string> {
102
+ const { data } = await getOctokit().users.getAuthenticated();
103
+ return data.login;
104
+ }
105
+
106
+ export async function forkRepo(owner: string, repo: string): Promise<string> {
107
+ const octokit = getOctokit();
108
+ const { data } = await octokit.repos.createFork({ owner, repo });
109
+ return data.full_name; // e.g. "myuser/original-repo"
110
+ }
111
+
112
+ export async function getRepoDetails(owner: string, repo: string) {
113
+ const { data } = await getOctokit().repos.get({ owner, repo });
114
+ return data;
115
+ }
116
+
117
+ export async function getLatestCheckRuns(owner: string, repo: string, ref: string) {
118
+ const octokit = getOctokit();
119
+ const { data: checks } = await octokit.checks.listForRef({ owner, repo, ref });
120
+ const { data: status } = await octokit.repos.getCombinedStatusForRef({ owner, repo, ref });
121
+
122
+ return {
123
+ checkRuns: checks.check_runs,
124
+ combinedState: status.state, // 'success', 'failure', 'pending'
125
+ statuses: status.statuses
126
+ };
127
+ }
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env tsx
1
+ #!/usr/bin/env node
2
2
  // create-issues.ts — Generic issue creator from JSON data file
3
3
  //
4
4
  // Usage via GitHub Action:
package/src/pr-review.ts CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env tsx
1
+ #!/usr/bin/env node
2
2
  // pr-review.ts — Generic PR review agent for any repository
3
3
  //
4
4
  // Checks: linked issues, PR size, file scope, test coverage, commit messages, sensitive files