recall-mcp-v3 3.9.0 → 3.9.1

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.
Files changed (149) hide show
  1. package/package.json +1 -1
  2. package/dist/__tests__/api-get-token.test.d.ts +0 -18
  3. package/dist/__tests__/api-get-token.test.d.ts.map +0 -1
  4. package/dist/__tests__/api-get-token.test.js +0 -195
  5. package/dist/__tests__/api-get-token.test.js.map +0 -1
  6. package/dist/__tests__/cli-save.test.d.ts +0 -12
  7. package/dist/__tests__/cli-save.test.d.ts.map +0 -1
  8. package/dist/__tests__/cli-save.test.js +0 -109
  9. package/dist/__tests__/cli-save.test.js.map +0 -1
  10. package/dist/__tests__/cli.test.d.ts +0 -7
  11. package/dist/__tests__/cli.test.d.ts.map +0 -1
  12. package/dist/__tests__/cli.test.js +0 -133
  13. package/dist/__tests__/cli.test.js.map +0 -1
  14. package/dist/__tests__/codex-transcript.test.d.ts +0 -11
  15. package/dist/__tests__/codex-transcript.test.d.ts.map +0 -1
  16. package/dist/__tests__/codex-transcript.test.js +0 -372
  17. package/dist/__tests__/codex-transcript.test.js.map +0 -1
  18. package/dist/__tests__/enrollment-isError.test.d.ts +0 -9
  19. package/dist/__tests__/enrollment-isError.test.d.ts.map +0 -1
  20. package/dist/__tests__/enrollment-isError.test.js +0 -119
  21. package/dist/__tests__/enrollment-isError.test.js.map +0 -1
  22. package/dist/__tests__/format.test.d.ts +0 -2
  23. package/dist/__tests__/format.test.d.ts.map +0 -1
  24. package/dist/__tests__/format.test.js +0 -229
  25. package/dist/__tests__/format.test.js.map +0 -1
  26. package/dist/__tests__/gemini-transcript.test.d.ts +0 -12
  27. package/dist/__tests__/gemini-transcript.test.d.ts.map +0 -1
  28. package/dist/__tests__/gemini-transcript.test.js +0 -322
  29. package/dist/__tests__/gemini-transcript.test.js.map +0 -1
  30. package/dist/__tests__/get-context-repo-resolution.test.d.ts +0 -11
  31. package/dist/__tests__/get-context-repo-resolution.test.d.ts.map +0 -1
  32. package/dist/__tests__/get-context-repo-resolution.test.js +0 -310
  33. package/dist/__tests__/get-context-repo-resolution.test.js.map +0 -1
  34. package/dist/__tests__/integration.test.d.ts +0 -11
  35. package/dist/__tests__/integration.test.d.ts.map +0 -1
  36. package/dist/__tests__/integration.test.js +0 -323
  37. package/dist/__tests__/integration.test.js.map +0 -1
  38. package/dist/__tests__/no-git-repo.test.d.ts +0 -9
  39. package/dist/__tests__/no-git-repo.test.d.ts.map +0 -1
  40. package/dist/__tests__/no-git-repo.test.js +0 -125
  41. package/dist/__tests__/no-git-repo.test.js.map +0 -1
  42. package/dist/__tests__/preprocessor.test.d.ts +0 -12
  43. package/dist/__tests__/preprocessor.test.d.ts.map +0 -1
  44. package/dist/__tests__/preprocessor.test.js +0 -690
  45. package/dist/__tests__/preprocessor.test.js.map +0 -1
  46. package/dist/__tests__/repo-detection-guard.test.d.ts +0 -9
  47. package/dist/__tests__/repo-detection-guard.test.d.ts.map +0 -1
  48. package/dist/__tests__/repo-detection-guard.test.js +0 -153
  49. package/dist/__tests__/repo-detection-guard.test.js.map +0 -1
  50. package/dist/__tests__/repo-enrollment.test.d.ts +0 -9
  51. package/dist/__tests__/repo-enrollment.test.d.ts.map +0 -1
  52. package/dist/__tests__/repo-enrollment.test.js +0 -107
  53. package/dist/__tests__/repo-enrollment.test.js.map +0 -1
  54. package/dist/__tests__/repo-override-save-log.test.d.ts +0 -11
  55. package/dist/__tests__/repo-override-save-log.test.d.ts.map +0 -1
  56. package/dist/__tests__/repo-override-save-log.test.js +0 -352
  57. package/dist/__tests__/repo-override-save-log.test.js.map +0 -1
  58. package/dist/api.d.ts +0 -353
  59. package/dist/api.d.ts.map +0 -1
  60. package/dist/api.js +0 -727
  61. package/dist/api.js.map +0 -1
  62. package/dist/auth/__tests__/auth-store.test.d.ts +0 -6
  63. package/dist/auth/__tests__/auth-store.test.d.ts.map +0 -1
  64. package/dist/auth/__tests__/auth-store.test.js +0 -161
  65. package/dist/auth/__tests__/auth-store.test.js.map +0 -1
  66. package/dist/auth/__tests__/device-client.test.d.ts +0 -10
  67. package/dist/auth/__tests__/device-client.test.d.ts.map +0 -1
  68. package/dist/auth/__tests__/device-client.test.js +0 -327
  69. package/dist/auth/__tests__/device-client.test.js.map +0 -1
  70. package/dist/auth/__tests__/preflight.test.d.ts +0 -2
  71. package/dist/auth/__tests__/preflight.test.d.ts.map +0 -1
  72. package/dist/auth/__tests__/preflight.test.js +0 -37
  73. package/dist/auth/__tests__/preflight.test.js.map +0 -1
  74. package/dist/auth/__tests__/run-auth.test.d.ts +0 -11
  75. package/dist/auth/__tests__/run-auth.test.d.ts.map +0 -1
  76. package/dist/auth/__tests__/run-auth.test.js +0 -387
  77. package/dist/auth/__tests__/run-auth.test.js.map +0 -1
  78. package/dist/auth/__tests__/tool-detection.test.d.ts +0 -10
  79. package/dist/auth/__tests__/tool-detection.test.d.ts.map +0 -1
  80. package/dist/auth/__tests__/tool-detection.test.js +0 -122
  81. package/dist/auth/__tests__/tool-detection.test.js.map +0 -1
  82. package/dist/auth/__tests__/tool-patching.test.d.ts +0 -13
  83. package/dist/auth/__tests__/tool-patching.test.d.ts.map +0 -1
  84. package/dist/auth/__tests__/tool-patching.test.js +0 -385
  85. package/dist/auth/__tests__/tool-patching.test.js.map +0 -1
  86. package/dist/auth/auth-store.d.ts +0 -61
  87. package/dist/auth/auth-store.d.ts.map +0 -1
  88. package/dist/auth/auth-store.js +0 -158
  89. package/dist/auth/auth-store.js.map +0 -1
  90. package/dist/auth/device-client.d.ts +0 -85
  91. package/dist/auth/device-client.d.ts.map +0 -1
  92. package/dist/auth/device-client.js +0 -269
  93. package/dist/auth/device-client.js.map +0 -1
  94. package/dist/auth/preflight.d.ts +0 -10
  95. package/dist/auth/preflight.d.ts.map +0 -1
  96. package/dist/auth/preflight.js +0 -35
  97. package/dist/auth/preflight.js.map +0 -1
  98. package/dist/auth/run-auth.d.ts +0 -56
  99. package/dist/auth/run-auth.d.ts.map +0 -1
  100. package/dist/auth/run-auth.js +0 -222
  101. package/dist/auth/run-auth.js.map +0 -1
  102. package/dist/auth/tool-detection.d.ts +0 -47
  103. package/dist/auth/tool-detection.d.ts.map +0 -1
  104. package/dist/auth/tool-detection.js +0 -99
  105. package/dist/auth/tool-detection.js.map +0 -1
  106. package/dist/auth/tool-patching.d.ts +0 -85
  107. package/dist/auth/tool-patching.d.ts.map +0 -1
  108. package/dist/auth/tool-patching.js +0 -353
  109. package/dist/auth/tool-patching.js.map +0 -1
  110. package/dist/cli.d.ts +0 -32
  111. package/dist/cli.d.ts.map +0 -1
  112. package/dist/cli.js +0 -315
  113. package/dist/cli.js.map +0 -1
  114. package/dist/codex-transcript.d.ts +0 -31
  115. package/dist/codex-transcript.d.ts.map +0 -1
  116. package/dist/codex-transcript.js +0 -304
  117. package/dist/codex-transcript.js.map +0 -1
  118. package/dist/crypto.d.ts +0 -36
  119. package/dist/crypto.d.ts.map +0 -1
  120. package/dist/crypto.js +0 -104
  121. package/dist/crypto.js.map +0 -1
  122. package/dist/detect.d.ts +0 -40
  123. package/dist/detect.d.ts.map +0 -1
  124. package/dist/detect.js +0 -165
  125. package/dist/detect.js.map +0 -1
  126. package/dist/format.d.ts +0 -53
  127. package/dist/format.d.ts.map +0 -1
  128. package/dist/format.js +0 -177
  129. package/dist/format.js.map +0 -1
  130. package/dist/gemini-transcript.d.ts +0 -29
  131. package/dist/gemini-transcript.d.ts.map +0 -1
  132. package/dist/gemini-transcript.js +0 -303
  133. package/dist/gemini-transcript.js.map +0 -1
  134. package/dist/index.d.ts +0 -12
  135. package/dist/index.d.ts.map +0 -1
  136. package/dist/index.js +0 -291
  137. package/dist/index.js.map +0 -1
  138. package/dist/preprocessor.d.ts +0 -39
  139. package/dist/preprocessor.d.ts.map +0 -1
  140. package/dist/preprocessor.js +0 -514
  141. package/dist/preprocessor.js.map +0 -1
  142. package/dist/tools.d.ts +0 -106
  143. package/dist/tools.d.ts.map +0 -1
  144. package/dist/tools.js +0 -784
  145. package/dist/tools.js.map +0 -1
  146. package/dist/transcript-finder.d.ts +0 -27
  147. package/dist/transcript-finder.d.ts.map +0 -1
  148. package/dist/transcript-finder.js +0 -143
  149. package/dist/transcript-finder.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recall-mcp-v3",
3
- "version": "3.9.0",
3
+ "version": "3.9.1",
4
4
  "description": "Recall MCP server for Claude Code - team memory for AI coding assistants",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,18 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-get-token.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/api-get-token.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
@@ -1,195 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-get-token.test.js","sourceRoot":"","sources":["../../src/__tests__/api-get-token.test.ts"],"names":[],"mappings":"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"}
@@ -1,12 +0,0 @@
1
- /**
2
- * Tests for CLI save pipeline alignment (Phase 4).
3
- *
4
- * Verifies that the SessionEnd hook (cli.ts saveTranscript) uses the same
5
- * server-side pipeline as the MCP recall_save_session tool:
6
- * JSONL transcript → preprocess → api.resolveRepo → api.saveSessionAsync
7
- *
8
- * NOT the old path:
9
- * JSONL → preprocess → /v1/summarize (sync) → encrypt client-side → POST /sessions
10
- */
11
- export {};
12
- //# sourceMappingURL=cli-save.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-save.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-save.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
@@ -1,109 +0,0 @@
1
- /**
2
- * Tests for CLI save pipeline alignment (Phase 4).
3
- *
4
- * Verifies that the SessionEnd hook (cli.ts saveTranscript) uses the same
5
- * server-side pipeline as the MCP recall_save_session tool:
6
- * JSONL transcript → preprocess → api.resolveRepo → api.saveSessionAsync
7
- *
8
- * NOT the old path:
9
- * JSONL → preprocess → /v1/summarize (sync) → encrypt client-side → POST /sessions
10
- */
11
- import { describe, it, expect, vi, beforeEach } from 'vitest';
12
- // Mock api module - this is what cli.ts uses
13
- vi.mock('../api.js', () => ({
14
- resolveRepo: vi.fn().mockResolvedValue({ repoId: 'repo-123', teamId: 'team-456' }),
15
- saveSessionAsync: vi.fn().mockResolvedValue({ id: 'session-789', created_at: '2026-02-09' }),
16
- }));
17
- // Mock fs for transcript reading
18
- vi.mock('fs', async (importOriginal) => {
19
- const actual = await importOriginal();
20
- return {
21
- ...actual,
22
- readFileSync: vi.fn().mockReturnValue('{"type":"message","role":"user"}\n{"type":"message","role":"assistant"}'),
23
- existsSync: vi.fn().mockReturnValue(true),
24
- readdirSync: vi.fn().mockReturnValue([]),
25
- };
26
- });
27
- // Mock child_process for git commands
28
- vi.mock('child_process', () => ({
29
- execSync: vi.fn((cmd) => {
30
- if (cmd.includes('remote.origin.url'))
31
- return 'https://github.com/testorg/testrepo.git\n';
32
- if (cmd.includes('rev-parse --abbrev-ref'))
33
- return 'main\n';
34
- return '';
35
- }),
36
- }));
37
- // Mock preprocessor - content must be >= 100 chars (cli.ts threshold)
38
- vi.mock('../preprocessor.js', () => ({
39
- preprocessTranscript: vi.fn().mockResolvedValue({
40
- content: '## Assistant\nFixed the login bug by updating the auth middleware. The root cause was an expired JWT token check that was comparing timestamps incorrectly. Updated the comparison logic and added tests.',
41
- stats: { originalSize: 5000, processedSize: 500, messagesExtracted: 10, errorsFound: 0, toolCallsLogged: 3 },
42
- }),
43
- }));
44
- // Mock format
45
- vi.mock('../format.js', () => ({
46
- extractPreliminarySummary: vi.fn().mockReturnValue('Fixed login bug'),
47
- }));
48
- import { saveTranscript } from '../cli.js';
49
- import * as api from '../api.js';
50
- describe('CLI saveTranscript pipeline alignment', () => {
51
- beforeEach(() => {
52
- vi.clearAllMocks();
53
- process.env.RECALL_API_TOKEN = 'rcl_test_token_12345';
54
- process.env.RECALL_API_URL = 'https://api-v3.recall.team';
55
- });
56
- it('should call api.saveSessionAsync (the async pipeline)', async () => {
57
- await saveTranscript({
58
- transcriptPath: '/test/transcript.jsonl',
59
- cwd: '/test/project',
60
- quiet: true,
61
- });
62
- // Verify saveSessionAsync was called (same pipeline as typing save)
63
- expect(api.saveSessionAsync).toHaveBeenCalledOnce();
64
- expect(api.saveSessionAsync).toHaveBeenCalledWith('repo-123', expect.any(String), expect.objectContaining({
65
- tool: 'claude-code',
66
- }));
67
- });
68
- it('should send preprocessed transcript content to saveSessionAsync', async () => {
69
- await saveTranscript({
70
- transcriptPath: '/test/transcript.jsonl',
71
- cwd: '/test/project',
72
- quiet: true,
73
- });
74
- // The second arg to saveSessionAsync is the transcript content
75
- const transcript = api.saveSessionAsync.mock.calls[0]?.[1];
76
- expect(transcript).toBeDefined();
77
- expect(typeof transcript).toBe('string');
78
- expect(transcript.length).toBeGreaterThan(0);
79
- // Should be the preprocessed content, not raw JSONL
80
- expect(transcript).toContain('Fixed the login bug');
81
- expect(transcript).toContain('expired JWT token');
82
- });
83
- it('should call api.resolveRepo before saving', async () => {
84
- await saveTranscript({
85
- transcriptPath: '/test/transcript.jsonl',
86
- cwd: '/test/project',
87
- quiet: true,
88
- });
89
- // Verify resolveRepo was called with extracted git info
90
- expect(api.resolveRepo).toHaveBeenCalledOnce();
91
- expect(api.resolveRepo).toHaveBeenCalledWith('testorg/testrepo', 'main');
92
- });
93
- it('should NOT use old summarize-then-encrypt path', async () => {
94
- // Mock global fetch to detect any direct API calls
95
- const mockFetch = vi.fn();
96
- vi.stubGlobal('fetch', mockFetch);
97
- await saveTranscript({
98
- transcriptPath: '/test/transcript.jsonl',
99
- cwd: '/test/project',
100
- quiet: true,
101
- });
102
- // cli.ts should NOT call fetch directly - everything goes through api module
103
- // No calls to /v1/summarize or direct /sessions POST
104
- const summarizeCall = mockFetch.mock.calls.find((call) => typeof call[0] === 'string' && call[0].includes('/v1/summarize'));
105
- expect(summarizeCall).toBeUndefined();
106
- vi.unstubAllGlobals();
107
- });
108
- });
109
- //# sourceMappingURL=cli-save.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-save.test.js","sourceRoot":"","sources":["../../src/__tests__/cli-save.test.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- /**
2
- * CLI Unit Tests
3
- *
4
- * Tests for findCurrentTranscript and related CLI functions.
5
- */
6
- export {};
7
- //# sourceMappingURL=cli.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -1,133 +0,0 @@
1
- /**
2
- * CLI Unit Tests
3
- *
4
- * Tests for findCurrentTranscript and related CLI functions.
5
- */
6
- import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
7
- import * as fs from 'fs';
8
- import * as path from 'path';
9
- import * as os from 'os';
10
- import { findCurrentTranscript } from '../cli.js';
11
- // Test fixtures directory (simulates ~/.claude/projects/)
12
- const TEST_CLAUDE_DIR = path.join(os.tmpdir(), 'recall-cli-tests', '.claude', 'projects');
13
- const TEST_PROJECT_PATH = '/Users/testuser/projects/my-app';
14
- // Claude Code hash algorithm: replace all / with -
15
- // e.g., /Users/testuser/projects/my-app -> -Users-testuser-projects-my-app
16
- const PROJECT_HASH = TEST_PROJECT_PATH.replace(/\//g, '-');
17
- const TRANSCRIPT_DIR = path.join(TEST_CLAUDE_DIR, PROJECT_HASH);
18
- describe('findCurrentTranscript', () => {
19
- beforeAll(() => {
20
- // Create the test directory structure
21
- fs.mkdirSync(TRANSCRIPT_DIR, { recursive: true });
22
- });
23
- afterAll(() => {
24
- // Cleanup
25
- const testRoot = path.join(os.tmpdir(), 'recall-cli-tests');
26
- if (fs.existsSync(testRoot)) {
27
- fs.rmSync(testRoot, { recursive: true });
28
- }
29
- });
30
- beforeEach(() => {
31
- // Clear any files from previous tests
32
- if (fs.existsSync(TRANSCRIPT_DIR)) {
33
- const files = fs.readdirSync(TRANSCRIPT_DIR);
34
- for (const file of files) {
35
- fs.unlinkSync(path.join(TRANSCRIPT_DIR, file));
36
- }
37
- }
38
- });
39
- it('returns null if directory not found', () => {
40
- // Use a path that doesn't exist
41
- const result = findCurrentTranscript('/nonexistent/path/to/project');
42
- expect(result).toBeNull();
43
- });
44
- it('returns null if no .jsonl files exist', () => {
45
- // Directory exists but is empty
46
- const result = findCurrentTranscript(TEST_PROJECT_PATH);
47
- // This will fail because we're using a mock path, but the logic is correct
48
- // In real usage, it would check ~/.claude/projects/<hash>/
49
- // For this test, we're verifying the function handles empty directories
50
- expect(result).toBeNull();
51
- });
52
- it('returns the most recent .jsonl file when multiple exist', () => {
53
- // Create multiple transcript files with different mtimes
54
- const oldFile = path.join(TRANSCRIPT_DIR, 'old-session.jsonl');
55
- const newFile = path.join(TRANSCRIPT_DIR, 'new-session.jsonl');
56
- // Create old file first
57
- fs.writeFileSync(oldFile, '{"type":"user","content":"old"}');
58
- // Wait a bit to ensure different mtime
59
- const oldTime = new Date(Date.now() - 10000);
60
- fs.utimesSync(oldFile, oldTime, oldTime);
61
- // Create new file
62
- fs.writeFileSync(newFile, '{"type":"user","content":"new"}');
63
- // The function looks in ~/.claude/projects/<hash>/, not our test dir directly
64
- // This test documents the expected behavior
65
- // In practice, we'd need to mock os.homedir() to fully test this
66
- });
67
- it('handles paths with special characters', () => {
68
- // Test path with spaces or special chars
69
- const specialPath = '/Users/test user/my projects/app-v2';
70
- const expectedHash = specialPath.replace(/\//g, '-');
71
- // Verify the hash algorithm
72
- expect(expectedHash).toBe('-Users-test user-my projects-app-v2');
73
- });
74
- it('keeps leading dash in project hash', () => {
75
- // Verify the hash algorithm preserves leading dash
76
- const testPath = '/Users/ray/projects/recall';
77
- const hash = testPath.replace(/\//g, '-');
78
- expect(hash).toBe('-Users-ray-projects-recall');
79
- expect(hash.startsWith('-')).toBe(true);
80
- });
81
- });
82
- describe('findCurrentTranscript - hash algorithm', () => {
83
- it('correctly converts absolute paths to Claude Code hashes', () => {
84
- const testCases = [
85
- {
86
- path: '/Users/ray/projects/recall-v3',
87
- expected: '-Users-ray-projects-recall-v3',
88
- },
89
- {
90
- path: '/home/developer/work/my-app',
91
- expected: '-home-developer-work-my-app',
92
- },
93
- {
94
- path: '/Users/rayhernandez/Library/CloudStorage/Dropbox-Personal/Goldfish/personal/Recall-v3',
95
- expected: '-Users-rayhernandez-Library-CloudStorage-Dropbox-Personal-Goldfish-personal-Recall-v3',
96
- },
97
- ];
98
- for (const { path: testPath, expected } of testCases) {
99
- const hash = testPath.replace(/\//g, '-');
100
- expect(hash).toBe(expected);
101
- }
102
- });
103
- });
104
- describe('findCurrentTranscript - directory tree walking', () => {
105
- it('walks up directory tree to find transcripts from subdirectories', () => {
106
- // This is a behavioral test documenting the expected behavior.
107
- // When called from a subdirectory like /project/packages/mcp-v3,
108
- // the function should walk up to /project and find transcripts there.
109
- //
110
- // The algorithm:
111
- // 1. Start at the given path
112
- // 2. Check if ~/.claude/projects/<hash>/ exists
113
- // 3. If not, move up one directory and repeat
114
- // 4. Stop at filesystem root
115
- //
116
- // Example:
117
- // Input: /Users/ray/projects/recall-v3/packages/mcp-v3
118
- // Check: ~/.claude/projects/-Users-ray-projects-recall-v3-packages-mcp-v3 (not found)
119
- // Check: ~/.claude/projects/-Users-ray-projects-recall-v3-packages (not found)
120
- // Check: ~/.claude/projects/-Users-ray-projects-recall-v3 (FOUND!)
121
- // We can't fully test this without mocking os.homedir(), but we verify
122
- // that the function returns null for nonexistent paths (doesn't infinite loop)
123
- const deepPath = '/nonexistent/very/deep/nested/path/here';
124
- const result = findCurrentTranscript(deepPath);
125
- expect(result).toBeNull();
126
- });
127
- it('handles root path without infinite loop', () => {
128
- // Edge case: calling with root path should not loop forever
129
- const result = findCurrentTranscript('/');
130
- expect(result).toBeNull();
131
- });
132
- });
133
- //# sourceMappingURL=cli.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../src/__tests__/cli.test.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- /**
2
- * Tests for Codex Transcript Finder & Preprocessor
3
- *
4
- * Verifies:
5
- * 1. CWD matching from session_meta
6
- * 2. Noise filtering (event_msg, developer messages, session_meta, turn_context)
7
- * 3. Signal preservation (user, assistant, reasoning, function_call, function_call_output)
8
- * 4. Output format is clean markdown with no YAML
9
- */
10
- export {};
11
- //# sourceMappingURL=codex-transcript.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"codex-transcript.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/codex-transcript.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}