@recall_v3/mcp-server 0.1.0 → 3.0.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/README.md +66 -0
- package/dist/api/client.d.ts +102 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +65 -16
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +297 -0
- package/dist/config/index.d.ts +10 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +71 -4
- package/dist/crypto/index.d.ts +10 -0
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.js +29 -0
- package/dist/index.js +12 -12
- package/dist/tools/getContext.d.ts +2 -2
- package/dist/tools/getContext.d.ts.map +1 -1
- package/dist/tools/getContext.js +57 -20
- package/dist/tools/getHistory.d.ts +1 -1
- package/dist/tools/getHistory.d.ts.map +1 -1
- package/dist/tools/getHistory.js +93 -30
- package/dist/tools/getTranscripts.js +1 -1
- package/dist/tools/saveSession.d.ts +8 -3
- package/dist/tools/saveSession.d.ts.map +1 -1
- package/dist/tools/saveSession.js +186 -45
- package/package.json +1 -1
- package/src/api/client.ts +154 -17
- package/src/cli.ts +334 -0
- package/src/config/index.ts +84 -4
- package/src/crypto/index.ts +33 -0
- package/src/index.ts +12 -12
- package/src/tools/getContext.ts +102 -20
- package/src/tools/getHistory.ts +157 -31
- package/src/tools/getTranscripts.ts +1 -1
- package/src/tools/saveSession.ts +282 -50
package/dist/config/index.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Recall Configuration Management
|
|
2
|
+
* Recall v3 Configuration Management
|
|
3
3
|
*
|
|
4
|
-
* Manages the local config file at ~/.recall/config.json.
|
|
4
|
+
* Manages the local config file at ~/.config/recall/config.json.
|
|
5
|
+
* This is intentionally SEPARATE from v2's ~/.recall/ directory.
|
|
5
6
|
* Handles secure storage of API tokens and team keys.
|
|
6
7
|
*/
|
|
7
8
|
import type { RecallConfig } from '@recall_v3/shared';
|
|
8
9
|
/**
|
|
9
|
-
* Get the path to the Recall config directory
|
|
10
|
+
* Get the path to the Recall v3 config directory
|
|
11
|
+
* Uses ~/.config/recall/ (XDG-compliant, separate from v2)
|
|
10
12
|
*/
|
|
11
13
|
export declare function getConfigDir(): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get the path to the legacy v2 config directory
|
|
16
|
+
* (used only for migration checking)
|
|
17
|
+
*/
|
|
18
|
+
export declare function getLegacyConfigDir(): string;
|
|
12
19
|
/**
|
|
13
20
|
* Get the path to the config file
|
|
14
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AActD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAqGD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,YAAY,CA2BzC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAe9D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAQtC;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,GAAG,IAAI,CAS3C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAG/C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAI5D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAEpG;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAErD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,IAAI,CAQhC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,CAOlD"}
|
package/dist/config/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Recall Configuration Management
|
|
3
|
+
* Recall v3 Configuration Management
|
|
4
4
|
*
|
|
5
|
-
* Manages the local config file at ~/.recall/config.json.
|
|
5
|
+
* Manages the local config file at ~/.config/recall/config.json.
|
|
6
|
+
* This is intentionally SEPARATE from v2's ~/.recall/ directory.
|
|
6
7
|
* Handles secure storage of API tokens and team keys.
|
|
7
8
|
*/
|
|
8
9
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
@@ -40,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
40
41
|
})();
|
|
41
42
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
43
|
exports.getConfigDir = getConfigDir;
|
|
44
|
+
exports.getLegacyConfigDir = getLegacyConfigDir;
|
|
43
45
|
exports.getConfigPath = getConfigPath;
|
|
44
46
|
exports.loadConfig = loadConfig;
|
|
45
47
|
exports.saveConfig = saveConfig;
|
|
@@ -63,11 +65,23 @@ const os = __importStar(require("node:os"));
|
|
|
63
65
|
const CONFIG_VERSION = 1;
|
|
64
66
|
// Default API base URL (v3)
|
|
65
67
|
const DEFAULT_API_BASE_URL = 'https://api-v3.recall.team';
|
|
68
|
+
// v3 uses ~/.config/recall/ (XDG-compliant, separate from v2's ~/.recall/)
|
|
69
|
+
const V3_CONFIG_DIR = path.join(os.homedir(), '.config', 'recall');
|
|
70
|
+
// v2 used ~/.recall/ - we check this for migration
|
|
71
|
+
const V2_CONFIG_DIR = path.join(os.homedir(), '.recall');
|
|
66
72
|
/**
|
|
67
|
-
* Get the path to the Recall config directory
|
|
73
|
+
* Get the path to the Recall v3 config directory
|
|
74
|
+
* Uses ~/.config/recall/ (XDG-compliant, separate from v2)
|
|
68
75
|
*/
|
|
69
76
|
function getConfigDir() {
|
|
70
|
-
return
|
|
77
|
+
return V3_CONFIG_DIR;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get the path to the legacy v2 config directory
|
|
81
|
+
* (used only for migration checking)
|
|
82
|
+
*/
|
|
83
|
+
function getLegacyConfigDir() {
|
|
84
|
+
return V2_CONFIG_DIR;
|
|
71
85
|
}
|
|
72
86
|
/**
|
|
73
87
|
* Get the path to the config file
|
|
@@ -108,11 +122,64 @@ function migrateConfig(config) {
|
|
|
108
122
|
migrated.version = CONFIG_VERSION;
|
|
109
123
|
return migrated;
|
|
110
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if a config file at a given path is a v3 config
|
|
127
|
+
* v3 configs have teamKeys and a version field (v2 didn't)
|
|
128
|
+
*/
|
|
129
|
+
function isV3Config(config) {
|
|
130
|
+
// v3 configs always have version field
|
|
131
|
+
return typeof config.version === 'number' && config.version >= 1;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Migrate v3 config from old v2 location (~/.recall/) to new v3 location (~/.config/recall/)
|
|
135
|
+
* This only migrates if:
|
|
136
|
+
* 1. No config exists at new v3 location
|
|
137
|
+
* 2. A v3 config exists at old v2 location (has version field)
|
|
138
|
+
*
|
|
139
|
+
* v2 configs (without version field) are left alone - they belong to v2
|
|
140
|
+
*/
|
|
141
|
+
function migrateFromV2Location() {
|
|
142
|
+
const v3ConfigPath = getConfigPath();
|
|
143
|
+
const v2ConfigPath = path.join(getLegacyConfigDir(), 'config.json');
|
|
144
|
+
// If v3 config already exists at new location, nothing to migrate
|
|
145
|
+
if (fs.existsSync(v3ConfigPath)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
// If no config exists at old v2 location, nothing to migrate
|
|
149
|
+
if (!fs.existsSync(v2ConfigPath)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const raw = fs.readFileSync(v2ConfigPath, 'utf-8');
|
|
154
|
+
const parsed = JSON.parse(raw);
|
|
155
|
+
// Only migrate if it's a v3 config (has version field)
|
|
156
|
+
// v2 configs don't have version field and belong to v2
|
|
157
|
+
if (!isV3Config(parsed)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// This is a v3 config in the old location - migrate it
|
|
161
|
+
console.log(`[Recall v3] Migrating config from ~/.recall/ to ~/.config/recall/`);
|
|
162
|
+
// Ensure new directory exists
|
|
163
|
+
ensureConfigDir();
|
|
164
|
+
// Copy config to new location
|
|
165
|
+
fs.writeFileSync(v3ConfigPath, JSON.stringify(parsed, null, 2), { mode: 0o600 });
|
|
166
|
+
// Remove config from old location (but leave other v2 artifacts)
|
|
167
|
+
// Note: We only remove config.json, not the whole directory
|
|
168
|
+
fs.unlinkSync(v2ConfigPath);
|
|
169
|
+
console.log(`[Recall v3] Migration complete. v3 config is now at ~/.config/recall/config.json`);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// Migration failed - not critical, user can manually migrate
|
|
173
|
+
console.warn(`[Recall v3] Could not migrate config from ~/.recall/ (non-critical)`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
111
176
|
/**
|
|
112
177
|
* Load configuration from disk
|
|
113
178
|
* Returns a default config if the file doesn't exist
|
|
114
179
|
*/
|
|
115
180
|
function loadConfig() {
|
|
181
|
+
// First, try to migrate from old v2 location if needed
|
|
182
|
+
migrateFromV2Location();
|
|
116
183
|
const configPath = getConfigPath();
|
|
117
184
|
if (!fs.existsSync(configPath)) {
|
|
118
185
|
return createDefaultConfig();
|
package/dist/crypto/index.d.ts
CHANGED
|
@@ -53,4 +53,14 @@ export declare function decryptContent(encrypted: string, keyBase64: string): st
|
|
|
53
53
|
* Encrypt content and return as JSON string
|
|
54
54
|
*/
|
|
55
55
|
export declare function encryptContent(plaintext: string, keyBase64: string): string;
|
|
56
|
+
/**
|
|
57
|
+
* Encrypt content and return in Recall format: RECALL_ENCRYPTED:v1:iv:tag:ciphertext
|
|
58
|
+
* This is the format expected by the v3 API.
|
|
59
|
+
*/
|
|
60
|
+
export declare function encryptForApi(plaintext: string, keyBase64: string): string;
|
|
61
|
+
/**
|
|
62
|
+
* Decrypt content in Recall format: RECALL_ENCRYPTED:v1:iv:tag:ciphertext
|
|
63
|
+
* This is the format returned by the v3 API.
|
|
64
|
+
*/
|
|
65
|
+
export declare function decryptFromApi(encrypted: string, keyBase64: string): string;
|
|
56
66
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAO1D;;GAEG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAEvC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAGpC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB,CA+B9E;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CA0C5E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAWxE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAEpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA8BtD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG3E"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAO1D;;GAEG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAEvC;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAGpC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,gBAAgB,CA+B9E;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CA0C5E;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAWxE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAEpE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CA8BtD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAY3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG3E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG1E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAkB3E"}
|
package/dist/crypto/index.js
CHANGED
|
@@ -48,6 +48,8 @@ exports.serializeEncrypted = serializeEncrypted;
|
|
|
48
48
|
exports.isEncryptedString = isEncryptedString;
|
|
49
49
|
exports.decryptContent = decryptContent;
|
|
50
50
|
exports.encryptContent = encryptContent;
|
|
51
|
+
exports.encryptForApi = encryptForApi;
|
|
52
|
+
exports.decryptFromApi = decryptFromApi;
|
|
51
53
|
const crypto = __importStar(require("node:crypto"));
|
|
52
54
|
// AES-256-GCM constants
|
|
53
55
|
const ALGORITHM = 'aes-256-gcm';
|
|
@@ -222,3 +224,30 @@ function encryptContent(plaintext, keyBase64) {
|
|
|
222
224
|
const payload = encrypt(plaintext, keyBase64);
|
|
223
225
|
return JSON.stringify(payload);
|
|
224
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Encrypt content and return in Recall format: RECALL_ENCRYPTED:v1:iv:tag:ciphertext
|
|
229
|
+
* This is the format expected by the v3 API.
|
|
230
|
+
*/
|
|
231
|
+
function encryptForApi(plaintext, keyBase64) {
|
|
232
|
+
const payload = encrypt(plaintext, keyBase64);
|
|
233
|
+
return `RECALL_ENCRYPTED:v1:${payload.iv}:${payload.tag}:${payload.ciphertext}`;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Decrypt content in Recall format: RECALL_ENCRYPTED:v1:iv:tag:ciphertext
|
|
237
|
+
* This is the format returned by the v3 API.
|
|
238
|
+
*/
|
|
239
|
+
function decryptFromApi(encrypted, keyBase64) {
|
|
240
|
+
if (!encrypted.startsWith('RECALL_ENCRYPTED:')) {
|
|
241
|
+
throw new Error('Invalid encrypted format: must start with RECALL_ENCRYPTED:');
|
|
242
|
+
}
|
|
243
|
+
const parts = encrypted.split(':');
|
|
244
|
+
if (parts.length !== 5) {
|
|
245
|
+
throw new Error('Invalid encrypted format: expected RECALL_ENCRYPTED:v1:iv:tag:ciphertext');
|
|
246
|
+
}
|
|
247
|
+
const [, version, iv, tag, ciphertext] = parts;
|
|
248
|
+
if (version !== 'v1') {
|
|
249
|
+
throw new Error(`Unsupported encryption version: ${version}`);
|
|
250
|
+
}
|
|
251
|
+
const payload = { iv, tag, ciphertext };
|
|
252
|
+
return decrypt(payload, keyBase64);
|
|
253
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -16,8 +16,8 @@ const index_js_2 = require("./tools/index.js");
|
|
|
16
16
|
// Tool definitions
|
|
17
17
|
const TOOLS = [
|
|
18
18
|
{
|
|
19
|
-
name: '
|
|
20
|
-
description: "Get team brain (context.md) for the current repository. This is the distilled current state - loads automatically at every session start. Use
|
|
19
|
+
name: 'recall3_get_context',
|
|
20
|
+
description: "Get team brain (context.md) for the current repository. This is the distilled current state - loads automatically at every session start. Use recall3_get_history for the full encyclopedia.",
|
|
21
21
|
inputSchema: {
|
|
22
22
|
type: 'object',
|
|
23
23
|
properties: {
|
|
@@ -29,8 +29,8 @@ const TOOLS = [
|
|
|
29
29
|
},
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
|
-
name: '
|
|
33
|
-
description: "Get detailed session history (context.md + recent sessions). This includes more context than
|
|
32
|
+
name: 'recall3_get_history',
|
|
33
|
+
description: "Get detailed session history (context.md + recent sessions). This includes more context than recall3_get_context but uses more tokens.",
|
|
34
34
|
inputSchema: {
|
|
35
35
|
type: 'object',
|
|
36
36
|
properties: {
|
|
@@ -43,7 +43,7 @@ const TOOLS = [
|
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
|
-
name: '
|
|
46
|
+
name: 'recall3_get_transcripts',
|
|
47
47
|
description: "Get full session transcripts (context.md + history.md). WARNING: This can be very large and use many tokens. Only use when you need complete historical details.",
|
|
48
48
|
inputSchema: {
|
|
49
49
|
type: 'object',
|
|
@@ -57,7 +57,7 @@ const TOOLS = [
|
|
|
57
57
|
},
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
|
-
name: '
|
|
60
|
+
name: 'recall3_save_session',
|
|
61
61
|
description: "Save a summary of what was accomplished in this coding session. This updates the team memory files.",
|
|
62
62
|
inputSchema: {
|
|
63
63
|
type: 'object',
|
|
@@ -101,7 +101,7 @@ const TOOLS = [
|
|
|
101
101
|
},
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
|
-
name: '
|
|
104
|
+
name: 'recall3_log_decision',
|
|
105
105
|
description: "Log an important decision made during coding. Quick way to capture why something was done.",
|
|
106
106
|
inputSchema: {
|
|
107
107
|
type: 'object',
|
|
@@ -143,19 +143,19 @@ class RecallMCPServer {
|
|
|
143
143
|
try {
|
|
144
144
|
let result;
|
|
145
145
|
switch (name) {
|
|
146
|
-
case '
|
|
146
|
+
case 'recall3_get_context':
|
|
147
147
|
result = await (0, index_js_2.getContext)(args);
|
|
148
148
|
break;
|
|
149
|
-
case '
|
|
149
|
+
case 'recall3_get_history':
|
|
150
150
|
result = await (0, index_js_2.getHistory)(args);
|
|
151
151
|
break;
|
|
152
|
-
case '
|
|
152
|
+
case 'recall3_get_transcripts':
|
|
153
153
|
result = await (0, index_js_2.getTranscripts)(args);
|
|
154
154
|
break;
|
|
155
|
-
case '
|
|
155
|
+
case 'recall3_save_session':
|
|
156
156
|
result = await (0, index_js_2.saveSession)(args);
|
|
157
157
|
break;
|
|
158
|
-
case '
|
|
158
|
+
case 'recall3_log_decision':
|
|
159
159
|
result = await (0, index_js_2.logDecision)(args);
|
|
160
160
|
break;
|
|
161
161
|
default:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* getContext Tool Implementation
|
|
3
3
|
*
|
|
4
|
-
* Fetches the team brain (context
|
|
4
|
+
* Fetches the team brain (context) for the current repository from Recall v3 API.
|
|
5
5
|
* This is the distilled current state - loaded at every session start.
|
|
6
6
|
*/
|
|
7
7
|
import { type ToolResponse } from './types.js';
|
|
@@ -12,7 +12,7 @@ export interface GetContextArgs {
|
|
|
12
12
|
* Execute the getContext tool
|
|
13
13
|
*
|
|
14
14
|
* @param args - Tool arguments (projectPath is optional)
|
|
15
|
-
* @returns MCP tool response with context
|
|
15
|
+
* @returns MCP tool response with context content
|
|
16
16
|
*/
|
|
17
17
|
export declare function getContext(args: GetContextArgs): Promise<ToolResponse>;
|
|
18
18
|
//# sourceMappingURL=getContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getContext.d.ts","sourceRoot":"","sources":["../../src/tools/getContext.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"getContext.d.ts","sourceRoot":"","sources":["../../src/tools/getContext.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA2FD;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CA2E5E"}
|
package/dist/tools/getContext.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* getContext Tool Implementation
|
|
4
4
|
*
|
|
5
|
-
* Fetches the team brain (context
|
|
5
|
+
* Fetches the team brain (context) for the current repository from Recall v3 API.
|
|
6
6
|
* This is the distilled current state - loaded at every session start.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -12,11 +12,62 @@ const index_js_1 = require("../config/index.js");
|
|
|
12
12
|
const index_js_2 = require("../crypto/index.js");
|
|
13
13
|
const types_js_1 = require("./types.js");
|
|
14
14
|
const utils_js_1 = require("./utils.js");
|
|
15
|
+
/**
|
|
16
|
+
* Build context markdown from sessions
|
|
17
|
+
*/
|
|
18
|
+
function buildContextFromSessions(sessions, teamKey, repoName) {
|
|
19
|
+
const parts = [];
|
|
20
|
+
parts.push(`# Team Memory - ${repoName}`);
|
|
21
|
+
parts.push('');
|
|
22
|
+
parts.push(`Last updated: ${new Date().toISOString().split('T')[0]}`);
|
|
23
|
+
parts.push('');
|
|
24
|
+
if (sessions.length === 0) {
|
|
25
|
+
parts.push('No sessions recorded yet. Use `recall save` to save your first session.');
|
|
26
|
+
return parts.join('\n');
|
|
27
|
+
}
|
|
28
|
+
parts.push('## Recent Sessions');
|
|
29
|
+
parts.push('');
|
|
30
|
+
// Show last 10 sessions for context
|
|
31
|
+
const recentSessions = sessions.slice(0, 10);
|
|
32
|
+
for (const session of recentSessions) {
|
|
33
|
+
const date = session.started_at.split('T')[0];
|
|
34
|
+
const developer = session.user.github_username || session.user.name || 'Unknown';
|
|
35
|
+
parts.push(`### ${date} - ${developer}`);
|
|
36
|
+
parts.push('');
|
|
37
|
+
// Use TLDR summary for quick context
|
|
38
|
+
if (session.tldr_summary) {
|
|
39
|
+
parts.push(session.tldr_summary);
|
|
40
|
+
parts.push('');
|
|
41
|
+
}
|
|
42
|
+
// Try to decrypt and include full content if available
|
|
43
|
+
if (session.encrypted_content && session.encrypted_content.startsWith('RECALL_ENCRYPTED:')) {
|
|
44
|
+
try {
|
|
45
|
+
const decrypted = (0, index_js_2.decryptFromApi)(session.encrypted_content, teamKey);
|
|
46
|
+
parts.push(decrypted);
|
|
47
|
+
parts.push('');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// If decryption fails, just use the TLDR
|
|
51
|
+
if (!session.tldr_summary) {
|
|
52
|
+
parts.push('(Session content encrypted)');
|
|
53
|
+
parts.push('');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
parts.push('---');
|
|
58
|
+
parts.push('');
|
|
59
|
+
}
|
|
60
|
+
if (sessions.length > 10) {
|
|
61
|
+
parts.push(`*${sessions.length - 10} more sessions available. Use recall_get_history for full history.*`);
|
|
62
|
+
parts.push('');
|
|
63
|
+
}
|
|
64
|
+
return parts.join('\n');
|
|
65
|
+
}
|
|
15
66
|
/**
|
|
16
67
|
* Execute the getContext tool
|
|
17
68
|
*
|
|
18
69
|
* @param args - Tool arguments (projectPath is optional)
|
|
19
|
-
* @returns MCP tool response with context
|
|
70
|
+
* @returns MCP tool response with context content
|
|
20
71
|
*/
|
|
21
72
|
async function getContext(args) {
|
|
22
73
|
try {
|
|
@@ -48,25 +99,11 @@ async function getContext(args) {
|
|
|
48
99
|
(0, index_js_1.setTeamKey)(teamId, teamKey);
|
|
49
100
|
}
|
|
50
101
|
// Fetch context from API
|
|
51
|
-
const response = await client.
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
// Check if content is encrypted
|
|
56
|
-
if (response.contextMd.startsWith('{') || response.contextMd.includes(':')) {
|
|
57
|
-
contextMd = (0, index_js_2.decryptContent)(response.contextMd, teamKey);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Already plaintext (shouldn't happen, but handle gracefully)
|
|
61
|
-
contextMd = response.contextMd;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
catch (decryptError) {
|
|
65
|
-
// If decryption fails, it might already be plaintext
|
|
66
|
-
contextMd = response.contextMd;
|
|
67
|
-
}
|
|
102
|
+
const response = await client.getContextV3(repoId);
|
|
103
|
+
// Build context markdown from sessions
|
|
104
|
+
const contextMd = buildContextFromSessions(response.sessions, teamKey, repoInfo.fullName);
|
|
68
105
|
// Format output with metadata
|
|
69
|
-
const header =
|
|
106
|
+
const header = `# Team Memory (Recall)\n\nThe following is your team's shared context for this repository.\nUse this to understand what has been built, why decisions were made,\nand what mistakes to avoid.\n\n---`;
|
|
70
107
|
return (0, types_js_1.formattedResponse)(header, contextMd);
|
|
71
108
|
}
|
|
72
109
|
catch (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* getHistory Tool Implementation
|
|
3
3
|
*
|
|
4
|
-
* Fetches context
|
|
4
|
+
* Fetches context + recent session history for the repository from Recall v3 API.
|
|
5
5
|
* This provides more detail than getContext but uses more tokens.
|
|
6
6
|
*/
|
|
7
7
|
import { type ToolResponse } from './types.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getHistory.d.ts","sourceRoot":"","sources":["../../src/tools/getHistory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"getHistory.d.ts","sourceRoot":"","sources":["../../src/tools/getHistory.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;AAmJD;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CA2E5E"}
|
package/dist/tools/getHistory.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* getHistory Tool Implementation
|
|
4
4
|
*
|
|
5
|
-
* Fetches context
|
|
5
|
+
* Fetches context + recent session history for the repository from Recall v3 API.
|
|
6
6
|
* This provides more detail than getContext but uses more tokens.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -12,6 +12,90 @@ const index_js_1 = require("../config/index.js");
|
|
|
12
12
|
const index_js_2 = require("../crypto/index.js");
|
|
13
13
|
const types_js_1 = require("./types.js");
|
|
14
14
|
const utils_js_1 = require("./utils.js");
|
|
15
|
+
/**
|
|
16
|
+
* Build history markdown from API response
|
|
17
|
+
*/
|
|
18
|
+
function buildHistoryMarkdown(response, teamKey, repoName) {
|
|
19
|
+
const parts = [];
|
|
20
|
+
parts.push(`# Team Memory History - ${repoName}`);
|
|
21
|
+
parts.push('');
|
|
22
|
+
parts.push(`Generated: ${new Date().toISOString()}`);
|
|
23
|
+
parts.push('');
|
|
24
|
+
// Decisions section
|
|
25
|
+
if (response.decisions.length > 0) {
|
|
26
|
+
parts.push('## Key Decisions');
|
|
27
|
+
parts.push('');
|
|
28
|
+
for (const decision of response.decisions) {
|
|
29
|
+
const date = decision.created_at.split('T')[0];
|
|
30
|
+
const author = decision.user.github_username || decision.user.name || 'Unknown';
|
|
31
|
+
parts.push(`### ${date} - ${author}`);
|
|
32
|
+
parts.push('');
|
|
33
|
+
parts.push(`**${decision.title}**`);
|
|
34
|
+
parts.push('');
|
|
35
|
+
// Try to decrypt full content
|
|
36
|
+
if (decision.encrypted_content && decision.encrypted_content.startsWith('RECALL_ENCRYPTED:')) {
|
|
37
|
+
try {
|
|
38
|
+
const decrypted = (0, index_js_2.decryptFromApi)(decision.encrypted_content, teamKey);
|
|
39
|
+
parts.push(decrypted);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Use title only
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
parts.push('');
|
|
46
|
+
}
|
|
47
|
+
parts.push('---');
|
|
48
|
+
parts.push('');
|
|
49
|
+
}
|
|
50
|
+
// Mistakes section
|
|
51
|
+
if (response.mistakes.length > 0) {
|
|
52
|
+
parts.push('## Mistakes & Gotchas');
|
|
53
|
+
parts.push('');
|
|
54
|
+
parts.push('*Things the team learned the hard way - avoid repeating these.*');
|
|
55
|
+
parts.push('');
|
|
56
|
+
for (const mistake of response.mistakes) {
|
|
57
|
+
const date = mistake.created_at.split('T')[0];
|
|
58
|
+
const author = mistake.user.github_username || mistake.user.name || 'Unknown';
|
|
59
|
+
parts.push(`- **${mistake.title}** (${date}, ${author})`);
|
|
60
|
+
}
|
|
61
|
+
parts.push('');
|
|
62
|
+
parts.push('---');
|
|
63
|
+
parts.push('');
|
|
64
|
+
}
|
|
65
|
+
// Sessions section
|
|
66
|
+
parts.push('## Session History');
|
|
67
|
+
parts.push('');
|
|
68
|
+
if (response.sessions.length === 0) {
|
|
69
|
+
parts.push('No sessions recorded yet.');
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
for (const session of response.sessions) {
|
|
73
|
+
const date = session.started_at.split('T')[0];
|
|
74
|
+
const developer = session.user.github_username || session.user.name || 'Unknown';
|
|
75
|
+
parts.push(`### ${date} - ${developer}`);
|
|
76
|
+
parts.push('');
|
|
77
|
+
// TLDR summary
|
|
78
|
+
if (session.tldr_summary) {
|
|
79
|
+
parts.push(`**Summary:** ${session.tldr_summary}`);
|
|
80
|
+
parts.push('');
|
|
81
|
+
}
|
|
82
|
+
// Full content if available
|
|
83
|
+
if (session.encrypted_content && session.encrypted_content.startsWith('RECALL_ENCRYPTED:')) {
|
|
84
|
+
try {
|
|
85
|
+
const decrypted = (0, index_js_2.decryptFromApi)(session.encrypted_content, teamKey);
|
|
86
|
+
parts.push(decrypted);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Use TLDR only
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
parts.push('');
|
|
93
|
+
parts.push('---');
|
|
94
|
+
parts.push('');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return parts.join('\n');
|
|
98
|
+
}
|
|
15
99
|
/**
|
|
16
100
|
* Execute the getHistory tool
|
|
17
101
|
*
|
|
@@ -48,36 +132,15 @@ async function getHistory(args) {
|
|
|
48
132
|
(0, index_js_1.setTeamKey)(teamId, teamKey);
|
|
49
133
|
}
|
|
50
134
|
// Fetch history from API
|
|
51
|
-
const response = await client.
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
let historyMd;
|
|
55
|
-
try {
|
|
56
|
-
// Decrypt context
|
|
57
|
-
if (response.contextMd.startsWith('{') || response.contextMd.includes(':')) {
|
|
58
|
-
contextMd = (0, index_js_2.decryptContent)(response.contextMd, teamKey);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
contextMd = response.contextMd;
|
|
62
|
-
}
|
|
63
|
-
// Decrypt history
|
|
64
|
-
if (response.historyMd.startsWith('{') || response.historyMd.includes(':')) {
|
|
65
|
-
historyMd = (0, index_js_2.decryptContent)(response.historyMd, teamKey);
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
historyMd = response.historyMd;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch (decryptError) {
|
|
72
|
-
// If decryption fails, use as-is
|
|
73
|
-
contextMd = response.contextMd;
|
|
74
|
-
historyMd = response.historyMd;
|
|
75
|
-
}
|
|
76
|
-
// Combine context and history
|
|
77
|
-
const combinedContent = `# Recall Context\n\n${contextMd}\n\n---\n\n# Session History\n\n${historyMd}`;
|
|
135
|
+
const response = await client.getHistoryV3(repoId);
|
|
136
|
+
// Build history markdown
|
|
137
|
+
const historyMd = buildHistoryMarkdown(response, teamKey, repoInfo.fullName);
|
|
78
138
|
// Format output with metadata
|
|
79
|
-
const
|
|
80
|
-
|
|
139
|
+
const sessionCount = response.sessions.length;
|
|
140
|
+
const decisionCount = response.decisions.length;
|
|
141
|
+
const mistakeCount = response.mistakes.length;
|
|
142
|
+
const header = `# Team Memory (Recall)\n\nRepository: ${repoInfo.fullName}\nSessions: ${sessionCount} | Decisions: ${decisionCount} | Mistakes: ${mistakeCount}\n\n---`;
|
|
143
|
+
return (0, types_js_1.formattedResponse)(header, historyMd);
|
|
81
144
|
}
|
|
82
145
|
catch (error) {
|
|
83
146
|
if (error instanceof client_js_1.AuthenticationError) {
|
|
@@ -108,7 +108,7 @@ async function getTranscripts(args) {
|
|
|
108
108
|
transcriptsMd,
|
|
109
109
|
].join('\n');
|
|
110
110
|
// Format output
|
|
111
|
-
const header = `
|
|
111
|
+
const header = `Full session transcripts for: ${repoInfo.fullName}`;
|
|
112
112
|
return (0, types_js_1.formattedResponse)(header, combinedContent);
|
|
113
113
|
}
|
|
114
114
|
catch (error) {
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* saveSession Tool Implementation
|
|
3
3
|
*
|
|
4
4
|
* Saves a summary of what was accomplished in this coding session.
|
|
5
|
-
*
|
|
5
|
+
* Encrypts content with team key and sends to Recall v3 API.
|
|
6
6
|
*/
|
|
7
7
|
import { type ToolResponse } from './types.js';
|
|
8
8
|
export interface SaveSessionArgs {
|
|
9
|
-
summary
|
|
9
|
+
/** Pre-written summary (if transcript not provided) */
|
|
10
|
+
summary?: string;
|
|
11
|
+
/** Raw conversation transcript - will be summarized by AI */
|
|
12
|
+
transcript?: string;
|
|
13
|
+
/** Git repository path (defaults to cwd if not provided) */
|
|
14
|
+
projectPath?: string;
|
|
10
15
|
decisions?: Array<{
|
|
11
16
|
what: string;
|
|
12
17
|
why: string;
|
|
@@ -19,7 +24,7 @@ export interface SaveSessionArgs {
|
|
|
19
24
|
/**
|
|
20
25
|
* Execute the saveSession tool
|
|
21
26
|
*
|
|
22
|
-
* @param args - Tool arguments with session summary and metadata
|
|
27
|
+
* @param args - Tool arguments with session summary/transcript and metadata
|
|
23
28
|
* @returns MCP tool response with save confirmation
|
|
24
29
|
*/
|
|
25
30
|
export declare function saveSession(args: SaveSessionArgs): Promise<ToolResponse>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saveSession.d.ts","sourceRoot":"","sources":["../../src/tools/saveSession.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"saveSession.d.ts","sourceRoot":"","sources":["../../src/tools/saveSession.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/E,MAAM,WAAW,eAAe;IAC9B,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA4JD;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAwM9E"}
|