recall-mcp-v3 3.0.1 → 3.1.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.
- package/dist/api.d.ts +65 -33
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +187 -14
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts +20 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +295 -0
- package/dist/cli.js.map +1 -0
- package/dist/crypto.d.ts +36 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +104 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -1,18 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Recall API Client
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Reads token from RECALL_API_TOKEN environment variable
|
|
4
|
+
* HTTP client for the Recall v3 API with encryption support.
|
|
5
|
+
* - Reads token from RECALL_API_TOKEN environment variable
|
|
6
|
+
* - Fetches team encryption key from API
|
|
7
|
+
* - Encrypts content before sending, decrypts after receiving
|
|
6
8
|
*/
|
|
7
9
|
declare class RecallApiError extends Error {
|
|
8
10
|
code: string;
|
|
9
11
|
status: number;
|
|
10
12
|
constructor(message: string, code: string, status: number);
|
|
11
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Fetch the team encryption key from API.
|
|
16
|
+
* Caches the key in memory for the duration of the process.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getTeamKey(): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Get cached team tier (must call getTeamKey first).
|
|
21
|
+
*/
|
|
22
|
+
export declare function getCachedTier(): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Clear cached team key (useful for testing or key rotation).
|
|
25
|
+
*/
|
|
26
|
+
export declare function clearKeyCache(): void;
|
|
12
27
|
interface ResolveRepoResponse {
|
|
13
28
|
repoId: string;
|
|
14
29
|
teamId: string;
|
|
15
30
|
}
|
|
31
|
+
interface SessionUser {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string | null;
|
|
34
|
+
github_username: string | null;
|
|
35
|
+
avatar_url?: string | null;
|
|
36
|
+
}
|
|
16
37
|
interface Session {
|
|
17
38
|
id: string;
|
|
18
39
|
summary: string;
|
|
@@ -25,36 +46,19 @@ interface Session {
|
|
|
25
46
|
files_changed?: string[];
|
|
26
47
|
blockers?: string | null;
|
|
27
48
|
next_steps?: string | null;
|
|
28
|
-
user:
|
|
29
|
-
id: string;
|
|
30
|
-
name: string | null;
|
|
31
|
-
github_username: string | null;
|
|
32
|
-
};
|
|
49
|
+
user: SessionUser;
|
|
33
50
|
}
|
|
34
|
-
interface
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
interface HistoryDecision {
|
|
52
|
+
id: string;
|
|
53
|
+
decision: string;
|
|
54
|
+
reasoning: string;
|
|
55
|
+
created_at: string;
|
|
56
|
+
user: SessionUser;
|
|
39
57
|
}
|
|
40
|
-
interface
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
decision: string;
|
|
45
|
-
reasoning: string;
|
|
46
|
-
created_at: string;
|
|
47
|
-
user: {
|
|
48
|
-
id: string;
|
|
49
|
-
name: string | null;
|
|
50
|
-
github_username: string | null;
|
|
51
|
-
};
|
|
52
|
-
}>;
|
|
53
|
-
mistakes: Array<{
|
|
54
|
-
id: string;
|
|
55
|
-
content: string;
|
|
56
|
-
created_at: string;
|
|
57
|
-
}>;
|
|
58
|
+
interface HistoryMistake {
|
|
59
|
+
id: string;
|
|
60
|
+
content: string;
|
|
61
|
+
created_at: string;
|
|
58
62
|
}
|
|
59
63
|
interface SaveSessionResponse {
|
|
60
64
|
id: string;
|
|
@@ -65,9 +69,34 @@ interface LogDecisionResponse {
|
|
|
65
69
|
created_at: string;
|
|
66
70
|
}
|
|
67
71
|
export declare function resolveRepo(fullName: string, defaultBranch?: string): Promise<ResolveRepoResponse>;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Get context for a repo. Decrypts session content.
|
|
74
|
+
*/
|
|
75
|
+
export declare function getContext(repoId: string): Promise<{
|
|
76
|
+
sessions: Session[];
|
|
77
|
+
cached_context: string;
|
|
78
|
+
session_count: number;
|
|
79
|
+
tier: string;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Get history for a repo. Decrypts session, decision, and mistake content.
|
|
83
|
+
*/
|
|
84
|
+
export declare function getHistory(repoId: string, days?: number): Promise<{
|
|
85
|
+
sessions: Session[];
|
|
86
|
+
decisions: HistoryDecision[];
|
|
87
|
+
mistakes: HistoryMistake[];
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* Get transcripts for a repo. Same as history but for Pro tier with full content.
|
|
91
|
+
*/
|
|
92
|
+
export declare function getTranscripts(repoId: string): Promise<{
|
|
93
|
+
sessions: Session[];
|
|
94
|
+
decisions: HistoryDecision[];
|
|
95
|
+
mistakes: HistoryMistake[];
|
|
96
|
+
}>;
|
|
97
|
+
/**
|
|
98
|
+
* Save a session. Encrypts content before sending.
|
|
99
|
+
*/
|
|
71
100
|
export declare function saveSession(repoId: string, data: {
|
|
72
101
|
summary: string;
|
|
73
102
|
status?: 'complete' | 'in-progress' | 'blocked';
|
|
@@ -80,6 +109,9 @@ export declare function saveSession(repoId: string, data: {
|
|
|
80
109
|
next_steps?: string;
|
|
81
110
|
blockers?: string;
|
|
82
111
|
}): Promise<SaveSessionResponse>;
|
|
112
|
+
/**
|
|
113
|
+
* Log a decision. Encrypts content before sending.
|
|
114
|
+
*/
|
|
83
115
|
export declare function logDecision(repoId: string, decision: string, reasoning: string): Promise<LogDecisionResponse>;
|
|
84
116
|
export { RecallApiError };
|
|
85
117
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Recall API Client
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Reads token from RECALL_API_TOKEN environment variable
|
|
4
|
+
* HTTP client for the Recall v3 API with encryption support.
|
|
5
|
+
* - Reads token from RECALL_API_TOKEN environment variable
|
|
6
|
+
* - Fetches team encryption key from API
|
|
7
|
+
* - Encrypts content before sending, decrypts after receiving
|
|
6
8
|
*/
|
|
9
|
+
import { encrypt, decrypt, isEncrypted, safeDecrypt } from './crypto.js';
|
|
7
10
|
const API_URL = process.env.RECALL_API_URL || 'https://api-v3.recall.team';
|
|
11
|
+
// Cache team key in memory (per process)
|
|
12
|
+
let cachedTeamKey = null;
|
|
13
|
+
let cachedTeamId = null;
|
|
14
|
+
let cachedTier = null;
|
|
8
15
|
class RecallApiError extends Error {
|
|
9
16
|
code;
|
|
10
17
|
status;
|
|
@@ -29,46 +36,212 @@ async function request(method, path, body) {
|
|
|
29
36
|
method,
|
|
30
37
|
headers: {
|
|
31
38
|
'Content-Type': 'application/json',
|
|
32
|
-
|
|
39
|
+
Authorization: `Bearer ${token}`,
|
|
33
40
|
},
|
|
34
41
|
body: body ? JSON.stringify(body) : undefined,
|
|
35
42
|
});
|
|
36
43
|
if (!response.ok) {
|
|
37
|
-
const errorBody = await response.json().catch(() => ({}));
|
|
44
|
+
const errorBody = (await response.json().catch(() => ({})));
|
|
38
45
|
throw new RecallApiError(errorBody.error || `HTTP ${response.status}`, errorBody.code || 'API_ERROR', response.status);
|
|
39
46
|
}
|
|
40
47
|
return response.json();
|
|
41
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Fetch the team encryption key from API.
|
|
51
|
+
* Caches the key in memory for the duration of the process.
|
|
52
|
+
*/
|
|
53
|
+
export async function getTeamKey() {
|
|
54
|
+
if (cachedTeamKey) {
|
|
55
|
+
return cachedTeamKey;
|
|
56
|
+
}
|
|
57
|
+
const response = await request('GET', '/v1/keys/team');
|
|
58
|
+
if (!response.hasAccess) {
|
|
59
|
+
throw new RecallApiError('No access to team encryption key', 'NO_ACCESS', 403);
|
|
60
|
+
}
|
|
61
|
+
cachedTeamKey = response.encryptionKey;
|
|
62
|
+
cachedTeamId = response.teamId;
|
|
63
|
+
cachedTier = response.tier;
|
|
64
|
+
return cachedTeamKey;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get cached team tier (must call getTeamKey first).
|
|
68
|
+
*/
|
|
69
|
+
export function getCachedTier() {
|
|
70
|
+
return cachedTier;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Clear cached team key (useful for testing or key rotation).
|
|
74
|
+
*/
|
|
75
|
+
export function clearKeyCache() {
|
|
76
|
+
cachedTeamKey = null;
|
|
77
|
+
cachedTeamId = null;
|
|
78
|
+
cachedTier = null;
|
|
79
|
+
}
|
|
80
|
+
// ============================================================================
|
|
42
81
|
// API Methods
|
|
82
|
+
// ============================================================================
|
|
43
83
|
export async function resolveRepo(fullName, defaultBranch) {
|
|
44
|
-
return request('POST', '/v1/repos/resolve', {
|
|
84
|
+
return request('POST', '/v1/repos/resolve', {
|
|
85
|
+
fullName,
|
|
86
|
+
defaultBranch,
|
|
87
|
+
});
|
|
45
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Get context for a repo. Decrypts session content.
|
|
91
|
+
*/
|
|
46
92
|
export async function getContext(repoId) {
|
|
47
|
-
|
|
93
|
+
// Ensure we have the team key for decryption
|
|
94
|
+
const teamKey = await getTeamKey();
|
|
95
|
+
const response = await request('GET', `/v1/repos/${repoId}/context`);
|
|
96
|
+
// Decrypt session content
|
|
97
|
+
const sessions = response.sessions.map((raw) => {
|
|
98
|
+
// Try to decrypt encrypted_content, use tldr_summary as fallback
|
|
99
|
+
let summary = raw.tldr_summary || '';
|
|
100
|
+
if (raw.encrypted_content && isEncrypted(raw.encrypted_content)) {
|
|
101
|
+
try {
|
|
102
|
+
summary = decrypt(raw.encrypted_content, teamKey);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// If decryption fails, use tldr_summary
|
|
106
|
+
summary = raw.tldr_summary || '';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (raw.encrypted_content) {
|
|
110
|
+
// Not encrypted (legacy or plaintext) - use as-is
|
|
111
|
+
summary = raw.encrypted_content;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
id: raw.id,
|
|
115
|
+
summary,
|
|
116
|
+
status: raw.status,
|
|
117
|
+
started_at: raw.started_at,
|
|
118
|
+
ended_at: raw.ended_at,
|
|
119
|
+
user: raw.user,
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
sessions,
|
|
124
|
+
cached_context: response.cached_context,
|
|
125
|
+
session_count: response.session_count,
|
|
126
|
+
tier: response.tier,
|
|
127
|
+
};
|
|
48
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Get history for a repo. Decrypts session, decision, and mistake content.
|
|
131
|
+
*/
|
|
49
132
|
export async function getHistory(repoId, days = 30) {
|
|
50
|
-
|
|
133
|
+
// Ensure we have the team key for decryption
|
|
134
|
+
const teamKey = await getTeamKey();
|
|
135
|
+
const response = await request('GET', `/v1/repos/${repoId}/history?days=${days}`);
|
|
136
|
+
// Decrypt sessions
|
|
137
|
+
const sessions = response.sessions.map((raw) => {
|
|
138
|
+
let summary = raw.tldr_summary || '';
|
|
139
|
+
if (raw.encrypted_content && isEncrypted(raw.encrypted_content)) {
|
|
140
|
+
summary = safeDecrypt(raw.encrypted_content, teamKey);
|
|
141
|
+
}
|
|
142
|
+
else if (raw.encrypted_content) {
|
|
143
|
+
summary = raw.encrypted_content;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
id: raw.id,
|
|
147
|
+
summary,
|
|
148
|
+
status: raw.status,
|
|
149
|
+
started_at: raw.started_at,
|
|
150
|
+
ended_at: raw.ended_at,
|
|
151
|
+
user: raw.user,
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
// Decrypt decisions
|
|
155
|
+
const decisions = response.decisions.map((raw) => {
|
|
156
|
+
let reasoning = '';
|
|
157
|
+
if (raw.encrypted_content && isEncrypted(raw.encrypted_content)) {
|
|
158
|
+
reasoning = safeDecrypt(raw.encrypted_content, teamKey);
|
|
159
|
+
}
|
|
160
|
+
else if (raw.encrypted_content) {
|
|
161
|
+
reasoning = raw.encrypted_content;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
id: raw.id,
|
|
165
|
+
decision: raw.title,
|
|
166
|
+
reasoning,
|
|
167
|
+
created_at: raw.created_at,
|
|
168
|
+
user: raw.user,
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
// Decrypt mistakes
|
|
172
|
+
const mistakes = response.mistakes.map((raw) => {
|
|
173
|
+
let content = raw.title;
|
|
174
|
+
if (raw.encrypted_content && isEncrypted(raw.encrypted_content)) {
|
|
175
|
+
content = safeDecrypt(raw.encrypted_content, teamKey);
|
|
176
|
+
}
|
|
177
|
+
else if (raw.encrypted_content) {
|
|
178
|
+
content = raw.encrypted_content;
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
id: raw.id,
|
|
182
|
+
content,
|
|
183
|
+
created_at: raw.created_at,
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
return { sessions, decisions, mistakes };
|
|
51
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Get transcripts for a repo. Same as history but for Pro tier with full content.
|
|
190
|
+
*/
|
|
52
191
|
export async function getTranscripts(repoId) {
|
|
53
|
-
|
|
192
|
+
// Use the history endpoint with longer timeframe for transcripts
|
|
193
|
+
return getHistory(repoId, 90);
|
|
54
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* Save a session. Encrypts content before sending.
|
|
197
|
+
*/
|
|
55
198
|
export async function saveSession(repoId, data) {
|
|
56
|
-
|
|
199
|
+
// Ensure we have the team key for encryption
|
|
200
|
+
const teamKey = await getTeamKey();
|
|
201
|
+
// Build the content to encrypt (full session summary)
|
|
202
|
+
const contentToEncrypt = JSON.stringify({
|
|
57
203
|
summary: data.summary,
|
|
58
|
-
status: data.status || 'complete',
|
|
59
204
|
decisions: data.decisions,
|
|
60
205
|
mistakes: data.mistakes,
|
|
61
206
|
files_changed: data.files_changed,
|
|
62
207
|
next_steps: data.next_steps,
|
|
63
208
|
blockers: data.blockers,
|
|
64
|
-
|
|
65
|
-
|
|
209
|
+
});
|
|
210
|
+
// Encrypt the content
|
|
211
|
+
const encryptedContent = encrypt(contentToEncrypt, teamKey);
|
|
212
|
+
// Build TLDR for plaintext metadata
|
|
213
|
+
const tldr = {
|
|
214
|
+
summary: data.summary.substring(0, 1000), // First 1000 chars for search
|
|
215
|
+
status: data.status || 'complete',
|
|
216
|
+
decisions: data.decisions?.map((d) => d.what) || [],
|
|
217
|
+
mistakes: data.mistakes || [],
|
|
218
|
+
tags: [], // Could extract tags from content
|
|
219
|
+
files_changed: data.files_changed || [],
|
|
220
|
+
blockers: data.blockers || null,
|
|
221
|
+
next_steps: data.next_steps || null,
|
|
222
|
+
};
|
|
223
|
+
const now = new Date().toISOString();
|
|
224
|
+
// Send to API with encrypted content + plaintext TLDR
|
|
225
|
+
return request('POST', `/v1/repos/${repoId}/sessions`, {
|
|
226
|
+
encrypted_content: encryptedContent,
|
|
227
|
+
tldr,
|
|
228
|
+
started_at: now,
|
|
229
|
+
ended_at: now,
|
|
230
|
+
tool: 'claude-code',
|
|
66
231
|
});
|
|
67
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Log a decision. Encrypts content before sending.
|
|
235
|
+
*/
|
|
68
236
|
export async function logDecision(repoId, decision, reasoning) {
|
|
237
|
+
// Ensure we have the team key for encryption
|
|
238
|
+
const teamKey = await getTeamKey();
|
|
239
|
+
// Encrypt the reasoning (the full decision context)
|
|
240
|
+
const encryptedContent = encrypt(reasoning, teamKey);
|
|
241
|
+
// API expects: title (plaintext for search) + encrypted_content
|
|
69
242
|
return request('POST', `/v1/repos/${repoId}/decisions`, {
|
|
70
|
-
decision,
|
|
71
|
-
reasoning
|
|
243
|
+
title: decision, // Plaintext title for search/display
|
|
244
|
+
encrypted_content: encryptedContent, // Encrypted reasoning
|
|
72
245
|
});
|
|
73
246
|
}
|
|
74
247
|
export { RecallApiError };
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recall CLI Module
|
|
3
|
+
*
|
|
4
|
+
* CLI commands for use from shell hooks (e.g., SessionEnd).
|
|
5
|
+
* This allows Claude Code hooks to trigger Recall saves automatically.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Save a transcript with AI summarization.
|
|
9
|
+
* This is the main entry point for SessionEnd hooks.
|
|
10
|
+
*/
|
|
11
|
+
export declare function saveTranscript(options: {
|
|
12
|
+
transcriptPath: string;
|
|
13
|
+
cwd: string;
|
|
14
|
+
quiet?: boolean;
|
|
15
|
+
}): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* CLI entry point - parses arguments and dispatches to commands.
|
|
18
|
+
*/
|
|
19
|
+
export declare function runCli(args: string[]): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgNH;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoHhB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAmF1D"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recall CLI Module
|
|
3
|
+
*
|
|
4
|
+
* CLI commands for use from shell hooks (e.g., SessionEnd).
|
|
5
|
+
* This allows Claude Code hooks to trigger Recall saves automatically.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import { execSync } from 'child_process';
|
|
9
|
+
import { encrypt } from './crypto.js';
|
|
10
|
+
const API_URL = process.env.RECALL_API_URL || 'https://api-v3.recall.team';
|
|
11
|
+
function getToken() {
|
|
12
|
+
const token = process.env.RECALL_API_TOKEN;
|
|
13
|
+
if (!token) {
|
|
14
|
+
throw new Error('RECALL_API_TOKEN environment variable not set');
|
|
15
|
+
}
|
|
16
|
+
return token;
|
|
17
|
+
}
|
|
18
|
+
async function request(method, path, body) {
|
|
19
|
+
const token = getToken();
|
|
20
|
+
const url = `${API_URL}${path}`;
|
|
21
|
+
const response = await fetch(url, {
|
|
22
|
+
method,
|
|
23
|
+
headers: {
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
Authorization: `Bearer ${token}`,
|
|
26
|
+
},
|
|
27
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
28
|
+
});
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
const errorBody = await response.json().catch(() => ({}));
|
|
31
|
+
throw new Error(`API Error ${response.status}: ${errorBody.error || 'Unknown error'}`);
|
|
32
|
+
}
|
|
33
|
+
return response.json();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse Claude Code's JSONL transcript file into a single transcript string.
|
|
37
|
+
*/
|
|
38
|
+
function parseTranscript(transcriptPath) {
|
|
39
|
+
if (!fs.existsSync(transcriptPath)) {
|
|
40
|
+
throw new Error(`Transcript file not found: ${transcriptPath}`);
|
|
41
|
+
}
|
|
42
|
+
const content = fs.readFileSync(transcriptPath, 'utf-8');
|
|
43
|
+
const lines = content.split('\n').filter((line) => line.trim());
|
|
44
|
+
const messages = [];
|
|
45
|
+
for (const line of lines) {
|
|
46
|
+
try {
|
|
47
|
+
const entry = JSON.parse(line);
|
|
48
|
+
// Claude Code JSONL format varies - try to extract messages
|
|
49
|
+
if (entry.type === 'user' || entry.role === 'user') {
|
|
50
|
+
messages.push({
|
|
51
|
+
role: 'user',
|
|
52
|
+
content: entry.content || entry.message || entry.text || '',
|
|
53
|
+
timestamp: entry.timestamp,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
else if (entry.type === 'assistant' ||
|
|
57
|
+
entry.role === 'assistant' ||
|
|
58
|
+
entry.type === 'response') {
|
|
59
|
+
messages.push({
|
|
60
|
+
role: 'assistant',
|
|
61
|
+
content: entry.content || entry.message || entry.text || '',
|
|
62
|
+
timestamp: entry.timestamp,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Skip invalid JSON lines
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Build transcript string
|
|
71
|
+
const transcriptLines = [];
|
|
72
|
+
for (const msg of messages) {
|
|
73
|
+
const role = msg.role === 'user' ? 'User' : 'Assistant';
|
|
74
|
+
const content = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
75
|
+
transcriptLines.push(`${role}: ${content.substring(0, 5000)}`);
|
|
76
|
+
}
|
|
77
|
+
return transcriptLines.join('\n\n');
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get git repo info from a directory.
|
|
81
|
+
*/
|
|
82
|
+
function getRepoInfo(projectPath) {
|
|
83
|
+
try {
|
|
84
|
+
const remoteUrl = execSync('git config --get remote.origin.url', {
|
|
85
|
+
cwd: projectPath,
|
|
86
|
+
encoding: 'utf-8',
|
|
87
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
88
|
+
}).trim();
|
|
89
|
+
let fullName;
|
|
90
|
+
if (remoteUrl.includes('github.com')) {
|
|
91
|
+
const match = remoteUrl.match(/github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
92
|
+
if (match) {
|
|
93
|
+
fullName = match[1];
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
let defaultBranch = 'main';
|
|
103
|
+
try {
|
|
104
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
105
|
+
cwd: projectPath,
|
|
106
|
+
encoding: 'utf-8',
|
|
107
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
108
|
+
}).trim();
|
|
109
|
+
if (branch) {
|
|
110
|
+
defaultBranch = branch;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Use default
|
|
115
|
+
}
|
|
116
|
+
return { fullName, defaultBranch };
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Save a transcript with AI summarization.
|
|
124
|
+
* This is the main entry point for SessionEnd hooks.
|
|
125
|
+
*/
|
|
126
|
+
export async function saveTranscript(options) {
|
|
127
|
+
const { transcriptPath, cwd, quiet } = options;
|
|
128
|
+
const log = quiet ? () => { } : console.error;
|
|
129
|
+
try {
|
|
130
|
+
// 1. Parse the transcript
|
|
131
|
+
log('[Recall] Parsing transcript...');
|
|
132
|
+
const transcript = parseTranscript(transcriptPath);
|
|
133
|
+
if (transcript.length < 100) {
|
|
134
|
+
log('[Recall] Transcript too short, skipping save');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// 2. Get repo info
|
|
138
|
+
log('[Recall] Resolving repository...');
|
|
139
|
+
const repoInfo = getRepoInfo(cwd);
|
|
140
|
+
if (!repoInfo) {
|
|
141
|
+
log('[Recall] Not a GitHub repository, skipping save');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// 3. Resolve repo to get repoId
|
|
145
|
+
const { repoId } = await request('POST', '/v1/repos/resolve', {
|
|
146
|
+
fullName: repoInfo.fullName,
|
|
147
|
+
defaultBranch: repoInfo.defaultBranch,
|
|
148
|
+
});
|
|
149
|
+
// 4. Get team key for encryption
|
|
150
|
+
log('[Recall] Fetching team key...');
|
|
151
|
+
const teamKeyResponse = await request('GET', '/v1/keys/team');
|
|
152
|
+
if (!teamKeyResponse.hasAccess) {
|
|
153
|
+
throw new Error('No access to team encryption key');
|
|
154
|
+
}
|
|
155
|
+
// 5. Send transcript to summarize endpoint
|
|
156
|
+
log('[Recall] Generating AI summary...');
|
|
157
|
+
const summarizeResponse = await request('POST', '/v1/summarize', {
|
|
158
|
+
transcript,
|
|
159
|
+
repo_name: repoInfo.fullName,
|
|
160
|
+
tool: 'claude-code',
|
|
161
|
+
started_at: new Date().toISOString(),
|
|
162
|
+
ended_at: new Date().toISOString(),
|
|
163
|
+
});
|
|
164
|
+
// 6. Build content to encrypt
|
|
165
|
+
const contentToEncrypt = JSON.stringify({
|
|
166
|
+
summary: summarizeResponse.summary,
|
|
167
|
+
decisions: summarizeResponse.decisions.map((d) => ({
|
|
168
|
+
what: d.what,
|
|
169
|
+
why: d.title,
|
|
170
|
+
})),
|
|
171
|
+
mistakes: summarizeResponse.tldr.mistakes,
|
|
172
|
+
files_changed: summarizeResponse.tldr.files_changed,
|
|
173
|
+
lessons: summarizeResponse.lessons,
|
|
174
|
+
});
|
|
175
|
+
// 7. Encrypt the content
|
|
176
|
+
log('[Recall] Encrypting session...');
|
|
177
|
+
const encryptedContent = encrypt(contentToEncrypt, teamKeyResponse.encryptionKey);
|
|
178
|
+
// 8. Build TLDR for plaintext metadata
|
|
179
|
+
const tldr = {
|
|
180
|
+
summary: summarizeResponse.tldr.summary.substring(0, 1000),
|
|
181
|
+
status: summarizeResponse.tldr.status,
|
|
182
|
+
decisions: summarizeResponse.tldr.decisions,
|
|
183
|
+
mistakes: summarizeResponse.tldr.mistakes,
|
|
184
|
+
tags: summarizeResponse.tldr.tags,
|
|
185
|
+
files_changed: summarizeResponse.tldr.files_changed,
|
|
186
|
+
blockers: null,
|
|
187
|
+
next_steps: null,
|
|
188
|
+
};
|
|
189
|
+
const now = new Date().toISOString();
|
|
190
|
+
// 9. Save to database
|
|
191
|
+
log('[Recall] Saving session...');
|
|
192
|
+
const saveResponse = await request('POST', `/v1/repos/${repoId}/sessions`, {
|
|
193
|
+
encrypted_content: encryptedContent,
|
|
194
|
+
tldr,
|
|
195
|
+
started_at: now,
|
|
196
|
+
ended_at: now,
|
|
197
|
+
tool: 'claude-code',
|
|
198
|
+
quality_metadata: summarizeResponse.quality_metadata,
|
|
199
|
+
});
|
|
200
|
+
log(`[Recall] Session saved: ${saveResponse.id}`);
|
|
201
|
+
// Output success for hook
|
|
202
|
+
console.log(JSON.stringify({
|
|
203
|
+
success: true,
|
|
204
|
+
session_id: saveResponse.id,
|
|
205
|
+
}));
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
209
|
+
log(`[Recall] Error: ${message}`);
|
|
210
|
+
// Output failure for hook
|
|
211
|
+
console.log(JSON.stringify({
|
|
212
|
+
success: false,
|
|
213
|
+
error: message,
|
|
214
|
+
}));
|
|
215
|
+
// Exit with error code but don't throw (hooks shouldn't block)
|
|
216
|
+
process.exitCode = 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* CLI entry point - parses arguments and dispatches to commands.
|
|
221
|
+
*/
|
|
222
|
+
export async function runCli(args) {
|
|
223
|
+
const command = args[0];
|
|
224
|
+
switch (command) {
|
|
225
|
+
case 'save-transcript': {
|
|
226
|
+
// Read hook input from stdin
|
|
227
|
+
let input = null;
|
|
228
|
+
// Check if we have stdin data (non-TTY means piped input)
|
|
229
|
+
if (!process.stdin.isTTY) {
|
|
230
|
+
try {
|
|
231
|
+
const stdinData = fs.readFileSync(0, 'utf-8');
|
|
232
|
+
if (stdinData.trim()) {
|
|
233
|
+
input = JSON.parse(stdinData);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// No stdin or invalid JSON
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Parse command-line options as fallback
|
|
241
|
+
const transcriptPath = input?.transcript_path ||
|
|
242
|
+
args.find((a) => a.startsWith('--file='))?.split('=')[1] ||
|
|
243
|
+
args[args.indexOf('--file') + 1];
|
|
244
|
+
const cwd = input?.cwd ||
|
|
245
|
+
args.find((a) => a.startsWith('--cwd='))?.split('=')[1] ||
|
|
246
|
+
args[args.indexOf('--cwd') + 1] ||
|
|
247
|
+
process.cwd();
|
|
248
|
+
const quiet = args.includes('--quiet') || args.includes('-q');
|
|
249
|
+
if (!transcriptPath) {
|
|
250
|
+
console.error('Usage: recall-mcp-v3 save-transcript --file <path> [--cwd <dir>] [--quiet]');
|
|
251
|
+
console.error('Or pipe SessionEnd hook JSON to stdin');
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
await saveTranscript({ transcriptPath, cwd, quiet });
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case 'help':
|
|
258
|
+
case '--help':
|
|
259
|
+
case '-h': {
|
|
260
|
+
console.log(`
|
|
261
|
+
Recall MCP v3 CLI
|
|
262
|
+
|
|
263
|
+
Usage:
|
|
264
|
+
recall-mcp-v3 Start MCP server (for Claude Code)
|
|
265
|
+
recall-mcp-v3 save-transcript Save session from transcript file
|
|
266
|
+
recall-mcp-v3 help Show this help
|
|
267
|
+
|
|
268
|
+
Commands:
|
|
269
|
+
save-transcript
|
|
270
|
+
Save a Claude Code session transcript with AI summarization.
|
|
271
|
+
|
|
272
|
+
Options:
|
|
273
|
+
--file <path> Path to transcript JSONL file (required)
|
|
274
|
+
--cwd <dir> Working directory for git repo detection (default: cwd)
|
|
275
|
+
--quiet, -q Suppress progress output
|
|
276
|
+
|
|
277
|
+
Can also read SessionEnd hook JSON from stdin:
|
|
278
|
+
echo '{"transcript_path":"/path/to/file.jsonl","cwd":"/project"}' | recall-mcp-v3 save-transcript
|
|
279
|
+
|
|
280
|
+
Environment:
|
|
281
|
+
RECALL_API_TOKEN API token (required) - get from https://v3.recall.team/app/settings
|
|
282
|
+
RECALL_API_URL API URL (default: https://api-v3.recall.team)
|
|
283
|
+
`);
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
default: {
|
|
287
|
+
// No command or unrecognized - this means start MCP server
|
|
288
|
+
// Return false to indicate CLI didn't handle it
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// CLI handled the command - exit to prevent MCP server from starting
|
|
293
|
+
process.exit(process.exitCode || 0);
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recall Encryption Module
|
|
3
|
+
*
|
|
4
|
+
* Client-side AES-256-GCM encryption/decryption for zero-knowledge architecture.
|
|
5
|
+
* Team key is fetched from API and used to encrypt content before sending,
|
|
6
|
+
* and decrypt content after receiving.
|
|
7
|
+
*
|
|
8
|
+
* Format: RECALL_ENCRYPTED:v1:[base64_iv]:[base64_ciphertext]:[base64_tag]
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Encrypt content using AES-256-GCM.
|
|
12
|
+
*
|
|
13
|
+
* @param plaintext - The content to encrypt
|
|
14
|
+
* @param teamKeyBase64 - The team encryption key (base64)
|
|
15
|
+
* @returns Encrypted string in format: RECALL_ENCRYPTED:v1:[iv]:[ciphertext]:[tag]
|
|
16
|
+
*/
|
|
17
|
+
export declare function encrypt(plaintext: string, teamKeyBase64: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Decrypt content that was encrypted with AES-256-GCM.
|
|
20
|
+
*
|
|
21
|
+
* @param encryptedString - The encrypted content (RECALL_ENCRYPTED:v1:...)
|
|
22
|
+
* @param teamKeyBase64 - The team encryption key (base64)
|
|
23
|
+
* @returns Decrypted plaintext
|
|
24
|
+
* @throws Error if decryption fails or format is invalid
|
|
25
|
+
*/
|
|
26
|
+
export declare function decrypt(encryptedString: string, teamKeyBase64: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a string is encrypted content.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isEncrypted(content: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Safely decrypt content - returns original if not encrypted or if decryption fails.
|
|
33
|
+
* This allows gradual migration and handling of mixed content.
|
|
34
|
+
*/
|
|
35
|
+
export declare function safeDecrypt(content: string, teamKeyBase64: string): string;
|
|
36
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAYxE;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,eAAe,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAwC9E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAW1E"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recall Encryption Module
|
|
3
|
+
*
|
|
4
|
+
* Client-side AES-256-GCM encryption/decryption for zero-knowledge architecture.
|
|
5
|
+
* Team key is fetched from API and used to encrypt content before sending,
|
|
6
|
+
* and decrypt content after receiving.
|
|
7
|
+
*
|
|
8
|
+
* Format: RECALL_ENCRYPTED:v1:[base64_iv]:[base64_ciphertext]:[base64_tag]
|
|
9
|
+
*/
|
|
10
|
+
import * as crypto from 'crypto';
|
|
11
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
12
|
+
const IV_LENGTH = 16; // 128 bits
|
|
13
|
+
const TAG_LENGTH = 16; // 128 bits
|
|
14
|
+
const ENCRYPTED_PREFIX = 'RECALL_ENCRYPTED:v1:';
|
|
15
|
+
/**
|
|
16
|
+
* Derive a 256-bit key from the base64 team key.
|
|
17
|
+
* The team key from API is already a raw 256-bit key in base64.
|
|
18
|
+
*/
|
|
19
|
+
function deriveKey(teamKeyBase64) {
|
|
20
|
+
// Decode the base64 key - it's already 256 bits (32 bytes)
|
|
21
|
+
const keyBuffer = Buffer.from(teamKeyBase64, 'base64');
|
|
22
|
+
// If the key is not 32 bytes, hash it to get 32 bytes
|
|
23
|
+
if (keyBuffer.length !== 32) {
|
|
24
|
+
return crypto.createHash('sha256').update(teamKeyBase64).digest();
|
|
25
|
+
}
|
|
26
|
+
return keyBuffer;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Encrypt content using AES-256-GCM.
|
|
30
|
+
*
|
|
31
|
+
* @param plaintext - The content to encrypt
|
|
32
|
+
* @param teamKeyBase64 - The team encryption key (base64)
|
|
33
|
+
* @returns Encrypted string in format: RECALL_ENCRYPTED:v1:[iv]:[ciphertext]:[tag]
|
|
34
|
+
*/
|
|
35
|
+
export function encrypt(plaintext, teamKeyBase64) {
|
|
36
|
+
const key = deriveKey(teamKeyBase64);
|
|
37
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
38
|
+
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
|
|
39
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'base64');
|
|
40
|
+
encrypted += cipher.final('base64');
|
|
41
|
+
const authTag = cipher.getAuthTag();
|
|
42
|
+
return `${ENCRYPTED_PREFIX}${iv.toString('base64')}:${encrypted}:${authTag.toString('base64')}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Decrypt content that was encrypted with AES-256-GCM.
|
|
46
|
+
*
|
|
47
|
+
* @param encryptedString - The encrypted content (RECALL_ENCRYPTED:v1:...)
|
|
48
|
+
* @param teamKeyBase64 - The team encryption key (base64)
|
|
49
|
+
* @returns Decrypted plaintext
|
|
50
|
+
* @throws Error if decryption fails or format is invalid
|
|
51
|
+
*/
|
|
52
|
+
export function decrypt(encryptedString, teamKeyBase64) {
|
|
53
|
+
// Check format
|
|
54
|
+
if (!encryptedString.startsWith(ENCRYPTED_PREFIX)) {
|
|
55
|
+
throw new Error('Invalid encrypted content format: missing RECALL_ENCRYPTED prefix');
|
|
56
|
+
}
|
|
57
|
+
// Parse components
|
|
58
|
+
const withoutPrefix = encryptedString.substring(ENCRYPTED_PREFIX.length);
|
|
59
|
+
const parts = withoutPrefix.split(':');
|
|
60
|
+
if (parts.length !== 3) {
|
|
61
|
+
throw new Error(`Invalid encrypted content format: expected 3 parts (iv:ciphertext:tag), got ${parts.length}`);
|
|
62
|
+
}
|
|
63
|
+
const [ivBase64, ciphertextBase64, tagBase64] = parts;
|
|
64
|
+
const key = deriveKey(teamKeyBase64);
|
|
65
|
+
const iv = Buffer.from(ivBase64, 'base64');
|
|
66
|
+
const ciphertext = Buffer.from(ciphertextBase64, 'base64');
|
|
67
|
+
const authTag = Buffer.from(tagBase64, 'base64');
|
|
68
|
+
// Validate IV length
|
|
69
|
+
if (iv.length !== IV_LENGTH) {
|
|
70
|
+
throw new Error(`Invalid IV length: expected ${IV_LENGTH}, got ${iv.length}`);
|
|
71
|
+
}
|
|
72
|
+
// Validate auth tag length
|
|
73
|
+
if (authTag.length !== TAG_LENGTH) {
|
|
74
|
+
throw new Error(`Invalid auth tag length: expected ${TAG_LENGTH}, got ${authTag.length}`);
|
|
75
|
+
}
|
|
76
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
|
|
77
|
+
decipher.setAuthTag(authTag);
|
|
78
|
+
let decrypted = decipher.update(ciphertext, undefined, 'utf8');
|
|
79
|
+
decrypted += decipher.final('utf8');
|
|
80
|
+
return decrypted;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if a string is encrypted content.
|
|
84
|
+
*/
|
|
85
|
+
export function isEncrypted(content) {
|
|
86
|
+
return content.startsWith(ENCRYPTED_PREFIX);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Safely decrypt content - returns original if not encrypted or if decryption fails.
|
|
90
|
+
* This allows gradual migration and handling of mixed content.
|
|
91
|
+
*/
|
|
92
|
+
export function safeDecrypt(content, teamKeyBase64) {
|
|
93
|
+
if (!isEncrypted(content)) {
|
|
94
|
+
return content;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
return decrypt(content, teamKeyBase64);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('Failed to decrypt content:', error);
|
|
101
|
+
return content; // Return as-is if decryption fails
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A clean, simple MCP server for team memory in AI coding assistants.
|
|
6
6
|
* Reads RECALL_API_TOKEN from environment variable (set by Claude Code).
|
|
7
|
+
*
|
|
8
|
+
* Also supports CLI mode for shell hooks:
|
|
9
|
+
* recall-mcp-v3 save-transcript --file /path/to/transcript.jsonl
|
|
7
10
|
*/
|
|
8
11
|
export {};
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG"}
|
package/dist/index.js
CHANGED
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A clean, simple MCP server for team memory in AI coding assistants.
|
|
6
6
|
* Reads RECALL_API_TOKEN from environment variable (set by Claude Code).
|
|
7
|
+
*
|
|
8
|
+
* Also supports CLI mode for shell hooks:
|
|
9
|
+
* recall-mcp-v3 save-transcript --file /path/to/transcript.jsonl
|
|
7
10
|
*/
|
|
8
11
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
12
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
13
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
11
14
|
import { getContext, getHistory, getTranscripts, saveSession, logDecision, } from './tools.js';
|
|
15
|
+
import { runCli } from './cli.js';
|
|
12
16
|
// Tool definitions
|
|
13
17
|
const TOOLS = [
|
|
14
18
|
{
|
|
@@ -189,7 +193,18 @@ class RecallServer {
|
|
|
189
193
|
console.error('Recall MCP v3 server running');
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
|
-
//
|
|
193
|
-
const
|
|
194
|
-
|
|
196
|
+
// Check for CLI arguments
|
|
197
|
+
const args = process.argv.slice(2);
|
|
198
|
+
// If CLI arguments provided, run in CLI mode
|
|
199
|
+
if (args.length > 0) {
|
|
200
|
+
runCli(args).catch((error) => {
|
|
201
|
+
console.error('CLI Error:', error.message);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
// No args - start MCP server (default mode for Claude Code)
|
|
207
|
+
const server = new RecallServer();
|
|
208
|
+
server.run().catch(console.error);
|
|
209
|
+
}
|
|
195
210
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|