ghagga 3.0.0 → 3.2.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/dist/commands/login.test.js +0 -2
- package/dist/commands/login.test.js.map +1 -1
- package/dist/commands/memory/backfill.d.ts +13 -0
- package/dist/commands/memory/backfill.d.ts.map +1 -0
- package/dist/commands/memory/backfill.js +47 -0
- package/dist/commands/memory/backfill.js.map +1 -0
- package/dist/commands/memory/backfill.test.d.ts +11 -0
- package/dist/commands/memory/backfill.test.d.ts.map +1 -0
- package/dist/commands/memory/backfill.test.js +127 -0
- package/dist/commands/memory/backfill.test.js.map +1 -0
- package/dist/commands/memory/clear.test.js +9 -0
- package/dist/commands/memory/clear.test.js.map +1 -1
- package/dist/commands/memory/delete.test.js +9 -0
- package/dist/commands/memory/delete.test.js.map +1 -1
- package/dist/commands/memory/index.d.ts +3 -3
- package/dist/commands/memory/index.d.ts.map +1 -1
- package/dist/commands/memory/index.js +5 -3
- package/dist/commands/memory/index.js.map +1 -1
- package/dist/commands/memory/list.test.js +9 -0
- package/dist/commands/memory/list.test.js.map +1 -1
- package/dist/commands/memory/search.test.js +9 -0
- package/dist/commands/memory/search.test.js.map +1 -1
- package/dist/commands/memory/show.test.js +9 -0
- package/dist/commands/memory/show.test.js.map +1 -1
- package/dist/commands/memory/stats.test.js +9 -0
- 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 +14 -1
- package/dist/commands/memory/utils.js.map +1 -1
- package/dist/commands/review-output.test.js +37 -0
- package/dist/commands/review-output.test.js.map +1 -1
- package/dist/commands/review.d.ts +12 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +239 -5
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/review.mr-exit.test.d.ts +13 -0
- package/dist/commands/review.mr-exit.test.d.ts.map +1 -0
- package/dist/commands/review.mr-exit.test.js +190 -0
- package/dist/commands/review.mr-exit.test.js.map +1 -0
- package/dist/commands/review.postback-disclosure.test.d.ts +22 -0
- package/dist/commands/review.postback-disclosure.test.d.ts.map +1 -0
- package/dist/commands/review.postback-disclosure.test.js +192 -0
- package/dist/commands/review.postback-disclosure.test.js.map +1 -0
- package/dist/commands/review.pr-exit.test.d.ts +13 -0
- package/dist/commands/review.pr-exit.test.d.ts.map +1 -0
- package/dist/commands/review.pr-exit.test.js +162 -0
- package/dist/commands/review.pr-exit.test.js.map +1 -0
- package/dist/commands/review.pr-jenkins.test.d.ts +16 -0
- package/dist/commands/review.pr-jenkins.test.d.ts.map +1 -0
- package/dist/commands/review.pr-jenkins.test.js +106 -0
- package/dist/commands/review.pr-jenkins.test.js.map +1 -0
- package/dist/commands/review.pr-nativeid-fallback.test.d.ts +15 -0
- package/dist/commands/review.pr-nativeid-fallback.test.d.ts.map +1 -0
- package/dist/commands/review.pr-nativeid-fallback.test.js +151 -0
- package/dist/commands/review.pr-nativeid-fallback.test.js.map +1 -0
- package/dist/commands/review.test.js +13 -0
- package/dist/commands/review.test.js.map +1 -1
- package/dist/index.js +39 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/cli-github-client-port.d.ts +52 -0
- package/dist/lib/cli-github-client-port.d.ts.map +1 -0
- package/dist/lib/cli-github-client-port.js +199 -0
- package/dist/lib/cli-github-client-port.js.map +1 -0
- package/dist/lib/cli-github-client-port.test.d.ts +10 -0
- package/dist/lib/cli-github-client-port.test.d.ts.map +1 -0
- package/dist/lib/cli-github-client-port.test.js +47 -0
- package/dist/lib/cli-github-client-port.test.js.map +1 -0
- package/dist/lib/cli-gitlab-client-port.d.ts +62 -0
- package/dist/lib/cli-gitlab-client-port.d.ts.map +1 -0
- package/dist/lib/cli-gitlab-client-port.js +209 -0
- package/dist/lib/cli-gitlab-client-port.js.map +1 -0
- package/dist/lib/cli-gitlab-client-port.test.d.ts +9 -0
- package/dist/lib/cli-gitlab-client-port.test.d.ts.map +1 -0
- package/dist/lib/cli-gitlab-client-port.test.js +292 -0
- package/dist/lib/cli-gitlab-client-port.test.js.map +1 -0
- package/dist/lib/config.d.ts +23 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +9 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/embedding.d.ts +23 -0
- package/dist/lib/embedding.d.ts.map +1 -0
- package/dist/lib/embedding.js +39 -0
- package/dist/lib/embedding.js.map +1 -0
- package/dist/lib/embedding.test.d.ts +8 -0
- package/dist/lib/embedding.test.d.ts.map +1 -0
- package/dist/lib/embedding.test.js +101 -0
- package/dist/lib/embedding.test.js.map +1 -0
- package/dist/lib/forge-postback.d.ts +72 -0
- package/dist/lib/forge-postback.d.ts.map +1 -0
- package/dist/lib/forge-postback.js +39 -0
- package/dist/lib/forge-postback.js.map +1 -0
- package/dist/lib/gitlab-api.d.ts +50 -0
- package/dist/lib/gitlab-api.d.ts.map +1 -0
- package/dist/lib/gitlab-api.js +75 -0
- package/dist/lib/gitlab-api.js.map +1 -0
- package/dist/lib/gitlab-api.test.d.ts +2 -0
- package/dist/lib/gitlab-api.test.d.ts.map +1 -0
- package/dist/lib/gitlab-api.test.js +79 -0
- package/dist/lib/gitlab-api.test.js.map +1 -0
- package/dist/lib/gitlab-e2e.manual.test.d.ts +57 -0
- package/dist/lib/gitlab-e2e.manual.test.d.ts.map +1 -0
- package/dist/lib/gitlab-e2e.manual.test.js +135 -0
- package/dist/lib/gitlab-e2e.manual.test.js.map +1 -0
- package/dist/lib/gitlab-token.d.ts +17 -0
- package/dist/lib/gitlab-token.d.ts.map +1 -0
- package/dist/lib/gitlab-token.js +24 -0
- package/dist/lib/gitlab-token.js.map +1 -0
- package/dist/lib/gitlab-token.test.d.ts +2 -0
- package/dist/lib/gitlab-token.test.d.ts.map +1 -0
- package/dist/lib/gitlab-token.test.js +38 -0
- package/dist/lib/gitlab-token.test.js.map +1 -0
- package/dist/lib/oauth.test.js +0 -1
- package/dist/lib/oauth.test.js.map +1 -1
- package/dist/lib/pr-postback.d.ts +42 -0
- package/dist/lib/pr-postback.d.ts.map +1 -0
- package/dist/lib/pr-postback.js +44 -0
- package/dist/lib/pr-postback.js.map +1 -0
- package/dist/lib/pr-postback.test.d.ts +9 -0
- package/dist/lib/pr-postback.test.d.ts.map +1 -0
- package/dist/lib/pr-postback.test.js +212 -0
- package/dist/lib/pr-postback.test.js.map +1 -0
- package/dist/lib/pr-token.d.ts +15 -0
- package/dist/lib/pr-token.d.ts.map +1 -0
- package/dist/lib/pr-token.js +22 -0
- package/dist/lib/pr-token.js.map +1 -0
- package/dist/lib/pr-token.test.d.ts +2 -0
- package/dist/lib/pr-token.test.d.ts.map +1 -0
- package/dist/lib/pr-token.test.js +25 -0
- package/dist/lib/pr-token.test.js.map +1 -0
- package/package.json +9 -8
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R-GITLAB / R-LEAK-PUBLISH: the `--mr` post-back routes through the REAL
|
|
3
|
+
* GitLabForgeAdapter folding over the CLI's own GitLabClientPort. We mock ONLY
|
|
4
|
+
* `fetch` (the network seam), so this exercises the genuine adapter
|
|
5
|
+
* find→delete→repost idempotency AND the genuine CLI port REST calls — a
|
|
6
|
+
* faithful simulation against a mocked GitLab.
|
|
7
|
+
*/
|
|
8
|
+
import { GitLabForgeAdapter } from 'ghagga-forge';
|
|
9
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
10
|
+
import { createCliGitLabClientPort, resolveGitLabApiBase, resolveGitLabProjectId, } from './cli-gitlab-client-port.js';
|
|
11
|
+
import { postSummaryComment } from './pr-postback.js';
|
|
12
|
+
const mockFetch = vi.fn();
|
|
13
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
14
|
+
function jsonResponse(status, body) {
|
|
15
|
+
return {
|
|
16
|
+
ok: status >= 200 && status < 300,
|
|
17
|
+
status,
|
|
18
|
+
statusText: status === 200 ? 'OK' : status === 201 ? 'Created' : 'ERR',
|
|
19
|
+
text: () => Promise.resolve(JSON.stringify(body)),
|
|
20
|
+
json: () => Promise.resolve(body),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const MARKER = { html: '<!-- ghagga-review -->' };
|
|
24
|
+
const PROJECT_ID = '12345';
|
|
25
|
+
const REF = {
|
|
26
|
+
repo: { kind: 'gitlab', nativeId: PROJECT_ID, path: 'acme/widgets' },
|
|
27
|
+
iid: 7,
|
|
28
|
+
};
|
|
29
|
+
function buildAdapter(token = 'glpat') {
|
|
30
|
+
return new GitLabForgeAdapter({
|
|
31
|
+
client: createCliGitLabClientPort(),
|
|
32
|
+
token,
|
|
33
|
+
projectId: PROJECT_ID,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
describe('resolveGitLabProjectId (numeric project id resolution, R-GITLAB)', () => {
|
|
37
|
+
beforeEach(() => mockFetch.mockReset());
|
|
38
|
+
it('GET /projects/:url-encoded-path → numeric id as string', async () => {
|
|
39
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 12345, path_with_namespace: 'acme/widgets' }));
|
|
40
|
+
const id = await resolveGitLabProjectId('acme/widgets', 'glpat');
|
|
41
|
+
expect(id).toBe('12345');
|
|
42
|
+
const [url] = mockFetch.mock.calls[0];
|
|
43
|
+
// path is URL-encoded (nested-group safe).
|
|
44
|
+
expect(url).toBe('https://gitlab.com/api/v4/projects/acme%2Fwidgets');
|
|
45
|
+
});
|
|
46
|
+
it('URL-encodes nested-group paths', async () => {
|
|
47
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 99 }));
|
|
48
|
+
await resolveGitLabProjectId('group/subgroup/project', 'glpat');
|
|
49
|
+
const [url] = mockFetch.mock.calls[0];
|
|
50
|
+
expect(url).toContain('projects/group%2Fsubgroup%2Fproject');
|
|
51
|
+
});
|
|
52
|
+
it('throws on a non-ok response', async () => {
|
|
53
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(404, { message: '404 Project Not Found' }));
|
|
54
|
+
await expect(resolveGitLabProjectId('nope/nope', 'glpat')).rejects.toThrow(/resolving project id/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('postSummaryComment via CLI GitLab port + GitLabForgeAdapter', () => {
|
|
58
|
+
beforeEach(() => mockFetch.mockReset());
|
|
59
|
+
it('creates a fresh note when none exists (no stale to delete)', async () => {
|
|
60
|
+
// listMrNotes: empty
|
|
61
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, []));
|
|
62
|
+
// createMrNote → { id }
|
|
63
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(201, { id: 9001 }));
|
|
64
|
+
const adapter = buildAdapter();
|
|
65
|
+
const body = `${MARKER.html}\n## body`;
|
|
66
|
+
const result = await postSummaryComment(adapter, REF, body, MARKER);
|
|
67
|
+
expect(result.createdNativeId).toBe(9001);
|
|
68
|
+
expect(result.deletedNativeIds).toEqual([]);
|
|
69
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
70
|
+
const [listUrl] = mockFetch.mock.calls[0];
|
|
71
|
+
expect(listUrl).toContain('/projects/12345/merge_requests/7/notes');
|
|
72
|
+
const [postUrl, postInit] = mockFetch.mock.calls[1];
|
|
73
|
+
expect(postUrl).toBe('https://gitlab.com/api/v4/projects/12345/merge_requests/7/notes');
|
|
74
|
+
expect(postInit.method).toBe('POST');
|
|
75
|
+
expect(JSON.parse(postInit.body)).toEqual({ body });
|
|
76
|
+
});
|
|
77
|
+
it('finds stale by marker → updates latest IN PLACE → prunes only stale duplicates (idempotent upsert)', async () => {
|
|
78
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, [
|
|
79
|
+
{ id: 100, body: `old ${MARKER.html}` },
|
|
80
|
+
{ id: 200, body: 'someone else' },
|
|
81
|
+
{ id: 300, body: `newer ${MARKER.html}` },
|
|
82
|
+
]));
|
|
83
|
+
// FORGE-UPSERT-005: updateMrNote(latest=300) IN PLACE (PUT) first...
|
|
84
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 300 }));
|
|
85
|
+
// ...then delete stale=100 only after the update confirms success.
|
|
86
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(204, {}));
|
|
87
|
+
const adapter = buildAdapter();
|
|
88
|
+
const result = await postSummaryComment(adapter, REF, 'body', MARKER);
|
|
89
|
+
// "created" now carries the updated latest note (300), not a freshly created one.
|
|
90
|
+
expect(result.createdNativeId).toBe(300);
|
|
91
|
+
// The latest (300) is updated, never deleted; only the stale duplicate (100) is pruned.
|
|
92
|
+
expect(result.deletedNativeIds).toEqual([100]);
|
|
93
|
+
// Update happens in place (PUT) on the latest, before any delete.
|
|
94
|
+
const updateCall = mockFetch.mock.calls[1];
|
|
95
|
+
expect(updateCall[0]).toContain('/notes/300');
|
|
96
|
+
expect(updateCall[1].method).toBe('PUT');
|
|
97
|
+
expect(JSON.parse(updateCall[1].body)).toEqual({ body: 'body' });
|
|
98
|
+
const del = mockFetch.mock.calls[2];
|
|
99
|
+
expect(del[0]).toContain('/notes/100');
|
|
100
|
+
expect(del[1].method).toBe('DELETE');
|
|
101
|
+
// The latest (300) is never the target of a DELETE.
|
|
102
|
+
const deleteUrls = mockFetch.mock.calls
|
|
103
|
+
.filter((c) => c[1].method === 'DELETE')
|
|
104
|
+
.map((c) => c[0]);
|
|
105
|
+
expect(deleteUrls.some((u) => u.includes('/notes/300'))).toBe(false);
|
|
106
|
+
// foreign note 200 never touched; no fresh POST on the replace path.
|
|
107
|
+
const allUrls = mockFetch.mock.calls.map((c) => c[0]).join('\n');
|
|
108
|
+
expect(allUrls).not.toContain('/notes/200');
|
|
109
|
+
const methods = mockFetch.mock.calls.map((c) => c[1].method);
|
|
110
|
+
expect(methods).not.toContain('POST');
|
|
111
|
+
});
|
|
112
|
+
it('sends ONLY PRIVATE-TOKEN (no Bearer) + an AbortSignal (FIX E)', async () => {
|
|
113
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, []));
|
|
114
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(201, { id: 1 }));
|
|
115
|
+
const adapter = buildAdapter('secret-pat');
|
|
116
|
+
await postSummaryComment(adapter, REF, 'body', MARKER);
|
|
117
|
+
const [, postInit] = mockFetch.mock.calls[1];
|
|
118
|
+
const headers = postInit.headers;
|
|
119
|
+
expect(headers['PRIVATE-TOKEN']).toBe('secret-pat');
|
|
120
|
+
expect(headers.Authorization).toBeUndefined();
|
|
121
|
+
for (const call of mockFetch.mock.calls) {
|
|
122
|
+
expect(call[1].signal).toBeInstanceOf(AbortSignal);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
it('a 401 with the static PAT is fatal (no retry loop)', async () => {
|
|
126
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(401, { message: '401 Unauthorized' }));
|
|
127
|
+
const adapter = buildAdapter();
|
|
128
|
+
await expect(postSummaryComment(adapter, REF, 'body', MARKER)).rejects.toThrow();
|
|
129
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe('CLI GitLab port — publishInline partial failure end-to-end (R-LEAK-PUBLISH)', () => {
|
|
133
|
+
beforeEach(() => mockFetch.mockReset());
|
|
134
|
+
it('5 inline notes, 3 fail (500) → posted 2, failed 3, never aborts', async () => {
|
|
135
|
+
// create calls in order: ok, 500, 500, ok, 500
|
|
136
|
+
mockFetch
|
|
137
|
+
.mockResolvedValueOnce(jsonResponse(201, { id: 11 }))
|
|
138
|
+
.mockResolvedValueOnce(jsonResponse(500, { message: 'boom' }))
|
|
139
|
+
.mockResolvedValueOnce(jsonResponse(500, { message: 'boom' }))
|
|
140
|
+
.mockResolvedValueOnce(jsonResponse(201, { id: 14 }))
|
|
141
|
+
.mockResolvedValueOnce(jsonResponse(500, { message: 'boom' }));
|
|
142
|
+
const adapter = buildAdapter();
|
|
143
|
+
const report = await adapter.publishInline(REF, [
|
|
144
|
+
{ path: 'a.ts', line: 1, body: 'c0' },
|
|
145
|
+
{ path: 'b.ts', line: 2, body: 'c1' },
|
|
146
|
+
{ path: 'c.ts', line: 3, body: 'c2' },
|
|
147
|
+
{ path: 'd.ts', line: 4, body: 'c3' },
|
|
148
|
+
{ path: 'e.ts', line: 5, body: 'c4' },
|
|
149
|
+
]);
|
|
150
|
+
expect(report.posted).toEqual([
|
|
151
|
+
{ kind: 'gitlab', raw: '11' },
|
|
152
|
+
{ kind: 'gitlab', raw: '14' },
|
|
153
|
+
]);
|
|
154
|
+
expect(report.failed.map((f) => f.index)).toEqual([1, 2, 4]);
|
|
155
|
+
expect(mockFetch).toHaveBeenCalledTimes(5);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe('resolveGitLabApiBase (FIX A — derive API base from host + env overrides)', () => {
|
|
159
|
+
it('defaults to https://<host>/api/v4 for the parsed remote host', () => {
|
|
160
|
+
expect(resolveGitLabApiBase('gitlab.com', {})).toBe('https://gitlab.com/api/v4');
|
|
161
|
+
expect(resolveGitLabApiBase('gitlab.example.com', {})).toBe('https://gitlab.example.com/api/v4');
|
|
162
|
+
});
|
|
163
|
+
it('GITLAB_HOST overrides the remote host', () => {
|
|
164
|
+
expect(resolveGitLabApiBase('gitlab.com', { GITLAB_HOST: 'api.internal' })).toBe('https://api.internal/api/v4');
|
|
165
|
+
});
|
|
166
|
+
it('GITLAB_API_BASE is a full override (subpath self-hosted)', () => {
|
|
167
|
+
expect(resolveGitLabApiBase('gitlab.com', {
|
|
168
|
+
GITLAB_API_BASE: 'https://example.com/gitlab/api/v4',
|
|
169
|
+
})).toBe('https://example.com/gitlab/api/v4');
|
|
170
|
+
});
|
|
171
|
+
it('GITLAB_API_BASE wins over GITLAB_HOST + trims trailing slash', () => {
|
|
172
|
+
expect(resolveGitLabApiBase('gitlab.com', {
|
|
173
|
+
GITLAB_HOST: 'ignored.example',
|
|
174
|
+
GITLAB_API_BASE: 'https://example.com/gitlab/api/v4/',
|
|
175
|
+
})).toBe('https://example.com/gitlab/api/v4');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
describe('CLI GitLab port — self-hosted API base (FIX A)', () => {
|
|
179
|
+
beforeEach(() => mockFetch.mockReset());
|
|
180
|
+
function buildSelfHostedAdapter() {
|
|
181
|
+
return new GitLabForgeAdapter({
|
|
182
|
+
client: createCliGitLabClientPort('https://gitlab.example.com/api/v4'),
|
|
183
|
+
token: 'glpat',
|
|
184
|
+
projectId: PROJECT_ID,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
it('routes note calls + project-id resolution against the self-hosted host', async () => {
|
|
188
|
+
// resolveGitLabProjectId against the self-hosted base.
|
|
189
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 12345 }));
|
|
190
|
+
const id = await resolveGitLabProjectId('team/repo', 'glpat', 'https://gitlab.example.com/api/v4');
|
|
191
|
+
expect(id).toBe('12345');
|
|
192
|
+
const [idUrl] = mockFetch.mock.calls[0];
|
|
193
|
+
expect(idUrl).toBe('https://gitlab.example.com/api/v4/projects/team%2Frepo');
|
|
194
|
+
mockFetch.mockReset();
|
|
195
|
+
// upsert against the self-hosted base.
|
|
196
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, []));
|
|
197
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(201, { id: 9001 }));
|
|
198
|
+
const adapter = buildSelfHostedAdapter();
|
|
199
|
+
await postSummaryComment(adapter, REF, 'body', MARKER);
|
|
200
|
+
const [postUrl, postInit] = mockFetch.mock.calls[1];
|
|
201
|
+
expect(postUrl).toBe('https://gitlab.example.com/api/v4/projects/12345/merge_requests/7/notes');
|
|
202
|
+
// PRIVATE-TOKEN only.
|
|
203
|
+
const headers = postInit.headers;
|
|
204
|
+
expect(headers['PRIVATE-TOKEN']).toBe('glpat');
|
|
205
|
+
expect(headers.Authorization).toBeUndefined();
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe('CLI GitLab port — listMrNotes pagination (backlog #6)', () => {
|
|
209
|
+
beforeEach(() => mockFetch.mockReset());
|
|
210
|
+
function makeNotes(count, startId = 0, markerAt) {
|
|
211
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
212
|
+
id: startId + i,
|
|
213
|
+
body: i === markerAt ? `summary ${startId + i} ${MARKER.html}` : `noise ${startId + i}`,
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
it('single page (< 100 notes) → exactly one list call, no extra fetch', async () => {
|
|
217
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, makeNotes(20, 0)));
|
|
218
|
+
const port = createCliGitLabClientPort();
|
|
219
|
+
const notes = await port.listMrNotes('12345', 7, 'glpat');
|
|
220
|
+
expect(notes).toHaveLength(20);
|
|
221
|
+
expect(mockFetch).toHaveBeenCalledTimes(1);
|
|
222
|
+
const [url] = mockFetch.mock.calls[0];
|
|
223
|
+
expect(url).toContain('page=1');
|
|
224
|
+
});
|
|
225
|
+
it('multi-page → full page 1 forces page 2 fetch; stale-on-page-2 found + updated in place (no duplicate)', async () => {
|
|
226
|
+
// page 1: 100 notes, NO marker → must fetch page 2; page 2 carries the sole marker.
|
|
227
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, makeNotes(100, 0)));
|
|
228
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, makeNotes(15, 100, 5))); // marker id 105
|
|
229
|
+
// FORGE-UPSERT-005: single GHAGGA note → update it in place (PUT), nothing to prune.
|
|
230
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, { id: 105 })); // update 105
|
|
231
|
+
const adapter = buildAdapter();
|
|
232
|
+
const result = await postSummaryComment(adapter, REF, 'body', MARKER);
|
|
233
|
+
// Sole note (105) is updated in place: it carries the body, nothing is deleted.
|
|
234
|
+
expect(result.deletedNativeIds).toEqual([]);
|
|
235
|
+
expect(result.createdNativeId).toBe(105);
|
|
236
|
+
// page 1 + page 2 list calls happened.
|
|
237
|
+
expect(mockFetch.mock.calls[0][0]).toContain('page=1');
|
|
238
|
+
expect(mockFetch.mock.calls[1][0]).toContain('page=2');
|
|
239
|
+
const updateCall = mockFetch.mock.calls[2];
|
|
240
|
+
expect(updateCall[0]).toContain('/notes/105');
|
|
241
|
+
expect(updateCall[1].method).toBe('PUT');
|
|
242
|
+
// No DELETE and no POST — the sole note is updated, not replaced.
|
|
243
|
+
const methods = mockFetch.mock.calls.map((c) => c[1].method);
|
|
244
|
+
expect(methods).not.toContain('DELETE');
|
|
245
|
+
expect(methods).not.toContain('POST');
|
|
246
|
+
});
|
|
247
|
+
it('safety bound → stops at MAX_PAGES (50) and warns instead of looping forever', async () => {
|
|
248
|
+
for (let page = 0; page < 50; page++) {
|
|
249
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(200, makeNotes(100, page * 100)));
|
|
250
|
+
}
|
|
251
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
252
|
+
const port = createCliGitLabClientPort();
|
|
253
|
+
const notes = await port.listMrNotes('12345', 7, 'glpat');
|
|
254
|
+
expect(notes).toHaveLength(5000);
|
|
255
|
+
expect(mockFetch).toHaveBeenCalledTimes(50);
|
|
256
|
+
expect(mockFetch.mock.calls[49][0]).toContain('page=50');
|
|
257
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('MAX_PAGES (50)'));
|
|
258
|
+
warnSpy.mockRestore();
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
describe('CLI GitLab port — createMrDiscussion (FIX C true positioning)', () => {
|
|
262
|
+
beforeEach(() => mockFetch.mockReset());
|
|
263
|
+
it('posts a positioned inline comment to /discussions and boxes notes[0].id', async () => {
|
|
264
|
+
mockFetch.mockResolvedValueOnce(jsonResponse(201, { id: 'disc-1', notes: [{ id: 555 }] }));
|
|
265
|
+
const adapter = buildAdapter();
|
|
266
|
+
const report = await adapter.publishInline(REF, [
|
|
267
|
+
{
|
|
268
|
+
path: 'src/x.ts',
|
|
269
|
+
line: 4,
|
|
270
|
+
side: 'new',
|
|
271
|
+
body: 'anchored',
|
|
272
|
+
position: { baseSha: 'B', headSha: 'H', startSha: 'S', newLine: 4 },
|
|
273
|
+
},
|
|
274
|
+
]);
|
|
275
|
+
expect(report.posted).toEqual([{ kind: 'gitlab', raw: '555' }]);
|
|
276
|
+
const [discUrl, discInit] = mockFetch.mock.calls[0];
|
|
277
|
+
expect(discUrl).toBe('https://gitlab.com/api/v4/projects/12345/merge_requests/7/discussions');
|
|
278
|
+
expect(discInit.method).toBe('POST');
|
|
279
|
+
const payload = JSON.parse(discInit.body);
|
|
280
|
+
expect(payload.body).toBe('anchored');
|
|
281
|
+
expect(payload.position).toEqual({
|
|
282
|
+
position_type: 'text',
|
|
283
|
+
base_sha: 'B',
|
|
284
|
+
head_sha: 'H',
|
|
285
|
+
start_sha: 'S',
|
|
286
|
+
old_path: 'src/x.ts',
|
|
287
|
+
new_path: 'src/x.ts',
|
|
288
|
+
new_line: 4,
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
//# sourceMappingURL=cli-gitlab-client-port.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-gitlab-client-port.test.js","sourceRoot":"","sources":["../../src/lib/cli-gitlab-client-port.test.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -9,10 +9,27 @@ export interface GhaggaCliConfig {
|
|
|
9
9
|
githubToken?: string;
|
|
10
10
|
/** GitHub username (fetched after login) */
|
|
11
11
|
githubLogin?: string;
|
|
12
|
+
/**
|
|
13
|
+
* GitLab Personal/Project/Group Access Token (PAT). SEPARATE from the GitHub
|
|
14
|
+
* token: a GitHub token MUST NOT be used against GitLab. Resolved by the `--mr`
|
|
15
|
+
* post-back AFTER env GITLAB_TOKEN / GL_TOKEN.
|
|
16
|
+
*/
|
|
17
|
+
gitlabToken?: string;
|
|
12
18
|
/** Default LLM provider */
|
|
13
19
|
defaultProvider?: string;
|
|
14
20
|
/** Default model for the provider */
|
|
15
21
|
defaultModel?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Embedding provider config overrides (design D2). Config-file keys take
|
|
24
|
+
* precedence over the matching `EMBEDDING_*` env vars — see
|
|
25
|
+
* `resolveCliEmbeddingConfig` in `./embedding.js`.
|
|
26
|
+
*/
|
|
27
|
+
embeddingProvider?: string;
|
|
28
|
+
embeddingModel?: string;
|
|
29
|
+
embeddingBaseUrl?: string;
|
|
30
|
+
embeddingApiKey?: string;
|
|
31
|
+
embeddingDimension?: number;
|
|
32
|
+
embeddingCandidateK?: number;
|
|
16
33
|
}
|
|
17
34
|
export declare function getConfigDir(): string;
|
|
18
35
|
/**
|
|
@@ -35,6 +52,12 @@ export declare function isLoggedIn(): boolean;
|
|
|
35
52
|
* Get the stored GitHub token, or null if not logged in.
|
|
36
53
|
*/
|
|
37
54
|
export declare function getStoredToken(): string | null;
|
|
55
|
+
/**
|
|
56
|
+
* Get the stored GitLab token, or null if none. SEPARATE from
|
|
57
|
+
* {@link getStoredToken} (GitHub): the `--mr` post-back must never authenticate
|
|
58
|
+
* to GitLab with a GitHub token.
|
|
59
|
+
*/
|
|
60
|
+
export declare function getStoredGitLabToken(): string | null;
|
|
38
61
|
/**
|
|
39
62
|
* Get the config file path (for display in status/error messages).
|
|
40
63
|
*/
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2BAA2B;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAID,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAQD;;GAEG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAa5C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAYxD;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;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAGpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
|
package/dist/lib/config.js
CHANGED
|
@@ -67,6 +67,15 @@ export function getStoredToken() {
|
|
|
67
67
|
const config = loadConfig();
|
|
68
68
|
return config.githubToken ?? null;
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the stored GitLab token, or null if none. SEPARATE from
|
|
72
|
+
* {@link getStoredToken} (GitHub): the `--mr` post-back must never authenticate
|
|
73
|
+
* to GitLab with a GitHub token.
|
|
74
|
+
*/
|
|
75
|
+
export function getStoredGitLabToken() {
|
|
76
|
+
const config = loadConfig();
|
|
77
|
+
return config.gitlabToken ?? null;
|
|
78
|
+
}
|
|
70
79
|
/**
|
|
71
80
|
* Get the config file path (for display in status/error messages).
|
|
72
81
|
*/
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +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,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
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,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqCjC,mEAAmE;AAEnE,MAAM,UAAU,YAAY;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAC9C,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,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,aAAa,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QAChE,QAAQ,EAAE,OAAO;QACjB,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,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;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,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,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI embedding provider resolution (design D2, task 5.2).
|
|
3
|
+
*
|
|
4
|
+
* Merges the `EMBEDDING_*` keys stored in `~/.config/ghagga/config.json`
|
|
5
|
+
* over `process.env` before delegating to `resolveEmbeddingConfig` /
|
|
6
|
+
* `createEmbeddingProvider` from `ghagga-core` — the same resolver every
|
|
7
|
+
* construction site (server, CLI, Action) shares. Config-file values win
|
|
8
|
+
* over env so `ghagga login`-style persisted preferences aren't shadowed
|
|
9
|
+
* by ambient env vars.
|
|
10
|
+
*/
|
|
11
|
+
import type { EmbeddingConfig, EmbeddingProvider } from 'ghagga-core';
|
|
12
|
+
/** Resolve the merged embedding config (config-file over env, design D2). */
|
|
13
|
+
export declare function resolveCliEmbeddingConfig(): EmbeddingConfig;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the merged config AND build the concrete provider in one call —
|
|
16
|
+
* the common case for every SqliteMemoryStorage construction site.
|
|
17
|
+
* Returns `provider: undefined` when unconfigured (`none`-default parity).
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveCliEmbeddingProvider(): {
|
|
20
|
+
config: EmbeddingConfig;
|
|
21
|
+
provider: EmbeddingProvider | undefined;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=embedding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../src/lib/embedding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAItE,6EAA6E;AAC7E,wBAAgB,yBAAyB,IAAI,eAAe,CAmB3D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI;IAC7C,MAAM,EAAE,eAAe,CAAC;IACxB,QAAQ,EAAE,iBAAiB,GAAG,SAAS,CAAC;CACzC,CAGA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI embedding provider resolution (design D2, task 5.2).
|
|
3
|
+
*
|
|
4
|
+
* Merges the `EMBEDDING_*` keys stored in `~/.config/ghagga/config.json`
|
|
5
|
+
* over `process.env` before delegating to `resolveEmbeddingConfig` /
|
|
6
|
+
* `createEmbeddingProvider` from `ghagga-core` — the same resolver every
|
|
7
|
+
* construction site (server, CLI, Action) shares. Config-file values win
|
|
8
|
+
* over env so `ghagga login`-style persisted preferences aren't shadowed
|
|
9
|
+
* by ambient env vars.
|
|
10
|
+
*/
|
|
11
|
+
import { createEmbeddingProvider, resolveEmbeddingConfig } from 'ghagga-core';
|
|
12
|
+
import { loadConfig } from './config.js';
|
|
13
|
+
/** Resolve the merged embedding config (config-file over env, design D2). */
|
|
14
|
+
export function resolveCliEmbeddingConfig() {
|
|
15
|
+
const fileConfig = loadConfig();
|
|
16
|
+
const merged = {
|
|
17
|
+
EMBEDDING_PROVIDER: fileConfig.embeddingProvider ?? process.env.EMBEDDING_PROVIDER,
|
|
18
|
+
EMBEDDING_MODEL: fileConfig.embeddingModel ?? process.env.EMBEDDING_MODEL,
|
|
19
|
+
EMBEDDING_BASE_URL: fileConfig.embeddingBaseUrl ?? process.env.EMBEDDING_BASE_URL,
|
|
20
|
+
EMBEDDING_API_KEY: fileConfig.embeddingApiKey ?? process.env.EMBEDDING_API_KEY,
|
|
21
|
+
EMBEDDING_DIMENSION: fileConfig.embeddingDimension !== undefined
|
|
22
|
+
? String(fileConfig.embeddingDimension)
|
|
23
|
+
: process.env.EMBEDDING_DIMENSION,
|
|
24
|
+
EMBEDDING_CANDIDATE_K: fileConfig.embeddingCandidateK !== undefined
|
|
25
|
+
? String(fileConfig.embeddingCandidateK)
|
|
26
|
+
: process.env.EMBEDDING_CANDIDATE_K,
|
|
27
|
+
};
|
|
28
|
+
return resolveEmbeddingConfig(merged);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve the merged config AND build the concrete provider in one call —
|
|
32
|
+
* the common case for every SqliteMemoryStorage construction site.
|
|
33
|
+
* Returns `provider: undefined` when unconfigured (`none`-default parity).
|
|
34
|
+
*/
|
|
35
|
+
export function resolveCliEmbeddingProvider() {
|
|
36
|
+
const config = resolveCliEmbeddingConfig();
|
|
37
|
+
return { config, provider: createEmbeddingProvider(config) ?? undefined };
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/lib/embedding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,6EAA6E;AAC7E,MAAM,UAAU,yBAAyB;IACvC,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;IAEhC,MAAM,MAAM,GAAuC;QACjD,kBAAkB,EAAE,UAAU,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAClF,eAAe,EAAE,UAAU,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;QACzE,kBAAkB,EAAE,UAAU,CAAC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QACjF,iBAAiB,EAAE,UAAU,CAAC,eAAe,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC9E,mBAAmB,EACjB,UAAU,CAAC,kBAAkB,KAAK,SAAS;YACzC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC;YACvC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB;QACrC,qBAAqB,EACnB,UAAU,CAAC,mBAAmB,KAAK,SAAS;YAC1C,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC;YACxC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB;KACxC,CAAC;IAEF,OAAO,sBAAsB,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IAIzC,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAC;IAC3C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB,CAAC,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CLI embedding provider resolution (design D2, task 5.2/5.4).
|
|
3
|
+
*
|
|
4
|
+
* Mocks `./config.js` (loadConfig) to isolate the merge-precedence logic:
|
|
5
|
+
* config-file keys override the matching `EMBEDDING_*` env vars.
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=embedding.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.test.d.ts","sourceRoot":"","sources":["../../src/lib/embedding.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for CLI embedding provider resolution (design D2, task 5.2/5.4).
|
|
3
|
+
*
|
|
4
|
+
* Mocks `./config.js` (loadConfig) to isolate the merge-precedence logic:
|
|
5
|
+
* config-file keys override the matching `EMBEDDING_*` env vars.
|
|
6
|
+
*/
|
|
7
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
8
|
+
const { mockLoadConfig } = vi.hoisted(() => ({
|
|
9
|
+
mockLoadConfig: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
vi.mock('./config.js', () => ({
|
|
12
|
+
loadConfig: () => mockLoadConfig(),
|
|
13
|
+
}));
|
|
14
|
+
import { resolveCliEmbeddingConfig, resolveCliEmbeddingProvider } from './embedding.js';
|
|
15
|
+
const ENV_KEYS = [
|
|
16
|
+
'EMBEDDING_PROVIDER',
|
|
17
|
+
'EMBEDDING_MODEL',
|
|
18
|
+
'EMBEDDING_BASE_URL',
|
|
19
|
+
'EMBEDDING_API_KEY',
|
|
20
|
+
'EMBEDDING_DIMENSION',
|
|
21
|
+
'EMBEDDING_CANDIDATE_K',
|
|
22
|
+
];
|
|
23
|
+
let originalEnv;
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.clearAllMocks();
|
|
26
|
+
mockLoadConfig.mockReturnValue({});
|
|
27
|
+
originalEnv = {};
|
|
28
|
+
for (const key of ENV_KEYS) {
|
|
29
|
+
originalEnv[key] = process.env[key];
|
|
30
|
+
delete process.env[key];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
for (const key of ENV_KEYS) {
|
|
35
|
+
if (originalEnv[key] === undefined) {
|
|
36
|
+
delete process.env[key];
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
process.env[key] = originalEnv[key];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
describe('resolveCliEmbeddingConfig', () => {
|
|
44
|
+
it('resolves to "none" when neither config file nor env is set', () => {
|
|
45
|
+
const config = resolveCliEmbeddingConfig();
|
|
46
|
+
expect(config.provider).toBe('none');
|
|
47
|
+
expect(config.candidateK).toBe(200);
|
|
48
|
+
expect(config.model).toBeUndefined();
|
|
49
|
+
});
|
|
50
|
+
it('falls back to env when the config file has no embedding keys', () => {
|
|
51
|
+
process.env.EMBEDDING_PROVIDER = 'openai-compatible';
|
|
52
|
+
process.env.EMBEDDING_MODEL = 'text-embedding-3-small';
|
|
53
|
+
process.env.EMBEDDING_BASE_URL = 'https://api.openai.com/v1';
|
|
54
|
+
process.env.EMBEDDING_DIMENSION = '1536';
|
|
55
|
+
const config = resolveCliEmbeddingConfig();
|
|
56
|
+
expect(config.provider).toBe('openai-compatible');
|
|
57
|
+
expect(config.model).toBe('text-embedding-3-small');
|
|
58
|
+
expect(config.dimension).toBe(1536);
|
|
59
|
+
});
|
|
60
|
+
it('prefers config-file values over env (design D2 precedence)', () => {
|
|
61
|
+
process.env.EMBEDDING_PROVIDER = 'openai-compatible';
|
|
62
|
+
process.env.EMBEDDING_MODEL = 'env-model';
|
|
63
|
+
mockLoadConfig.mockReturnValue({
|
|
64
|
+
embeddingProvider: 'openai-compatible',
|
|
65
|
+
embeddingModel: 'config-file-model',
|
|
66
|
+
embeddingBaseUrl: 'https://api.example.com/v1',
|
|
67
|
+
embeddingDimension: 768,
|
|
68
|
+
embeddingCandidateK: 42,
|
|
69
|
+
});
|
|
70
|
+
const config = resolveCliEmbeddingConfig();
|
|
71
|
+
expect(config.model).toBe('config-file-model');
|
|
72
|
+
expect(config.baseUrl).toBe('https://api.example.com/v1');
|
|
73
|
+
expect(config.dimension).toBe(768);
|
|
74
|
+
expect(config.candidateK).toBe(42);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe('resolveCliEmbeddingProvider', () => {
|
|
78
|
+
it('returns provider: undefined when unconfigured (none-default parity)', () => {
|
|
79
|
+
const { provider, config } = resolveCliEmbeddingProvider();
|
|
80
|
+
expect(provider).toBeUndefined();
|
|
81
|
+
expect(config.provider).toBe('none');
|
|
82
|
+
});
|
|
83
|
+
it('returns a concrete provider when fully configured', () => {
|
|
84
|
+
mockLoadConfig.mockReturnValue({
|
|
85
|
+
embeddingProvider: 'openai-compatible',
|
|
86
|
+
embeddingModel: 'text-embedding-3-small',
|
|
87
|
+
embeddingBaseUrl: 'https://api.openai.com/v1',
|
|
88
|
+
embeddingDimension: 1536,
|
|
89
|
+
});
|
|
90
|
+
const { provider, config } = resolveCliEmbeddingProvider();
|
|
91
|
+
expect(provider).toBeDefined();
|
|
92
|
+
expect(provider?.dimension).toBe(1536);
|
|
93
|
+
expect(config.model).toBe('text-embedding-3-small');
|
|
94
|
+
});
|
|
95
|
+
it('an unknown provider id falls back to undefined (never throws)', () => {
|
|
96
|
+
mockLoadConfig.mockReturnValue({ embeddingProvider: 'totally-unknown' });
|
|
97
|
+
const { provider } = resolveCliEmbeddingProvider();
|
|
98
|
+
expect(provider).toBeUndefined();
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=embedding.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding.test.js","sourceRoot":"","sources":["../../src/lib/embedding.test.ts"],"names":[],"mappings":"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"}
|