diff --git a/.claude/skills/add-atomic-chat-tool/SKILL.md b/.claude/skills/add-atomic-chat-tool/SKILL.md index 6a6d85862..24fcf9613 100644 --- a/.claude/skills/add-atomic-chat-tool/SKILL.md +++ b/.claude/skills/add-atomic-chat-tool/SKILL.md @@ -182,9 +182,12 @@ ATOMIC_CHAT_API_KEY=sk-... ### Restart the service +Run from your NanoClaw project root: + ```bash -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# Linux: systemctl --user restart $(systemd_unit) ``` ## Phase 4: Verify diff --git a/.claude/skills/add-dashboard/SKILL.md b/.claude/skills/add-dashboard/SKILL.md index c891563ef..6f3ea7e07 100644 --- a/.claude/skills/add-dashboard/SKILL.md +++ b/.claude/skills/add-dashboard/SKILL.md @@ -93,10 +93,13 @@ Generate the secret: `node -e "console.log('nc-' + require('crypto').randomBytes ### 6. Build and restart +Run from your NanoClaw project root: + ```bash pnpm run build -systemctl --user restart nanoclaw # Linux -# or: launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS +source setup/lib/install-slug.sh +systemctl --user restart $(systemd_unit) # Linux +# or: launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS ``` ### 7. Verify diff --git a/.claude/skills/add-deltachat/REMOVE.md b/.claude/skills/add-deltachat/REMOVE.md index 7cb2d3109..7765cb698 100644 --- a/.claude/skills/add-deltachat/REMOVE.md +++ b/.claude/skills/add-deltachat/REMOVE.md @@ -23,14 +23,17 @@ DC_SMTP_PORT ## 3. Rebuild and restart +Run from your NanoClaw project root: + ```bash pnpm run build +source setup/lib/install-slug.sh # Linux -systemctl --user restart nanoclaw +systemctl --user restart $(systemd_unit) # macOS -launchctl kickstart -k gui/$(id -u)/com.nanoclaw +launchctl kickstart -k gui/$(id -u)/$(launchd_label) ``` ## 4. Remove account data (optional) diff --git a/.claude/skills/add-deltachat/SKILL.md b/.claude/skills/add-deltachat/SKILL.md index 3dd5df6be..9f06e07fe 100644 --- a/.claude/skills/add-deltachat/SKILL.md +++ b/.claude/skills/add-deltachat/SKILL.md @@ -98,12 +98,16 @@ The `/set-avatar` command (send an image with that caption) is the easiest way t ### Restart +Run from your NanoClaw project root: + ```bash +source setup/lib/install-slug.sh + # Linux -systemctl --user restart nanoclaw +systemctl --user restart $(systemd_unit) # macOS -launchctl kickstart -k gui/$(id -u)/com.nanoclaw +launchctl kickstart -k gui/$(id -u)/$(launchd_label) ``` On first start the adapter configures the email account (IMAP/SMTP credentials, calls `configure()`). Subsequent starts skip straight to `startIo()`. Account data is stored in `dc-account/` in the project root (or your `DC_ACCOUNT_DIR`). @@ -232,7 +236,7 @@ Set `DC_SMTP_SECURITY=1` and `DC_SMTP_PORT=465` in `.env`, then restart. ```bash rm -f dc-account/accounts.lock -systemctl --user restart nanoclaw +systemctl --user restart "$(. setup/lib/install-slug.sh && systemd_unit)" ``` ### Bot not responding after restart diff --git a/.claude/skills/add-emacs/SKILL.md b/.claude/skills/add-emacs/SKILL.md index 4a24eca52..1a64a5cd6 100644 --- a/.claude/skills/add-emacs/SKILL.md +++ b/.claude/skills/add-emacs/SKILL.md @@ -162,10 +162,13 @@ If you changed `EMACS_CHANNEL_PORT` from the default: ## Restart NanoClaw +Run from your NanoClaw project root: + ```bash pnpm run build -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# systemctl --user restart nanoclaw # Linux +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# systemctl --user restart $(systemd_unit) # Linux ``` ## Verify @@ -240,7 +243,7 @@ grep -q "import './emacs.js'" src/channels/index.ts && echo "imported" || echo " ### No response from agent -1. NanoClaw running: `launchctl list | grep nanoclaw` (macOS) / `systemctl --user status nanoclaw` (Linux) +1. NanoClaw running: `launchctl list | grep "$(. setup/lib/install-slug.sh && launchd_label)"` (macOS) / `systemctl --user status "$(. setup/lib/install-slug.sh && systemd_unit)"` (Linux) 2. Messaging group wired: `pnpm exec tsx scripts/q.ts data/v2.db "SELECT mg.platform_id, ag.folder FROM messaging_groups mg JOIN messaging_group_agents mga ON mg.id = mga.messaging_group_id JOIN agent_groups ag ON ag.id = mga.agent_group_id WHERE mg.channel_type = 'emacs'"` 3. Logs show inbound: `grep 'channel_type=emacs\|Emacs' logs/nanoclaw.log | tail -20` @@ -282,13 +285,16 @@ If an agent outputs org-mode directly, markers get double-converted and render i ## Removal +Run from your NanoClaw project root: + ```bash rm src/channels/emacs.ts src/channels/emacs.test.ts emacs/nanoclaw.el # Remove the `import './emacs.js';` line from src/channels/index.ts # Remove EMACS_* lines from .env pnpm run build -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# systemctl --user restart nanoclaw # Linux +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# systemctl --user restart $(systemd_unit) # Linux # Remove the NanoClaw block from your Emacs config # Optionally clean up the messaging group: diff --git a/.claude/skills/add-gcal-tool/SKILL.md b/.claude/skills/add-gcal-tool/SKILL.md index 04cebff2b..077f39f7d 100644 --- a/.claude/skills/add-gcal-tool/SKILL.md +++ b/.claude/skills/add-gcal-tool/SKILL.md @@ -175,8 +175,14 @@ Run from your NanoClaw project root (where `data/v2.db` lives). The `$[#]` place ```bash pnpm run build -systemctl --user restart nanoclaw # Linux -# launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS +``` + +Run from your NanoClaw project root: + +```bash +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux ``` Kill any existing agent containers so they respawn with the new mcpServers config: @@ -220,7 +226,7 @@ Common signals: WHERE agent_group_id = '';" ``` 3. Remove `CALENDAR_MCP_VERSION` ARG and the calendar package from the Dockerfile install block. -4. `pnpm run build && ./container/build.sh && systemctl --user restart nanoclaw`. +4. `pnpm run build && ./container/build.sh && systemctl --user restart "$(. setup/lib/install-slug.sh && systemd_unit)"`. 5. Optional: `rm -rf ~/.calendar-mcp/` and `onecli apps disconnect --provider google-calendar`. No `TOOL_ALLOWLIST` removal step — Phase 2 no longer edits it. diff --git a/.claude/skills/add-github/SKILL.md b/.claude/skills/add-github/SKILL.md index 2441f13f6..99c19e738 100644 --- a/.claude/skills/add-github/SKILL.md +++ b/.claude/skills/add-github/SKILL.md @@ -136,7 +136,15 @@ Use `per-thread` session mode so each PR/issue gets its own agent session. If you're in the middle of `/setup`, return to the setup flow now. -Otherwise, restart the service (`systemctl --user restart nanoclaw` or `launchctl kickstart -k gui/$(id -u)/com.nanoclaw`) to pick up the new channel. +Otherwise, restart the service to pick up the new channel. + +Run from your NanoClaw project root: + +```bash +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux +``` ## Channel Info diff --git a/.claude/skills/add-gmail-tool/SKILL.md b/.claude/skills/add-gmail-tool/SKILL.md index 3111cfcf9..e1d4899dc 100644 --- a/.claude/skills/add-gmail-tool/SKILL.md +++ b/.claude/skills/add-gmail-tool/SKILL.md @@ -192,8 +192,14 @@ Run from your NanoClaw project root (where `data/v2.db` lives). The `$[#]` place ```bash pnpm run build -systemctl --user restart nanoclaw # Linux -# launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS +``` + +Run from your NanoClaw project root: + +```bash +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux ``` ## Phase 5: Verify @@ -235,7 +241,7 @@ Common signals: WHERE agent_group_id = '';" ``` 3. Remove the `GMAIL_MCP_VERSION` ARG and the `pnpm install -g @gongrzhe/server-gmail-autoauth-mcp` block from `container/Dockerfile`. -4. `pnpm run build && ./container/build.sh && systemctl --user restart nanoclaw`. +4. `pnpm run build && ./container/build.sh && systemctl --user restart "$(. setup/lib/install-slug.sh && systemd_unit)"`. 5. (Optional) `rm -rf ~/.gmail-mcp/` if no other host-side tool needs the stubs. 6. (Optional) Disconnect Gmail in OneCLI: `onecli apps disconnect --provider gmail`. diff --git a/.claude/skills/add-karpathy-llm-wiki/SKILL.md b/.claude/skills/add-karpathy-llm-wiki/SKILL.md index 79bfed958..304a091c5 100644 --- a/.claude/skills/add-karpathy-llm-wiki/SKILL.md +++ b/.claude/skills/add-karpathy-llm-wiki/SKILL.md @@ -75,9 +75,12 @@ If yes, ask the agent to schedule the lint task using the `schedule_task` MCP to ## Step 6: Restart +Run from your NanoClaw project root: + ```bash -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux ``` Tell the user to test by sending a source to the wiki group. diff --git a/.claude/skills/add-linear/SKILL.md b/.claude/skills/add-linear/SKILL.md index 237aaa086..477777595 100644 --- a/.claude/skills/add-linear/SKILL.md +++ b/.claude/skills/add-linear/SKILL.md @@ -156,7 +156,15 @@ The `platform_id` must be `linear:` matching the `LINEAR_TEAM_KEY` env If you're in the middle of `/setup`, return to the setup flow now. -Otherwise, restart the service (`systemctl --user restart nanoclaw` or `launchctl kickstart -k gui/$(id -u)/com.nanoclaw`) to pick up the new channel. +Otherwise, restart the service to pick up the new channel. + +Run from your NanoClaw project root: + +```bash +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux +``` ## Channel Info diff --git a/.claude/skills/add-mnemon/SKILL.md b/.claude/skills/add-mnemon/SKILL.md index db0d0299f..f6ab05582 100644 --- a/.claude/skills/add-mnemon/SKILL.md +++ b/.claude/skills/add-mnemon/SKILL.md @@ -89,9 +89,12 @@ docker run --rm --entrypoint mnemon nanoclaw-agent:latest --version ### Restart the service +Run from your NanoClaw project root: + ```bash -systemctl --user restart nanoclaw # Linux -# launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS +source setup/lib/install-slug.sh +systemctl --user restart $(systemd_unit) # Linux +# launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS ``` ### Confirm mnemon hooks are registered diff --git a/.claude/skills/add-ollama-provider/SKILL.md b/.claude/skills/add-ollama-provider/SKILL.md index fe42249a9..740818b2e 100644 --- a/.claude/skills/add-ollama-provider/SKILL.md +++ b/.claude/skills/add-ollama-provider/SKILL.md @@ -130,12 +130,15 @@ file, not from env vars. This file is bind-mounted into the container as `~/.cla ## 5. Build and restart +Run from your NanoClaw project root: + ```bash export PATH="/opt/homebrew/bin:$PATH" pnpm run build -launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist -launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl unload ~/Library/LaunchAgents/$(launchd_label).plist +launchctl load ~/Library/LaunchAgents/$(launchd_label).plist +# Linux: systemctl --user restart $(systemd_unit) ``` ## 6. Verify diff --git a/.claude/skills/add-ollama-tool/SKILL.md b/.claude/skills/add-ollama-tool/SKILL.md index 3c94e75f4..0c0baeae3 100644 --- a/.claude/skills/add-ollama-tool/SKILL.md +++ b/.claude/skills/add-ollama-tool/SKILL.md @@ -122,9 +122,12 @@ OLLAMA_HOST=http://your-ollama-host:11434 ### Restart the service +Run from your NanoClaw project root: + ```bash -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux ``` ## Phase 4: Verify diff --git a/.claude/skills/add-parallel/SKILL.md b/.claude/skills/add-parallel/SKILL.md index c391f5309..77ce3297c 100644 --- a/.claude/skills/add-parallel/SKILL.md +++ b/.claude/skills/add-parallel/SKILL.md @@ -229,19 +229,22 @@ echo '{}' | docker run -i --entrypoint /bin/echo nanoclaw-agent:latest "Containe ### 7. Restart Service -Rebuild the main app and restart: +Rebuild the main app and restart. + +Run from your NanoClaw project root: ```bash pnpm run build -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# Linux: systemctl --user restart $(systemd_unit) ``` Wait 3 seconds for service to start, then verify: ```bash sleep 3 -launchctl list | grep nanoclaw # macOS -# Linux: systemctl --user status nanoclaw +launchctl list | grep "$(. setup/lib/install-slug.sh && launchd_label)" # macOS +# Linux: systemctl --user status "$(. setup/lib/install-slug.sh && systemd_unit)" ``` ### 8. Test Integration @@ -287,4 +290,4 @@ To remove Parallel AI integration: 2. Revert changes to container-runner.ts and agent-runner/src/index.ts 3. Remove Web Research Tools section from groups/main/CLAUDE.md 4. Rebuild: `./container/build.sh && pnpm run build` -5. Restart: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux) +5. Restart: `source setup/lib/install-slug.sh && launchctl kickstart -k gui/$(id -u)/$(launchd_label)` (macOS) or `source setup/lib/install-slug.sh && systemctl --user restart $(systemd_unit)` (Linux) diff --git a/.claude/skills/add-signal/SKILL.md b/.claude/skills/add-signal/SKILL.md index 6b63a5c1d..73f84b768 100644 --- a/.claude/skills/add-signal/SKILL.md +++ b/.claude/skills/add-signal/SKILL.md @@ -90,17 +90,21 @@ No output = success. > ⚠ Stop NanoClaw before running signal-cli commands — the daemon holds an exclusive lock on its data directory while running. +Run from your NanoClaw project root: + ```bash +source setup/lib/install-slug.sh + # macOS -launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist +launchctl unload ~/Library/LaunchAgents/$(launchd_label).plist signal-cli -a +1YOURNUMBER updateProfile --name "YourBotName" # optionally: --avatar /path/to/avatar.jpg -launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist +launchctl load ~/Library/LaunchAgents/$(launchd_label).plist # Linux -systemctl --user stop nanoclaw +systemctl --user stop $(systemd_unit) signal-cli -a +1YOURNUMBER updateProfile --name "YourBotName" -systemctl --user start nanoclaw +systemctl --user start $(systemd_unit) ``` ### Path B: Link as secondary device @@ -185,12 +189,16 @@ Sync to container: `mkdir -p data/env && cp .env data/env/env` ### Restart +Run from your NanoClaw project root: + ```bash +source setup/lib/install-slug.sh + # macOS -launchctl kickstart -k gui/$(id -u)/com.nanoclaw +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # Linux -systemctl --user restart nanoclaw +systemctl --user restart $(systemd_unit) ``` ## Wiring @@ -283,7 +291,7 @@ If you see `Signal daemon not reachable at 127.0.0.1:7583` and `SIGNAL_MANAGE_DA 1. Channel initialized: `grep "Signal channel connected" logs/nanoclaw.log | tail -1` 2. Channel wired: `pnpm exec tsx scripts/q.ts data/v2.db "SELECT mg.platform_id, mg.name FROM messaging_groups mg JOIN messaging_group_agents mga ON mg.id = mga.messaging_group_id WHERE mg.channel_type='signal'"` -3. Service running: `launchctl print gui/$(id -u)/com.nanoclaw` (macOS) / `systemctl --user status nanoclaw` (Linux) +3. Service running: `launchctl print gui/$(id -u)/"$(. setup/lib/install-slug.sh && launchd_label)"` (macOS) / `systemctl --user status "$(. setup/lib/install-slug.sh && systemd_unit)"` (Linux) 4. **Check for duplicate service instances** — if `logs/nanoclaw.error.log` shows `No adapter for channel type channelType="signal"` despite the adapter starting, two NanoClaw processes are racing. See the `/debug` skill section "No adapter for channel type / Messages silently lost" for the full fix. ### Messages delivered but never arrive (null platformMsgId) diff --git a/.claude/skills/add-wechat/REMOVE.md b/.claude/skills/add-wechat/REMOVE.md index 366739e32..07367c097 100644 --- a/.claude/skills/add-wechat/REMOVE.md +++ b/.claude/skills/add-wechat/REMOVE.md @@ -41,9 +41,12 @@ DELETE FROM messaging_groups WHERE channel_type = 'wechat'; ### 6. Rebuild and restart +Run from your NanoClaw project root: + ```bash pnpm run build -systemctl --user restart nanoclaw # Linux +source setup/lib/install-slug.sh +systemctl --user restart $(systemd_unit) # Linux # or -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS ``` diff --git a/.claude/skills/add-wechat/SKILL.md b/.claude/skills/add-wechat/SKILL.md index 49746ce6f..9c94756ce 100644 --- a/.claude/skills/add-wechat/SKILL.md +++ b/.claude/skills/add-wechat/SKILL.md @@ -82,12 +82,15 @@ Sync to container: `mkdir -p data/env && cp .env data/env/env` ### 2. Start the service and scan the QR -Restart NanoClaw: +Restart NanoClaw. + +Run from your NanoClaw project root: ```bash -systemctl --user restart nanoclaw # Linux +source setup/lib/install-slug.sh +systemctl --user restart $(systemd_unit) # Linux # or -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS ``` The adapter will print a **QR URL** to the logs and save it to `data/wechat/qr.txt`: diff --git a/.claude/skills/add-whatsapp/SKILL.md b/.claude/skills/add-whatsapp/SKILL.md index edec47989..462683ece 100644 --- a/.claude/skills/add-whatsapp/SKILL.md +++ b/.claude/skills/add-whatsapp/SKILL.md @@ -244,12 +244,15 @@ rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --met ### "waiting for this message" on reactions -Signal sessions corrupted from rapid restarts. Clear sessions: +Signal sessions corrupted from rapid restarts. Clear sessions. + +Run from your NanoClaw project root: ```bash -systemctl --user stop nanoclaw +source setup/lib/install-slug.sh +systemctl --user stop $(systemd_unit) rm store/auth/session-*.json -systemctl --user start nanoclaw +systemctl --user start $(systemd_unit) ``` ### Bot not responding @@ -257,7 +260,7 @@ systemctl --user start nanoclaw 1. Auth exists: `test -f store/auth/creds.json` 2. Connected: `grep "Connected to WhatsApp" logs/nanoclaw.log | tail -1` 3. Channel wired: `pnpm exec tsx scripts/q.ts data/v2.db "SELECT mg.platform_id, mg.name FROM messaging_groups mg JOIN messaging_group_agents mga ON mg.id=mga.messaging_group_id WHERE mg.channel_type='whatsapp'"` -4. Service running: `systemctl --user status nanoclaw` +4. Service running: `systemctl --user status "$(. setup/lib/install-slug.sh && systemd_unit)"` ### "conflict" disconnection diff --git a/.claude/skills/convert-to-apple-container/SKILL.md b/.claude/skills/convert-to-apple-container/SKILL.md index cf25698ad..16c166712 100644 --- a/.claude/skills/convert-to-apple-container/SKILL.md +++ b/.claude/skills/convert-to-apple-container/SKILL.md @@ -171,9 +171,12 @@ Expected: Both operations succeed. ### Full integration test +Run from your NanoClaw project root: + ```bash pnpm run build -launchctl kickstart -k gui/$(id -u)/com.nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) ``` Send a message via WhatsApp and verify the agent responds. diff --git a/.claude/skills/customize/SKILL.md b/.claude/skills/customize/SKILL.md index c83bd2689..259e9fac4 100644 --- a/.claude/skills/customize/SKILL.md +++ b/.claude/skills/customize/SKILL.md @@ -88,15 +88,19 @@ Implementation: ## After Changes -Always tell the user: +Always tell the user. + +Run from your NanoClaw project root: + ```bash # Rebuild and restart pnpm run build +source setup/lib/install-slug.sh # macOS: -launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist -launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist +launchctl unload ~/Library/LaunchAgents/$(launchd_label).plist +launchctl load ~/Library/LaunchAgents/$(launchd_label).plist # Linux: -# systemctl --user restart nanoclaw +# systemctl --user restart $(systemd_unit) ``` ## Example Interaction diff --git a/.claude/skills/init-first-agent/SKILL.md b/.claude/skills/init-first-agent/SKILL.md index 67ab80b12..6a671b0ad 100644 --- a/.claude/skills/init-first-agent/SKILL.md +++ b/.claude/skills/init-first-agent/SKILL.md @@ -9,7 +9,7 @@ Stand up the first NanoClaw agent for a channel and verify end-to-end delivery b ## Prerequisites -- **Service running.** Check: `launchctl list | grep nanoclaw` (macOS) or `systemctl --user status nanoclaw` (Linux). If stopped, tell the user to run `/setup` first. +- **Service running.** Check: `launchctl list | grep "$(. setup/lib/install-slug.sh && launchd_label)"` (macOS) or `systemctl --user status "$(. setup/lib/install-slug.sh && systemd_unit)"` (Linux). If stopped, tell the user to run `/setup` first. - **Target channel installed.** At least one `/add-` skill has run, credentials are in `.env`, and the adapter is uncommented in `src/channels/index.ts`. - **Adapter connected.** Tail `logs/nanoclaw.log` — look for a recent `channel setup` / `adapter connected` line for the target channel. diff --git a/.claude/skills/init-onecli/SKILL.md b/.claude/skills/init-onecli/SKILL.md index ab64b73df..55b484207 100644 --- a/.claude/skills/init-onecli/SKILL.md +++ b/.claude/skills/init-onecli/SKILL.md @@ -236,9 +236,12 @@ pnpm run build If build fails, diagnose and fix. Common issue: `@onecli-sh/sdk` not installed — run `pnpm install` first. -Restart the service: -- macOS (launchd): `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` -- Linux (systemd): `systemctl --user restart nanoclaw` +Restart the service. + +Run from your NanoClaw project root: + +- macOS (launchd): `launchctl kickstart -k gui/$(id -u)/"$(. setup/lib/install-slug.sh && launchd_label)"` +- Linux (systemd): `systemctl --user restart "$(. setup/lib/install-slug.sh && systemd_unit)"` - WSL/manual: stop and re-run `bash start-nanoclaw.sh` ## Phase 5: Verify diff --git a/.claude/skills/manage-mounts/SKILL.md b/.claude/skills/manage-mounts/SKILL.md index ddfa28b73..df0c375d6 100644 --- a/.claude/skills/manage-mounts/SKILL.md +++ b/.claude/skills/manage-mounts/SKILL.md @@ -41,7 +41,12 @@ npx tsx setup/index.ts --step mounts --force -- --empty ## After Changes -Restart the service so containers pick up the new config: +Restart the service so containers pick up the new config (the unit/label names are per-install — see `setup/lib/install-slug.sh`). -- macOS: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` -- Linux: `systemctl --user restart nanoclaw` +Run from your NanoClaw project root: + +```bash +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +systemctl --user restart $(systemd_unit) # Linux +``` diff --git a/.claude/skills/update-nanoclaw/SKILL.md b/.claude/skills/update-nanoclaw/SKILL.md index 06e3fcb32..465aa2ae2 100644 --- a/.claude/skills/update-nanoclaw/SKILL.md +++ b/.claude/skills/update-nanoclaw/SKILL.md @@ -270,9 +270,9 @@ Show: Tell the user: - To rollback: `git reset --hard ` - Backup branch also exists: `backup/pre-update--` -- Restart the service to apply changes. Detect platform with `uname -s`: - - **macOS (Darwin)**: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` - - **Linux**: detect the service name with `systemctl --user list-units --type=service | grep nanoclaw | awk '{print $1}'`, then `systemctl --user restart ` +- Restart the service to apply changes. The unit/label names are per-install — derive them with `setup/lib/install-slug.sh`. Run from your NanoClaw project root: + - **macOS (Darwin)**: `source setup/lib/install-slug.sh && launchctl kickstart -k gui/$(id -u)/$(launchd_label)` + - **Linux**: `source setup/lib/install-slug.sh && systemctl --user restart $(systemd_unit)` (or, if you want to confirm the unit name first: `systemctl --user list-units --type=service | grep "$(. setup/lib/install-slug.sh && systemd_unit)"`) - **Manual** (no service found): restart `pnpm run dev` diff --git a/.claude/skills/use-native-credential-proxy/SKILL.md b/.claude/skills/use-native-credential-proxy/SKILL.md index 18d29bf5a..28d8017a5 100644 --- a/.claude/skills/use-native-credential-proxy/SKILL.md +++ b/.claude/skills/use-native-credential-proxy/SKILL.md @@ -128,9 +128,12 @@ echo 'ANTHROPIC_API_KEY=' >> .env pnpm run build ``` -Then restart the service: -- macOS: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` -- Linux: `systemctl --user restart nanoclaw` +Then restart the service. + +Run from your NanoClaw project root: + +- macOS: `launchctl kickstart -k gui/$(id -u)/"$(. setup/lib/install-slug.sh && launchd_label)"` +- Linux: `systemctl --user restart "$(. setup/lib/install-slug.sh && systemd_unit)"` - WSL/manual: stop and re-run `bash start-nanoclaw.sh` 2. Check logs for successful proxy startup: diff --git a/.claude/skills/x-integration/SKILL.md b/.claude/skills/x-integration/SKILL.md index 5dc859e82..f5337aeef 100644 --- a/.claude/skills/x-integration/SKILL.md +++ b/.claude/skills/x-integration/SKILL.md @@ -38,6 +38,8 @@ Before using this skill, ensure: ## Quick Start +Run from your NanoClaw project root: + ```bash # 1. Setup authentication (interactive) pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/setup.ts @@ -49,9 +51,10 @@ pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/s # 3. Rebuild host and restart service pnpm run build -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw -# Verify: launchctl list | grep nanoclaw (macOS) or systemctl --user status nanoclaw (Linux) +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# Linux: systemctl --user restart $(systemd_unit) +# Verify: launchctl list | grep "$(launchd_label)" (macOS) or systemctl --user status $(systemd_unit) (Linux) ``` ## Configuration @@ -270,16 +273,23 @@ cat data/x-auth.json # Should show {"authenticated": true, ...} ### 4. Restart Service +Run from your NanoClaw project root: + ```bash pnpm run build -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# Linux: systemctl --user restart $(systemd_unit) ``` -**Verify success:** +**Verify success.** + +Run from your NanoClaw project root: + ```bash -launchctl list | grep nanoclaw # macOS — should show PID and exit code 0 or - -# Linux: systemctl --user status nanoclaw +source setup/lib/install-slug.sh +launchctl list | grep "$(launchd_label)" # macOS — should show PID and exit code 0 or - +# Linux: systemctl --user status $(systemd_unit) ``` ## Usage via WhatsApp @@ -343,10 +353,13 @@ echo '{"content":"Test"}' | pnpm exec tsx .claude/skills/x-integration/scripts/p ### Authentication Expired +Run from your NanoClaw project root: + ```bash pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/setup.ts -launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS -# Linux: systemctl --user restart nanoclaw +source setup/lib/install-slug.sh +launchctl kickstart -k gui/$(id -u)/$(launchd_label) # macOS +# Linux: systemctl --user restart $(systemd_unit) ``` ### Browser Lock Files diff --git a/src/cli/client.ts b/src/cli/client.ts index 93ed50090..0f155ca6c 100644 --- a/src/cli/client.ts +++ b/src/cli/client.ts @@ -21,6 +21,7 @@ import { formatResponse } from './format.js'; import type { RequestFrame } from './frame.js'; import { SocketTransport } from './socket-client.js'; import type { Transport } from './transport.js'; +import { formatTransportError } from './transport-errors.js'; async function main(): Promise { const argv = process.argv.slice(2); @@ -105,21 +106,6 @@ function printUsage(): void { ); } -function formatTransportError(e: unknown): string { - const msg = e instanceof Error ? e.message : String(e); - if (msg.includes('ENOENT') || msg.includes('ECONNREFUSED')) { - return [ - `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`, - ` Linux: systemctl --user restart nanoclaw`, - ``, - ].join('\n'); - } - return `ncl: transport error: ${msg}\n`; -} - main().catch((err) => { process.stderr.write(`ncl: unexpected error: ${err instanceof Error ? err.message : String(err)}\n`); process.exit(2); diff --git a/src/cli/transport-errors.test.ts b/src/cli/transport-errors.test.ts new file mode 100644 index 000000000..a6f5666e6 --- /dev/null +++ b/src/cli/transport-errors.test.ts @@ -0,0 +1,31 @@ +import { describe, it, expect } from 'vitest'; + +import { getLaunchdLabel, getSystemdUnit } from '../install-slug.js'; +import { formatTransportError } from './transport-errors.js'; + +describe('formatTransportError', () => { + it('renders per-install service names on ENOENT, not the bare v1 names', () => { + const out = formatTransportError(new Error('connect ENOENT /tmp/nanoclaw.sock')); + + // Regression for #2484: pre-fix, this string was a hardcoded + // `com.nanoclaw` / `nanoclaw`, which doesn't match the actual + // v2 per-install slug-suffixed unit and label. + expect(out).toContain(`gui/$(id -u)/${getLaunchdLabel()}`); + expect(out).toContain(`systemctl --user restart ${getSystemdUnit()}`); + expect(out).not.toMatch(/gui\/\$\(id -u\)\/com\.nanoclaw\b(?!-v2)/); + expect(out).not.toMatch(/systemctl --user restart nanoclaw\b(?!-v2)/); + }); + + it('renders the same on ECONNREFUSED', () => { + const out = formatTransportError(new Error('connect ECONNREFUSED')); + expect(out).toContain(getLaunchdLabel()); + expect(out).toContain(getSystemdUnit()); + }); + + it('falls back to a generic transport error for other failures', () => { + const out = formatTransportError(new Error('some unrelated failure')); + expect(out).toBe('ncl: transport error: some unrelated failure\n'); + expect(out).not.toContain('launchctl'); + expect(out).not.toContain('systemctl'); + }); +}); diff --git a/src/cli/transport-errors.ts b/src/cli/transport-errors.ts new file mode 100644 index 000000000..d1e76559b --- /dev/null +++ b/src/cli/transport-errors.ts @@ -0,0 +1,19 @@ +import { getLaunchdLabel, getSystemdUnit } from '../install-slug.js'; + +export function formatTransportError(e: unknown): string { + const msg = e instanceof Error ? e.message : String(e); + if (msg.includes('ENOENT') || msg.includes('ECONNREFUSED')) { + // `bin/ncl` cd's to the project root before exec'ing client.ts, so + // process.cwd() is the install dir — install-slug helpers pick up + // the right per-checkout suffix. + return [ + `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)/${getLaunchdLabel()}`, + ` Linux: systemctl --user restart ${getSystemdUnit()}`, + ``, + ].join('\n'); + } + return `ncl: transport error: ${msg}\n`; +}