local-mcp 3.0.226 → 3.0.228
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/download.js +1 -145
- package/index.js +1 -3
- package/package.json +1 -1
package/download.js
CHANGED
|
@@ -493,148 +493,4 @@ async function ensureSlackProxy() {
|
|
|
493
493
|
}
|
|
494
494
|
}
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
* Downloads local-mcp-helper on first install only.
|
|
498
|
-
* CRITICAL: never replaces an existing helper binary — the helper owns
|
|
499
|
-
* Calendar/Contacts/Reminders TCC grants via its cdhash. Replacing the
|
|
500
|
-
* binary silently resets those grants and users would have to re-authorize.
|
|
501
|
-
* @returns {Promise<string|null>} Path to the binary, or null if it fails
|
|
502
|
-
*/
|
|
503
|
-
async function ensureHelper() {
|
|
504
|
-
const binPath = path.join(CACHE_DIR, 'local-mcp-helper')
|
|
505
|
-
|
|
506
|
-
// Already installed — never replace. Stable cdhash = stable TCC grants.
|
|
507
|
-
if (fs.existsSync(binPath)) return binPath
|
|
508
|
-
|
|
509
|
-
const info = await getLatestBinary()
|
|
510
|
-
const version = info.version
|
|
511
|
-
const arch = process.arch === 'arm64' ? 'darwin-arm64' : 'darwin-x64'
|
|
512
|
-
const url = `https://download.local-mcp.com/local-mcp-helper-${version}-${arch}.tar.gz`
|
|
513
|
-
process.stderr.write(`\nDownloading local-mcp-helper v${version}...\n`)
|
|
514
|
-
|
|
515
|
-
fs.mkdirSync(CACHE_DIR, { recursive: true })
|
|
516
|
-
const tarPath = path.join(CACHE_DIR, `local-mcp-helper-${version}.tar.gz`)
|
|
517
|
-
|
|
518
|
-
try {
|
|
519
|
-
await downloadFile(url, tarPath)
|
|
520
|
-
const stat = fs.statSync(tarPath)
|
|
521
|
-
if (stat.size < 1000) { fs.unlinkSync(tarPath); throw new Error(`Incomplete download (${stat.size} bytes)`) }
|
|
522
|
-
|
|
523
|
-
extractTar(tarPath, CACHE_DIR)
|
|
524
|
-
fs.unlinkSync(tarPath)
|
|
525
|
-
|
|
526
|
-
if (!fs.existsSync(binPath)) throw new Error('local-mcp-helper not found after extraction')
|
|
527
|
-
fs.chmodSync(binPath, 0o755)
|
|
528
|
-
// Do NOT codesign: the pre-built binary's cdhash must remain exactly as
|
|
529
|
-
// distributed. Codesigning a fresh binary produces the same cdhash only
|
|
530
|
-
// when the content is identical, but we want the CI-signed cdhash to be
|
|
531
|
-
// the canonical identity used in TCC grants.
|
|
532
|
-
|
|
533
|
-
fs.writeFileSync(path.join(CACHE_DIR, '.helper-version'), version, 'utf8')
|
|
534
|
-
process.stderr.write(` local-mcp-helper installed at ${binPath}\n`)
|
|
535
|
-
return binPath
|
|
536
|
-
} catch (err) {
|
|
537
|
-
try { if (fs.existsSync(tarPath)) fs.unlinkSync(tarPath) } catch {}
|
|
538
|
-
process.stderr.write(` (local-mcp-helper not available: ${err.message})\n`)
|
|
539
|
-
return null
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
/**
|
|
544
|
-
* Downloads local-mcp-jxa-runner on first install only.
|
|
545
|
-
* CRITICAL: never replaces an existing jxa-runner binary — the runner owns
|
|
546
|
-
* Automation (JXA) TCC grants for Mail, Messages, Safari, etc. via its cdhash.
|
|
547
|
-
* Replacing the binary silently resets those grants and users would have to
|
|
548
|
-
* re-authorize in System Settings → Privacy & Security → Automation.
|
|
549
|
-
* @returns {Promise<string|null>} Path to the binary, or null if it fails
|
|
550
|
-
*/
|
|
551
|
-
async function ensureJXARunner() {
|
|
552
|
-
const binPath = path.join(CACHE_DIR, 'local-mcp-jxa-runner')
|
|
553
|
-
|
|
554
|
-
// Already installed — never replace. Stable cdhash = stable TCC grants.
|
|
555
|
-
if (fs.existsSync(binPath)) return binPath
|
|
556
|
-
|
|
557
|
-
const info = await getLatestBinary()
|
|
558
|
-
const version = info.version
|
|
559
|
-
const arch = process.arch === 'arm64' ? 'darwin-arm64' : 'darwin-x64'
|
|
560
|
-
const url = `https://download.local-mcp.com/local-mcp-jxa-runner-${version}-${arch}.tar.gz`
|
|
561
|
-
process.stderr.write(`\nDownloading local-mcp-jxa-runner v${version}...\n`)
|
|
562
|
-
|
|
563
|
-
fs.mkdirSync(CACHE_DIR, { recursive: true })
|
|
564
|
-
const tarPath = path.join(CACHE_DIR, `local-mcp-jxa-runner-${version}.tar.gz`)
|
|
565
|
-
|
|
566
|
-
try {
|
|
567
|
-
await downloadFile(url, tarPath)
|
|
568
|
-
const stat = fs.statSync(tarPath)
|
|
569
|
-
if (stat.size < 1000) { fs.unlinkSync(tarPath); throw new Error(`Incomplete download (${stat.size} bytes)`) }
|
|
570
|
-
|
|
571
|
-
extractTar(tarPath, CACHE_DIR)
|
|
572
|
-
fs.unlinkSync(tarPath)
|
|
573
|
-
|
|
574
|
-
if (!fs.existsSync(binPath)) throw new Error('local-mcp-jxa-runner not found after extraction')
|
|
575
|
-
fs.chmodSync(binPath, 0o755)
|
|
576
|
-
// Do NOT codesign: the pre-built binary's cdhash must remain exactly as
|
|
577
|
-
// distributed so the Automation TCC entry stays valid permanently.
|
|
578
|
-
|
|
579
|
-
fs.writeFileSync(path.join(CACHE_DIR, '.jxa-runner-version'), version, 'utf8')
|
|
580
|
-
process.stderr.write(` local-mcp-jxa-runner installed at ${binPath}\n`)
|
|
581
|
-
return binPath
|
|
582
|
-
} catch (err) {
|
|
583
|
-
try { if (fs.existsSync(tarPath)) fs.unlinkSync(tarPath) } catch {}
|
|
584
|
-
process.stderr.write(` (local-mcp-jxa-runner not available: ${err.message})\n`)
|
|
585
|
-
return null
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
async function _ensureTrayWindows() {
|
|
590
|
-
const info = await getLatestBinary()
|
|
591
|
-
const version = info.version
|
|
592
|
-
const binDir = path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'local-mcp', 'bin')
|
|
593
|
-
const trayPath = path.join(binDir, 'lmcp-tray.exe')
|
|
594
|
-
const verFile = path.join(binDir, '.tray-version')
|
|
595
|
-
|
|
596
|
-
if (fs.existsSync(trayPath) && fs.existsSync(verFile)) {
|
|
597
|
-
if (fs.readFileSync(verFile, 'utf8').trim() === version) return trayPath
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
const url = `https://download.local-mcp.com/lmcp-tray.exe?v=${version}`
|
|
601
|
-
process.stderr.write(`\nDescargando tray v${version}...\n`)
|
|
602
|
-
fs.mkdirSync(binDir, { recursive: true })
|
|
603
|
-
|
|
604
|
-
// Download to a temp file first — if the tray is running, the exe is locked
|
|
605
|
-
// and we can't write directly to it (EBUSY). Download first, then kill, then replace.
|
|
606
|
-
const tmpPath = trayPath + '.tmp'
|
|
607
|
-
try { if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath) } catch {}
|
|
608
|
-
await downloadFile(url, tmpPath)
|
|
609
|
-
|
|
610
|
-
// Kill the running tray (if any) before replacing the binary
|
|
611
|
-
try { execSync('taskkill /F /IM lmcp-tray.exe /T', { stdio: 'ignore' }) } catch {}
|
|
612
|
-
// Give Windows a moment to release the file handle
|
|
613
|
-
await new Promise(r => setTimeout(r, 500))
|
|
614
|
-
|
|
615
|
-
// Replace the old binary with the downloaded one
|
|
616
|
-
try { if (fs.existsSync(trayPath)) fs.unlinkSync(trayPath) } catch {}
|
|
617
|
-
fs.renameSync(tmpPath, trayPath)
|
|
618
|
-
|
|
619
|
-
const stat = fs.statSync(trayPath)
|
|
620
|
-
if (stat.size < 100000) {
|
|
621
|
-
try { fs.unlinkSync(trayPath) } catch {}
|
|
622
|
-
throw new Error(`Tray download incomplete (${stat.size} bytes)`)
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
fs.writeFileSync(verFile, version, 'utf8')
|
|
626
|
-
|
|
627
|
-
// Auto-start on login
|
|
628
|
-
const startupDir = path.join(process.env.APPDATA || '', 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup')
|
|
629
|
-
if (fs.existsSync(startupDir)) {
|
|
630
|
-
fs.writeFileSync(path.join(startupDir, 'LMCP Tray.cmd'), `@echo off\r\nstart "" "${trayPath}"`, 'ascii')
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// Launch tray now (use cmd start on Windows for proper detach)
|
|
634
|
-
try { execSync(`start "" "${trayPath}"`, { stdio: 'ignore', shell: true }) } catch {}
|
|
635
|
-
|
|
636
|
-
process.stderr.write(` Tray installed at ${trayPath}\n`)
|
|
637
|
-
return trayPath
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
module.exports = { ensureBinary, ensureRuntime, ensureTray, ensureTeamsProxy, ensureSlackProxy, ensureHelper, ensureJXARunner, CACHE_DIR, TRAY_DIR }
|
|
496
|
+
module.exports = { ensureBinary, ensureRuntime, ensureTray, ensureTeamsProxy, ensureSlackProxy, CACHE_DIR, TRAY_DIR }
|
package/index.js
CHANGED
|
@@ -154,12 +154,10 @@ async function main() {
|
|
|
154
154
|
|
|
155
155
|
async function ensureDarwinComponents() {
|
|
156
156
|
if (process.platform !== 'darwin') return
|
|
157
|
-
const { ensureTray, ensureTeamsProxy
|
|
157
|
+
const { ensureTray, ensureTeamsProxy } = require('./download')
|
|
158
158
|
await Promise.all([
|
|
159
159
|
ensureTray().catch((e) => { process.stderr.write(`[LMCP] Tray install failed: ${e.message}\n`) }),
|
|
160
160
|
ensureTeamsProxy().catch((e) => { process.stderr.write(`[LMCP] teams-proxy install failed: ${e.message}\n`) }),
|
|
161
|
-
ensureHelper().catch((e) => { process.stderr.write(`[LMCP] helper install failed: ${e.message}\n`) }),
|
|
162
|
-
ensureJXARunner().catch((e) => { process.stderr.write(`[LMCP] jxa-runner install failed: ${e.message}\n`) }),
|
|
163
161
|
])
|
|
164
162
|
}
|
|
165
163
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "local-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.228",
|
|
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": {
|