tandem-editor 0.1.1 → 0.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/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +3 -1
package/dist/cli/index.js
CHANGED
|
@@ -211,7 +211,9 @@ var init_start = __esm({
|
|
|
211
211
|
});
|
|
212
212
|
|
|
213
213
|
// src/cli/index.ts
|
|
214
|
-
|
|
214
|
+
import updateNotifier from "update-notifier";
|
|
215
|
+
var version = true ? "0.1.2" : "0.0.0-dev";
|
|
216
|
+
updateNotifier({ pkg: { name: "tandem-editor", version } }).notify();
|
|
215
217
|
var args = process.argv.slice(2);
|
|
216
218
|
if (args.includes("--help") || args.includes("-h")) {
|
|
217
219
|
console.log(`tandem v${version}
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/constants.ts","../../src/cli/setup.ts","../../src/cli/start.ts","../../src/cli/index.ts"],"sourcesContent":["export const DEFAULT_WS_PORT = 3478;\r\nexport const DEFAULT_MCP_PORT = 3479;\r\n\r\n/** File extensions the server accepts for opening. */\r\nexport const SUPPORTED_EXTENSIONS = new Set([\".md\", \".txt\", \".html\", \".htm\", \".docx\"]);\r\nexport const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB\r\nexport const MAX_WS_PAYLOAD = 10 * 1024 * 1024; // 10MB\r\nexport const MAX_WS_CONNECTIONS = 4;\r\nexport const IDLE_TIMEOUT = 30 * 60 * 1000; // 30 minutes\r\nexport const SESSION_MAX_AGE = 30 * 24 * 60 * 60 * 1000; // 30 days\r\nexport const TYPING_DEBOUNCE = 3000; // 3 seconds\r\nexport const DISCONNECT_DEBOUNCE_MS = 3000; // 3 seconds before showing \"server not reachable\"\r\nexport const PROLONGED_DISCONNECT_MS = 30_000; // 30 seconds before showing App-level disconnect banner\r\nexport const OVERLAY_STALE_DEBOUNCE = 200; // 200ms\r\nexport const REVIEW_BANNER_THRESHOLD = 5;\r\n\r\nexport const HIGHLIGHT_COLORS: Record<string, string> = {\r\n yellow: \"rgba(255, 235, 59, 0.3)\",\r\n red: \"rgba(244, 67, 54, 0.3)\",\r\n green: \"rgba(76, 175, 80, 0.3)\",\r\n blue: \"rgba(33, 150, 243, 0.3)\",\r\n purple: \"rgba(156, 39, 176, 0.3)\",\r\n};\r\n\r\nexport const INTERRUPTION_MODE_DEFAULT = \"all\" as const;\r\nexport const INTERRUPTION_MODE_KEY = \"tandem:interruptionMode\";\r\n\r\n// Large file thresholds\r\nexport const CHARS_PER_PAGE = 3_000;\r\nexport const LARGE_FILE_PAGE_THRESHOLD = 50;\r\nexport const VERY_LARGE_FILE_PAGE_THRESHOLD = 100;\r\n\r\nexport const CLAUDE_PRESENCE_COLOR = \"#6366f1\";\r\nexport const CLAUDE_FOCUS_OPACITY = 0.1;\r\n\r\nexport const CTRL_ROOM = \"__tandem_ctrl__\";\r\n\r\n/** Y.Map key constants — centralized to prevent silent bugs from string typos. */\r\nexport const Y_MAP_ANNOTATIONS = \"annotations\";\r\nexport const Y_MAP_AWARENESS = \"awareness\";\r\nexport const Y_MAP_USER_AWARENESS = \"userAwareness\";\r\nexport const Y_MAP_CHAT = \"chat\";\r\nexport const Y_MAP_DOCUMENT_META = \"documentMeta\";\r\nexport const Y_MAP_SAVED_AT_VERSION = \"savedAtVersion\";\r\n\r\nexport const SERVER_INFO_DIR = \".tandem\";\r\nexport const SERVER_INFO_FILE = \".tandem/.server-info\";\r\n\r\nexport const RECENT_FILES_KEY = \"tandem:recentFiles\";\r\nexport const RECENT_FILES_CAP = 20;\r\n\r\nexport const USER_NAME_KEY = \"tandem:userName\";\r\nexport const USER_NAME_DEFAULT = \"You\";\r\n\r\n// Toast notifications\r\nexport const TOAST_DISMISS_MS = { error: 8000, warning: 6000, info: 4000 } as const;\r\nexport const MAX_VISIBLE_TOASTS = 5;\r\nexport const NOTIFICATION_BUFFER_SIZE = 50;\r\n\r\n// Onboarding tutorial\r\nexport const TUTORIAL_COMPLETED_KEY = \"tandem:tutorialCompleted\";\r\nexport const TUTORIAL_ANNOTATION_PREFIX = \"tutorial-\";\r\n\r\n// Channel / event queue\r\nexport const CHANNEL_EVENT_BUFFER_SIZE = 200;\r\nexport const CHANNEL_EVENT_BUFFER_AGE_MS = 60_000; // 60 seconds\r\nexport const CHANNEL_SSE_KEEPALIVE_MS = 15_000; // 15 seconds\r\nexport const CHANNEL_MAX_RETRIES = 5;\r\nexport const CHANNEL_RETRY_DELAY_MS = 2_000;\r\n","import { readFileSync, existsSync } from \"node:fs\";\r\nimport { writeFile, rename, copyFile, unlink, mkdir } from \"node:fs/promises\";\r\nimport { homedir } from \"node:os\";\r\nimport { join, dirname, resolve } from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport { randomUUID } from \"node:crypto\";\r\nimport { DEFAULT_MCP_PORT } from \"../shared/constants.js\";\r\n\r\nconst __dirname = dirname(fileURLToPath(import.meta.url));\r\n\r\n// Absolute path to dist/channel/index.js (sibling of dist/cli/)\r\nconst CHANNEL_DIST = resolve(__dirname, \"../channel/index.js\");\r\n\r\nconst MCP_URL = `http://localhost:${DEFAULT_MCP_PORT}`;\r\n\r\nexport interface McpEntry {\r\n type?: \"http\";\r\n url?: string;\r\n command?: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n}\r\n\r\nexport interface McpEntries {\r\n tandem: McpEntry;\r\n \"tandem-channel\": McpEntry;\r\n}\r\n\r\nexport function buildMcpEntries(channelPath: string): McpEntries {\r\n return {\r\n tandem: {\r\n type: \"http\",\r\n url: `${MCP_URL}/mcp`,\r\n },\r\n \"tandem-channel\": {\r\n command: \"node\",\r\n args: [channelPath],\r\n env: { TANDEM_URL: MCP_URL },\r\n },\r\n };\r\n}\r\n\r\nexport interface DetectedTarget {\r\n label: string;\r\n configPath: string;\r\n}\r\n\r\ninterface DetectOptions {\r\n homeOverride?: string;\r\n force?: boolean;\r\n}\r\n\r\nexport function detectTargets(opts: DetectOptions = {}): DetectedTarget[] {\r\n const home = opts.homeOverride ?? homedir();\r\n const targets: DetectedTarget[] = [];\r\n\r\n // Claude Code — cross-platform.\r\n // Detect if the config file exists OR if ~/.claude directory exists\r\n // (Claude Code creates ~/.claude at install; mcp_settings.json may not exist yet).\r\n // With --force, always include regardless.\r\n const claudeCodeConfig = join(home, \".claude\", \"mcp_settings.json\");\r\n const claudeCodeDir = dirname(claudeCodeConfig);\r\n if (opts.force || existsSync(claudeCodeConfig) || existsSync(claudeCodeDir)) {\r\n targets.push({ label: \"Claude Code\", configPath: claudeCodeConfig });\r\n }\r\n\r\n // Claude Desktop — platform-specific.\r\n // Only detect if the config file already exists (user has launched Desktop at least once).\r\n // With --force, always include.\r\n let desktopConfig: string | null = null;\r\n if (process.platform === \"win32\") {\r\n const appdata = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\r\n desktopConfig = join(appdata, \"Claude\", \"claude_desktop_config.json\");\r\n } else if (process.platform === \"darwin\") {\r\n desktopConfig = join(\r\n home,\r\n \"Library\",\r\n \"Application Support\",\r\n \"Claude\",\r\n \"claude_desktop_config.json\",\r\n );\r\n } else {\r\n desktopConfig = join(home, \".config\", \"claude\", \"claude_desktop_config.json\");\r\n }\r\n\r\n if (desktopConfig && (opts.force || existsSync(desktopConfig))) {\r\n targets.push({ label: \"Claude Desktop\", configPath: desktopConfig });\r\n }\r\n\r\n return targets;\r\n}\r\n\r\n/**\r\n * Atomic write: write to a temp file in the SAME directory as the destination,\r\n * then rename. Using the same directory avoids EXDEV errors on Windows when\r\n * %TEMP% and %APPDATA% are on different drives.\r\n */\r\nasync function atomicWrite(content: string, dest: string): Promise<void> {\r\n const tmp = join(dirname(dest), `.tandem-setup-${randomUUID()}.json.tmp`);\r\n await writeFile(tmp, content, \"utf-8\");\r\n try {\r\n await rename(tmp, dest);\r\n } catch (err) {\r\n // EXDEV: cross-device link — fall back to copy + delete\r\n if ((err as NodeJS.ErrnoException).code === \"EXDEV\") {\r\n await copyFile(tmp, dest);\r\n await unlink(tmp);\r\n } else {\r\n await unlink(tmp).catch((cleanupErr: Error) => {\r\n console.error(` Warning: could not remove temp file ${tmp}: ${cleanupErr.message}`);\r\n });\r\n throw err;\r\n }\r\n }\r\n}\r\n\r\nexport async function applyConfig(configPath: string, entries: McpEntries): Promise<void> {\r\n // Read existing config or start fresh — no existsSync guard needed.\r\n // ENOENT and malformed JSON start fresh; other errors (permissions, disk) propagate.\r\n let existing: { mcpServers?: Record<string, McpEntry> } = {};\r\n try {\r\n existing = JSON.parse(readFileSync(configPath, \"utf-8\"));\r\n } catch (err) {\r\n const code = (err as NodeJS.ErrnoException).code;\r\n if (code === \"ENOENT\") {\r\n // File doesn't exist yet — start fresh\r\n } else if (err instanceof SyntaxError) {\r\n console.error(\r\n ` Warning: ${configPath} contains malformed JSON — replacing with fresh config`,\r\n );\r\n } else {\r\n throw err; // Permission errors, disk errors, etc. should not be silently swallowed\r\n }\r\n }\r\n\r\n const updated = {\r\n ...existing,\r\n mcpServers: {\r\n ...(existing.mcpServers ?? {}),\r\n ...entries,\r\n },\r\n };\r\n\r\n await mkdir(dirname(configPath), { recursive: true });\r\n await atomicWrite(JSON.stringify(updated, null, 2) + \"\\n\", configPath);\r\n}\r\n\r\n/** Run the setup command. Writes MCP config to all detected Claude installs. */\r\nexport async function runSetup(opts: { force?: boolean } = {}): Promise<void> {\r\n console.error(\"\\nTandem Setup\\n\");\r\n console.error(\"Detecting Claude installations...\");\r\n\r\n const targets = detectTargets({ force: opts.force });\r\n\r\n if (targets.length === 0) {\r\n console.error(\r\n \" No Claude installations detected.\\n\" +\r\n \" If Claude Code is installed, ensure ~/.claude exists.\\n\" +\r\n \" You can force configuration to default paths with: tandem setup --force\",\r\n );\r\n return;\r\n }\r\n\r\n for (const t of targets) {\r\n console.error(` Found: ${t.label} (${t.configPath})`);\r\n }\r\n\r\n console.error(\"\\nWriting MCP configuration...\");\r\n const entries = buildMcpEntries(CHANNEL_DIST);\r\n\r\n let failures = 0;\r\n for (const t of targets) {\r\n try {\r\n await applyConfig(t.configPath, entries);\r\n console.error(` \\x1b[32m✓\\x1b[0m ${t.label}`);\r\n } catch (err) {\r\n failures++;\r\n console.error(\r\n ` \\x1b[31m✗\\x1b[0m ${t.label}: ${err instanceof Error ? err.message : String(err)}`,\r\n );\r\n }\r\n }\r\n\r\n if (failures === targets.length) {\r\n console.error(\"\\nSetup failed — could not write any configuration. Check file permissions.\");\r\n process.exit(1);\r\n } else if (failures > 0) {\r\n console.error(\r\n `\\nSetup partially complete (${failures} target(s) failed). Start Tandem with: tandem`,\r\n );\r\n } else {\r\n console.error(\"\\nSetup complete! Start Tandem with: tandem\");\r\n console.error(\"Then in Claude, your tandem_* tools will be available.\\n\");\r\n }\r\n}\r\n","import { spawn } from \"node:child_process\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { dirname, resolve } from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\n\r\nconst __dirname = dirname(fileURLToPath(import.meta.url));\r\nconst SERVER_DIST = resolve(__dirname, \"../server/index.js\");\r\n\r\nexport function runStart(): void {\r\n if (!existsSync(SERVER_DIST)) {\r\n console.error(`[Tandem] Server not found at ${SERVER_DIST}`);\r\n console.error(\"[Tandem] The installation may be corrupted. Try: npm install -g tandem-editor\");\r\n process.exit(1);\r\n }\r\n\r\n console.error(\"[Tandem] Starting server...\");\r\n\r\n const proc = spawn(\"node\", [SERVER_DIST], {\r\n stdio: \"inherit\",\r\n env: { ...process.env, TANDEM_OPEN_BROWSER: \"1\" },\r\n });\r\n\r\n proc.on(\"error\", (err) => {\r\n console.error(`[Tandem] Failed to start server: ${err.message}`);\r\n process.exit(1);\r\n });\r\n\r\n proc.on(\"exit\", (code) => {\r\n process.exit(code ?? 0);\r\n });\r\n\r\n // Forward signals — proc.kill() with no argument uses SIGTERM on Unix\r\n // and TerminateProcess on Windows (correct cross-platform behavior).\r\n // On Windows SIGTERM is not emitted by the OS, but SIGINT (Ctrl+C) works.\r\n // Both are listed for Unix compatibility.\r\n for (const sig of [\"SIGINT\", \"SIGTERM\"] as const) {\r\n process.once(sig, () => proc.kill());\r\n }\r\n}\r\n","/**\r\n * Tandem CLI — entry point for the `tandem` global command.\r\n * Shebang is added by tsup banner at build time.\r\n *\r\n * Usage:\r\n * tandem Start the Tandem server and open the browser\r\n * tandem setup Register Tandem MCP tools with Claude Code / Claude Desktop\r\n * tandem setup --force Register even if no Claude install is auto-detected\r\n * tandem --help Show this help\r\n * tandem --version Show version\r\n */\r\n\r\n// Injected at build time by tsup define; declared here for TypeScript\r\ndeclare const __TANDEM_VERSION__: string;\r\nconst version = typeof __TANDEM_VERSION__ !== \"undefined\" ? __TANDEM_VERSION__ : \"0.0.0-dev\";\r\n\r\n// TypeScript needs a top-level export to treat this as a module (enabling top-level await)\r\nexport {};\r\n\r\nconst args = process.argv.slice(2);\r\n\r\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\r\n console.log(`tandem v${version}\r\n\r\nUsage:\r\n tandem Start Tandem server and open the browser\r\n tandem setup Register MCP tools with Claude Code / Claude Desktop\r\n tandem setup --force Register to default paths regardless of detection\r\n tandem --version\r\n tandem --help\r\n`);\r\n process.exit(0);\r\n}\r\n\r\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\r\n console.log(version);\r\n process.exit(0);\r\n}\r\n\r\ntry {\r\n if (args[0] === \"setup\") {\r\n const { runSetup } = await import(\"./setup.js\");\r\n await runSetup({ force: args.includes(\"--force\") });\r\n } else if (!args[0] || args[0] === \"start\") {\r\n const { runStart } = await import(\"./start.js\");\r\n runStart();\r\n } else {\r\n console.error(`Unknown command: ${args[0]}`);\r\n console.error(\"Run 'tandem --help' for usage.\");\r\n process.exit(1);\r\n }\r\n} catch (err) {\r\n console.error(`\\n[Tandem] Fatal error: ${err instanceof Error ? err.message : String(err)}`);\r\n console.error(\"If this persists, try reinstalling: npm install -g tandem-editor\\n\");\r\n process.exit(1);\r\n}\r\n"],"mappings":"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","names":["existsSync","dirname","resolve","fileURLToPath","__dirname","runSetup","runStart"]}
|
|
1
|
+
{"version":3,"sources":["../../src/shared/constants.ts","../../src/cli/setup.ts","../../src/cli/start.ts","../../src/cli/index.ts"],"sourcesContent":["export const DEFAULT_WS_PORT = 3478;\r\nexport const DEFAULT_MCP_PORT = 3479;\r\n\r\n/** File extensions the server accepts for opening. */\r\nexport const SUPPORTED_EXTENSIONS = new Set([\".md\", \".txt\", \".html\", \".htm\", \".docx\"]);\r\nexport const MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB\r\nexport const MAX_WS_PAYLOAD = 10 * 1024 * 1024; // 10MB\r\nexport const MAX_WS_CONNECTIONS = 4;\r\nexport const IDLE_TIMEOUT = 30 * 60 * 1000; // 30 minutes\r\nexport const SESSION_MAX_AGE = 30 * 24 * 60 * 60 * 1000; // 30 days\r\nexport const TYPING_DEBOUNCE = 3000; // 3 seconds\r\nexport const DISCONNECT_DEBOUNCE_MS = 3000; // 3 seconds before showing \"server not reachable\"\r\nexport const PROLONGED_DISCONNECT_MS = 30_000; // 30 seconds before showing App-level disconnect banner\r\nexport const OVERLAY_STALE_DEBOUNCE = 200; // 200ms\r\nexport const REVIEW_BANNER_THRESHOLD = 5;\r\n\r\nexport const HIGHLIGHT_COLORS: Record<string, string> = {\r\n yellow: \"rgba(255, 235, 59, 0.3)\",\r\n red: \"rgba(244, 67, 54, 0.3)\",\r\n green: \"rgba(76, 175, 80, 0.3)\",\r\n blue: \"rgba(33, 150, 243, 0.3)\",\r\n purple: \"rgba(156, 39, 176, 0.3)\",\r\n};\r\n\r\nexport const INTERRUPTION_MODE_DEFAULT = \"all\" as const;\r\nexport const INTERRUPTION_MODE_KEY = \"tandem:interruptionMode\";\r\n\r\n// Large file thresholds\r\nexport const CHARS_PER_PAGE = 3_000;\r\nexport const LARGE_FILE_PAGE_THRESHOLD = 50;\r\nexport const VERY_LARGE_FILE_PAGE_THRESHOLD = 100;\r\n\r\nexport const CLAUDE_PRESENCE_COLOR = \"#6366f1\";\r\nexport const CLAUDE_FOCUS_OPACITY = 0.1;\r\n\r\nexport const CTRL_ROOM = \"__tandem_ctrl__\";\r\n\r\n/** Y.Map key constants — centralized to prevent silent bugs from string typos. */\r\nexport const Y_MAP_ANNOTATIONS = \"annotations\";\r\nexport const Y_MAP_AWARENESS = \"awareness\";\r\nexport const Y_MAP_USER_AWARENESS = \"userAwareness\";\r\nexport const Y_MAP_CHAT = \"chat\";\r\nexport const Y_MAP_DOCUMENT_META = \"documentMeta\";\r\nexport const Y_MAP_SAVED_AT_VERSION = \"savedAtVersion\";\r\n\r\nexport const SERVER_INFO_DIR = \".tandem\";\r\nexport const SERVER_INFO_FILE = \".tandem/.server-info\";\r\n\r\nexport const RECENT_FILES_KEY = \"tandem:recentFiles\";\r\nexport const RECENT_FILES_CAP = 20;\r\n\r\nexport const USER_NAME_KEY = \"tandem:userName\";\r\nexport const USER_NAME_DEFAULT = \"You\";\r\n\r\n// Toast notifications\r\nexport const TOAST_DISMISS_MS = { error: 8000, warning: 6000, info: 4000 } as const;\r\nexport const MAX_VISIBLE_TOASTS = 5;\r\nexport const NOTIFICATION_BUFFER_SIZE = 50;\r\n\r\n// Onboarding tutorial\r\nexport const TUTORIAL_COMPLETED_KEY = \"tandem:tutorialCompleted\";\r\nexport const TUTORIAL_ANNOTATION_PREFIX = \"tutorial-\";\r\n\r\n// Channel / event queue\r\nexport const CHANNEL_EVENT_BUFFER_SIZE = 200;\r\nexport const CHANNEL_EVENT_BUFFER_AGE_MS = 60_000; // 60 seconds\r\nexport const CHANNEL_SSE_KEEPALIVE_MS = 15_000; // 15 seconds\r\nexport const CHANNEL_MAX_RETRIES = 5;\r\nexport const CHANNEL_RETRY_DELAY_MS = 2_000;\r\n","import { readFileSync, existsSync } from \"node:fs\";\r\nimport { writeFile, rename, copyFile, unlink, mkdir } from \"node:fs/promises\";\r\nimport { homedir } from \"node:os\";\r\nimport { join, dirname, resolve } from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport { randomUUID } from \"node:crypto\";\r\nimport { DEFAULT_MCP_PORT } from \"../shared/constants.js\";\r\n\r\nconst __dirname = dirname(fileURLToPath(import.meta.url));\r\n\r\n// Absolute path to dist/channel/index.js (sibling of dist/cli/)\r\nconst CHANNEL_DIST = resolve(__dirname, \"../channel/index.js\");\r\n\r\nconst MCP_URL = `http://localhost:${DEFAULT_MCP_PORT}`;\r\n\r\nexport interface McpEntry {\r\n type?: \"http\";\r\n url?: string;\r\n command?: string;\r\n args?: string[];\r\n env?: Record<string, string>;\r\n}\r\n\r\nexport interface McpEntries {\r\n tandem: McpEntry;\r\n \"tandem-channel\": McpEntry;\r\n}\r\n\r\nexport function buildMcpEntries(channelPath: string): McpEntries {\r\n return {\r\n tandem: {\r\n type: \"http\",\r\n url: `${MCP_URL}/mcp`,\r\n },\r\n \"tandem-channel\": {\r\n command: \"node\",\r\n args: [channelPath],\r\n env: { TANDEM_URL: MCP_URL },\r\n },\r\n };\r\n}\r\n\r\nexport interface DetectedTarget {\r\n label: string;\r\n configPath: string;\r\n}\r\n\r\ninterface DetectOptions {\r\n homeOverride?: string;\r\n force?: boolean;\r\n}\r\n\r\nexport function detectTargets(opts: DetectOptions = {}): DetectedTarget[] {\r\n const home = opts.homeOverride ?? homedir();\r\n const targets: DetectedTarget[] = [];\r\n\r\n // Claude Code — cross-platform.\r\n // Detect if the config file exists OR if ~/.claude directory exists\r\n // (Claude Code creates ~/.claude at install; mcp_settings.json may not exist yet).\r\n // With --force, always include regardless.\r\n const claudeCodeConfig = join(home, \".claude\", \"mcp_settings.json\");\r\n const claudeCodeDir = dirname(claudeCodeConfig);\r\n if (opts.force || existsSync(claudeCodeConfig) || existsSync(claudeCodeDir)) {\r\n targets.push({ label: \"Claude Code\", configPath: claudeCodeConfig });\r\n }\r\n\r\n // Claude Desktop — platform-specific.\r\n // Only detect if the config file already exists (user has launched Desktop at least once).\r\n // With --force, always include.\r\n let desktopConfig: string | null = null;\r\n if (process.platform === \"win32\") {\r\n const appdata = process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\r\n desktopConfig = join(appdata, \"Claude\", \"claude_desktop_config.json\");\r\n } else if (process.platform === \"darwin\") {\r\n desktopConfig = join(\r\n home,\r\n \"Library\",\r\n \"Application Support\",\r\n \"Claude\",\r\n \"claude_desktop_config.json\",\r\n );\r\n } else {\r\n desktopConfig = join(home, \".config\", \"claude\", \"claude_desktop_config.json\");\r\n }\r\n\r\n if (desktopConfig && (opts.force || existsSync(desktopConfig))) {\r\n targets.push({ label: \"Claude Desktop\", configPath: desktopConfig });\r\n }\r\n\r\n return targets;\r\n}\r\n\r\n/**\r\n * Atomic write: write to a temp file in the SAME directory as the destination,\r\n * then rename. Using the same directory avoids EXDEV errors on Windows when\r\n * %TEMP% and %APPDATA% are on different drives.\r\n */\r\nasync function atomicWrite(content: string, dest: string): Promise<void> {\r\n const tmp = join(dirname(dest), `.tandem-setup-${randomUUID()}.json.tmp`);\r\n await writeFile(tmp, content, \"utf-8\");\r\n try {\r\n await rename(tmp, dest);\r\n } catch (err) {\r\n // EXDEV: cross-device link — fall back to copy + delete\r\n if ((err as NodeJS.ErrnoException).code === \"EXDEV\") {\r\n await copyFile(tmp, dest);\r\n await unlink(tmp);\r\n } else {\r\n await unlink(tmp).catch((cleanupErr: Error) => {\r\n console.error(` Warning: could not remove temp file ${tmp}: ${cleanupErr.message}`);\r\n });\r\n throw err;\r\n }\r\n }\r\n}\r\n\r\nexport async function applyConfig(configPath: string, entries: McpEntries): Promise<void> {\r\n // Read existing config or start fresh — no existsSync guard needed.\r\n // ENOENT and malformed JSON start fresh; other errors (permissions, disk) propagate.\r\n let existing: { mcpServers?: Record<string, McpEntry> } = {};\r\n try {\r\n existing = JSON.parse(readFileSync(configPath, \"utf-8\"));\r\n } catch (err) {\r\n const code = (err as NodeJS.ErrnoException).code;\r\n if (code === \"ENOENT\") {\r\n // File doesn't exist yet — start fresh\r\n } else if (err instanceof SyntaxError) {\r\n console.error(\r\n ` Warning: ${configPath} contains malformed JSON — replacing with fresh config`,\r\n );\r\n } else {\r\n throw err; // Permission errors, disk errors, etc. should not be silently swallowed\r\n }\r\n }\r\n\r\n const updated = {\r\n ...existing,\r\n mcpServers: {\r\n ...(existing.mcpServers ?? {}),\r\n ...entries,\r\n },\r\n };\r\n\r\n await mkdir(dirname(configPath), { recursive: true });\r\n await atomicWrite(JSON.stringify(updated, null, 2) + \"\\n\", configPath);\r\n}\r\n\r\n/** Run the setup command. Writes MCP config to all detected Claude installs. */\r\nexport async function runSetup(opts: { force?: boolean } = {}): Promise<void> {\r\n console.error(\"\\nTandem Setup\\n\");\r\n console.error(\"Detecting Claude installations...\");\r\n\r\n const targets = detectTargets({ force: opts.force });\r\n\r\n if (targets.length === 0) {\r\n console.error(\r\n \" No Claude installations detected.\\n\" +\r\n \" If Claude Code is installed, ensure ~/.claude exists.\\n\" +\r\n \" You can force configuration to default paths with: tandem setup --force\",\r\n );\r\n return;\r\n }\r\n\r\n for (const t of targets) {\r\n console.error(` Found: ${t.label} (${t.configPath})`);\r\n }\r\n\r\n console.error(\"\\nWriting MCP configuration...\");\r\n const entries = buildMcpEntries(CHANNEL_DIST);\r\n\r\n let failures = 0;\r\n for (const t of targets) {\r\n try {\r\n await applyConfig(t.configPath, entries);\r\n console.error(` \\x1b[32m✓\\x1b[0m ${t.label}`);\r\n } catch (err) {\r\n failures++;\r\n console.error(\r\n ` \\x1b[31m✗\\x1b[0m ${t.label}: ${err instanceof Error ? err.message : String(err)}`,\r\n );\r\n }\r\n }\r\n\r\n if (failures === targets.length) {\r\n console.error(\"\\nSetup failed — could not write any configuration. Check file permissions.\");\r\n process.exit(1);\r\n } else if (failures > 0) {\r\n console.error(\r\n `\\nSetup partially complete (${failures} target(s) failed). Start Tandem with: tandem`,\r\n );\r\n } else {\r\n console.error(\"\\nSetup complete! Start Tandem with: tandem\");\r\n console.error(\"Then in Claude, your tandem_* tools will be available.\\n\");\r\n }\r\n}\r\n","import { spawn } from \"node:child_process\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { dirname, resolve } from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\n\r\nconst __dirname = dirname(fileURLToPath(import.meta.url));\r\nconst SERVER_DIST = resolve(__dirname, \"../server/index.js\");\r\n\r\nexport function runStart(): void {\r\n if (!existsSync(SERVER_DIST)) {\r\n console.error(`[Tandem] Server not found at ${SERVER_DIST}`);\r\n console.error(\"[Tandem] The installation may be corrupted. Try: npm install -g tandem-editor\");\r\n process.exit(1);\r\n }\r\n\r\n console.error(\"[Tandem] Starting server...\");\r\n\r\n const proc = spawn(\"node\", [SERVER_DIST], {\r\n stdio: \"inherit\",\r\n env: { ...process.env, TANDEM_OPEN_BROWSER: \"1\" },\r\n });\r\n\r\n proc.on(\"error\", (err) => {\r\n console.error(`[Tandem] Failed to start server: ${err.message}`);\r\n process.exit(1);\r\n });\r\n\r\n proc.on(\"exit\", (code) => {\r\n process.exit(code ?? 0);\r\n });\r\n\r\n // Forward signals — proc.kill() with no argument uses SIGTERM on Unix\r\n // and TerminateProcess on Windows (correct cross-platform behavior).\r\n // On Windows SIGTERM is not emitted by the OS, but SIGINT (Ctrl+C) works.\r\n // Both are listed for Unix compatibility.\r\n for (const sig of [\"SIGINT\", \"SIGTERM\"] as const) {\r\n process.once(sig, () => proc.kill());\r\n }\r\n}\r\n","/**\n * Tandem CLI — entry point for the `tandem` global command.\n * Shebang is added by tsup banner at build time.\n *\n * Usage:\n * tandem Start the Tandem server and open the browser\n * tandem setup Register Tandem MCP tools with Claude Code / Claude Desktop\n * tandem setup --force Register even if no Claude install is auto-detected\n * tandem --help Show this help\n * tandem --version Show version\n */\n\nimport updateNotifier from \"update-notifier\";\n\n// Injected at build time by tsup define; declared here for TypeScript\ndeclare const __TANDEM_VERSION__: string;\nconst version = typeof __TANDEM_VERSION__ !== \"undefined\" ? __TANDEM_VERSION__ : \"0.0.0-dev\";\n\n// Check for updates in background (non-blocking, throttled to once/day)\nupdateNotifier({ pkg: { name: \"tandem-editor\", version } }).notify();\n\nconst args = process.argv.slice(2);\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`tandem v${version}\n\nUsage:\n tandem Start Tandem server and open the browser\n tandem setup Register MCP tools with Claude Code / Claude Desktop\n tandem setup --force Register to default paths regardless of detection\n tandem --version\n tandem --help\n`);\n process.exit(0);\n}\n\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(version);\n process.exit(0);\n}\n\ntry {\n if (args[0] === \"setup\") {\n const { runSetup } = await import(\"./setup.js\");\n await runSetup({ force: args.includes(\"--force\") });\n } else if (!args[0] || args[0] === \"start\") {\n const { runStart } = await import(\"./start.js\");\n runStart();\n } else {\n console.error(`Unknown command: ${args[0]}`);\n console.error(\"Run 'tandem --help' for usage.\");\n process.exit(1);\n }\n} catch (err) {\n console.error(`\\n[Tandem] Fatal error: ${err instanceof Error ? err.message : String(err)}`);\n console.error(\"If this persists, try reinstalling: npm install -g tandem-editor\\n\");\n process.exit(1);\n}\n"],"mappings":"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","names":["existsSync","dirname","resolve","fileURLToPath","__dirname","runSetup","runStart"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tandem-editor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Collaborative AI-human document editor with MCP tool integration for Claude",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tandem",
|
|
@@ -91,6 +91,7 @@
|
|
|
91
91
|
"remark-parse": "^11.0.0",
|
|
92
92
|
"remark-stringify": "^11.0.0",
|
|
93
93
|
"unified": "^11.0.0",
|
|
94
|
+
"update-notifier": "^7.3.1",
|
|
94
95
|
"y-prosemirror": "^1.2.12",
|
|
95
96
|
"y-protocols": "^1.0.6",
|
|
96
97
|
"yjs": "^13.6.0",
|
|
@@ -102,6 +103,7 @@
|
|
|
102
103
|
"@types/node": "^25.5.0",
|
|
103
104
|
"@types/react": "^19.2.14",
|
|
104
105
|
"@types/react-dom": "^19.2.3",
|
|
106
|
+
"@types/update-notifier": "^6.0.8",
|
|
105
107
|
"@vitejs/plugin-react": "^4.3.0",
|
|
106
108
|
"concurrently": "^9.1.0",
|
|
107
109
|
"eslint": "^9.39.4",
|