recall-mcp-v3 3.0.1 → 3.1.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/api.d.ts CHANGED
@@ -1,18 +1,39 @@
1
1
  /**
2
2
  * Recall API Client
3
3
  *
4
- * Simple HTTP client for the Recall v3 API.
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 ContextResponse {
35
- sessions: Session[];
36
- cached_context: string;
37
- session_count: number;
38
- tier: string;
51
+ interface HistoryDecision {
52
+ id: string;
53
+ decision: string;
54
+ reasoning: string;
55
+ created_at: string;
56
+ user: SessionUser;
39
57
  }
40
- interface HistoryResponse {
41
- sessions: Session[];
42
- decisions: Array<{
43
- id: string;
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
- export declare function getContext(repoId: string): Promise<ContextResponse>;
69
- export declare function getHistory(repoId: string, days?: number): Promise<HistoryResponse>;
70
- export declare function getTranscripts(repoId: string): Promise<HistoryResponse>;
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;;;;;GAKG;AASH,cAAM,cAAe,SAAQ,KAAK;IAGvB,IAAI,EAAE,MAAM;IACZ,MAAM,EAAE,MAAM;gBAFrB,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM;CAKxB;AA4CD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;KAChC,CAAC;CACH;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,eAAe;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,KAAK,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAC;KAC3E,CAAC,CAAC;IACH,QAAQ,EAAE,KAAK,CAAC;QACd,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACJ;AAED,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,mBAAmB;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAExG;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEzE;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,OAAO,CAAC,eAAe,CAAC,CAEpF;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAE7E;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;IAChD,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,mBAAmB,CAAC,CAY9B;AAED,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,mBAAmB,CAAC,CAK9B;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
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
- * Simple HTTP client for the Recall v3 API.
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
- 'Authorization': `Bearer ${token}`,
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', { fullName, defaultBranch });
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
- return request('GET', `/v1/repos/${repoId}/context`);
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
- return request('GET', `/v1/repos/${repoId}/history?days=${days}`);
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
- return request('GET', `/v1/repos/${repoId}/transcripts`);
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
- return request('POST', `/v1/repos/${repoId}/sessions`, {
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
- started_at: new Date().toISOString(),
65
- ended_at: new Date().toISOString(),
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":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,4BAA4B,CAAC;AAE3E,yCAAyC;AACzC,IAAI,aAAa,GAAkB,IAAI,CAAC;AACxC,IAAI,YAAY,GAAkB,IAAI,CAAC;AACvC,IAAI,UAAU,GAAkB,IAAI,CAAC;AAOrC,MAAM,cAAe,SAAQ,KAAK;IAGvB;IACA;IAHT,YACE,OAAe,EACR,IAAY,EACZ,MAAc;QAErB,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAQ;QACZ,WAAM,GAAN,MAAM,CAAQ;QAGrB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,SAAS,QAAQ;IACf,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,cAAc,CACtB,+CAA+C,EAC/C,UAAU,EACV,GAAG,CACJ,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,MAAyC,EACzC,IAAY,EACZ,IAAc;IAEd,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,IAAI,EAAE,CAAC;IAEhC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM;QACN,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,KAAK,EAAE;SACjC;QACD,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9C,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAa,CAAC;QACxE,MAAM,IAAI,cAAc,CACtB,SAAS,CAAC,KAAK,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAC5C,SAAS,CAAC,IAAI,IAAI,WAAW,EAC7B,QAAQ,CAAC,MAAM,CAChB,CAAC;IACJ,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;AACvC,CAAC;AAgBD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAkB,KAAK,EAAE,eAAe,CAAC,CAAC;IAExE,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,cAAc,CAAC,kCAAkC,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IACjF,CAAC;IAED,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;IACvC,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC/B,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC;IAE3B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,aAAa,GAAG,IAAI,CAAC;IACrB,YAAY,GAAG,IAAI,CAAC;IACpB,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AAsGD,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,aAAsB;IAEtB,OAAO,OAAO,CAAsB,MAAM,EAAE,mBAAmB,EAAE;QAC/D,QAAQ;QACR,aAAa;KACd,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc;IAM7C,6CAA6C;IAC7C,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IAEnC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAkB,KAAK,EAAE,aAAa,MAAM,UAAU,CAAC,CAAC;IAEtF,0BAA0B;IAC1B,MAAM,QAAQ,GAAc,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACxD,iEAAiE;QACjE,IAAI,OAAO,GAAG,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,iBAAiB,IAAI,WAAW,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAChE,IAAI,CAAC;gBACH,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;YACpD,CAAC;YAAC,MAAM,CAAC;gBACP,wCAAwC;gBACxC,OAAO,GAAG,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;YACnC,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACjC,kDAAkD;YAClD,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC;QAClC,CAAC;QAED,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,OAAO;YACP,MAAM,EAAE,GAAG,CAAC,MAAgD;YAC5D,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,QAAQ;QACR,cAAc,EAAE,QAAQ,CAAC,cAAc;QACvC,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,IAAI,GAAG,EAAE;IAMT,6CAA6C;IAC7C,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IAEnC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAC5B,KAAK,EACL,aAAa,MAAM,iBAAiB,IAAI,EAAE,CAC3C,CAAC;IAEF,mBAAmB;IACnB,MAAM,QAAQ,GAAc,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACxD,IAAI,OAAO,GAAG,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;QACrC,IAAI,GAAG,CAAC,iBAAiB,IAAI,WAAW,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAChE,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;aAAM,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACjC,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC;QAClC,CAAC;QAED,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,OAAO;YACP,MAAM,EAAE,GAAG,CAAC,MAAgD;YAC5D,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,SAAS,GAAsB,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAClE,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,GAAG,CAAC,iBAAiB,IAAI,WAAW,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAChE,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;QAC1D,CAAC;aAAM,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACjC,SAAS,GAAG,GAAG,CAAC,iBAAiB,CAAC;QACpC,CAAC;QAED,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,QAAQ,EAAE,GAAG,CAAC,KAAK;YACnB,SAAS;YACT,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,mBAAmB;IACnB,MAAM,QAAQ,GAAqB,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC/D,IAAI,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC;QACxB,IAAI,GAAG,CAAC,iBAAiB,IAAI,WAAW,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAChE,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC;aAAM,IAAI,GAAG,CAAC,iBAAiB,EAAE,CAAC;YACjC,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC;QAClC,CAAC;QAED,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,OAAO;YACP,UAAU,EAAE,GAAG,CAAC,UAAU;SAC3B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc;IAKjD,iEAAiE;IACjE,OAAO,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,IAQC;IAED,6CAA6C;IAC7C,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IAEnC,sDAAsD;IACtD,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC;QACtC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAE5D,oCAAoC;IACpC,MAAM,IAAI,GAAG;QACX,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,8BAA8B;QACxE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,UAAU;QACjC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE;QACnD,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;QAC7B,IAAI,EAAE,EAAE,EAAE,kCAAkC;QAC5C,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,EAAE;QACvC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;QAC/B,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;KACpC,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,sDAAsD;IACtD,OAAO,OAAO,CAAsB,MAAM,EAAE,aAAa,MAAM,WAAW,EAAE;QAC1E,iBAAiB,EAAE,gBAAgB;QACnC,IAAI;QACJ,UAAU,EAAE,GAAG;QACf,QAAQ,EAAE,GAAG;QACb,IAAI,EAAE,aAAa;KACpB,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,QAAgB,EAChB,SAAiB;IAEjB,6CAA6C;IAC7C,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IAEnC,oDAAoD;IACpD,MAAM,gBAAgB,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAErD,gEAAgE;IAChE,OAAO,OAAO,CAAsB,MAAM,EAAE,aAAa,MAAM,YAAY,EAAE;QAC3E,KAAK,EAAE,QAAQ,EAAE,qCAAqC;QACtD,iBAAiB,EAAE,gBAAgB,EAAE,sBAAsB;KAC5D,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -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":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,MAAM,SAAS,GAAG,aAAa,CAAC;AAChC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,WAAW;AACjC,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,WAAW;AAClC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AAEhD;;;GAGG;AACH,SAAS,SAAS,CAAC,aAAqB;IACtC,2DAA2D;IAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IAEvD,sDAAsD;IACtD,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC5B,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,EAAE,CAAC;IACpE,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,SAAiB,EAAE,aAAqB;IAC9D,MAAM,GAAG,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAEzD,IAAI,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC3D,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAEpC,OAAO,GAAG,gBAAgB,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,SAAS,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;AAClG,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,OAAO,CAAC,eAAuB,EAAE,aAAqB;IACpE,eAAe;IACf,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IAED,mBAAmB;IACnB,MAAM,aAAa,GAAG,eAAe,CAAC,SAAS,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,+EAA+E,KAAK,CAAC,MAAM,EAAE,CAC9F,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,QAAQ,EAAE,gBAAgB,EAAE,SAAS,CAAC,GAAG,KAAK,CAAC;IAEtD,MAAM,GAAG,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEjD,qBAAqB;IACrB,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,+BAA+B,SAAS,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,2BAA2B;IAC3B,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,qCAAqC,UAAU,SAAS,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC7D,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAE7B,IAAI,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAC/D,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEpC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,aAAqB;IAChE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC,CAAC,mCAAmC;IACrD,CAAC;AACH,CAAC"}
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recall-mcp-v3",
3
- "version": "3.0.1",
3
+ "version": "3.1.0",
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",