#!/usr/bin/env node // Conduit client — thin CLI wrapper for Claude to call the conduit server. // Usage: // node client/index.mjs --secrets /path/to/secrets.json --user agent '{"action": "list-actions"}' // node client/index.mjs --secrets /path/to/secrets.json --user agent '{"action":' '"edit-file",' '"filename": "/workspace/foo.mjs"}' import { readFileSync } from 'fs'; import { sign_request } from './auth.mjs'; const BASE_URL = process.env.CONDUIT_URL || 'http://localhost:3015'; function get_arg(argv, flag) { const i = argv.indexOf(flag); return i !== -1 ? argv[i + 1] : null; } function get_remaining(argv) { // Collect all args that aren't --secrets or --user and their values const result = []; let i = 2; while (i < argv.length) { if (argv[i] === '--secrets' || argv[i] === '--user') { i += 2; } else { result.push(argv[i]); i++; } } return result; } async function call_action(payload, auth_headers) { const body_string = JSON.stringify(payload); const res = await fetch(`${BASE_URL}/action`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...auth_headers(body_string) }, body: body_string, }); const body = await res.json(); return { status: res.status, body }; } async function main() { const secrets_path = get_arg(process.argv, '--secrets'); const username = get_arg(process.argv, '--user'); if (!secrets_path || !username) { console.error('Usage: conduit --secrets --user '); process.exit(1); } let secrets; try { secrets = JSON.parse(readFileSync(secrets_path, 'utf8')); } catch (err) { console.error(`Cannot read secrets file: ${err.message}`); process.exit(1); } const user_entry = secrets.users?.[username]; if (!user_entry) { console.error(`User '${username}' not found in secrets file`); process.exit(1); } const remaining = get_remaining(process.argv); if (!remaining.length) { console.error('Usage: conduit --secrets --user '); process.exit(1); } let payload; try { payload = JSON.parse(remaining.join(' ')); } catch (err) { console.error(`Invalid JSON payload: ${err.message}`); process.exit(1); } const auth_headers = (body_string) => sign_request(user_entry.secret, username, body_string); const { status, body } = await call_action(payload, auth_headers); console.log(JSON.stringify(body, null, 2)); process.exit(status >= 400 ? 1 : 0); } main().catch((err) => { console.error('Conduit error:', err.message); process.exit(1); });