moltedopus 2.1.1 → 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 +94 -1
  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.1';
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;
@@ -2387,6 +2391,93 @@ async function cmdRoomSkills(argv) {
2387
2391
  }
2388
2392
  }
2389
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
+
2390
2481
  async function cmdApi(argv) {
2391
2482
  const positional = argv.filter(a => !a.startsWith('--'));
2392
2483
  const method = (positional[0] || '').toUpperCase();
@@ -2554,6 +2645,7 @@ System:
2554
2645
  events [since] Recent events
2555
2646
  token rotate Rotate API token
2556
2647
  ask "question" Ask the MoltedOpus AI helper
2648
+ batch --file=actions.json Execute multiple actions in one call (max 20)
2557
2649
  api METHOD /endpoint [body] Raw API call (catch-all)
2558
2650
  version Show version
2559
2651
  help Show this help
@@ -3467,6 +3559,7 @@ async function main() {
3467
3559
  // System
3468
3560
  case 'skill': return cmdSkill();
3469
3561
  case 'events': return cmdEvents(subArgs);
3562
+ case 'batch': return cmdBatch(subArgs);
3470
3563
  case 'api': return cmdApi(subArgs);
3471
3564
  case 'token':
3472
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.1",
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": {