suparank 1.3.2 → 1.3.3

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/bin/suparank.js +94 -3
  2. package/package.json +1 -1
package/bin/suparank.js CHANGED
@@ -15,9 +15,74 @@ import * as fs from 'fs'
15
15
  import * as path from 'path'
16
16
  import * as os from 'os'
17
17
  import * as readline from 'readline'
18
- import { spawn } from 'child_process'
18
+ import { spawn, execSync } from 'child_process'
19
+ import { fileURLToPath } from 'url'
19
20
 
20
21
  const SUPARANK_DIR = path.join(os.homedir(), '.suparank')
22
+ const VERSION_CACHE_FILE = path.join(SUPARANK_DIR, '.version-check')
23
+
24
+ // Get current package version
25
+ function getCurrentVersion() {
26
+ try {
27
+ const packagePath = path.join(import.meta.dirname, '..', 'package.json')
28
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf-8'))
29
+ return pkg.version
30
+ } catch {
31
+ return null
32
+ }
33
+ }
34
+
35
+ // Check for updates (non-blocking, cached for 1 hour)
36
+ async function checkForUpdates() {
37
+ const currentVersion = getCurrentVersion()
38
+ if (!currentVersion) return
39
+
40
+ // Check cache to avoid spamming npm registry
41
+ try {
42
+ if (fs.existsSync(VERSION_CACHE_FILE)) {
43
+ const cache = JSON.parse(fs.readFileSync(VERSION_CACHE_FILE, 'utf-8'))
44
+ const cacheAge = Date.now() - cache.timestamp
45
+ if (cacheAge < 3600000) { // 1 hour cache
46
+ if (cache.latest !== currentVersion && cache.latest > currentVersion) {
47
+ console.error(`[suparank] Update available: ${currentVersion} → ${cache.latest}`)
48
+ }
49
+ return
50
+ }
51
+ }
52
+ } catch {}
53
+
54
+ // Fetch latest version from npm (with timeout)
55
+ try {
56
+ const controller = new AbortController()
57
+ const timeout = setTimeout(() => controller.abort(), 3000) // 3 second timeout
58
+
59
+ const response = await fetch('https://registry.npmjs.org/suparank/latest', {
60
+ signal: controller.signal
61
+ })
62
+ clearTimeout(timeout)
63
+
64
+ if (response.ok) {
65
+ const data = await response.json()
66
+ const latestVersion = data.version
67
+
68
+ // Cache the result
69
+ fs.mkdirSync(SUPARANK_DIR, { recursive: true })
70
+ fs.writeFileSync(VERSION_CACHE_FILE, JSON.stringify({
71
+ latest: latestVersion,
72
+ current: currentVersion,
73
+ timestamp: Date.now()
74
+ }))
75
+
76
+ if (latestVersion !== currentVersion && latestVersion > currentVersion) {
77
+ console.error(`[suparank] Update available: ${currentVersion} → ${latestVersion}`)
78
+ console.error('[suparank] Run: npx suparank@latest OR npx clear-npx-cache')
79
+ }
80
+ }
81
+ } catch {
82
+ // Silently fail - don't block MCP startup
83
+ }
84
+ }
85
+
21
86
  const CONFIG_FILE = path.join(SUPARANK_DIR, 'config.json')
22
87
  const CREDENTIALS_FILE = path.join(SUPARANK_DIR, 'credentials.json')
23
88
  const SESSION_FILE = path.join(SUPARANK_DIR, 'session.json')
@@ -35,7 +100,7 @@ const colors = {
35
100
  }
36
101
 
37
102
  // Check if running in MCP mode (no command argument = MCP server)
38
- const isMCPMode = !process.argv[2] || !['setup', 'test', 'session', 'clear', 'help', '--help', '-h'].includes(process.argv[2])
103
+ const isMCPMode = !process.argv[2] || !['setup', 'test', 'session', 'clear', 'update', 'version', '-v', '--version', 'help', '--help', '-h'].includes(process.argv[2])
39
104
 
40
105
  function log(message, color = 'reset') {
41
106
  // In MCP mode, use stderr to avoid breaking JSON protocol
@@ -344,7 +409,10 @@ function clearSession() {
344
409
  }
345
410
  }
346
411
 
347
- function runMCP() {
412
+ async function runMCP() {
413
+ // Check for updates in background (non-blocking)
414
+ checkForUpdates()
415
+
348
416
  const config = loadConfig()
349
417
 
350
418
  if (!config) {
@@ -412,6 +480,27 @@ switch (command) {
412
480
  case 'clear':
413
481
  clearSession()
414
482
  break
483
+ case 'update':
484
+ logHeader('Updating Suparank')
485
+ log('Clearing npx cache and fetching latest version...', 'yellow')
486
+ try {
487
+ execSync('rm -rf ~/.npm/_npx', { stdio: 'inherit' })
488
+ log('Cache cleared!', 'green')
489
+ log('Next run will use the latest version.', 'dim')
490
+ // Also clear version cache
491
+ if (fs.existsSync(VERSION_CACHE_FILE)) {
492
+ fs.unlinkSync(VERSION_CACHE_FILE)
493
+ }
494
+ } catch (e) {
495
+ log(`Update failed: ${e.message}`, 'red')
496
+ }
497
+ break
498
+ case 'version':
499
+ case '-v':
500
+ case '--version':
501
+ const ver = getCurrentVersion()
502
+ console.log(ver || 'unknown')
503
+ break
415
504
  case 'help':
416
505
  case '--help':
417
506
  case '-h':
@@ -424,6 +513,8 @@ switch (command) {
424
513
  log(' test Test API connection', 'dim')
425
514
  log(' session View current session state', 'dim')
426
515
  log(' clear Clear session state', 'dim')
516
+ log(' update Clear cache and update to latest', 'dim')
517
+ log(' version Show current version', 'dim')
427
518
  log(' help Show this help message', 'dim')
428
519
  break
429
520
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suparank",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "AI-powered SEO content creation MCP - generate and publish optimized blog posts with your AI assistant",
5
5
  "type": "module",
6
6
  "bin": {