@getmarrow/mcp 2.8.0 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 (mod) {
24
- if (mod && mod.__esModule) return mod;
25
- var result = {};
26
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
27
- __setModuleDefault(result, mod);
28
- return result;
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 () => { await autoCommitOnClose(); });
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().catch((e) => { process.stderr.write('[marrow] background op failed: ' + String(e) + '\n'); });
700
+ refreshOrientWarnings();
402
701
  }
403
- // Inject orient warnings into EVERY think() response (not just first)
702
+ // Inject cached orient warnings into intelligence.insights
404
703
  if (cachedOrientWarnings.length > 0) {
405
- const intel = result.intelligence;
406
- const existing = intel.insights || [];
407
- intel.insights = [
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: formatWarningActionably(w),
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
- ...existing,
713
+ ...existingInsights,
416
714
  ];
417
715
  }
418
- // Track for auto-commit on session close
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
- const description = args.description;
451
- const type = args.type || 'general';
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: runSuccess,
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 autoSuccess = args.success !== undefined ? args.success : true;
765
+ const outcomeSuccess = args.success ?? true;
484
766
  const type = args.type || 'general';
485
- if (!action) {
486
- error(id, -32602, 'action parameter is required');
487
- return;
488
- }
489
- // Collect warnings synchronously from cache — no API call
490
- const warnings = cachedOrientWarnings.map(formatWarningActionably);
491
- const hash = actionHash(action);
492
- if (outcome) {
493
- // Full round-trip: think + commit, fire-and-forget
494
- const existingPending = pendingDecisions.get(hash);
495
- if (existingPending) {
496
- // Match a previous intent commit against that decision
497
- const decisionId = existingPending.decision_id;
498
- pendingDecisions.delete(hash);
499
- (0, index_1.marrowCommit)(API_KEY, BASE_URL, {
500
- decision_id: decisionId,
501
- success: autoSuccess,
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: autoSuccess,
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
- else {
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
- success(id, {
554
- content: [{ type: 'text', text: JSON.stringify({
555
- warnings,
556
- decision_id: null,
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 query = args.query;
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
- type: 'text',
586
- text: JSON.stringify(result, null, 2),
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, `Unknown tool: ${toolName}`);
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 msg = err instanceof Error ? err.message.slice(0, 200) : 'Internal error';
600
- error(id, -32603, msg);
919
+ const message = err instanceof Error ? err.message : String(err);
920
+ error(id, -32000, message);
601
921
  }
602
922
  }
603
- // stdio server
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 req = JSON.parse(trimmed);
615
- handleRequest(req).catch((err) => {
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(`Failed to parse request: ${trimmed}\n`);
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