linkgravity 1.7.4 → 1.7.5
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/bin/cli.js +111 -24
- package/package.json +1 -1
- package/src/cogs/voice_cog.py +1 -1
- package/src/main_slack.py +4 -1
package/bin/cli.js
CHANGED
|
@@ -342,7 +342,10 @@ function launchBlocker() {
|
|
|
342
342
|
return null;
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
|
|
345
|
+
// pm2 keys an app by name AND script path, so an install that moved (node version switch, npm prefix
|
|
346
|
+
// change, npm link) registers a second app under the same name instead of replacing the first, and
|
|
347
|
+
// every name-based pm2 command then acts on both at once.
|
|
348
|
+
function getPm2Procs() {
|
|
346
349
|
const jlist = spawnSync(process.execPath, [PM2_BIN, 'jlist'], { stdio: 'pipe' });
|
|
347
350
|
if (jlist.status !== 0) return null;
|
|
348
351
|
|
|
@@ -353,7 +356,7 @@ function getPm2Proc() {
|
|
|
353
356
|
if (out[i] !== '[') continue;
|
|
354
357
|
try {
|
|
355
358
|
const procs = JSON.parse(out.slice(i));
|
|
356
|
-
if (Array.isArray(procs)) return procs.
|
|
359
|
+
if (Array.isArray(procs)) return procs.filter((p) => p.name === LGY_PM2_NAME);
|
|
357
360
|
} catch (e) {}
|
|
358
361
|
}
|
|
359
362
|
|
|
@@ -363,6 +366,71 @@ function getPm2Proc() {
|
|
|
363
366
|
return null;
|
|
364
367
|
}
|
|
365
368
|
|
|
369
|
+
function isOurRegistration(proc) {
|
|
370
|
+
const registered = proc.pm2_env.pm_exec_path || '';
|
|
371
|
+
if (!isWin) return registered === LGY_SCRIPT_PATH;
|
|
372
|
+
return registered.toLowerCase() === LGY_SCRIPT_PATH.toLowerCase();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function printRegistrations(procs) {
|
|
376
|
+
for (const proc of procs) {
|
|
377
|
+
const mine = isOurRegistration(proc) ? ' <- this install' : '';
|
|
378
|
+
console.log(
|
|
379
|
+
` ${String(proc.pm2_env.status).padEnd(8)} ${proc.pm2_env.pm_exec_path}${mine}`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
let duplicatesReported = false;
|
|
385
|
+
function pickPm2Proc(procs) {
|
|
386
|
+
if (!procs || procs.length === 0) return null;
|
|
387
|
+
|
|
388
|
+
if (procs.length > 1 && !duplicatesReported) {
|
|
389
|
+
duplicatesReported = true;
|
|
390
|
+
console.log(
|
|
391
|
+
`\n${color.yellow}⚠${color.reset} pm2 has ${procs.length} apps registered as '${LGY_PM2_NAME}' - only this install's should be:`,
|
|
392
|
+
);
|
|
393
|
+
printRegistrations(procs);
|
|
394
|
+
console.log(
|
|
395
|
+
` Everything below reports on one of them. Run ${color.cyan}lgy start${color.reset} to drop the stale ones.\n`,
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const isOnline = (proc) => proc.pm2_env.status === 'online';
|
|
400
|
+
return (
|
|
401
|
+
procs.find((proc) => isOnline(proc) && isOurRegistration(proc)) ||
|
|
402
|
+
procs.find(isOnline) ||
|
|
403
|
+
procs.find(isOurRegistration) ||
|
|
404
|
+
procs[0]
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function getPm2Proc() {
|
|
409
|
+
return pickPm2Proc(getPm2Procs());
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function startDaemon() {
|
|
413
|
+
runPm2([
|
|
414
|
+
'start',
|
|
415
|
+
LGY_SCRIPT_PATH,
|
|
416
|
+
'--interpreter',
|
|
417
|
+
daemonPython,
|
|
418
|
+
'--name',
|
|
419
|
+
LGY_PM2_NAME,
|
|
420
|
+
'--update-env',
|
|
421
|
+
]);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// The saved autostart list keeps the removed paths until pm2 save runs, so a reboot restores them.
|
|
425
|
+
function clearRegistrations(procs) {
|
|
426
|
+
console.log(
|
|
427
|
+
`\n${color.yellow}⚠${color.reset} pm2 has ${procs.length} app(s) registered as '${LGY_PM2_NAME}', not all from this install:`,
|
|
428
|
+
);
|
|
429
|
+
printRegistrations(procs);
|
|
430
|
+
console.log(' Removing all of them and registering this install alone.\n');
|
|
431
|
+
runPm2(['delete', LGY_PM2_NAME]);
|
|
432
|
+
}
|
|
433
|
+
|
|
366
434
|
// Best-effort: pm2 has no API for "is this registered to start on boot", so this checks the OS directly and returns null (unknown) if that check itself isn't available.
|
|
367
435
|
function isAutostartEnabled() {
|
|
368
436
|
if (isWin) return null;
|
|
@@ -403,8 +471,11 @@ if (cmd === 'version' || cmd === '-v' || cmd === '--version') {
|
|
|
403
471
|
const pkg = require('../package.json');
|
|
404
472
|
console.log(`linkgravity v${pkg.version}`);
|
|
405
473
|
} else if (cmd === 'start') {
|
|
406
|
-
const
|
|
407
|
-
|
|
474
|
+
const registered = getPm2Procs() || [];
|
|
475
|
+
const stale = registered.filter((proc) => !isOurRegistration(proc));
|
|
476
|
+
const existing = registered.find(isOurRegistration);
|
|
477
|
+
|
|
478
|
+
if (!stale.length && existing && existing.pm2_env.status === 'online') {
|
|
408
479
|
console.log(
|
|
409
480
|
`\n${color.yellow}⚠${color.reset} LinkGravity is already running. ` +
|
|
410
481
|
`Use ${color.cyan}lgy restart${color.reset} to apply changes, or ${color.cyan}lgy stop${color.reset} first.\n`,
|
|
@@ -425,16 +496,11 @@ if (cmd === 'version' || cmd === '-v' || cmd === '--version') {
|
|
|
425
496
|
|
|
426
497
|
repairHookRegistration();
|
|
427
498
|
|
|
499
|
+
if (stale.length) clearRegistrations(registered);
|
|
500
|
+
|
|
428
501
|
info('Starting LinkGravity daemon...');
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
LGY_SCRIPT_PATH,
|
|
432
|
-
'--interpreter',
|
|
433
|
-
daemonPython,
|
|
434
|
-
'--name',
|
|
435
|
-
LGY_PM2_NAME,
|
|
436
|
-
'--update-env',
|
|
437
|
-
]);
|
|
502
|
+
startDaemon();
|
|
503
|
+
if (stale.length) runPm2(['save']);
|
|
438
504
|
verifyStartup().then((ok) => process.exit(ok ? 0 : 1));
|
|
439
505
|
} else if (cmd === 'stop') {
|
|
440
506
|
info('Stopping LinkGravity daemon...');
|
|
@@ -442,6 +508,18 @@ if (cmd === 'version' || cmd === '-v' || cmd === '--version') {
|
|
|
442
508
|
runPm2(['reset', LGY_PM2_NAME]);
|
|
443
509
|
success('Daemon stopped successfully.\n');
|
|
444
510
|
} else if (cmd === 'restart') {
|
|
511
|
+
const registered = getPm2Procs() || [];
|
|
512
|
+
if (registered.some((proc) => !isOurRegistration(proc))) {
|
|
513
|
+
console.log(
|
|
514
|
+
`\n${color.yellow}⚠${color.reset} pm2 has ${registered.length} app(s) registered as '${LGY_PM2_NAME}', and a restart would start every one of them:`,
|
|
515
|
+
);
|
|
516
|
+
printRegistrations(registered);
|
|
517
|
+
console.log(
|
|
518
|
+
` Run ${color.cyan}lgy start${color.reset} instead - it drops the stale ones first.\n`,
|
|
519
|
+
);
|
|
520
|
+
process.exit(1);
|
|
521
|
+
}
|
|
522
|
+
|
|
445
523
|
info('Restarting LinkGravity daemon...');
|
|
446
524
|
runPm2(['restart', LGY_PM2_NAME, '--update-env']);
|
|
447
525
|
runPm2(['reset', LGY_PM2_NAME]);
|
|
@@ -640,8 +718,10 @@ if (cmd === 'version' || cmd === '-v' || cmd === '--version') {
|
|
|
640
718
|
process.exit(0);
|
|
641
719
|
}
|
|
642
720
|
|
|
643
|
-
const
|
|
721
|
+
const registeredBeforeUpdate = getPm2Procs() || [];
|
|
722
|
+
const procBeforeUpdate = pickPm2Proc(registeredBeforeUpdate);
|
|
644
723
|
const wasOnline = !!procBeforeUpdate && procBeforeUpdate.pm2_env.status === 'online';
|
|
724
|
+
const hadStale = registeredBeforeUpdate.some((proc) => !isOurRegistration(proc));
|
|
645
725
|
|
|
646
726
|
info(`Updating: v${currentVersion} -> v${latestVersion}...`);
|
|
647
727
|
const installResult = runNpm(['install', '-g', 'linkgravity@latest'], { stdio: 'inherit' });
|
|
@@ -666,15 +746,20 @@ if (cmd === 'version' || cmd === '-v' || cmd === '--version') {
|
|
|
666
746
|
process.exit(0);
|
|
667
747
|
}
|
|
668
748
|
info("Daemon wasn't running - starting it fresh...");
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
'
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
749
|
+
startDaemon();
|
|
750
|
+
verifyStartup().then((ok) => process.exit(ok ? 0 : 1));
|
|
751
|
+
} else if (hadStale) {
|
|
752
|
+
clearRegistrations(registeredBeforeUpdate);
|
|
753
|
+
if (!wasOnline) {
|
|
754
|
+
runPm2(['save']);
|
|
755
|
+
success(
|
|
756
|
+
`Daemon was stopped - leaving it stopped. Run 'lgy start' when you're ready.\n`,
|
|
757
|
+
);
|
|
758
|
+
process.exit(0);
|
|
759
|
+
}
|
|
760
|
+
info('Starting the daemon from this install...');
|
|
761
|
+
startDaemon();
|
|
762
|
+
runPm2(['save']);
|
|
678
763
|
verifyStartup().then((ok) => process.exit(ok ? 0 : 1));
|
|
679
764
|
} else if (wasOnline) {
|
|
680
765
|
info('Restarting daemon to apply the update...');
|
|
@@ -753,7 +838,9 @@ if (cmd === 'version' || cmd === '-v' || cmd === '--version') {
|
|
|
753
838
|
spawnSync(process.argv[0], [process.argv[1], action], { stdio: 'inherit' });
|
|
754
839
|
})();
|
|
755
840
|
} else {
|
|
756
|
-
|
|
841
|
+
// Not stdout: an eval "$(lgy ...)" line in a shell rc would run this message as commands.
|
|
842
|
+
console.error(
|
|
757
843
|
`\n❌ Unknown command: ${cmd || 'none'}\n💡 Run 'lgy help' to see available commands.`,
|
|
758
844
|
);
|
|
845
|
+
process.exit(1);
|
|
759
846
|
}
|
package/package.json
CHANGED
package/src/cogs/voice_cog.py
CHANGED
|
@@ -583,7 +583,7 @@ class VoiceCog(commands.Cog):
|
|
|
583
583
|
wake_syllables = len(re.sub(r"[^\w가-힣]", "", matched_wake_word or ""))
|
|
584
584
|
min_prefix_similarity = 0.55 if wake_syllables <= 2 else 0.35
|
|
585
585
|
if is_waking_up and prefix_similarity is not None and prefix_similarity < min_prefix_similarity:
|
|
586
|
-
self.logger.
|
|
586
|
+
self.logger.debug(
|
|
587
587
|
f"STT: ignoring wake - '{text}' doesn't resemble '{matched_wake_word}' "
|
|
588
588
|
f"(prefix similarity {prefix_similarity:.2f}, needed {min_prefix_similarity:.2f})"
|
|
589
589
|
)
|
package/src/main_slack.py
CHANGED
|
@@ -258,7 +258,7 @@ async def run_slack(stop_event: asyncio.Event) -> None:
|
|
|
258
258
|
|
|
259
259
|
app, adapter = build_app()
|
|
260
260
|
try:
|
|
261
|
-
await adapter.resolve_bot_user_id()
|
|
261
|
+
bot_user_id = await adapter.resolve_bot_user_id()
|
|
262
262
|
except SlackApiError as e:
|
|
263
263
|
logger.critical(f"Slack auth_test failed - check slack_bot_token: {e}")
|
|
264
264
|
return
|
|
@@ -266,6 +266,9 @@ async def run_slack(stop_event: asyncio.Event) -> None:
|
|
|
266
266
|
handler = AsyncSocketModeHandler(app, SLACK_APP_TOKEN)
|
|
267
267
|
logger.info("✅ Slack bot starting (Socket Mode)...")
|
|
268
268
|
await handler.connect_async()
|
|
269
|
+
# cli.js's verifyStartup() waits for this exact sentence - without it a Slack-only install
|
|
270
|
+
# never reports a successful startup and every lgy start/restart/update times out.
|
|
271
|
+
logger.info(f"✅ Bot is fully online and ready! Logged in as {bot_user_id}")
|
|
269
272
|
platform_health.set_status("slack", "running")
|
|
270
273
|
try:
|
|
271
274
|
await stop_event.wait()
|