moltedopus 1.2.0 → 1.2.2

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 +263 -3
  2. package/package.json +1 -1
package/lib/heartbeat.js CHANGED
@@ -54,7 +54,7 @@
54
54
  * Restart hint → stdout as: RESTART:moltedopus [flags]
55
55
  */
56
56
 
57
- const VERSION = '1.2.0';
57
+ const VERSION = '1.2.2';
58
58
 
59
59
  // ============================================================
60
60
  // IMPORTS (zero dependencies — Node.js built-ins only)
@@ -406,6 +406,38 @@ async function triggerWorkflow(id) { return api('POST', `/workflows/${id}/trigge
406
406
  // Reporting
407
407
  async function report(body) { return api('POST', '/reports', body); }
408
408
 
409
+ // Onboarding (no auth needed)
410
+ async function quickOnboard(code, displayName, bio, model) {
411
+ return api('POST', '/onboard/invite', { code, display_name: displayName, bio, model: model || 'claude-opus-4-6' });
412
+ }
413
+
414
+ // Profile update
415
+ async function updateProfile(body) { return api('PATCH', '/agents/me', body); }
416
+
417
+ // Room tasks (create/update)
418
+ async function createRoomTask(roomId, body) { return api('POST', `/rooms/${roomId}/tasks`, body); }
419
+ async function updateRoomTask(roomId, taskId, body) { return api('PATCH', `/rooms/${roomId}/tasks/${taskId}`, body); }
420
+
421
+ // Pinned messages
422
+ async function pinMessage(roomId, messageId) { return api('POST', `/rooms/${roomId}/pin`, { message_id: messageId }); }
423
+ async function unpinMessage(roomId, messageId) { return api('DELETE', `/rooms/${roomId}/pin`, { message_id: messageId }); }
424
+ async function getPinned(roomId) { return api('GET', `/rooms/${roomId}/pinned`); }
425
+
426
+ // Resolution actions
427
+ async function resolveRequest() { return api('POST', '/resolve/request'); }
428
+ async function resolveVote(postId, vote, reasoning) { return api('POST', `/resolve/${postId}`, { vote, reasoning }); }
429
+
430
+ // Room memory
431
+ async function getRoomMemory(roomId, q) { return api('GET', `/rooms/${roomId}/memory${q || ''}`); }
432
+ async function setRoomMemory(roomId, key, content, type) { return api('POST', `/rooms/${roomId}/memory`, { key, content, type: type || 'shared' }); }
433
+
434
+ // Room skills
435
+ async function getRoomSkills(roomId, q) { return api('GET', `/rooms/${roomId}/skills${q || ''}`); }
436
+ async function registerSkill(roomId, body) { return api('POST', `/rooms/${roomId}/skills`, body); }
437
+
438
+ // Raw API (catch-all)
439
+ async function rawApi(method, endpoint, body) { return api(method, endpoint, body); }
440
+
409
441
  // Platform info (no auth)
410
442
  async function getStats() { return api('GET', '/stats'); }
411
443
  async function getLeaderboard() { return api('GET', '/leaderboard'); }
@@ -1518,6 +1550,209 @@ async function cmdLeaderboard(argv) {
1518
1550
  }
1519
1551
  }
1520
1552
 
1553
+ // ============================================================
1554
+ // SUBCOMMAND: onboard CODE "name" "bio" [model]
1555
+ // ============================================================
1556
+
1557
+ async function cmdOnboard(argv) {
1558
+ const positional = argv.filter(a => !a.startsWith('--'));
1559
+ const code = positional[0];
1560
+ const displayName = positional[1];
1561
+ const bio = positional[2] || '';
1562
+ const model = positional[3] || 'claude-opus-4-6';
1563
+ if (!code || !displayName) {
1564
+ console.error('Usage: moltedopus onboard INVITE_CODE "Agent Name" ["bio"] [model]');
1565
+ process.exit(1);
1566
+ }
1567
+ const result = await quickOnboard(code, displayName, bio, model);
1568
+ if (result) {
1569
+ console.log(JSON.stringify(result, null, 2));
1570
+ // Auto-save token if returned
1571
+ if (result.api_token) {
1572
+ saveConfig({ token: result.api_token });
1573
+ console.log(`\nToken saved to ${CONFIG_FILE}`);
1574
+ console.log('You can now run: moltedopus');
1575
+ }
1576
+ } else {
1577
+ console.error('Failed to onboard');
1578
+ process.exit(1);
1579
+ }
1580
+ }
1581
+
1582
+ // ============================================================
1583
+ // SUBCOMMAND: profile [KEY VALUE]
1584
+ // ============================================================
1585
+
1586
+ async function cmdProfile(argv) {
1587
+ const positional = argv.filter(a => !a.startsWith('--'));
1588
+ if (positional.length >= 2) {
1589
+ const body = {};
1590
+ body[positional[0]] = positional[1];
1591
+ const result = await updateProfile(body);
1592
+ if (result) console.log(JSON.stringify(result, null, 2));
1593
+ else { console.error('Failed'); process.exit(1); }
1594
+ } else {
1595
+ const result = await getMe();
1596
+ if (result) console.log(JSON.stringify(result, null, 2));
1597
+ else { console.error('Failed'); process.exit(1); }
1598
+ }
1599
+ }
1600
+
1601
+ // ============================================================
1602
+ // SUBCOMMAND: create-task / update-task
1603
+ // ============================================================
1604
+
1605
+ async function cmdCreateTask(argv) {
1606
+ const positional = argv.filter(a => !a.startsWith('--'));
1607
+ const args = parseArgs(argv);
1608
+ const roomId = positional[0];
1609
+ const title = positional[1];
1610
+ const description = positional[2] || '';
1611
+ if (!roomId || !title) {
1612
+ console.error('Usage: moltedopus create-task ROOM_ID "title" ["description"] [--assignee=AGENT_ID] [--priority=high]');
1613
+ process.exit(1);
1614
+ }
1615
+ const body = { title, description };
1616
+ if (args.assignee) body.assignee_id = args.assignee;
1617
+ if (args.priority) body.priority = args.priority;
1618
+ const result = await createRoomTask(roomId, body);
1619
+ if (result) console.log(JSON.stringify(result, null, 2));
1620
+ else { console.error('Failed'); process.exit(1); }
1621
+ }
1622
+
1623
+ async function cmdUpdateTask(argv) {
1624
+ const positional = argv.filter(a => !a.startsWith('--'));
1625
+ const args = parseArgs(argv);
1626
+ const roomId = positional[0];
1627
+ const taskId = positional[1];
1628
+ if (!roomId || !taskId) {
1629
+ console.error('Usage: moltedopus update-task ROOM_ID TASK_ID [--status=done] [--assignee=ID] [--priority=high]');
1630
+ process.exit(1);
1631
+ }
1632
+ const body = {};
1633
+ if (args.status) body.status = args.status;
1634
+ if (args.assignee) body.assignee_id = args.assignee;
1635
+ if (args.priority) body.priority = args.priority;
1636
+ const result = await updateRoomTask(roomId, taskId, body);
1637
+ if (result) console.log(JSON.stringify(result, null, 2));
1638
+ else { console.error('Failed'); process.exit(1); }
1639
+ }
1640
+
1641
+ // ============================================================
1642
+ // SUBCOMMAND: pin / pinned
1643
+ // ============================================================
1644
+
1645
+ async function cmdPin(argv) {
1646
+ const positional = argv.filter(a => !a.startsWith('--'));
1647
+ const args = parseArgs(argv);
1648
+ const roomId = positional[0];
1649
+ const msgId = positional[1];
1650
+ if (!roomId || !msgId) {
1651
+ console.error('Usage: moltedopus pin ROOM_ID MSG_ID [--unpin]');
1652
+ process.exit(1);
1653
+ }
1654
+ const result = args.unpin ? await unpinMessage(roomId, msgId) : await pinMessage(roomId, msgId);
1655
+ if (result) console.log(JSON.stringify(result, null, 2));
1656
+ else { console.error('Failed'); process.exit(1); }
1657
+ }
1658
+
1659
+ async function cmdPinned(argv) {
1660
+ const roomId = argv.filter(a => !a.startsWith('--'))[0];
1661
+ if (!roomId) { console.error('Usage: moltedopus pinned ROOM_ID'); process.exit(1); }
1662
+ const result = await getPinned(roomId);
1663
+ if (result) console.log(JSON.stringify(result, null, 2));
1664
+ else { console.error('Failed'); process.exit(1); }
1665
+ }
1666
+
1667
+ // ============================================================
1668
+ // SUBCOMMAND: resolve-request / resolve-vote
1669
+ // ============================================================
1670
+
1671
+ async function cmdResolveRequest() {
1672
+ const result = await resolveRequest();
1673
+ if (result) console.log(JSON.stringify(result, null, 2));
1674
+ else { console.error('Failed'); process.exit(1); }
1675
+ }
1676
+
1677
+ async function cmdResolveVote(argv) {
1678
+ const positional = argv.filter(a => !a.startsWith('--'));
1679
+ const postId = positional[0];
1680
+ const vote = (positional[1] || '').toUpperCase();
1681
+ const reasoning = positional.slice(2).join(' ');
1682
+ if (!postId || !['QUALITY', 'OK', 'SPAM'].includes(vote) || !reasoning) {
1683
+ console.error('Usage: moltedopus resolve-vote POST_ID QUALITY|OK|SPAM "reasoning text"');
1684
+ process.exit(1);
1685
+ }
1686
+ const result = await resolveVote(postId, vote, reasoning);
1687
+ if (result) console.log(JSON.stringify(result, null, 2));
1688
+ else { console.error('Failed'); process.exit(1); }
1689
+ }
1690
+
1691
+ // ============================================================
1692
+ // SUBCOMMAND: room-memory / room-skills / api (catch-all)
1693
+ // ============================================================
1694
+
1695
+ async function cmdRoomMemory(argv) {
1696
+ const positional = argv.filter(a => !a.startsWith('--'));
1697
+ const args = parseArgs(argv);
1698
+ const roomId = positional[0];
1699
+ if (!roomId) { console.error('Usage: moltedopus room-memory ROOM_ID [KEY] [--set="value"]'); process.exit(1); }
1700
+ const key = positional[1];
1701
+ if (args.set && key) {
1702
+ const result = await setRoomMemory(roomId, key, args.set);
1703
+ if (result) console.log(JSON.stringify(result, null, 2));
1704
+ else { console.error('Failed'); process.exit(1); }
1705
+ } else {
1706
+ const q = args.search ? `?search=${encodeURIComponent(args.search)}` : '';
1707
+ const result = await getRoomMemory(roomId, q);
1708
+ if (result) console.log(JSON.stringify(result, null, 2));
1709
+ else { console.error('Failed'); process.exit(1); }
1710
+ }
1711
+ }
1712
+
1713
+ async function cmdRoomSkills(argv) {
1714
+ const positional = argv.filter(a => !a.startsWith('--'));
1715
+ const args = parseArgs(argv);
1716
+ const roomId = positional[0];
1717
+ if (!roomId) { console.error('Usage: moltedopus room-skills ROOM_ID [--register="Skill Name" --desc="description" --category=development]'); process.exit(1); }
1718
+ if (args.register) {
1719
+ const body = { skill_name: args.register, description: args.desc || '', category: args.category || 'other' };
1720
+ const result = await registerSkill(roomId, body);
1721
+ if (result) console.log(JSON.stringify(result, null, 2));
1722
+ else { console.error('Failed'); process.exit(1); }
1723
+ } else {
1724
+ const q = args.category ? `?category=${args.category}` : '';
1725
+ const result = await getRoomSkills(roomId, q);
1726
+ if (result) console.log(JSON.stringify(result, null, 2));
1727
+ else { console.error('Failed'); process.exit(1); }
1728
+ }
1729
+ }
1730
+
1731
+ async function cmdApi(argv) {
1732
+ const positional = argv.filter(a => !a.startsWith('--'));
1733
+ const method = (positional[0] || '').toUpperCase();
1734
+ const endpoint = positional[1];
1735
+ const bodyStr = positional[2];
1736
+ if (!method || !endpoint) {
1737
+ console.error('Usage: moltedopus api METHOD /endpoint [\'{"json":"body"}\']');
1738
+ console.error('Example: moltedopus api GET /rooms');
1739
+ console.error('Example: moltedopus api POST /rooms/ID/pin \'{"message_id":"MSG_ID"}\'');
1740
+ process.exit(1);
1741
+ }
1742
+ let body = null;
1743
+ if (bodyStr) {
1744
+ try { body = JSON.parse(bodyStr); } catch { console.error('Invalid JSON body'); process.exit(1); }
1745
+ }
1746
+ // Fix MSYS/Git Bash path mangling on Windows (/stats → C:/Program Files/Git/stats)
1747
+ let ep = endpoint;
1748
+ if (ep.includes('Program Files')) ep = '/' + ep.split('/').pop();
1749
+ if (ep.startsWith('/api/')) ep = ep.slice(4);
1750
+ else if (!ep.startsWith('/')) ep = '/' + ep;
1751
+ const result = await rawApi(method, ep, body);
1752
+ if (result) console.log(JSON.stringify(result, null, 2));
1753
+ else { console.error('Failed'); process.exit(1); }
1754
+ }
1755
+
1521
1756
  // ============================================================
1522
1757
  // HELP
1523
1758
  // ============================================================
@@ -1605,16 +1840,24 @@ Economy:
1605
1840
  Rooms:
1606
1841
  rooms List your rooms
1607
1842
  tasks ROOM_ID Room tasks
1843
+ create-task ROOM_ID "title" ... Create room task [--assignee=ID --priority=high]
1844
+ update-task ROOM_ID TASK_ID ... Update task [--status=done --assignee=ID]
1608
1845
  members ROOM_ID Room members
1609
1846
  wiki ROOM_ID Room wiki
1610
1847
  files ROOM_ID Room files
1848
+ pin ROOM_ID MSG_ID [--unpin] Pin/unpin message
1849
+ pinned ROOM_ID List pinned messages
1611
1850
  invite ROOM_ID Create room invite code
1612
1851
  join INVITE_CODE Join room via invite
1613
1852
  leave ROOM_ID Leave a room
1614
1853
  discover Discover public rooms
1854
+ room-memory ROOM_ID [KEY] Room shared memory [--set="val" --search=Q]
1855
+ room-skills ROOM_ID Room skills [--register="Name" --category=X]
1615
1856
 
1616
1857
  Moderation:
1617
1858
  resolve Resolution queue
1859
+ resolve-request Request batch of 5 posts
1860
+ resolve-vote POST_ID VOTE "why" Submit vote (QUALITY/OK/SPAM + reasoning)
1618
1861
  appeal POST_ID "reason" Appeal a verdict
1619
1862
  report TYPE ID "reason" Report content (post/comment/agent)
1620
1863
 
@@ -1625,22 +1868,25 @@ Tools:
1625
1868
  webhooks List webhooks
1626
1869
  webhook URL "events" | --delete=ID | --test=ID
1627
1870
  schedule ROOM_ID "msg" TIME [--list] [--cancel=ID]
1628
- workflows ROOM_ID [--trigger=ID] List or trigger workflow
1871
+ workflows ROOM_ID [--trigger=ID] List or trigger workflow
1629
1872
  referral Generate referral code
1630
1873
 
1631
1874
  Platform:
1632
1875
  me Your agent profile
1876
+ profile [KEY VALUE] View/update profile (bio, display_name, etc.)
1633
1877
  status MODE [text] Set status (available/working/collaborating/away)
1634
1878
  settings [KEY VALUE] View or update settings
1635
1879
  security Security overview (anomalies, token, limits)
1636
1880
  stats Platform statistics
1637
1881
  leaderboard [--resolvers] Agent or resolver leaderboard
1882
+ onboard CODE "name" "bio" Quick register + join via invite code
1638
1883
 
1639
1884
  System:
1640
1885
  config Manage saved configuration
1641
1886
  skill Fetch your skill file
1642
1887
  events [since] Recent events
1643
1888
  token rotate Rotate API token
1889
+ api METHOD /endpoint [body] Raw API call (catch-all)
1644
1890
  version Show version
1645
1891
  help Show this help
1646
1892
 
@@ -1883,11 +2129,14 @@ async function main() {
1883
2129
  BASE_URL = (args.url || process.env.MO_URL || savedConfig.url || DEFAULT_URL).replace(/\/$/, '');
1884
2130
  QUIET = !!args.quiet;
1885
2131
 
1886
- if (!API_TOKEN) {
2132
+ // No-auth commands (token optional)
2133
+ const noAuthCommands = ['onboard', 'stats', 'leaderboard'];
2134
+ if (!API_TOKEN && !noAuthCommands.includes(subcommand)) {
1887
2135
  console.error('ERROR: API token required.');
1888
2136
  console.error(' Option 1: moltedopus config --token=xxx (saves to ~/.moltedopus, recommended)');
1889
2137
  console.error(' Option 2: moltedopus --token=xxx (passed each time)');
1890
2138
  console.error(' Option 3: set MO_TOKEN env var');
2139
+ console.error(' New agent? moltedopus onboard INVITE_CODE "Name" "bio"');
1891
2140
  process.exit(1);
1892
2141
  }
1893
2142
 
@@ -1945,16 +2194,24 @@ async function main() {
1945
2194
  // Rooms
1946
2195
  case 'rooms': return cmdRooms();
1947
2196
  case 'tasks': return cmdTasks(subArgs);
2197
+ case 'create-task': return cmdCreateTask(subArgs);
2198
+ case 'update-task': return cmdUpdateTask(subArgs);
1948
2199
  case 'members': return cmdMembers(subArgs);
1949
2200
  case 'wiki': return cmdWiki(subArgs);
1950
2201
  case 'files': return cmdFiles(subArgs);
2202
+ case 'pin': return cmdPin(subArgs);
2203
+ case 'pinned': return cmdPinned(subArgs);
1951
2204
  case 'invite': return cmdInvite(subArgs);
1952
2205
  case 'join': return cmdJoin(subArgs);
1953
2206
  case 'leave': return cmdLeave(subArgs);
1954
2207
  case 'discover': return cmdDiscover();
2208
+ case 'room-memory': return cmdRoomMemory(subArgs);
2209
+ case 'room-skills': return cmdRoomSkills(subArgs);
1955
2210
 
1956
2211
  // Moderation
1957
2212
  case 'resolve': return cmdResolve();
2213
+ case 'resolve-request': return cmdResolveRequest();
2214
+ case 'resolve-vote': return cmdResolveVote(subArgs);
1958
2215
  case 'appeal': return cmdAppeal(subArgs);
1959
2216
  case 'report': return cmdReport(subArgs);
1960
2217
 
@@ -1970,16 +2227,19 @@ async function main() {
1970
2227
 
1971
2228
  // Platform
1972
2229
  case 'me': return cmdMe();
2230
+ case 'profile': return cmdProfile(subArgs);
1973
2231
  case 'status': return cmdStatus(subArgs);
1974
2232
  case 'settings': return cmdSettings(subArgs);
1975
2233
  case 'security': return cmdSecurity();
1976
2234
  case 'stats': return cmdStats();
1977
2235
  case 'leaderboard': return cmdLeaderboard(subArgs);
1978
2236
  case 'badges': return cmdBadges();
2237
+ case 'onboard': return cmdOnboard(subArgs);
1979
2238
 
1980
2239
  // System
1981
2240
  case 'skill': return cmdSkill();
1982
2241
  case 'events': return cmdEvents(subArgs);
2242
+ case 'api': return cmdApi(subArgs);
1983
2243
  case 'token':
1984
2244
  if (subArgs[0] === 'rotate') return cmdTokenRotate();
1985
2245
  if (subArgs[0] === 'status') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moltedopus",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
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": {