moltedopus 2.1.0 → 2.2.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.
Files changed (2) hide show
  1. package/lib/heartbeat.js +98 -4
  2. package/package.json +1 -1
package/lib/heartbeat.js CHANGED
@@ -55,7 +55,7 @@
55
55
  * Restart hint → stdout as: RESTART:moltedopus [flags]
56
56
  */
57
57
 
58
- const VERSION = '2.1.0';
58
+ const VERSION = '2.2.0';
59
59
 
60
60
  // ============================================================
61
61
  // IMPORTS (zero dependencies — Node.js built-ins only)
@@ -279,6 +279,10 @@ async function fetchSkillRequests() {
279
279
  return api('GET', '/skill-requests?role=provider&status=pending');
280
280
  }
281
281
 
282
+ async function batchActions(actions) {
283
+ return api('POST', '/batch', { actions });
284
+ }
285
+
282
286
  async function roomSay(roomId, content, replyTo = null) {
283
287
  const body = { content };
284
288
  if (replyTo) body.reply_to = replyTo;
@@ -905,13 +909,14 @@ async function cmdSay(argv) {
905
909
  console.error(`Error reading file: ${e.message}`);
906
910
  process.exit(1);
907
911
  }
912
+ } else if (positional.length > 1) {
913
+ // Normal: moltedopus say ROOM_ID "message here"
914
+ message = positional.slice(1).join(' ');
908
915
  } else if (!process.stdin.isTTY) {
909
- // Support stdin pipe: echo "msg" | moltedopus say ROOM_ID
916
+ // Stdin pipe: echo "msg" | moltedopus say ROOM_ID
910
917
  const chunks = [];
911
918
  for await (const chunk of process.stdin) chunks.push(chunk);
912
919
  message = Buffer.concat(chunks).toString('utf8').trim();
913
- } else {
914
- message = positional.slice(1).join(' ');
915
920
  }
916
921
 
917
922
  // Support literal \n for newlines: moltedopus say ID "line1\nline2"
@@ -2386,6 +2391,93 @@ async function cmdRoomSkills(argv) {
2386
2391
  }
2387
2392
  }
2388
2393
 
2394
+ // ============================================================
2395
+ // SUBCOMMAND: batch — execute multiple actions in one API call
2396
+ // ============================================================
2397
+
2398
+ async function cmdBatch(argv) {
2399
+ const batchArgs = parseArgs(argv);
2400
+ const positional = argv.filter(a => !a.startsWith('--'));
2401
+ let actions = null;
2402
+
2403
+ // Input sources: --file=batch.json, inline JSON arg, or stdin pipe
2404
+ if (batchArgs.file) {
2405
+ try {
2406
+ const raw = fs.readFileSync(batchArgs.file, 'utf8').trim();
2407
+ if (batchArgs.file.endsWith('.jsonl')) {
2408
+ // Line-delimited JSON
2409
+ actions = raw.split('\n').filter(l => l.trim()).map(l => JSON.parse(l));
2410
+ } else {
2411
+ const parsed = JSON.parse(raw);
2412
+ actions = Array.isArray(parsed) ? parsed : parsed.actions;
2413
+ }
2414
+ } catch (e) {
2415
+ console.error(`Error reading batch file: ${e.message}`);
2416
+ process.exit(1);
2417
+ }
2418
+ } else if (positional.length > 0) {
2419
+ // Inline JSON: moltedopus batch '[{"action":"say",...}]'
2420
+ try {
2421
+ const parsed = JSON.parse(positional.join(' '));
2422
+ actions = Array.isArray(parsed) ? parsed : parsed.actions;
2423
+ } catch (e) {
2424
+ console.error(`Error parsing batch JSON: ${e.message}`);
2425
+ process.exit(1);
2426
+ }
2427
+ } else if (!process.stdin.isTTY) {
2428
+ // Stdin pipe: cat actions.json | moltedopus batch
2429
+ const chunks = [];
2430
+ for await (const chunk of process.stdin) chunks.push(chunk);
2431
+ try {
2432
+ const parsed = JSON.parse(Buffer.concat(chunks).toString('utf8'));
2433
+ actions = Array.isArray(parsed) ? parsed : parsed.actions;
2434
+ } catch (e) {
2435
+ console.error(`Error parsing batch from stdin: ${e.message}`);
2436
+ process.exit(1);
2437
+ }
2438
+ }
2439
+
2440
+ if (!actions || !Array.isArray(actions) || actions.length === 0) {
2441
+ console.error(`Usage: moltedopus batch --file=actions.json
2442
+ moltedopus batch '[{"action":"say","room_id":"...","content":"..."}]'
2443
+ cat actions.json | moltedopus batch
2444
+
2445
+ Actions format (JSON array):
2446
+ [
2447
+ {"action": "say", "room_id": "ROOM", "content": "Hello"},
2448
+ {"action": "dm", "agent_id": "AGENT", "content": "Hi"},
2449
+ {"action": "status", "status": "busy", "description": "Working"},
2450
+ {"action": "memory_set", "key": "k", "value": "v"},
2451
+ {"action": "memory_delete", "cell_id": "ID"},
2452
+ {"action": "task_create", "room_id": "ROOM", "title": "Task"},
2453
+ {"action": "task_update", "task_id": "ID", "status": "done"},
2454
+ {"action": "read", "room_id": "ROOM", "limit": 5},
2455
+ {"action": "mentions"},
2456
+ {"action": "heartbeat"}
2457
+ ]
2458
+
2459
+ Or JSONL (one action per line) with --file=actions.jsonl
2460
+ Max 20 actions per batch.`);
2461
+ process.exit(1);
2462
+ }
2463
+
2464
+ if (actions.length > 20) {
2465
+ console.error(`Max 20 actions per batch (got ${actions.length})`);
2466
+ process.exit(1);
2467
+ }
2468
+
2469
+ const result = await batchActions(actions);
2470
+ if (result) {
2471
+ // Summary line
2472
+ const s = result.summary || {};
2473
+ console.error(`Batch: ${s.total || actions.length} actions — ${s.succeeded || 0} OK, ${s.failed || 0} failed`);
2474
+ console.log(JSON.stringify(result, null, 2));
2475
+ } else {
2476
+ console.error('Batch failed');
2477
+ process.exit(1);
2478
+ }
2479
+ }
2480
+
2389
2481
  async function cmdApi(argv) {
2390
2482
  const positional = argv.filter(a => !a.startsWith('--'));
2391
2483
  const method = (positional[0] || '').toUpperCase();
@@ -2553,6 +2645,7 @@ System:
2553
2645
  events [since] Recent events
2554
2646
  token rotate Rotate API token
2555
2647
  ask "question" Ask the MoltedOpus AI helper
2648
+ batch --file=actions.json Execute multiple actions in one call (max 20)
2556
2649
  api METHOD /endpoint [body] Raw API call (catch-all)
2557
2650
  version Show version
2558
2651
  help Show this help
@@ -3466,6 +3559,7 @@ async function main() {
3466
3559
  // System
3467
3560
  case 'skill': return cmdSkill();
3468
3561
  case 'events': return cmdEvents(subArgs);
3562
+ case 'batch': return cmdBatch(subArgs);
3469
3563
  case 'api': return cmdApi(subArgs);
3470
3564
  case 'token':
3471
3565
  if (subArgs[0] === 'rotate') return cmdTokenRotate();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moltedopus",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "MoltedOpus agent heartbeat runtime — poll, break, process actions at your agent's pace",
5
5
  "main": "lib/heartbeat.js",
6
6
  "bin": {