feat(setup): prompt for display name, hardcode agent persona

Before the cli-agent step, ask the operator what the agent should
call them (defaults to \$USER). The agent's own persona name is
hardcoded to "Terminal Agent" — this is the scratch CLI agent, not
one of the operator's real personas. NANOCLAW_DISPLAY_NAME still
skips the prompt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-21 23:46:49 +03:00
parent 81838bbb34
commit d02001e144

View File

@@ -7,8 +7,9 @@
* module check). This driver picks up from there. * module check). This driver picks up from there.
* *
* Config via env: * Config via env:
* NANOCLAW_DISPLAY_NAME operator name for the CLI agent (default: $USER) * NANOCLAW_DISPLAY_NAME operator name for the CLI agent — skips the
* NANOCLAW_AGENT_NAME agent persona name (default: display name) * interactive prompt before cli-agent. If unset,
* the driver asks, defaulting to $USER.
* NANOCLAW_SKIP comma-separated step names to skip * NANOCLAW_SKIP comma-separated step names to skip
* (environment|container|onecli|auth| * (environment|container|onecli|auth|
* mounts|service|cli-agent|verify) * mounts|service|cli-agent|verify)
@@ -24,6 +25,9 @@
* and `/manage-channels` after this driver completes. * and `/manage-channels` after this driver completes.
*/ */
import { spawn, spawnSync } from 'child_process'; import { spawn, spawnSync } from 'child_process';
import { createInterface } from 'readline/promises';
const CLI_AGENT_NAME = 'Terminal Agent';
type Fields = Record<string, string>; type Fields = Record<string, string>;
type StepResult = { ok: boolean; fields: Fields; exitCode: number }; type StepResult = { ok: boolean; fields: Fields; exitCode: number };
@@ -114,6 +118,18 @@ function anthropicSecretExists(): boolean {
} }
} }
async function askDisplayName(fallback: string): Promise<string> {
const rl = createInterface({ input: process.stdin, output: process.stdout });
try {
const answer = await rl.question(
`\nWhat should the agent call you? [${fallback}]: `,
);
return answer.trim() || fallback;
} finally {
rl.close();
}
}
function runBashScript(relPath: string): Promise<number> { function runBashScript(relPath: string): Promise<number> {
return new Promise((resolve) => { return new Promise((resolve) => {
const child = spawn('bash', [relPath], { stdio: 'inherit' }); const child = spawn('bash', [relPath], { stdio: 'inherit' });
@@ -223,19 +239,20 @@ async function main(): Promise<void> {
} }
if (!skip.has('cli-agent')) { if (!skip.has('cli-agent')) {
const displayName = const fallback = process.env.USER?.trim() || 'Operator';
process.env.NANOCLAW_DISPLAY_NAME?.trim() || const preset = process.env.NANOCLAW_DISPLAY_NAME?.trim();
process.env.USER?.trim() || const displayName = preset || (await askDisplayName(fallback));
'Operator';
const agentName = process.env.NANOCLAW_AGENT_NAME?.trim();
const args = ['--display-name', displayName];
if (agentName) args.push('--agent-name', agentName);
const res = await runStep('cli-agent', args); const res = await runStep('cli-agent', [
'--display-name',
displayName,
'--agent-name',
CLI_AGENT_NAME,
]);
if (!res.ok) { if (!res.ok) {
fail( fail(
'CLI agent wiring failed', 'CLI agent wiring failed',
'Re-run `pnpm exec tsx scripts/init-cli-agent.ts --display-name "<your name>"` to fix.', `Re-run \`pnpm exec tsx scripts/init-cli-agent.ts --display-name "${displayName}" --agent-name "${CLI_AGENT_NAME}"\` to fix.`,
); );
} }
} }