lantern-connect 0.2.0 โ†’ 0.2.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.
@@ -1,91 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, readFileSync, writeFileSync } from 'fs'
4
- import { homedir, platform } from 'os'
5
- import { join } from 'path'
6
- import { execSync } from 'child_process'
7
-
8
- function expandHome(path) {
9
- if (path.startsWith('~')) {
10
- return join(homedir(), path.slice(1))
11
- }
12
- return path
13
- }
14
-
15
- function getClaudeDesktopConfigPath() {
16
- const os = platform()
17
- if (os === 'darwin') {
18
- return expandHome('~/Library/Application Support/Claude/claude_desktop_config.json')
19
- } else if (os === 'win32') {
20
- return join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json')
21
- } else {
22
- return expandHome('~/.config/Claude/claude_desktop_config.json')
23
- }
24
- }
25
-
26
- function removeFromJsonConfig(configPath, name) {
27
- if (!existsSync(configPath)) {
28
- return { found: false, reason: 'config file not found' }
29
- }
30
-
31
- try {
32
- const content = readFileSync(configPath, 'utf-8')
33
- const config = JSON.parse(content)
34
-
35
- if (!config.mcpServers || !config.mcpServers[name]) {
36
- return { found: false, reason: 'lantern not configured' }
37
- }
38
-
39
- delete config.mcpServers[name]
40
- writeFileSync(configPath, JSON.stringify(config, null, 2))
41
- return { found: true }
42
- } catch (err) {
43
- return { found: false, reason: err.message }
44
- }
45
- }
46
-
47
- function clearGeminiOAuthCache(serverName) {
48
- const cachePath = expandHome('~/.gemini/mcp-oauth-tokens.json')
49
- if (!existsSync(cachePath)) {
50
- return { cleared: false }
51
- }
52
-
53
- try {
54
- const content = readFileSync(cachePath, 'utf-8')
55
- const tokens = JSON.parse(content)
56
-
57
- if (!Array.isArray(tokens)) {
58
- return { cleared: false }
59
- }
60
-
61
- const filtered = tokens.filter(t => t.serverName !== serverName)
62
- if (filtered.length === tokens.length) {
63
- return { cleared: false }
64
- }
65
-
66
- writeFileSync(cachePath, JSON.stringify(filtered, null, 2))
67
- return { cleared: true }
68
- } catch (err) {
69
- return { cleared: false }
70
- }
71
- }
72
-
73
- function removeClaudeCode() {
74
- try {
75
- execSync('claude mcp remove lantern', { stdio: 'pipe' })
76
- return { found: true }
77
- } catch (err) {
78
- const stderr = err.stderr?.toString() || ''
79
- if (stderr.includes('not found') || stderr.includes('does not exist')) {
80
- return { found: false, reason: 'lantern not configured' }
81
- }
82
- // If claude CLI doesn't exist
83
- if (err.message.includes('ENOENT') || err.message.includes('not found')) {
84
- return { found: false, reason: 'claude CLI not installed' }
85
- }
86
- return { found: false, reason: err.message }
87
- }
88
- }
3
+ import {
4
+ expandHome,
5
+ getClaudeDesktopConfigPath,
6
+ removeFromJsonConfig,
7
+ clearGeminiOAuthCache,
8
+ removeClaudeCode,
9
+ } from '../src/reset.js'
89
10
 
90
11
  async function main() {
91
12
  console.log('')
@@ -100,11 +21,11 @@ async function main() {
100
21
  // Claude Desktop
101
22
  const claudeDesktopPath = getClaudeDesktopConfigPath()
102
23
  const claudeDesktopResult = removeFromJsonConfig(claudeDesktopPath, 'lantern')
103
- results.push({ name: 'Claude Desktop', ...claudeDesktopResult })
24
+ results.push({ name: 'Claude Desktop', ...claudeDesktopResult, reason: 'not configured' })
104
25
 
105
26
  // Claude Code
106
27
  const claudeCodeResult = removeClaudeCode()
107
- results.push({ name: 'Claude Code', ...claudeCodeResult })
28
+ results.push({ name: 'Claude Code', ...claudeCodeResult, reason: 'not configured' })
108
29
 
109
30
  // Gemini CLI
110
31
  const geminiPath = expandHome('~/.gemini/settings.json')
@@ -113,12 +34,12 @@ async function main() {
113
34
  if (geminiOAuthResult.cleared) {
114
35
  geminiResult.oauthCleared = true
115
36
  }
116
- results.push({ name: 'Gemini CLI', ...geminiResult })
37
+ results.push({ name: 'Gemini CLI', ...geminiResult, reason: 'not configured' })
117
38
 
118
39
  // Cursor
119
40
  const cursorPath = expandHome('~/.cursor/mcp.json')
120
41
  const cursorResult = removeFromJsonConfig(cursorPath, 'lantern')
121
- results.push({ name: 'Cursor', ...cursorResult })
42
+ results.push({ name: 'Cursor', ...cursorResult, reason: 'not configured' })
122
43
 
123
44
  // Print results
124
45
  let anyRemoved = false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lantern-connect",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "CLI installer to connect AI tools (Claude, Gemini, Cursor) to Lantern",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,8 +1,37 @@
1
1
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'
2
2
  import { dirname } from 'path'
3
+ import { execSync } from 'child_process'
3
4
  import { tools } from '../detect.js'
4
5
 
6
+ function checkNodeVersion() {
7
+ try {
8
+ const version = execSync('node -v', { encoding: 'utf-8' }).trim()
9
+ const major = parseInt(version.slice(1).split('.')[0], 10)
10
+
11
+ if (major < 20) {
12
+ const lines = [
13
+ `Node.js >= 20 required, but found ${version}`,
14
+ '',
15
+ 'Claude Desktop uses mcp-remote which requires Node.js 20+.',
16
+ '',
17
+ 'To fix:',
18
+ ' โ€ข If using nvm: nvm install 20 && nvm alias default 20',
19
+ ' โ€ข Or download from: https://nodejs.org',
20
+ '',
21
+ 'Then restart your terminal and run lantern-connect again.',
22
+ ]
23
+ throw new Error(lines.join('\n'))
24
+ }
25
+ } catch (err) {
26
+ if (err.message.includes('Node.js >= 20')) {
27
+ throw err
28
+ }
29
+ // If node command fails, let it proceed and fail later with a clearer error
30
+ }
31
+ }
32
+
5
33
  export function configureClaudeDesktop(mcpUrl) {
34
+ checkNodeVersion()
6
35
  const configPath = tools.claudeDesktop.configPath()
7
36
 
8
37
  // Ensure directory exists
package/src/index.js CHANGED
@@ -3,6 +3,7 @@ import { configureClaudeDesktop } from './configure/claude-desktop.js'
3
3
  import { configureClaudeCode } from './configure/claude-code.js'
4
4
  import { configureGeminiCli } from './configure/gemini-cli.js'
5
5
  import { configureCursor } from './configure/cursor.js'
6
+ import { resetAll } from './reset.js'
6
7
 
7
8
  const DEFAULT_MCP_URL = 'https://mcp.onlantern.com/mcp'
8
9
 
@@ -72,7 +73,12 @@ export async function main() {
72
73
  process.exit(1)
73
74
  }
74
75
 
75
- // Step 2: Configure each detected tool
76
+ // Step 2: Reset existing configs and OAuth caches
77
+ console.log(' ๐Ÿงน Cleaning up old configs...')
78
+ resetAll()
79
+ console.log('')
80
+
81
+ // Step 3: Configure each detected tool
76
82
  console.log(' ๐Ÿ“ Configuring...')
77
83
  console.log('')
78
84
 
@@ -97,7 +103,7 @@ export async function main() {
97
103
 
98
104
  console.log('')
99
105
 
100
- // Step 3: Summary
106
+ // Step 4: Summary
101
107
  if (configured.length > 0) {
102
108
  console.log(' ๐ŸŽ‰ Done!')
103
109
  console.log('')
package/src/reset.js ADDED
@@ -0,0 +1,123 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'fs'
2
+ import { homedir, platform } from 'os'
3
+ import { join } from 'path'
4
+ import { execSync } from 'child_process'
5
+
6
+ function expandHome(path) {
7
+ if (path.startsWith('~')) {
8
+ return join(homedir(), path.slice(1))
9
+ }
10
+ return path
11
+ }
12
+
13
+ function getClaudeDesktopConfigPath() {
14
+ const os = platform()
15
+ if (os === 'darwin') {
16
+ return expandHome('~/Library/Application Support/Claude/claude_desktop_config.json')
17
+ } else if (os === 'win32') {
18
+ return join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json')
19
+ } else {
20
+ return expandHome('~/.config/Claude/claude_desktop_config.json')
21
+ }
22
+ }
23
+
24
+ function removeFromJsonConfig(configPath, name) {
25
+ if (!existsSync(configPath)) {
26
+ return { found: false }
27
+ }
28
+
29
+ try {
30
+ const content = readFileSync(configPath, 'utf-8')
31
+ const config = JSON.parse(content)
32
+
33
+ if (!config.mcpServers || !config.mcpServers[name]) {
34
+ return { found: false }
35
+ }
36
+
37
+ delete config.mcpServers[name]
38
+ writeFileSync(configPath, JSON.stringify(config, null, 2))
39
+ return { found: true }
40
+ } catch (err) {
41
+ return { found: false }
42
+ }
43
+ }
44
+
45
+ function clearGeminiOAuthCache(serverName) {
46
+ const cachePath = expandHome('~/.gemini/mcp-oauth-tokens.json')
47
+ if (!existsSync(cachePath)) {
48
+ return { cleared: false }
49
+ }
50
+
51
+ try {
52
+ const content = readFileSync(cachePath, 'utf-8')
53
+ const tokens = JSON.parse(content)
54
+
55
+ if (!Array.isArray(tokens)) {
56
+ return { cleared: false }
57
+ }
58
+
59
+ const filtered = tokens.filter(t => t.serverName !== serverName)
60
+ if (filtered.length === tokens.length) {
61
+ return { cleared: false }
62
+ }
63
+
64
+ writeFileSync(cachePath, JSON.stringify(filtered, null, 2))
65
+ return { cleared: true }
66
+ } catch (err) {
67
+ return { cleared: false }
68
+ }
69
+ }
70
+
71
+ function removeClaudeCode() {
72
+ try {
73
+ execSync('claude mcp remove lantern', { stdio: 'pipe' })
74
+ return { found: true }
75
+ } catch (err) {
76
+ return { found: false }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Reset all Lantern configs and OAuth caches silently
82
+ * Returns true if anything was reset
83
+ */
84
+ export function resetAll() {
85
+ let anyReset = false
86
+
87
+ // Claude Desktop
88
+ const claudeDesktopPath = getClaudeDesktopConfigPath()
89
+ if (removeFromJsonConfig(claudeDesktopPath, 'lantern').found) {
90
+ anyReset = true
91
+ }
92
+
93
+ // Claude Code
94
+ if (removeClaudeCode().found) {
95
+ anyReset = true
96
+ }
97
+
98
+ // Gemini CLI
99
+ const geminiPath = expandHome('~/.gemini/settings.json')
100
+ if (removeFromJsonConfig(geminiPath, 'lantern').found) {
101
+ anyReset = true
102
+ }
103
+ if (clearGeminiOAuthCache('lantern').cleared) {
104
+ anyReset = true
105
+ }
106
+
107
+ // Cursor
108
+ const cursorPath = expandHome('~/.cursor/mcp.json')
109
+ if (removeFromJsonConfig(cursorPath, 'lantern').found) {
110
+ anyReset = true
111
+ }
112
+
113
+ return anyReset
114
+ }
115
+
116
+ // Export individual functions for lantern-reset CLI
117
+ export {
118
+ expandHome,
119
+ getClaudeDesktopConfigPath,
120
+ removeFromJsonConfig,
121
+ clearGeminiOAuthCache,
122
+ removeClaudeCode,
123
+ }