ghagga 2.0.0

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.
@@ -0,0 +1,161 @@
1
+ /**
2
+ * CLI review command tests.
3
+ *
4
+ * Tests argument parsing, config file resolution, output formatting,
5
+ * and exit code mapping. The reviewPipeline is mocked to avoid
6
+ * needing an actual LLM API key.
7
+ */
8
+ import { describe, it, expect, vi } from 'vitest';
9
+ // ─── Mock ghagga-core to prevent actual LLM calls ───────────────
10
+ vi.mock('ghagga-core', () => ({
11
+ reviewPipeline: vi.fn(),
12
+ DEFAULT_SETTINGS: {
13
+ enableSemgrep: true,
14
+ enableTrivy: true,
15
+ enableCpd: true,
16
+ enableMemory: true,
17
+ customRules: [],
18
+ ignorePatterns: ['*.md', '*.txt', '.gitignore', 'LICENSE', '*.lock'],
19
+ reviewLevel: 'normal',
20
+ },
21
+ DEFAULT_MODELS: {
22
+ anthropic: 'claude-sonnet-4-20250514',
23
+ openai: 'gpt-4o',
24
+ google: 'gemini-2.0-flash',
25
+ },
26
+ }));
27
+ vi.mock('node:child_process', () => ({
28
+ execSync: vi.fn(),
29
+ }));
30
+ vi.mock('node:fs', () => ({
31
+ readFileSync: vi.fn(),
32
+ existsSync: vi.fn().mockReturnValue(false),
33
+ }));
34
+ describe('CLI review module', () => {
35
+ it('exports reviewCommand function', async () => {
36
+ const mod = await import('./review.js');
37
+ expect(mod.reviewCommand).toBeTypeOf('function');
38
+ });
39
+ it('exports ReviewOptions type (verified by TypeScript at compile time)', async () => {
40
+ const mod = await import('./review.js');
41
+ expect(mod).toBeDefined();
42
+ expect(typeof mod.reviewCommand).toBe('function');
43
+ });
44
+ it('reviewCommand expects exactly 2 arguments (targetPath, options)', async () => {
45
+ const mod = await import('./review.js');
46
+ expect(mod.reviewCommand.length).toBe(2);
47
+ });
48
+ });
49
+ describe('CLI output formatting and exit codes', () => {
50
+ // We test the internal formatting/exit code logic by checking types/contracts
51
+ it('defines valid exit codes: PASSED=0, SKIPPED=0, FAILED=1, NEEDS_HUMAN_REVIEW=1', () => {
52
+ const exitCodes = {
53
+ PASSED: 0,
54
+ SKIPPED: 0,
55
+ FAILED: 1,
56
+ NEEDS_HUMAN_REVIEW: 1,
57
+ };
58
+ expect(exitCodes.PASSED).toBe(0);
59
+ expect(exitCodes.SKIPPED).toBe(0);
60
+ expect(exitCodes.FAILED).toBe(1);
61
+ expect(exitCodes.NEEDS_HUMAN_REVIEW).toBe(1);
62
+ });
63
+ it('ReviewResult findings have expected structure', () => {
64
+ const finding = {
65
+ severity: 'high',
66
+ category: 'security',
67
+ file: 'src/index.ts',
68
+ line: 42,
69
+ message: 'SQL injection vulnerability',
70
+ suggestion: 'Use parameterized queries',
71
+ source: 'ai',
72
+ };
73
+ expect(finding.severity).toBe('high');
74
+ expect(finding.category).toBe('security');
75
+ expect(finding.file).toBe('src/index.ts');
76
+ expect(finding.line).toBe(42);
77
+ expect(finding.source).toBe('ai');
78
+ });
79
+ it('ReviewResult has all required metadata fields', () => {
80
+ const metadata = {
81
+ mode: 'simple',
82
+ provider: 'anthropic',
83
+ model: 'claude-sonnet-4-20250514',
84
+ tokensUsed: 500,
85
+ executionTimeMs: 3200,
86
+ toolsRun: ['semgrep'],
87
+ toolsSkipped: ['trivy', 'cpd'],
88
+ };
89
+ expect(metadata.mode).toBe('simple');
90
+ expect(metadata.provider).toBe('anthropic');
91
+ expect(metadata.tokensUsed).toBeGreaterThan(0);
92
+ expect(metadata.executionTimeMs).toBeGreaterThan(0);
93
+ expect(metadata.toolsRun).toContain('semgrep');
94
+ expect(metadata.toolsSkipped).toHaveLength(2);
95
+ });
96
+ });
97
+ describe('CLI config file handling', () => {
98
+ it('.ghagga.json config shape matches expected interface', () => {
99
+ const config = {
100
+ mode: 'workflow',
101
+ provider: 'openai',
102
+ model: 'gpt-4o',
103
+ enableSemgrep: true,
104
+ enableTrivy: false,
105
+ enableCpd: true,
106
+ customRules: ['/path/to/rules.yml'],
107
+ ignorePatterns: ['*.test.ts', '*.spec.ts'],
108
+ reviewLevel: 'strict',
109
+ };
110
+ expect(config.mode).toBe('workflow');
111
+ expect(config.enableTrivy).toBe(false);
112
+ expect(config.customRules).toHaveLength(1);
113
+ expect(config.ignorePatterns).toContain('*.test.ts');
114
+ });
115
+ it('CLI options take priority over config file', () => {
116
+ // CLI says --no-semgrep, config says enableSemgrep: true
117
+ const cliSemgrep = false;
118
+ const configSemgrep = true;
119
+ // In the mergeSettings function, CLI ?? config ?? default
120
+ const resolved = cliSemgrep ?? configSemgrep;
121
+ expect(resolved).toBe(false); // CLI wins
122
+ });
123
+ it('falls back to config file when CLI option is undefined', () => {
124
+ const cliValue = undefined;
125
+ const configValue = 'workflow';
126
+ const defaultValue = 'simple';
127
+ const resolved = cliValue ?? configValue ?? defaultValue;
128
+ expect(resolved).toBe('workflow'); // Config wins over default
129
+ });
130
+ it('falls back to default when both CLI and config are undefined', () => {
131
+ const cliValue = undefined;
132
+ const configValue = undefined;
133
+ const defaultValue = 'normal';
134
+ const resolved = cliValue ?? configValue ?? defaultValue;
135
+ expect(resolved).toBe('normal'); // Default wins
136
+ });
137
+ });
138
+ describe('CLI input validation', () => {
139
+ it('valid modes are: simple, workflow, consensus', () => {
140
+ const validModes = ['simple', 'workflow', 'consensus'];
141
+ expect(validModes).toContain('simple');
142
+ expect(validModes).toContain('workflow');
143
+ expect(validModes).toContain('consensus');
144
+ expect(validModes).not.toContain('turbo');
145
+ });
146
+ it('valid providers are: anthropic, openai, google, github', () => {
147
+ const validProviders = ['anthropic', 'openai', 'google', 'github'];
148
+ expect(validProviders).toContain('anthropic');
149
+ expect(validProviders).toContain('openai');
150
+ expect(validProviders).toContain('google');
151
+ expect(validProviders).toContain('github');
152
+ expect(validProviders).not.toContain('mistral');
153
+ });
154
+ it('valid formats are: markdown, json', () => {
155
+ const validFormats = ['markdown', 'json'];
156
+ expect(validFormats).toContain('markdown');
157
+ expect(validFormats).toContain('json');
158
+ expect(validFormats).not.toContain('html');
159
+ });
160
+ });
161
+ //# sourceMappingURL=review.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.test.js","sourceRoot":"","sources":["../../src/commands/review.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Status command — shows current authentication and configuration.
3
+ */
4
+ export declare function statusCommand(): Promise<void>;
5
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA8BnD"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Status command — shows current authentication and configuration.
3
+ */
4
+ import { loadConfig, getConfigFilePath, isLoggedIn } from '../lib/config.js';
5
+ import { fetchGitHubUser } from '../lib/oauth.js';
6
+ export async function statusCommand() {
7
+ const config = loadConfig();
8
+ const configPath = getConfigFilePath();
9
+ console.log('\ud83e\udd16 GHAGGA Status\n');
10
+ console.log(` Config: ${configPath}`);
11
+ if (!isLoggedIn()) {
12
+ console.log(' Auth: \x1b[31mNot logged in\x1b[0m');
13
+ console.log('\n Run "ghagga login" to authenticate with GitHub.\n');
14
+ return;
15
+ }
16
+ console.log(` Auth: \x1b[32mLogged in\x1b[0m as \x1b[1m${config.githubLogin ?? 'unknown'}\x1b[0m`);
17
+ console.log(` Provider: ${config.defaultProvider ?? 'github'}`);
18
+ console.log(` Model: ${config.defaultModel ?? 'gpt-4o-mini'}`);
19
+ // Validate the stored credential is still valid
20
+ if (config.githubToken) {
21
+ try {
22
+ const user = await fetchGitHubUser(config.githubToken);
23
+ console.log(` Session: \x1b[32mValid\x1b[0m (${user.login})`);
24
+ }
25
+ catch {
26
+ console.log(` Session: \x1b[31mExpired or invalid\x1b[0m`);
27
+ console.log('\n Run "ghagga login" to re-authenticate.\n');
28
+ return;
29
+ }
30
+ }
31
+ console.log('');
32
+ }
33
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,cAAc,UAAU,EAAE,CAAC,CAAC;IAExC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;QACtE,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,iDAAiD,MAAM,CAAC,WAAW,IAAI,SAAS,SAAS,CAAC,CAAC;IACvG,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,eAAe,IAAI,QAAQ,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,YAAY,IAAI,aAAa,EAAE,CAAC,CAAC;IAEpE,gDAAgD;IAChD,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;YAC7D,OAAO;QACT,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * GHAGGA CLI — AI-powered code review from the command line.
4
+ *
5
+ * Quick start:
6
+ * ghagga login Authenticate with GitHub (free!)
7
+ * ghagga review [path] Review staged or uncommitted changes
8
+ * ghagga status Show current auth and config
9
+ * ghagga logout Clear stored credentials
10
+ *
11
+ * After "ghagga login", reviews use GitHub Models (gpt-4o-mini) for free.
12
+ * You can override with --provider, --model, --api-key for other providers.
13
+ *
14
+ * Environment variables (override stored config):
15
+ * GHAGGA_API_KEY API key for the LLM provider
16
+ * GHAGGA_PROVIDER LLM provider: anthropic, openai, google, github, ollama
17
+ * GHAGGA_MODEL Model identifier
18
+ * GITHUB_TOKEN GitHub token (fallback for github provider)
19
+ */
20
+ import 'dotenv/config';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * GHAGGA CLI — AI-powered code review from the command line.
4
+ *
5
+ * Quick start:
6
+ * ghagga login Authenticate with GitHub (free!)
7
+ * ghagga review [path] Review staged or uncommitted changes
8
+ * ghagga status Show current auth and config
9
+ * ghagga logout Clear stored credentials
10
+ *
11
+ * After "ghagga login", reviews use GitHub Models (gpt-4o-mini) for free.
12
+ * You can override with --provider, --model, --api-key for other providers.
13
+ *
14
+ * Environment variables (override stored config):
15
+ * GHAGGA_API_KEY API key for the LLM provider
16
+ * GHAGGA_PROVIDER LLM provider: anthropic, openai, google, github, ollama
17
+ * GHAGGA_MODEL Model identifier
18
+ * GITHUB_TOKEN GitHub token (fallback for github provider)
19
+ */
20
+ import 'dotenv/config';
21
+ import { Command } from 'commander';
22
+ import { DEFAULT_MODELS } from 'ghagga-core';
23
+ import { loadConfig, getStoredToken } from './lib/config.js';
24
+ import { reviewCommand } from './commands/review.js';
25
+ import { loginCommand } from './commands/login.js';
26
+ import { logoutCommand } from './commands/logout.js';
27
+ import { statusCommand } from './commands/status.js';
28
+ const program = new Command();
29
+ program
30
+ .name('ghagga')
31
+ .description('AI-powered code review CLI')
32
+ .version('2.0.0');
33
+ // ─── Login ──────────────────────────────────────────────────────
34
+ program
35
+ .command('login')
36
+ .description('Authenticate with GitHub (uses free AI models)')
37
+ .action(async () => {
38
+ await loginCommand();
39
+ });
40
+ // ─── Logout ─────────────────────────────────────────────────────
41
+ program
42
+ .command('logout')
43
+ .description('Clear stored GitHub credentials')
44
+ .action(() => {
45
+ logoutCommand();
46
+ });
47
+ // ─── Status ─────────────────────────────────────────────────────
48
+ program
49
+ .command('status')
50
+ .description('Show current authentication and configuration')
51
+ .action(async () => {
52
+ await statusCommand();
53
+ });
54
+ // ─── Review ─────────────────────────────────────────────────────
55
+ program
56
+ .command('review')
57
+ .description('Review local code changes using AI')
58
+ .argument('[path]', 'Path to the repository', '.')
59
+ .option('-m, --mode <mode>', 'Review mode', 'simple')
60
+ .option('-p, --provider <provider>', 'LLM provider (auto-detected from login)', process.env['GHAGGA_PROVIDER'])
61
+ .option('--model <model>', 'LLM model identifier', process.env['GHAGGA_MODEL'])
62
+ .option('--api-key <key>', 'LLM provider API key', process.env['GHAGGA_API_KEY'])
63
+ .option('-f, --format <format>', 'Output format', 'markdown')
64
+ .option('--no-semgrep', 'Disable Semgrep static analysis')
65
+ .option('--no-trivy', 'Disable Trivy vulnerability scanning')
66
+ .option('--no-cpd', 'Disable CPD duplicate detection')
67
+ .option('-c, --config <path>', 'Path to .ghagga.json config file')
68
+ .option('-v, --verbose', 'Show detailed progress during review')
69
+ .action(async (path, options) => {
70
+ // ── Auto-resolve auth from stored config ──────────────────
71
+ const config = loadConfig();
72
+ const storedToken = getStoredToken();
73
+ // Priority: CLI flag > env var > stored config
74
+ if (!options.provider) {
75
+ options.provider = config.defaultProvider ?? 'github';
76
+ }
77
+ if (!options.model) {
78
+ options.model = config.defaultModel ?? undefined;
79
+ }
80
+ // Auto-resolve API key: CLI flag > env var > GITHUB_TOKEN > stored token
81
+ if (!options.apiKey) {
82
+ if (options.provider === 'github') {
83
+ options.apiKey = process.env['GITHUB_TOKEN'] ?? storedToken ?? undefined;
84
+ }
85
+ }
86
+ // ── Validate mode ─────────────────────────────────────────
87
+ const validModes = ['simple', 'workflow', 'consensus'];
88
+ if (!validModes.includes(options.mode)) {
89
+ console.error(`\u274c Invalid mode "${options.mode}". Choose from: ${validModes.join(', ')}`);
90
+ process.exit(1);
91
+ }
92
+ // ── Validate provider ─────────────────────────────────────
93
+ const validProviders = ['anthropic', 'openai', 'google', 'github', 'ollama'];
94
+ if (!validProviders.includes(options.provider)) {
95
+ console.error(`\u274c Invalid provider "${options.provider}". Choose from: ${validProviders.join(', ')}`);
96
+ process.exit(1);
97
+ }
98
+ // ── Validate format ───────────────────────────────────────
99
+ const validFormats = ['markdown', 'json'];
100
+ if (!validFormats.includes(options.format)) {
101
+ console.error(`\u274c Invalid format "${options.format}". Choose from: ${validFormats.join(', ')}`);
102
+ process.exit(1);
103
+ }
104
+ // ── Validate API key (not required for ollama) ─────────────
105
+ if (!options.apiKey && options.provider !== 'ollama') {
106
+ console.error('\u274c No API key available.\n');
107
+ console.error(' Quick fix: run "ghagga login" to authenticate with GitHub (free!)');
108
+ console.error(' Or pass --api-key <key> or set GHAGGA_API_KEY.');
109
+ console.error(' Or use --provider ollama for local models (no key needed).\n');
110
+ process.exit(1);
111
+ }
112
+ // Ollama doesn't need an API key — use a placeholder
113
+ if (options.provider === 'ollama' && !options.apiKey) {
114
+ options.apiKey = 'ollama';
115
+ }
116
+ // ── Resolve model default ─────────────────────────────────
117
+ const provider = options.provider;
118
+ const model = options.model ?? DEFAULT_MODELS[provider];
119
+ await reviewCommand(path, {
120
+ mode: options.mode,
121
+ provider,
122
+ model,
123
+ apiKey: options.apiKey,
124
+ format: options.format,
125
+ semgrep: options.semgrep,
126
+ trivy: options.trivy,
127
+ cpd: options.cpd,
128
+ config: options.config,
129
+ verbose: options.verbose ?? false,
130
+ });
131
+ });
132
+ program.parse();
133
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * CLI configuration management.
3
+ *
4
+ * Stores auth credentials and preferences in ~/.config/ghagga/config.json
5
+ * following the XDG Base Directory specification.
6
+ */
7
+ export interface GhaggaCliConfig {
8
+ /** GitHub OAuth access token from Device Flow */
9
+ githubToken?: string;
10
+ /** GitHub username (fetched after login) */
11
+ githubLogin?: string;
12
+ /** Default LLM provider */
13
+ defaultProvider?: string;
14
+ /** Default model for the provider */
15
+ defaultModel?: string;
16
+ }
17
+ /**
18
+ * Load the CLI config file. Returns empty config if not found.
19
+ */
20
+ export declare function loadConfig(): GhaggaCliConfig;
21
+ /**
22
+ * Save the CLI config file. Creates the directory if needed.
23
+ */
24
+ export declare function saveConfig(config: GhaggaCliConfig): void;
25
+ /**
26
+ * Clear all stored auth credentials.
27
+ */
28
+ export declare function clearConfig(): void;
29
+ /**
30
+ * Check if the user is logged in (has a stored token).
31
+ */
32
+ export declare function isLoggedIn(): boolean;
33
+ /**
34
+ * Get the stored GitHub token, or null if not logged in.
35
+ */
36
+ export declare function getStoredToken(): string | null;
37
+ /**
38
+ * Get the config file path (for display in status/error messages).
39
+ */
40
+ export declare function getConfigFilePath(): string;
41
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2BAA2B;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgBD;;GAEG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAa5C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CASxD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAGpC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAG9C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * CLI configuration management.
3
+ *
4
+ * Stores auth credentials and preferences in ~/.config/ghagga/config.json
5
+ * following the XDG Base Directory specification.
6
+ */
7
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { homedir } from 'node:os';
10
+ // ─── Paths ──────────────────────────────────────────────────────
11
+ function getConfigDir() {
12
+ const xdgConfig = process.env['XDG_CONFIG_HOME'];
13
+ const base = xdgConfig || join(homedir(), '.config');
14
+ return join(base, 'ghagga');
15
+ }
16
+ function getConfigPath() {
17
+ return join(getConfigDir(), 'config.json');
18
+ }
19
+ // ─── Read / Write ───────────────────────────────────────────────
20
+ /**
21
+ * Load the CLI config file. Returns empty config if not found.
22
+ */
23
+ export function loadConfig() {
24
+ const configPath = getConfigPath();
25
+ if (!existsSync(configPath)) {
26
+ return {};
27
+ }
28
+ try {
29
+ const raw = readFileSync(configPath, 'utf-8');
30
+ return JSON.parse(raw);
31
+ }
32
+ catch {
33
+ return {};
34
+ }
35
+ }
36
+ /**
37
+ * Save the CLI config file. Creates the directory if needed.
38
+ */
39
+ export function saveConfig(config) {
40
+ const configDir = getConfigDir();
41
+ const configPath = getConfigPath();
42
+ if (!existsSync(configDir)) {
43
+ mkdirSync(configDir, { recursive: true });
44
+ }
45
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
46
+ }
47
+ /**
48
+ * Clear all stored auth credentials.
49
+ */
50
+ export function clearConfig() {
51
+ saveConfig({});
52
+ }
53
+ /**
54
+ * Check if the user is logged in (has a stored token).
55
+ */
56
+ export function isLoggedIn() {
57
+ const config = loadConfig();
58
+ return !!config.githubToken;
59
+ }
60
+ /**
61
+ * Get the stored GitHub token, or null if not logged in.
62
+ */
63
+ export function getStoredToken() {
64
+ const config = loadConfig();
65
+ return config.githubToken ?? null;
66
+ }
67
+ /**
68
+ * Get the config file path (for display in status/error messages).
69
+ */
70
+ export function getConfigFilePath() {
71
+ return getConfigPath();
72
+ }
73
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAkBlC,mEAAmE;AAEnE,SAAS,YAAY;IACnB,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,aAAa,CAAC,CAAC;AAC7C,CAAC;AAED,mEAAmE;AAEnE;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAuB;IAChD,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW;IACzB,UAAU,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,OAAO,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * GitHub OAuth Device Flow for CLI authentication.
3
+ *
4
+ * Implements RFC 8628 (Device Authorization Grant) against GitHub's
5
+ * OAuth endpoints. The user visits github.com/login/device, enters
6
+ * a short code, and the CLI receives an access token.
7
+ *
8
+ * @see https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow
9
+ */
10
+ /** GHAGGA OAuth App Client ID (public — safe to embed in code) */
11
+ export declare const GITHUB_CLIENT_ID = "Ov23liyYpSgDqOLUFa5k";
12
+ export interface DeviceCodeResponse {
13
+ device_code: string;
14
+ user_code: string;
15
+ verification_uri: string;
16
+ expires_in: number;
17
+ interval: number;
18
+ }
19
+ export interface AccessTokenResponse {
20
+ access_token: string;
21
+ token_type: string;
22
+ scope: string;
23
+ }
24
+ export interface DeviceFlowError {
25
+ error: string;
26
+ error_description?: string;
27
+ interval?: number;
28
+ }
29
+ export interface GitHubUser {
30
+ login: string;
31
+ id: number;
32
+ avatar_url: string;
33
+ }
34
+ /**
35
+ * Step 1: Request device and user verification codes from GitHub.
36
+ */
37
+ export declare function requestDeviceCode(): Promise<DeviceCodeResponse>;
38
+ /**
39
+ * Step 3: Poll GitHub for the access token until the user authorizes.
40
+ *
41
+ * Respects the polling interval and handles slow_down errors by
42
+ * increasing the interval as required by the spec.
43
+ *
44
+ * @param deviceCode - The device_code from Step 1
45
+ * @param interval - Polling interval in seconds from Step 1
46
+ * @param expiresIn - Expiration time in seconds from Step 1
47
+ * @returns The access token on success
48
+ * @throws On timeout, access_denied, or other fatal errors
49
+ */
50
+ export declare function pollForAccessToken(deviceCode: string, interval: number, expiresIn: number): Promise<AccessTokenResponse>;
51
+ /**
52
+ * Fetch the authenticated user's profile from GitHub API.
53
+ */
54
+ export declare function fetchGitHubUser(token: string): Promise<GitHubUser>;
55
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/lib/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAIvD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAmBrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC,CAuD9B;AAID;;GAEG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAcxE"}