refactor(cli): rename nc to ncl

Rename the CLI binary, socket path, container wrapper, error prefixes,
and all references from `nc` to `ncl`. Add ~/.local/bin symlink during
setup and pnpm script alias.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-05-08 15:56:09 +03:00
parent 33cbf59dd8
commit 0855369b79
15 changed files with 89 additions and 50 deletions

View File

@@ -1,19 +1,19 @@
/**
* `nc` binary entry point.
* `ncl` binary entry point.
*
* Parses argv, builds a request frame, sends it via the picked transport,
* formats the response, exits non-zero on error.
*
* Usage:
* nc <resource> <verb> [target] [--key value ...] [--json]
* ncl <resource> <verb> [target] [--key value ...] [--json]
*
* Examples:
* nc groups list
* nc groups get abc123
* nc groups create --name foo --folder bar
* nc groups update abc123 --name baz
* nc help
* nc groups help
* ncl groups list
* ncl groups get abc123
* ncl groups create --name foo --folder bar
* ncl groups update abc123 --name baz
* ncl help
* ncl groups help
*/
import { randomUUID } from 'crypto';
@@ -80,14 +80,14 @@ function parseArgv(argv: string[]): {
}
if (positional.length === 0) {
process.stderr.write('nc: missing command\n');
process.stderr.write('ncl: missing command\n');
printUsage();
process.exit(2);
}
// Single word: `nc help`
// Two words: `nc groups list`, `nc groups help`
// Three words: `nc groups get abc123`
// Single word: `ncl help`
// Two words: `ncl groups list`, `ncl groups help`
// Three words: `ncl groups get abc123`
let command: string;
if (positional.length === 1) {
command = positional[0];
@@ -106,9 +106,9 @@ function parseArgv(argv: string[]): {
function printUsage(): void {
process.stdout.write(
[
'Usage: nc <resource> <verb> [target] [--key value ...] [--json]',
'Usage: ncl <resource> <verb> [target] [--key value ...] [--json]',
'',
'Run `nc help` to list available resources and commands.',
'Run `ncl help` to list available resources and commands.',
'',
].join('\n'),
);
@@ -118,7 +118,7 @@ function formatTransportError(e: unknown): string {
const msg = e instanceof Error ? e.message : String(e);
if (msg.includes('ENOENT') || msg.includes('ECONNREFUSED')) {
return [
`nc: cannot reach NanoClaw host (${msg}).`,
`ncl: cannot reach NanoClaw host (${msg}).`,
`Is the host running? Start it with: pnpm run dev`,
`Or, if installed as a service:`,
` macOS: launchctl kickstart -k gui/$(id -u)/com.nanoclaw`,
@@ -126,10 +126,10 @@ function formatTransportError(e: unknown): string {
``,
].join('\n');
}
return `nc: transport error: ${msg}\n`;
return `ncl: transport error: ${msg}\n`;
}
main().catch((err) => {
process.stderr.write(`nc: unexpected error: ${err instanceof Error ? err.message : String(err)}\n`);
process.stderr.write(`ncl: unexpected error: ${err instanceof Error ? err.message : String(err)}\n`);
process.exit(2);
});

View File

@@ -1,8 +1,8 @@
/**
* Built-in help command. Introspects the resource and command registries.
*
* nc help — list all resources and commands
* nc groups help — show group resource details (verbs, columns, enums)
* ncl help — list all resources and commands
* ncl groups help — show group resource details (verbs, columns, enums)
*/
import { getResource, getResources } from '../crud.js';
import { listCommands, register } from '../registry.js';
@@ -41,7 +41,7 @@ register({
}
lines.push('');
lines.push('Run `nc <resource> help` for detailed field information.');
lines.push('Run `ncl <resource> help` for detailed field information.');
return lines.join('\n');
},
});

View File

@@ -3,7 +3,7 @@
*
* Takes a declarative resource definition (table, columns, access levels)
* and auto-registers list/get/create/update/delete commands in the CLI
* registry. Column metadata doubles as documentation — `nc <resource> help`
* registry. Column metadata doubles as documentation — `ncl <resource> help`
* is generated from the same definitions.
*/
import { randomUUID } from 'crypto';

View File

@@ -1,5 +1,5 @@
/**
* Output formatting for the `nc` binary. Two modes:
* Output formatting for the `ncl` binary. Two modes:
* - human (default): a small auto-table for arrays of flat records,
* JSON.stringify for everything else, plain "error: ..." line for !ok.
* - json: the response frame, pretty-printed.

View File

@@ -1,5 +1,5 @@
/**
* Command registry — single source of truth for what `nc` can do.
* Command registry — single source of truth for what `ncl` can do.
*
* Each command file under `commands/` calls `register()` at top level,
* and `commands/index.ts` imports them all for side effects so the

View File

@@ -1,5 +1,5 @@
/**
* SocketTransport — client side. Used by the `nc` binary when running on
* SocketTransport — client side. Used by the `ncl` binary when running on
* the host (i.e. invoked from a shell or by Claude in the project).
*
* Wire format: line-delimited JSON. One request per connection; the server
@@ -12,7 +12,7 @@ import { DATA_DIR } from '../config.js';
import type { RequestFrame, ResponseFrame } from './frame.js';
import type { Transport } from './transport.js';
export const DEFAULT_SOCKET_PATH = path.join(DATA_DIR, 'nc.sock');
export const DEFAULT_SOCKET_PATH = path.join(DATA_DIR, 'ncl.sock');
export class SocketTransport implements Transport {
constructor(private readonly socketPath: string = DEFAULT_SOCKET_PATH) {}

View File

@@ -3,7 +3,7 @@
* per connection, calls dispatch() with caller='host', writes the response
* frame, closes.
*
* Lives at data/nc.sock (separate from data/cli.sock, which the existing
* Lives at data/ncl.sock (separate from data/cli.sock, which the existing
* chat-style CLI channel adapter owns). Socket file is chmod 0600 — only
* the user that started the host can connect.
*/
@@ -25,7 +25,7 @@ export async function startCliServer(socketPath: string = DEFAULT_SOCKET_PATH):
} catch (err) {
const e = err as NodeJS.ErrnoException;
if (e.code !== 'ENOENT') {
log.warn('Failed to unlink stale nc socket (will try to bind anyway)', { socketPath, err });
log.warn('Failed to unlink stale ncl socket (will try to bind anyway)', { socketPath, err });
}
}
@@ -37,9 +37,9 @@ export async function startCliServer(socketPath: string = DEFAULT_SOCKET_PATH):
try {
fs.chmodSync(socketPath, 0o600);
} catch (err) {
log.warn('Failed to chmod nc socket (continuing)', { socketPath, err });
log.warn('Failed to chmod ncl socket (continuing)', { socketPath, err });
}
log.info('nc CLI server listening', { socketPath });
log.info('ncl CLI server listening', { socketPath });
resolve();
});
});
@@ -65,7 +65,7 @@ function handleConnection(conn: net.Socket): void {
}
});
conn.on('error', (err) => {
log.warn('nc CLI server connection error', { err });
log.warn('ncl CLI server connection error', { err });
});
}
@@ -87,7 +87,7 @@ async function handleFrame(conn: net.Socket, line: string): Promise<void> {
return;
}
// Host caller — connecting to data/nc.sock requires file-system access
// Host caller — connecting to data/ncl.sock requires file-system access
// to a 0600 socket owned by the host user, so we treat the socket path
// itself as the auth boundary.
const ctx: CallerContext = { caller: 'host' };
@@ -100,7 +100,7 @@ function write(conn: net.Socket, frame: ResponseFrame): void {
conn.write(JSON.stringify(frame) + '\n');
conn.end();
} catch (err) {
log.warn('Failed to write nc CLI response', { err });
log.warn('Failed to write ncl CLI response', { err });
}
}

View File

@@ -1,5 +1,5 @@
/**
* Client-side transport interface. The `nc` binary picks one of these and
* Client-side transport interface. The `ncl` binary picks one of these and
* calls sendFrame; the caller doesn't know whether bytes traveled over a
* Unix socket (host) or through outbound.db / inbound.db rows (container).
*/

View File

@@ -53,7 +53,7 @@ import './channels/index.js';
// append registry-based modules. Imported for side effects (registrations).
import './modules/index.js';
// CLI command barrel — populates the `nc` registry before the CLI server
// CLI command barrel — populates the `ncl` registry before the CLI server
// accepts connections.
import './cli/commands/index.js';
import './cli/delivery-action.js';
@@ -169,7 +169,7 @@ async function main(): Promise<void> {
startHostSweep();
log.info('Host sweep started');
// 7. Start the `nc` CLI socket server (data/nc.sock).
// 7. Start the `ncl` CLI socket server (data/ncl.sock).
await startCliServer();
log.info('NanoClaw running');