feat(setup): optional Telegram wiring in setup:auto

After cli-agent, prompt the user to connect a messaging app. For now
only Telegram is offered; "skip" falls through to the existing CLI
flow.

setup/add-telegram.sh runs the scriptable half of /add-telegram: fetch
the channels branch, copy the adapter + pair-telegram files, append
the self-registration import, install @chat-adapter/telegram@4.26.0
(pinned to match the skill), rebuild, collect TELEGRAM_BOT_TOKEN via
silent paste, write .env + data/env/env, and kick the service so the
new adapter is live. Idempotent throughout.

setup:auto then runs the existing `pair-telegram` step with
--intent main. The step emits the 4-digit code in its status stream,
which is already forwarded to stdout by runStep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-22 00:04:14 +03:00
parent c87cd250b2
commit 9c7e1d02af
3 changed files with 178 additions and 3 deletions

View File

@@ -11,8 +11,8 @@
* interactive prompt before cli-agent. If unset,
* the driver asks, defaulting to $USER.
* NANOCLAW_SKIP comma-separated step names to skip
* (environment|container|onecli|auth|
* mounts|service|cli-agent|verify)
* (environment|container|onecli|auth|mounts|
* service|cli-agent|channel|verify)
*
* Timezone is not configured here — it defaults to the host system's TZ.
* Run `pnpm exec tsx setup/index.ts --step timezone -- --tz <zone>` later
@@ -130,6 +130,19 @@ async function askDisplayName(fallback: string): Promise<string> {
}
}
async function askChannelChoice(): Promise<'telegram' | 'skip'> {
const rl = createInterface({ input: process.stdin, output: process.stdout });
try {
console.log('\nConnect a messaging app so you can chat from your phone?');
console.log(' 1) Telegram');
console.log(' 2) Skip — just use the CLI for now');
const answer = (await rl.question('Choose [1/2]: ')).trim();
return answer === '1' ? 'telegram' : 'skip';
} finally {
rl.close();
}
}
function runBashScript(relPath: string): Promise<number> {
return new Promise((resolve) => {
const child = spawn('bash', [relPath], { stdio: 'inherit' });
@@ -257,6 +270,34 @@ async function main(): Promise<void> {
}
}
if (!skip.has('channel')) {
const choice = await askChannelChoice();
if (choice === 'telegram') {
const installCode = await runBashScript('setup/add-telegram.sh');
if (installCode !== 0) {
fail(
'Telegram install failed.',
'Re-run `bash setup/add-telegram.sh`, then `pnpm exec tsx setup/index.ts --step pair-telegram -- --intent main`.',
);
}
console.log(
'\n[setup:auto] Pairing Telegram. A 4-digit code will appear below.\n' +
' From Telegram, send just those 4 digits to your bot\n' +
' (DM the bot for a personal chat, or prefix with your\n' +
' bot handle in a group with privacy on).\n',
);
const pair = await runStep('pair-telegram', ['--intent', 'main']);
if (!pair.ok) {
fail(
'Telegram pairing failed.',
'Re-run `pnpm exec tsx setup/index.ts --step pair-telegram -- --intent main`.',
);
}
}
}
if (!skip.has('verify')) {
const res = await runStep('verify');
if (!res.ok) {