🎩 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.18
to
0.1.19
+17
bin/cordon.js
#!/usr/bin/env node
process.stderr.write([
"",
" cordon-cli has been renamed to @getcordon/cli.",
"",
" Run:",
" npm install -g @getcordon/cli",
"",
" The new package has the activation flow, the Windows OAuth fix,",
" the dashboard integration, and call-graph policies.",
"",
" Repo: https://github.com/marras0914/cordon",
" Site: https://getcordon.com",
"",
""
].join("\n"));
process.exit(1);
MIT License
Copyright (c) 2026 Cordon Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+19
-53
{
"name": "cordon-cli",
"version": "0.1.18",
"mcpName": "io.github.marras0914/cordon",
"description": "Cordon for MCP — security gateway for MCP tool calls. Firewall, auditor, and human-in-the-loop approvals over any stdio MCP server.",
"version": "0.1.19",
"description": "DEPRECATED — Cordon CLI has moved to @getcordon/cli. Run: npm install -g @getcordon/cli",
"bin": {
"cordon": "bin/cordon.js"
},
"files": [
"bin",
"README.md",
"LICENSE"
],
"keywords": [
"deprecated",
"cordon",
"mcp"
],
"license": "MIT",
"author": "marras0914",
"license": "MIT",
"homepage": "https://getcordon.com",
"repository": {
"type": "git",
"url": "git+https://github.com/marras0914/cordon.git",
"directory": "packages/cli"
"url": "https://github.com/marras0914/cordon.git",
"directory": "packaging/cordon-cli"
},
"bugs": {
"url": "https://github.com/marras0914/cordon/issues"
},
"keywords": [
"mcp",
"security",
"gateway",
"proxy",
"human-in-the-loop",
"audit-log",
"tool-call",
"ai-agent",
"cli",
"ai",
"llm",
"policy",
"cordon"
],
"type": "module",
"bin": {
"cordon": "dist/bin/cordon.js"
},
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"files": [
"dist",
"README.md"
],
"scripts": {
"build": "tsup",
"dev": "tsup --watch"
},
"dependencies": {
"@getcordon/core": "*",
"cordon-sdk": "*",
"commander": "^12.1.0",
"jiti": "^2.4.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"typescript": "^5.6.0",
"tsup": "^8.3.0"
}
"deprecated": "cordon-cli has been renamed. Run: npm install -g @getcordon/cli"
}

@@ -1,64 +0,12 @@

# cordon-cli
# cordon-cli (deprecated)
The command-line interface for [Cordon for MCP](https://github.com/marras0914/cordon), the security gateway for MCP tool calls.
This package has been renamed. Install instead:
## Install
```bash
npm install -g cordon-cli
npm install -g @getcordon/cli
```
## Quickstart
The new package has the activation flow, the Windows OAuth fix, the dashboard integration, and call-graph policies.
```bash
cordon init # reads your Claude Desktop config, generates cordon.config.ts,
# patches Claude Desktop to route tool calls through Cordon
cordon start # launches the gateway
```
Restart Claude Desktop after `cordon init`. Every MCP tool call now flows through Cordon.
## What it does
- Scans `claude_desktop_config.json` and generates a starter `cordon.config.ts`
- Patches your MCP client config to route through Cordon (opt-in, backed up)
- Runs the gateway as an MCP server that aggregates your existing upstream servers
- Enforces per-tool policies (allow, block, approve, read-only, log-only, hidden, sql-read-only, sql-approve-writes)
- Supports closed-world tool catalogs via `knownTools` so new upstream tools don't silently become callable
- SQL-aware policies parse the statement in tool-call args and decide based on type (SELECT vs DML vs DDL)
- Surfaces approval prompts in the terminal, or Slack via the hosted dashboard
## Config example
```typescript
import { defineConfig } from 'cordon-sdk';
export default defineConfig({
servers: [
{
name: 'database',
transport: 'stdio',
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-postgres', process.env.POSTGRES_URL!],
policy: 'read-only',
// Optional: declare the exact tool surface you expect. New tools in
// future upstream releases get blocked until you add them here.
knownTools: ['query', 'list_tables', 'describe_table'],
},
],
audit: { enabled: true, output: 'file' },
approvals: { channel: 'terminal', timeoutMs: 60_000 },
});
```
## Full documentation
Complete policy reference, approval channels, audit outputs, and architecture overview:
**https://github.com/marras0914/cordon**
Writeup with real-world examples:
**https://dev.to/marras0914/mcp-has-no-security-model-heres-how-to-fix-it-in-2-minutes-5f7o**
## License
MIT
- Repo: https://github.com/marras0914/cordon
- Site: https://getcordon.com
#!/usr/bin/env node
// src/bin/cordon.ts
import { Command } from "commander";
// src/commands/start.ts
import { CordonGateway } from "@getcordon/core";
// src/config-loader.ts
import { existsSync } from "fs";
import { join } from "path";
import { homedir } from "os";
import { createJiti } from "jiti";
var SEARCH_PATHS = [
() => join(process.cwd(), "cordon.config.ts"),
() => join(process.cwd(), "cordon.config.js"),
() => join(homedir(), ".cordon", "config.ts"),
() => join(homedir(), ".cordon", "config.js")
];
async function findConfigPath(explicit) {
if (explicit) {
if (!existsSync(explicit)) {
throw new Error(`Config file not found: ${explicit}`);
}
return explicit;
}
for (const candidate of SEARCH_PATHS) {
const p = candidate();
if (existsSync(p)) return p;
}
throw new Error(
"No cordon config found. Run `cordon init` to create one, or pass --config <path>."
);
}
async function loadConfig(configPath) {
const jiti = createJiti(import.meta.url);
const mod = await jiti.import(configPath);
const raw = mod.default ?? mod;
if (!raw || typeof raw !== "object" || !Array.isArray(raw.servers)) {
throw new Error(
`Invalid config at ${configPath}: expected an object with a 'servers' array. Make sure you are using \`export default defineConfig({...})\`.`
);
}
return applyDefaults(raw);
}
function applyDefaults(config) {
return {
...config,
audit: config.audit ?? { enabled: true, output: "stdout" },
approvals: config.approvals ?? { channel: "terminal" }
};
}
function emptyConfig() {
return applyDefaults({ servers: [] });
}
// src/cli-state.ts
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(cordonDir(), "state.json");
}
function authPath() {
return join2(cordonDir(), "auth.json");
}
function ensureCordonDir() {
const dir = cordonDir();
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
}
function getState() {
const path = statePath();
if (!existsSync2(path)) return {};
try {
return JSON.parse(readFileSync(path, "utf8"));
} catch {
return {};
}
}
function setState(patch) {
try {
ensureCordonDir();
const merged = { ...getState(), ...patch };
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 && !getAuth()) {
process.stderr.write(
`
\x1B[36m[cordon] Want centralized audit logs + Slack approvals?\x1B[0m
[cordon] Run \`cordon login\` or register at ${DASHBOARD_URL}?utm_source=cli_start
`
);
setState({ welcomed: true });
}
let config = emptyConfig();
let configPath = null;
try {
configPath = await findConfigPath(options.config);
} catch (err) {
if (options.config) {
process.stderr.write(`\x1B[31merror\x1B[0m: ${String(err)}
`);
process.exit(1);
}
process.stderr.write(
"\x1B[33m[cordon] no cordon.config.ts found \u2014 starting with zero upstream servers.\x1B[0m\n[cordon] Run `cordon init` to generate a config and connect real MCP servers.\n"
);
}
if (configPath) {
process.stderr.write(`[cordon] loading config from ${configPath}
`);
try {
config = await loadConfig(configPath);
} catch (err) {
process.stderr.write(`\x1B[31merror\x1B[0m: ${String(err)}
`);
process.exit(1);
}
}
config = applyAuthDefaults(config);
const gateway = new CordonGateway(config);
const shutdown = async () => {
process.stderr.write("\n[cordon] shutting down...\n");
try {
await gateway.stop();
process.exit(0);
} catch (err) {
process.stderr.write(`\x1B[31merror\x1B[0m: shutdown failed: ${String(err)}
`);
process.exit(1);
}
};
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
try {
await gateway.start();
} catch (err) {
process.stderr.write(`\x1B[31merror\x1B[0m: gateway failed: ${String(err)}
`);
process.exit(1);
}
}
// src/commands/init.ts
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
import { spawnSync } from "child_process";
import { join as join3 } from "path";
import { homedir as homedir3 } from "os";
var DASHBOARD_URL2 = "https://cordon-server-production.up.railway.app/dashboard/";
function ensureCordonSdkInstalled(cwd) {
if (existsSync3(join3(cwd, "node_modules", "cordon-sdk", "package.json"))) {
return;
}
if (!existsSync3(join3(cwd, "package.json"))) {
writeFileSync2(
join3(cwd, "package.json"),
JSON.stringify({ name: "cordon-config", version: "0.0.0", private: true }, null, 2) + "\n",
"utf8"
);
process.stderr.write(`\x1B[32m\u2713\x1B[0m created package.json
`);
}
process.stderr.write(`[cordon] installing cordon-sdk...
`);
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
const result = spawnSync(npmCmd, ["install", "cordon-sdk"], {
cwd,
stdio: ["ignore", "inherit", "inherit"]
});
if (result.status === 0) {
process.stderr.write(`\x1B[32m\u2713\x1B[0m installed cordon-sdk
`);
} else {
process.stderr.write(
`\x1B[33mwarn\x1B[0m: could not auto-install cordon-sdk. Run 'npm install cordon-sdk' in this directory before 'cordon start'.
`
);
}
}
function getClaudeConfigPath() {
const candidates = [];
if (process.platform === "darwin") {
candidates.push(
join3(homedir3(), "Library", "Application Support", "Claude", "claude_desktop_config.json")
);
} else if (process.platform === "win32") {
const appData = process.env["APPDATA"] ?? join3(homedir3(), "AppData", "Roaming");
candidates.push(join3(appData, "Claude", "claude_desktop_config.json"));
} else {
candidates.push(join3(homedir3(), ".config", "Claude", "claude_desktop_config.json"));
}
return candidates.find((p) => existsSync3(p)) ?? null;
}
async function initCommand() {
const outputPath = join3(process.cwd(), "cordon.config.ts");
if (existsSync3(outputPath)) {
process.stderr.write(
`\x1B[33mwarn\x1B[0m: cordon.config.ts already exists \u2014 not overwriting.
`
);
process.exit(1);
}
const claudePath = getClaudeConfigPath();
let claudeConfig = {};
if (claudePath) {
process.stderr.write(`[cordon] found Claude Desktop config at ${claudePath}
`);
try {
claudeConfig = JSON.parse(readFileSync2(claudePath, "utf8"));
} catch {
process.stderr.write(`\x1B[33mwarn\x1B[0m: could not parse Claude Desktop config
`);
}
} else {
process.stderr.write(
`[cordon] no Claude Desktop config found \u2014 generating a blank config
`
);
}
const servers = Object.entries(claudeConfig.mcpServers ?? {});
const serverBlocks = servers.length > 0 ? servers.map(([name, cfg]) => {
const argsStr = cfg.args?.length ? `, args: ${JSON.stringify(cfg.args)}` : "";
const envStr = cfg.env && Object.keys(cfg.env).length ? `, env: ${JSON.stringify(cfg.env)}` : "";
return ` {
name: ${JSON.stringify(name)},
transport: 'stdio',
command: ${JSON.stringify(cfg.command)}${argsStr}${envStr},
policy: 'allow',
// tools: {
// execute: 'approve',
// delete: 'block',
// },
},`;
}).join("\n") : ` // {
// name: 'my-server',
// transport: 'stdio',
// command: 'npx',
// args: ['-y', '@my-org/my-mcp-server'],
// policy: 'allow',
// },`;
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';
export default defineConfig({
servers: [
${serverBlocks}
],
${auditBlock}
approvals: {
channel: 'terminal',
// timeoutMs: 60_000,
},
});
`;
writeFileSync2(outputPath, content, "utf8");
process.stderr.write(`\x1B[32m\u2713\x1B[0m wrote cordon.config.ts
`);
ensureCordonSdkInstalled(process.cwd());
if (claudePath && servers.length > 0) {
const cordonConfigPath = outputPath.replace(/\\/g, "/");
const nodePath = process.execPath.replace(/\\/g, "/");
const cordonScriptPath = (process.argv[1] ?? "").replace(/\\/g, "/");
if (!cordonScriptPath) {
process.stderr.write(
`\x1B[33mwarn\x1B[0m: could not detect cordon CLI script path. Skipping Claude Desktop patch.
Manually add this to your claude_desktop_config.json mcpServers:
"cordon": { "command": "${nodePath}", "args": ["<path-to-cordon.js>", "start", "--config", "${cordonConfigPath}"] }
`
);
return;
}
const newClaudeConfig = {
...claudeConfig,
mcpServers: {
cordon: {
command: nodePath,
args: [cordonScriptPath, "start", "--config", cordonConfigPath]
}
}
};
const backupPath = `${claudePath}.cordon-backup`;
if (existsSync3(backupPath)) {
process.stderr.write(
`[cordon] existing backup at ${backupPath} preserved (won't overwrite)
`
);
} else {
writeFileSync2(backupPath, readFileSync2(claudePath, "utf8"), "utf8");
process.stderr.write(`\x1B[32m\u2713\x1B[0m backed up Claude Desktop config to ${backupPath}
`);
}
writeFileSync2(claudePath, JSON.stringify(newClaudeConfig, null, 2), "utf8");
process.stderr.write(`\x1B[32m\u2713\x1B[0m patched Claude Desktop config
`);
process.stderr.write(
`
\x1B[36mRestart Claude Desktop to activate Cordon.\x1B[0m
`
);
} else if (!claudePath) {
const nodePath = process.execPath.replace(/\\/g, "/");
const cordonScriptPath = (process.argv[1] ?? "<path-to-cordon.js>").replace(/\\/g, "/");
process.stderr.write(
`
\x1B[33mwarn\x1B[0m: Claude Desktop config not found on this system.
Edit cordon.config.ts, then manually add Cordon to your MCP client config:
"mcpServers": {
"cordon": {
"command": "${nodePath}",
"args": ["${cordonScriptPath}", "start", "--config", "${outputPath.replace(/\\/g, "/")}"]
}
}
`
);
} else {
process.stderr.write(
`
Edit cordon.config.ts to add your MCP servers, then run \x1B[36mnpx cordon start\x1B[0m.
`
);
}
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
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 for MCP</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 for MCP. 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
var program = new Command();
program.name("cordon").description("Cordon for MCP \u2014 security gateway for MCP tool calls").version("0.1.0");
program.command("start").description("Start the Cordon gateway").option("-c, --config <path>", "Path to cordon.config.ts").action(startCommand);
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
{"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('Cordon for MCP — security gateway for MCP tool calls')\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: ${JSON.stringify(name)},\n transport: 'stdio',\n command: ${JSON.stringify(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 //\n // We bind the spawn to the *exact* node + cordon.js paths that ran this\n // init. Earlier versions wrote `npx.cmd` (or `npx`), which relies on\n // PATH lookup at spawn time. Claude Desktop's spawned subprocesses\n // inherit a stripped PATH on Windows that often lacks the user's\n // nvm/Node bin dir, so `npx.cmd` fails with \"is not recognized as an\n // internal or external command\". Using full paths skips PATH and the\n // cmd.exe wrapper entirely.\n if (claudePath && servers.length > 0) {\n const cordonConfigPath = outputPath.replace(/\\\\/g, '/');\n const nodePath = process.execPath.replace(/\\\\/g, '/');\n const cordonScriptPath = (process.argv[1] ?? '').replace(/\\\\/g, '/');\n\n if (!cordonScriptPath) {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: could not detect cordon CLI script path. ` +\n `Skipping Claude Desktop patch.\\n` +\n `Manually add this to your claude_desktop_config.json mcpServers:\\n` +\n ` \"cordon\": { \"command\": \"${nodePath}\", \"args\": [\"<path-to-cordon.js>\", \"start\", \"--config\", \"${cordonConfigPath}\"] }\\n`,\n );\n return;\n }\n\n const newClaudeConfig: ClaudeDesktopConfig = {\n ...claudeConfig,\n mcpServers: {\n cordon: {\n command: nodePath,\n args: [cordonScriptPath, 'start', '--config', cordonConfigPath],\n },\n },\n };\n\n // Backup the original — only if no backup exists yet, so re-running init\n // never overwrites the user's true pre-cordon config.\n const backupPath = `${claudePath}.cordon-backup`;\n if (existsSync(backupPath)) {\n process.stderr.write(\n `[cordon] existing backup at ${backupPath} preserved (won't overwrite)\\n`,\n );\n } else {\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\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 const nodePath = process.execPath.replace(/\\\\/g, '/');\n const cordonScriptPath = (process.argv[1] ?? '<path-to-cordon.js>').replace(/\\\\/g, '/');\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\": \"${nodePath}\",\\n` +\n ` \"args\": [\"${cordonScriptPath}\", \"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 for MCP</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 for MCP. 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"]}
import { ResolvedConfig } from 'cordon-sdk';
interface StartOptions {
config?: string;
}
declare function startCommand(options: StartOptions): Promise<void>;
declare function initCommand(): Promise<void>;
declare function findConfigPath(explicit?: string): Promise<string>;
declare function loadConfig(configPath: string): Promise<ResolvedConfig>;
export { findConfigPath, initCommand, loadConfig, startCommand };
// src/commands/start.ts
import { CordonGateway } from "@getcordon/core";
// src/config-loader.ts
import { existsSync } from "fs";
import { join } from "path";
import { homedir } from "os";
import { createJiti } from "jiti";
var SEARCH_PATHS = [
() => join(process.cwd(), "cordon.config.ts"),
() => join(process.cwd(), "cordon.config.js"),
() => join(homedir(), ".cordon", "config.ts"),
() => join(homedir(), ".cordon", "config.js")
];
async function findConfigPath(explicit) {
if (explicit) {
if (!existsSync(explicit)) {
throw new Error(`Config file not found: ${explicit}`);
}
return explicit;
}
for (const candidate of SEARCH_PATHS) {
const p = candidate();
if (existsSync(p)) return p;
}
throw new Error(
"No cordon config found. Run `cordon init` to create one, or pass --config <path>."
);
}
async function loadConfig(configPath) {
const jiti = createJiti(import.meta.url);
const mod = await jiti.import(configPath);
const raw = mod.default ?? mod;
if (!raw || typeof raw !== "object" || !Array.isArray(raw.servers)) {
throw new Error(
`Invalid config at ${configPath}: expected an object with a 'servers' array. Make sure you are using \`export default defineConfig({...})\`.`
);
}
return applyDefaults(raw);
}
function applyDefaults(config) {
return {
...config,
audit: config.audit ?? { enabled: true, output: "stdout" },
approvals: config.approvals ?? { channel: "terminal" }
};
}
function emptyConfig() {
return applyDefaults({ servers: [] });
}
// src/cli-state.ts
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(cordonDir(), "state.json");
}
function authPath() {
return join2(cordonDir(), "auth.json");
}
function ensureCordonDir() {
const dir = cordonDir();
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
}
function getState() {
const path = statePath();
if (!existsSync2(path)) return {};
try {
return JSON.parse(readFileSync(path, "utf8"));
} catch {
return {};
}
}
function setState(patch) {
try {
ensureCordonDir();
const merged = { ...getState(), ...patch };
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 && !getAuth()) {
process.stderr.write(
`
\x1B[36m[cordon] Want centralized audit logs + Slack approvals?\x1B[0m
[cordon] Run \`cordon login\` or register at ${DASHBOARD_URL}?utm_source=cli_start
`
);
setState({ welcomed: true });
}
let config = emptyConfig();
let configPath = null;
try {
configPath = await findConfigPath(options.config);
} catch (err) {
if (options.config) {
process.stderr.write(`\x1B[31merror\x1B[0m: ${String(err)}
`);
process.exit(1);
}
process.stderr.write(
"\x1B[33m[cordon] no cordon.config.ts found \u2014 starting with zero upstream servers.\x1B[0m\n[cordon] Run `cordon init` to generate a config and connect real MCP servers.\n"
);
}
if (configPath) {
process.stderr.write(`[cordon] loading config from ${configPath}
`);
try {
config = await loadConfig(configPath);
} catch (err) {
process.stderr.write(`\x1B[31merror\x1B[0m: ${String(err)}
`);
process.exit(1);
}
}
config = applyAuthDefaults(config);
const gateway = new CordonGateway(config);
const shutdown = async () => {
process.stderr.write("\n[cordon] shutting down...\n");
try {
await gateway.stop();
process.exit(0);
} catch (err) {
process.stderr.write(`\x1B[31merror\x1B[0m: shutdown failed: ${String(err)}
`);
process.exit(1);
}
};
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
try {
await gateway.start();
} catch (err) {
process.stderr.write(`\x1B[31merror\x1B[0m: gateway failed: ${String(err)}
`);
process.exit(1);
}
}
// src/commands/init.ts
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3 } from "fs";
import { spawnSync } from "child_process";
import { join as join3 } from "path";
import { homedir as homedir3 } from "os";
var DASHBOARD_URL2 = "https://cordon-server-production.up.railway.app/dashboard/";
function ensureCordonSdkInstalled(cwd) {
if (existsSync3(join3(cwd, "node_modules", "cordon-sdk", "package.json"))) {
return;
}
if (!existsSync3(join3(cwd, "package.json"))) {
writeFileSync2(
join3(cwd, "package.json"),
JSON.stringify({ name: "cordon-config", version: "0.0.0", private: true }, null, 2) + "\n",
"utf8"
);
process.stderr.write(`\x1B[32m\u2713\x1B[0m created package.json
`);
}
process.stderr.write(`[cordon] installing cordon-sdk...
`);
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
const result = spawnSync(npmCmd, ["install", "cordon-sdk"], {
cwd,
stdio: ["ignore", "inherit", "inherit"]
});
if (result.status === 0) {
process.stderr.write(`\x1B[32m\u2713\x1B[0m installed cordon-sdk
`);
} else {
process.stderr.write(
`\x1B[33mwarn\x1B[0m: could not auto-install cordon-sdk. Run 'npm install cordon-sdk' in this directory before 'cordon start'.
`
);
}
}
function getClaudeConfigPath() {
const candidates = [];
if (process.platform === "darwin") {
candidates.push(
join3(homedir3(), "Library", "Application Support", "Claude", "claude_desktop_config.json")
);
} else if (process.platform === "win32") {
const appData = process.env["APPDATA"] ?? join3(homedir3(), "AppData", "Roaming");
candidates.push(join3(appData, "Claude", "claude_desktop_config.json"));
} else {
candidates.push(join3(homedir3(), ".config", "Claude", "claude_desktop_config.json"));
}
return candidates.find((p) => existsSync3(p)) ?? null;
}
async function initCommand() {
const outputPath = join3(process.cwd(), "cordon.config.ts");
if (existsSync3(outputPath)) {
process.stderr.write(
`\x1B[33mwarn\x1B[0m: cordon.config.ts already exists \u2014 not overwriting.
`
);
process.exit(1);
}
const claudePath = getClaudeConfigPath();
let claudeConfig = {};
if (claudePath) {
process.stderr.write(`[cordon] found Claude Desktop config at ${claudePath}
`);
try {
claudeConfig = JSON.parse(readFileSync2(claudePath, "utf8"));
} catch {
process.stderr.write(`\x1B[33mwarn\x1B[0m: could not parse Claude Desktop config
`);
}
} else {
process.stderr.write(
`[cordon] no Claude Desktop config found \u2014 generating a blank config
`
);
}
const servers = Object.entries(claudeConfig.mcpServers ?? {});
const serverBlocks = servers.length > 0 ? servers.map(([name, cfg]) => {
const argsStr = cfg.args?.length ? `, args: ${JSON.stringify(cfg.args)}` : "";
const envStr = cfg.env && Object.keys(cfg.env).length ? `, env: ${JSON.stringify(cfg.env)}` : "";
return ` {
name: ${JSON.stringify(name)},
transport: 'stdio',
command: ${JSON.stringify(cfg.command)}${argsStr}${envStr},
policy: 'allow',
// tools: {
// execute: 'approve',
// delete: 'block',
// },
},`;
}).join("\n") : ` // {
// name: 'my-server',
// transport: 'stdio',
// command: 'npx',
// args: ['-y', '@my-org/my-mcp-server'],
// policy: 'allow',
// },`;
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';
export default defineConfig({
servers: [
${serverBlocks}
],
${auditBlock}
approvals: {
channel: 'terminal',
// timeoutMs: 60_000,
},
});
`;
writeFileSync2(outputPath, content, "utf8");
process.stderr.write(`\x1B[32m\u2713\x1B[0m wrote cordon.config.ts
`);
ensureCordonSdkInstalled(process.cwd());
if (claudePath && servers.length > 0) {
const cordonConfigPath = outputPath.replace(/\\/g, "/");
const nodePath = process.execPath.replace(/\\/g, "/");
const cordonScriptPath = (process.argv[1] ?? "").replace(/\\/g, "/");
if (!cordonScriptPath) {
process.stderr.write(
`\x1B[33mwarn\x1B[0m: could not detect cordon CLI script path. Skipping Claude Desktop patch.
Manually add this to your claude_desktop_config.json mcpServers:
"cordon": { "command": "${nodePath}", "args": ["<path-to-cordon.js>", "start", "--config", "${cordonConfigPath}"] }
`
);
return;
}
const newClaudeConfig = {
...claudeConfig,
mcpServers: {
cordon: {
command: nodePath,
args: [cordonScriptPath, "start", "--config", cordonConfigPath]
}
}
};
const backupPath = `${claudePath}.cordon-backup`;
if (existsSync3(backupPath)) {
process.stderr.write(
`[cordon] existing backup at ${backupPath} preserved (won't overwrite)
`
);
} else {
writeFileSync2(backupPath, readFileSync2(claudePath, "utf8"), "utf8");
process.stderr.write(`\x1B[32m\u2713\x1B[0m backed up Claude Desktop config to ${backupPath}
`);
}
writeFileSync2(claudePath, JSON.stringify(newClaudeConfig, null, 2), "utf8");
process.stderr.write(`\x1B[32m\u2713\x1B[0m patched Claude Desktop config
`);
process.stderr.write(
`
\x1B[36mRestart Claude Desktop to activate Cordon.\x1B[0m
`
);
} else if (!claudePath) {
const nodePath = process.execPath.replace(/\\/g, "/");
const cordonScriptPath = (process.argv[1] ?? "<path-to-cordon.js>").replace(/\\/g, "/");
process.stderr.write(
`
\x1B[33mwarn\x1B[0m: Claude Desktop config not found on this system.
Edit cordon.config.ts, then manually add Cordon to your MCP client config:
"mcpServers": {
"cordon": {
"command": "${nodePath}",
"args": ["${cordonScriptPath}", "start", "--config", "${outputPath.replace(/\\/g, "/")}"]
}
}
`
);
} else {
process.stderr.write(
`
Edit cordon.config.ts to add your MCP servers, then run \x1B[36mnpx cordon start\x1B[0m.
`
);
}
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
Run \x1B[36mcordon login\x1B[0m to register a free account, or sign up at ${DASHBOARD_URL2}?utm_source=cli_init
`
);
}
setState({ welcomed: true });
}
export {
findConfigPath,
initCommand,
loadConfig,
startCommand
};
//# sourceMappingURL=index.js.map
{"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: ${JSON.stringify(name)},\n transport: 'stdio',\n command: ${JSON.stringify(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 //\n // We bind the spawn to the *exact* node + cordon.js paths that ran this\n // init. Earlier versions wrote `npx.cmd` (or `npx`), which relies on\n // PATH lookup at spawn time. Claude Desktop's spawned subprocesses\n // inherit a stripped PATH on Windows that often lacks the user's\n // nvm/Node bin dir, so `npx.cmd` fails with \"is not recognized as an\n // internal or external command\". Using full paths skips PATH and the\n // cmd.exe wrapper entirely.\n if (claudePath && servers.length > 0) {\n const cordonConfigPath = outputPath.replace(/\\\\/g, '/');\n const nodePath = process.execPath.replace(/\\\\/g, '/');\n const cordonScriptPath = (process.argv[1] ?? '').replace(/\\\\/g, '/');\n\n if (!cordonScriptPath) {\n process.stderr.write(\n `\\x1b[33mwarn\\x1b[0m: could not detect cordon CLI script path. ` +\n `Skipping Claude Desktop patch.\\n` +\n `Manually add this to your claude_desktop_config.json mcpServers:\\n` +\n ` \"cordon\": { \"command\": \"${nodePath}\", \"args\": [\"<path-to-cordon.js>\", \"start\", \"--config\", \"${cordonConfigPath}\"] }\\n`,\n );\n return;\n }\n\n const newClaudeConfig: ClaudeDesktopConfig = {\n ...claudeConfig,\n mcpServers: {\n cordon: {\n command: nodePath,\n args: [cordonScriptPath, 'start', '--config', cordonConfigPath],\n },\n },\n };\n\n // Backup the original — only if no backup exists yet, so re-running init\n // never overwrites the user's true pre-cordon config.\n const backupPath = `${claudePath}.cordon-backup`;\n if (existsSync(backupPath)) {\n process.stderr.write(\n `[cordon] existing backup at ${backupPath} preserved (won't overwrite)\\n`,\n );\n } else {\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\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 const nodePath = process.execPath.replace(/\\\\/g, '/');\n const cordonScriptPath = (process.argv[1] ?? '<path-to-cordon.js>').replace(/\\\\/g, '/');\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\": \"${nodePath}\",\\n` +\n ` \"args\": [\"${cordonScriptPath}\", \"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"]}