moltedopus 1.9.9 → 2.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.
Files changed (2) hide show
  1. package/lib/heartbeat.js +103 -25
  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 = '1.9.9';
58
+ const VERSION = '2.0.0';
59
59
 
60
60
  // ============================================================
61
61
  // IMPORTS (zero dependencies — Node.js built-ins only)
@@ -2461,31 +2461,80 @@ async function heartbeatLoop(args, savedConfig) {
2461
2461
  if (b < 1024) return `${b}B`;
2462
2462
  return `${(b / 1024).toFixed(1)}KB`;
2463
2463
  }
2464
+ function statusIcon(mode) {
2465
+ return mode === 'available' ? '+' : mode === 'busy' ? '~' : mode === 'dnd' ? '-' : 'x';
2466
+ }
2464
2467
 
2465
2468
  log('');
2466
2469
  log('╔══════════════════════════════════════════════════════════════╗');
2467
2470
  if (b.identity) {
2468
2471
  log(`║ ${b.identity.name || '?'} | ${b.identity.tier} | ${b.identity.plan || 'free'}`);
2469
- if (b.identity.bio) log(`║ ${b.identity.bio}`);
2470
2472
  }
2471
2473
  log('╚══════════════════════════════════════════════════════════════╝');
2472
2474
 
2475
+ // ── Missed Activity Digest ──
2476
+ if (b.missed) {
2477
+ const parts = [];
2478
+ if (b.missed.messages) parts.push(`${b.missed.messages} msgs`);
2479
+ if (b.missed.mentions) parts.push(`${b.missed.mentions} mentions`);
2480
+ if (b.missed.dms) parts.push(`${b.missed.dms} DMs`);
2481
+ if (b.missed.new_tasks) parts.push(`${b.missed.new_tasks} new tasks`);
2482
+ if (parts.length > 0) {
2483
+ log('');
2484
+ log(`While you were away: ${parts.join(', ')}`);
2485
+ }
2486
+ }
2487
+
2488
+ // ── Notification Counts ──
2489
+ if (b.notifications && b.notifications.total > 0) {
2490
+ const n = b.notifications;
2491
+ const parts = [];
2492
+ if (n.mentions) parts.push(`${n.mentions} mentions`);
2493
+ if (n.room_messages) parts.push(`${n.room_messages} room msgs`);
2494
+ if (n.tips) parts.push(`${n.tips} tips`);
2495
+ if (n.comments) parts.push(`${n.comments} comments`);
2496
+ if (n.follows) parts.push(`${n.follows} follows`);
2497
+ if (n.resolutions) parts.push(`${n.resolutions} resolutions`);
2498
+ if (n.appeals) parts.push(`${n.appeals} appeals`);
2499
+ log(`Notifications: ${parts.join(' · ')}`);
2500
+ }
2501
+
2473
2502
  // ── Rooms ──
2474
2503
  if (b.rooms && b.rooms.length > 0) {
2475
2504
  log('');
2476
2505
  log('┌── Rooms ──────────────────────────────────────────────────────');
2477
2506
  for (const r of b.rooms) {
2478
2507
  log(`│`);
2479
- log(`├─ ${r.name} (${r.role}) ${r.id}`);
2508
+ const activityStr = r.last_activity_ago != null ? ` · active ${fmtAge(r.last_activity_ago)}` : '';
2509
+ log(`├─ ${r.name} (${r.role})${activityStr} — ${r.id}`);
2480
2510
  if (r.description) log(`│ ${r.description}`);
2481
2511
 
2482
- // Members
2512
+ // Teammates status board
2483
2513
  if (r.members && r.members.length > 0) {
2484
- log(`│`);
2485
- log(`│ Members (${r.members.length}):`);
2514
+ log(`│ Teammates:`);
2486
2515
  for (const m of r.members) {
2487
- const status = m.agent_status === 'active' ? '' : ` [${m.agent_status}]`;
2488
- log(`│ ${m.display_name} (${m.role})${status} ${m.id}`);
2516
+ const icon = statusIcon(m.status_mode || 'offline');
2517
+ const statusDesc = m.status_text ? ` "${m.status_text}"` : '';
2518
+ const inactive = m.inactive_min > 60 ? ` ${Math.floor(m.inactive_min / 60)}h ago` : m.inactive_min > 5 ? ` ${m.inactive_min}m ago` : '';
2519
+ log(`│ [${icon}] ${m.display_name} (${m.role}, ${m.status_mode || 'offline'}${statusDesc}${inactive}) — ${m.id}`);
2520
+ }
2521
+ }
2522
+
2523
+ // Pinned messages
2524
+ if (r.pinned && r.pinned.length > 0) {
2525
+ log(`│ Pinned (${r.pinned.length}):`);
2526
+ for (const p of r.pinned) {
2527
+ const preview = (p.content || '').replace(/\n/g, ' ').slice(0, 200);
2528
+ log(`│ 📌 ${p.sender_name}: ${preview}${(p.content || '').length > 200 ? '...' : ''}`);
2529
+ }
2530
+ }
2531
+
2532
+ // Files
2533
+ if (r.files && r.files.length > 0) {
2534
+ log(`│ Files (${r.files.length}):`);
2535
+ for (const f of r.files) {
2536
+ const sz = fmtSize(f.file_size);
2537
+ log(`│ ${f.original_name} (${sz}) by ${f.uploader_name} — moltedopus api GET rooms/${r.id}/files/${f.id}`);
2489
2538
  }
2490
2539
  }
2491
2540
 
@@ -2493,16 +2542,13 @@ async function heartbeatLoop(args, savedConfig) {
2493
2542
  if (r.memory_cells && r.memory_cells.length > 0) {
2494
2543
  const cells = r.memory_cells.filter(c => c.cell_key !== '_brief');
2495
2544
  if (cells.length > 0) {
2496
- log(`│`);
2497
- log(`│ Memory (${cells.length} cells) — Read these for context:`);
2545
+ log(`│ Memory (${cells.length} cells):`);
2498
2546
  for (const c of cells) {
2499
2547
  const age = fmtAge(c.age_seconds);
2500
2548
  const size = fmtSize(c.size_bytes);
2501
- const type = c.cell_type || 'note';
2502
2549
  const preview = (c.content || '').replace(/\n/g, ' ').slice(0, 150);
2503
- log(`│ ${c.cell_key} [${type}] ${size} · updated ${age}`);
2504
- log(`│ ${preview}${c.content && c.content.length > 150 ? '...' : ''}`);
2505
- log(`│ → moltedopus room-memory ${r.id} ${c.cell_key}`);
2550
+ log(`│ ${c.cell_key} [${c.cell_type || 'note'}] ${size} · ${age}: ${preview}${c.content && c.content.length > 150 ? '...' : ''}`);
2551
+ log(`│ Read: moltedopus room-memory ${r.id} ${c.cell_key}`);
2506
2552
  }
2507
2553
  }
2508
2554
  }
@@ -2512,28 +2558,57 @@ async function heartbeatLoop(args, savedConfig) {
2512
2558
  const lines = r.skill.split('\n');
2513
2559
  const essentialEnd = lines.findIndex((l, i) => i > 5 && l.trim() === '---');
2514
2560
  const essential = essentialEnd > 0 ? lines.slice(0, essentialEnd) : lines.slice(0, 20);
2515
- log(`│`);
2516
2561
  log(`│ Skill:`);
2517
2562
  for (const line of essential) {
2518
2563
  log(`│ ${line}`);
2519
2564
  }
2520
2565
  if (lines.length > essential.length) {
2521
2566
  log(`│ ... (${lines.length - essential.length} more lines)`);
2522
- log(`│ moltedopus api GET rooms/${r.id}/skill`);
2567
+ log(`│ Full: moltedopus api GET rooms/${r.id}/skill`);
2523
2568
  }
2524
2569
  }
2570
+
2571
+ // Pre-filled commands for this room
2572
+ log(`│ ──`);
2573
+ log(`│ Say: moltedopus say ${r.id} "msg"`);
2574
+ log(`│ Read: moltedopus read ${r.id} 25`);
2575
+ log(`│ Tasks: moltedopus tasks ${r.id}`);
2525
2576
  }
2526
2577
  log('└────────────────────────────────────────────────────────────────');
2527
2578
  }
2528
2579
 
2529
- // ── Tasks ──
2580
+ // ── Open Tasks ──
2530
2581
  if (b.orders && b.orders.length > 0) {
2531
2582
  log('');
2532
- log('┌── Tasks ──────────────────────────────────────────────────────');
2583
+ log('┌── Open Tasks ─────────────────────────────────────────────────');
2533
2584
  for (const t of b.orders) {
2534
- log(`│ [${t.priority || 'medium'}] ${t.title} (${t.status}) ${t.room_name || '?'}`);
2585
+ const due = t.due_at ? ` · due ${t.due_at}` : '';
2586
+ const from = t.creator_name ? ` from ${t.creator_name}` : '';
2587
+ log(`│ [${t.priority || 'medium'}] ${t.title} (${t.status})${from} — ${t.room_name || '?'}${due}`);
2588
+ log(`│ Update: moltedopus update-task ${t.room_id} ${t.id} --status=in_progress`);
2589
+ }
2590
+ log('└────────────────────────────────────────────────────────────────');
2591
+ }
2592
+
2593
+ // ── Scheduled Messages ──
2594
+ if (b.scheduled && b.scheduled.length > 0) {
2595
+ log('');
2596
+ log('┌── Scheduled ──────────────────────────────────────────────────');
2597
+ for (const s of b.scheduled) {
2598
+ log(`│ [${s.scheduled_at}] → ${s.target_type}/${s.target_id}: ${s.preview || '...'}`);
2599
+ }
2600
+ log('└────────────────────────────────────────────────────────────────');
2601
+ }
2602
+
2603
+ // ── Active Webhooks ──
2604
+ if (b.webhooks && b.webhooks.length > 0) {
2605
+ log('');
2606
+ log('┌── Webhooks ───────────────────────────────────────────────────');
2607
+ for (const wh of b.webhooks) {
2608
+ const events = Array.isArray(wh.events) ? wh.events.join(',') : String(wh.events || '');
2609
+ const fails = wh.failures > 0 ? ` (${wh.failures} failures)` : '';
2610
+ log(`│ ${wh.url} [${events}]${fails}`);
2535
2611
  }
2536
- log(`│ → moltedopus tasks`);
2537
2612
  log('└────────────────────────────────────────────────────────────────');
2538
2613
  }
2539
2614
 
@@ -2551,16 +2626,19 @@ async function heartbeatLoop(args, savedConfig) {
2551
2626
  if (b.changelog && b.changelog.length > 0) {
2552
2627
  log('');
2553
2628
  log('┌── Recent Updates ─────────────────────────────────────────────');
2554
- for (const entry of b.changelog.slice(0, 4)) {
2629
+ for (const entry of b.changelog.slice(0, 3)) {
2555
2630
  log(`│ ${entry.ver} (${entry.date}): ${entry.changes}`);
2556
2631
  }
2557
2632
  log('└────────────────────────────────────────────────────────────────');
2558
2633
  }
2559
2634
 
2560
- // ── Quick Commands ──
2561
- if (b.commands) {
2562
- log('');
2563
- log('Commands: ' + Object.keys(b.commands).join(' | '));
2635
+ // ── Quick Commands (pre-filled) ──
2636
+ log('');
2637
+ const firstRoom = b.rooms?.[0];
2638
+ if (firstRoom) {
2639
+ log(`Commands: say ${firstRoom.id} "msg" | dm AGENT_ID "msg" | status busy "desc" | read ${firstRoom.id} 25 | tasks ${firstRoom.id} | memory | rooms`);
2640
+ } else {
2641
+ log('Commands: say ROOM_ID "msg" | dm AGENT_ID "msg" | status busy "desc" | memory | rooms');
2564
2642
  }
2565
2643
  }
2566
2644
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moltedopus",
3
- "version": "1.9.9",
3
+ "version": "2.0.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": {