@geravant/sinain 1.6.3 → 1.6.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/launcher.js CHANGED
@@ -35,11 +35,13 @@ let skipSense = false;
35
35
  let skipOverlay = false;
36
36
  let skipAgent = false;
37
37
  let agentName = null;
38
+ let forceSetup = false;
38
39
 
39
40
  for (const arg of args) {
40
41
  if (arg === "--no-sense") { skipSense = true; continue; }
41
42
  if (arg === "--no-overlay") { skipOverlay = true; continue; }
42
43
  if (arg === "--no-agent") { skipAgent = true; continue; }
44
+ if (arg === "--setup") { forceSetup = true; continue; }
43
45
  if (arg.startsWith("--agent=")) { agentName = arg.split("=")[1]; continue; }
44
46
  console.error(`Unknown flag: ${arg}`);
45
47
  process.exit(1);
@@ -60,9 +62,9 @@ async function main() {
60
62
  await preflight();
61
63
  console.log();
62
64
 
63
- // Run setup wizard on first launch (no ~/.sinain/.env)
65
+ // Run setup wizard on first launch (no ~/.sinain/.env) or when --setup flag is passed
64
66
  const userEnvPath = path.join(SINAIN_DIR, ".env");
65
- if (!fs.existsSync(userEnvPath)) {
67
+ if (forceSetup || !fs.existsSync(userEnvPath)) {
66
68
  await setupWizard(userEnvPath);
67
69
  }
68
70
 
@@ -129,7 +131,7 @@ async function main() {
129
131
  try {
130
132
  const depCheck = IS_WINDOWS
131
133
  ? 'python3 -c "import PIL; import skimage"'
132
- : 'python3 -c "import PIL; import skimage; import Quartz"';
134
+ : 'python3 -c "import PIL; import skimage; import Quartz; import Vision"';
133
135
  execSync(depCheck, { stdio: "pipe" });
134
136
  } catch {
135
137
  log("Installing sense_client Python dependencies...");
@@ -374,9 +376,20 @@ async function setupWizard(envPath) {
374
376
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
375
377
  const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
376
378
 
379
+ // Load existing .env values as defaults (for re-configuration)
380
+ const existing = {};
381
+ if (fs.existsSync(envPath)) {
382
+ for (const line of fs.readFileSync(envPath, "utf-8").split("\n")) {
383
+ const m = line.match(/^([A-Z_]+)=(.*)$/);
384
+ if (m) existing[m[1]] = m[2];
385
+ }
386
+ }
387
+ const hasExisting = Object.keys(existing).length > 0;
388
+
377
389
  console.log();
378
- console.log(`${BOLD}── First-time setup ────────────────────${RESET}`);
390
+ console.log(`${BOLD}── ${hasExisting ? "Re-configure" : "First-time setup"} ────────────────────${RESET}`);
379
391
  console.log(` Configuring ${DIM}~/.sinain/.env${RESET}`);
392
+ if (hasExisting) console.log(` ${DIM}Press Enter to keep current values shown in [brackets]${RESET}`);
380
393
  console.log();
381
394
 
382
395
  const vars = {};
@@ -428,10 +441,13 @@ async function setupWizard(envPath) {
428
441
 
429
442
  // 2. OpenRouter API key (if cloud backend or for vision/OCR)
430
443
  if (transcriptionBackend === "openrouter") {
444
+ const existingKey = existing.OPENROUTER_API_KEY;
445
+ const keyHint = existingKey ? ` [${existingKey.slice(0, 8)}...${existingKey.slice(-4)}]` : "";
431
446
  let key = "";
432
447
  while (!key) {
433
- key = await ask(` OpenRouter API key (sk-or-...): `);
448
+ key = await ask(` OpenRouter API key (sk-or-...)${keyHint}: `);
434
449
  key = key.trim();
450
+ if (!key && existingKey) { key = existingKey; break; }
435
451
  if (key && !key.startsWith("sk-or-")) {
436
452
  console.log(` ${YELLOW}⚠${RESET} Key should start with sk-or-. Try again or press Enter to skip.`);
437
453
  const retry = await ask(` Use this key anyway? [y/N]: `);
@@ -445,13 +461,17 @@ async function setupWizard(envPath) {
445
461
  if (key) vars.OPENROUTER_API_KEY = key;
446
462
  } else {
447
463
  // Still ask for OpenRouter key (needed for vision/OCR)
448
- const key = await ask(` OpenRouter API key for vision/OCR (optional, Enter to skip): `);
464
+ const existingKey = existing.OPENROUTER_API_KEY;
465
+ const keyHint = existingKey ? ` [${existingKey.slice(0, 8)}...${existingKey.slice(-4)}]` : "";
466
+ const key = await ask(` OpenRouter API key for vision/OCR (optional, Enter to skip)${keyHint}: `);
449
467
  if (key.trim()) vars.OPENROUTER_API_KEY = key.trim();
468
+ else if (existingKey) vars.OPENROUTER_API_KEY = existingKey;
450
469
  }
451
470
 
452
471
  // 3. Agent selection
453
- const agentChoice = await ask(` Agent? [${BOLD}claude${RESET}/codex/goose/junie/aider]: `);
454
- vars.SINAIN_AGENT = agentChoice.trim().toLowerCase() || "claude";
472
+ const defaultAgent = existing.SINAIN_AGENT || "claude";
473
+ const agentChoice = await ask(` Agent? [${BOLD}${defaultAgent}${RESET}/claude/codex/goose/junie/aider]: `);
474
+ vars.SINAIN_AGENT = agentChoice.trim().toLowerCase() || defaultAgent;
455
475
 
456
476
  // 3b. Local vision (Ollama)
457
477
  const IS_MACOS = os.platform() === "darwin";
@@ -506,25 +526,37 @@ async function setupWizard(envPath) {
506
526
  console.log(` selective — score-based (errors, questions trigger it)`);
507
527
  console.log(` focus — always escalate every tick`);
508
528
  console.log(` rich — always escalate with maximum context`);
509
- const escMode = await ask(` Escalation mode? [off/${BOLD}selective${RESET}/focus/rich]: `);
510
- vars.ESCALATION_MODE = escMode.trim().toLowerCase() || "selective";
529
+ const defaultEsc = existing.ESCALATION_MODE || "selective";
530
+ const escMode = await ask(` Escalation mode? [off/${BOLD}${defaultEsc}${RESET}/selective/focus/rich]: `);
531
+ vars.ESCALATION_MODE = escMode.trim().toLowerCase() || defaultEsc;
511
532
 
512
533
  // 5. OpenClaw gateway
513
- const hasGateway = await ask(` Do you have an OpenClaw gateway? [y/N]: `);
514
- if (hasGateway.trim().toLowerCase() === "y") {
515
- const wsUrl = await ask(` Gateway WebSocket URL [ws://localhost:18789]: `);
516
- vars.OPENCLAW_WS_URL = wsUrl.trim() || "ws://localhost:18789";
517
-
518
- const wsToken = await ask(` Gateway auth token (48-char hex): `);
534
+ const hadGateway = !!(existing.OPENCLAW_WS_URL);
535
+ const gatewayDefault = hadGateway ? "Y" : "N";
536
+ const hasGateway = await ask(` Do you have an OpenClaw gateway? [${gatewayDefault === "Y" ? "Y/n" : "y/N"}]: `);
537
+ const wantsGateway = hasGateway.trim()
538
+ ? hasGateway.trim().toLowerCase() === "y"
539
+ : hadGateway;
540
+ if (wantsGateway) {
541
+ const defaultWs = existing.OPENCLAW_WS_URL || "ws://localhost:18789";
542
+ const wsUrl = await ask(` Gateway WebSocket URL [${defaultWs}]: `);
543
+ vars.OPENCLAW_WS_URL = wsUrl.trim() || defaultWs;
544
+
545
+ const existingToken = existing.OPENCLAW_WS_TOKEN;
546
+ const tokenHint = existingToken ? ` [${existingToken.slice(0, 6)}...${existingToken.slice(-4)}]` : "";
547
+ const wsToken = await ask(` Gateway auth token (48-char hex)${tokenHint}: `);
519
548
  if (wsToken.trim()) {
520
549
  vars.OPENCLAW_WS_TOKEN = wsToken.trim();
521
550
  vars.OPENCLAW_HTTP_TOKEN = wsToken.trim();
551
+ } else if (existingToken) {
552
+ vars.OPENCLAW_WS_TOKEN = existingToken;
553
+ vars.OPENCLAW_HTTP_TOKEN = existing.OPENCLAW_HTTP_TOKEN || existingToken;
522
554
  }
523
555
 
524
556
  // Derive HTTP URL from WS URL
525
557
  const httpBase = vars.OPENCLAW_WS_URL.replace(/^ws/, "http");
526
558
  vars.OPENCLAW_HTTP_URL = `${httpBase}/hooks/agent`;
527
- vars.OPENCLAW_SESSION_KEY = "agent:main:sinain";
559
+ vars.OPENCLAW_SESSION_KEY = existing.OPENCLAW_SESSION_KEY || "agent:main:sinain";
528
560
  } else {
529
561
  // No gateway — disable WS connection attempts
530
562
  vars.OPENCLAW_WS_URL = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geravant/sinain",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "description": "Ambient AI overlay invisible to screen capture — real-time insights from audio + screen context",
5
5
  "type": "module",
6
6
  "bin": {
@@ -4,6 +4,7 @@ numpy>=1.24
4
4
  pytesseract>=0.3
5
5
  requests>=2.31
6
6
  pyobjc-framework-Quartz>=10.0; sys_platform == "darwin"
7
+ pyobjc-framework-Vision>=10.0; sys_platform == "darwin"
7
8
  mss>=9.0; sys_platform == "win32"
8
9
  psutil>=5.9; sys_platform == "win32"
9
10
  winrt-Windows.Media.Ocr>=2.0; sys_platform == "win32"