Merge pull request #1771 from meeech/feat/v2-pnpm-migration
chore: migrate v2 from npm to pnpm
This commit is contained in:
@@ -6,17 +6,17 @@
|
||||
"allow": [
|
||||
"Bash(bash setup.sh*)",
|
||||
"Bash(git remote *)",
|
||||
"Bash(npx tsx setup/index.ts*)",
|
||||
"Bash(npx tsx scripts/init-first-agent.ts*)",
|
||||
"Bash(npm install @chat-adapter/*)",
|
||||
"Bash(npm install chat-adapter-imessage*)",
|
||||
"Bash(npm install @bitbasti/chat-adapter-webex*)",
|
||||
"Bash(npm install @resend/chat-sdk-adapter*)",
|
||||
"Bash(npm install @whiskeysockets/baileys*)",
|
||||
"Bash(npm install @beeper/chat-adapter-matrix*)",
|
||||
"Bash(npm install @nanoco/nanoclaw-dashboard*)",
|
||||
"Bash(npm ci*)",
|
||||
"Bash(npm run build*)",
|
||||
"Bash(pnpm exec tsx setup/index.ts*)",
|
||||
"Bash(pnpm exec tsx scripts/init-first-agent.ts*)",
|
||||
"Bash(pnpm install @chat-adapter/*)",
|
||||
"Bash(pnpm install chat-adapter-imessage*)",
|
||||
"Bash(pnpm install @bitbasti/chat-adapter-webex*)",
|
||||
"Bash(pnpm install @resend/chat-sdk-adapter*)",
|
||||
"Bash(pnpm install @whiskeysockets/baileys*)",
|
||||
"Bash(pnpm install @beeper/chat-adapter-matrix*)",
|
||||
"Bash(pnpm install @nanoco/nanoclaw-dashboard*)",
|
||||
"Bash(pnpm install --frozen-lockfile*)",
|
||||
"Bash(pnpm run build*)",
|
||||
"Bash(curl -fsSL onecli.sh*)",
|
||||
"Bash(onecli *)",
|
||||
"Bash(grep -q *)",
|
||||
|
||||
@@ -39,8 +39,8 @@ This adds:
|
||||
### Validate
|
||||
|
||||
```bash
|
||||
npm test
|
||||
npm run build
|
||||
pnpm test
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### Rebuild container
|
||||
@@ -60,7 +60,7 @@ launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
|
||||
### Integration Test
|
||||
|
||||
1. Start NanoClaw in dev mode: `npm run dev`
|
||||
1. Start NanoClaw in dev mode: `pnpm run dev`
|
||||
2. From the **main group** (self-chat), send exactly: `/compact`
|
||||
3. Verify:
|
||||
- The agent acknowledges compaction (e.g., "Conversation compacted.")
|
||||
@@ -104,8 +104,8 @@ launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
git clone <your-fork> /tmp/nanoclaw-test
|
||||
cd /tmp/nanoclaw-test
|
||||
claude # then run /add-compact
|
||||
npm run build
|
||||
npm test
|
||||
pnpm run build
|
||||
pnpm test
|
||||
./container/build.sh
|
||||
# Manual: send /compact from main group, verify compaction + continuation
|
||||
# Manual: send @<assistant> /compact from non-main as non-admin, verify denial
|
||||
|
||||
@@ -25,7 +25,7 @@ NanoClaw (pusher) Dashboard (npm package)
|
||||
### 1. Install the npm package
|
||||
|
||||
```bash
|
||||
npm install @nanoco/nanoclaw-dashboard
|
||||
pnpm install @nanoco/nanoclaw-dashboard
|
||||
```
|
||||
|
||||
### 2. Copy the pusher module
|
||||
@@ -94,7 +94,7 @@ Generate the secret: `node -e "console.log('nc-' + require('crypto').randomBytes
|
||||
### 6. Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
systemctl --user restart nanoclaw # Linux
|
||||
# or: launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
```
|
||||
@@ -130,9 +130,9 @@ Open `http://localhost:3100/dashboard` in a browser.
|
||||
## Removal
|
||||
|
||||
```bash
|
||||
npm uninstall @nanoco/nanoclaw-dashboard
|
||||
pnpm uninstall @nanoco/nanoclaw-dashboard
|
||||
rm src/dashboard-pusher.ts
|
||||
# Remove the dashboard block from src/index.ts
|
||||
# Remove DASHBOARD_SECRET and DASHBOARD_PORT from .env
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
@@ -26,7 +26,7 @@ import './discord.js';
|
||||
### Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -40,8 +40,8 @@ git remote add discord https://github.com/qwibitai/nanoclaw-discord.git
|
||||
```bash
|
||||
git fetch discord main
|
||||
git merge discord/main || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -58,9 +58,9 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/channels/discord.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/discord.test.ts
|
||||
```
|
||||
|
||||
All tests must pass (including the new Discord tests) and build must be clean before proceeding.
|
||||
@@ -108,7 +108,7 @@ The container reads environment from `data/env/env`, not `.env` directly.
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
|
||||
```
|
||||
|
||||
@@ -130,18 +130,18 @@ Wait for the user to provide the channel ID (format: `dc:1234567890123456`).
|
||||
|
||||
### Register the channel
|
||||
|
||||
The channel ID, name, and folder name are needed. Use `npx tsx setup/index.ts --step register` with the appropriate flags.
|
||||
The channel ID, name, and folder name are needed. Use `pnpm exec tsx setup/index.ts --step register` with the appropriate flags.
|
||||
|
||||
For a main channel (responds to all messages):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "dc:<channel-id>" --name "<server-name> #<channel-name>" --folder "discord_main" --trigger "@${ASSISTANT_NAME}" --channel discord --no-trigger-required --is-main
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "dc:<channel-id>" --name "<server-name> #<channel-name>" --folder "discord_main" --trigger "@${ASSISTANT_NAME}" --channel discord --no-trigger-required --is-main
|
||||
```
|
||||
|
||||
For additional channels (trigger-only):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "dc:<channel-id>" --name "<server-name> #<channel-name>" --folder "discord_<channel-name>" --trigger "@${ASSISTANT_NAME}" --channel discord
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "dc:<channel-id>" --name "<server-name> #<channel-name>" --folder "discord_<channel-name>" --trigger "@${ASSISTANT_NAME}" --channel discord
|
||||
```
|
||||
|
||||
## Phase 5: Verify
|
||||
|
||||
@@ -51,12 +51,12 @@ git fetch upstream skill/emacs
|
||||
git merge upstream/skill/emacs
|
||||
```
|
||||
|
||||
If there are merge conflicts on `package-lock.json`, resolve them by accepting the incoming
|
||||
If there are merge conflicts on `pnpm-lock.yaml`, resolve them by accepting the incoming
|
||||
version and continuing:
|
||||
|
||||
```bash
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
```
|
||||
|
||||
@@ -73,8 +73,8 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx vitest run src/channels/emacs.test.ts
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/emacs.test.ts
|
||||
```
|
||||
|
||||
Build must be clean and tests must pass before proceeding.
|
||||
@@ -158,7 +158,7 @@ If `EMACS_CHANNEL_PORT` was changed from the default, also add:
|
||||
### Restart NanoClaw
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
@@ -246,18 +246,18 @@ If NanoClaw is cloned elsewhere, update the `load`/`load-file` path in your Emac
|
||||
|
||||
## After Setup
|
||||
|
||||
If running `npm run dev` while the service is active:
|
||||
If running `pnpm run dev` while the service is active:
|
||||
|
||||
```bash
|
||||
# macOS:
|
||||
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
npm run dev
|
||||
pnpm run dev
|
||||
# When done testing:
|
||||
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
|
||||
# Linux:
|
||||
# systemctl --user stop nanoclaw
|
||||
# npm run dev
|
||||
# pnpm run dev
|
||||
# systemctl --user start nanoclaw
|
||||
```
|
||||
|
||||
@@ -286,4 +286,4 @@ To remove the Emacs channel:
|
||||
3. Remove the NanoClaw block from your Emacs config file
|
||||
4. Remove Emacs registration from SQLite: `sqlite3 store/messages.db "DELETE FROM registered_groups WHERE jid = 'emacs:default'"`
|
||||
5. Remove `EMACS_CHANNEL_PORT` and `EMACS_AUTH_TOKEN` from `.env` if set
|
||||
6. Rebuild: `npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `npm run build && systemctl --user restart nanoclaw` (Linux)
|
||||
6. Rebuild: `pnpm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `pnpm run build && systemctl --user restart nanoclaw` (Linux)
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './gchat.js'` in `src/channels/index.ts`
|
||||
2. Remove `GCHAT_CREDENTIALS` from `.env`
|
||||
3. `npm uninstall @chat-adapter/gchat`
|
||||
3. `pnpm uninstall @chat-adapter/gchat`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/gchat.ts` exists and the import is uncommented in `src/ch
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/gchat
|
||||
pnpm install @chat-adapter/gchat
|
||||
```
|
||||
|
||||
Uncomment the Google Chat import in `src/channels/index.ts`:
|
||||
@@ -24,7 +24,7 @@ import './gchat.js';
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './github.js'` in `src/channels/index.ts`
|
||||
2. Remove `GITHUB_TOKEN` and `GITHUB_WEBHOOK_SECRET` from `.env`
|
||||
3. `npm uninstall @chat-adapter/github`
|
||||
3. `pnpm uninstall @chat-adapter/github`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/github.ts` exists and the import is uncommented in `src/c
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/github
|
||||
pnpm install @chat-adapter/github
|
||||
```
|
||||
|
||||
Uncomment the GitHub import in `src/channels/index.ts`:
|
||||
@@ -24,7 +24,7 @@ import './github.js';
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -41,8 +41,8 @@ git remote add gmail https://github.com/qwibitai/nanoclaw-gmail.git
|
||||
```bash
|
||||
git fetch gmail main
|
||||
git merge gmail/main || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -70,9 +70,9 @@ When you receive an email notification (messages starting with `[Email from ...`
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/channels/gmail.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/gmail.test.ts
|
||||
```
|
||||
|
||||
All tests must pass (including the new Gmail tests) and build must be clean before proceeding.
|
||||
@@ -136,10 +136,10 @@ Tell the user:
|
||||
Run the authorization:
|
||||
|
||||
```bash
|
||||
npx -y @gongrzhe/server-gmail-autoauth-mcp auth
|
||||
pnpm dlx @gongrzhe/server-gmail-autoauth-mcp auth
|
||||
```
|
||||
|
||||
If that fails (some versions don't have an auth subcommand), try `timeout 60 npx -y @gongrzhe/server-gmail-autoauth-mcp || true`. Verify with `ls ~/.gmail-mcp/credentials.json`.
|
||||
If that fails (some versions don't have an auth subcommand), try `timeout 60 pnpm dlx @gongrzhe/server-gmail-autoauth-mcp || true`. Verify with `ls ~/.gmail-mcp/credentials.json`.
|
||||
|
||||
### Build and restart
|
||||
|
||||
@@ -158,7 +158,7 @@ cd container && ./build.sh
|
||||
Then compile and restart:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
@@ -192,7 +192,7 @@ tail -f logs/nanoclaw.log
|
||||
Test directly:
|
||||
|
||||
```bash
|
||||
npx -y @gongrzhe/server-gmail-autoauth-mcp
|
||||
pnpm dlx @gongrzhe/server-gmail-autoauth-mcp
|
||||
```
|
||||
|
||||
### OAuth token expired
|
||||
@@ -201,7 +201,7 @@ Re-authorize:
|
||||
|
||||
```bash
|
||||
rm ~/.gmail-mcp/credentials.json
|
||||
npx -y @gongrzhe/server-gmail-autoauth-mcp
|
||||
pnpm dlx @gongrzhe/server-gmail-autoauth-mcp
|
||||
```
|
||||
|
||||
### Container can't access Gmail
|
||||
@@ -222,7 +222,7 @@ npx -y @gongrzhe/server-gmail-autoauth-mcp
|
||||
2. Remove `gmail` MCP server and `mcp__gmail__*` from `container/agent-runner/src/index.ts`
|
||||
3. Rebuild and restart
|
||||
4. Clear stale agent-runner copies: `rm -r data/sessions/*/agent-runner-src 2>/dev/null || true`
|
||||
5. Rebuild: `cd container && ./build.sh && cd .. && npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux)
|
||||
5. Rebuild: `cd container && ./build.sh && cd .. && pnpm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux)
|
||||
|
||||
### Channel mode
|
||||
|
||||
@@ -230,7 +230,7 @@ npx -y @gongrzhe/server-gmail-autoauth-mcp
|
||||
2. Remove `import './gmail.js'` from `src/channels/index.ts`
|
||||
3. Remove `~/.gmail-mcp` mount from `src/container-runner.ts`
|
||||
4. Remove `gmail` MCP server and `mcp__gmail__*` from `container/agent-runner/src/index.ts`
|
||||
5. Uninstall: `npm uninstall googleapis`
|
||||
5. Uninstall: `pnpm uninstall googleapis`
|
||||
6. Rebuild and restart
|
||||
7. Clear stale agent-runner copies: `rm -r data/sessions/*/agent-runner-src 2>/dev/null || true`
|
||||
8. Rebuild: `cd container && ./build.sh && cd .. && npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux)
|
||||
8. Rebuild: `cd container && ./build.sh && cd .. && pnpm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux)
|
||||
|
||||
@@ -33,8 +33,8 @@ git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
|
||||
```bash
|
||||
git fetch whatsapp skill/image-vision
|
||||
git merge whatsapp/skill/image-vision || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -52,9 +52,9 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/image.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/image.test.ts
|
||||
```
|
||||
|
||||
All tests must pass and build must be clean before proceeding.
|
||||
@@ -90,5 +90,5 @@ All tests must pass and build must be clean before proceeding.
|
||||
## Troubleshooting
|
||||
|
||||
- **"Image - download failed"**: Check WhatsApp connection stability. The download may timeout on slow connections.
|
||||
- **"Image - processing failed"**: Sharp may not be installed correctly. Run `npm ls sharp` to verify.
|
||||
- **"Image - processing failed"**: Sharp may not be installed correctly. Run `pnpm ls sharp` to verify.
|
||||
- **Agent doesn't mention image content**: Check container logs for "Loaded image" messages. If missing, ensure agent-runner source was synced to group caches.
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './imessage.js'` in `src/channels/index.ts`
|
||||
2. Remove iMessage env vars (`IMESSAGE_ENABLED`, `IMESSAGE_LOCAL`, `IMESSAGE_SERVER_URL`, `IMESSAGE_API_KEY`) from `.env`
|
||||
3. `npm uninstall chat-adapter-imessage`
|
||||
3. `pnpm uninstall chat-adapter-imessage`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/imessage.ts` exists and the import is uncommented in `src
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install chat-adapter-imessage
|
||||
pnpm install chat-adapter-imessage
|
||||
```
|
||||
|
||||
Uncomment the iMessage import in `src/channels/index.ts`:
|
||||
@@ -24,7 +24,7 @@ import './imessage.js';
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -19,7 +19,7 @@ AskUserQuestion: "Which group should have the wiki?"
|
||||
2. **Dedicated group** — create a new group just for the wiki
|
||||
3. **Other** — pick an existing group
|
||||
|
||||
If dedicated: ask which channel and chat, then register with `npx tsx setup/index.ts --step register`.
|
||||
If dedicated: ask which channel and chat, then register with `pnpm exec tsx setup/index.ts --step register`.
|
||||
|
||||
## Step 3: Design collaboratively
|
||||
|
||||
@@ -74,7 +74,7 @@ AskUserQuestion: "Want periodic wiki health checks?"
|
||||
If yes, create a NanoClaw scheduled task that runs in the wiki group. This is NOT a Claude Code cron job — it's a NanoClaw group task that runs in the agent container. Insert it into the SQLite database:
|
||||
|
||||
```bash
|
||||
npx tsx -e "
|
||||
pnpm exec tsx -e "
|
||||
const Database = require('better-sqlite3');
|
||||
const { CronExpressionParser } = require('cron-parser');
|
||||
const db = new Database('store/messages.db');
|
||||
@@ -101,7 +101,7 @@ Use the group's `folder` and `chat_jid` from the registered groups table. Cron e
|
||||
## Step 6: Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
./container/build.sh
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './linear.js'` in `src/channels/index.ts`
|
||||
2. Remove `LINEAR_API_KEY` and `LINEAR_WEBHOOK_SECRET` from `.env`
|
||||
3. `npm uninstall @chat-adapter/linear`
|
||||
3. `pnpm uninstall @chat-adapter/linear`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/linear.ts` exists and the import is uncommented in `src/c
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/linear
|
||||
pnpm install @chat-adapter/linear
|
||||
```
|
||||
|
||||
Uncomment the Linear import in `src/channels/index.ts`:
|
||||
@@ -24,7 +24,7 @@ import './linear.js';
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './matrix.js'` in `src/channels/index.ts`
|
||||
2. Remove `MATRIX_BASE_URL`, `MATRIX_ACCESS_TOKEN`, `MATRIX_USER_ID`, `MATRIX_BOT_USERNAME` from `.env`
|
||||
3. `npm uninstall @beeper/chat-adapter-matrix`
|
||||
3. `pnpm uninstall @beeper/chat-adapter-matrix`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/matrix.ts` exists and the import is uncommented in `src/c
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @beeper/chat-adapter-matrix
|
||||
pnpm install @beeper/chat-adapter-matrix
|
||||
```
|
||||
|
||||
Uncomment the Matrix import in `src/channels/index.ts`:
|
||||
@@ -24,7 +24,7 @@ import './matrix.js';
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -87,7 +87,7 @@ done
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
./container/build.sh
|
||||
```
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ echo '{}' | docker run -i --entrypoint /bin/echo nanoclaw-agent:latest "Containe
|
||||
Rebuild the main app and restart:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
@@ -286,5 +286,5 @@ To remove Parallel AI integration:
|
||||
1. Remove from .env: `sed -i.bak '/PARALLEL_API_KEY/d' .env`
|
||||
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 && npm run build`
|
||||
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)
|
||||
|
||||
@@ -31,8 +31,8 @@ git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
|
||||
```bash
|
||||
git fetch whatsapp skill/pdf-reader
|
||||
git merge whatsapp/skill/pdf-reader || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -49,8 +49,8 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx vitest run src/channels/whatsapp.test.ts
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/whatsapp.test.ts
|
||||
```
|
||||
|
||||
### Rebuild container
|
||||
|
||||
@@ -38,8 +38,8 @@ git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
|
||||
```bash
|
||||
git fetch whatsapp skill/reactions
|
||||
git merge whatsapp/skill/reactions || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -54,14 +54,14 @@ This adds:
|
||||
### Run database migration
|
||||
|
||||
```bash
|
||||
npx tsx scripts/migrate-reactions.ts
|
||||
pnpm exec tsx scripts/migrate-reactions.ts
|
||||
```
|
||||
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm test
|
||||
npm run build
|
||||
pnpm test
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
All tests must pass and build must be clean before proceeding.
|
||||
@@ -71,7 +71,7 @@ All tests must pass and build must be clean before proceeding.
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Linux:
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './resend.js'` in `src/channels/index.ts`
|
||||
2. Remove `RESEND_API_KEY`, `RESEND_FROM_ADDRESS`, `RESEND_FROM_NAME`, `RESEND_WEBHOOK_SECRET` from `.env`
|
||||
3. `npm uninstall @resend/chat-sdk-adapter`
|
||||
3. `pnpm uninstall @resend/chat-sdk-adapter`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/resend.ts` exists and the import is uncommented in `src/c
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @resend/chat-sdk-adapter
|
||||
pnpm install @resend/chat-sdk-adapter
|
||||
```
|
||||
|
||||
Uncomment the Resend import in `src/channels/index.ts`:
|
||||
@@ -26,7 +26,7 @@ import './resend.js';
|
||||
Build:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './slack.js'` in `src/channels/index.ts`
|
||||
2. Remove `SLACK_BOT_TOKEN` and `SLACK_SIGNING_SECRET` from `.env`
|
||||
3. `npm uninstall @chat-adapter/slack`
|
||||
3. `pnpm uninstall @chat-adapter/slack`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -16,7 +16,7 @@ Check if `src/channels/slack.ts` exists and the import is uncommented in `src/ch
|
||||
### Install the adapter package
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/slack
|
||||
pnpm install @chat-adapter/slack
|
||||
```
|
||||
|
||||
### Enable the channel
|
||||
@@ -30,7 +30,7 @@ import './slack.js';
|
||||
### Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -36,8 +36,8 @@ git remote add slack https://github.com/qwibitai/nanoclaw-slack.git
|
||||
```bash
|
||||
git fetch slack main
|
||||
git merge slack/main || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -54,9 +54,9 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/channels/slack.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/slack.test.ts
|
||||
```
|
||||
|
||||
All tests must pass (including the new Slack tests) and build must be clean before proceeding.
|
||||
@@ -98,7 +98,7 @@ The container reads environment from `data/env/env`, not `.env` directly.
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
|
||||
```
|
||||
|
||||
@@ -118,18 +118,18 @@ Wait for the user to provide the channel ID.
|
||||
|
||||
### Register the channel
|
||||
|
||||
The channel ID, name, and folder name are needed. Use `npx tsx setup/index.ts --step register` with the appropriate flags.
|
||||
The channel ID, name, and folder name are needed. Use `pnpm exec tsx setup/index.ts --step register` with the appropriate flags.
|
||||
|
||||
For a main channel (responds to all messages):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "slack:<channel-id>" --name "<channel-name>" --folder "slack_main" --trigger "@${ASSISTANT_NAME}" --channel slack --no-trigger-required --is-main
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "slack:<channel-id>" --name "<channel-name>" --folder "slack_main" --trigger "@${ASSISTANT_NAME}" --channel slack --no-trigger-required --is-main
|
||||
```
|
||||
|
||||
For additional channels (trigger-only):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "slack:<channel-id>" --name "<channel-name>" --folder "slack_<channel-name>" --trigger "@${ASSISTANT_NAME}" --channel slack
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "slack:<channel-id>" --name "<channel-name>" --folder "slack_<channel-name>" --trigger "@${ASSISTANT_NAME}" --channel slack
|
||||
```
|
||||
|
||||
## Phase 5: Verify
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './teams.js'` in `src/channels/index.ts`
|
||||
2. Remove `TEAMS_APP_ID` and `TEAMS_APP_PASSWORD` from `.env`
|
||||
3. `npm uninstall @chat-adapter/teams`
|
||||
3. `pnpm uninstall @chat-adapter/teams`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/teams.ts` exists and the import is uncommented in `src/ch
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/teams
|
||||
pnpm install @chat-adapter/teams
|
||||
```
|
||||
|
||||
Uncomment the Teams import in `src/channels/index.ts`:
|
||||
@@ -26,7 +26,7 @@ import './teams.js';
|
||||
Build:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -319,7 +319,7 @@ Also add `TELEGRAM_BOT_POOL` to the launchd plist (`~/Library/LaunchAgents/com.n
|
||||
### Step 7: Rebuild and Restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
./container/build.sh # Required — MCP tool changed
|
||||
# macOS:
|
||||
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
@@ -381,4 +381,4 @@ To remove Agent Swarm support while keeping basic Telegram:
|
||||
5. Remove `sender` param from MCP tool in `container/agent-runner/src/ipc-mcp-stdio.ts`
|
||||
6. Remove Agent Teams section from group CLAUDE.md files
|
||||
7. Remove `TELEGRAM_BOT_POOL` from `.env`, `data/env/env`, and launchd plist/systemd unit
|
||||
8. Rebuild: `npm run build && ./container/build.sh && launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist` (macOS) or `npm run build && ./container/build.sh && systemctl --user restart nanoclaw` (Linux)
|
||||
8. Rebuild: `pnpm run build && ./container/build.sh && launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist` (macOS) or `pnpm run build && ./container/build.sh && systemctl --user restart nanoclaw` (Linux)
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './telegram.js'` in `src/channels/index.ts`
|
||||
2. Remove `TELEGRAM_BOT_TOKEN` from `.env`
|
||||
3. `npm uninstall @chat-adapter/telegram`
|
||||
3. `pnpm uninstall @chat-adapter/telegram`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -16,7 +16,7 @@ Check if `src/channels/telegram.ts` exists and the import is uncommented in `src
|
||||
### Install the adapter package
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/telegram
|
||||
pnpm install @chat-adapter/telegram
|
||||
```
|
||||
|
||||
### Enable the channel
|
||||
@@ -30,7 +30,7 @@ import './telegram.js';
|
||||
### Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
@@ -68,7 +68,7 @@ Otherwise, run `/manage-channels` to wire this channel to an agent group.
|
||||
|
||||
- **type**: `telegram`
|
||||
- **terminology**: Telegram calls them "groups" and "chats." A "group" has multiple members; a "chat" is a 1:1 conversation with the bot.
|
||||
- **how-to-find-id**: Do NOT ask the user for a chat ID. Telegram registration uses pairing — run `npx tsx setup/index.ts --step pair-telegram -- --intent <main|wire-to:folder|new-agent:folder>`, show the user the 4-digit `CODE` from the `PAIR_TELEGRAM_ISSUED` block (follow the `REMINDER_TO_ASSISTANT` line in that block), and tell them to send just the 4 digits as a message from the chat they want to register (DM the bot for `main`, post in the group otherwise). In groups with Group Privacy ON, prefix with the bot handle: `@<botname> CODE`. Wrong guesses invalidate the code — if a `PAIR_TELEGRAM_ATTEMPT` block arrives with a mismatched `RECEIVED_CODE`, a `PAIR_TELEGRAM_NEW_CODE` block will follow automatically (up to 5 regenerations); show the new code. On `PAIR_TELEGRAM STATUS=failed ERROR=max-regenerations-exceeded`, ask the user if they want to try again and re-invoke the step — each invocation starts a fresh 5-attempt batch. Success emits `PAIR_TELEGRAM STATUS=success` with `PLATFORM_ID`, `IS_GROUP`, and `ADMIN_USER_ID`. The service must be running for this to work (the polling adapter is what observes the code).
|
||||
- **how-to-find-id**: Do NOT ask the user for a chat ID. Telegram registration uses pairing — run `pnpm exec tsx setup/index.ts --step pair-telegram -- --intent <main|wire-to:folder|new-agent:folder>`, show the user the 4-digit `CODE` from the `PAIR_TELEGRAM_ISSUED` block (follow the `REMINDER_TO_ASSISTANT` line in that block), and tell them to send just the 4 digits as a message from the chat they want to register (DM the bot for `main`, post in the group otherwise). In groups with Group Privacy ON, prefix with the bot handle: `@<botname> CODE`. Wrong guesses invalidate the code — if a `PAIR_TELEGRAM_ATTEMPT` block arrives with a mismatched `RECEIVED_CODE`, a `PAIR_TELEGRAM_NEW_CODE` block will follow automatically (up to 5 regenerations); show the new code. On `PAIR_TELEGRAM STATUS=failed ERROR=max-regenerations-exceeded`, ask the user if they want to try again and re-invoke the step — each invocation starts a fresh 5-attempt batch. Success emits `PAIR_TELEGRAM STATUS=success` with `PLATFORM_ID`, `IS_GROUP`, and `ADMIN_USER_ID`. The service must be running for this to work (the polling adapter is what observes the code).
|
||||
- **supports-threads**: no
|
||||
- **typical-use**: Interactive chat — direct messages or small groups
|
||||
- **default-isolation**: Same agent group if you're the only participant across multiple chats. Separate agent group if different people are in different groups.
|
||||
|
||||
@@ -40,8 +40,8 @@ git remote add telegram https://github.com/qwibitai/nanoclaw-telegram.git
|
||||
```bash
|
||||
git fetch telegram main
|
||||
git merge telegram/main || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -58,9 +58,9 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/channels/telegram.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/telegram.test.ts
|
||||
```
|
||||
|
||||
All tests must pass (including the new Telegram tests) and build must be clean before proceeding.
|
||||
@@ -114,7 +114,7 @@ Tell the user:
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
@@ -133,18 +133,18 @@ Wait for the user to provide the chat ID (format: `tg:123456789` or `tg:-1001234
|
||||
|
||||
### Register the chat
|
||||
|
||||
The chat ID, name, and folder name are needed. Use `npx tsx setup/index.ts --step register` with the appropriate flags.
|
||||
The chat ID, name, and folder name are needed. Use `pnpm exec tsx setup/index.ts --step register` with the appropriate flags.
|
||||
|
||||
For a main chat (responds to all messages):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "tg:<chat-id>" --name "<chat-name>" --folder "telegram_main" --trigger "@${ASSISTANT_NAME}" --channel telegram --no-trigger-required --is-main
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "tg:<chat-id>" --name "<chat-name>" --folder "telegram_main" --trigger "@${ASSISTANT_NAME}" --channel telegram --no-trigger-required --is-main
|
||||
```
|
||||
|
||||
For additional chats (trigger-only):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "tg:<chat-id>" --name "<chat-name>" --folder "telegram_<group-name>" --trigger "@${ASSISTANT_NAME}" --channel telegram
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "tg:<chat-id>" --name "<chat-name>" --folder "telegram_<group-name>" --trigger "@${ASSISTANT_NAME}" --channel telegram
|
||||
```
|
||||
|
||||
## Phase 5: Verify
|
||||
@@ -189,16 +189,16 @@ If `/chatid` doesn't work:
|
||||
|
||||
## After Setup
|
||||
|
||||
If running `npm run dev` while the service is active:
|
||||
If running `pnpm run dev` while the service is active:
|
||||
```bash
|
||||
# macOS:
|
||||
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
npm run dev
|
||||
pnpm run dev
|
||||
# When done testing:
|
||||
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
# Linux:
|
||||
# systemctl --user stop nanoclaw
|
||||
# npm run dev
|
||||
# pnpm run dev
|
||||
# systemctl --user start nanoclaw
|
||||
```
|
||||
|
||||
@@ -210,5 +210,5 @@ To remove Telegram integration:
|
||||
2. Remove `import './telegram.js'` from `src/channels/index.ts`
|
||||
3. Remove `TELEGRAM_BOT_TOKEN` from `.env`
|
||||
4. Remove Telegram registrations from SQLite: `sqlite3 store/messages.db "DELETE FROM registered_groups WHERE jid LIKE 'tg:%'"`
|
||||
5. Uninstall: `npm uninstall grammy`
|
||||
6. Rebuild: `npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `npm run build && systemctl --user restart nanoclaw` (Linux)
|
||||
5. Uninstall: `pnpm uninstall grammy`
|
||||
6. Rebuild: `pnpm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `pnpm run build && systemctl --user restart nanoclaw` (Linux)
|
||||
|
||||
@@ -42,8 +42,8 @@ git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
|
||||
```bash
|
||||
git fetch whatsapp skill/voice-transcription
|
||||
git merge whatsapp/skill/voice-transcription || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -60,9 +60,9 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install --legacy-peer-deps
|
||||
npm run build
|
||||
npx vitest run src/channels/whatsapp.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/whatsapp.test.ts
|
||||
```
|
||||
|
||||
All tests must pass and build must be clean before proceeding.
|
||||
@@ -103,7 +103,7 @@ The container reads environment from `data/env/env`, not `.env` directly.
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './webex.js'` in `src/channels/index.ts`
|
||||
2. Remove `WEBEX_BOT_TOKEN` and `WEBEX_WEBHOOK_SECRET` from `.env`
|
||||
3. `npm uninstall @bitbasti/chat-adapter-webex`
|
||||
3. `pnpm uninstall @bitbasti/chat-adapter-webex`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/webex.ts` exists and the import is uncommented in `src/ch
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @bitbasti/chat-adapter-webex
|
||||
pnpm install @bitbasti/chat-adapter-webex
|
||||
```
|
||||
|
||||
Uncomment the Webex import in `src/channels/index.ts`:
|
||||
@@ -24,7 +24,7 @@ import './webex.js';
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
1. Comment out `import './whatsapp-cloud.js'` in `src/channels/index.ts`
|
||||
2. Remove `WHATSAPP_ACCESS_TOKEN`, `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_APP_SECRET`, `WHATSAPP_VERIFY_TOKEN` from `.env`
|
||||
3. `npm uninstall @chat-adapter/whatsapp`
|
||||
3. `pnpm uninstall @chat-adapter/whatsapp`
|
||||
4. Rebuild and restart
|
||||
|
||||
@@ -14,7 +14,7 @@ Check if `src/channels/whatsapp-cloud.ts` exists and the import is uncommented i
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @chat-adapter/whatsapp
|
||||
pnpm install @chat-adapter/whatsapp
|
||||
```
|
||||
|
||||
Uncomment the WhatsApp Cloud API import in `src/channels/index.ts`:
|
||||
@@ -26,7 +26,7 @@ import './whatsapp-cloud.js';
|
||||
Build:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
@@ -16,7 +16,7 @@ Check if `src/channels/whatsapp.ts` exists and the import is uncommented in `src
|
||||
### Install the adapter packages
|
||||
|
||||
```bash
|
||||
npm install @whiskeysockets/baileys@^6.7.21 pino@^9.6.0 qrcode@^1.5.4 @types/qrcode@^1.5.6
|
||||
pnpm install @whiskeysockets/baileys@^6.7.21 pino@^9.6.0 qrcode@^1.5.4 @types/qrcode@^1.5.6
|
||||
```
|
||||
|
||||
### Enable the channel
|
||||
@@ -39,7 +39,7 @@ import './whatsapp.js';
|
||||
### Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Credentials
|
||||
@@ -90,7 +90,7 @@ rm -rf store/auth/
|
||||
For QR code in browser (recommended):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
```
|
||||
|
||||
(Bash timeout: 150000ms)
|
||||
@@ -106,7 +106,7 @@ Tell the user:
|
||||
For QR code in terminal:
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step whatsapp-auth -- --method qr-terminal
|
||||
pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-terminal
|
||||
```
|
||||
|
||||
(Bash timeout: 150000ms)
|
||||
@@ -123,7 +123,7 @@ Tell the user to have WhatsApp open on **Settings > Linked Devices > Link a Devi
|
||||
Run the auth process in the background and poll `store/pairing-code.txt` for the code:
|
||||
|
||||
```bash
|
||||
rm -f store/pairing-code.txt && npx tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <their-phone-number> > /tmp/wa-auth.log 2>&1 &
|
||||
rm -f store/pairing-code.txt && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <their-phone-number> > /tmp/wa-auth.log 2>&1 &
|
||||
```
|
||||
|
||||
Then immediately poll for the code (do NOT wait for the background command to finish):
|
||||
@@ -199,7 +199,7 @@ Not supported (WhatsApp linked device limitation): edit messages, delete message
|
||||
QR codes expire after ~60 seconds. Re-run the auth command:
|
||||
|
||||
```bash
|
||||
rm -rf store/auth/ && npx tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
```
|
||||
|
||||
### Pairing code not working
|
||||
@@ -207,7 +207,7 @@ rm -rf store/auth/ && npx tsx setup/index.ts --step whatsapp-auth -- --method qr
|
||||
Codes expire in ~60 seconds. Delete auth and retry:
|
||||
|
||||
```bash
|
||||
rm -rf store/auth/ && npx tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <phone>
|
||||
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <phone>
|
||||
```
|
||||
|
||||
Ensure: digits only (no `+`), phone has internet, WhatsApp is updated.
|
||||
@@ -215,7 +215,7 @@ Ensure: digits only (no `+`), phone has internet, WhatsApp is updated.
|
||||
If pairing code keeps failing, switch to QR-browser auth instead:
|
||||
|
||||
```bash
|
||||
rm -rf store/auth/ && npx tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
```
|
||||
|
||||
### "waiting for this message" on reactions
|
||||
|
||||
@@ -63,8 +63,8 @@ git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
|
||||
```bash
|
||||
git fetch whatsapp main
|
||||
git merge whatsapp/main || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -84,9 +84,9 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/channels/whatsapp.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/channels/whatsapp.test.ts
|
||||
```
|
||||
|
||||
All tests must pass and build must be clean before proceeding.
|
||||
@@ -104,7 +104,7 @@ rm -rf store/auth/
|
||||
For QR code in browser (recommended):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
```
|
||||
|
||||
(Bash timeout: 150000ms)
|
||||
@@ -120,10 +120,10 @@ Tell the user:
|
||||
For QR code in terminal:
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step whatsapp-auth -- --method qr-terminal
|
||||
pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-terminal
|
||||
```
|
||||
|
||||
Tell the user to run `npm run auth` in another terminal, then:
|
||||
Tell the user to run `pnpm run auth` in another terminal, then:
|
||||
|
||||
> 1. Open WhatsApp > **Settings** > **Linked Devices** > **Link a Device**
|
||||
> 2. Scan the QR code displayed in the terminal
|
||||
@@ -135,7 +135,7 @@ Tell the user to have WhatsApp open on **Settings > Linked Devices > Link a Devi
|
||||
Run the auth process in the background and poll `store/pairing-code.txt` for the code:
|
||||
|
||||
```bash
|
||||
rm -f store/pairing-code.txt && npx tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <their-phone-number> > /tmp/wa-auth.log 2>&1 &
|
||||
rm -f store/pairing-code.txt && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method pairing-code --phone <their-phone-number> > /tmp/wa-auth.log 2>&1 &
|
||||
```
|
||||
|
||||
Then immediately poll for the code (do NOT wait for the background command to finish):
|
||||
@@ -221,8 +221,8 @@ node -e "const c=JSON.parse(require('fs').readFileSync('store/auth/creds.json','
|
||||
**Group (solo, existing):** Run group sync and list available groups:
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step groups
|
||||
npx tsx setup/index.ts --step groups --list
|
||||
pnpm exec tsx setup/index.ts --step groups
|
||||
pnpm exec tsx setup/index.ts --step groups --list
|
||||
```
|
||||
|
||||
The output shows `JID|GroupName` pairs. Present candidates as AskUserQuestion (names only, not JIDs).
|
||||
@@ -230,7 +230,7 @@ The output shows `JID|GroupName` pairs. Present candidates as AskUserQuestion (n
|
||||
### Register the chat
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register \
|
||||
pnpm exec tsx setup/index.ts --step register \
|
||||
--jid "<jid>" \
|
||||
--name "<chat-name>" \
|
||||
--trigger "@<trigger>" \
|
||||
@@ -244,7 +244,7 @@ npx tsx setup/index.ts --step register \
|
||||
For additional groups (trigger-required):
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register \
|
||||
pnpm exec tsx setup/index.ts --step register \
|
||||
--jid "<group-jid>" \
|
||||
--name "<group-name>" \
|
||||
--trigger "@<trigger>" \
|
||||
@@ -257,7 +257,7 @@ npx tsx setup/index.ts --step register \
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Restart the service:
|
||||
@@ -296,7 +296,7 @@ tail -f logs/nanoclaw.log
|
||||
QR codes expire after ~60 seconds. Re-run the auth command:
|
||||
|
||||
```bash
|
||||
rm -rf store/auth/ && npx tsx src/whatsapp-auth.ts
|
||||
rm -rf store/auth/ && pnpm exec tsx src/whatsapp-auth.ts
|
||||
```
|
||||
|
||||
### Pairing code not working
|
||||
@@ -304,7 +304,7 @@ rm -rf store/auth/ && npx tsx src/whatsapp-auth.ts
|
||||
Codes expire in ~60 seconds. To retry:
|
||||
|
||||
```bash
|
||||
rm -rf store/auth/ && npx tsx src/whatsapp-auth.ts --pairing-code --phone <phone>
|
||||
rm -rf store/auth/ && pnpm exec tsx src/whatsapp-auth.ts --pairing-code --phone <phone>
|
||||
```
|
||||
|
||||
Enter the code **immediately** when it appears. Also ensure:
|
||||
@@ -315,7 +315,7 @@ Enter the code **immediately** when it appears. Also ensure:
|
||||
If pairing code keeps failing, switch to QR-browser auth instead:
|
||||
|
||||
```bash
|
||||
rm -rf store/auth/ && npx tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
rm -rf store/auth/ && pnpm exec tsx setup/index.ts --step whatsapp-auth -- --method qr-browser
|
||||
```
|
||||
|
||||
### "conflict" disconnection
|
||||
@@ -340,25 +340,25 @@ Check:
|
||||
Run group metadata sync:
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step groups
|
||||
pnpm exec tsx setup/index.ts --step groups
|
||||
```
|
||||
|
||||
This fetches all group names from WhatsApp. Runs automatically every 24 hours.
|
||||
|
||||
## After Setup
|
||||
|
||||
If running `npm run dev` while the service is active:
|
||||
If running `pnpm run dev` while the service is active:
|
||||
|
||||
```bash
|
||||
# macOS:
|
||||
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
npm run dev
|
||||
pnpm run dev
|
||||
# When done testing:
|
||||
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
|
||||
# Linux:
|
||||
# systemctl --user stop nanoclaw
|
||||
# npm run dev
|
||||
# pnpm run dev
|
||||
# systemctl --user start nanoclaw
|
||||
```
|
||||
|
||||
@@ -369,4 +369,4 @@ To remove WhatsApp integration:
|
||||
1. Delete auth credentials: `rm -rf store/auth/`
|
||||
2. Remove WhatsApp registrations: `sqlite3 store/messages.db "DELETE FROM registered_groups WHERE jid LIKE '%@g.us' OR jid LIKE '%@s.whatsapp.net'"`
|
||||
3. Sync env: `mkdir -p data/env && cp .env data/env/env`
|
||||
4. Rebuild and restart: `npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `npm run build && systemctl --user restart nanoclaw` (Linux)
|
||||
4. Rebuild and restart: `pnpm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `pnpm run build && systemctl --user restart nanoclaw` (Linux)
|
||||
|
||||
@@ -51,12 +51,12 @@ git fetch upstream skill/channel-formatting
|
||||
git merge upstream/skill/channel-formatting
|
||||
```
|
||||
|
||||
If there are merge conflicts on `package-lock.json`, resolve them by accepting the incoming
|
||||
If there are merge conflicts on `pnpm-lock.yaml`, resolve them by accepting the incoming
|
||||
version and continuing:
|
||||
|
||||
```bash
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
```
|
||||
|
||||
@@ -74,9 +74,9 @@ This merge adds:
|
||||
### Validate
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/formatting.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/formatting.test.ts
|
||||
```
|
||||
|
||||
All 73 tests should pass and the build should be clean before continuing.
|
||||
@@ -86,7 +86,7 @@ All 73 tests should pass and the build should be clean before continuing.
|
||||
### Rebuild and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
@@ -133,5 +133,5 @@ git checkout upstream/main -- src/router.ts
|
||||
# Revert the index.ts sendMessage call sites to plain formatOutbound(rawText)
|
||||
# (edit manually or: git checkout upstream/main -- src/index.ts)
|
||||
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
@@ -80,8 +80,8 @@ If the merge reports conflicts, resolve them by reading the conflicted files and
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm test
|
||||
npm run build
|
||||
pnpm test
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
All tests must pass and build must be clean before proceeding.
|
||||
@@ -172,7 +172,7 @@ Expected: Both operations succeed.
|
||||
### Full integration test
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
|
||||
```
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ Implementation:
|
||||
Always tell the user:
|
||||
```bash
|
||||
# Rebuild and restart
|
||||
npm run build
|
||||
pnpm run build
|
||||
# macOS:
|
||||
launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
|
||||
@@ -41,7 +41,7 @@ Set `LOG_LEVEL=debug` for verbose output:
|
||||
|
||||
```bash
|
||||
# For development
|
||||
LOG_LEVEL=debug npm run dev
|
||||
LOG_LEVEL=debug pnpm run dev
|
||||
|
||||
# For launchd service (macOS), add to plist EnvironmentVariables:
|
||||
<key>LOG_LEVEL</key>
|
||||
@@ -231,7 +231,7 @@ query({
|
||||
|
||||
```bash
|
||||
# Rebuild main app
|
||||
npm run build
|
||||
pnpm run build
|
||||
|
||||
# Rebuild container (use --no-cache for clean rebuild)
|
||||
./container/build.sh
|
||||
|
||||
@@ -231,10 +231,10 @@ Ask them to let you know when done.
|
||||
## Phase 4: Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
If build fails, diagnose and fix. Common issue: `@onecli-sh/sdk` not installed — run `npm install` first.
|
||||
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`
|
||||
|
||||
@@ -43,7 +43,7 @@ Use the channel's `typical-use` and `default-isolation` fields to pick the recom
|
||||
### Register Command
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- \
|
||||
pnpm exec tsx setup/index.ts --step register -- \
|
||||
--platform-id "<id>" --name "<name>" \
|
||||
--folder "<folder>" --channel "<type>" \
|
||||
--session-mode "<shared|agent-shared|per-thread>" \
|
||||
@@ -58,10 +58,10 @@ For separate agents, also ask for a folder name and optionally a different assis
|
||||
|
||||
When adding another group/chat on an already-configured platform (e.g. a second Telegram group):
|
||||
|
||||
1. **Telegram:** ask the isolation question first to determine intent (`wire-to:<folder>` for an existing agent, `new-agent:<folder>` for a fresh one). Run `npx tsx setup/index.ts --step pair-telegram -- --intent <intent>`, show the CODE (follow the `REMINDER_TO_ASSISTANT` line in the `PAIR_TELEGRAM_ISSUED` block) and tell the user to post `@<botname> CODE` in the target group (or DM the bot for a private chat). Wait for the `PAIR_TELEGRAM` block. The inbound interceptor has already created the `messaging_groups` row with `unknown_sender_policy = 'strict'` and upserted the paired user — `register` only needs to add the wiring:
|
||||
1. **Telegram:** ask the isolation question first to determine intent (`wire-to:<folder>` for an existing agent, `new-agent:<folder>` for a fresh one). Run `pnpm exec tsx setup/index.ts --step pair-telegram -- --intent <intent>`, show the CODE (follow the `REMINDER_TO_ASSISTANT` line in the `PAIR_TELEGRAM_ISSUED` block) and tell the user to post `@<botname> CODE` in the target group (or DM the bot for a private chat). Wait for the `PAIR_TELEGRAM` block. The inbound interceptor has already created the `messaging_groups` row with `unknown_sender_policy = 'strict'` and upserted the paired user — `register` only needs to add the wiring:
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- \
|
||||
pnpm exec tsx setup/index.ts --step register -- \
|
||||
--platform-id "<PLATFORM_ID>" --name "<group-name>" \
|
||||
--folder "<folder>" --channel "telegram" \
|
||||
--session-mode "<shared|agent-shared|per-thread>" \
|
||||
|
||||
@@ -68,7 +68,7 @@ Source: `src/db.ts`
|
||||
Insert directly into the SQLite database. This requires groups to be registered first (Phase 1). Use the registered group's `folder` and `chat_jid`:
|
||||
|
||||
```bash
|
||||
npx tsx -e "
|
||||
pnpm exec tsx -e "
|
||||
const Database = require('better-sqlite3');
|
||||
const { CronExpressionParser } = require('cron-parser');
|
||||
const db = new Database('store/messages.db');
|
||||
|
||||
@@ -36,7 +36,7 @@ Keep it factual and terse — this is for machine recovery after compaction, not
|
||||
Run the discovery script to find and summarize the OpenClaw installation:
|
||||
|
||||
```bash
|
||||
npx tsx ${CLAUDE_SKILL_DIR}/scripts/discover-openclaw.ts
|
||||
pnpm exec tsx ${CLAUDE_SKILL_DIR}/scripts/discover-openclaw.ts
|
||||
```
|
||||
|
||||
If the user specifies a custom path, pass it: `--state-dir <path>`
|
||||
@@ -106,7 +106,7 @@ The discovery script provides detected groups in the GROUPS field (format: `chan
|
||||
For each group the user wants to bring over, pre-register it:
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step register -- --jid "<nanoclaw_jid>" --name "<group_name>" --folder "<channel>_<slug>" --trigger "@<confirmed_name>" --channel <channel> --assistant-name "<confirmed_name>"
|
||||
pnpm exec tsx setup/index.ts --step register -- --jid "<nanoclaw_jid>" --name "<group_name>" --folder "<channel>_<slug>" --trigger "@<confirmed_name>" --channel <channel> --assistant-name "<confirmed_name>"
|
||||
```
|
||||
|
||||
Only pass `--assistant-name` on the first registration (it updates all CLAUDE.md templates globally).
|
||||
@@ -115,7 +115,7 @@ Folder naming: `<channel>_<name-slug>` (e.g. `whatsapp_family-chat`, `telegram_d
|
||||
|
||||
For the first/primary group, add `--is-main --no-trigger-required`. Other groups default to requiring a trigger prefix.
|
||||
|
||||
**Important:** Registration requires the database to exist. If the environment step hasn't been run yet, run it first: `npx tsx setup/index.ts --step environment`. Registration also creates the group folder under `groups/` and copies the CLAUDE.md template.
|
||||
**Important:** Registration requires the database to exist. If the environment step hasn't been run yet, run it first: `pnpm exec tsx setup/index.ts --step environment`. Registration also creates the group folder under `groups/` and copies the CLAUDE.md template.
|
||||
|
||||
Register groups from all channels — including channels NanoClaw doesn't yet support (signal, matrix, etc.). The registration stores the JID and metadata in the database, ready for when that channel is added later. Groups won't receive messages until their channel code is installed, but the registration, group folder, and CLAUDE.md will be ready.
|
||||
|
||||
@@ -295,7 +295,7 @@ For each detected plugin, present the name to the user and discuss whether to se
|
||||
|
||||
1. **If NanoClaw has a matching skill** — check the available NanoClaw skills list for an equivalent (e.g. `/add-voice-transcription` for whisper). If found, save the API key to `.env` and invoke that skill.
|
||||
|
||||
2. **If the OpenClaw plugin was an MCP server** — read its config to find the exact package name and command. Install the same MCP server (e.g. `npx -y <exact-package-from-config>`). Don't search for or guess at MCP packages — only install what was explicitly configured.
|
||||
2. **If the OpenClaw plugin was an MCP server** — read its config to find the exact package name and command. Install the same MCP server (e.g. `pnpm dlx <exact-package-from-config>`). Don't search for or guess at MCP packages — only install what was explicitly configured.
|
||||
|
||||
3. **If the OpenClaw plugin was a CLI tool** — read the config to identify the exact tool. If it's an npm package, add it to the container's Dockerfile. Add a note to the group's CLAUDE.md that the tool is available and how to invoke it.
|
||||
|
||||
@@ -324,7 +324,7 @@ Run the credential extraction script with `--write-env .env` so it writes creden
|
||||
First, run without `--write-env` to preview:
|
||||
|
||||
```bash
|
||||
npx tsx ${CLAUDE_SKILL_DIR}/scripts/extract-channel-credentials.ts --state-dir <STATE_DIR> --channel <name>
|
||||
pnpm exec tsx ${CLAUDE_SKILL_DIR}/scripts/extract-channel-credentials.ts --state-dir <STATE_DIR> --channel <name>
|
||||
```
|
||||
|
||||
Parse the status block. Key fields: HAS_CREDENTIAL, CREDENTIAL_MASKED, NANOCLAW_ENV_VAR.
|
||||
@@ -339,7 +339,7 @@ If HAS_CREDENTIAL=true: Show the masked credential (`CREDENTIAL_MASKED`). AskUse
|
||||
If using the credential:
|
||||
|
||||
```bash
|
||||
npx tsx ${CLAUDE_SKILL_DIR}/scripts/extract-channel-credentials.ts --state-dir <STATE_DIR> --channel <name> --write-env .env
|
||||
pnpm exec tsx ${CLAUDE_SKILL_DIR}/scripts/extract-channel-credentials.ts --state-dir <STATE_DIR> --channel <name> --write-env .env
|
||||
```
|
||||
|
||||
The script writes the credential directly to `.env` using the correct NanoClaw variable name (e.g. `TELEGRAM_BOT_TOKEN`). Check the status block for `WRITTEN_TO` and `WRITTEN_COUNT` to confirm.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Discover an existing OpenClaw installation and emit a structured summary.
|
||||
*
|
||||
* Usage: npx tsx .claude/skills/migrate-from-openclaw/scripts/discover-openclaw.ts [--state-dir <path>]
|
||||
* Usage: pnpm exec tsx .claude/skills/migrate-from-openclaw/scripts/discover-openclaw.ts [--state-dir <path>]
|
||||
*
|
||||
* Checks (in order): --state-dir arg, $OPENCLAW_STATE_DIR, ~/.openclaw, ~/.clawdbot
|
||||
* Parses openclaw.json (JSON5-tolerant), scans workspace for identity/memory files,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Extract a channel credential from an OpenClaw configuration and write it
|
||||
* directly to the NanoClaw .env file.
|
||||
*
|
||||
* Usage: npx tsx .claude/skills/migrate-from-openclaw/scripts/extract-channel-credentials.ts \
|
||||
* Usage: pnpm exec tsx .claude/skills/migrate-from-openclaw/scripts/extract-channel-credentials.ts \
|
||||
* --channel telegram --state-dir ~/.openclaw --write-env .env
|
||||
*
|
||||
* Handles OpenClaw SecretRef formats:
|
||||
|
||||
@@ -391,7 +391,7 @@ For behavior customizations (CLAUDE.md files): copy from the main tree. These ar
|
||||
## 2.6 Validate in worktree
|
||||
|
||||
```bash
|
||||
cd "$WORKTREE" && npm install && npm run build && npm test
|
||||
cd "$WORKTREE" && pnpm install && pnpm run build && pnpm test
|
||||
```
|
||||
|
||||
If build fails, show the error. Fix only issues caused by the migration. If unclear, ask the user.
|
||||
@@ -417,7 +417,7 @@ If testing live:
|
||||
ln -s "$PROJECT_ROOT/.env" "$WORKTREE/.env"
|
||||
```
|
||||
|
||||
3. Start from worktree: `cd "$WORKTREE" && npm run dev`
|
||||
3. Start from worktree: `cd "$WORKTREE" && pnpm run dev`
|
||||
|
||||
4. Ask the user to send a test message from their phone. Wait for them to confirm it works.
|
||||
|
||||
@@ -461,7 +461,7 @@ Do NOT use `git checkout -B` to create an intermediate branch — this caused is
|
||||
|
||||
## 2.9 Post-upgrade
|
||||
|
||||
Run `npm install && npm run build` in the main tree to confirm.
|
||||
Run `npm install && pnpm run build` in the main tree to confirm.
|
||||
|
||||
Restart the service:
|
||||
```bash
|
||||
|
||||
@@ -55,7 +55,7 @@ Run `bash setup.sh` and parse the status block.
|
||||
|
||||
## 2. Check Environment
|
||||
|
||||
Run `npx tsx setup/index.ts --step environment` and parse the status block.
|
||||
Run `pnpm exec tsx setup/index.ts --step environment` and parse the status block.
|
||||
|
||||
- If HAS_AUTH=true → WhatsApp is already configured, note for step 5
|
||||
- If HAS_REGISTERED_GROUPS=true → note existing config, offer to skip or reconfigure
|
||||
@@ -73,9 +73,9 @@ If "Migrate now": invoke `/migrate-from-openclaw`, then return here and continue
|
||||
|
||||
## 2a. Timezone
|
||||
|
||||
Run `npx tsx setup/index.ts --step timezone` and parse the status block.
|
||||
Run `pnpm exec tsx setup/index.ts --step timezone` and parse the status block.
|
||||
|
||||
- If NEEDS_USER_INPUT=true → The system timezone could not be autodetected (e.g. POSIX-style TZ like `IST-2`). AskUserQuestion: "What is your timezone?" with common options (America/New_York, Europe/London, Asia/Jerusalem, Asia/Tokyo) and an "Other" escape. Then re-run: `npx tsx setup/index.ts --step timezone -- --tz <their-answer>`.
|
||||
- If NEEDS_USER_INPUT=true → The system timezone could not be autodetected (e.g. POSIX-style TZ like `IST-2`). AskUserQuestion: "What is your timezone?" with common options (America/New_York, Europe/London, Asia/Jerusalem, Asia/Tokyo) and an "Other" escape. Then re-run: `pnpm exec tsx setup/index.ts --step timezone -- --tz <their-answer>`.
|
||||
- If STATUS=success and RESOLVED_TZ is `UTC` or `Etc/UTC` → confirm with the user: "Your system timezone is UTC — is that correct, or are you on a remote server?" If wrong, ask for their actual timezone and re-run with `--tz`.
|
||||
- If STATUS=success → Timezone is configured. Note RESOLVED_TZ for reference.
|
||||
|
||||
@@ -91,7 +91,7 @@ Run `npx tsx setup/index.ts --step timezone` and parse the status block.
|
||||
|
||||
### 3b. Build and test
|
||||
|
||||
Run `npx tsx setup/index.ts --step container -- --runtime docker` and parse the status block.
|
||||
Run `pnpm exec tsx setup/index.ts --step container -- --runtime docker` and parse the status block.
|
||||
|
||||
**If BUILD_OK=false:** Read `logs/setup.log` tail for the build error.
|
||||
- Cache issue (stale layers): `docker builder prune -f`. Retry.
|
||||
@@ -220,7 +220,7 @@ The skill will:
|
||||
**After the channel skill completes**, install dependencies and rebuild — channel merges may introduce new packages:
|
||||
|
||||
```bash
|
||||
npm install && npm run build
|
||||
pnpm install && pnpm run build
|
||||
```
|
||||
|
||||
If the build fails, read the error output and fix it (usually a missing dependency). Then continue to step 5a.
|
||||
@@ -230,7 +230,7 @@ If the build fails, read the error output and fix it (usually a missing dependen
|
||||
Set empty mount allowlist (agents only access their own workspace). Users can configure mounts later with `/manage-mounts`.
|
||||
|
||||
```bash
|
||||
npx tsx setup/index.ts --step mounts -- --empty
|
||||
pnpm exec tsx setup/index.ts --step mounts -- --empty
|
||||
```
|
||||
|
||||
## 7. Start Service
|
||||
@@ -239,7 +239,7 @@ If service already running: unload first.
|
||||
- macOS: `launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist`
|
||||
- Linux: `systemctl --user stop nanoclaw` (or `systemctl stop nanoclaw` if root)
|
||||
|
||||
Run `npx tsx setup/index.ts --step service` and parse the status block.
|
||||
Run `pnpm exec tsx setup/index.ts --step service` and parse the status block.
|
||||
|
||||
**If FALLBACK=wsl_no_systemd:** WSL without systemd detected. Tell user they can either enable systemd in WSL (`echo -e "[boot]\nsystemd=true" | sudo tee /etc/wsl.conf` then restart WSL) or use the generated `start-nanoclaw.sh` wrapper.
|
||||
|
||||
@@ -287,10 +287,10 @@ If yes: invoke `/add-vercel`.
|
||||
|
||||
## 8. Verify
|
||||
|
||||
Run `npx tsx setup/index.ts --step verify` and parse the status block.
|
||||
Run `pnpm exec tsx setup/index.ts --step verify` and parse the status block.
|
||||
|
||||
**If STATUS=failed, fix each:**
|
||||
- SERVICE=stopped → `npm run build`, then restart: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux) or `bash start-nanoclaw.sh` (WSL nohup)
|
||||
- SERVICE=stopped → `pnpm run build`, then restart: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw` (macOS) or `systemctl --user restart nanoclaw` (Linux) or `bash start-nanoclaw.sh` (WSL nohup)
|
||||
- SERVICE=not_found → re-run step 7
|
||||
- CREDENTIALS=missing → re-run step 4 (check `onecli secrets list`)
|
||||
- CHANNEL_AUTH shows `not_found` for any channel → re-invoke that channel's skill (e.g. `/add-telegram`)
|
||||
@@ -303,7 +303,7 @@ Tell user to test: send a message in their registered chat. Show: `tail -f logs/
|
||||
|
||||
**Container agent fails ("Claude Code process exited with code 1"):** Ensure Docker is running — `open -a Docker` (macOS) or `sudo systemctl start docker` (Linux). Check container logs in `groups/main/logs/container-*.log`.
|
||||
|
||||
**No response to messages:** Check trigger pattern. Main channel doesn't need prefix. Check DB: `npx tsx setup/index.ts --step verify`. Check `logs/nanoclaw.log`.
|
||||
**No response to messages:** Check trigger pattern. Main channel doesn't need prefix. Check DB: `pnpm exec tsx setup/index.ts --step verify`. Check `logs/nanoclaw.log`.
|
||||
|
||||
**Channel not connecting:** Verify the channel's credentials are set in `.env`. Channels auto-enable when their credentials are present. For WhatsApp: check `store/auth/creds.json` exists. For token-based channels: check token values in `.env`. Restart the service after any `.env` change.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Run `/update-nanoclaw` in Claude Code.
|
||||
|
||||
**Conflict resolution**: opens only conflicted files, resolves the conflict markers, keeps your local customizations intact.
|
||||
|
||||
**Validation**: runs `npm run build` and `npm test`.
|
||||
**Validation**: runs `pnpm run build` and `pnpm test`.
|
||||
|
||||
**Breaking changes check**: after validation, reads CHANGELOG.md for any `[BREAKING]` entries introduced by the update. If found, shows each breaking change and offers to run the recommended skill to migrate.
|
||||
|
||||
@@ -109,7 +109,7 @@ Show file-level impact from upstream:
|
||||
Bucket the upstream changed files:
|
||||
- **Skills** (`.claude/skills/`): unlikely to conflict unless the user edited an upstream skill
|
||||
- **Source** (`src/`): may conflict if user modified the same files
|
||||
- **Build/config** (`package.json`, `package-lock.json`, `tsconfig*.json`, `container/`, `launchd/`): review needed
|
||||
- **Build/config** (`package.json`, `pnpm-lock.yaml`, `tsconfig*.json`, `container/`, `launchd/`): review needed
|
||||
- **Other**: docs, tests, misc
|
||||
|
||||
**Large drift check:** If the upstream commit count and age suggest the user has a lot of catching up to do, mention that `/migrate-nanoclaw` might be a better fit — it extracts customizations and reapplies them on clean upstream instead of merging. Offer it as an option but don't push.
|
||||
@@ -175,8 +175,8 @@ If it gets messy (more than 3 rounds of conflicts):
|
||||
|
||||
# Step 5: Validation
|
||||
Run:
|
||||
- `npm run build`
|
||||
- `npm test` (do not fail the flow if tests are not configured)
|
||||
- `pnpm run build`
|
||||
- `pnpm test` (do not fail the flow if tests are not configured)
|
||||
|
||||
If build fails:
|
||||
- Show the error.
|
||||
@@ -234,7 +234,7 @@ Tell the user:
|
||||
- Backup branch also exists: `backup/pre-update-<HASH>-<TIMESTAMP>`
|
||||
- Restart the service to apply changes:
|
||||
- If using launchd: `launchctl unload ~/Library/LaunchAgents/com.nanoclaw.plist && launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist`
|
||||
- If running manually: restart `npm run dev`
|
||||
- If running manually: restart `pnpm run dev`
|
||||
|
||||
|
||||
## Diagnostics
|
||||
|
||||
@@ -110,8 +110,8 @@ If a merge fails badly (e.g., cannot resolve conflicts):
|
||||
# Step 4: Validation
|
||||
|
||||
After all selected skills are merged:
|
||||
- `npm run build`
|
||||
- `npm test` (do not fail the flow if tests are not configured)
|
||||
- `pnpm run build`
|
||||
- `pnpm test` (do not fail the flow if tests are not configured)
|
||||
|
||||
If build fails:
|
||||
- Show the error.
|
||||
|
||||
@@ -76,8 +76,8 @@ git remote add whatsapp https://github.com/qwibitai/nanoclaw-whatsapp.git
|
||||
```bash
|
||||
git fetch whatsapp skill/local-whisper
|
||||
git merge whatsapp/skill/local-whisper || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -87,7 +87,7 @@ This modifies `src/transcription.ts` to use the `whisper-cli` binary instead of
|
||||
### Validate
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
## Phase 3: Verify
|
||||
@@ -110,7 +110,7 @@ launchctl load ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
### Build and restart
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
|
||||
```
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ git remote add upstream https://github.com/qwibitai/nanoclaw.git
|
||||
```bash
|
||||
git fetch upstream skill/native-credential-proxy
|
||||
git merge upstream/skill/native-credential-proxy || {
|
||||
git checkout --theirs package-lock.json
|
||||
git add package-lock.json
|
||||
git checkout --theirs pnpm-lock.yaml
|
||||
git add pnpm-lock.yaml
|
||||
git merge --continue
|
||||
}
|
||||
```
|
||||
@@ -62,7 +62,7 @@ This merges in:
|
||||
- Restored platform-aware proxy bind address detection
|
||||
- Reverted setup skill to `.env`-based credential instructions
|
||||
|
||||
If the merge reports conflicts beyond `package-lock.json`, resolve them by reading the conflicted files and understanding the intent of both sides.
|
||||
If the merge reports conflicts beyond `pnpm-lock.yaml`, resolve them by reading the conflicted files and understanding the intent of both sides.
|
||||
|
||||
### Update main group CLAUDE.md
|
||||
|
||||
@@ -77,9 +77,9 @@ with:
|
||||
### Validate code changes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npx vitest run src/credential-proxy.test.ts src/container-runner.test.ts
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm exec vitest run src/credential-proxy.test.ts src/container-runner.test.ts
|
||||
```
|
||||
|
||||
All tests must pass and build must be clean before proceeding.
|
||||
@@ -125,7 +125,7 @@ echo 'ANTHROPIC_API_KEY=<key>' >> .env
|
||||
1. Rebuild and restart:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Then restart the service:
|
||||
@@ -161,7 +161,7 @@ To revert to OneCLI gateway:
|
||||
|
||||
1. Find the merge commit: `git log --oneline --merges -5`
|
||||
2. Revert it: `git revert <merge-commit> -m 1` (undoes the skill branch merge, keeps your other changes)
|
||||
3. `npm install` (re-adds `@onecli-sh/sdk`)
|
||||
4. `npm run build`
|
||||
3. `pnpm install` (re-adds `@onecli-sh/sdk`)
|
||||
4. `pnpm run build`
|
||||
5. Follow `/setup` step 4 to configure OneCLI credentials
|
||||
6. Remove `ANTHROPIC_API_KEY` / `CLAUDE_CODE_OAUTH_TOKEN` from `.env`
|
||||
|
||||
@@ -26,7 +26,7 @@ Before using this skill, ensure:
|
||||
1. **NanoClaw is installed and running** - WhatsApp connected, service active
|
||||
2. **Dependencies installed**:
|
||||
```bash
|
||||
npm ls playwright dotenv-cli || npm install playwright dotenv-cli
|
||||
pnpm ls playwright dotenv-cli || pnpm install playwright dotenv-cli
|
||||
```
|
||||
3. **CHROME_PATH configured** in `.env` (if Chrome is not at default location):
|
||||
```bash
|
||||
@@ -40,7 +40,7 @@ Before using this skill, ensure:
|
||||
|
||||
```bash
|
||||
# 1. Setup authentication (interactive)
|
||||
npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
# Verify: data/x-auth.json should exist after successful login
|
||||
|
||||
# 2. Rebuild container to include skill
|
||||
@@ -48,7 +48,7 @@ npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
# Verify: Output shows "COPY .claude/skills/x-integration/agent.ts"
|
||||
|
||||
# 3. Rebuild host and restart service
|
||||
npm run build
|
||||
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)
|
||||
@@ -225,7 +225,7 @@ COPY container/agent-runner/package*.json ./
|
||||
COPY container/agent-runner/ ./
|
||||
```
|
||||
|
||||
Then add COPY line after `COPY container/agent-runner/ ./` and before `RUN npm run build`:
|
||||
Then add COPY line after `COPY container/agent-runner/ ./` and before `RUN pnpm run build`:
|
||||
```dockerfile
|
||||
# Copy skill MCP tools
|
||||
COPY .claude/skills/x-integration/agent.ts ./src/skills/x-integration/
|
||||
@@ -247,7 +247,7 @@ echo "Chrome not found - update CHROME_PATH in .env"
|
||||
### 2. Run Authentication
|
||||
|
||||
```bash
|
||||
npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
```
|
||||
|
||||
This opens Chrome for manual X login. Session saved to `data/x-browser-profile/`.
|
||||
@@ -271,7 +271,7 @@ cat data/x-auth.json # Should show {"authenticated": true, ...}
|
||||
### 4. Restart Service
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
|
||||
# Linux: systemctl --user restart nanoclaw
|
||||
```
|
||||
@@ -317,26 +317,26 @@ ls -la data/x-browser-profile/ 2>/dev/null | head -5
|
||||
### Re-authenticate (if expired)
|
||||
|
||||
```bash
|
||||
npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
```
|
||||
|
||||
### Test Post (will actually post)
|
||||
|
||||
```bash
|
||||
echo '{"content":"Test tweet - please ignore"}' | npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/post.ts
|
||||
echo '{"content":"Test tweet - please ignore"}' | pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/post.ts
|
||||
```
|
||||
|
||||
### Test Like
|
||||
|
||||
```bash
|
||||
echo '{"tweetUrl":"https://x.com/user/status/123"}' | npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/like.ts
|
||||
echo '{"tweetUrl":"https://x.com/user/status/123"}' | pnpm exec dotenv -e .env -- pnpm exec tsx .claude/skills/x-integration/scripts/like.ts
|
||||
```
|
||||
|
||||
Or export `CHROME_PATH` manually before running:
|
||||
|
||||
```bash
|
||||
export CHROME_PATH="/path/to/chrome"
|
||||
echo '{"content":"Test"}' | npx tsx .claude/skills/x-integration/scripts/post.ts
|
||||
echo '{"content":"Test"}' | pnpm exec tsx .claude/skills/x-integration/scripts/post.ts
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
@@ -344,7 +344,7 @@ echo '{"content":"Test"}' | npx tsx .claude/skills/x-integration/scripts/post.ts
|
||||
### Authentication Expired
|
||||
|
||||
```bash
|
||||
npx dotenv -e .env -- npx tsx .claude/skills/x-integration/scripts/setup.ts
|
||||
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
|
||||
```
|
||||
|
||||
@@ -22,7 +22,7 @@ async function runScript(script: string, args: object): Promise<SkillResult> {
|
||||
const scriptPath = path.join(process.cwd(), '.claude', 'skills', 'x-integration', 'scripts', `${script}.ts`);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn('npx', ['tsx', scriptPath], {
|
||||
const proc = spawn('pnpm', ['exec', 'tsx', scriptPath], {
|
||||
cwd: process.cwd(),
|
||||
env: { ...process.env, NANOCLAW_ROOT: process.cwd() },
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
#!/usr/bin/env pnpm exec tsx
|
||||
/**
|
||||
* X Integration - Like Tweet
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123"}' | npx tsx like.ts
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123"}' | pnpm exec tsx like.ts
|
||||
*/
|
||||
|
||||
import { getBrowserContext, navigateToTweet, runScript, config, ScriptResult } from '../lib/browser.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
#!/usr/bin/env pnpm exec tsx
|
||||
/**
|
||||
* X Integration - Post Tweet
|
||||
* Usage: echo '{"content":"Hello world"}' | npx tsx post.ts
|
||||
* Usage: echo '{"content":"Hello world"}' | pnpm exec tsx post.ts
|
||||
*/
|
||||
|
||||
import { getBrowserContext, runScript, validateContent, config, ScriptResult } from '../lib/browser.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
#!/usr/bin/env pnpm exec tsx
|
||||
/**
|
||||
* X Integration - Quote Tweet
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123","comment":"My thoughts"}' | npx tsx quote.ts
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123","comment":"My thoughts"}' | pnpm exec tsx quote.ts
|
||||
*/
|
||||
|
||||
import { getBrowserContext, navigateToTweet, runScript, validateContent, config, ScriptResult } from '../lib/browser.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
#!/usr/bin/env pnpm exec tsx
|
||||
/**
|
||||
* X Integration - Reply to Tweet
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123","content":"Great post!"}' | npx tsx reply.ts
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123","content":"Great post!"}' | pnpm exec tsx reply.ts
|
||||
*/
|
||||
|
||||
import { getBrowserContext, navigateToTweet, runScript, validateContent, config, ScriptResult } from '../lib/browser.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
#!/usr/bin/env pnpm exec tsx
|
||||
/**
|
||||
* X Integration - Retweet
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123"}' | npx tsx retweet.ts
|
||||
* Usage: echo '{"tweetUrl":"https://x.com/user/status/123"}' | pnpm exec tsx retweet.ts
|
||||
*/
|
||||
|
||||
import { getBrowserContext, navigateToTweet, runScript, config, ScriptResult } from '../lib/browser.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
#!/usr/bin/env pnpm exec tsx
|
||||
/**
|
||||
* X Integration - Authentication Setup
|
||||
* Usage: npx tsx setup.ts
|
||||
* Usage: pnpm exec tsx setup.ts
|
||||
*
|
||||
* Interactive script - opens browser for manual login
|
||||
*/
|
||||
|
||||
6
.github/workflows/bump-version.yml
vendored
6
.github/workflows/bump-version.yml
vendored
@@ -20,10 +20,12 @@ jobs:
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Bump patch version
|
||||
run: |
|
||||
npm version patch --no-git-tag-version
|
||||
git add package.json package-lock.json
|
||||
pnpm version patch --no-git-tag-version
|
||||
git add package.json
|
||||
git diff --cached --quiet && exit 0
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -9,17 +9,18 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: npm
|
||||
- run: npm ci
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Format check
|
||||
run: npm run format:check
|
||||
run: pnpm run format:check
|
||||
|
||||
- name: Typecheck
|
||||
run: npx tsc --noEmit
|
||||
run: pnpm exec tsc --noEmit
|
||||
|
||||
- name: Tests
|
||||
run: npx vitest run
|
||||
run: pnpm exec vitest run
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
.npm-cache/
|
||||
# pnpm content-addressable store (created when running in sandbox mode)
|
||||
.pnpm-store/
|
||||
# Build output
|
||||
dist/
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
npm run format:fix
|
||||
pnpm run format:fix
|
||||
|
||||
4
.npmrc
4
.npmrc
@@ -1 +1,3 @@
|
||||
minReleaseAge=7d
|
||||
# Safety net — pnpm-workspace.yaml has the authoritative minimumReleaseAge (4320 min = 3 days)
|
||||
# This .npmrc value is a fallback if npm is ever invoked directly
|
||||
minReleaseAge=3d
|
||||
|
||||
19
CLAUDE.md
19
CLAUDE.md
@@ -102,13 +102,13 @@ Before creating a PR, adding a skill, or preparing any contribution, you MUST re
|
||||
Run commands directly — don't tell the user to run them.
|
||||
|
||||
```bash
|
||||
npm run dev # Host with hot reload
|
||||
npm run build # Compile host TypeScript (src/)
|
||||
./container/build.sh # Rebuild agent container image (nanoclaw-agent:latest)
|
||||
npm test # Host tests
|
||||
pnpm run dev # Host with hot reload
|
||||
pnpm run build # Compile host TypeScript (src/)
|
||||
./container/build.sh # Rebuild agent container image (nanoclaw-agent:latest)
|
||||
pnpm test # Host tests
|
||||
```
|
||||
|
||||
Container typecheck is a separate tsconfig — if you edit `container/agent-runner/src/`, run `npx tsc -p container/agent-runner/tsconfig.json --noEmit` to check it.
|
||||
Container typecheck is a separate tsconfig — if you edit `container/agent-runner/src/`, run `pnpm exec tsc -p container/agent-runner/tsconfig.json --noEmit` to check it.
|
||||
|
||||
Service management:
|
||||
```bash
|
||||
@@ -123,6 +123,15 @@ systemctl --user start|stop|restart nanoclaw
|
||||
|
||||
Host logs: `logs/nanoclaw.log` (normal) and `logs/nanoclaw.error.log` (errors only — some delivery/approval failures only show up here).
|
||||
|
||||
## Supply Chain Security (pnpm)
|
||||
|
||||
This project uses pnpm with `minimumReleaseAge: 4320` (3 days) in `pnpm-workspace.yaml`. New package versions must exist on the npm registry for 3 days before pnpm will resolve them.
|
||||
|
||||
**Rules — do not bypass without explicit human approval:**
|
||||
- **`minimumReleaseAgeExclude`**: Never add entries without human sign-off. If a package must bypass the release age gate, the human must approve and the entry must pin the exact version being excluded (e.g. `package@1.2.3`), never a range.
|
||||
- **`onlyBuiltDependencies`**: Never add packages to this list without human approval — build scripts execute arbitrary code during install.
|
||||
- **`pnpm install --frozen-lockfile`** should be used in CI, automation, and container builds. Never run bare `pnpm install` in those contexts.
|
||||
|
||||
## v2 Docs Index
|
||||
|
||||
| Doc | Purpose |
|
||||
|
||||
2
container/.dockerignore
Normal file
2
container/.dockerignore
Normal file
@@ -0,0 +1,2 @@
|
||||
agent-runner/node_modules
|
||||
agent-runner/dist
|
||||
@@ -30,23 +30,29 @@ RUN apt-get update && apt-get install -y \
|
||||
ENV AGENT_BROWSER_EXECUTABLE_PATH=/usr/bin/chromium
|
||||
ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
|
||||
|
||||
# Install agent-browser and claude-code globally
|
||||
RUN npm install -g agent-browser @anthropic-ai/claude-code vercel
|
||||
# Enable pnpm via corepack
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
|
||||
# Allow agent-browser build scripts for global install, then install
|
||||
RUN echo "only-built-dependencies[]=agent-browser" > /root/.npmrc && \
|
||||
pnpm install -g agent-browser @anthropic-ai/claude-code vercel
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files first for better caching
|
||||
COPY agent-runner/package*.json ./
|
||||
COPY agent-runner/package.json agent-runner/pnpm-lock.yaml agent-runner/pnpm-workspace.yaml ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm install
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# Copy source code
|
||||
COPY agent-runner/ ./
|
||||
|
||||
# Build TypeScript
|
||||
RUN npm run build
|
||||
RUN pnpm run build
|
||||
|
||||
# Create workspace directories
|
||||
RUN mkdir -p /workspace/group /workspace/global /workspace/extra
|
||||
@@ -56,7 +62,7 @@ RUN mkdir -p /workspace/group /workspace/global /workspace/extra
|
||||
# recompiles on startup — this lets host source edits and skill installs
|
||||
# take effect without rebuilding the image. All IO goes through the session
|
||||
# DBs (inbound.db / outbound.db) mounted into /workspace.
|
||||
RUN printf '#!/bin/bash\nset -e\ncd /app && npx tsc --outDir /tmp/dist 2>&1 >&2\nln -s /app/node_modules /tmp/dist/node_modules\nchmod -R a-w /tmp/dist\ncat > /tmp/input.json\nnode /tmp/dist/index.js < /tmp/input.json\n' > /app/entrypoint.sh && chmod +x /app/entrypoint.sh
|
||||
RUN printf '#!/bin/bash\nset -e\ncd /app && pnpm exec tsc --outDir /tmp/dist 2>&1 >&2\nln -s /app/node_modules /tmp/dist/node_modules\nchmod -R a-w /tmp/dist\ncat > /tmp/input.json\nnode /tmp/dist/index.js < /tmp/input.json\n' > /app/entrypoint.sh && chmod +x /app/entrypoint.sh
|
||||
|
||||
# Set ownership to node user (non-root) for writable directories
|
||||
RUN chown -R node:node /workspace && chmod 777 /home/node
|
||||
|
||||
2016
container/agent-runner/package-lock.json
generated
2016
container/agent-runner/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
1309
container/agent-runner/pnpm-lock.yaml
generated
Normal file
1309
container/agent-runner/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
container/agent-runner/pnpm-workspace.yaml
Normal file
5
container/agent-runner/pnpm-workspace.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
onlyBuiltDependencies:
|
||||
- better-sqlite3
|
||||
|
||||
pnpm:
|
||||
minimumReleaseAge: 4320
|
||||
@@ -66,7 +66,7 @@ Every frontend task follows this sequence. Do not skip steps.
|
||||
Run the build and fix ALL errors:
|
||||
|
||||
```bash
|
||||
npm run build 2>&1
|
||||
pnpm run build 2>&1
|
||||
```
|
||||
|
||||
If it fails, **fix it**. Do not deploy broken builds. Do not disable ESLint rules or TypeScript checks to make it pass.
|
||||
@@ -76,7 +76,7 @@ If it fails, **fix it**. Do not deploy broken builds. Do not disable ESLint rule
|
||||
Start the dev server and test in a real browser:
|
||||
|
||||
```bash
|
||||
npm run dev &
|
||||
pnpm run dev &
|
||||
DEV_PID=$!
|
||||
sleep 3
|
||||
```
|
||||
|
||||
@@ -87,4 +87,4 @@ User: "Can you transcribe audio?"
|
||||
|
||||
- **The change is for a one-off task** — just do it in your workspace, don't modify the container
|
||||
- **The request is ambiguous** — ask the user what they actually need before spinning up builders or requesting installs
|
||||
- **You don't know if it will work** — prototype in your workspace first (`npm install` in `/workspace/agent/`), then promote to container-level install if it proves useful
|
||||
- **You don't know if it will work** — prototype in your workspace first (`pnpm install` in `/workspace/agent/`), then promote to container-level install if it proves useful
|
||||
|
||||
@@ -117,7 +117,7 @@ After sending, tell the user you've handed it off and will share the result when
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Run `npm run build` locally before deploying to catch build errors early
|
||||
- Run `pnpm run build` locally before deploying to catch build errors early
|
||||
- Use `--cwd` instead of `cd` to keep your working directory stable
|
||||
- For Next.js projects, `vercel deploy` auto-detects the framework — no extra config needed
|
||||
- Use `vercel.json` only when you need custom build settings, rewrites, or headers
|
||||
|
||||
@@ -57,7 +57,7 @@ The same files conflict every time:
|
||||
| File | Resolution |
|
||||
|------|------------|
|
||||
| `package.json` | Take main's version + keep fork/branch-specific deps |
|
||||
| `package-lock.json` | `git checkout main -- package-lock.json && npm install` |
|
||||
| `pnpm-lock.yaml` | `git checkout main -- pnpm-lock.yaml && pnpm install` |
|
||||
| `.env.example` | Combine: main's entries + fork/branch-specific entries |
|
||||
| `repo-tokens/badge.svg` | Take main's version (auto-generated) |
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ grep 'QR\|authentication required\|qr' logs/nanoclaw.log | tail -5
|
||||
ls -la store/auth/
|
||||
|
||||
# Re-authenticate if needed
|
||||
npm run auth
|
||||
pnpm run auth
|
||||
```
|
||||
|
||||
## Service Management
|
||||
@@ -167,5 +167,5 @@ launchctl bootout gui/$(id -u)/com.nanoclaw
|
||||
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.nanoclaw.plist
|
||||
|
||||
# Rebuild after code changes
|
||||
npm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw
|
||||
pnpm run build && launchctl kickstart -k gui/$(id -u)/com.nanoclaw
|
||||
```
|
||||
|
||||
@@ -123,3 +123,39 @@ Each NanoClaw group gets its own OneCLI agent identity. This allows different cr
|
||||
│ • No real credentials in environment or filesystem │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Supply Chain Security (pnpm)
|
||||
|
||||
NanoClaw uses pnpm with two supply chain defenses configured in `pnpm-workspace.yaml`:
|
||||
|
||||
### Minimum Release Age
|
||||
|
||||
`minimumReleaseAge: 4320` (3 days). pnpm will refuse to resolve any package version published less than 3 days ago. This defends against typosquatting and compromised maintainer accounts — most malicious publishes are detected and pulled within 72 hours.
|
||||
|
||||
**Excluding a package from the release age gate** (`minimumReleaseAgeExclude`):
|
||||
|
||||
This should be rare. When a zero-day fix or critical dependency requires an immediate update:
|
||||
|
||||
1. The exclusion must be reviewed and approved by a human maintainer
|
||||
2. The entry must pin the **exact version** being excluded — never a range or wildcard
|
||||
```yaml
|
||||
minimumReleaseAgeExclude:
|
||||
some-package: "1.2.3" # Approved by @user, 2026-04-14 — CVE-XXXX-YYYY fix
|
||||
```
|
||||
3. The exclusion should be removed once the version ages past the threshold (i.e. after 3 days)
|
||||
4. Automated agents (Claude, CI bots) must never add exclusions without human sign-off
|
||||
|
||||
### Build Script Allowlist
|
||||
|
||||
`onlyBuiltDependencies` restricts which packages can execute install/postinstall scripts. Only packages on this list are permitted to run build scripts during `pnpm install`. Currently allowed:
|
||||
|
||||
- `better-sqlite3` — compiles native SQLite bindings
|
||||
- `esbuild` — downloads platform-specific binary
|
||||
- `protobufjs` — generates protobuf bindings (used by Baileys/libsignal)
|
||||
- `sharp` — downloads platform-specific image processing binary
|
||||
|
||||
Adding a package to this list requires human approval — build scripts execute arbitrary code with the installing user's permissions.
|
||||
|
||||
### `.npmrc` Safety Net
|
||||
|
||||
The `.npmrc` file contains `minReleaseAge=3d` as a fallback. The authoritative setting is in `pnpm-workspace.yaml`, but `.npmrc` provides defense-in-depth if npm is ever invoked directly (e.g. by a tool that doesn't respect pnpm).
|
||||
|
||||
@@ -404,7 +404,7 @@ Only the authentication variables (`CLAUDE_CODE_OAUTH_TOKEN` and `ANTHROPIC_API_
|
||||
Set the `ASSISTANT_NAME` environment variable:
|
||||
|
||||
```bash
|
||||
ASSISTANT_NAME=Bot npm start
|
||||
ASSISTANT_NAME=Bot pnpm start
|
||||
```
|
||||
|
||||
Or edit the default in `src/config.ts`. This changes:
|
||||
@@ -779,7 +779,7 @@ chmod 700 groups/
|
||||
|
||||
Run manually for verbose output:
|
||||
```bash
|
||||
npm run dev
|
||||
pnpm run dev
|
||||
# or
|
||||
node dist/index.js
|
||||
```
|
||||
|
||||
@@ -87,8 +87,8 @@ mv nanoclaw "$WORKSPACE/nanoclaw"
|
||||
cd "$WORKSPACE/nanoclaw"
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
npm install https-proxy-agent
|
||||
pnpm install
|
||||
pnpm install https-proxy-agent
|
||||
```
|
||||
|
||||
## Step 4: Apply Proxy and Sandbox Patches
|
||||
@@ -97,7 +97,7 @@ NanoClaw needs several patches to work inside a Docker Sandbox. These handle pro
|
||||
|
||||
### 4a. Dockerfile — proxy args for container image build
|
||||
|
||||
`npm install` inside `docker build` fails with `SELF_SIGNED_CERT_IN_CHAIN` because the sandbox's MITM proxy presents its own certificate. Add proxy build args to `container/Dockerfile`:
|
||||
`pnpm install` inside `docker build` fails with `SELF_SIGNED_CERT_IN_CHAIN` because the sandbox's MITM proxy presents its own certificate. Add proxy build args to `container/Dockerfile`:
|
||||
|
||||
Add these lines after the `FROM` line:
|
||||
|
||||
@@ -111,7 +111,7 @@ ARG npm_config_strict_ssl=true
|
||||
RUN npm config set strict-ssl ${npm_config_strict_ssl}
|
||||
```
|
||||
|
||||
And after the `RUN npm install` line:
|
||||
And after the `RUN pnpm install` line:
|
||||
|
||||
```dockerfile
|
||||
RUN npm config set strict-ssl true
|
||||
@@ -185,7 +185,7 @@ Patch `setup/container.ts` to pass the same proxy `--build-arg` flags as `build.
|
||||
## Step 5: Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
pnpm run build
|
||||
bash container/build.sh
|
||||
```
|
||||
|
||||
@@ -195,10 +195,10 @@ bash container/build.sh
|
||||
|
||||
```bash
|
||||
# Apply the Telegram skill
|
||||
npx tsx scripts/apply-skill.ts .claude/skills/add-telegram
|
||||
pnpm exec tsx scripts/apply-skill.ts .claude/skills/add-telegram
|
||||
|
||||
# Rebuild after applying the skill
|
||||
npm run build
|
||||
pnpm run build
|
||||
|
||||
# Configure .env
|
||||
cat > .env << EOF
|
||||
@@ -209,7 +209,7 @@ EOF
|
||||
mkdir -p data/env && cp .env data/env/env
|
||||
|
||||
# Register your chat
|
||||
npx tsx setup/index.ts --step register \
|
||||
pnpm exec tsx setup/index.ts --step register \
|
||||
--jid "tg:<your-chat-id>" \
|
||||
--name "My Chat" \
|
||||
--trigger "@nanoclaw" \
|
||||
@@ -235,10 +235,10 @@ Make sure you configured proxy bypass in [Step 1](#step-1-create-the-sandbox) fi
|
||||
|
||||
```bash
|
||||
# Apply the WhatsApp skill
|
||||
npx tsx scripts/apply-skill.ts .claude/skills/add-whatsapp
|
||||
pnpm exec tsx scripts/apply-skill.ts .claude/skills/add-whatsapp
|
||||
|
||||
# Rebuild
|
||||
npm run build
|
||||
pnpm run build
|
||||
|
||||
# Configure .env
|
||||
cat > .env << EOF
|
||||
@@ -250,13 +250,13 @@ mkdir -p data/env && cp .env data/env/env
|
||||
# Authenticate (choose one):
|
||||
|
||||
# QR code — scan with WhatsApp camera:
|
||||
npx tsx src/whatsapp-auth.ts
|
||||
pnpm exec tsx src/whatsapp-auth.ts
|
||||
|
||||
# OR pairing code — enter code in WhatsApp > Linked Devices > Link with phone number:
|
||||
npx tsx src/whatsapp-auth.ts --pairing-code --phone <phone-number-no-plus>
|
||||
pnpm exec tsx src/whatsapp-auth.ts --pairing-code --phone <phone-number-no-plus>
|
||||
|
||||
# Register your chat (JID = your phone number + @s.whatsapp.net)
|
||||
npx tsx setup/index.ts --step register \
|
||||
pnpm exec tsx setup/index.ts --step register \
|
||||
--jid "<phone>@s.whatsapp.net" \
|
||||
--name "My Chat" \
|
||||
--trigger "@nanoclaw" \
|
||||
@@ -276,7 +276,7 @@ Apply both skills, patch both for proxy support, combine the `.env` variables, a
|
||||
## Step 7: Run
|
||||
|
||||
```bash
|
||||
npm start
|
||||
pnpm start
|
||||
```
|
||||
|
||||
You don't need to set `ANTHROPIC_API_KEY` manually. The sandbox proxy intercepts requests and replaces `proxy-managed` with your real key automatically.
|
||||
@@ -306,7 +306,7 @@ The workspace is mounted via virtiofs. Git's pack file handling can corrupt over
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### npm install fails with SELF_SIGNED_CERT_IN_CHAIN
|
||||
### pnpm install fails with SELF_SIGNED_CERT_IN_CHAIN
|
||||
```bash
|
||||
npm config set strict-ssl false
|
||||
```
|
||||
@@ -355,5 +355,5 @@ Run the auth command interactively inside the sandbox (not piped through `docker
|
||||
```bash
|
||||
docker sandbox run shell-nanoclaw-workspace
|
||||
# Then inside:
|
||||
npx tsx src/whatsapp-auth.ts
|
||||
pnpm exec tsx src/whatsapp-auth.ts
|
||||
```
|
||||
|
||||
@@ -98,7 +98,7 @@ Standard Markdown works: `**bold**`, `*italic*`, `[links](url)`, `# headings`.
|
||||
|
||||
## Installing Packages & Tools
|
||||
|
||||
Your container is ephemeral — anything installed via `apt-get` or `npm install -g` is lost on restart. To install packages that persist, use the self-modification tools:
|
||||
Your container is ephemeral — anything installed via `apt-get` or `pnpm install -g` is lost on restart. To install packages that persist, use the self-modification tools:
|
||||
|
||||
1. **`install_packages`** — request system (apt) or global npm packages. Requires admin approval.
|
||||
2. **`request_rebuild`** — rebuild your container image so approved packages are baked in. Always call this after `install_packages` to apply the changes.
|
||||
@@ -111,16 +111,16 @@ request_rebuild({ reason: "Apply ffmpeg + transformers" })
|
||||
# → Admin approves → image rebuilt with the packages
|
||||
```
|
||||
|
||||
**When to use this vs workspace npm install:**
|
||||
- `npm install` in `/workspace/agent/` persists on disk (it's mounted) but isn't on the global PATH — use it for project-level dependencies
|
||||
**When to use this vs workspace pnpm install:**
|
||||
- `pnpm install` in `/workspace/agent/` persists on disk (it's mounted) but isn't on the global PATH — use it for project-level dependencies
|
||||
- `install_packages` is for system tools (ffmpeg, imagemagick) and global npm packages that need to be on PATH
|
||||
|
||||
### MCP Servers
|
||||
|
||||
Use **`add_mcp_server`** to add an MCP server to your configuration, then **`request_rebuild`** to apply. Browse available servers at https://mcp.so — it's a curated directory of high-quality MCP servers. Most Node.js servers run via `npx`, e.g.:
|
||||
Use **`add_mcp_server`** to add an MCP server to your configuration, then **`request_rebuild`** to apply. Browse available servers at https://mcp.so — it's a curated directory of high-quality MCP servers. Most Node.js servers run via `pnpm dlx`, e.g.:
|
||||
|
||||
```
|
||||
add_mcp_server({ name: "memory", command: "npx", args: ["@modelcontextprotocol/server-memory"] })
|
||||
add_mcp_server({ name: "memory", command: "pnpm", args: ["dlx", "@modelcontextprotocol/server-memory"] })
|
||||
request_rebuild({ reason: "Add memory MCP server" })
|
||||
```
|
||||
|
||||
|
||||
10160
package-lock.json
generated
10160
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
"version": "1.2.52",
|
||||
"description": "Personal Claude assistant. Lightweight, secure, customizable.",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.33.0",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
|
||||
6792
pnpm-lock.yaml
generated
Normal file
6792
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
8
pnpm-workspace.yaml
Normal file
8
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
onlyBuiltDependencies:
|
||||
- better-sqlite3
|
||||
- esbuild
|
||||
- protobufjs
|
||||
- sharp
|
||||
|
||||
pnpm:
|
||||
minimumReleaseAge: 4320
|
||||
@@ -10,7 +10,7 @@
|
||||
* channel adapters, so there's no Gateway conflict.
|
||||
*
|
||||
* Usage:
|
||||
* npx tsx scripts/init-first-agent.ts \
|
||||
* pnpm exec tsx scripts/init-first-agent.ts \
|
||||
* --channel discord \
|
||||
* --user-id discord:1470183333427675709 \
|
||||
* --platform-id discord:@me:1491573333382523708 \
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*
|
||||
* Idempotent — safe to re-run.
|
||||
*
|
||||
* Usage: npx tsx scripts/migrate-group-claude-md.ts
|
||||
* Usage: pnpm exec tsx scripts/migrate-group-claude-md.ts
|
||||
*/
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Seed the v2 central DB with a Discord agent group + messaging group.
|
||||
*
|
||||
* Usage: npx tsx scripts/seed-discord.ts
|
||||
* Usage: pnpm exec tsx scripts/seed-discord.ts
|
||||
*/
|
||||
import path from 'path';
|
||||
|
||||
@@ -73,4 +73,4 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Done! Run: npm run build && node dist/index.js');
|
||||
console.log('Done! Run: pnpm run build && node dist/index.js');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Quick integration test: create a session DB, insert a message,
|
||||
* run the v2 poll loop with the Claude provider, verify output.
|
||||
*
|
||||
* Usage: npx tsx scripts/test-v2-agent.ts
|
||||
* Usage: pnpm exec tsx scripts/test-v2-agent.ts
|
||||
*/
|
||||
import Database from 'better-sqlite3';
|
||||
import fs from 'fs';
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Mock adapter → onInbound → router → session DB → Docker container →
|
||||
* agent-runner → Claude → messages_out → delivery → mock adapter.deliver()
|
||||
*
|
||||
* Usage: npx tsx scripts/test-v2-channel-e2e.ts
|
||||
* Usage: pnpm exec tsx scripts/test-v2-channel-e2e.ts
|
||||
*/
|
||||
import Database from 'better-sqlite3';
|
||||
import fs from 'fs';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 3. Container runs v2 agent-runner, polls inbound.db, queries Claude, writes outbound.db
|
||||
* 4. Poll outbound.db for messages_out response
|
||||
*
|
||||
* Usage: npx tsx scripts/test-v2-host.ts
|
||||
* Usage: pnpm exec tsx scripts/test-v2-host.ts
|
||||
*/
|
||||
import Database from 'better-sqlite3';
|
||||
import fs from 'fs';
|
||||
|
||||
23
setup.sh
23
setup.sh
@@ -2,7 +2,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
# setup.sh — Bootstrap script for NanoClaw
|
||||
# Handles Node.js/npm setup, then hands off to the Node.js setup modules.
|
||||
# Handles Node.js/pnpm setup, then hands off to the Node.js setup modules.
|
||||
# This is the only bash script in the setup flow.
|
||||
|
||||
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
@@ -59,32 +59,29 @@ check_node() {
|
||||
fi
|
||||
}
|
||||
|
||||
# --- npm install ---
|
||||
# --- pnpm install ---
|
||||
|
||||
install_deps() {
|
||||
DEPS_OK="false"
|
||||
NATIVE_OK="false"
|
||||
|
||||
if [ "$NODE_OK" = "false" ]; then
|
||||
log "Skipping npm install — Node not available"
|
||||
log "Skipping pnpm install — Node not available"
|
||||
return
|
||||
fi
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# npm install with --unsafe-perm if root (needed for native modules)
|
||||
local npm_flags=""
|
||||
if [ "$IS_ROOT" = "true" ]; then
|
||||
npm_flags="--unsafe-perm"
|
||||
log "Running as root, using --unsafe-perm"
|
||||
fi
|
||||
# Enable corepack for pnpm
|
||||
log "Enabling corepack"
|
||||
corepack enable >> "$LOG_FILE" 2>&1 || true
|
||||
|
||||
log "Running npm ci $npm_flags"
|
||||
if npm ci $npm_flags >> "$LOG_FILE" 2>&1; then
|
||||
log "Running pnpm install --frozen-lockfile"
|
||||
if pnpm install --frozen-lockfile >> "$LOG_FILE" 2>&1; then
|
||||
DEPS_OK="true"
|
||||
log "npm install succeeded"
|
||||
log "pnpm install succeeded"
|
||||
else
|
||||
log "npm install failed"
|
||||
log "pnpm install failed"
|
||||
return
|
||||
fi
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ async function syncGroups(projectRoot: string): Promise<void> {
|
||||
log.info('Building TypeScript');
|
||||
let buildOk = false;
|
||||
try {
|
||||
execSync('npm run build', {
|
||||
execSync('pnpm run build', {
|
||||
cwd: projectRoot,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Setup CLI entry point.
|
||||
* Usage: npx tsx setup/index.ts --step <name> [args...]
|
||||
* Usage: pnpm exec tsx setup/index.ts --step <name> [args...]
|
||||
*/
|
||||
import { log } from '../src/log.js';
|
||||
import { emitStatus } from './status.js';
|
||||
@@ -27,7 +27,7 @@ async function main(): Promise<void> {
|
||||
|
||||
if (stepIdx === -1 || !args[stepIdx + 1]) {
|
||||
console.error(
|
||||
`Usage: npx tsx setup/index.ts --step <${Object.keys(STEPS).join('|')}> [args...]`,
|
||||
`Usage: pnpm exec tsx setup/index.ts --step <${Object.keys(STEPS).join('|')}> [args...]`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function run(_args: string[]): Promise<void> {
|
||||
// Build first
|
||||
log.info('Building TypeScript');
|
||||
try {
|
||||
execSync('npm run build', {
|
||||
execSync('pnpm run build', {
|
||||
cwd: projectRoot,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
@@ -298,7 +298,7 @@ async function buildContainerArgs(
|
||||
|
||||
args.push(
|
||||
'-c',
|
||||
'cd /app && npx tsc --outDir /tmp/dist 2>&1 >&2 && ln -sf /app/node_modules /tmp/dist/node_modules && node /tmp/dist/index.js',
|
||||
'cd /app && pnpm exec tsc --outDir /tmp/dist 2>&1 >&2 && ln -sf /app/node_modules /tmp/dist/node_modules && node /tmp/dist/index.js',
|
||||
);
|
||||
|
||||
return args;
|
||||
@@ -322,7 +322,12 @@ export async function buildAgentGroupImage(agentGroupId: string): Promise<void>
|
||||
dockerfile += `RUN apt-get update && apt-get install -y ${aptPackages.join(' ')} && rm -rf /var/lib/apt/lists/*\n`;
|
||||
}
|
||||
if (npmPackages.length > 0) {
|
||||
dockerfile += `RUN npm install -g ${npmPackages.join(' ')}\n`;
|
||||
// pnpm skips build scripts unless packages are allowlisted. Append each
|
||||
// to /root/.npmrc (base image sets it up for agent-browser) so packages
|
||||
// with postinstall — e.g. playwright, puppeteer, native addons — don't
|
||||
// install silently broken.
|
||||
const allowlist = npmPackages.map((p) => `echo 'only-built-dependencies[]=${p}' >> /root/.npmrc`).join(' && ');
|
||||
dockerfile += `RUN ${allowlist} && pnpm install -g ${npmPackages.join(' ')}\n`;
|
||||
}
|
||||
dockerfile += 'USER node\n';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user