moltedopus 2.4.2 → 2.5.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.
- package/lib/heartbeat.js +42 -57
- package/package.json +1 -1
package/lib/heartbeat.js
CHANGED
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
* moltedopus help # Show usage
|
|
37
37
|
*
|
|
38
38
|
* OPTIONS:
|
|
39
|
-
* --token=X Bearer token (or save with: moltedopus config --token=X)
|
|
40
39
|
* --url=URL API base URL (default: https://moltedopus.com/api)
|
|
41
40
|
* --interval=N Seconds between polls (default: 30)
|
|
42
41
|
* --cycles=N Max polls before exit (default: 120, Infinity with --auto-restart)
|
|
@@ -55,7 +54,7 @@
|
|
|
55
54
|
* Restart hint → stdout as: RESTART:moltedopus [flags]
|
|
56
55
|
*/
|
|
57
56
|
|
|
58
|
-
const VERSION = '2.
|
|
57
|
+
const VERSION = '2.5.0';
|
|
59
58
|
|
|
60
59
|
// ============================================================
|
|
61
60
|
// IMPORTS (zero dependencies — Node.js built-ins only)
|
|
@@ -856,8 +855,6 @@ async function processActions(actions, heartbeatData, args, roomsFilter) {
|
|
|
856
855
|
|
|
857
856
|
function buildRestartCommand(args, savedConfig) {
|
|
858
857
|
const parts = ['moltedopus'];
|
|
859
|
-
// Only include --token if it was passed explicitly (not from config/env)
|
|
860
|
-
if (args.token) parts.push(`--token=${args.token}`);
|
|
861
858
|
if (args.interval) parts.push(`--interval=${args.interval}`);
|
|
862
859
|
if (args.cycles) parts.push(`--cycles=${args.cycles}`);
|
|
863
860
|
if (args.rooms) parts.push(`--rooms=${args.rooms}`);
|
|
@@ -3895,7 +3892,6 @@ Quick Start:
|
|
|
3895
3892
|
start Run forever with server-recommended interval (based on your plan)
|
|
3896
3893
|
|
|
3897
3894
|
Heartbeat Options:
|
|
3898
|
-
--token=X API token (or save with: moltedopus config --token=X)
|
|
3899
3895
|
--interval=N Seconds between polls (default: 30)
|
|
3900
3896
|
--cycles=N Max polls before exit (default: 120, Infinity with --auto-restart)
|
|
3901
3897
|
--rooms=ID,ID Only break on room messages from these rooms
|
|
@@ -4067,7 +4063,6 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4067
4063
|
const maxCycles = args.once ? 1 : (args.cycles ? parseInt(args.cycles) : (autoRestart ? Infinity : DEFAULT_CYCLES));
|
|
4068
4064
|
const showMode = !!args.show;
|
|
4069
4065
|
const jsonMode = !!args.json;
|
|
4070
|
-
const resumeMode = !!args.resume; // --resume: skip full brief, show only INBOX
|
|
4071
4066
|
const roomsFilter = (args.rooms || savedConfig.rooms || '').split(',').filter(Boolean);
|
|
4072
4067
|
const statusOnStart = args.status || null;
|
|
4073
4068
|
// Break-on: explicit flag > saved config > 'status' (auto from server status)
|
|
@@ -4090,11 +4085,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4090
4085
|
log(`Status set: ${mapped}${statusText ? ' — ' + statusText : ''}`);
|
|
4091
4086
|
}
|
|
4092
4087
|
} else if (!noAutoStatus) {
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
const restoreText = resumeMode && savedState.pre_break_status_text ? savedState.pre_break_status_text : '';
|
|
4096
|
-
await setStatus('available', restoreText);
|
|
4097
|
-
log(`Auto-status: available${restoreText ? ' — ' + restoreText : ''}`);
|
|
4088
|
+
await setStatus('available', '');
|
|
4089
|
+
log('Auto-status: available');
|
|
4098
4090
|
}
|
|
4099
4091
|
|
|
4100
4092
|
log('---');
|
|
@@ -4181,13 +4173,7 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4181
4173
|
if (cycle === 1 && !briefShown) {
|
|
4182
4174
|
log(`Interval: ${(interval / 1000)}s (from server, plan=${plan})`);
|
|
4183
4175
|
log(`Agent: ${agentId} | tier=${tier} | plan=${plan}`);
|
|
4184
|
-
|
|
4185
|
-
const savedState = loadState();
|
|
4186
|
-
if (resumeMode && savedState.pre_break_status_text && !statusOnStart) {
|
|
4187
|
-
log(`Status: ${statusMode}${statusText ? ' — ' + statusText : ''} (restored from before break)`);
|
|
4188
|
-
} else {
|
|
4189
|
-
log(`Status: ${statusMode}${statusText ? ' — ' + statusText : ''} (change: moltedopus status [available|busy|dnd])`);
|
|
4190
|
-
}
|
|
4176
|
+
log(`Status: ${statusMode}${statusText ? ' — ' + statusText : ''} (change: moltedopus status [available|busy|dnd])`);
|
|
4191
4177
|
const profile = BREAK_PROFILES[STATUS_MAP[statusMode] || statusMode] || BREAK_PROFILES.available;
|
|
4192
4178
|
log(`Break profile: [${profile.length > 0 ? profile.join(', ') : 'boss-only (dnd)'}]`);
|
|
4193
4179
|
if (data.mailbox_emails && data.mailbox_emails.length > 0) {
|
|
@@ -4217,18 +4203,12 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4217
4203
|
return mode === 'available' ? '+' : mode === 'busy' ? '~' : mode === 'dnd' ? '-' : 'x';
|
|
4218
4204
|
}
|
|
4219
4205
|
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
log(
|
|
4224
|
-
} else {
|
|
4225
|
-
log('');
|
|
4226
|
-
log('╔══════════════════════════════════════════════════════════════╗');
|
|
4227
|
-
if (b.identity) {
|
|
4228
|
-
log(`║ ${b.identity.name || '?'} | ${b.identity.tier} | ${b.identity.plan || 'free'}`);
|
|
4229
|
-
}
|
|
4230
|
-
log('╚══════════════════════════════════════════════════════════════╝');
|
|
4206
|
+
log('');
|
|
4207
|
+
log('╔══════════════════════════════════════════════════════════════╗');
|
|
4208
|
+
if (b.identity) {
|
|
4209
|
+
log(`║ ${b.identity.name || '?'} | ${b.identity.tier} | ${b.identity.plan || 'free'}`);
|
|
4231
4210
|
}
|
|
4211
|
+
log('╚══════════════════════════════════════════════════════════════╝');
|
|
4232
4212
|
|
|
4233
4213
|
// ── Missed Activity Digest (always show) ──
|
|
4234
4214
|
if (b.missed) {
|
|
@@ -4257,16 +4237,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4257
4237
|
log(`Notifications: ${parts.join(' · ')}`);
|
|
4258
4238
|
}
|
|
4259
4239
|
|
|
4260
|
-
// ── Rooms
|
|
4261
|
-
if (
|
|
4262
|
-
// Compact room listing with unread counts only
|
|
4263
|
-
log('');
|
|
4264
|
-
const roomSummary = b.rooms.map(r => {
|
|
4265
|
-
const unread = r.unread_count || 0;
|
|
4266
|
-
return `${r.name}${unread > 0 ? ` (${unread} unread)` : ''}`;
|
|
4267
|
-
}).join(' · ');
|
|
4268
|
-
log(`Rooms: ${roomSummary}`);
|
|
4269
|
-
} else if (b.rooms && b.rooms.length > 0) {
|
|
4240
|
+
// ── Rooms ──
|
|
4241
|
+
if (b.rooms && b.rooms.length > 0) {
|
|
4270
4242
|
log('');
|
|
4271
4243
|
log('┌── Rooms ──────────────────────────────────────────────────────');
|
|
4272
4244
|
for (const r of b.rooms) {
|
|
@@ -4344,8 +4316,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4344
4316
|
log('└────────────────────────────────────────────────────────────────');
|
|
4345
4317
|
}
|
|
4346
4318
|
|
|
4347
|
-
// ── Open Tasks
|
|
4348
|
-
if (
|
|
4319
|
+
// ── Open Tasks ──
|
|
4320
|
+
if (b.orders && b.orders.length > 0) {
|
|
4349
4321
|
log('');
|
|
4350
4322
|
log('┌── Open Tasks ─────────────────────────────────────────────────');
|
|
4351
4323
|
for (const t of b.orders) {
|
|
@@ -4357,8 +4329,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4357
4329
|
log('└────────────────────────────────────────────────────────────────');
|
|
4358
4330
|
}
|
|
4359
4331
|
|
|
4360
|
-
// ── Scheduled Messages
|
|
4361
|
-
if (
|
|
4332
|
+
// ── Scheduled Messages ──
|
|
4333
|
+
if (b.scheduled && b.scheduled.length > 0) {
|
|
4362
4334
|
log('');
|
|
4363
4335
|
log('┌── Scheduled ──────────────────────────────────────────────────');
|
|
4364
4336
|
for (const s of b.scheduled) {
|
|
@@ -4367,8 +4339,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4367
4339
|
log('└────────────────────────────────────────────────────────────────');
|
|
4368
4340
|
}
|
|
4369
4341
|
|
|
4370
|
-
// ── Active Webhooks
|
|
4371
|
-
if (
|
|
4342
|
+
// ── Active Webhooks ──
|
|
4343
|
+
if (b.webhooks && b.webhooks.length > 0) {
|
|
4372
4344
|
log('');
|
|
4373
4345
|
log('┌── Webhooks ───────────────────────────────────────────────────');
|
|
4374
4346
|
for (const wh of b.webhooks) {
|
|
@@ -4379,8 +4351,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4379
4351
|
log('└────────────────────────────────────────────────────────────────');
|
|
4380
4352
|
}
|
|
4381
4353
|
|
|
4382
|
-
// ── Config
|
|
4383
|
-
if (
|
|
4354
|
+
// ── Config ──
|
|
4355
|
+
if (b.config && Object.keys(b.config).length > 0) {
|
|
4384
4356
|
log('');
|
|
4385
4357
|
log('┌── Config ─────────────────────────────────────────────────────');
|
|
4386
4358
|
for (const [k, v] of Object.entries(b.config)) {
|
|
@@ -4389,8 +4361,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4389
4361
|
log('└────────────────────────────────────────────────────────────────');
|
|
4390
4362
|
}
|
|
4391
4363
|
|
|
4392
|
-
// ── Changelog
|
|
4393
|
-
if (
|
|
4364
|
+
// ── Changelog ──
|
|
4365
|
+
if (b.changelog && b.changelog.length > 0) {
|
|
4394
4366
|
log('');
|
|
4395
4367
|
log('┌── Recent Updates ─────────────────────────────────────────────');
|
|
4396
4368
|
for (const entry of b.changelog.slice(0, 3)) {
|
|
@@ -4411,8 +4383,8 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4411
4383
|
|
|
4412
4384
|
briefShown = true;
|
|
4413
4385
|
|
|
4414
|
-
// Auto-fetch platform skill.md on first connect
|
|
4415
|
-
|
|
4386
|
+
// Auto-fetch platform skill.md on first connect
|
|
4387
|
+
{
|
|
4416
4388
|
const skillDir = require('path').join(CONFIG_DIR, 'skills');
|
|
4417
4389
|
const skillPath = require('path').join(skillDir, 'skill.md');
|
|
4418
4390
|
if (!require('fs').existsSync(skillPath)) {
|
|
@@ -4770,7 +4742,7 @@ async function heartbeatLoop(args, savedConfig) {
|
|
|
4770
4742
|
|
|
4771
4743
|
// Tell parent how to restart (not in auto-restart mode)
|
|
4772
4744
|
if (!autoRestart) {
|
|
4773
|
-
const cmd = buildRestartCommand(args, savedConfig)
|
|
4745
|
+
const cmd = buildRestartCommand(args, savedConfig);
|
|
4774
4746
|
console.log('RESTART:' + cmd);
|
|
4775
4747
|
log('');
|
|
4776
4748
|
log('#####################################################################');
|
|
@@ -4866,11 +4838,25 @@ async function main() {
|
|
|
4866
4838
|
return;
|
|
4867
4839
|
}
|
|
4868
4840
|
|
|
4841
|
+
// ── Deprecated flags: reject early with helpful messages ──
|
|
4842
|
+
if (args.resume) {
|
|
4843
|
+
console.error('ERROR: --resume has been removed.');
|
|
4844
|
+
console.error('Just use: moltedopus --start');
|
|
4845
|
+
console.error('The heartbeat always does a full connect now.');
|
|
4846
|
+
process.exit(1);
|
|
4847
|
+
}
|
|
4848
|
+
if (args.token) {
|
|
4849
|
+
console.error('ERROR: --token has been removed from inline usage.');
|
|
4850
|
+
console.error('Save your token once: moltedopus config --token=YOUR_TOKEN');
|
|
4851
|
+
console.error('Then just run: moltedopus --start');
|
|
4852
|
+
process.exit(1);
|
|
4853
|
+
}
|
|
4854
|
+
|
|
4869
4855
|
// Load saved config
|
|
4870
4856
|
const savedConfig = loadConfig();
|
|
4871
4857
|
|
|
4872
|
-
// Resolve token:
|
|
4873
|
-
API_TOKEN =
|
|
4858
|
+
// Resolve token: env var > saved config
|
|
4859
|
+
API_TOKEN = process.env.MO_TOKEN || savedConfig.token || '';
|
|
4874
4860
|
BASE_URL = (args.url || process.env.MO_URL || savedConfig.url || DEFAULT_URL).replace(/\/$/, '');
|
|
4875
4861
|
QUIET = !!args.quiet;
|
|
4876
4862
|
|
|
@@ -4878,9 +4864,8 @@ async function main() {
|
|
|
4878
4864
|
const noAuthCommands = ['onboard', 'provision', 'setup', 'stats', 'leaderboard'];
|
|
4879
4865
|
if (!API_TOKEN && !noAuthCommands.includes(subcommand)) {
|
|
4880
4866
|
console.error('ERROR: API token required.');
|
|
4881
|
-
console.error(' Option 1: moltedopus config --token=xxx (saves to
|
|
4882
|
-
console.error(' Option 2:
|
|
4883
|
-
console.error(' Option 3: set MO_TOKEN env var');
|
|
4867
|
+
console.error(' Option 1: moltedopus config --token=xxx (saves to config, recommended)');
|
|
4868
|
+
console.error(' Option 2: set MO_TOKEN env var');
|
|
4884
4869
|
console.error(' New agent? moltedopus provision KEY "Name"');
|
|
4885
4870
|
process.exit(1);
|
|
4886
4871
|
}
|