recall-mcp-v3 3.7.4 → 3.9.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/__tests__/api-get-token.test.d.ts +18 -0
- package/dist/__tests__/api-get-token.test.d.ts.map +1 -0
- package/dist/__tests__/api-get-token.test.js +195 -0
- package/dist/__tests__/api-get-token.test.js.map +1 -0
- package/dist/__tests__/repo-override-save-log.test.d.ts +11 -0
- package/dist/__tests__/repo-override-save-log.test.d.ts.map +1 -0
- package/dist/__tests__/repo-override-save-log.test.js +352 -0
- package/dist/__tests__/repo-override-save-log.test.js.map +1 -0
- package/dist/api.d.ts +6 -1
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +49 -5
- package/dist/api.js.map +1 -1
- package/dist/auth/__tests__/auth-store.test.d.ts +6 -0
- package/dist/auth/__tests__/auth-store.test.d.ts.map +1 -0
- package/dist/auth/__tests__/auth-store.test.js +161 -0
- package/dist/auth/__tests__/auth-store.test.js.map +1 -0
- package/dist/auth/__tests__/device-client.test.d.ts +10 -0
- package/dist/auth/__tests__/device-client.test.d.ts.map +1 -0
- package/dist/auth/__tests__/device-client.test.js +327 -0
- package/dist/auth/__tests__/device-client.test.js.map +1 -0
- package/dist/auth/__tests__/preflight.test.d.ts +2 -0
- package/dist/auth/__tests__/preflight.test.d.ts.map +1 -0
- package/dist/auth/__tests__/preflight.test.js +37 -0
- package/dist/auth/__tests__/preflight.test.js.map +1 -0
- package/dist/auth/__tests__/run-auth.test.d.ts +11 -0
- package/dist/auth/__tests__/run-auth.test.d.ts.map +1 -0
- package/dist/auth/__tests__/run-auth.test.js +387 -0
- package/dist/auth/__tests__/run-auth.test.js.map +1 -0
- package/dist/auth/__tests__/tool-detection.test.d.ts +10 -0
- package/dist/auth/__tests__/tool-detection.test.d.ts.map +1 -0
- package/dist/auth/__tests__/tool-detection.test.js +122 -0
- package/dist/auth/__tests__/tool-detection.test.js.map +1 -0
- package/dist/auth/__tests__/tool-patching.test.d.ts +13 -0
- package/dist/auth/__tests__/tool-patching.test.d.ts.map +1 -0
- package/dist/auth/__tests__/tool-patching.test.js +385 -0
- package/dist/auth/__tests__/tool-patching.test.js.map +1 -0
- package/dist/auth/auth-store.d.ts +61 -0
- package/dist/auth/auth-store.d.ts.map +1 -0
- package/dist/auth/auth-store.js +158 -0
- package/dist/auth/auth-store.js.map +1 -0
- package/dist/auth/device-client.d.ts +85 -0
- package/dist/auth/device-client.d.ts.map +1 -0
- package/dist/auth/device-client.js +269 -0
- package/dist/auth/device-client.js.map +1 -0
- package/dist/auth/preflight.d.ts +10 -0
- package/dist/auth/preflight.d.ts.map +1 -0
- package/dist/auth/preflight.js +35 -0
- package/dist/auth/preflight.js.map +1 -0
- package/dist/auth/run-auth.d.ts +56 -0
- package/dist/auth/run-auth.d.ts.map +1 -0
- package/dist/auth/run-auth.js +222 -0
- package/dist/auth/run-auth.js.map +1 -0
- package/dist/auth/tool-detection.d.ts +47 -0
- package/dist/auth/tool-detection.d.ts.map +1 -0
- package/dist/auth/tool-detection.js +99 -0
- package/dist/auth/tool-detection.js.map +1 -0
- package/dist/auth/tool-patching.d.ts +85 -0
- package/dist/auth/tool-patching.d.ts.map +1 -0
- package/dist/auth/tool-patching.js +353 -0
- package/dist/auth/tool-patching.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +30 -0
- package/dist/cli.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/tools.d.ts +2 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +27 -2
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `getToken()` resolution in api.ts.
|
|
3
|
+
*
|
|
4
|
+
* Exercises:
|
|
5
|
+
* - Auth store wins over env var when both are set.
|
|
6
|
+
* - Env var used as fallback when auth store absent.
|
|
7
|
+
* - Corrupt auth store logs once + falls through to env (does not throw).
|
|
8
|
+
* - Missing both paths throws with an actionable error.
|
|
9
|
+
* - Result is memoized: subsequent calls don't re-read the filesystem.
|
|
10
|
+
* - "No token found" is also memoized so we don't hammer stderr on retries.
|
|
11
|
+
*
|
|
12
|
+
* `getToken` itself is not exported, but every request-making function calls
|
|
13
|
+
* it before issuing a fetch. We use `saveSession`'s code path by mocking the
|
|
14
|
+
* network layer — any call that reaches `fetch` has already resolved the
|
|
15
|
+
* token. The `__resetTokenCache` export is the test seam.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=api-get-token.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-get-token.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/api-get-token.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the `getToken()` resolution in api.ts.
|
|
3
|
+
*
|
|
4
|
+
* Exercises:
|
|
5
|
+
* - Auth store wins over env var when both are set.
|
|
6
|
+
* - Env var used as fallback when auth store absent.
|
|
7
|
+
* - Corrupt auth store logs once + falls through to env (does not throw).
|
|
8
|
+
* - Missing both paths throws with an actionable error.
|
|
9
|
+
* - Result is memoized: subsequent calls don't re-read the filesystem.
|
|
10
|
+
* - "No token found" is also memoized so we don't hammer stderr on retries.
|
|
11
|
+
*
|
|
12
|
+
* `getToken` itself is not exported, but every request-making function calls
|
|
13
|
+
* it before issuing a fetch. We use `saveSession`'s code path by mocking the
|
|
14
|
+
* network layer — any call that reaches `fetch` has already resolved the
|
|
15
|
+
* token. The `__resetTokenCache` export is the test seam.
|
|
16
|
+
*/
|
|
17
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
18
|
+
import * as fs from 'node:fs';
|
|
19
|
+
import * as os from 'node:os';
|
|
20
|
+
import * as path from 'node:path';
|
|
21
|
+
import { __resetTokenCache, getTokenSource, RecallApiError } from '../api.js';
|
|
22
|
+
import { writeAuthStore } from '../auth/auth-store.js';
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Fixture: the encryption layer and /v1/keys/team endpoint are mocked so we
|
|
25
|
+
// can isolate the token-resolution behavior from everything downstream.
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
vi.mock('../crypto.js', () => ({
|
|
28
|
+
encrypt: vi.fn().mockReturnValue('encrypted'),
|
|
29
|
+
decrypt: vi.fn().mockReturnValue('decrypted'),
|
|
30
|
+
isEncrypted: vi.fn().mockReturnValue(false),
|
|
31
|
+
safeDecrypt: vi.fn().mockReturnValue(''),
|
|
32
|
+
normalizeToString: vi.fn((s) => s),
|
|
33
|
+
}));
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// readAuthStoreSync resolves its path via process.env at call time, so each
|
|
36
|
+
// test points RECALL_AUTH_DIR at its own tmp dir and resets the cache.
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
let tmp;
|
|
39
|
+
let originalEnv;
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'recall-gettoken-'));
|
|
42
|
+
originalEnv = {
|
|
43
|
+
token: process.env.RECALL_API_TOKEN,
|
|
44
|
+
authDir: process.env.RECALL_AUTH_DIR,
|
|
45
|
+
};
|
|
46
|
+
// Start each test with a clean slate.
|
|
47
|
+
delete process.env.RECALL_API_TOKEN;
|
|
48
|
+
process.env.RECALL_AUTH_DIR = path.join(tmp, 'recall');
|
|
49
|
+
__resetTokenCache();
|
|
50
|
+
vi.restoreAllMocks();
|
|
51
|
+
});
|
|
52
|
+
afterEach(() => {
|
|
53
|
+
if (originalEnv.token !== undefined) {
|
|
54
|
+
process.env.RECALL_API_TOKEN = originalEnv.token;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
delete process.env.RECALL_API_TOKEN;
|
|
58
|
+
}
|
|
59
|
+
if (originalEnv.authDir !== undefined) {
|
|
60
|
+
process.env.RECALL_AUTH_DIR = originalEnv.authDir;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
delete process.env.RECALL_AUTH_DIR;
|
|
64
|
+
}
|
|
65
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
66
|
+
__resetTokenCache();
|
|
67
|
+
});
|
|
68
|
+
async function writeStore(token) {
|
|
69
|
+
await writeAuthStore({
|
|
70
|
+
token,
|
|
71
|
+
issued_at: '2026-04-23T00:00:00.000Z',
|
|
72
|
+
api_base: 'https://api-v3.recall.team',
|
|
73
|
+
client_version: '3.9.0',
|
|
74
|
+
}, process.env);
|
|
75
|
+
}
|
|
76
|
+
// Helper to force a call through getToken + observe the token it attached
|
|
77
|
+
// to the request. We shim global fetch so no real network call happens.
|
|
78
|
+
async function captureTokenViaFetch() {
|
|
79
|
+
const fetchSpy = vi
|
|
80
|
+
.spyOn(globalThis, 'fetch')
|
|
81
|
+
.mockImplementation(() => Promise.resolve(new Response(JSON.stringify({
|
|
82
|
+
hasAccess: true,
|
|
83
|
+
encryptionKey: 'k',
|
|
84
|
+
keyVersion: 1,
|
|
85
|
+
teamId: 't',
|
|
86
|
+
teamName: 'tt',
|
|
87
|
+
teamSlug: 'ts',
|
|
88
|
+
tier: 'free',
|
|
89
|
+
}), { status: 200, headers: { 'Content-Type': 'application/json' } })));
|
|
90
|
+
const { getTeamKey, clearKeyCache } = await import('../api.js');
|
|
91
|
+
clearKeyCache();
|
|
92
|
+
try {
|
|
93
|
+
await getTeamKey();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// If getToken throws NO_TOKEN the fetch was never called — that's valid
|
|
97
|
+
// in the "no token found" test which asserts by catching the error.
|
|
98
|
+
}
|
|
99
|
+
const call = fetchSpy.mock.calls[0];
|
|
100
|
+
if (!call)
|
|
101
|
+
return null;
|
|
102
|
+
const init = call[1];
|
|
103
|
+
const auth = init?.headers?.['Authorization'];
|
|
104
|
+
return auth?.replace(/^Bearer\s+/, '') ?? null;
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Tests
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
describe('getToken: auth store precedence', () => {
|
|
110
|
+
it('prefers the auth store over RECALL_API_TOKEN when both are set', async () => {
|
|
111
|
+
await writeStore('rcl_from_store');
|
|
112
|
+
process.env.RECALL_API_TOKEN = 'rcl_from_env';
|
|
113
|
+
const tokenUsed = await captureTokenViaFetch();
|
|
114
|
+
expect(tokenUsed).toBe('rcl_from_store');
|
|
115
|
+
expect(getTokenSource()).toBe('auth_store');
|
|
116
|
+
});
|
|
117
|
+
it('falls back to RECALL_API_TOKEN when the auth store is absent', async () => {
|
|
118
|
+
process.env.RECALL_API_TOKEN = 'rcl_from_env_only';
|
|
119
|
+
const tokenUsed = await captureTokenViaFetch();
|
|
120
|
+
expect(tokenUsed).toBe('rcl_from_env_only');
|
|
121
|
+
expect(getTokenSource()).toBe('env');
|
|
122
|
+
});
|
|
123
|
+
it('uses the auth store even when the env var is empty string', async () => {
|
|
124
|
+
await writeStore('rcl_store_only');
|
|
125
|
+
process.env.RECALL_API_TOKEN = '';
|
|
126
|
+
const tokenUsed = await captureTokenViaFetch();
|
|
127
|
+
expect(tokenUsed).toBe('rcl_store_only');
|
|
128
|
+
expect(getTokenSource()).toBe('auth_store');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('getToken: error handling', () => {
|
|
132
|
+
it('throws NO_TOKEN when neither store nor env is present', async () => {
|
|
133
|
+
const { getTeamKey, clearKeyCache } = await import('../api.js');
|
|
134
|
+
clearKeyCache();
|
|
135
|
+
await expect(getTeamKey()).rejects.toMatchObject({
|
|
136
|
+
name: 'RecallApiError',
|
|
137
|
+
code: 'NO_TOKEN',
|
|
138
|
+
status: 401,
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
it('the NO_TOKEN error message suggests both `auth` and the env var', async () => {
|
|
142
|
+
const { getTeamKey, clearKeyCache } = await import('../api.js');
|
|
143
|
+
clearKeyCache();
|
|
144
|
+
await expect(getTeamKey()).rejects.toThrow(/recall-mcp-v3 auth/);
|
|
145
|
+
await expect(getTeamKey()).rejects.toThrow(/RECALL_API_TOKEN/);
|
|
146
|
+
});
|
|
147
|
+
it('falls through to env on a corrupt auth store and logs once', async () => {
|
|
148
|
+
const dir = path.join(tmp, 'recall');
|
|
149
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
150
|
+
fs.writeFileSync(path.join(dir, 'auth.json'), 'not valid json {{{');
|
|
151
|
+
process.env.RECALL_API_TOKEN = 'rcl_env_rescue';
|
|
152
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
153
|
+
const tokenUsed = await captureTokenViaFetch();
|
|
154
|
+
expect(tokenUsed).toBe('rcl_env_rescue');
|
|
155
|
+
expect(getTokenSource()).toBe('env');
|
|
156
|
+
expect(consoleSpy).toHaveBeenCalledTimes(1);
|
|
157
|
+
expect(consoleSpy.mock.calls[0][0]).toMatch(/auth store/i);
|
|
158
|
+
});
|
|
159
|
+
it('corrupt store + no env throws NO_TOKEN but still only logs the corruption once', async () => {
|
|
160
|
+
const dir = path.join(tmp, 'recall');
|
|
161
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
162
|
+
fs.writeFileSync(path.join(dir, 'auth.json'), '{corrupt');
|
|
163
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
164
|
+
const { getTeamKey, clearKeyCache } = await import('../api.js');
|
|
165
|
+
clearKeyCache();
|
|
166
|
+
await expect(getTeamKey()).rejects.toBeInstanceOf(RecallApiError);
|
|
167
|
+
// Second call should NOT re-log: the "no token" outcome is memoized.
|
|
168
|
+
await expect(getTeamKey()).rejects.toBeInstanceOf(RecallApiError);
|
|
169
|
+
expect(consoleSpy).toHaveBeenCalledTimes(1);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe('getToken: memoization', () => {
|
|
173
|
+
it('does not re-read the auth store on subsequent calls', async () => {
|
|
174
|
+
// Observation: delete the auth store after the first call. If the token
|
|
175
|
+
// cache is working, the second call still returns the first token; if
|
|
176
|
+
// the second call re-read the file, it would fall through to env (unset)
|
|
177
|
+
// and throw NO_TOKEN.
|
|
178
|
+
await writeStore('rcl_memo_test');
|
|
179
|
+
const first = await captureTokenViaFetch();
|
|
180
|
+
expect(first).toBe('rcl_memo_test');
|
|
181
|
+
fs.rmSync(path.join(tmp, 'recall'), { recursive: true, force: true });
|
|
182
|
+
const second = await captureTokenViaFetch();
|
|
183
|
+
expect(second).toBe('rcl_memo_test');
|
|
184
|
+
});
|
|
185
|
+
it('__resetTokenCache forces a fresh read (test seam works)', async () => {
|
|
186
|
+
await writeStore('rcl_first');
|
|
187
|
+
expect(await captureTokenViaFetch()).toBe('rcl_first');
|
|
188
|
+
await writeStore('rcl_second');
|
|
189
|
+
// Without reset, the old token is memoized.
|
|
190
|
+
expect(await captureTokenViaFetch()).toBe('rcl_first');
|
|
191
|
+
__resetTokenCache();
|
|
192
|
+
expect(await captureTokenViaFetch()).toBe('rcl_second');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
//# sourceMappingURL=api-get-token.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-get-token.test.js","sourceRoot":"","sources":["../../src/__tests__/api-get-token.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for explicit `repo` param override on saveSession and logDecision.
|
|
3
|
+
*
|
|
4
|
+
* When a developer's git remote (e.g., raydawg88/stoodio-v2) doesn't match
|
|
5
|
+
* the enrolled Recall repo name (e.g., defendersoftheinternet/stoodio-v2),
|
|
6
|
+
* the explicit `repo` param lets the caller specify the correct name.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors the existing test patterns in get-context-repo-resolution.test.ts.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=repo-override-save-log.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-override-save-log.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/repo-override-save-log.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for explicit `repo` param override on saveSession and logDecision.
|
|
3
|
+
*
|
|
4
|
+
* When a developer's git remote (e.g., raydawg88/stoodio-v2) doesn't match
|
|
5
|
+
* the enrolled Recall repo name (e.g., defendersoftheinternet/stoodio-v2),
|
|
6
|
+
* the explicit `repo` param lets the caller specify the correct name.
|
|
7
|
+
*
|
|
8
|
+
* Mirrors the existing test patterns in get-context-repo-resolution.test.ts.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
11
|
+
// Configurable mocks
|
|
12
|
+
const mockExecSync = vi.fn();
|
|
13
|
+
// Mock api module
|
|
14
|
+
vi.mock('../api.js', async (importOriginal) => {
|
|
15
|
+
const actual = await importOriginal();
|
|
16
|
+
return {
|
|
17
|
+
...actual,
|
|
18
|
+
resolveRepo: vi.fn(),
|
|
19
|
+
resolveRepoFromGraph: vi.fn().mockResolvedValue(null),
|
|
20
|
+
fetchTeamGraph: vi.fn().mockResolvedValue(null),
|
|
21
|
+
getTeamKey: vi.fn().mockResolvedValue('mock-key'),
|
|
22
|
+
getCachedTier: vi.fn().mockReturnValue('team'),
|
|
23
|
+
listRepos: vi.fn().mockResolvedValue([]),
|
|
24
|
+
saveSessionAsync: vi.fn().mockResolvedValue({ id: 'sess_test123' }),
|
|
25
|
+
logDecision: vi.fn().mockResolvedValue({ id: 'dec_test123' }),
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
vi.mock('../transcript-finder.js', () => ({
|
|
29
|
+
findCurrentTranscript: vi.fn().mockReturnValue(null),
|
|
30
|
+
readTranscriptFile: vi.fn().mockReturnValue(null),
|
|
31
|
+
}));
|
|
32
|
+
vi.mock('../preprocessor.js', () => ({
|
|
33
|
+
preprocessTranscript: vi.fn().mockResolvedValue({
|
|
34
|
+
content: 'test transcript',
|
|
35
|
+
stats: { originalSize: 100, processedSize: 50, messagesExtracted: 5, errorsFound: 0, toolCallsLogged: 2 },
|
|
36
|
+
}),
|
|
37
|
+
}));
|
|
38
|
+
// Mock child_process — delegates to configurable mockExecSync
|
|
39
|
+
vi.mock('child_process', () => ({
|
|
40
|
+
execSync: (...args) => mockExecSync(...args),
|
|
41
|
+
}));
|
|
42
|
+
// Mock fs
|
|
43
|
+
vi.mock('fs', async (importOriginal) => {
|
|
44
|
+
const actual = await importOriginal();
|
|
45
|
+
return {
|
|
46
|
+
...actual,
|
|
47
|
+
readdirSync: vi.fn().mockReturnValue([]),
|
|
48
|
+
existsSync: vi.fn().mockReturnValue(false),
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
import * as api from '../api.js';
|
|
52
|
+
import { saveSession, logDecision } from '../tools.js';
|
|
53
|
+
// Helper: set up resolveRepoFromGraph to return a valid resolved repo
|
|
54
|
+
function mockResolvedRepo() {
|
|
55
|
+
vi.mocked(api.resolveRepoFromGraph).mockResolvedValue({
|
|
56
|
+
repoId: 'repo-123',
|
|
57
|
+
teamId: 'team-456',
|
|
58
|
+
teamSlug: 'myteam',
|
|
59
|
+
encryptionKey: 'mock-key',
|
|
60
|
+
tier: 'pro',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
describe('saveSession with explicit repo param', () => {
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
vi.clearAllMocks();
|
|
66
|
+
// Default: not in a git repo
|
|
67
|
+
mockExecSync.mockImplementation(() => {
|
|
68
|
+
throw new Error('fatal: not a git repository');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
// =========================================================================
|
|
72
|
+
// Happy path: explicit repo resolves correctly
|
|
73
|
+
// =========================================================================
|
|
74
|
+
describe('valid repo param', () => {
|
|
75
|
+
it('should save session using the specified repo, skipping filesystem detection', async () => {
|
|
76
|
+
mockResolvedRepo();
|
|
77
|
+
const result = await saveSession({
|
|
78
|
+
repo: 'defendersoftheinternet/stoodio-v2',
|
|
79
|
+
summary: 'Wired contact form',
|
|
80
|
+
});
|
|
81
|
+
expect(result.isError).toBe(false);
|
|
82
|
+
// Should NOT try to read git config
|
|
83
|
+
expect(mockExecSync).not.toHaveBeenCalled();
|
|
84
|
+
// Should resolve with the explicit repo name
|
|
85
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('defendersoftheinternet/stoodio-v2');
|
|
86
|
+
});
|
|
87
|
+
it('should NOT call listRepos when repo param is provided', async () => {
|
|
88
|
+
mockResolvedRepo();
|
|
89
|
+
await saveSession({
|
|
90
|
+
repo: 'defendersoftheinternet/stoodio-v2',
|
|
91
|
+
summary: 'Test session',
|
|
92
|
+
});
|
|
93
|
+
expect(api.listRepos).not.toHaveBeenCalled();
|
|
94
|
+
});
|
|
95
|
+
it('should trim whitespace from repo param', async () => {
|
|
96
|
+
mockResolvedRepo();
|
|
97
|
+
await saveSession({
|
|
98
|
+
repo: ' defendersoftheinternet/stoodio-v2 ',
|
|
99
|
+
summary: 'Test session',
|
|
100
|
+
});
|
|
101
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('defendersoftheinternet/stoodio-v2');
|
|
102
|
+
});
|
|
103
|
+
it('should take priority over projectPath when both are provided', async () => {
|
|
104
|
+
mockResolvedRepo();
|
|
105
|
+
await saveSession({
|
|
106
|
+
repo: 'defendersoftheinternet/stoodio-v2',
|
|
107
|
+
projectPath: '/some/other/project',
|
|
108
|
+
summary: 'Test session',
|
|
109
|
+
});
|
|
110
|
+
// repo param wins — filesystem detection never called
|
|
111
|
+
expect(mockExecSync).not.toHaveBeenCalled();
|
|
112
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('defendersoftheinternet/stoodio-v2');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
// =========================================================================
|
|
116
|
+
// Invalid format
|
|
117
|
+
// =========================================================================
|
|
118
|
+
describe('invalid repo format', () => {
|
|
119
|
+
it('should reject repo without slash (no owner/repo format)', async () => {
|
|
120
|
+
const result = await saveSession({
|
|
121
|
+
repo: 'just-a-name',
|
|
122
|
+
summary: 'Test session',
|
|
123
|
+
});
|
|
124
|
+
expect(result.isError).toBe(true);
|
|
125
|
+
expect(result.content[0].text).toContain('Invalid repo format');
|
|
126
|
+
expect(result.content[0].text).toContain('owner/repo');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
// =========================================================================
|
|
130
|
+
// Empty/whitespace repo falls through to filesystem
|
|
131
|
+
// =========================================================================
|
|
132
|
+
describe('empty repo param', () => {
|
|
133
|
+
it('should fall through to filesystem when repo is empty string', async () => {
|
|
134
|
+
vi.mocked(api.listRepos).mockResolvedValue(['stoodiohq/recall-v3']);
|
|
135
|
+
const result = await saveSession({ repo: '', summary: 'Test' });
|
|
136
|
+
// Should hit the filesystem path (which fails in our mock) then list repos
|
|
137
|
+
expect(result.isError).toBe(true);
|
|
138
|
+
expect(result.content[0].text).toContain('stoodiohq/recall-v3');
|
|
139
|
+
expect(api.resolveRepoFromGraph).not.toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
it('should fall through to filesystem when repo is whitespace only', async () => {
|
|
142
|
+
vi.mocked(api.listRepos).mockResolvedValue(['stoodiohq/recall-v3']);
|
|
143
|
+
const result = await saveSession({ repo: ' ', summary: 'Test' });
|
|
144
|
+
expect(result.isError).toBe(true);
|
|
145
|
+
expect(result.content[0].text).toContain('stoodiohq/recall-v3');
|
|
146
|
+
expect(api.resolveRepoFromGraph).not.toHaveBeenCalled();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
// =========================================================================
|
|
150
|
+
// Error handling: REPO_NOT_ENROLLED
|
|
151
|
+
// =========================================================================
|
|
152
|
+
describe('repo not enrolled', () => {
|
|
153
|
+
it('should return NOT_ENROLLED with available repos when repo not found', async () => {
|
|
154
|
+
vi.mocked(api.resolveRepoFromGraph).mockResolvedValue(null);
|
|
155
|
+
vi.mocked(api.resolveRepo).mockRejectedValue(new api.RecallApiError('Repo not enrolled', 'REPO_NOT_ENROLLED', 404));
|
|
156
|
+
vi.mocked(api.listRepos).mockResolvedValue([
|
|
157
|
+
'stoodiohq/recall-v3',
|
|
158
|
+
'raydawg88/scratch-golf-site',
|
|
159
|
+
]);
|
|
160
|
+
const result = await saveSession({
|
|
161
|
+
repo: 'raydawg88/nonexistent-repo',
|
|
162
|
+
summary: 'Test',
|
|
163
|
+
});
|
|
164
|
+
expect(result.isError).toBe(true);
|
|
165
|
+
expect(result.content[0].text).toContain('raydawg88/nonexistent-repo');
|
|
166
|
+
expect(result.content[0].text).toContain('stoodiohq/recall-v3');
|
|
167
|
+
});
|
|
168
|
+
it('should return skip-all message when repo not found and no repos configured', async () => {
|
|
169
|
+
vi.mocked(api.resolveRepoFromGraph).mockResolvedValue(null);
|
|
170
|
+
vi.mocked(api.resolveRepo).mockRejectedValue(new api.RecallApiError('Repo not enrolled', 'REPO_NOT_ENROLLED', 404));
|
|
171
|
+
vi.mocked(api.listRepos).mockResolvedValue([]);
|
|
172
|
+
const result = await saveSession({
|
|
173
|
+
repo: 'raydawg88/nonexistent-repo',
|
|
174
|
+
summary: 'Test',
|
|
175
|
+
});
|
|
176
|
+
expect(result.isError).toBe(true);
|
|
177
|
+
expect(result.content[0].text.toLowerCase()).toMatch(/skip.*all.*recall.*tools/i);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
// =========================================================================
|
|
181
|
+
// Error handling: auth
|
|
182
|
+
// =========================================================================
|
|
183
|
+
describe('auth errors', () => {
|
|
184
|
+
it('should handle auth errors on repo param path', async () => {
|
|
185
|
+
vi.mocked(api.resolveRepoFromGraph).mockRejectedValue(new api.RecallApiError('Unauthorized', 'UNAUTHORIZED', 401));
|
|
186
|
+
const result = await saveSession({
|
|
187
|
+
repo: 'raydawg88/my-project',
|
|
188
|
+
summary: 'Test',
|
|
189
|
+
});
|
|
190
|
+
expect(result.isError).toBe(true);
|
|
191
|
+
expect(result.content[0].text).toContain('Authentication failed');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
// =========================================================================
|
|
195
|
+
// Backward compatibility: no repo param still works via filesystem
|
|
196
|
+
// =========================================================================
|
|
197
|
+
describe('backward compatibility (no repo param)', () => {
|
|
198
|
+
it('should still resolve from git remote when no repo param', async () => {
|
|
199
|
+
mockExecSync.mockImplementation((cmd) => {
|
|
200
|
+
if (typeof cmd === 'string' && cmd.includes('remote.origin.url')) {
|
|
201
|
+
return 'git@github.com:stoodiohq/recall-v3.git\n';
|
|
202
|
+
}
|
|
203
|
+
if (typeof cmd === 'string' && cmd.includes('rev-parse --abbrev-ref')) {
|
|
204
|
+
return 'main\n';
|
|
205
|
+
}
|
|
206
|
+
return '';
|
|
207
|
+
});
|
|
208
|
+
mockResolvedRepo();
|
|
209
|
+
const result = await saveSession({ summary: 'Test session' });
|
|
210
|
+
expect(result.isError).toBe(false);
|
|
211
|
+
// Should call git to detect the repo
|
|
212
|
+
expect(mockExecSync).toHaveBeenCalled();
|
|
213
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('stoodiohq/recall-v3');
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
describe('logDecision with explicit repo param', () => {
|
|
218
|
+
beforeEach(() => {
|
|
219
|
+
vi.clearAllMocks();
|
|
220
|
+
// Default: not in a git repo
|
|
221
|
+
mockExecSync.mockImplementation(() => {
|
|
222
|
+
throw new Error('fatal: not a git repository');
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
// =========================================================================
|
|
226
|
+
// Happy path: explicit repo resolves correctly
|
|
227
|
+
// =========================================================================
|
|
228
|
+
describe('valid repo param', () => {
|
|
229
|
+
it('should log decision using the specified repo, skipping filesystem detection', async () => {
|
|
230
|
+
mockResolvedRepo();
|
|
231
|
+
const result = await logDecision({
|
|
232
|
+
repo: 'defendersoftheinternet/stoodio-v2',
|
|
233
|
+
decision: 'Use Cloudflare Worker for contact form',
|
|
234
|
+
reasoning: 'Site is on Cloudflare Pages, simplest path',
|
|
235
|
+
});
|
|
236
|
+
expect(result.isError).toBe(false);
|
|
237
|
+
expect(result.content[0].text).toContain('Decision logged successfully');
|
|
238
|
+
// Should NOT try to read git config
|
|
239
|
+
expect(mockExecSync).not.toHaveBeenCalled();
|
|
240
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('defendersoftheinternet/stoodio-v2');
|
|
241
|
+
});
|
|
242
|
+
it('should trim whitespace from repo param', async () => {
|
|
243
|
+
mockResolvedRepo();
|
|
244
|
+
await logDecision({
|
|
245
|
+
repo: ' defendersoftheinternet/stoodio-v2 ',
|
|
246
|
+
decision: 'Test',
|
|
247
|
+
reasoning: 'Test',
|
|
248
|
+
});
|
|
249
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('defendersoftheinternet/stoodio-v2');
|
|
250
|
+
});
|
|
251
|
+
it('should take priority over projectPath when both are provided', async () => {
|
|
252
|
+
mockResolvedRepo();
|
|
253
|
+
await logDecision({
|
|
254
|
+
repo: 'defendersoftheinternet/stoodio-v2',
|
|
255
|
+
projectPath: '/some/other/project',
|
|
256
|
+
decision: 'Test',
|
|
257
|
+
reasoning: 'Test',
|
|
258
|
+
});
|
|
259
|
+
expect(mockExecSync).not.toHaveBeenCalled();
|
|
260
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('defendersoftheinternet/stoodio-v2');
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
// =========================================================================
|
|
264
|
+
// Invalid format
|
|
265
|
+
// =========================================================================
|
|
266
|
+
describe('invalid repo format', () => {
|
|
267
|
+
it('should reject repo without slash', async () => {
|
|
268
|
+
const result = await logDecision({
|
|
269
|
+
repo: 'just-a-name',
|
|
270
|
+
decision: 'Test',
|
|
271
|
+
reasoning: 'Test',
|
|
272
|
+
});
|
|
273
|
+
expect(result.isError).toBe(true);
|
|
274
|
+
expect(result.content[0].text).toContain('Invalid repo format');
|
|
275
|
+
expect(result.content[0].text).toContain('owner/repo');
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
// =========================================================================
|
|
279
|
+
// Empty repo falls through to filesystem
|
|
280
|
+
// =========================================================================
|
|
281
|
+
describe('empty repo param', () => {
|
|
282
|
+
it('should fall through to filesystem when repo is empty string', async () => {
|
|
283
|
+
const result = await logDecision({
|
|
284
|
+
repo: '',
|
|
285
|
+
decision: 'Test',
|
|
286
|
+
reasoning: 'Test',
|
|
287
|
+
});
|
|
288
|
+
// No git repo in mock, so it should error
|
|
289
|
+
expect(result.isError).toBe(true);
|
|
290
|
+
expect(result.content[0].text).toContain('Could not determine repository');
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
// =========================================================================
|
|
294
|
+
// Error handling: REPO_NOT_ENROLLED
|
|
295
|
+
// =========================================================================
|
|
296
|
+
describe('repo not enrolled', () => {
|
|
297
|
+
it('should return NOT_ENROLLED with available repos', async () => {
|
|
298
|
+
vi.mocked(api.resolveRepoFromGraph).mockResolvedValue(null);
|
|
299
|
+
vi.mocked(api.resolveRepo).mockRejectedValue(new api.RecallApiError('Repo not enrolled', 'REPO_NOT_ENROLLED', 404));
|
|
300
|
+
vi.mocked(api.listRepos).mockResolvedValue([
|
|
301
|
+
'stoodiohq/recall-v3',
|
|
302
|
+
]);
|
|
303
|
+
const result = await logDecision({
|
|
304
|
+
repo: 'raydawg88/nonexistent-repo',
|
|
305
|
+
decision: 'Test',
|
|
306
|
+
reasoning: 'Test',
|
|
307
|
+
});
|
|
308
|
+
expect(result.isError).toBe(true);
|
|
309
|
+
expect(result.content[0].text).toContain('raydawg88/nonexistent-repo');
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
// =========================================================================
|
|
313
|
+
// Auth errors
|
|
314
|
+
// =========================================================================
|
|
315
|
+
describe('auth errors', () => {
|
|
316
|
+
it('should handle auth errors', async () => {
|
|
317
|
+
vi.mocked(api.resolveRepoFromGraph).mockRejectedValue(new api.RecallApiError('Unauthorized', 'UNAUTHORIZED', 401));
|
|
318
|
+
const result = await logDecision({
|
|
319
|
+
repo: 'raydawg88/my-project',
|
|
320
|
+
decision: 'Test',
|
|
321
|
+
reasoning: 'Test',
|
|
322
|
+
});
|
|
323
|
+
expect(result.isError).toBe(true);
|
|
324
|
+
expect(result.content[0].text).toContain('Authentication failed');
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
// =========================================================================
|
|
328
|
+
// Backward compatibility
|
|
329
|
+
// =========================================================================
|
|
330
|
+
describe('backward compatibility (no repo param)', () => {
|
|
331
|
+
it('should still resolve from git remote when no repo param', async () => {
|
|
332
|
+
mockExecSync.mockImplementation((cmd) => {
|
|
333
|
+
if (typeof cmd === 'string' && cmd.includes('remote.origin.url')) {
|
|
334
|
+
return 'git@github.com:stoodiohq/recall-v3.git\n';
|
|
335
|
+
}
|
|
336
|
+
if (typeof cmd === 'string' && cmd.includes('rev-parse --abbrev-ref')) {
|
|
337
|
+
return 'main\n';
|
|
338
|
+
}
|
|
339
|
+
return '';
|
|
340
|
+
});
|
|
341
|
+
mockResolvedRepo();
|
|
342
|
+
const result = await logDecision({
|
|
343
|
+
decision: 'Use Workers',
|
|
344
|
+
reasoning: 'Cloudflare stack',
|
|
345
|
+
});
|
|
346
|
+
expect(result.isError).toBe(false);
|
|
347
|
+
expect(mockExecSync).toHaveBeenCalled();
|
|
348
|
+
expect(api.resolveRepoFromGraph).toHaveBeenCalledWith('stoodiohq/recall-v3');
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
//# sourceMappingURL=repo-override-save-log.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo-override-save-log.test.js","sourceRoot":"","sources":["../../src/__tests__/repo-override-save-log.test.ts"],"names":[],"mappings":"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"}
|
package/dist/api.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Recall API Client
|
|
3
3
|
*
|
|
4
4
|
* HTTP client for the Recall v3 API with encryption support.
|
|
5
|
-
* - Reads token from
|
|
5
|
+
* - Reads token from the local auth store (written by `recall-mcp-v3 auth`);
|
|
6
|
+
* falls back to RECALL_API_TOKEN env var for legacy installs.
|
|
6
7
|
* - Fetches team encryption key from API
|
|
7
8
|
* - Encrypts content before sending, decrypts after receiving
|
|
8
9
|
*/
|
|
@@ -45,6 +46,10 @@ declare class RecallApiError extends Error {
|
|
|
45
46
|
status: number;
|
|
46
47
|
constructor(message: string, code: string, status: number);
|
|
47
48
|
}
|
|
49
|
+
/** Test-only hook so suites can reset the cached token between runs. */
|
|
50
|
+
export declare function __resetTokenCache(): void;
|
|
51
|
+
/** Exposed for debugging / heartbeat telemetry. */
|
|
52
|
+
export declare function getTokenSource(): 'auth_store' | 'env' | null;
|
|
48
53
|
/**
|
|
49
54
|
* Fetch the team encryption key from API.
|
|
50
55
|
* Caches the key in memory for the duration of the process.
|