- Container step: duration hint + 3-line rolling output window with
60s stall detector that offers "keep waiting" vs "ask Claude"
- First chat: reframed as a try-out with sandbox-model explainer
(wakes on message, sleeps when idle, context persists)
- Timezone: auto-detected non-UTC zones now get an explicit
confirm from the user instead of silent persist
- Outro: added always-on warning + prominent "check your DM" banner
when a channel was configured; directive last line
- Discord: always show token-location reminder even when user says
they have one; new "do you have a server?" branch walks through
server creation if not
- All select prompts: custom brightSelect renderer keeps inactive
option labels at full brightness (was dim gray); adds @clack/core
as a direct dep
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Trunk ships no channel adapters — /add-telegram installs the package on demand from the channels branch. This dependency was stale and pulled ~2 transitive packages into every fresh install.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Major version for the v2 rewrite. CHANGELOG documents the breaking
changes users will hit on upgrade: new entity model, two-DB session
split, `bash nanoclaw.sh` as default install, channels/providers
relocated to sibling branches, three-level isolation, Apple Container
removed from default setup.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wraps the scripted setup flow in a branded, friendly UI. Each step runs
under a clack spinner with elapsed time; child stdout/stderr is captured
quietly and dumped only on failure. Interactive children (token paste,
Anthropic OAuth) bypass the spinner and inherit the TTY.
- intro: NanoClaw wordmark + brand-cyan accent chip, truecolor with
kleur fallback and NO_COLOR / non-TTY awareness
- pair-telegram: emits PAIR_TELEGRAM_CODE / _ATTEMPT status blocks only;
auto.ts renders clack notes + "received X — doesn't match" checkpoints
- streaming status-block parser handles mid-step events without waiting
for the child to exit
- terminal-block detection now finds any block with a STATUS field
(handles MOUNTS emitting CONFIGURE_MOUNTS, etc.) and treats 'skipped'
as a success variant with an optional friendlier label
Also fixes a latent bash bug where `$VAR…` (unbraced followed by a
multi-byte Unicode character) pulled ellipsis bytes into the variable
name lookup and tripped `set -u`. Braced `${VAR}` in add-telegram.sh
and register-claude-token.sh.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`pnpm run setup:auto` chains the deterministic setup steps (environment
→ timezone → container → mounts → service → verify) by spawning the
existing per-step CLI and parsing its status blocks. Config via env:
NANOCLAW_TZ, NANOCLAW_SKIP.
Credentials + channel install + /manage-channels stay interactive —
verify reports what's left and exits 0 rather than failing the driver.
Also have the container step try to start Docker when it's installed
but not running (open -a Docker on macOS, sudo systemctl start docker
on Linux) and poll `docker info` for up to 60s before giving up. Both
/setup and setup:auto pick this up automatically.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First default channel that ships with main. Unix-socket adapter + thin
client; plugs into the running daemon rather than spawning its own host.
## src/channels/cli.ts
- ChannelAdapter with channelType='cli', platformId='local'.
- setup() unlinks any stale socket, listens on $DATA_DIR/cli.sock (mode 0600
so only the local user can connect).
- On client connect: reads newline-delimited JSON ({"text": "..."}) and
calls config.onInbound('local', null, {id, kind:'chat', content, ts}).
- deliver() writes {"text": <body>} back to the connected socket; silently
no-ops when no client is attached (outbound row still persists).
- Single-client policy: a second connection supersedes the first with a
[superseded] notice.
- teardown() closes the client, closes the server, removes the socket file.
## scripts/chat.ts + pnpm run chat
One-shot client:
- pnpm run chat <message...>
- Connects to the socket, writes one JSON line with the message.
- Reads replies; exits 2s after the first reply lands (hard timeout 120s).
- ENOENT/ECONNREFUSED prints a hint to start the daemon.
## scripts/init-first-agent.ts
- Fix stale imports after earlier module extractions (permissions +
agent-to-agent moved their DB helpers into modules/).
- After wiring the DM channel, also create cli/local messaging_group
(unknown_sender_policy='public' — local socket perms handle auth) and
wire it to the same agent. User can `pnpm run chat` immediately.
## package.json
- Add "chat": "tsx scripts/chat.ts" script.
## Validation
- pnpm run build clean.
- pnpm test — 137 host tests pass.
- bun test in container/agent-runner — 17 pass.
- Service boot logs: "CLI channel listening" + "Channel adapter started
channel=cli type=cli". Clean SIGTERM shutdown; socket file removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
setup/groups.ts is whatsapp-only — its inline syncScript imports baileys
and pino to fetch group metadata via Baileys.groupFetchAllParticipating.
On trunk it was a no-op for non-whatsapp users (returned early without
auth) and the only thing keeping pino alive.
Removed:
- setup/groups.ts (lives on `channels` branch; restored by /add-whatsapp-v2)
- `groups` STEPS entry from setup/index.ts
- pino from package.json (no longer used outside the moved file)
/add-whatsapp-v2 skill updated to copy setup/groups.ts and register both
groups + whatsapp-auth in setup/index.ts STEPS, install pino@9.6.0 along
with baileys + qrcode.
Verified: build clean, 326 host tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>