seo-intel 1.1.0 → 1.1.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.
package/README.md CHANGED
@@ -240,4 +240,4 @@ The OpenClaw agent provides:
240
240
 
241
241
  ---
242
242
 
243
- Built by [froggo.pro](https://froggo.pro) — local-first SEO intelligence.
243
+ Built by [ukkometa.fi](https://ukkometa.fi) — local-first SEO intelligence.
@@ -2,10 +2,26 @@
2
2
  cd "$(dirname "$0")" || cd ~
3
3
  clear
4
4
  echo ""
5
- echo " SEO Intel — Setup Wizard"
6
- echo " ========================"
5
+ echo " 🦀 SEO Intel — Setup Wizard"
6
+ echo " Opening in your browser..."
7
7
  echo ""
8
- npx seo-intel setup
8
+
9
+ # Start server in background if not already running
10
+ if ! curl -s http://localhost:3000/ > /dev/null 2>&1; then
11
+ npx seo-intel serve &
12
+ SERVER_PID=$!
13
+ sleep 2
14
+ fi
15
+
16
+ # Open setup wizard in browser
17
+ open "http://localhost:3000/setup" 2>/dev/null || xdg-open "http://localhost:3000/setup" 2>/dev/null
18
+
19
+ echo " Setup wizard is open at http://localhost:3000/setup"
20
+ echo " Keep this window open while using the wizard."
9
21
  echo ""
10
- echo " Setup complete. You can close this window."
11
- read -n 1 -s -r -p " Press any key to exit..."
22
+ read -n 1 -s -r -p " Press any key to stop the server and exit..."
23
+
24
+ # Clean up
25
+ if [ -n "$SERVER_PID" ]; then
26
+ kill $SERVER_PID 2>/dev/null
27
+ fi
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seo-intel",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Local Ahrefs-style SEO competitor intelligence. Crawl → SQLite → cloud analysis.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -261,6 +261,44 @@ function buildHtmlTemplate(data, opts = {}) {
261
261
  }
262
262
 
263
263
  /* ─── Header Bar ─────────────────────────────────────────────────────── */
264
+ .update-banner {
265
+ padding: 10px 20px;
266
+ border-radius: var(--radius);
267
+ display: flex;
268
+ align-items: center;
269
+ gap: 12px;
270
+ font-size: 0.78rem;
271
+ margin-bottom: 12px;
272
+ }
273
+ .update-banner.update-normal {
274
+ background: rgba(232,213,163,0.06);
275
+ border: 1px solid rgba(232,213,163,0.2);
276
+ color: var(--accent-gold);
277
+ }
278
+ .update-banner.update-security {
279
+ background: rgba(220,80,80,0.08);
280
+ border: 1px solid rgba(220,80,80,0.25);
281
+ color: #ff6b6b;
282
+ }
283
+ .update-banner .update-version { font-family: var(--font-mono); font-weight: 600; }
284
+ .update-banner .update-changelog { font-size: 0.68rem; color: var(--text-muted); flex:1; }
285
+ .update-banner .update-btn {
286
+ padding: 5px 14px;
287
+ border-radius: 6px;
288
+ font-size: 0.7rem;
289
+ font-weight: 600;
290
+ border: 1px solid currentColor;
291
+ background: transparent;
292
+ color: inherit;
293
+ cursor: pointer;
294
+ white-space: nowrap;
295
+ }
296
+ .update-banner .update-btn:hover { background: rgba(255,255,255,0.06); }
297
+ .update-banner .update-dismiss {
298
+ cursor: pointer; opacity: 0.5; font-size: 0.7rem;
299
+ }
300
+ .update-banner .update-dismiss:hover { opacity: 1; }
301
+
264
302
  .header-bar {
265
303
  background: var(--bg-card);
266
304
  border: 1px solid var(--border-card);
@@ -1795,6 +1833,8 @@ function buildHtmlTemplate(data, opts = {}) {
1795
1833
  // ── Panel HTML (project-specific body content) ──
1796
1834
  const panelHtml = `
1797
1835
  <div class="project-panel" data-project="${project}">
1836
+ <!-- UPDATE BANNER (populated by JS if update available) -->
1837
+ <div id="updateBanner${suffix}" style="display:none;"></div>
1798
1838
  <!-- HEADER BAR -->
1799
1839
  <div class="header-bar" id="header">
1800
1840
  <div class="header-left">
@@ -3405,6 +3445,27 @@ function buildHtmlTemplate(data, opts = {}) {
3405
3445
  bg: '#111111', grid: '#222222', text: '#b8b8b8', muted: '#555555'
3406
3446
  };
3407
3447
 
3448
+ // ═══ UPDATE CHECK ═══
3449
+ (function() {
3450
+ if (!window.location.protocol.startsWith('http')) return;
3451
+ fetch('/api/update-check').then(r => r.json()).then(function(info) {
3452
+ if (!info.hasUpdate) return;
3453
+ var banner = document.getElementById('updateBanner${suffix}');
3454
+ if (!banner) return;
3455
+ var cls = info.security ? 'update-security' : 'update-normal';
3456
+ var icon = info.security ? 'fa-shield-halved' : 'fa-arrow-up';
3457
+ var changelogHtml = info.changelog ? '<span class="update-changelog">' + info.changelog.split('\\n')[0] + '</span>' : '';
3458
+ banner.style.display = 'block';
3459
+ banner.innerHTML = '<div class="update-banner ' + cls + '">' +
3460
+ '<i class="fa-solid ' + icon + '"></i>' +
3461
+ '<span class="update-version">' + info.current + ' → ' + info.latest + '</span>' +
3462
+ changelogHtml +
3463
+ '<button class="update-btn" onclick="navigator.clipboard.writeText(\\'npm update -g seo-intel\\');this.textContent=\\'Copied!\\';setTimeout(()=>this.textContent=\\'Update\\',2000)">Update</button>' +
3464
+ '<span class="update-dismiss" onclick="this.closest(\\'.update-banner\\').style.display=\\'none\\'"><i class="fa-solid fa-xmark"></i></span>' +
3465
+ '</div>';
3466
+ }).catch(function() {});
3467
+ })();
3468
+
3408
3469
  // ═══ LIVE DASHBOARD CONTROLS ═══
3409
3470
  (function() {
3410
3471
  const isServed = window.location.protocol.startsWith('http');
package/server.js CHANGED
@@ -3,6 +3,7 @@ import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs';
3
3
  import { spawn } from 'child_process';
4
4
  import { dirname, join, extname } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
+ import { checkForUpdates, getUpdateInfo } from './lib/updater.js';
6
7
 
7
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
9
  const PORT = parseInt(process.env.PORT || '3000', 10);
@@ -325,6 +326,17 @@ async function handleRequest(req, res) {
325
326
 
326
327
 
327
328
  // ─── API: Stop running job ───
329
+ // ─── API: Update check ───
330
+ if (req.method === 'GET' && path === '/api/update-check') {
331
+ try {
332
+ const info = await getUpdateInfo();
333
+ json(res, 200, info);
334
+ } catch (e) {
335
+ json(res, 200, { hasUpdate: false, error: e.message });
336
+ }
337
+ return;
338
+ }
339
+
328
340
  if (req.method === 'POST' && path === '/api/stop') {
329
341
  try {
330
342
  const progress = readProgress();
@@ -604,6 +616,9 @@ const server = createServer((req, res) => {
604
616
  });
605
617
  });
606
618
 
619
+ // Start background update check
620
+ checkForUpdates();
621
+
607
622
  server.listen(PORT, '127.0.0.1', () => {
608
623
  console.log(`\n SEO Intel Dashboard Server`);
609
624
  console.log(` http://localhost:${PORT}\n`);
@@ -258,7 +258,7 @@ export async function cliAgentSetup(systemCheck) {
258
258
 
259
259
  const ask = (prompt) => new Promise(resolve => rl.question(prompt, resolve));
260
260
 
261
- console.log('\n \x1b[36m\x1b[1m🐸 SEO Intel — Agent-Powered Setup\x1b[0m\n');
261
+ console.log('\n \x1b[36m\x1b[1m🦀 SEO Intel — Agent-Powered Setup\x1b[0m\n');
262
262
  console.log(' \x1b[2mOpenClaw is guiding your setup. Type your answers, or "done" to finish.\x1b[0m\n');
263
263
 
264
264
  try {