local-mcp 3.0.167 → 3.0.169

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/package.json +1 -1
  2. package/setup.js +24 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-mcp",
3
- "version": "3.0.167",
3
+ "version": "3.0.169",
4
4
  "description": "LMCP — connect Claude Desktop, Cursor, Windsurf to Mail, Calendar, Contacts, Teams, OneDrive on macOS. Privacy-first: all data stays on your Mac.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/setup.js CHANGED
@@ -511,12 +511,17 @@ async function runSetup(opts = {}) {
511
511
  // (stdin is the pipe in that context; /dev/tty is always the real terminal).
512
512
  // Non-fatal: if /dev/tty is unavailable (CI, automated scripts) we skip.
513
513
  // ENXIO fix (LMCA-401): pre-test /dev/tty open on macOS/Linux. ENXIO means
514
- // no controlling terminal (launchd, SSH -T, background process). 11 machines
515
- // were logging prompt failures this avoids the noisy error path entirely.
516
- let _hasTty = _IS_WIN ? true : false
517
- if (!_IS_WIN) {
518
- try { const fd = fs.openSync('/dev/tty', 'r'); fs.closeSync(fd); _hasTty = true }
519
- catch { /* ENXIO or ENOENT — no terminal available */ }
514
+ // no controlling terminal (launchd, SSH -T, background process).
515
+ // LMCA-415: Windows also needs a TTY check (npm subprocess has no stdin.isTTY
516
+ // when launched from Go tray installer). Pre-test uses 'r+' (same flags as
517
+ // the actual open) to avoid a race where the pre-test passes but actual open fails.
518
+ let _hasTty = false
519
+ if (_IS_WIN) {
520
+ // Windows: check stdin.isTTY — false when spawned as a subprocess without console
521
+ _hasTty = process.stdin && process.stdin.isTTY === true
522
+ } else {
523
+ try { const fd = fs.openSync('/dev/tty', 'r+'); fs.closeSync(fd); _hasTty = true }
524
+ catch { /* ENXIO or ENOENT — no controlling terminal */ }
520
525
  }
521
526
  if (!email && !_hasTty) {
522
527
  _trackEmailPrompt('skipped_no_tty', '', '')
@@ -531,8 +536,15 @@ async function runSetup(opts = {}) {
531
536
  // Windows: use process.stdin directly (works in PowerShell and cmd)
532
537
  rl = require('readline').createInterface({ input: process.stdin, output: process.stderr })
533
538
  } else {
534
- // macOS/Linux: open /dev/tty to read from terminal even when stdin is piped
535
- ttyFd = fs.openSync('/dev/tty', 'r+')
539
+ // macOS/Linux: open /dev/tty to read from terminal even when stdin is piped.
540
+ // If this throws (ENXIO/ENOENT), treat as no-tty, not a failure.
541
+ try { ttyFd = fs.openSync('/dev/tty', 'r+') }
542
+ catch (ttyErr) {
543
+ _trackEmailPrompt('skipped_no_tty', '', '')
544
+ ttyFd = null
545
+ // Skip the rest of the prompt block
546
+ throw Object.assign(new Error('no_tty'), { _skipPrompt: true })
547
+ }
536
548
  const ttyIn = require('stream').Readable.from(
537
549
  (function* () {
538
550
  const buf = Buffer.alloc(256)
@@ -578,7 +590,10 @@ async function runSetup(opts = {}) {
578
590
  } else {
579
591
  emailPromptResult = 'skipped'
580
592
  }
581
- } catch (err) { emailPromptResult = 'failed'; emailPromptError = (err && err.message) || String(err) }
593
+ } catch (err) {
594
+ if (err && err._skipPrompt) { /* skipped_no_tty already tracked above */ }
595
+ else { emailPromptResult = 'failed'; emailPromptError = (err && err.message) || String(err) }
596
+ }
582
597
 
583
598
  // Track prompt outcome so we can measure conversion and diagnose failures
584
599
  _trackEmailPrompt(emailPromptResult, emailPromptResult === 'submitted' ? email : '', emailPromptError)