🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

cordon-cli

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cordon-cli - npm Package Compare versions

Comparing version
0.1.12
to
0.1.13
+193
-16
dist/bin/cordon.js

@@ -58,8 +58,18 @@ #!/usr/bin/env node

// src/cli-state.ts
import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync, chmodSync, unlinkSync } from "fs";
import { join as join2 } from "path";
import { homedir as homedir2 } from "os";
function cordonDir() {
return join2(homedir2(), ".cordon");
}
function statePath() {
return join2(homedir2(), ".cordon", "state.json");
return join2(cordonDir(), "state.json");
}
function authPath() {
return join2(cordonDir(), "auth.json");
}
function ensureCordonDir() {
const dir = cordonDir();
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
}
function getState() {

@@ -75,20 +85,64 @@ const path = statePath();

function setState(patch) {
const path = statePath();
const dir = join2(homedir2(), ".cordon");
try {
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
ensureCordonDir();
const merged = { ...getState(), ...patch };
writeFileSync(path, JSON.stringify(merged, null, 2), "utf8");
writeFileSync(statePath(), JSON.stringify(merged, null, 2), "utf8");
} catch {
}
}
function getAuth() {
const path = authPath();
if (!existsSync2(path)) return null;
try {
return JSON.parse(readFileSync(path, "utf8"));
} catch {
return null;
}
}
function setAuth(auth) {
ensureCordonDir();
const path = authPath();
writeFileSync(path, JSON.stringify(auth, null, 2), "utf8");
if (process.platform !== "win32") {
try {
chmodSync(path, 384);
} catch {
}
}
}
function clearAuth() {
const path = authPath();
if (!existsSync2(path)) return false;
try {
unlinkSync(path);
return true;
} catch {
return false;
}
}
// src/commands/start.ts
var DASHBOARD_URL = "https://cordon-server-production.up.railway.app/dashboard/";
function applyAuthDefaults(config) {
const auth = getAuth();
if (!auth) return config;
const audit = config.audit;
const usesHosted = audit && (audit.output === "hosted" || Array.isArray(audit.output) && audit.output.includes("hosted"));
if (!usesHosted) return config;
if (audit.endpoint && audit.apiKey) return config;
return {
...config,
audit: {
...audit,
endpoint: audit.endpoint ?? auth.endpoint,
apiKey: audit.apiKey ?? auth.apiKey
}
};
}
async function startCommand(options) {
if (!getState().welcomed) {
if (!getState().welcomed && !getAuth()) {
process.stderr.write(
`
\x1B[36m[cordon] Want centralized audit logs + Slack approvals?\x1B[0m
[cordon] Register at ${DASHBOARD_URL}?utm_source=cli_start
[cordon] Run \`cordon login\` or register at ${DASHBOARD_URL}?utm_source=cli_start

@@ -124,2 +178,3 @@ `

}
config = applyAuthDefaults(config);
const gateway = new CordonGateway(config);

@@ -245,2 +300,11 @@ const shutdown = async () => {

// },`;
const auth = getAuth();
const auditBlock = auth ? `audit: {
enabled: true,
output: 'hosted',
// endpoint + apiKey are auto-loaded from ~/.cordon/auth.json (cordon login)
},` : `audit: {
enabled: true,
output: 'stdout',
},`;
const content = `import { defineConfig } from 'cordon-sdk';

@@ -253,6 +317,3 @@

audit: {
enabled: true,
output: 'stdout',
},
${auditBlock}

@@ -314,11 +375,121 @@ approvals: {

}
process.stderr.write(
`
if (auth) {
process.stderr.write(
`
\x1B[32m\u2713\x1B[0m audit logs will stream to your Cordon account (${auth.endpoint})
`
);
} else {
process.stderr.write(
`
\x1B[36mWant centralized audit logs + Slack approvals?\x1B[0m
Register a free account at ${DASHBOARD_URL2}?utm_source=cli_init
Run \x1B[36mcordon login\x1B[0m to register a free account, or sign up at ${DASHBOARD_URL2}?utm_source=cli_init
`
);
);
}
setState({ welcomed: true });
}
// src/commands/login.ts
import { createServer } from "http";
import { spawn } from "child_process";
import { randomBytes } from "crypto";
var DEFAULT_ENDPOINT = "https://cordon-server-production.up.railway.app";
var PORT_RANGE = [53247, 53249, 53251];
var TIMEOUT_MS = 5 * 60 * 1e3;
function openBrowser(url) {
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
const args = process.platform === "win32" ? ["/c", "start", '""', url] : [url];
try {
spawn(cmd, args, { detached: true, stdio: "ignore" }).unref();
} catch {
}
}
async function listenForCallback(port, expectedState) {
return new Promise((resolve, reject) => {
const server = createServer((req, res) => {
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
if (url.pathname !== "/cb") {
res.writeHead(404).end("not found");
return;
}
const token = url.searchParams.get("token") ?? "";
const state = url.searchParams.get("state") ?? "";
const signup = url.searchParams.get("signup") ?? "false";
if (state !== expectedState || !token) {
res.writeHead(400, { "Content-Type": "text/html" }).end("<html><body><h2>Login failed</h2><p>State mismatch or missing token. You can close this tab.</p></body></html>");
server.close();
reject(new Error("Callback state mismatch"));
return;
}
res.writeHead(200, { "Content-Type": "text/html" }).end('<html><body style="font-family:system-ui;padding:40px;"><h2>Logged in to Cordon</h2><p>You can close this tab and return to your terminal.</p></body></html>');
server.close();
resolve({ token, state, signup });
});
server.listen(port, "127.0.0.1");
server.on("error", (err) => reject(err));
setTimeout(() => {
server.close();
reject(new Error("Login timed out after 5 minutes"));
}, TIMEOUT_MS).unref();
});
}
async function loginCommand(options = {}) {
const endpoint = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
const state = randomBytes(16).toString("hex");
let port = null;
let result = null;
let lastErr = null;
for (const candidate of PORT_RANGE) {
try {
const callback = `http://localhost:${candidate}/cb`;
const authUrl = `${endpoint}/auth/cli/start?callback=${encodeURIComponent(callback)}&state=${state}`;
process.stderr.write(
`
[cordon] opening browser to log in...
[cordon] if it doesn't open, visit:
${authUrl}
`
);
openBrowser(authUrl);
const pending = listenForCallback(candidate, state);
port = candidate;
result = await pending;
break;
} catch (err) {
lastErr = err;
const code = err.code;
if (code === "EADDRINUSE") continue;
throw err;
}
}
if (!result) {
throw lastErr instanceof Error ? lastErr : new Error("Could not bind a local callback port");
}
setAuth({
endpoint,
apiKey: result.token,
loggedInAt: (/* @__PURE__ */ new Date()).toISOString()
});
process.stderr.write(`\x1B[32m\u2713\x1B[0m logged in. API key saved to ~/.cordon/auth.json
`);
if (result.signup === "true") {
process.stderr.write(`Welcome to Cordon. Run \x1B[36mcordon init\x1B[0m next to wire up your MCP servers.
`);
}
void port;
}
// src/commands/logout.ts
function logoutCommand() {
if (clearAuth()) {
process.stderr.write(`\x1B[32m\u2713\x1B[0m logged out. ~/.cordon/auth.json removed
`);
} else {
process.stderr.write(`[cordon] not logged in
`);
}
}
// src/bin/cordon.ts

@@ -329,3 +500,9 @@ var program = new Command();

program.command("init").description("Generate cordon.config.ts and patch Claude Desktop config").action(initCommand);
program.command("login").description("Log in to Cordon (browser OAuth) and save an API key locally").option("--endpoint <url>", "Cordon server endpoint (defaults to the hosted instance)").action((opts) => loginCommand(opts).catch((err) => {
process.stderr.write(`\x1B[31merror\x1B[0m: login failed: ${String(err)}
`);
process.exit(1);
}));
program.command("logout").description("Remove the local Cordon credentials").action(logoutCommand);
program.parse();
//# sourceMappingURL=cordon.js.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/bin/cordon.ts","../../src/commands/start.ts","../../src/config-loader.ts","../../src/cli-state.ts","../../src/commands/init.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { startCommand } from '../commands/start.js';\nimport { initCommand } from '../commands/init.js';\n\nconst program = new Command();\n\nprogram\n .name('cordon')\n .description('The security gateway for AI agents')\n .version('0.1.0');\n\nprogram\n .command('start')\n .description('Start the Cordon gateway')\n .option('-c, --config <path>', 'Path to cordon.config.ts')\n .action(startCommand);\n\nprogram\n .command('init')\n .description('Generate cordon.config.ts and patch Claude Desktop config')\n .action(initCommand);\n\nprogram.parse();\n","import { CordonGateway } from '@getcordon/core';\nimport type { ResolvedConfig } from 'cordon-sdk';\nimport { emptyConfig, findConfigPath, loadConfig } from '../config-loader.js';\nimport { getState, setState } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\ninterface StartOptions {\n config?: string;\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n if (!getState().welcomed) {\n process.stderr.write(\n `\\n\\x1b[36m[cordon] Want centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `[cordon] Register at ${DASHBOARD_URL}?utm_source=cli_start\\n\\n`,\n );\n setState({ welcomed: true });\n }\n\n // Default to an empty server list so auto-install probes (Glama, MCP\n // registry, fresh `npx -y cordon-cli start`) succeed instead of crashing.\n // Real users get a loud stderr warning so they don't silently run a no-op.\n let config: ResolvedConfig = emptyConfig();\n let configPath: string | null = null;\n\n try {\n configPath = await findConfigPath(options.config);\n } catch (err) {\n if (options.config) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n process.stderr.write(\n '\\x1b[33m[cordon] no cordon.config.ts found — starting with zero upstream servers.\\x1b[0m\\n' +\n '[cordon] Run `cordon init` to generate a config and connect real MCP servers.\\n',\n );\n }\n\n if (configPath) {\n process.stderr.write(`[cordon] loading config from ${configPath}\\n`);\n try {\n config = await loadConfig(configPath);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n }\n\n const gateway = new CordonGateway(config);\n\n const shutdown = async () => {\n process.stderr.write('\\n[cordon] shutting down...\\n');\n try {\n await gateway.stop();\n process.exit(0);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: shutdown failed: ${String(err)}\\n`);\n process.exit(1);\n }\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await gateway.start();\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: gateway failed: ${String(err)}\\n`);\n process.exit(1);\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { createJiti } from 'jiti';\nimport type { CordonConfig, ResolvedConfig } from 'cordon-sdk';\n\nconst SEARCH_PATHS = [\n () => join(process.cwd(), 'cordon.config.ts'),\n () => join(process.cwd(), 'cordon.config.js'),\n () => join(homedir(), '.cordon', 'config.ts'),\n () => join(homedir(), '.cordon', 'config.js'),\n];\n\nexport async function findConfigPath(explicit?: string): Promise<string> {\n if (explicit) {\n if (!existsSync(explicit)) {\n throw new Error(`Config file not found: ${explicit}`);\n }\n return explicit;\n }\n\n for (const candidate of SEARCH_PATHS) {\n const p = candidate();\n if (existsSync(p)) return p;\n }\n\n throw new Error(\n 'No cordon config found. Run `cordon init` to create one, or pass --config <path>.',\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<ResolvedConfig> {\n // jiti handles TypeScript config files without requiring a separate compile step\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import(configPath);\n\n const raw = (mod as { default?: CordonConfig }).default ?? (mod as CordonConfig);\n\n if (!raw || typeof raw !== 'object' || !Array.isArray(raw.servers)) {\n throw new Error(\n `Invalid config at ${configPath}: expected an object with a 'servers' array. ` +\n `Make sure you are using \\`export default defineConfig({...})\\`.`,\n );\n }\n\n return applyDefaults(raw as CordonConfig);\n}\n\nfunction applyDefaults(config: CordonConfig): ResolvedConfig {\n return {\n ...config,\n audit: config.audit ?? { enabled: true, output: 'stdout' },\n approvals: config.approvals ?? { channel: 'terminal' },\n };\n}\n\nexport function emptyConfig(): ResolvedConfig {\n return applyDefaults({ servers: [] });\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\ninterface CliState {\n welcomed?: boolean;\n}\n\nfunction statePath(): string {\n return join(homedir(), '.cordon', 'state.json');\n}\n\nexport function getState(): CliState {\n const path = statePath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as CliState;\n } catch {\n return {};\n }\n}\n\nexport function setState(patch: CliState): void {\n const path = statePath();\n const dir = join(homedir(), '.cordon');\n try {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n const merged = { ...getState(), ...patch };\n writeFileSync(path, JSON.stringify(merged, null, 2), 'utf8');\n } catch {\n // Non-fatal: missing state just means we re-show the banner next time.\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { spawnSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { setState } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\nfunction ensureCordonSdkInstalled(cwd: string): void {\n // Config imports from 'cordon-sdk', and jiti resolves it from the config\n // file's directory. Without a local install, `cordon start` dies with\n // \"Cannot find module 'cordon-sdk'\" even when the CLI is global.\n if (existsSync(join(cwd, 'node_modules', 'cordon-sdk', 'package.json'))) {\n return;\n }\n\n if (!existsSync(join(cwd, 'package.json'))) {\n writeFileSync(\n join(cwd, 'package.json'),\n JSON.stringify({ name: 'cordon-config', version: '0.0.0', private: true }, null, 2) + '\\n',\n 'utf8',\n );\n process.stderr.write(`\\x1b[32m✓\\x1b[0m created package.json\\n`);\n }\n\n process.stderr.write(`[cordon] installing cordon-sdk...\\n`);\n const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';\n const result = spawnSync(npmCmd, ['install', 'cordon-sdk'], {\n cwd,\n stdio: ['ignore', 'inherit', 'inherit'],\n });\n\n if (result.status === 0) {\n process.stderr.write(`\\x1b[32m✓\\x1b[0m installed cordon-sdk\\n`);\n } else {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: could not auto-install cordon-sdk. ` +\n `Run 'npm install cordon-sdk' in this directory before 'cordon start'.\\n`,\n );\n }\n}\n\ninterface ClaudeDesktopConfig {\n mcpServers?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n}\n\nfunction getClaudeConfigPath(): string | null {\n const candidates: string[] = [];\n\n if (process.platform === 'darwin') {\n candidates.push(\n join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),\n );\n } else if (process.platform === 'win32') {\n const appData = process.env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n candidates.push(join(appData, 'Claude', 'claude_desktop_config.json'));\n } else {\n candidates.push(join(homedir(), '.config', 'Claude', 'claude_desktop_config.json'));\n }\n\n return candidates.find((p) => existsSync(p)) ?? null;\n}\n\nexport async function initCommand(): Promise<void> {\n const outputPath = join(process.cwd(), 'cordon.config.ts');\n\n if (existsSync(outputPath)) {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: cordon.config.ts already exists — not overwriting.\\n`,\n );\n process.exit(1);\n }\n\n // Try to discover existing MCP servers from Claude Desktop config\n const claudePath = getClaudeConfigPath();\n let claudeConfig: ClaudeDesktopConfig = {};\n\n if (claudePath) {\n process.stderr.write(`[cordon] found Claude Desktop config at ${claudePath}\\n`);\n try {\n claudeConfig = JSON.parse(readFileSync(claudePath, 'utf8')) as ClaudeDesktopConfig;\n } catch {\n process.stderr.write(`\\x1b[33mwarn\\x1b[0m: could not parse Claude Desktop config\\n`);\n }\n } else {\n process.stderr.write(\n `[cordon] no Claude Desktop config found — generating a blank config\\n`,\n );\n }\n\n const servers = Object.entries(claudeConfig.mcpServers ?? {});\n\n // Generate cordon.config.ts\n const serverBlocks = servers.length > 0\n ? servers\n .map(([name, cfg]) => {\n const argsStr = cfg.args?.length\n ? `, args: ${JSON.stringify(cfg.args)}`\n : '';\n const envStr =\n cfg.env && Object.keys(cfg.env).length\n ? `, env: ${JSON.stringify(cfg.env)}`\n : '';\n return ` {\n name: '${name}',\n transport: 'stdio',\n command: '${cfg.command}'${argsStr}${envStr},\n policy: 'allow',\n // tools: {\n // execute: 'approve',\n // delete: 'block',\n // },\n },`;\n })\n .join('\\n')\n : ` // {\n // name: 'my-server',\n // transport: 'stdio',\n // command: 'npx',\n // args: ['-y', '@my-org/my-mcp-server'],\n // policy: 'allow',\n // },`;\n\n const content = `import { defineConfig } from 'cordon-sdk';\n\nexport default defineConfig({\n servers: [\n${serverBlocks}\n ],\n\n audit: {\n enabled: true,\n output: 'stdout',\n },\n\n approvals: {\n channel: 'terminal',\n // timeoutMs: 60_000,\n },\n});\n`;\n\n writeFileSync(outputPath, content, 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m wrote cordon.config.ts\\n`);\n\n // The config imports from 'cordon-sdk'. Install it locally so jiti can\n // resolve it when `cordon start` runs.\n ensureCordonSdkInstalled(process.cwd());\n\n // Patch Claude Desktop config to route through cordon\n if (claudePath && servers.length > 0) {\n const cordonConfigPath = outputPath.replace(/\\\\/g, '/');\n // On Windows, Claude Desktop spawns MCP servers via CreateProcess which\n // won't auto-resolve `npx` without the .cmd extension.\n const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n\n const newClaudeConfig: ClaudeDesktopConfig = {\n ...claudeConfig,\n mcpServers: {\n cordon: {\n command: npxCommand,\n args: ['-y', 'cordon-cli', 'start', '--config', cordonConfigPath],\n },\n },\n };\n\n // Backup the original\n const backupPath = `${claudePath}.cordon-backup`;\n writeFileSync(backupPath, readFileSync(claudePath, 'utf8'), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m backed up Claude Desktop config to ${backupPath}\\n`);\n\n writeFileSync(claudePath, JSON.stringify(newClaudeConfig, null, 2), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m patched Claude Desktop config\\n`);\n process.stderr.write(\n `\\n\\x1b[36mRestart Claude Desktop to activate Cordon.\\x1b[0m\\n`,\n );\n } else if (!claudePath) {\n process.stderr.write(\n `\\n\\x1b[33mwarn\\x1b[0m: Claude Desktop config not found on this system.\\n` +\n `Edit cordon.config.ts, then manually add Cordon to your MCP client config:\\n\\n` +\n ` \"mcpServers\": {\\n` +\n ` \"cordon\": {\\n` +\n ` \"command\": \"${process.platform === 'win32' ? 'npx.cmd' : 'npx'}\",\\n` +\n ` \"args\": [\"-y\", \"cordon-cli\", \"start\", \"--config\", \"${outputPath.replace(/\\\\/g, '/')}\"]\\n` +\n ` }\\n` +\n ` }\\n`,\n );\n } else {\n // claudePath found but no existing servers — config written, no patching needed\n process.stderr.write(\n `\\nEdit cordon.config.ts to add your MCP servers, then run \\x1b[36mnpx cordon start\\x1b[0m.\\n`,\n );\n }\n\n process.stderr.write(\n `\\n\\x1b[36mWant centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `Register a free account at ${DASHBOARD_URL}?utm_source=cli_init\\n`,\n );\n setState({ welcomed: true });\n}\n"],"mappings":"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","names":["existsSync","join","homedir","readFileSync","writeFileSync","existsSync","join","homedir","DASHBOARD_URL","existsSync","join","writeFileSync","homedir","readFileSync"]}
{"version":3,"sources":["../../src/bin/cordon.ts","../../src/commands/start.ts","../../src/config-loader.ts","../../src/cli-state.ts","../../src/commands/init.ts","../../src/commands/login.ts","../../src/commands/logout.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { startCommand } from '../commands/start.js';\nimport { initCommand } from '../commands/init.js';\nimport { loginCommand } from '../commands/login.js';\nimport { logoutCommand } from '../commands/logout.js';\n\nconst program = new Command();\n\nprogram\n .name('cordon')\n .description('The security gateway for AI agents')\n .version('0.1.0');\n\nprogram\n .command('start')\n .description('Start the Cordon gateway')\n .option('-c, --config <path>', 'Path to cordon.config.ts')\n .action(startCommand);\n\nprogram\n .command('init')\n .description('Generate cordon.config.ts and patch Claude Desktop config')\n .action(initCommand);\n\nprogram\n .command('login')\n .description('Log in to Cordon (browser OAuth) and save an API key locally')\n .option('--endpoint <url>', 'Cordon server endpoint (defaults to the hosted instance)')\n .action((opts) => loginCommand(opts).catch((err) => {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: login failed: ${String(err)}\\n`);\n process.exit(1);\n }));\n\nprogram\n .command('logout')\n .description('Remove the local Cordon credentials')\n .action(logoutCommand);\n\nprogram.parse();\n","import { CordonGateway } from '@getcordon/core';\nimport type { ResolvedConfig } from 'cordon-sdk';\nimport { emptyConfig, findConfigPath, loadConfig } from '../config-loader.js';\nimport { getState, setState, getAuth } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\nfunction applyAuthDefaults(config: ResolvedConfig): ResolvedConfig {\n const auth = getAuth();\n if (!auth) return config;\n\n const audit = config.audit;\n const usesHosted = audit && (audit.output === 'hosted' || (Array.isArray(audit.output) && audit.output.includes('hosted')));\n if (!usesHosted) return config;\n if (audit.endpoint && audit.apiKey) return config;\n\n return {\n ...config,\n audit: {\n ...audit,\n endpoint: audit.endpoint ?? auth.endpoint,\n apiKey: audit.apiKey ?? auth.apiKey,\n },\n };\n}\n\ninterface StartOptions {\n config?: string;\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n if (!getState().welcomed && !getAuth()) {\n process.stderr.write(\n `\\n\\x1b[36m[cordon] Want centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `[cordon] Run \\`cordon login\\` or register at ${DASHBOARD_URL}?utm_source=cli_start\\n\\n`,\n );\n setState({ welcomed: true });\n }\n\n // Default to an empty server list so auto-install probes (Glama, MCP\n // registry, fresh `npx -y cordon-cli start`) succeed instead of crashing.\n // Real users get a loud stderr warning so they don't silently run a no-op.\n let config: ResolvedConfig = emptyConfig();\n let configPath: string | null = null;\n\n try {\n configPath = await findConfigPath(options.config);\n } catch (err) {\n if (options.config) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n process.stderr.write(\n '\\x1b[33m[cordon] no cordon.config.ts found — starting with zero upstream servers.\\x1b[0m\\n' +\n '[cordon] Run `cordon init` to generate a config and connect real MCP servers.\\n',\n );\n }\n\n if (configPath) {\n process.stderr.write(`[cordon] loading config from ${configPath}\\n`);\n try {\n config = await loadConfig(configPath);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n }\n\n config = applyAuthDefaults(config);\n\n const gateway = new CordonGateway(config);\n\n const shutdown = async () => {\n process.stderr.write('\\n[cordon] shutting down...\\n');\n try {\n await gateway.stop();\n process.exit(0);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: shutdown failed: ${String(err)}\\n`);\n process.exit(1);\n }\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await gateway.start();\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: gateway failed: ${String(err)}\\n`);\n process.exit(1);\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { createJiti } from 'jiti';\nimport type { CordonConfig, ResolvedConfig } from 'cordon-sdk';\n\nconst SEARCH_PATHS = [\n () => join(process.cwd(), 'cordon.config.ts'),\n () => join(process.cwd(), 'cordon.config.js'),\n () => join(homedir(), '.cordon', 'config.ts'),\n () => join(homedir(), '.cordon', 'config.js'),\n];\n\nexport async function findConfigPath(explicit?: string): Promise<string> {\n if (explicit) {\n if (!existsSync(explicit)) {\n throw new Error(`Config file not found: ${explicit}`);\n }\n return explicit;\n }\n\n for (const candidate of SEARCH_PATHS) {\n const p = candidate();\n if (existsSync(p)) return p;\n }\n\n throw new Error(\n 'No cordon config found. Run `cordon init` to create one, or pass --config <path>.',\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<ResolvedConfig> {\n // jiti handles TypeScript config files without requiring a separate compile step\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import(configPath);\n\n const raw = (mod as { default?: CordonConfig }).default ?? (mod as CordonConfig);\n\n if (!raw || typeof raw !== 'object' || !Array.isArray(raw.servers)) {\n throw new Error(\n `Invalid config at ${configPath}: expected an object with a 'servers' array. ` +\n `Make sure you are using \\`export default defineConfig({...})\\`.`,\n );\n }\n\n return applyDefaults(raw as CordonConfig);\n}\n\nfunction applyDefaults(config: CordonConfig): ResolvedConfig {\n return {\n ...config,\n audit: config.audit ?? { enabled: true, output: 'stdout' },\n approvals: config.approvals ?? { channel: 'terminal' },\n };\n}\n\nexport function emptyConfig(): ResolvedConfig {\n return applyDefaults({ servers: [] });\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\ninterface CliState {\n welcomed?: boolean;\n}\n\nexport interface CliAuth {\n endpoint: string;\n apiKey: string;\n userLogin?: string;\n loggedInAt: string;\n}\n\nfunction cordonDir(): string {\n return join(homedir(), '.cordon');\n}\n\nfunction statePath(): string {\n return join(cordonDir(), 'state.json');\n}\n\nfunction authPath(): string {\n return join(cordonDir(), 'auth.json');\n}\n\nfunction ensureCordonDir(): void {\n const dir = cordonDir();\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport function getState(): CliState {\n const path = statePath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as CliState;\n } catch {\n return {};\n }\n}\n\nexport function setState(patch: CliState): void {\n try {\n ensureCordonDir();\n const merged = { ...getState(), ...patch };\n writeFileSync(statePath(), JSON.stringify(merged, null, 2), 'utf8');\n } catch {\n // Non-fatal: missing state just means we re-show the banner next time.\n }\n}\n\nexport function getAuth(): CliAuth | null {\n const path = authPath();\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as CliAuth;\n } catch {\n return null;\n }\n}\n\nexport function setAuth(auth: CliAuth): void {\n ensureCordonDir();\n const path = authPath();\n writeFileSync(path, JSON.stringify(auth, null, 2), 'utf8');\n if (process.platform !== 'win32') {\n try { chmodSync(path, 0o600); } catch { /* best-effort */ }\n }\n}\n\nexport function clearAuth(): boolean {\n const path = authPath();\n if (!existsSync(path)) return false;\n try {\n unlinkSync(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { spawnSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { setState, getAuth } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\nfunction ensureCordonSdkInstalled(cwd: string): void {\n // Config imports from 'cordon-sdk', and jiti resolves it from the config\n // file's directory. Without a local install, `cordon start` dies with\n // \"Cannot find module 'cordon-sdk'\" even when the CLI is global.\n if (existsSync(join(cwd, 'node_modules', 'cordon-sdk', 'package.json'))) {\n return;\n }\n\n if (!existsSync(join(cwd, 'package.json'))) {\n writeFileSync(\n join(cwd, 'package.json'),\n JSON.stringify({ name: 'cordon-config', version: '0.0.0', private: true }, null, 2) + '\\n',\n 'utf8',\n );\n process.stderr.write(`\\x1b[32m✓\\x1b[0m created package.json\\n`);\n }\n\n process.stderr.write(`[cordon] installing cordon-sdk...\\n`);\n const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';\n const result = spawnSync(npmCmd, ['install', 'cordon-sdk'], {\n cwd,\n stdio: ['ignore', 'inherit', 'inherit'],\n });\n\n if (result.status === 0) {\n process.stderr.write(`\\x1b[32m✓\\x1b[0m installed cordon-sdk\\n`);\n } else {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: could not auto-install cordon-sdk. ` +\n `Run 'npm install cordon-sdk' in this directory before 'cordon start'.\\n`,\n );\n }\n}\n\ninterface ClaudeDesktopConfig {\n mcpServers?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n}\n\nfunction getClaudeConfigPath(): string | null {\n const candidates: string[] = [];\n\n if (process.platform === 'darwin') {\n candidates.push(\n join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),\n );\n } else if (process.platform === 'win32') {\n const appData = process.env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n candidates.push(join(appData, 'Claude', 'claude_desktop_config.json'));\n } else {\n candidates.push(join(homedir(), '.config', 'Claude', 'claude_desktop_config.json'));\n }\n\n return candidates.find((p) => existsSync(p)) ?? null;\n}\n\nexport async function initCommand(): Promise<void> {\n const outputPath = join(process.cwd(), 'cordon.config.ts');\n\n if (existsSync(outputPath)) {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: cordon.config.ts already exists — not overwriting.\\n`,\n );\n process.exit(1);\n }\n\n // Try to discover existing MCP servers from Claude Desktop config\n const claudePath = getClaudeConfigPath();\n let claudeConfig: ClaudeDesktopConfig = {};\n\n if (claudePath) {\n process.stderr.write(`[cordon] found Claude Desktop config at ${claudePath}\\n`);\n try {\n claudeConfig = JSON.parse(readFileSync(claudePath, 'utf8')) as ClaudeDesktopConfig;\n } catch {\n process.stderr.write(`\\x1b[33mwarn\\x1b[0m: could not parse Claude Desktop config\\n`);\n }\n } else {\n process.stderr.write(\n `[cordon] no Claude Desktop config found — generating a blank config\\n`,\n );\n }\n\n const servers = Object.entries(claudeConfig.mcpServers ?? {});\n\n // Generate cordon.config.ts\n const serverBlocks = servers.length > 0\n ? servers\n .map(([name, cfg]) => {\n const argsStr = cfg.args?.length\n ? `, args: ${JSON.stringify(cfg.args)}`\n : '';\n const envStr =\n cfg.env && Object.keys(cfg.env).length\n ? `, env: ${JSON.stringify(cfg.env)}`\n : '';\n return ` {\n name: '${name}',\n transport: 'stdio',\n command: '${cfg.command}'${argsStr}${envStr},\n policy: 'allow',\n // tools: {\n // execute: 'approve',\n // delete: 'block',\n // },\n },`;\n })\n .join('\\n')\n : ` // {\n // name: 'my-server',\n // transport: 'stdio',\n // command: 'npx',\n // args: ['-y', '@my-org/my-mcp-server'],\n // policy: 'allow',\n // },`;\n\n const auth = getAuth();\n const auditBlock = auth\n ? `audit: {\n enabled: true,\n output: 'hosted',\n // endpoint + apiKey are auto-loaded from ~/.cordon/auth.json (cordon login)\n },`\n : `audit: {\n enabled: true,\n output: 'stdout',\n },`;\n\n const content = `import { defineConfig } from 'cordon-sdk';\n\nexport default defineConfig({\n servers: [\n${serverBlocks}\n ],\n\n ${auditBlock}\n\n approvals: {\n channel: 'terminal',\n // timeoutMs: 60_000,\n },\n});\n`;\n\n writeFileSync(outputPath, content, 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m wrote cordon.config.ts\\n`);\n\n // The config imports from 'cordon-sdk'. Install it locally so jiti can\n // resolve it when `cordon start` runs.\n ensureCordonSdkInstalled(process.cwd());\n\n // Patch Claude Desktop config to route through cordon\n if (claudePath && servers.length > 0) {\n const cordonConfigPath = outputPath.replace(/\\\\/g, '/');\n // On Windows, Claude Desktop spawns MCP servers via CreateProcess which\n // won't auto-resolve `npx` without the .cmd extension.\n const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n\n const newClaudeConfig: ClaudeDesktopConfig = {\n ...claudeConfig,\n mcpServers: {\n cordon: {\n command: npxCommand,\n args: ['-y', 'cordon-cli', 'start', '--config', cordonConfigPath],\n },\n },\n };\n\n // Backup the original\n const backupPath = `${claudePath}.cordon-backup`;\n writeFileSync(backupPath, readFileSync(claudePath, 'utf8'), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m backed up Claude Desktop config to ${backupPath}\\n`);\n\n writeFileSync(claudePath, JSON.stringify(newClaudeConfig, null, 2), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m patched Claude Desktop config\\n`);\n process.stderr.write(\n `\\n\\x1b[36mRestart Claude Desktop to activate Cordon.\\x1b[0m\\n`,\n );\n } else if (!claudePath) {\n process.stderr.write(\n `\\n\\x1b[33mwarn\\x1b[0m: Claude Desktop config not found on this system.\\n` +\n `Edit cordon.config.ts, then manually add Cordon to your MCP client config:\\n\\n` +\n ` \"mcpServers\": {\\n` +\n ` \"cordon\": {\\n` +\n ` \"command\": \"${process.platform === 'win32' ? 'npx.cmd' : 'npx'}\",\\n` +\n ` \"args\": [\"-y\", \"cordon-cli\", \"start\", \"--config\", \"${outputPath.replace(/\\\\/g, '/')}\"]\\n` +\n ` }\\n` +\n ` }\\n`,\n );\n } else {\n // claudePath found but no existing servers — config written, no patching needed\n process.stderr.write(\n `\\nEdit cordon.config.ts to add your MCP servers, then run \\x1b[36mnpx cordon start\\x1b[0m.\\n`,\n );\n }\n\n if (auth) {\n process.stderr.write(\n `\\n\\x1b[32m✓\\x1b[0m audit logs will stream to your Cordon account (${auth.endpoint})\\n`,\n );\n } else {\n process.stderr.write(\n `\\n\\x1b[36mWant centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `Run \\x1b[36mcordon login\\x1b[0m to register a free account, ` +\n `or sign up at ${DASHBOARD_URL}?utm_source=cli_init\\n`,\n );\n }\n setState({ welcomed: true });\n}\n","import { createServer } from 'node:http';\nimport { spawn } from 'node:child_process';\nimport { randomBytes } from 'node:crypto';\nimport { setAuth } from '../cli-state.js';\n\nconst DEFAULT_ENDPOINT = 'https://cordon-server-production.up.railway.app';\nconst PORT_RANGE = [53247, 53249, 53251] as const;\nconst TIMEOUT_MS = 5 * 60 * 1000;\n\ninterface LoginOptions {\n endpoint?: string;\n}\n\nfunction openBrowser(url: string): void {\n const cmd = process.platform === 'darwin' ? 'open'\n : process.platform === 'win32' ? 'cmd'\n : 'xdg-open';\n const args = process.platform === 'win32' ? ['/c', 'start', '\"\"', url] : [url];\n try {\n spawn(cmd, args, { detached: true, stdio: 'ignore' }).unref();\n } catch { /* swallow — caller has already printed the URL for manual paste */ }\n}\n\ninterface CallbackResult {\n token: string;\n state: string;\n signup: string;\n}\n\nasync function listenForCallback(port: number, expectedState: string): Promise<CallbackResult> {\n return new Promise((resolve, reject) => {\n const server = createServer((req, res) => {\n const url = new URL(req.url ?? '/', `http://localhost:${port}`);\n if (url.pathname !== '/cb') {\n res.writeHead(404).end('not found');\n return;\n }\n const token = url.searchParams.get('token') ?? '';\n const state = url.searchParams.get('state') ?? '';\n const signup = url.searchParams.get('signup') ?? 'false';\n\n if (state !== expectedState || !token) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n .end('<html><body><h2>Login failed</h2><p>State mismatch or missing token. You can close this tab.</p></body></html>');\n server.close();\n reject(new Error('Callback state mismatch'));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'text/html' })\n .end('<html><body style=\"font-family:system-ui;padding:40px;\"><h2>Logged in to Cordon</h2><p>You can close this tab and return to your terminal.</p></body></html>');\n server.close();\n resolve({ token, state, signup });\n });\n\n server.listen(port, '127.0.0.1');\n server.on('error', (err) => reject(err));\n\n setTimeout(() => {\n server.close();\n reject(new Error('Login timed out after 5 minutes'));\n }, TIMEOUT_MS).unref();\n });\n}\n\nexport async function loginCommand(options: LoginOptions = {}): Promise<void> {\n const endpoint = (options.endpoint ?? DEFAULT_ENDPOINT).replace(/\\/$/, '');\n const state = randomBytes(16).toString('hex');\n\n let port: number | null = null;\n let result: CallbackResult | null = null;\n let lastErr: unknown = null;\n\n for (const candidate of PORT_RANGE) {\n try {\n const callback = `http://localhost:${candidate}/cb`;\n const authUrl =\n `${endpoint}/auth/cli/start?callback=${encodeURIComponent(callback)}&state=${state}`;\n\n process.stderr.write(\n `\\n[cordon] opening browser to log in...\\n` +\n `[cordon] if it doesn't open, visit:\\n ${authUrl}\\n\\n`,\n );\n openBrowser(authUrl);\n\n const pending = listenForCallback(candidate, state);\n port = candidate;\n result = await pending;\n break;\n } catch (err) {\n lastErr = err;\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'EADDRINUSE') continue;\n throw err;\n }\n }\n\n if (!result) {\n throw lastErr instanceof Error ? lastErr : new Error('Could not bind a local callback port');\n }\n\n setAuth({\n endpoint,\n apiKey: result.token,\n loggedInAt: new Date().toISOString(),\n });\n\n process.stderr.write(`\\x1b[32m✓\\x1b[0m logged in. API key saved to ~/.cordon/auth.json\\n`);\n if (result.signup === 'true') {\n process.stderr.write(`Welcome to Cordon. Run \\x1b[36mcordon init\\x1b[0m next to wire up your MCP servers.\\n`);\n }\n // Suppress unused var warning when port is set but not otherwise used\n void port;\n}\n","import { clearAuth } from '../cli-state.js';\n\nexport function logoutCommand(): void {\n if (clearAuth()) {\n process.stderr.write(`\\x1b[32m✓\\x1b[0m logged out. ~/.cordon/auth.json removed\\n`);\n } else {\n process.stderr.write(`[cordon] not logged in\\n`);\n }\n}\n"],"mappings":"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","names":["existsSync","join","homedir","readFileSync","writeFileSync","existsSync","join","homedir","DASHBOARD_URL","existsSync","join","writeFileSync","homedir","readFileSync"]}

@@ -53,8 +53,18 @@ // src/commands/start.ts

// src/cli-state.ts
import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync, chmodSync, unlinkSync } from "fs";
import { join as join2 } from "path";
import { homedir as homedir2 } from "os";
function cordonDir() {
return join2(homedir2(), ".cordon");
}
function statePath() {
return join2(homedir2(), ".cordon", "state.json");
return join2(cordonDir(), "state.json");
}
function authPath() {
return join2(cordonDir(), "auth.json");
}
function ensureCordonDir() {
const dir = cordonDir();
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
}
function getState() {

@@ -70,20 +80,43 @@ const path = statePath();

function setState(patch) {
const path = statePath();
const dir = join2(homedir2(), ".cordon");
try {
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
ensureCordonDir();
const merged = { ...getState(), ...patch };
writeFileSync(path, JSON.stringify(merged, null, 2), "utf8");
writeFileSync(statePath(), JSON.stringify(merged, null, 2), "utf8");
} catch {
}
}
function getAuth() {
const path = authPath();
if (!existsSync2(path)) return null;
try {
return JSON.parse(readFileSync(path, "utf8"));
} catch {
return null;
}
}
// src/commands/start.ts
var DASHBOARD_URL = "https://cordon-server-production.up.railway.app/dashboard/";
function applyAuthDefaults(config) {
const auth = getAuth();
if (!auth) return config;
const audit = config.audit;
const usesHosted = audit && (audit.output === "hosted" || Array.isArray(audit.output) && audit.output.includes("hosted"));
if (!usesHosted) return config;
if (audit.endpoint && audit.apiKey) return config;
return {
...config,
audit: {
...audit,
endpoint: audit.endpoint ?? auth.endpoint,
apiKey: audit.apiKey ?? auth.apiKey
}
};
}
async function startCommand(options) {
if (!getState().welcomed) {
if (!getState().welcomed && !getAuth()) {
process.stderr.write(
`
\x1B[36m[cordon] Want centralized audit logs + Slack approvals?\x1B[0m
[cordon] Register at ${DASHBOARD_URL}?utm_source=cli_start
[cordon] Run \`cordon login\` or register at ${DASHBOARD_URL}?utm_source=cli_start

@@ -119,2 +152,3 @@ `

}
config = applyAuthDefaults(config);
const gateway = new CordonGateway(config);

@@ -240,2 +274,11 @@ const shutdown = async () => {

// },`;
const auth = getAuth();
const auditBlock = auth ? `audit: {
enabled: true,
output: 'hosted',
// endpoint + apiKey are auto-loaded from ~/.cordon/auth.json (cordon login)
},` : `audit: {
enabled: true,
output: 'stdout',
},`;
const content = `import { defineConfig } from 'cordon-sdk';

@@ -248,6 +291,3 @@

audit: {
enabled: true,
output: 'stdout',
},
${auditBlock}

@@ -309,8 +349,16 @@ approvals: {

}
process.stderr.write(
`
if (auth) {
process.stderr.write(
`
\x1B[32m\u2713\x1B[0m audit logs will stream to your Cordon account (${auth.endpoint})
`
);
} else {
process.stderr.write(
`
\x1B[36mWant centralized audit logs + Slack approvals?\x1B[0m
Register a free account at ${DASHBOARD_URL2}?utm_source=cli_init
Run \x1B[36mcordon login\x1B[0m to register a free account, or sign up at ${DASHBOARD_URL2}?utm_source=cli_init
`
);
);
}
setState({ welcomed: true });

@@ -317,0 +365,0 @@ }

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/commands/start.ts","../src/config-loader.ts","../src/cli-state.ts","../src/commands/init.ts"],"sourcesContent":["import { CordonGateway } from '@getcordon/core';\nimport type { ResolvedConfig } from 'cordon-sdk';\nimport { emptyConfig, findConfigPath, loadConfig } from '../config-loader.js';\nimport { getState, setState } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\ninterface StartOptions {\n config?: string;\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n if (!getState().welcomed) {\n process.stderr.write(\n `\\n\\x1b[36m[cordon] Want centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `[cordon] Register at ${DASHBOARD_URL}?utm_source=cli_start\\n\\n`,\n );\n setState({ welcomed: true });\n }\n\n // Default to an empty server list so auto-install probes (Glama, MCP\n // registry, fresh `npx -y cordon-cli start`) succeed instead of crashing.\n // Real users get a loud stderr warning so they don't silently run a no-op.\n let config: ResolvedConfig = emptyConfig();\n let configPath: string | null = null;\n\n try {\n configPath = await findConfigPath(options.config);\n } catch (err) {\n if (options.config) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n process.stderr.write(\n '\\x1b[33m[cordon] no cordon.config.ts found — starting with zero upstream servers.\\x1b[0m\\n' +\n '[cordon] Run `cordon init` to generate a config and connect real MCP servers.\\n',\n );\n }\n\n if (configPath) {\n process.stderr.write(`[cordon] loading config from ${configPath}\\n`);\n try {\n config = await loadConfig(configPath);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n }\n\n const gateway = new CordonGateway(config);\n\n const shutdown = async () => {\n process.stderr.write('\\n[cordon] shutting down...\\n');\n try {\n await gateway.stop();\n process.exit(0);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: shutdown failed: ${String(err)}\\n`);\n process.exit(1);\n }\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await gateway.start();\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: gateway failed: ${String(err)}\\n`);\n process.exit(1);\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { createJiti } from 'jiti';\nimport type { CordonConfig, ResolvedConfig } from 'cordon-sdk';\n\nconst SEARCH_PATHS = [\n () => join(process.cwd(), 'cordon.config.ts'),\n () => join(process.cwd(), 'cordon.config.js'),\n () => join(homedir(), '.cordon', 'config.ts'),\n () => join(homedir(), '.cordon', 'config.js'),\n];\n\nexport async function findConfigPath(explicit?: string): Promise<string> {\n if (explicit) {\n if (!existsSync(explicit)) {\n throw new Error(`Config file not found: ${explicit}`);\n }\n return explicit;\n }\n\n for (const candidate of SEARCH_PATHS) {\n const p = candidate();\n if (existsSync(p)) return p;\n }\n\n throw new Error(\n 'No cordon config found. Run `cordon init` to create one, or pass --config <path>.',\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<ResolvedConfig> {\n // jiti handles TypeScript config files without requiring a separate compile step\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import(configPath);\n\n const raw = (mod as { default?: CordonConfig }).default ?? (mod as CordonConfig);\n\n if (!raw || typeof raw !== 'object' || !Array.isArray(raw.servers)) {\n throw new Error(\n `Invalid config at ${configPath}: expected an object with a 'servers' array. ` +\n `Make sure you are using \\`export default defineConfig({...})\\`.`,\n );\n }\n\n return applyDefaults(raw as CordonConfig);\n}\n\nfunction applyDefaults(config: CordonConfig): ResolvedConfig {\n return {\n ...config,\n audit: config.audit ?? { enabled: true, output: 'stdout' },\n approvals: config.approvals ?? { channel: 'terminal' },\n };\n}\n\nexport function emptyConfig(): ResolvedConfig {\n return applyDefaults({ servers: [] });\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\ninterface CliState {\n welcomed?: boolean;\n}\n\nfunction statePath(): string {\n return join(homedir(), '.cordon', 'state.json');\n}\n\nexport function getState(): CliState {\n const path = statePath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as CliState;\n } catch {\n return {};\n }\n}\n\nexport function setState(patch: CliState): void {\n const path = statePath();\n const dir = join(homedir(), '.cordon');\n try {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n const merged = { ...getState(), ...patch };\n writeFileSync(path, JSON.stringify(merged, null, 2), 'utf8');\n } catch {\n // Non-fatal: missing state just means we re-show the banner next time.\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { spawnSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { setState } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\nfunction ensureCordonSdkInstalled(cwd: string): void {\n // Config imports from 'cordon-sdk', and jiti resolves it from the config\n // file's directory. Without a local install, `cordon start` dies with\n // \"Cannot find module 'cordon-sdk'\" even when the CLI is global.\n if (existsSync(join(cwd, 'node_modules', 'cordon-sdk', 'package.json'))) {\n return;\n }\n\n if (!existsSync(join(cwd, 'package.json'))) {\n writeFileSync(\n join(cwd, 'package.json'),\n JSON.stringify({ name: 'cordon-config', version: '0.0.0', private: true }, null, 2) + '\\n',\n 'utf8',\n );\n process.stderr.write(`\\x1b[32m✓\\x1b[0m created package.json\\n`);\n }\n\n process.stderr.write(`[cordon] installing cordon-sdk...\\n`);\n const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';\n const result = spawnSync(npmCmd, ['install', 'cordon-sdk'], {\n cwd,\n stdio: ['ignore', 'inherit', 'inherit'],\n });\n\n if (result.status === 0) {\n process.stderr.write(`\\x1b[32m✓\\x1b[0m installed cordon-sdk\\n`);\n } else {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: could not auto-install cordon-sdk. ` +\n `Run 'npm install cordon-sdk' in this directory before 'cordon start'.\\n`,\n );\n }\n}\n\ninterface ClaudeDesktopConfig {\n mcpServers?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n}\n\nfunction getClaudeConfigPath(): string | null {\n const candidates: string[] = [];\n\n if (process.platform === 'darwin') {\n candidates.push(\n join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),\n );\n } else if (process.platform === 'win32') {\n const appData = process.env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n candidates.push(join(appData, 'Claude', 'claude_desktop_config.json'));\n } else {\n candidates.push(join(homedir(), '.config', 'Claude', 'claude_desktop_config.json'));\n }\n\n return candidates.find((p) => existsSync(p)) ?? null;\n}\n\nexport async function initCommand(): Promise<void> {\n const outputPath = join(process.cwd(), 'cordon.config.ts');\n\n if (existsSync(outputPath)) {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: cordon.config.ts already exists — not overwriting.\\n`,\n );\n process.exit(1);\n }\n\n // Try to discover existing MCP servers from Claude Desktop config\n const claudePath = getClaudeConfigPath();\n let claudeConfig: ClaudeDesktopConfig = {};\n\n if (claudePath) {\n process.stderr.write(`[cordon] found Claude Desktop config at ${claudePath}\\n`);\n try {\n claudeConfig = JSON.parse(readFileSync(claudePath, 'utf8')) as ClaudeDesktopConfig;\n } catch {\n process.stderr.write(`\\x1b[33mwarn\\x1b[0m: could not parse Claude Desktop config\\n`);\n }\n } else {\n process.stderr.write(\n `[cordon] no Claude Desktop config found — generating a blank config\\n`,\n );\n }\n\n const servers = Object.entries(claudeConfig.mcpServers ?? {});\n\n // Generate cordon.config.ts\n const serverBlocks = servers.length > 0\n ? servers\n .map(([name, cfg]) => {\n const argsStr = cfg.args?.length\n ? `, args: ${JSON.stringify(cfg.args)}`\n : '';\n const envStr =\n cfg.env && Object.keys(cfg.env).length\n ? `, env: ${JSON.stringify(cfg.env)}`\n : '';\n return ` {\n name: '${name}',\n transport: 'stdio',\n command: '${cfg.command}'${argsStr}${envStr},\n policy: 'allow',\n // tools: {\n // execute: 'approve',\n // delete: 'block',\n // },\n },`;\n })\n .join('\\n')\n : ` // {\n // name: 'my-server',\n // transport: 'stdio',\n // command: 'npx',\n // args: ['-y', '@my-org/my-mcp-server'],\n // policy: 'allow',\n // },`;\n\n const content = `import { defineConfig } from 'cordon-sdk';\n\nexport default defineConfig({\n servers: [\n${serverBlocks}\n ],\n\n audit: {\n enabled: true,\n output: 'stdout',\n },\n\n approvals: {\n channel: 'terminal',\n // timeoutMs: 60_000,\n },\n});\n`;\n\n writeFileSync(outputPath, content, 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m wrote cordon.config.ts\\n`);\n\n // The config imports from 'cordon-sdk'. Install it locally so jiti can\n // resolve it when `cordon start` runs.\n ensureCordonSdkInstalled(process.cwd());\n\n // Patch Claude Desktop config to route through cordon\n if (claudePath && servers.length > 0) {\n const cordonConfigPath = outputPath.replace(/\\\\/g, '/');\n // On Windows, Claude Desktop spawns MCP servers via CreateProcess which\n // won't auto-resolve `npx` without the .cmd extension.\n const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n\n const newClaudeConfig: ClaudeDesktopConfig = {\n ...claudeConfig,\n mcpServers: {\n cordon: {\n command: npxCommand,\n args: ['-y', 'cordon-cli', 'start', '--config', cordonConfigPath],\n },\n },\n };\n\n // Backup the original\n const backupPath = `${claudePath}.cordon-backup`;\n writeFileSync(backupPath, readFileSync(claudePath, 'utf8'), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m backed up Claude Desktop config to ${backupPath}\\n`);\n\n writeFileSync(claudePath, JSON.stringify(newClaudeConfig, null, 2), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m patched Claude Desktop config\\n`);\n process.stderr.write(\n `\\n\\x1b[36mRestart Claude Desktop to activate Cordon.\\x1b[0m\\n`,\n );\n } else if (!claudePath) {\n process.stderr.write(\n `\\n\\x1b[33mwarn\\x1b[0m: Claude Desktop config not found on this system.\\n` +\n `Edit cordon.config.ts, then manually add Cordon to your MCP client config:\\n\\n` +\n ` \"mcpServers\": {\\n` +\n ` \"cordon\": {\\n` +\n ` \"command\": \"${process.platform === 'win32' ? 'npx.cmd' : 'npx'}\",\\n` +\n ` \"args\": [\"-y\", \"cordon-cli\", \"start\", \"--config\", \"${outputPath.replace(/\\\\/g, '/')}\"]\\n` +\n ` }\\n` +\n ` }\\n`,\n );\n } else {\n // claudePath found but no existing servers — config written, no patching needed\n process.stderr.write(\n `\\nEdit cordon.config.ts to add your MCP servers, then run \\x1b[36mnpx cordon start\\x1b[0m.\\n`,\n );\n }\n\n process.stderr.write(\n `\\n\\x1b[36mWant centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `Register a free account at ${DASHBOARD_URL}?utm_source=cli_init\\n`,\n );\n setState({ welcomed: true });\n}\n"],"mappings":"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","names":["existsSync","join","homedir","readFileSync","writeFileSync","existsSync","join","homedir","DASHBOARD_URL","existsSync","join","writeFileSync","homedir","readFileSync"]}
{"version":3,"sources":["../src/commands/start.ts","../src/config-loader.ts","../src/cli-state.ts","../src/commands/init.ts"],"sourcesContent":["import { CordonGateway } from '@getcordon/core';\nimport type { ResolvedConfig } from 'cordon-sdk';\nimport { emptyConfig, findConfigPath, loadConfig } from '../config-loader.js';\nimport { getState, setState, getAuth } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\nfunction applyAuthDefaults(config: ResolvedConfig): ResolvedConfig {\n const auth = getAuth();\n if (!auth) return config;\n\n const audit = config.audit;\n const usesHosted = audit && (audit.output === 'hosted' || (Array.isArray(audit.output) && audit.output.includes('hosted')));\n if (!usesHosted) return config;\n if (audit.endpoint && audit.apiKey) return config;\n\n return {\n ...config,\n audit: {\n ...audit,\n endpoint: audit.endpoint ?? auth.endpoint,\n apiKey: audit.apiKey ?? auth.apiKey,\n },\n };\n}\n\ninterface StartOptions {\n config?: string;\n}\n\nexport async function startCommand(options: StartOptions): Promise<void> {\n if (!getState().welcomed && !getAuth()) {\n process.stderr.write(\n `\\n\\x1b[36m[cordon] Want centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `[cordon] Run \\`cordon login\\` or register at ${DASHBOARD_URL}?utm_source=cli_start\\n\\n`,\n );\n setState({ welcomed: true });\n }\n\n // Default to an empty server list so auto-install probes (Glama, MCP\n // registry, fresh `npx -y cordon-cli start`) succeed instead of crashing.\n // Real users get a loud stderr warning so they don't silently run a no-op.\n let config: ResolvedConfig = emptyConfig();\n let configPath: string | null = null;\n\n try {\n configPath = await findConfigPath(options.config);\n } catch (err) {\n if (options.config) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n process.stderr.write(\n '\\x1b[33m[cordon] no cordon.config.ts found — starting with zero upstream servers.\\x1b[0m\\n' +\n '[cordon] Run `cordon init` to generate a config and connect real MCP servers.\\n',\n );\n }\n\n if (configPath) {\n process.stderr.write(`[cordon] loading config from ${configPath}\\n`);\n try {\n config = await loadConfig(configPath);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: ${String(err)}\\n`);\n process.exit(1);\n }\n }\n\n config = applyAuthDefaults(config);\n\n const gateway = new CordonGateway(config);\n\n const shutdown = async () => {\n process.stderr.write('\\n[cordon] shutting down...\\n');\n try {\n await gateway.stop();\n process.exit(0);\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: shutdown failed: ${String(err)}\\n`);\n process.exit(1);\n }\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n try {\n await gateway.start();\n } catch (err) {\n process.stderr.write(`\\x1b[31merror\\x1b[0m: gateway failed: ${String(err)}\\n`);\n process.exit(1);\n }\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { createJiti } from 'jiti';\nimport type { CordonConfig, ResolvedConfig } from 'cordon-sdk';\n\nconst SEARCH_PATHS = [\n () => join(process.cwd(), 'cordon.config.ts'),\n () => join(process.cwd(), 'cordon.config.js'),\n () => join(homedir(), '.cordon', 'config.ts'),\n () => join(homedir(), '.cordon', 'config.js'),\n];\n\nexport async function findConfigPath(explicit?: string): Promise<string> {\n if (explicit) {\n if (!existsSync(explicit)) {\n throw new Error(`Config file not found: ${explicit}`);\n }\n return explicit;\n }\n\n for (const candidate of SEARCH_PATHS) {\n const p = candidate();\n if (existsSync(p)) return p;\n }\n\n throw new Error(\n 'No cordon config found. Run `cordon init` to create one, or pass --config <path>.',\n );\n}\n\nexport async function loadConfig(configPath: string): Promise<ResolvedConfig> {\n // jiti handles TypeScript config files without requiring a separate compile step\n const jiti = createJiti(import.meta.url);\n const mod = await jiti.import(configPath);\n\n const raw = (mod as { default?: CordonConfig }).default ?? (mod as CordonConfig);\n\n if (!raw || typeof raw !== 'object' || !Array.isArray(raw.servers)) {\n throw new Error(\n `Invalid config at ${configPath}: expected an object with a 'servers' array. ` +\n `Make sure you are using \\`export default defineConfig({...})\\`.`,\n );\n }\n\n return applyDefaults(raw as CordonConfig);\n}\n\nfunction applyDefaults(config: CordonConfig): ResolvedConfig {\n return {\n ...config,\n audit: config.audit ?? { enabled: true, output: 'stdout' },\n approvals: config.approvals ?? { channel: 'terminal' },\n };\n}\n\nexport function emptyConfig(): ResolvedConfig {\n return applyDefaults({ servers: [] });\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync, unlinkSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\ninterface CliState {\n welcomed?: boolean;\n}\n\nexport interface CliAuth {\n endpoint: string;\n apiKey: string;\n userLogin?: string;\n loggedInAt: string;\n}\n\nfunction cordonDir(): string {\n return join(homedir(), '.cordon');\n}\n\nfunction statePath(): string {\n return join(cordonDir(), 'state.json');\n}\n\nfunction authPath(): string {\n return join(cordonDir(), 'auth.json');\n}\n\nfunction ensureCordonDir(): void {\n const dir = cordonDir();\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport function getState(): CliState {\n const path = statePath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as CliState;\n } catch {\n return {};\n }\n}\n\nexport function setState(patch: CliState): void {\n try {\n ensureCordonDir();\n const merged = { ...getState(), ...patch };\n writeFileSync(statePath(), JSON.stringify(merged, null, 2), 'utf8');\n } catch {\n // Non-fatal: missing state just means we re-show the banner next time.\n }\n}\n\nexport function getAuth(): CliAuth | null {\n const path = authPath();\n if (!existsSync(path)) return null;\n try {\n return JSON.parse(readFileSync(path, 'utf8')) as CliAuth;\n } catch {\n return null;\n }\n}\n\nexport function setAuth(auth: CliAuth): void {\n ensureCordonDir();\n const path = authPath();\n writeFileSync(path, JSON.stringify(auth, null, 2), 'utf8');\n if (process.platform !== 'win32') {\n try { chmodSync(path, 0o600); } catch { /* best-effort */ }\n }\n}\n\nexport function clearAuth(): boolean {\n const path = authPath();\n if (!existsSync(path)) return false;\n try {\n unlinkSync(path);\n return true;\n } catch {\n return false;\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { spawnSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { setState, getAuth } from '../cli-state.js';\n\nconst DASHBOARD_URL = 'https://cordon-server-production.up.railway.app/dashboard/';\n\nfunction ensureCordonSdkInstalled(cwd: string): void {\n // Config imports from 'cordon-sdk', and jiti resolves it from the config\n // file's directory. Without a local install, `cordon start` dies with\n // \"Cannot find module 'cordon-sdk'\" even when the CLI is global.\n if (existsSync(join(cwd, 'node_modules', 'cordon-sdk', 'package.json'))) {\n return;\n }\n\n if (!existsSync(join(cwd, 'package.json'))) {\n writeFileSync(\n join(cwd, 'package.json'),\n JSON.stringify({ name: 'cordon-config', version: '0.0.0', private: true }, null, 2) + '\\n',\n 'utf8',\n );\n process.stderr.write(`\\x1b[32m✓\\x1b[0m created package.json\\n`);\n }\n\n process.stderr.write(`[cordon] installing cordon-sdk...\\n`);\n const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';\n const result = spawnSync(npmCmd, ['install', 'cordon-sdk'], {\n cwd,\n stdio: ['ignore', 'inherit', 'inherit'],\n });\n\n if (result.status === 0) {\n process.stderr.write(`\\x1b[32m✓\\x1b[0m installed cordon-sdk\\n`);\n } else {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: could not auto-install cordon-sdk. ` +\n `Run 'npm install cordon-sdk' in this directory before 'cordon start'.\\n`,\n );\n }\n}\n\ninterface ClaudeDesktopConfig {\n mcpServers?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n}\n\nfunction getClaudeConfigPath(): string | null {\n const candidates: string[] = [];\n\n if (process.platform === 'darwin') {\n candidates.push(\n join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),\n );\n } else if (process.platform === 'win32') {\n const appData = process.env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming');\n candidates.push(join(appData, 'Claude', 'claude_desktop_config.json'));\n } else {\n candidates.push(join(homedir(), '.config', 'Claude', 'claude_desktop_config.json'));\n }\n\n return candidates.find((p) => existsSync(p)) ?? null;\n}\n\nexport async function initCommand(): Promise<void> {\n const outputPath = join(process.cwd(), 'cordon.config.ts');\n\n if (existsSync(outputPath)) {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: cordon.config.ts already exists — not overwriting.\\n`,\n );\n process.exit(1);\n }\n\n // Try to discover existing MCP servers from Claude Desktop config\n const claudePath = getClaudeConfigPath();\n let claudeConfig: ClaudeDesktopConfig = {};\n\n if (claudePath) {\n process.stderr.write(`[cordon] found Claude Desktop config at ${claudePath}\\n`);\n try {\n claudeConfig = JSON.parse(readFileSync(claudePath, 'utf8')) as ClaudeDesktopConfig;\n } catch {\n process.stderr.write(`\\x1b[33mwarn\\x1b[0m: could not parse Claude Desktop config\\n`);\n }\n } else {\n process.stderr.write(\n `[cordon] no Claude Desktop config found — generating a blank config\\n`,\n );\n }\n\n const servers = Object.entries(claudeConfig.mcpServers ?? {});\n\n // Generate cordon.config.ts\n const serverBlocks = servers.length > 0\n ? servers\n .map(([name, cfg]) => {\n const argsStr = cfg.args?.length\n ? `, args: ${JSON.stringify(cfg.args)}`\n : '';\n const envStr =\n cfg.env && Object.keys(cfg.env).length\n ? `, env: ${JSON.stringify(cfg.env)}`\n : '';\n return ` {\n name: '${name}',\n transport: 'stdio',\n command: '${cfg.command}'${argsStr}${envStr},\n policy: 'allow',\n // tools: {\n // execute: 'approve',\n // delete: 'block',\n // },\n },`;\n })\n .join('\\n')\n : ` // {\n // name: 'my-server',\n // transport: 'stdio',\n // command: 'npx',\n // args: ['-y', '@my-org/my-mcp-server'],\n // policy: 'allow',\n // },`;\n\n const auth = getAuth();\n const auditBlock = auth\n ? `audit: {\n enabled: true,\n output: 'hosted',\n // endpoint + apiKey are auto-loaded from ~/.cordon/auth.json (cordon login)\n },`\n : `audit: {\n enabled: true,\n output: 'stdout',\n },`;\n\n const content = `import { defineConfig } from 'cordon-sdk';\n\nexport default defineConfig({\n servers: [\n${serverBlocks}\n ],\n\n ${auditBlock}\n\n approvals: {\n channel: 'terminal',\n // timeoutMs: 60_000,\n },\n});\n`;\n\n writeFileSync(outputPath, content, 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m wrote cordon.config.ts\\n`);\n\n // The config imports from 'cordon-sdk'. Install it locally so jiti can\n // resolve it when `cordon start` runs.\n ensureCordonSdkInstalled(process.cwd());\n\n // Patch Claude Desktop config to route through cordon\n if (claudePath && servers.length > 0) {\n const cordonConfigPath = outputPath.replace(/\\\\/g, '/');\n // On Windows, Claude Desktop spawns MCP servers via CreateProcess which\n // won't auto-resolve `npx` without the .cmd extension.\n const npxCommand = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n\n const newClaudeConfig: ClaudeDesktopConfig = {\n ...claudeConfig,\n mcpServers: {\n cordon: {\n command: npxCommand,\n args: ['-y', 'cordon-cli', 'start', '--config', cordonConfigPath],\n },\n },\n };\n\n // Backup the original\n const backupPath = `${claudePath}.cordon-backup`;\n writeFileSync(backupPath, readFileSync(claudePath, 'utf8'), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m backed up Claude Desktop config to ${backupPath}\\n`);\n\n writeFileSync(claudePath, JSON.stringify(newClaudeConfig, null, 2), 'utf8');\n process.stderr.write(`\\x1b[32m✓\\x1b[0m patched Claude Desktop config\\n`);\n process.stderr.write(\n `\\n\\x1b[36mRestart Claude Desktop to activate Cordon.\\x1b[0m\\n`,\n );\n } else if (!claudePath) {\n process.stderr.write(\n `\\n\\x1b[33mwarn\\x1b[0m: Claude Desktop config not found on this system.\\n` +\n `Edit cordon.config.ts, then manually add Cordon to your MCP client config:\\n\\n` +\n ` \"mcpServers\": {\\n` +\n ` \"cordon\": {\\n` +\n ` \"command\": \"${process.platform === 'win32' ? 'npx.cmd' : 'npx'}\",\\n` +\n ` \"args\": [\"-y\", \"cordon-cli\", \"start\", \"--config\", \"${outputPath.replace(/\\\\/g, '/')}\"]\\n` +\n ` }\\n` +\n ` }\\n`,\n );\n } else {\n // claudePath found but no existing servers — config written, no patching needed\n process.stderr.write(\n `\\nEdit cordon.config.ts to add your MCP servers, then run \\x1b[36mnpx cordon start\\x1b[0m.\\n`,\n );\n }\n\n if (auth) {\n process.stderr.write(\n `\\n\\x1b[32m✓\\x1b[0m audit logs will stream to your Cordon account (${auth.endpoint})\\n`,\n );\n } else {\n process.stderr.write(\n `\\n\\x1b[36mWant centralized audit logs + Slack approvals?\\x1b[0m\\n` +\n `Run \\x1b[36mcordon login\\x1b[0m to register a free account, ` +\n `or sign up at ${DASHBOARD_URL}?utm_source=cli_init\\n`,\n );\n }\n setState({ welcomed: true });\n}\n"],"mappings":"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","names":["existsSync","join","homedir","readFileSync","writeFileSync","existsSync","join","homedir","DASHBOARD_URL","existsSync","join","writeFileSync","homedir","readFileSync"]}
{
"name": "cordon-cli",
"version": "0.1.12",
"version": "0.1.13",
"mcpName": "io.github.marras0914/cordon",

@@ -5,0 +5,0 @@ "description": "The security gateway for AI agents — firewall, auditor, and remote control for MCP tool calls",