@getmarrow/mcp 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -271
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +487 -176
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +23 -98
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -23
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +111 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +9 -3
package/dist/cli.js
CHANGED
|
@@ -20,13 +20,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
20
20
|
}) : function(o, v) {
|
|
21
21
|
o["default"] = v;
|
|
22
22
|
});
|
|
23
|
-
var __importStar = (this && this.__importStar) || function (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
};
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
30
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
41
|
const readline = __importStar(require("readline"));
|
|
32
42
|
const index_1 = require("./index");
|
|
@@ -40,7 +50,6 @@ if (!API_KEY) {
|
|
|
40
50
|
// Auto-orient on startup — cache warnings, inject into EVERY marrow_think response
|
|
41
51
|
let cachedOrientWarnings = [];
|
|
42
52
|
let thinkCallCount = 0;
|
|
43
|
-
// Pending decision map for marrow_auto (action hash → decision_id)
|
|
44
53
|
const pendingDecisions = new Map();
|
|
45
54
|
const PENDING_TTL_MS = 30 * 60 * 1000; // 30 min TTL
|
|
46
55
|
function actionHash(action) {
|
|
@@ -56,8 +65,9 @@ function actionHash(action) {
|
|
|
56
65
|
function cleanupPending() {
|
|
57
66
|
const now = Date.now();
|
|
58
67
|
for (const [key, val] of pendingDecisions) {
|
|
59
|
-
if (now - val.timestamp > PENDING_TTL_MS)
|
|
68
|
+
if (now - val.timestamp > PENDING_TTL_MS) {
|
|
60
69
|
pendingDecisions.delete(key);
|
|
70
|
+
}
|
|
61
71
|
}
|
|
62
72
|
}
|
|
63
73
|
function formatWarningActionably(w) {
|
|
@@ -69,11 +79,13 @@ async function refreshOrientWarnings() {
|
|
|
69
79
|
const r = await (0, index_1.marrowOrient)(API_KEY, BASE_URL, undefined, SESSION_ID);
|
|
70
80
|
cachedOrientWarnings = r.warnings;
|
|
71
81
|
}
|
|
72
|
-
catch {
|
|
82
|
+
catch {
|
|
83
|
+
// ignore
|
|
84
|
+
}
|
|
73
85
|
}
|
|
74
86
|
// Initial orient
|
|
75
87
|
refreshOrientWarnings().then(() => {
|
|
76
|
-
if (cachedOrientWarnings.some(w => w.failureRate > 0.4)) {
|
|
88
|
+
if (cachedOrientWarnings.some((w) => w.failureRate > 0.4)) {
|
|
77
89
|
process.stderr.write(`[marrow] ⚠️ High failure rate detected on startup — call marrow_orient for details before acting\n`);
|
|
78
90
|
}
|
|
79
91
|
});
|
|
@@ -92,7 +104,9 @@ async function autoCommitOnClose() {
|
|
|
92
104
|
}, SESSION_ID);
|
|
93
105
|
clearTimeout(timeout);
|
|
94
106
|
}
|
|
95
|
-
catch {
|
|
107
|
+
catch {
|
|
108
|
+
// ignore
|
|
109
|
+
}
|
|
96
110
|
}
|
|
97
111
|
}
|
|
98
112
|
process.on('SIGTERM', async () => {
|
|
@@ -101,7 +115,9 @@ process.on('SIGTERM', async () => {
|
|
|
101
115
|
await autoCommitOnClose();
|
|
102
116
|
process.exit(0);
|
|
103
117
|
});
|
|
104
|
-
process.stdin.on('end', async () => {
|
|
118
|
+
process.stdin.on('end', async () => {
|
|
119
|
+
await autoCommitOnClose();
|
|
120
|
+
});
|
|
105
121
|
function send(response) {
|
|
106
122
|
process.stdout.write(JSON.stringify(response) + '\n');
|
|
107
123
|
}
|
|
@@ -111,6 +127,157 @@ function success(id, result) {
|
|
|
111
127
|
function error(id, code, message) {
|
|
112
128
|
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
113
129
|
}
|
|
130
|
+
// Memory API functions
|
|
131
|
+
async function marrowListMemories(apiKey, baseUrl, params, sessionId) {
|
|
132
|
+
const qs = new URLSearchParams();
|
|
133
|
+
if (params?.status)
|
|
134
|
+
qs.set('status', params.status);
|
|
135
|
+
if (params?.query)
|
|
136
|
+
qs.set('query', params.query);
|
|
137
|
+
if (params?.limit)
|
|
138
|
+
qs.set('limit', String(params.limit));
|
|
139
|
+
if (params?.agentId)
|
|
140
|
+
qs.set('agent_id', params.agentId);
|
|
141
|
+
const res = await fetch(`${baseUrl}/v1/memories?${qs.toString()}`, {
|
|
142
|
+
headers: {
|
|
143
|
+
Authorization: `Bearer ${apiKey}`,
|
|
144
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
const json = await res.json();
|
|
148
|
+
return json.data?.memories || [];
|
|
149
|
+
}
|
|
150
|
+
async function marrowGetMemory(apiKey, baseUrl, id, sessionId) {
|
|
151
|
+
const res = await fetch(`${baseUrl}/v1/memories/${id}`, {
|
|
152
|
+
headers: {
|
|
153
|
+
Authorization: `Bearer ${apiKey}`,
|
|
154
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
const json = await res.json();
|
|
158
|
+
return json.data?.memory || null;
|
|
159
|
+
}
|
|
160
|
+
async function marrowUpdateMemory(apiKey, baseUrl, id, patch, sessionId) {
|
|
161
|
+
const res = await fetch(`${baseUrl}/v1/memories/${id}`, {
|
|
162
|
+
method: 'PATCH',
|
|
163
|
+
headers: {
|
|
164
|
+
Authorization: `Bearer ${apiKey}`,
|
|
165
|
+
'Content-Type': 'application/json',
|
|
166
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
167
|
+
},
|
|
168
|
+
body: JSON.stringify(patch),
|
|
169
|
+
});
|
|
170
|
+
const json = await res.json();
|
|
171
|
+
return json.data.memory;
|
|
172
|
+
}
|
|
173
|
+
async function marrowDeleteMemory(apiKey, baseUrl, id, meta, sessionId) {
|
|
174
|
+
const res = await fetch(`${baseUrl}/v1/memories/${id}`, {
|
|
175
|
+
method: 'DELETE',
|
|
176
|
+
headers: {
|
|
177
|
+
Authorization: `Bearer ${apiKey}`,
|
|
178
|
+
'Content-Type': 'application/json',
|
|
179
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
180
|
+
},
|
|
181
|
+
body: JSON.stringify(meta || {}),
|
|
182
|
+
});
|
|
183
|
+
const json = await res.json();
|
|
184
|
+
return json.data.memory;
|
|
185
|
+
}
|
|
186
|
+
async function marrowMarkOutdated(apiKey, baseUrl, id, meta, sessionId) {
|
|
187
|
+
const res = await fetch(`${baseUrl}/v1/memories/${id}/outdated`, {
|
|
188
|
+
method: 'POST',
|
|
189
|
+
headers: {
|
|
190
|
+
Authorization: `Bearer ${apiKey}`,
|
|
191
|
+
'Content-Type': 'application/json',
|
|
192
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
193
|
+
},
|
|
194
|
+
body: JSON.stringify(meta || {}),
|
|
195
|
+
});
|
|
196
|
+
const json = await res.json();
|
|
197
|
+
return json.data.memory;
|
|
198
|
+
}
|
|
199
|
+
async function marrowSupersedeMemory(apiKey, baseUrl, id, replacement, sessionId) {
|
|
200
|
+
const res = await fetch(`${baseUrl}/v1/memories/${id}/supersede`, {
|
|
201
|
+
method: 'POST',
|
|
202
|
+
headers: {
|
|
203
|
+
Authorization: `Bearer ${apiKey}`,
|
|
204
|
+
'Content-Type': 'application/json',
|
|
205
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
206
|
+
},
|
|
207
|
+
body: JSON.stringify(replacement),
|
|
208
|
+
});
|
|
209
|
+
const json = await res.json();
|
|
210
|
+
return json.data;
|
|
211
|
+
}
|
|
212
|
+
async function marrowShareMemory(apiKey, baseUrl, id, agentIds, actor, sessionId) {
|
|
213
|
+
const res = await fetch(`${baseUrl}/v1/memories/${id}/share`, {
|
|
214
|
+
method: 'POST',
|
|
215
|
+
headers: {
|
|
216
|
+
Authorization: `Bearer ${apiKey}`,
|
|
217
|
+
'Content-Type': 'application/json',
|
|
218
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
219
|
+
},
|
|
220
|
+
body: JSON.stringify({ agent_ids: agentIds, actor }),
|
|
221
|
+
});
|
|
222
|
+
const json = await res.json();
|
|
223
|
+
return json.data.memory;
|
|
224
|
+
}
|
|
225
|
+
async function marrowExportMemories(apiKey, baseUrl, params, sessionId) {
|
|
226
|
+
const qs = new URLSearchParams();
|
|
227
|
+
if (params?.format)
|
|
228
|
+
qs.set('format', params.format);
|
|
229
|
+
if (params?.status)
|
|
230
|
+
qs.set('status', params.status);
|
|
231
|
+
if (params?.tags)
|
|
232
|
+
qs.set('tags', params.tags);
|
|
233
|
+
const res = await fetch(`${baseUrl}/v1/memories/export?${qs.toString()}`, {
|
|
234
|
+
headers: {
|
|
235
|
+
Authorization: `Bearer ${apiKey}`,
|
|
236
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
const json = await res.json();
|
|
240
|
+
return json.data;
|
|
241
|
+
}
|
|
242
|
+
async function marrowImportMemories(apiKey, baseUrl, memories, mode, sessionId) {
|
|
243
|
+
const res = await fetch(`${baseUrl}/v1/memories/import`, {
|
|
244
|
+
method: 'POST',
|
|
245
|
+
headers: {
|
|
246
|
+
Authorization: `Bearer ${apiKey}`,
|
|
247
|
+
'Content-Type': 'application/json',
|
|
248
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
249
|
+
},
|
|
250
|
+
body: JSON.stringify({ memories, mode }),
|
|
251
|
+
});
|
|
252
|
+
const json = await res.json();
|
|
253
|
+
return json.data;
|
|
254
|
+
}
|
|
255
|
+
async function marrowRetrieveMemories(apiKey, baseUrl, query, params, sessionId) {
|
|
256
|
+
const qs = new URLSearchParams();
|
|
257
|
+
qs.set('q', query);
|
|
258
|
+
if (params?.limit)
|
|
259
|
+
qs.set('limit', String(params.limit));
|
|
260
|
+
if (params?.from)
|
|
261
|
+
qs.set('from', params.from);
|
|
262
|
+
if (params?.to)
|
|
263
|
+
qs.set('to', params.to);
|
|
264
|
+
if (params?.tags)
|
|
265
|
+
qs.set('tags', params.tags);
|
|
266
|
+
if (params?.source)
|
|
267
|
+
qs.set('source', params.source);
|
|
268
|
+
if (params?.status)
|
|
269
|
+
qs.set('status', params.status);
|
|
270
|
+
if (params?.shared !== undefined)
|
|
271
|
+
qs.set('shared', String(params.shared));
|
|
272
|
+
const res = await fetch(`${baseUrl}/v1/memories/retrieve?${qs.toString()}`, {
|
|
273
|
+
headers: {
|
|
274
|
+
Authorization: `Bearer ${apiKey}`,
|
|
275
|
+
...(sessionId ? { 'X-Marrow-Session-Id': sessionId } : {}),
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
const json = await res.json();
|
|
279
|
+
return json.data;
|
|
280
|
+
}
|
|
114
281
|
// Tool definitions
|
|
115
282
|
const TOOLS = [
|
|
116
283
|
{
|
|
@@ -280,6 +447,145 @@ const TOOLS = [
|
|
|
280
447
|
required: [],
|
|
281
448
|
},
|
|
282
449
|
},
|
|
450
|
+
{
|
|
451
|
+
name: 'marrow_list_memories',
|
|
452
|
+
description: 'List memories with optional filters (status, query, limit, agent_id for shared memories).',
|
|
453
|
+
inputSchema: {
|
|
454
|
+
type: 'object',
|
|
455
|
+
properties: {
|
|
456
|
+
status: { type: 'string', enum: ['active', 'outdated', 'deleted'], description: 'Filter by status' },
|
|
457
|
+
query: { type: 'string', description: 'Search query' },
|
|
458
|
+
limit: { type: 'number', description: 'Max results (default: 20)' },
|
|
459
|
+
agentId: { type: 'string', description: 'Agent ID for shared memories' },
|
|
460
|
+
},
|
|
461
|
+
required: [],
|
|
462
|
+
},
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: 'marrow_get_memory',
|
|
466
|
+
description: 'Get a single memory by ID.',
|
|
467
|
+
inputSchema: {
|
|
468
|
+
type: 'object',
|
|
469
|
+
properties: {
|
|
470
|
+
id: { type: 'string', description: 'Memory ID' },
|
|
471
|
+
},
|
|
472
|
+
required: ['id'],
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
name: 'marrow_update_memory',
|
|
477
|
+
description: 'Update memory text, tags, or metadata.',
|
|
478
|
+
inputSchema: {
|
|
479
|
+
type: 'object',
|
|
480
|
+
properties: {
|
|
481
|
+
id: { type: 'string', description: 'Memory ID' },
|
|
482
|
+
text: { type: 'string', description: 'New text' },
|
|
483
|
+
source: { type: 'string', description: 'Source' },
|
|
484
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
|
|
485
|
+
actor: { type: 'string', description: 'Actor name' },
|
|
486
|
+
note: { type: 'string', description: 'Audit note' },
|
|
487
|
+
},
|
|
488
|
+
required: ['id'],
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
name: 'marrow_delete_memory',
|
|
493
|
+
description: 'Soft delete a memory.',
|
|
494
|
+
inputSchema: {
|
|
495
|
+
type: 'object',
|
|
496
|
+
properties: {
|
|
497
|
+
id: { type: 'string', description: 'Memory ID' },
|
|
498
|
+
actor: { type: 'string', description: 'Actor name' },
|
|
499
|
+
note: { type: 'string', description: 'Audit note' },
|
|
500
|
+
},
|
|
501
|
+
required: ['id'],
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
name: 'marrow_mark_outdated',
|
|
506
|
+
description: 'Mark a memory as outdated.',
|
|
507
|
+
inputSchema: {
|
|
508
|
+
type: 'object',
|
|
509
|
+
properties: {
|
|
510
|
+
id: { type: 'string', description: 'Memory ID' },
|
|
511
|
+
actor: { type: 'string', description: 'Actor name' },
|
|
512
|
+
note: { type: 'string', description: 'Audit note' },
|
|
513
|
+
},
|
|
514
|
+
required: ['id'],
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: 'marrow_supersede_memory',
|
|
519
|
+
description: 'Atomically replace a memory with a new version.',
|
|
520
|
+
inputSchema: {
|
|
521
|
+
type: 'object',
|
|
522
|
+
properties: {
|
|
523
|
+
id: { type: 'string', description: 'Memory ID to supersede' },
|
|
524
|
+
text: { type: 'string', description: 'New memory text' },
|
|
525
|
+
source: { type: 'string', description: 'Source' },
|
|
526
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags' },
|
|
527
|
+
actor: { type: 'string', description: 'Actor name' },
|
|
528
|
+
note: { type: 'string', description: 'Audit note' },
|
|
529
|
+
},
|
|
530
|
+
required: ['id', 'text'],
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: 'marrow_share_memory',
|
|
535
|
+
description: 'Share a memory with specific agents.',
|
|
536
|
+
inputSchema: {
|
|
537
|
+
type: 'object',
|
|
538
|
+
properties: {
|
|
539
|
+
id: { type: 'string', description: 'Memory ID' },
|
|
540
|
+
agentIds: { type: 'array', items: { type: 'string' }, description: 'Agent IDs to share with' },
|
|
541
|
+
actor: { type: 'string', description: 'Actor name' },
|
|
542
|
+
},
|
|
543
|
+
required: ['id', 'agentIds'],
|
|
544
|
+
},
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
name: 'marrow_export_memories',
|
|
548
|
+
description: 'Export memories to JSON or CSV.',
|
|
549
|
+
inputSchema: {
|
|
550
|
+
type: 'object',
|
|
551
|
+
properties: {
|
|
552
|
+
format: { type: 'string', enum: ['json', 'csv'], description: 'Export format' },
|
|
553
|
+
status: { type: 'string', enum: ['active', 'all'], description: 'Filter by status' },
|
|
554
|
+
tags: { type: 'string', description: 'Comma-separated tags' },
|
|
555
|
+
},
|
|
556
|
+
required: [],
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
name: 'marrow_import_memories',
|
|
561
|
+
description: 'Import memories with merge (dedup) or replace mode.',
|
|
562
|
+
inputSchema: {
|
|
563
|
+
type: 'object',
|
|
564
|
+
properties: {
|
|
565
|
+
memories: { type: 'array', items: { type: 'object', properties: { text: { type: 'string' }, source: { type: 'string' }, tags: { type: 'array', items: { type: 'string' } } } }, description: 'Memories to import' },
|
|
566
|
+
mode: { type: 'string', enum: ['merge', 'replace'], description: 'Import mode' },
|
|
567
|
+
},
|
|
568
|
+
required: ['memories', 'mode'],
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
name: 'marrow_retrieve_memories',
|
|
573
|
+
description: 'Full-text search memories with filters (from, to, tags, source, status, shared).',
|
|
574
|
+
inputSchema: {
|
|
575
|
+
type: 'object',
|
|
576
|
+
properties: {
|
|
577
|
+
query: { type: 'string', description: 'Search query' },
|
|
578
|
+
limit: { type: 'number', description: 'Max results' },
|
|
579
|
+
from: { type: 'string', description: 'From date (ISO-8601)' },
|
|
580
|
+
to: { type: 'string', description: 'To date (ISO-8601)' },
|
|
581
|
+
tags: { type: 'string', description: 'Comma-separated tags' },
|
|
582
|
+
source: { type: 'string', description: 'Source filter' },
|
|
583
|
+
status: { type: 'string', enum: ['active', 'outdated', 'deleted'], description: 'Status filter' },
|
|
584
|
+
shared: { type: 'boolean', description: 'Include shared memories' },
|
|
585
|
+
},
|
|
586
|
+
required: ['query'],
|
|
587
|
+
},
|
|
588
|
+
},
|
|
283
589
|
];
|
|
284
590
|
// Request handler
|
|
285
591
|
async function handleRequest(req) {
|
|
@@ -299,9 +605,9 @@ async function handleRequest(req) {
|
|
|
299
605
|
{
|
|
300
606
|
name: 'marrow-always-on',
|
|
301
607
|
description: 'Always-on Marrow memory loop. Instructs the agent to orient at session start, log intent before meaningful actions, and commit outcomes after completion. Install once — works automatically.',
|
|
302
|
-
arguments: []
|
|
303
|
-
}
|
|
304
|
-
]
|
|
608
|
+
arguments: [],
|
|
609
|
+
},
|
|
610
|
+
],
|
|
305
611
|
});
|
|
306
612
|
return;
|
|
307
613
|
}
|
|
@@ -358,10 +664,10 @@ If you skip logging, the hive can't protect you or future agents from this mista
|
|
|
358
664
|
Every decision you log compounds. Failure rates drop. Patterns emerge. The next session starts smarter.
|
|
359
665
|
Marrow tells you what went wrong last time before you do it again. But only if you logged it.
|
|
360
666
|
|
|
361
|
-
This is not optional overhead — it's how you stop repeating the same failures
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
]
|
|
667
|
+
This is not optional overhead — it's how you stop repeating the same failures.`,
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
],
|
|
365
671
|
});
|
|
366
672
|
return;
|
|
367
673
|
}
|
|
@@ -373,16 +679,9 @@ This is not optional overhead — it's how you stop repeating the same failures.
|
|
|
373
679
|
const toolName = params?.name;
|
|
374
680
|
const args = (params?.arguments || {});
|
|
375
681
|
if (toolName === 'marrow_orient') {
|
|
376
|
-
const result = await (0, index_1.marrowOrient)(API_KEY, BASE_URL, {
|
|
377
|
-
taskType: args.taskType,
|
|
378
|
-
}, SESSION_ID);
|
|
682
|
+
const result = await (0, index_1.marrowOrient)(API_KEY, BASE_URL, { taskType: args.taskType }, SESSION_ID);
|
|
379
683
|
success(id, {
|
|
380
|
-
content: [
|
|
381
|
-
{
|
|
382
|
-
type: 'text',
|
|
383
|
-
text: JSON.stringify(result, null, 2),
|
|
384
|
-
},
|
|
385
|
-
],
|
|
684
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
386
685
|
});
|
|
387
686
|
return;
|
|
388
687
|
}
|
|
@@ -398,33 +697,27 @@ This is not optional overhead — it's how you stop repeating the same failures.
|
|
|
398
697
|
// Refresh orient warnings every 5th think call
|
|
399
698
|
thinkCallCount++;
|
|
400
699
|
if (thinkCallCount % 5 === 0) {
|
|
401
|
-
refreshOrientWarnings()
|
|
700
|
+
refreshOrientWarnings();
|
|
402
701
|
}
|
|
403
|
-
// Inject orient warnings into
|
|
702
|
+
// Inject cached orient warnings into intelligence.insights
|
|
404
703
|
if (cachedOrientWarnings.length > 0) {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
...cachedOrientWarnings.map(w => ({
|
|
704
|
+
const existingInsights = result.intelligence?.insights || [];
|
|
705
|
+
result.intelligence.insights = [
|
|
706
|
+
...cachedOrientWarnings.map((w) => ({
|
|
409
707
|
type: 'failure_pattern',
|
|
410
|
-
summary:
|
|
708
|
+
summary: w.message,
|
|
411
709
|
action: `Review past ${w.type} failures before proceeding`,
|
|
412
|
-
severity: w.failureRate > 0.4 ? 'critical' : 'warning',
|
|
710
|
+
severity: (w.failureRate > 0.4 ? 'critical' : 'warning'),
|
|
413
711
|
count: 0,
|
|
414
712
|
})),
|
|
415
|
-
...
|
|
713
|
+
...existingInsights,
|
|
416
714
|
];
|
|
417
715
|
}
|
|
418
|
-
// Track for auto-commit
|
|
716
|
+
// Track for auto-commit
|
|
419
717
|
lastDecisionId = result.decision_id;
|
|
420
718
|
lastCommitted = false;
|
|
421
719
|
success(id, {
|
|
422
|
-
content: [
|
|
423
|
-
{
|
|
424
|
-
type: 'text',
|
|
425
|
-
text: JSON.stringify(result, null, 2),
|
|
426
|
-
},
|
|
427
|
-
],
|
|
720
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
428
721
|
});
|
|
429
722
|
return;
|
|
430
723
|
}
|
|
@@ -436,191 +729,209 @@ This is not optional overhead — it's how you stop repeating the same failures.
|
|
|
436
729
|
caused_by: args.caused_by,
|
|
437
730
|
}, SESSION_ID);
|
|
438
731
|
lastCommitted = true;
|
|
732
|
+
lastDecisionId = null;
|
|
439
733
|
success(id, {
|
|
440
|
-
content: [
|
|
441
|
-
{
|
|
442
|
-
type: 'text',
|
|
443
|
-
text: JSON.stringify(result, null, 2),
|
|
444
|
-
},
|
|
445
|
-
],
|
|
734
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
446
735
|
});
|
|
447
736
|
return;
|
|
448
737
|
}
|
|
449
738
|
if (toolName === 'marrow_run') {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
const runSuccess = args.success;
|
|
453
|
-
const outcome = args.outcome;
|
|
739
|
+
// marrow_run = orient + think + commit in one call
|
|
740
|
+
await (0, index_1.marrowOrient)(API_KEY, BASE_URL, undefined, SESSION_ID);
|
|
454
741
|
const thinkResult = await (0, index_1.marrowThink)(API_KEY, BASE_URL, {
|
|
455
|
-
action: description,
|
|
456
|
-
type,
|
|
742
|
+
action: args.description,
|
|
743
|
+
type: args.type || 'general',
|
|
457
744
|
}, SESSION_ID);
|
|
458
745
|
const commitResult = await (0, index_1.marrowCommit)(API_KEY, BASE_URL, {
|
|
459
746
|
decision_id: thinkResult.decision_id,
|
|
460
|
-
success:
|
|
461
|
-
outcome,
|
|
747
|
+
success: args.success ?? true,
|
|
748
|
+
outcome: args.outcome,
|
|
462
749
|
}, SESSION_ID);
|
|
463
|
-
lastCommitted = true;
|
|
464
|
-
lastDecisionId = thinkResult.decision_id;
|
|
465
750
|
success(id, {
|
|
466
751
|
content: [
|
|
467
752
|
{
|
|
468
753
|
type: 'text',
|
|
469
|
-
text: JSON.stringify({
|
|
470
|
-
decision_id: thinkResult.decision_id,
|
|
471
|
-
success_rate: commitResult.success_rate,
|
|
472
|
-
insight: commitResult.insight,
|
|
473
|
-
intelligence: thinkResult.intelligence,
|
|
474
|
-
}, null, 2),
|
|
754
|
+
text: JSON.stringify({ think: thinkResult, commit: commitResult }, null, 2),
|
|
475
755
|
},
|
|
476
756
|
],
|
|
477
757
|
});
|
|
478
758
|
return;
|
|
479
759
|
}
|
|
480
760
|
if (toolName === 'marrow_auto') {
|
|
761
|
+
// marrow_auto = fire-and-forget background logging
|
|
762
|
+
// Return immediately with cached orient warnings, API calls happen in background
|
|
481
763
|
const action = args.action;
|
|
482
764
|
const outcome = args.outcome;
|
|
483
|
-
const
|
|
765
|
+
const outcomeSuccess = args.success ?? true;
|
|
484
766
|
const type = args.type || 'general';
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
outcome,
|
|
503
|
-
}, SESSION_ID).then(() => { lastCommitted = true; }).catch((e) => { process.stderr.write('[marrow] background op failed: ' + String(e) + '\n'); });
|
|
504
|
-
success(id, {
|
|
505
|
-
content: [{ type: 'text', text: JSON.stringify({
|
|
506
|
-
warnings,
|
|
507
|
-
decision_id: decisionId,
|
|
508
|
-
message: 'Logged. Continue with your task.',
|
|
509
|
-
}, null, 2) }],
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
else {
|
|
513
|
-
// No pending — fire-and-forget think+commit
|
|
514
|
-
(0, index_1.marrowThink)(API_KEY, BASE_URL, { action, type }, SESSION_ID)
|
|
515
|
-
.then(thinkResult => {
|
|
516
|
-
lastDecisionId = thinkResult.decision_id;
|
|
517
|
-
return (0, index_1.marrowCommit)(API_KEY, BASE_URL, {
|
|
767
|
+
// Return cached warnings immediately
|
|
768
|
+
const response = {
|
|
769
|
+
action,
|
|
770
|
+
outcome: outcome || 'pending',
|
|
771
|
+
warnings: cachedOrientWarnings.map(formatWarningActionably),
|
|
772
|
+
};
|
|
773
|
+
// Fire-and-forget the actual API calls
|
|
774
|
+
(async () => {
|
|
775
|
+
try {
|
|
776
|
+
if (!outcome) {
|
|
777
|
+
// Intent only
|
|
778
|
+
await (0, index_1.marrowThink)(API_KEY, BASE_URL, { action, type }, SESSION_ID);
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
// Full loop
|
|
782
|
+
const thinkResult = await (0, index_1.marrowThink)(API_KEY, BASE_URL, { action, type }, SESSION_ID);
|
|
783
|
+
await (0, index_1.marrowCommit)(API_KEY, BASE_URL, {
|
|
518
784
|
decision_id: thinkResult.decision_id,
|
|
519
|
-
success:
|
|
785
|
+
success: outcomeSuccess,
|
|
520
786
|
outcome,
|
|
521
787
|
}, SESSION_ID);
|
|
522
|
-
}
|
|
523
|
-
.then(() => { lastCommitted = true; })
|
|
524
|
-
.catch((e) => { process.stderr.write('[marrow] background op failed: ' + String(e) + '\n'); });
|
|
525
|
-
success(id, {
|
|
526
|
-
content: [{ type: 'text', text: JSON.stringify({
|
|
527
|
-
warnings,
|
|
528
|
-
decision_id: null,
|
|
529
|
-
message: 'Logged. Continue with your task.',
|
|
530
|
-
}, null, 2) }],
|
|
531
|
-
});
|
|
788
|
+
}
|
|
532
789
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
// Intent only — fire-and-forget think, store decision_id when resolved
|
|
536
|
-
cleanupPending();
|
|
537
|
-
(0, index_1.marrowThink)(API_KEY, BASE_URL, { action, type }, SESSION_ID)
|
|
538
|
-
.then(thinkResult => {
|
|
539
|
-
pendingDecisions.set(hash, {
|
|
540
|
-
decision_id: thinkResult.decision_id,
|
|
541
|
-
action,
|
|
542
|
-
timestamp: Date.now(),
|
|
543
|
-
});
|
|
544
|
-
lastDecisionId = thinkResult.decision_id;
|
|
545
|
-
lastCommitted = false;
|
|
546
|
-
})
|
|
547
|
-
.catch((e) => { process.stderr.write('[marrow] background op failed: ' + String(e) + '\n'); });
|
|
548
|
-
// Refresh orient warnings periodically
|
|
549
|
-
thinkCallCount++;
|
|
550
|
-
if (thinkCallCount % 5 === 0) {
|
|
551
|
-
refreshOrientWarnings().catch((e) => { process.stderr.write('[marrow] background op failed: ' + String(e) + '\n'); });
|
|
790
|
+
catch {
|
|
791
|
+
// Silently fail - auto is best-effort
|
|
552
792
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
message: 'Logged. Continue with your task.',
|
|
558
|
-
}, null, 2) }],
|
|
559
|
-
});
|
|
560
|
-
}
|
|
793
|
+
})();
|
|
794
|
+
success(id, {
|
|
795
|
+
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
|
|
796
|
+
});
|
|
561
797
|
return;
|
|
562
798
|
}
|
|
563
799
|
if (toolName === 'marrow_ask') {
|
|
564
|
-
const
|
|
565
|
-
if (!query) {
|
|
566
|
-
error(id, -32602, 'query parameter is required');
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
const result = await (0, index_1.marrowAsk)(API_KEY, BASE_URL, { query }, SESSION_ID);
|
|
800
|
+
const result = await (0, index_1.marrowAsk)(API_KEY, BASE_URL, { query: args.query }, SESSION_ID);
|
|
570
801
|
success(id, {
|
|
571
|
-
content: [
|
|
572
|
-
{
|
|
573
|
-
type: 'text',
|
|
574
|
-
text: JSON.stringify(result, null, 2),
|
|
575
|
-
},
|
|
576
|
-
],
|
|
802
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
577
803
|
});
|
|
578
804
|
return;
|
|
579
805
|
}
|
|
580
806
|
if (toolName === 'marrow_status') {
|
|
581
807
|
const result = await (0, index_1.marrowStatus)(API_KEY, BASE_URL, SESSION_ID);
|
|
582
808
|
success(id, {
|
|
583
|
-
content: [
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
809
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
810
|
+
});
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
// Memory control tools
|
|
814
|
+
if (toolName === 'marrow_list_memories') {
|
|
815
|
+
const result = await marrowListMemories(API_KEY, BASE_URL, {
|
|
816
|
+
status: args.status,
|
|
817
|
+
query: args.query,
|
|
818
|
+
limit: args.limit,
|
|
819
|
+
agentId: args.agentId,
|
|
820
|
+
}, SESSION_ID);
|
|
821
|
+
success(id, {
|
|
822
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
823
|
+
});
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
if (toolName === 'marrow_get_memory') {
|
|
827
|
+
const result = await marrowGetMemory(API_KEY, BASE_URL, args.id, SESSION_ID);
|
|
828
|
+
success(id, {
|
|
829
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
830
|
+
});
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
if (toolName === 'marrow_update_memory') {
|
|
834
|
+
const result = await marrowUpdateMemory(API_KEY, BASE_URL, args.id, {
|
|
835
|
+
text: args.text,
|
|
836
|
+
source: args.source,
|
|
837
|
+
tags: args.tags,
|
|
838
|
+
actor: args.actor,
|
|
839
|
+
note: args.note,
|
|
840
|
+
}, SESSION_ID);
|
|
841
|
+
success(id, {
|
|
842
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
843
|
+
});
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
if (toolName === 'marrow_delete_memory') {
|
|
847
|
+
const result = await marrowDeleteMemory(API_KEY, BASE_URL, args.id, { actor: args.actor, note: args.note }, SESSION_ID);
|
|
848
|
+
success(id, {
|
|
849
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
850
|
+
});
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (toolName === 'marrow_mark_outdated') {
|
|
854
|
+
const result = await marrowMarkOutdated(API_KEY, BASE_URL, args.id, { actor: args.actor, note: args.note }, SESSION_ID);
|
|
855
|
+
success(id, {
|
|
856
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
857
|
+
});
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
if (toolName === 'marrow_supersede_memory') {
|
|
861
|
+
const result = await marrowSupersedeMemory(API_KEY, BASE_URL, args.id, {
|
|
862
|
+
text: args.text,
|
|
863
|
+
source: args.source,
|
|
864
|
+
tags: args.tags,
|
|
865
|
+
actor: args.actor,
|
|
866
|
+
note: args.note,
|
|
867
|
+
}, SESSION_ID);
|
|
868
|
+
success(id, {
|
|
869
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
870
|
+
});
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (toolName === 'marrow_share_memory') {
|
|
874
|
+
const result = await marrowShareMemory(API_KEY, BASE_URL, args.id, args.agentIds || [], args.actor, SESSION_ID);
|
|
875
|
+
success(id, {
|
|
876
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
877
|
+
});
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (toolName === 'marrow_export_memories') {
|
|
881
|
+
const result = await marrowExportMemories(API_KEY, BASE_URL, {
|
|
882
|
+
format: args.format,
|
|
883
|
+
status: args.status,
|
|
884
|
+
tags: args.tags,
|
|
885
|
+
}, SESSION_ID);
|
|
886
|
+
success(id, {
|
|
887
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
888
|
+
});
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
if (toolName === 'marrow_import_memories') {
|
|
892
|
+
const result = await marrowImportMemories(API_KEY, BASE_URL, args.memories || [], args.mode || 'merge', SESSION_ID);
|
|
893
|
+
success(id, {
|
|
894
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
895
|
+
});
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
if (toolName === 'marrow_retrieve_memories') {
|
|
899
|
+
const result = await marrowRetrieveMemories(API_KEY, BASE_URL, args.query, {
|
|
900
|
+
limit: args.limit,
|
|
901
|
+
from: args.from,
|
|
902
|
+
to: args.to,
|
|
903
|
+
tags: args.tags,
|
|
904
|
+
source: args.source,
|
|
905
|
+
status: args.status,
|
|
906
|
+
shared: args.shared,
|
|
907
|
+
}, SESSION_ID);
|
|
908
|
+
success(id, {
|
|
909
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
589
910
|
});
|
|
590
911
|
return;
|
|
591
912
|
}
|
|
592
|
-
error(id, -32601, `
|
|
913
|
+
error(id, -32601, `Method not found: ${toolName}`);
|
|
593
914
|
return;
|
|
594
915
|
}
|
|
595
|
-
// Unknown method
|
|
596
916
|
error(id, -32601, `Method not found: ${method}`);
|
|
597
917
|
}
|
|
598
918
|
catch (err) {
|
|
599
|
-
const
|
|
600
|
-
error(id, -
|
|
919
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
920
|
+
error(id, -32000, message);
|
|
601
921
|
}
|
|
602
922
|
}
|
|
603
|
-
// stdio
|
|
923
|
+
// MCP stdio loop
|
|
604
924
|
const rl = readline.createInterface({
|
|
605
925
|
input: process.stdin,
|
|
606
926
|
output: process.stdout,
|
|
607
|
-
terminal: false,
|
|
608
927
|
});
|
|
609
|
-
rl.on('line', (line) => {
|
|
610
|
-
const trimmed = line.trim();
|
|
611
|
-
if (!trimmed)
|
|
612
|
-
return;
|
|
928
|
+
rl.on('line', async (line) => {
|
|
613
929
|
try {
|
|
614
|
-
const
|
|
615
|
-
handleRequest(
|
|
616
|
-
process.stderr.write(`Unhandled error: ${err}\n`);
|
|
617
|
-
});
|
|
930
|
+
const msg = JSON.parse(line);
|
|
931
|
+
await handleRequest(msg);
|
|
618
932
|
}
|
|
619
|
-
catch {
|
|
620
|
-
process.stderr.write(`
|
|
933
|
+
catch (err) {
|
|
934
|
+
process.stderr.write(`[marrow] Parse error: ${err}\n`);
|
|
621
935
|
}
|
|
622
936
|
});
|
|
623
|
-
rl.on('close', () => {
|
|
624
|
-
process.exit(0);
|
|
625
|
-
});
|
|
626
937
|
//# sourceMappingURL=cli.js.map
|