ghagga 2.1.0 → 2.3.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.
- package/README.md +41 -8
- package/dist/commands/hooks/index.d.ts +9 -0
- package/dist/commands/hooks/index.d.ts.map +1 -0
- package/dist/commands/hooks/index.js +15 -0
- package/dist/commands/hooks/index.js.map +1 -0
- package/dist/commands/hooks/install.d.ts +13 -0
- package/dist/commands/hooks/install.d.ts.map +1 -0
- package/dist/commands/hooks/install.js +64 -0
- package/dist/commands/hooks/install.js.map +1 -0
- package/dist/commands/hooks/install.test.d.ts +11 -0
- package/dist/commands/hooks/install.test.d.ts.map +1 -0
- package/dist/commands/hooks/install.test.js +169 -0
- package/dist/commands/hooks/install.test.js.map +1 -0
- package/dist/commands/hooks/status.d.ts +12 -0
- package/dist/commands/hooks/status.d.ts.map +1 -0
- package/dist/commands/hooks/status.js +38 -0
- package/dist/commands/hooks/status.js.map +1 -0
- package/dist/commands/hooks/status.test.d.ts +11 -0
- package/dist/commands/hooks/status.test.d.ts.map +1 -0
- package/dist/commands/hooks/status.test.js +153 -0
- package/dist/commands/hooks/status.test.js.map +1 -0
- package/dist/commands/hooks/uninstall.d.ts +12 -0
- package/dist/commands/hooks/uninstall.d.ts.map +1 -0
- package/dist/commands/hooks/uninstall.js +44 -0
- package/dist/commands/hooks/uninstall.js.map +1 -0
- package/dist/commands/hooks/uninstall.test.d.ts +10 -0
- package/dist/commands/hooks/uninstall.test.d.ts.map +1 -0
- package/dist/commands/hooks/uninstall.test.js +142 -0
- package/dist/commands/hooks/uninstall.test.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/login.test.js +5 -3
- package/dist/commands/login.test.js.map +1 -1
- package/dist/commands/logout.test.js +1 -1
- package/dist/commands/logout.test.js.map +1 -1
- package/dist/commands/memory/clear.d.ts +1 -1
- package/dist/commands/memory/clear.d.ts.map +1 -1
- package/dist/commands/memory/clear.js +1 -1
- package/dist/commands/memory/clear.js.map +1 -1
- package/dist/commands/memory/clear.test.js +5 -7
- package/dist/commands/memory/clear.test.js.map +1 -1
- package/dist/commands/memory/delete.d.ts +1 -1
- package/dist/commands/memory/delete.d.ts.map +1 -1
- package/dist/commands/memory/delete.js +2 -2
- package/dist/commands/memory/delete.js.map +1 -1
- package/dist/commands/memory/delete.test.js +5 -7
- package/dist/commands/memory/delete.test.js.map +1 -1
- package/dist/commands/memory/index.d.ts.map +1 -1
- package/dist/commands/memory/index.js +3 -4
- package/dist/commands/memory/index.js.map +1 -1
- package/dist/commands/memory/list.d.ts +1 -1
- package/dist/commands/memory/list.d.ts.map +1 -1
- package/dist/commands/memory/list.js +1 -1
- package/dist/commands/memory/list.js.map +1 -1
- package/dist/commands/memory/list.test.js +17 -5
- package/dist/commands/memory/list.test.js.map +1 -1
- package/dist/commands/memory/search.d.ts +1 -1
- package/dist/commands/memory/search.d.ts.map +1 -1
- package/dist/commands/memory/search.js +1 -1
- package/dist/commands/memory/search.js.map +1 -1
- package/dist/commands/memory/search.test.js +9 -4
- package/dist/commands/memory/search.test.js.map +1 -1
- package/dist/commands/memory/show.d.ts +1 -1
- package/dist/commands/memory/show.d.ts.map +1 -1
- package/dist/commands/memory/show.js +3 -5
- package/dist/commands/memory/show.js.map +1 -1
- package/dist/commands/memory/show.test.js +4 -6
- package/dist/commands/memory/show.test.js.map +1 -1
- package/dist/commands/memory/stats.d.ts +1 -1
- package/dist/commands/memory/stats.d.ts.map +1 -1
- package/dist/commands/memory/stats.js +3 -7
- package/dist/commands/memory/stats.js.map +1 -1
- package/dist/commands/memory/stats.test.js +3 -3
- package/dist/commands/memory/stats.test.js.map +1 -1
- package/dist/commands/memory/utils.d.ts.map +1 -1
- package/dist/commands/memory/utils.js +1 -1
- package/dist/commands/memory/utils.js.map +1 -1
- package/dist/commands/memory/utils.test.js +2 -2
- package/dist/commands/memory/utils.test.js.map +1 -1
- package/dist/commands/review-commit-msg.d.ts +28 -0
- package/dist/commands/review-commit-msg.d.ts.map +1 -0
- package/dist/commands/review-commit-msg.js +126 -0
- package/dist/commands/review-commit-msg.js.map +1 -0
- package/dist/commands/review-commit-msg.test.d.ts +11 -0
- package/dist/commands/review-commit-msg.test.d.ts.map +1 -0
- package/dist/commands/review-commit-msg.test.js +126 -0
- package/dist/commands/review-commit-msg.test.js.map +1 -0
- package/dist/commands/review.d.ts +7 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +107 -16
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/review.test.js +8 -7
- package/dist/commands/review.test.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status.test.js +2 -2
- package/dist/commands/status.test.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -16
- package/dist/index.js.map +1 -1
- package/dist/lib/config.js +3 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.js +11 -9
- package/dist/lib/config.test.js.map +1 -1
- package/dist/lib/git-hooks.d.ts +19 -0
- package/dist/lib/git-hooks.d.ts.map +1 -0
- package/dist/lib/git-hooks.js +129 -0
- package/dist/lib/git-hooks.js.map +1 -0
- package/dist/lib/git-hooks.test.d.ts +11 -0
- package/dist/lib/git-hooks.test.d.ts.map +1 -0
- package/dist/lib/git-hooks.test.js +178 -0
- package/dist/lib/git-hooks.test.js.map +1 -0
- package/dist/lib/git.d.ts +10 -0
- package/dist/lib/git.d.ts.map +1 -1
- package/dist/lib/git.js +33 -1
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/git.test.js +5 -3
- package/dist/lib/git.test.js.map +1 -1
- package/dist/lib/hook-templates.d.ts +12 -0
- package/dist/lib/hook-templates.d.ts.map +1 -0
- package/dist/lib/hook-templates.js +52 -0
- package/dist/lib/hook-templates.js.map +1 -0
- package/dist/lib/hook-templates.test.d.ts +11 -0
- package/dist/lib/hook-templates.test.d.ts.map +1 -0
- package/dist/lib/hook-templates.test.js +76 -0
- package/dist/lib/hook-templates.test.js.map +1 -0
- package/dist/lib/hooks-types.d.ts +30 -0
- package/dist/lib/hooks-types.d.ts.map +1 -0
- package/dist/lib/hooks-types.js +9 -0
- package/dist/lib/hooks-types.js.map +1 -0
- package/dist/lib/oauth.js +1 -1
- package/dist/lib/oauth.js.map +1 -1
- package/dist/lib/oauth.test.js +4 -3
- package/dist/lib/oauth.test.js.map +1 -1
- package/dist/ui/__tests__/format.test.js +36 -7
- package/dist/ui/__tests__/format.test.js.map +1 -1
- package/dist/ui/__tests__/theme.test.js +16 -7
- package/dist/ui/__tests__/theme.test.js.map +1 -1
- package/dist/ui/__tests__/tui.test.js +8 -8
- package/dist/ui/__tests__/tui.test.js.map +1 -1
- package/dist/ui/format.d.ts.map +1 -1
- package/dist/ui/format.js +6 -6
- package/dist/ui/format.js.map +1 -1
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.d.ts.map +1 -1
- package/dist/ui/theme.js +1 -1
- package/dist/ui/theme.js.map +1 -1
- package/dist/ui/tui.js +1 -1
- package/dist/ui/tui.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-hooks.js","sourceRoot":"","sources":["../../src/lib/git-hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for git hook utilities (install, uninstall, status).
|
|
3
|
+
*
|
|
4
|
+
* Mocks node:fs, node:child_process, and node:path to test
|
|
5
|
+
* isGitRepo, getHooksDir, getHookStatus, installHook, and uninstallHook
|
|
6
|
+
* without touching the real filesystem or git.
|
|
7
|
+
*
|
|
8
|
+
* @see Phase 4, Test 2
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=git-hooks.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-hooks.test.d.ts","sourceRoot":"","sources":["../../src/lib/git-hooks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for git hook utilities (install, uninstall, status).
|
|
3
|
+
*
|
|
4
|
+
* Mocks node:fs, node:child_process, and node:path to test
|
|
5
|
+
* isGitRepo, getHooksDir, getHookStatus, installHook, and uninstallHook
|
|
6
|
+
* without touching the real filesystem or git.
|
|
7
|
+
*
|
|
8
|
+
* @see Phase 4, Test 2
|
|
9
|
+
*/
|
|
10
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
11
|
+
import { HOOK_MARKER } from './hooks-types.js';
|
|
12
|
+
// ─── Mocks ──────────────────────────────────────────────────────
|
|
13
|
+
const { mockExecSync, mockExistsSync, mockReadFileSync, mockWriteFileSync, mockUnlinkSync, mockRenameSync, mockChmodSync, } = vi.hoisted(() => ({
|
|
14
|
+
mockExecSync: vi.fn(),
|
|
15
|
+
mockExistsSync: vi.fn(),
|
|
16
|
+
mockReadFileSync: vi.fn(),
|
|
17
|
+
mockWriteFileSync: vi.fn(),
|
|
18
|
+
mockUnlinkSync: vi.fn(),
|
|
19
|
+
mockRenameSync: vi.fn(),
|
|
20
|
+
mockChmodSync: vi.fn(),
|
|
21
|
+
}));
|
|
22
|
+
vi.mock('node:child_process', () => ({
|
|
23
|
+
execSync: (...args) => mockExecSync(...args),
|
|
24
|
+
}));
|
|
25
|
+
vi.mock('node:fs', () => ({
|
|
26
|
+
existsSync: (...args) => mockExistsSync(...args),
|
|
27
|
+
readFileSync: (...args) => mockReadFileSync(...args),
|
|
28
|
+
writeFileSync: (...args) => mockWriteFileSync(...args),
|
|
29
|
+
unlinkSync: (...args) => mockUnlinkSync(...args),
|
|
30
|
+
renameSync: (...args) => mockRenameSync(...args),
|
|
31
|
+
chmodSync: (...args) => mockChmodSync(...args),
|
|
32
|
+
}));
|
|
33
|
+
import { getHookStatus, getHooksDir, installHook, isGitRepo, uninstallHook } from './git-hooks.js';
|
|
34
|
+
// ─── Setup ──────────────────────────────────────────────────────
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
vi.clearAllMocks();
|
|
37
|
+
});
|
|
38
|
+
// ─── isGitRepo ──────────────────────────────────────────────────
|
|
39
|
+
describe('isGitRepo', () => {
|
|
40
|
+
it('returns true when inside a git repository', () => {
|
|
41
|
+
mockExecSync.mockReturnValue('.git');
|
|
42
|
+
expect(isGitRepo()).toBe(true);
|
|
43
|
+
expect(mockExecSync).toHaveBeenCalledWith('git rev-parse --git-dir', { stdio: 'pipe' });
|
|
44
|
+
});
|
|
45
|
+
it('returns false when outside a git repository', () => {
|
|
46
|
+
mockExecSync.mockImplementation(() => {
|
|
47
|
+
throw new Error('not a git repository');
|
|
48
|
+
});
|
|
49
|
+
expect(isGitRepo()).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
// ─── getHooksDir ────────────────────────────────────────────────
|
|
53
|
+
describe('getHooksDir', () => {
|
|
54
|
+
it('returns default .git/hooks when no core.hooksPath is set', () => {
|
|
55
|
+
mockExecSync
|
|
56
|
+
.mockImplementationOnce(() => {
|
|
57
|
+
// core.hooksPath fails (not set)
|
|
58
|
+
throw new Error('key does not exist');
|
|
59
|
+
})
|
|
60
|
+
.mockReturnValueOnce('.git\n'); // git rev-parse --git-dir
|
|
61
|
+
const result = getHooksDir();
|
|
62
|
+
expect(result).toMatch(/\.git[/\\]hooks$/);
|
|
63
|
+
});
|
|
64
|
+
it('respects core.hooksPath config when set', () => {
|
|
65
|
+
mockExecSync.mockReturnValueOnce('/custom/hooks-dir\n'); // core.hooksPath
|
|
66
|
+
const result = getHooksDir();
|
|
67
|
+
expect(result).toBe('/custom/hooks-dir');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
// ─── getHookStatus ──────────────────────────────────────────────
|
|
71
|
+
describe('getHookStatus', () => {
|
|
72
|
+
it('returns not installed when hook file does not exist', () => {
|
|
73
|
+
mockExistsSync.mockReturnValue(false);
|
|
74
|
+
const status = getHookStatus('/repo/.git/hooks', 'pre-commit');
|
|
75
|
+
expect(status.installed).toBe(false);
|
|
76
|
+
expect(status.managedByGhagga).toBe(false);
|
|
77
|
+
expect(status.type).toBe('pre-commit');
|
|
78
|
+
});
|
|
79
|
+
it('returns managed when GHAGGA marker is found in hook file', () => {
|
|
80
|
+
mockExistsSync.mockReturnValue(true);
|
|
81
|
+
mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`);
|
|
82
|
+
const status = getHookStatus('/repo/.git/hooks', 'pre-commit');
|
|
83
|
+
expect(status.installed).toBe(true);
|
|
84
|
+
expect(status.managedByGhagga).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it('returns not managed when external hook exists (no marker)', () => {
|
|
87
|
+
mockExistsSync.mockReturnValue(true);
|
|
88
|
+
mockReadFileSync.mockReturnValue('#!/bin/sh\necho "custom hook"');
|
|
89
|
+
const status = getHookStatus('/repo/.git/hooks', 'commit-msg');
|
|
90
|
+
expect(status.installed).toBe(true);
|
|
91
|
+
expect(status.managedByGhagga).toBe(false);
|
|
92
|
+
expect(status.type).toBe('commit-msg');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
// ─── installHook ────────────────────────────────────────────────
|
|
96
|
+
describe('installHook', () => {
|
|
97
|
+
const hookContent = `#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`;
|
|
98
|
+
it('creates a new hook file when none exists', () => {
|
|
99
|
+
mockExistsSync.mockReturnValue(false);
|
|
100
|
+
const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, false);
|
|
101
|
+
expect(result.success).toBe(true);
|
|
102
|
+
expect(result.type).toBe('pre-commit');
|
|
103
|
+
expect(result.message).toContain('Installed pre-commit hook');
|
|
104
|
+
expect(result.backedUp).toBeFalsy();
|
|
105
|
+
expect(mockWriteFileSync).toHaveBeenCalledWith(expect.stringContaining('pre-commit'), hookContent, { mode: 0o755 });
|
|
106
|
+
expect(mockChmodSync).toHaveBeenCalled();
|
|
107
|
+
});
|
|
108
|
+
it('overwrites GHAGGA-managed hooks without --force', () => {
|
|
109
|
+
mockExistsSync.mockReturnValue(true);
|
|
110
|
+
mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nold content`);
|
|
111
|
+
const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, false);
|
|
112
|
+
expect(result.success).toBe(true);
|
|
113
|
+
expect(result.backedUp).toBeFalsy();
|
|
114
|
+
expect(mockWriteFileSync).toHaveBeenCalled();
|
|
115
|
+
// Should NOT have been backed up (renamed)
|
|
116
|
+
expect(mockRenameSync).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
it('refuses to overwrite external hooks without --force', () => {
|
|
119
|
+
mockExistsSync.mockReturnValue(true);
|
|
120
|
+
mockReadFileSync.mockReturnValue('#!/bin/sh\necho "external"');
|
|
121
|
+
const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, false);
|
|
122
|
+
expect(result.success).toBe(false);
|
|
123
|
+
expect(result.message).toContain('already exists');
|
|
124
|
+
expect(result.message).toContain('--force');
|
|
125
|
+
expect(mockWriteFileSync).not.toHaveBeenCalled();
|
|
126
|
+
});
|
|
127
|
+
it('backs up external hooks with --force and installs', () => {
|
|
128
|
+
mockExistsSync.mockReturnValue(true);
|
|
129
|
+
mockReadFileSync.mockReturnValue('#!/bin/sh\necho "external"');
|
|
130
|
+
const result = installHook('/repo/.git/hooks', 'pre-commit', hookContent, true);
|
|
131
|
+
expect(result.success).toBe(true);
|
|
132
|
+
expect(result.backedUp).toBe(true);
|
|
133
|
+
expect(result.message).toContain('backed up');
|
|
134
|
+
expect(result.message).toContain('.ghagga-backup');
|
|
135
|
+
expect(mockRenameSync).toHaveBeenCalledWith(expect.stringContaining('pre-commit'), expect.stringContaining('pre-commit.ghagga-backup'));
|
|
136
|
+
expect(mockWriteFileSync).toHaveBeenCalled();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
// ─── uninstallHook ──────────────────────────────────────────────
|
|
140
|
+
describe('uninstallHook', () => {
|
|
141
|
+
it('removes GHAGGA-managed hooks', () => {
|
|
142
|
+
mockExistsSync
|
|
143
|
+
.mockReturnValueOnce(true) // hook exists
|
|
144
|
+
.mockReturnValueOnce(false); // no backup
|
|
145
|
+
mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`);
|
|
146
|
+
const result = uninstallHook('/repo/.git/hooks', 'pre-commit');
|
|
147
|
+
expect(result.success).toBe(true);
|
|
148
|
+
expect(result.message).toContain('Removed pre-commit hook');
|
|
149
|
+
expect(mockUnlinkSync).toHaveBeenCalled();
|
|
150
|
+
});
|
|
151
|
+
it('skips external hooks (not managed by GHAGGA)', () => {
|
|
152
|
+
mockExistsSync.mockReturnValue(true);
|
|
153
|
+
mockReadFileSync.mockReturnValue('#!/bin/sh\necho "external"');
|
|
154
|
+
const result = uninstallHook('/repo/.git/hooks', 'commit-msg');
|
|
155
|
+
expect(result.success).toBe(false);
|
|
156
|
+
expect(result.message).toContain('not managed by GHAGGA');
|
|
157
|
+
expect(mockUnlinkSync).not.toHaveBeenCalled();
|
|
158
|
+
});
|
|
159
|
+
it('restores backup when present after removing GHAGGA hook', () => {
|
|
160
|
+
mockExistsSync
|
|
161
|
+
.mockReturnValueOnce(true) // hook exists
|
|
162
|
+
.mockReturnValueOnce(true); // backup exists
|
|
163
|
+
mockReadFileSync.mockReturnValue(`#!/bin/sh\n${HOOK_MARKER}\nexec ghagga review`);
|
|
164
|
+
const result = uninstallHook('/repo/.git/hooks', 'pre-commit');
|
|
165
|
+
expect(result.success).toBe(true);
|
|
166
|
+
expect(result.message).toContain('restored previous hook from backup');
|
|
167
|
+
expect(mockUnlinkSync).toHaveBeenCalled();
|
|
168
|
+
expect(mockRenameSync).toHaveBeenCalledWith(expect.stringContaining('.ghagga-backup'), expect.stringContaining('pre-commit'));
|
|
169
|
+
});
|
|
170
|
+
it('handles not-installed case gracefully', () => {
|
|
171
|
+
mockExistsSync.mockReturnValue(false);
|
|
172
|
+
const result = uninstallHook('/repo/.git/hooks', 'pre-commit');
|
|
173
|
+
expect(result.success).toBe(true);
|
|
174
|
+
expect(result.message).toContain('not installed');
|
|
175
|
+
expect(mockUnlinkSync).not.toHaveBeenCalled();
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=git-hooks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-hooks.test.js","sourceRoot":"","sources":["../../src/lib/git-hooks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,mEAAmE;AAEnE,MAAM,EACJ,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,aAAa,GACd,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpB,YAAY,EAAE,EAAE,CAAC,EAAE,EAAE;IACrB,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE;IACvB,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE;IACzB,iBAAiB,EAAE,EAAE,CAAC,EAAE,EAAE;IAC1B,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE;IACvB,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE;IACvB,aAAa,EAAE,EAAE,CAAC,EAAE,EAAE;CACvB,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;CACxD,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACxB,UAAU,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;IAC3D,YAAY,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAAC;IACjE,UAAU,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;IAC3D,UAAU,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;IAC3D,SAAS,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;CAC1D,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEnG,mEAAmE;AAEnE,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,mEAAmE;AAEnE,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAErC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,yBAAyB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,mEAAmE;AAEnE,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,YAAY;aACT,sBAAsB,CAAC,GAAG,EAAE;YAC3B,iCAAiC;YACjC,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC,CAAC;aACD,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC,0BAA0B;QAE5D,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,YAAY,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,CAAC,CAAC,iBAAiB;QAE1E,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,mEAAmE;AAEnE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,gBAAgB,CAAC,eAAe,CAAC,cAAc,WAAW,sBAAsB,CAAC,CAAC;QAElF,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,gBAAgB,CAAC,eAAe,CAAC,+BAA+B,CAAC,CAAC;QAElE,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,mEAAmE;AAEnE,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,MAAM,WAAW,GAAG,cAAc,WAAW,sBAAsB,CAAC;IAEpE,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,WAAW,CAAC,kBAAkB,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAEjF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,2BAA2B,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,iBAAiB,CAAC,CAAC,oBAAoB,CAC5C,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,EACrC,WAAW,EACX,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CAAC;QACF,MAAM,CAAC,aAAa,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,gBAAgB,CAAC,eAAe,CAAC,cAAc,WAAW,eAAe,CAAC,CAAC;QAE3E,MAAM,MAAM,GAAG,WAAW,CAAC,kBAAkB,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAEjF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,iBAAiB,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC7C,2CAA2C;QAC3C,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,gBAAgB,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC;QAE/D,MAAM,MAAM,GAAG,WAAW,CAAC,kBAAkB,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QAEjF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,gBAAgB,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC;QAE/D,MAAM,MAAM,GAAG,WAAW,CAAC,kBAAkB,EAAE,YAAY,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QAEhF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QACnD,MAAM,CAAC,cAAc,CAAC,CAAC,oBAAoB,CACzC,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,EACrC,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,CAAC,CACpD,CAAC;QACF,MAAM,CAAC,iBAAiB,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,mEAAmE;AAEnE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,cAAc;aACX,mBAAmB,CAAC,IAAI,CAAC,CAAC,cAAc;aACxC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY;QAC3C,gBAAgB,CAAC,eAAe,CAAC,cAAc,WAAW,sBAAsB,CAAC,CAAC;QAElF,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAC5D,MAAM,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,cAAc,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,gBAAgB,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC;QAE/D,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;QAC1D,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,cAAc;aACX,mBAAmB,CAAC,IAAI,CAAC,CAAC,cAAc;aACxC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB;QAC9C,gBAAgB,CAAC,eAAe,CAAC,cAAc,WAAW,sBAAsB,CAAC,CAAC;QAElF,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oCAAoC,CAAC,CAAC;QACvE,MAAM,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,CAAC,oBAAoB,CACzC,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,EACzC,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,CACtC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QAClD,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/lib/git.d.ts
CHANGED
|
@@ -10,6 +10,16 @@
|
|
|
10
10
|
* Falls back to "local/unknown" if no remote is configured.
|
|
11
11
|
*/
|
|
12
12
|
export declare function resolveProjectId(repoPath: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get diff of staged files only.
|
|
15
|
+
* Returns an empty string if there are no staged changes or on error.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getStagedDiff(repoPath: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Get list of staged file paths.
|
|
20
|
+
* Returns an empty array if there are no staged files or on error.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getStagedFiles(repoPath: string): string[];
|
|
13
23
|
/**
|
|
14
24
|
* Normalize a git remote URL to "owner/repo" format.
|
|
15
25
|
*
|
package/dist/lib/git.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmBtD"}
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAUzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmBtD"}
|
package/dist/lib/git.js
CHANGED
|
@@ -22,6 +22,38 @@ export function resolveProjectId(repoPath) {
|
|
|
22
22
|
return 'local/unknown';
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Get diff of staged files only.
|
|
27
|
+
* Returns an empty string if there are no staged changes or on error.
|
|
28
|
+
*/
|
|
29
|
+
export function getStagedDiff(repoPath) {
|
|
30
|
+
try {
|
|
31
|
+
return execSync('git diff --cached', {
|
|
32
|
+
cwd: repoPath,
|
|
33
|
+
encoding: 'utf-8',
|
|
34
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return '';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get list of staged file paths.
|
|
43
|
+
* Returns an empty array if there are no staged files or on error.
|
|
44
|
+
*/
|
|
45
|
+
export function getStagedFiles(repoPath) {
|
|
46
|
+
try {
|
|
47
|
+
const output = execSync('git diff --cached --name-only', {
|
|
48
|
+
cwd: repoPath,
|
|
49
|
+
encoding: 'utf-8',
|
|
50
|
+
});
|
|
51
|
+
return output.trim().split('\n').filter(Boolean);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
25
57
|
/**
|
|
26
58
|
* Normalize a git remote URL to "owner/repo" format.
|
|
27
59
|
*
|
|
@@ -37,7 +69,7 @@ export function normalizeRemoteUrl(url) {
|
|
|
37
69
|
cleaned = cleaned.replace(/\.git$/, '');
|
|
38
70
|
// SSH format: git@host:owner/repo
|
|
39
71
|
const sshMatch = cleaned.match(/^[\w-]+@[\w.-]+:(.+)$/);
|
|
40
|
-
if (sshMatch)
|
|
72
|
+
if (sshMatch?.[1])
|
|
41
73
|
return sshMatch[1];
|
|
42
74
|
// HTTPS / SSH protocol: extract path after host
|
|
43
75
|
try {
|
package/dist/lib/git.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YACtD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,OAAO,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,OAAO,GAAG,GAAG,CAAC;IAElB,oBAAoB;IACpB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAExC,kCAAkC;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACxD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YACtD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,OAAO,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,mBAAmB,EAAE;YACnC,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;YACjB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;SAC5B,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,+BAA+B,EAAE;YACvD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,OAAO,GAAG,GAAG,CAAC;IAElB,oBAAoB;IACpB,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAExC,kCAAkC;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACxD,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtC,gDAAgD;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,uBAAuB;QACvB,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;QAC7C,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC"}
|
package/dist/lib/git.test.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
// ─── Mocks ──────────────────────────────────────────────────────
|
|
3
3
|
vi.mock('node:child_process', () => ({
|
|
4
4
|
execSync: vi.fn(),
|
|
5
5
|
}));
|
|
6
6
|
import { execSync } from 'node:child_process';
|
|
7
|
-
import {
|
|
7
|
+
import { normalizeRemoteUrl, resolveProjectId } from './git.js';
|
|
8
8
|
const mockExecSync = vi.mocked(execSync);
|
|
9
9
|
// ─── Tests ──────────────────────────────────────────────────────
|
|
10
10
|
describe('normalizeRemoteUrl', () => {
|
|
@@ -53,7 +53,9 @@ describe('resolveProjectId', () => {
|
|
|
53
53
|
expect(resolveProjectId('/path/to/repo')).toBe('acme/widgets');
|
|
54
54
|
});
|
|
55
55
|
it('falls back to local/unknown when no remote is configured', () => {
|
|
56
|
-
mockExecSync.mockImplementation(() => {
|
|
56
|
+
mockExecSync.mockImplementation(() => {
|
|
57
|
+
throw new Error('fatal: No such remote');
|
|
58
|
+
});
|
|
57
59
|
expect(resolveProjectId('/path/to/repo')).toBe('local/unknown');
|
|
58
60
|
});
|
|
59
61
|
it('passes repoPath as cwd to execSync', () => {
|
package/dist/lib/git.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../src/lib/git.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"git.test.js","sourceRoot":"","sources":["../../src/lib/git.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook script templates for pre-commit and commit-msg hooks.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions that return POSIX shell script strings.
|
|
5
|
+
* Each script includes the GHAGGA marker, a PATH check with
|
|
6
|
+
* graceful degradation, and the appropriate ghagga CLI invocation.
|
|
7
|
+
*/
|
|
8
|
+
/** Generate the pre-commit hook script */
|
|
9
|
+
export declare function generatePreCommitHook(extraArgs?: string): string;
|
|
10
|
+
/** Generate the commit-msg hook script */
|
|
11
|
+
export declare function generateCommitMsgHook(extraArgs?: string): string;
|
|
12
|
+
//# sourceMappingURL=hook-templates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-templates.d.ts","sourceRoot":"","sources":["../../src/lib/hook-templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,0CAA0C;AAC1C,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBhE;AAED,0CAA0C;AAC1C,wBAAgB,qBAAqB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAiBhE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook script templates for pre-commit and commit-msg hooks.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions that return POSIX shell script strings.
|
|
5
|
+
* Each script includes the GHAGGA marker, a PATH check with
|
|
6
|
+
* graceful degradation, and the appropriate ghagga CLI invocation.
|
|
7
|
+
*/
|
|
8
|
+
import { HOOK_MARKER } from './hooks-types.js';
|
|
9
|
+
/** Generate the pre-commit hook script */
|
|
10
|
+
export function generatePreCommitHook(extraArgs) {
|
|
11
|
+
const args = extraArgs ? ` ${extraArgs}` : '';
|
|
12
|
+
return `#!/bin/sh
|
|
13
|
+
${HOOK_MARKER}
|
|
14
|
+
# Installed by: ghagga hooks install
|
|
15
|
+
# To remove: ghagga hooks uninstall
|
|
16
|
+
|
|
17
|
+
# Check if ghagga is available
|
|
18
|
+
if ! command -v ghagga >/dev/null 2>&1; then
|
|
19
|
+
echo "Warning: ghagga not found in PATH. Skipping pre-commit review."
|
|
20
|
+
echo "Install: npm install -g ghagga"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Check if there are staged changes
|
|
25
|
+
if git diff --cached --quiet; then
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Run review on staged files
|
|
30
|
+
exec ghagga review --staged --plain --exit-on-issues${args}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
/** Generate the commit-msg hook script */
|
|
34
|
+
export function generateCommitMsgHook(extraArgs) {
|
|
35
|
+
const args = extraArgs ? ` ${extraArgs}` : '';
|
|
36
|
+
return `#!/bin/sh
|
|
37
|
+
${HOOK_MARKER}
|
|
38
|
+
# Installed by: ghagga hooks install
|
|
39
|
+
# To remove: ghagga hooks uninstall
|
|
40
|
+
|
|
41
|
+
# Check if ghagga is available
|
|
42
|
+
if ! command -v ghagga >/dev/null 2>&1; then
|
|
43
|
+
echo "Warning: ghagga not found in PATH. Skipping commit message review."
|
|
44
|
+
echo "Install: npm install -g ghagga"
|
|
45
|
+
exit 0
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Validate commit message
|
|
49
|
+
exec ghagga review --commit-msg "$1" --plain --exit-on-issues${args}
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=hook-templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-templates.js","sourceRoot":"","sources":["../../src/lib/hook-templates.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,0CAA0C;AAC1C,MAAM,UAAU,qBAAqB,CAAC,SAAkB;IACtD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO;EACP,WAAW;;;;;;;;;;;;;;;;;sDAiByC,IAAI;CACzD,CAAC;AACF,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,qBAAqB,CAAC,SAAkB;IACtD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,OAAO;EACP,WAAW;;;;;;;;;;;;+DAYkD,IAAI;CAClE,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for hook script template generators.
|
|
3
|
+
*
|
|
4
|
+
* Validates that generatePreCommitHook() and generateCommitMsgHook()
|
|
5
|
+
* produce correct POSIX shell scripts with the GHAGGA marker,
|
|
6
|
+
* PATH checks, and appropriate CLI invocations.
|
|
7
|
+
*
|
|
8
|
+
* @see Phase 4, Test 1
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=hook-templates.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-templates.test.d.ts","sourceRoot":"","sources":["../../src/lib/hook-templates.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for hook script template generators.
|
|
3
|
+
*
|
|
4
|
+
* Validates that generatePreCommitHook() and generateCommitMsgHook()
|
|
5
|
+
* produce correct POSIX shell scripts with the GHAGGA marker,
|
|
6
|
+
* PATH checks, and appropriate CLI invocations.
|
|
7
|
+
*
|
|
8
|
+
* @see Phase 4, Test 1
|
|
9
|
+
*/
|
|
10
|
+
import { describe, expect, it } from 'vitest';
|
|
11
|
+
import { generateCommitMsgHook, generatePreCommitHook } from './hook-templates.js';
|
|
12
|
+
import { HOOK_MARKER } from './hooks-types.js';
|
|
13
|
+
// ─── pre-commit template ────────────────────────────────────────
|
|
14
|
+
describe('generatePreCommitHook', () => {
|
|
15
|
+
it('starts with #!/bin/sh shebang', () => {
|
|
16
|
+
const script = generatePreCommitHook();
|
|
17
|
+
expect(script.startsWith('#!/bin/sh\n')).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('includes the GHAGGA marker comment', () => {
|
|
20
|
+
const script = generatePreCommitHook();
|
|
21
|
+
expect(script).toContain(HOOK_MARKER);
|
|
22
|
+
});
|
|
23
|
+
it('includes the ghagga review --staged command', () => {
|
|
24
|
+
const script = generatePreCommitHook();
|
|
25
|
+
expect(script).toContain('ghagga review --staged --plain --exit-on-issues');
|
|
26
|
+
});
|
|
27
|
+
it('includes PATH check with graceful fallback', () => {
|
|
28
|
+
const script = generatePreCommitHook();
|
|
29
|
+
expect(script).toContain('command -v ghagga');
|
|
30
|
+
expect(script).toContain('ghagga not found in PATH');
|
|
31
|
+
expect(script).toContain('exit 0');
|
|
32
|
+
});
|
|
33
|
+
it('includes empty staged check (git diff --cached --quiet)', () => {
|
|
34
|
+
const script = generatePreCommitHook();
|
|
35
|
+
expect(script).toContain('git diff --cached --quiet');
|
|
36
|
+
});
|
|
37
|
+
it('appends extra args when provided', () => {
|
|
38
|
+
const script = generatePreCommitHook('--quick');
|
|
39
|
+
expect(script).toContain('ghagga review --staged --plain --exit-on-issues --quick');
|
|
40
|
+
});
|
|
41
|
+
it('does not append extra args when not provided', () => {
|
|
42
|
+
const script = generatePreCommitHook();
|
|
43
|
+
// Should end the exec line without trailing args
|
|
44
|
+
expect(script).toContain('exec ghagga review --staged --plain --exit-on-issues\n');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// ─── commit-msg template ────────────────────────────────────────
|
|
48
|
+
describe('generateCommitMsgHook', () => {
|
|
49
|
+
it('starts with #!/bin/sh shebang', () => {
|
|
50
|
+
const script = generateCommitMsgHook();
|
|
51
|
+
expect(script.startsWith('#!/bin/sh\n')).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
it('includes the GHAGGA marker comment', () => {
|
|
54
|
+
const script = generateCommitMsgHook();
|
|
55
|
+
expect(script).toContain(HOOK_MARKER);
|
|
56
|
+
});
|
|
57
|
+
it('includes the ghagga review --commit-msg command', () => {
|
|
58
|
+
const script = generateCommitMsgHook();
|
|
59
|
+
expect(script).toContain('ghagga review --commit-msg "$1" --plain --exit-on-issues');
|
|
60
|
+
});
|
|
61
|
+
it('includes PATH check with graceful fallback', () => {
|
|
62
|
+
const script = generateCommitMsgHook();
|
|
63
|
+
expect(script).toContain('command -v ghagga');
|
|
64
|
+
expect(script).toContain('ghagga not found in PATH');
|
|
65
|
+
expect(script).toContain('exit 0');
|
|
66
|
+
});
|
|
67
|
+
it('appends extra args when provided', () => {
|
|
68
|
+
const script = generateCommitMsgHook('--quick');
|
|
69
|
+
expect(script).toContain('ghagga review --commit-msg "$1" --plain --exit-on-issues --quick');
|
|
70
|
+
});
|
|
71
|
+
it('does not append extra args when not provided', () => {
|
|
72
|
+
const script = generateCommitMsgHook();
|
|
73
|
+
expect(script).toContain('exec ghagga review --commit-msg "$1" --plain --exit-on-issues\n');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=hook-templates.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-templates.test.js","sourceRoot":"","sources":["../../src/lib/hook-templates.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook-related type definitions for the GHAGGA CLI.
|
|
3
|
+
*
|
|
4
|
+
* Used by git-hooks utilities, hook templates, and the hooks
|
|
5
|
+
* command group (install, uninstall, status).
|
|
6
|
+
*/
|
|
7
|
+
/** Marker comment identifying GHAGGA-managed hooks */
|
|
8
|
+
export declare const HOOK_MARKER = "# GHAGGA-MANAGED-HOOK \u2014 do not edit";
|
|
9
|
+
/** Supported git hook types */
|
|
10
|
+
export type HookType = 'pre-commit' | 'commit-msg';
|
|
11
|
+
/** Result of a hook status check */
|
|
12
|
+
export interface HookStatus {
|
|
13
|
+
type: HookType;
|
|
14
|
+
installed: boolean;
|
|
15
|
+
managedByGhagga: boolean;
|
|
16
|
+
path: string;
|
|
17
|
+
}
|
|
18
|
+
/** Options for hook installation */
|
|
19
|
+
export interface HookInstallOptions {
|
|
20
|
+
force?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Result of install/uninstall operations */
|
|
23
|
+
export interface HookOperationResult {
|
|
24
|
+
type: HookType;
|
|
25
|
+
success: boolean;
|
|
26
|
+
message: string;
|
|
27
|
+
/** Previous hook content if backed up */
|
|
28
|
+
backedUp?: boolean;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=hooks-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-types.d.ts","sourceRoot":"","sources":["../../src/lib/hooks-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sDAAsD;AACtD,eAAO,MAAM,WAAW,6CAAwC,CAAC;AAEjE,+BAA+B;AAC/B,MAAM,MAAM,QAAQ,GAAG,YAAY,GAAG,YAAY,CAAC;AAEnD,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oCAAoC;AACpC,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook-related type definitions for the GHAGGA CLI.
|
|
3
|
+
*
|
|
4
|
+
* Used by git-hooks utilities, hook templates, and the hooks
|
|
5
|
+
* command group (install, uninstall, status).
|
|
6
|
+
*/
|
|
7
|
+
/** Marker comment identifying GHAGGA-managed hooks */
|
|
8
|
+
export const HOOK_MARKER = '# GHAGGA-MANAGED-HOOK — do not edit';
|
|
9
|
+
//# sourceMappingURL=hooks-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks-types.js","sourceRoot":"","sources":["../../src/lib/hooks-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,WAAW,GAAG,qCAAqC,CAAC"}
|
package/dist/lib/oauth.js
CHANGED
|
@@ -61,7 +61,7 @@ export async function pollForAccessToken(deviceCode, interval, expiresIn) {
|
|
|
61
61
|
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
62
62
|
}),
|
|
63
63
|
});
|
|
64
|
-
const data = await response.json();
|
|
64
|
+
const data = (await response.json());
|
|
65
65
|
// Check if we got a token
|
|
66
66
|
if ('access_token' in data && data.access_token) {
|
|
67
67
|
return data;
|
package/dist/lib/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/lib/oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AA8BvD,mEAAmE;AAEnE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,sCAAsC,EAAE;QACnE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,MAAM,EAAE,kBAAkB;YAC1B,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,SAAS,EAAE,gBAAgB;YAC3B,KAAK,EAAE,EAAE,EAAE,wDAAwD;SACpE,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAiC,CAAC;AACxD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAAkB,EAClB,QAAgB,EAChB,SAAiB;IAEjB,IAAI,eAAe,GAAG,QAAQ,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC;IAE/C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,gCAAgC;QAChC,MAAM,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,6CAA6C,EAAE;YAC1E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,SAAS,EAAE,gBAAgB;gBAC3B,WAAW,EAAE,UAAU;gBACvB,UAAU,EAAE,8CAA8C;aAC3D,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/lib/oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/oauth.test.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Tests requestDeviceCode(), pollForAccessToken(), and fetchGitHubUser()
|
|
5
5
|
* with mocked global fetch and fake timers for the polling loop.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
8
|
+
import { fetchGitHubUser, GITHUB_CLIENT_ID, pollForAccessToken, requestDeviceCode, } from './oauth.js';
|
|
9
9
|
// ─── Mock global fetch ──────────────────────────────────────────
|
|
10
10
|
const mockFetch = vi.fn();
|
|
11
11
|
vi.stubGlobal('fetch', mockFetch);
|
|
@@ -53,6 +53,7 @@ describe('requestDeviceCode', () => {
|
|
|
53
53
|
}),
|
|
54
54
|
}));
|
|
55
55
|
// Verify client_id is in the body
|
|
56
|
+
// biome-ignore lint/style/noNonNullAssertion: test assertion on known mock data
|
|
56
57
|
const callArgs = mockFetch.mock.calls[0];
|
|
57
58
|
const body = JSON.parse(callArgs[1].body);
|
|
58
59
|
expect(body.client_id).toBe(GITHUB_CLIENT_ID);
|
|
@@ -74,7 +75,7 @@ describe('pollForAccessToken', () => {
|
|
|
74
75
|
vi.useRealTimers();
|
|
75
76
|
});
|
|
76
77
|
// Helper: run pollForAccessToken and advance timers
|
|
77
|
-
async function
|
|
78
|
+
async function _runPoll(deviceCode = 'dc_123', interval = 1, expiresIn = 60) {
|
|
78
79
|
const promise = pollForAccessToken(deviceCode, interval, expiresIn);
|
|
79
80
|
// Advance through the initial sleep + poll cycles
|
|
80
81
|
// We need to flush several timer rounds
|