* feat: add Slack channel skill (/add-slack)
Slack Bot integration via @slack/bolt with Socket Mode. Can replace
WhatsApp entirely (SLACK_ONLY=true) or run alongside it.
- SlackChannel implementing Channel interface (46 unit tests)
- Socket Mode connection (no public URL needed)
- @mention translation (Slack <@UBOTID> → TRIGGER_PATTERN)
- Message splitting at 4000-char Slack API limit
- Thread flattening (threaded replies delivered as channel messages)
- User name resolution with caching
- Outgoing message queue with flush-on-reconnect
- Channel metadata sync with pagination
- Proper Bolt types (GenericMessageEvent | BotMessageEvent)
- Multi-channel orchestrator changes (conditional channel creation)
- Setup guide (SLACK_SETUP.md) and known limitations documented
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* local settings
* adjusted when installing
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The telegram.ts implementation was updated to pass channel and isGroup
to onChatMetadata but the test file still asserted the old 3-arg form.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- connect() warns and returns instead of throwing when ~/.gmail-mcp/
credentials are missing, preventing app crash
- index.ts wraps gmail.connect() in try/catch as a safety net
- Poll loop uses exponential backoff on consecutive errors (caps at 30m)
instead of hammering the Gmail API every 60s on auth failures
- Switch from setInterval to setTimeout chain for proper backoff timing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Channel vs tool-only is now a code-level decision at skill apply time.
If the user chose channel mode, GmailChannel is wired unconditionally.
If tool-only, no channel code is added. No runtime flag needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The fetchLatestWaWebVersion call added in #443 could crash the
connection flow if the HTTP fetch fails. Wrap with .catch() to log
and fall back to the default Baileys version.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Baileys' default WhatsApp version can fall behind when WhatsApp updates
their protocol, causing 405 "Method Not Allowed" errors on the websocket
handshake. This prevents both new authentication and reconnection.
Now fetches the latest version on each connection so it stays current.
Applied to both the runtime connection (whatsapp.ts) and the setup auth
flow (whatsapp-auth.ts).
Add /update to skills tables in CLAUDE.md and REQUIREMENTS.md. Add
"Updating" section to README. Remove /add-telegram and /add-discord
from RFS (already exist). Add CI workflow to bump patch version on
source/container changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Interactive skill that guides Claude through fetching upstream NanoClaw,
previewing changes, merging with customizations, running migrations, and
verifying the result. Includes:
- SKILL.md with 9-step update flow
- fetch-upstream.sh: detects remote, fetches, extracts tracked paths
- run-migrations.ts: discovers and runs version-ordered migrations
- post-update.ts: clears backup after conflict resolution
- update-core.ts: adds --json and --preview-only flags
- BASE_INCLUDES moved to constants.ts as single source of truth
- 16 new tests covering fetch, migrations, and CLI flags
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Replace 'as any' with proper type definition for error status code access
- Add error logging to sendPresenceUpdate() catch block
- Add debug logging when .env file is not found
These changes improve type safety and visibility into potential failures
without changing any core functionality.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: gavrielc <gabicohen22@yahoo.com>
- Updated add-voice-transcription to use AskUserQuestion for API key prompt
- Updated add-gmail to use AskUserQuestion for mode selection and channel config
- Updated add-discord to use AskUserQuestion for mode and token prompts
- Updated add-parallel to use AskUserQuestion for API key and permission prompts
- Updated add-telegram to use AskUserQuestion for mode and token prompts
- Updated setup to use AskUserQuestion for Node.js, Docker, and container runtime prompts
The AskUserQuestion tool provides a structured way to collect user input during
skill execution, making the interaction pattern consistent across all skills.
* fix: filter empty messages from polling queries
WhatsApp history sync writes empty protocol artifacts (delivery receipts,
status updates) to the database. On fresh installs, the main channel
(no trigger required) picks these up and spawns a container agent
unnecessarily, causing a message loop on first startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: update test to match empty-content filtering in queries
The getMessagesSince query now filters out empty messages, so the test
should expect 0 results instead of 1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Containers had no TZ set, so any time-aware code inside ran in UTC while
the host interpreted bare timestamps as local time. Now TIMEZONE from
config.ts is passed via -e TZ= to the container args.
Also rejects Z-suffixed or offset-suffixed timestamps in the container's
schedule_task validation, since bare timestamps are expected to be local
time and silently accepting UTC suffixes would cause an offset mismatch.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The container agent-runner had 'Andy' hardcoded as the sender name in
archived conversation transcripts. This ignored the configurable
ASSISTANT_NAME setting, so users who changed their assistant's name
(via .env or config) would still see 'Andy' in transcripts.
- Add assistantName field to ContainerInput interface (both host and
container copies)
- Pass ASSISTANT_NAME from config through to container in index.ts
and task-scheduler.ts
- Thread assistantName through createPreCompactHook and
formatTranscriptMarkdown in the agent-runner
- Use 'AssistantNameMissing' as fallback instead of 'Andy' so a
missing name is visible rather than silently wrong
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The main group's project root was mounted read-write, allowing the
container agent to modify host application code (e.g. dist/container-runner.js)
to inject arbitrary mounts on next restart — a full sandbox escape.
Fix: mount the project root read-only. Writable paths the agent needs
(group folder, IPC, .claude/) are already mounted separately. The
agent-runner source is now copied into a per-group writable location
so agents can still customize container-side behavior without affecting
host code or other groups.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Setup scripts are standalone CLI tools run via tsx with no runtime
imports from the main app. Moving them out of src/ excludes them from
the tsc build output and reduces the compiled bundle size.
- git mv src/setup/ setup/
- Fix imports to use ../src/logger.js and ../src/config.js
- Update package.json, vitest.config.ts, SKILL.md references
- Fix platform tests to be cross-platform (macOS + Linux)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: migrate setup from bash scripts to cross-platform Node.js modules
Replace 9 bash scripts + qr-auth.html with a two-phase setup system:
a bash bootstrap (setup.sh) for Node.js/npm verification, and TypeScript
modules (src/setup/) for everything else. Resolves cross-platform issues:
sed -i replaced with fs operations, sqlite3 CLI replaced with better-sqlite3,
browser opening made cross-platform, service management supports launchd/
systemd/WSL nohup fallback, SQL injection prevented with parameterized queries.
Add Linux systemctl equivalents alongside macOS launchctl commands in 8 skill
files and CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: setup migration issues — pairing code, systemd fallback, nohup escaping
- Emit WhatsApp pairing code immediately when received, before polling
for auth completion. Previously the code was only shown in the final
status block after auth succeeded — a catch-22 since the user needs
the code to authenticate. (whatsapp-auth.ts)
- Add systemd user session pre-check before attempting to write the
user-level service unit. Falls back to nohup wrapper when user-level
systemd is unavailable (e.g. su session without login/D-Bus). (service.ts)
- Rewrite nohup wrapper template using array join instead of template
literal to fix shell variable escaping (\\$ → $). (service.ts)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: detect stale docker group and kill
orphaned processes on Linux systemd
* fix: remove redundant shell option from execSync to fix TS2769
execSync already runs in a shell by default; the explicit `shell: true`
caused a type error with @types/node which expects string, not boolean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: hide QR browser auth option on headless Linux
Emit IS_HEADLESS from environment step and condition SKILL.md to
only show pairing code + QR terminal when no display server is
available (headless Linux without WSL). WSL is excluded from the
headless gate because browser opening works via Windows interop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>