diff --git a/.claude/skills/add-discord/SKILL.md b/.claude/skills/add-discord/SKILL.md
index 6d3ccc8..f22c0c7 100644
--- a/.claude/skills/add-discord/SKILL.md
+++ b/.claude/skills/add-discord/SKILL.md
@@ -44,7 +44,7 @@ import './discord.js';
### 4. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/discord@4.26.0
+pnpm install @chat-adapter/discord@4.27.0
```
### 5. Build
diff --git a/.claude/skills/add-gchat/SKILL.md b/.claude/skills/add-gchat/SKILL.md
index c4d8dfd..b3b7d1b 100644
--- a/.claude/skills/add-gchat/SKILL.md
+++ b/.claude/skills/add-gchat/SKILL.md
@@ -44,7 +44,7 @@ import './gchat.js';
### 4. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/gchat@4.26.0
+pnpm install @chat-adapter/gchat@4.27.0
```
### 5. Build
diff --git a/.claude/skills/add-github/SKILL.md b/.claude/skills/add-github/SKILL.md
index 78366f3..2441f13 100644
--- a/.claude/skills/add-github/SKILL.md
+++ b/.claude/skills/add-github/SKILL.md
@@ -48,7 +48,7 @@ import './github.js';
### 4. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/github@4.26.0
+pnpm install @chat-adapter/github@4.27.0
```
### 5. Build
diff --git a/.claude/skills/add-linear/SKILL.md b/.claude/skills/add-linear/SKILL.md
index dc657af..237aaa0 100644
--- a/.claude/skills/add-linear/SKILL.md
+++ b/.claude/skills/add-linear/SKILL.md
@@ -87,7 +87,7 @@ Linear OAuth apps can't be @-mentioned, so the bridge's `onNewMention` handler n
### 5. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/linear@4.26.0
+pnpm install @chat-adapter/linear@4.27.0
```
### 6. Build
diff --git a/.claude/skills/add-slack/SKILL.md b/.claude/skills/add-slack/SKILL.md
index d09db61..0b67b50 100644
--- a/.claude/skills/add-slack/SKILL.md
+++ b/.claude/skills/add-slack/SKILL.md
@@ -44,7 +44,7 @@ import './slack.js';
### 4. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/slack@4.26.0
+pnpm install @chat-adapter/slack@4.27.0
```
### 5. Build
diff --git a/.claude/skills/add-teams/SKILL.md b/.claude/skills/add-teams/SKILL.md
index 10bce29..f6eeaf9 100644
--- a/.claude/skills/add-teams/SKILL.md
+++ b/.claude/skills/add-teams/SKILL.md
@@ -44,7 +44,7 @@ import './teams.js';
### 4. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/teams@4.26.0
+pnpm install @chat-adapter/teams@4.27.0
```
### 5. Build
diff --git a/.claude/skills/add-telegram/SKILL.md b/.claude/skills/add-telegram/SKILL.md
index f605b41..03247c5 100644
--- a/.claude/skills/add-telegram/SKILL.md
+++ b/.claude/skills/add-telegram/SKILL.md
@@ -58,7 +58,7 @@ In `setup/index.ts`, add this entry to the `STEPS` map (right after the `registe
### 5. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/telegram@4.26.0
+pnpm install @chat-adapter/telegram@4.27.0
```
### 6. Build
diff --git a/.claude/skills/add-whatsapp-cloud/SKILL.md b/.claude/skills/add-whatsapp-cloud/SKILL.md
index d08f375..7e8bd1c 100644
--- a/.claude/skills/add-whatsapp-cloud/SKILL.md
+++ b/.claude/skills/add-whatsapp-cloud/SKILL.md
@@ -44,7 +44,7 @@ import './whatsapp-cloud.js';
### 4. Install the adapter package (pinned)
```bash
-pnpm install @chat-adapter/whatsapp@4.26.0
+pnpm install @chat-adapter/whatsapp@4.27.0
```
### 5. Build
diff --git a/container/agent-runner/src/db/connection.ts b/container/agent-runner/src/db/connection.ts
index 3ca44a8..871e43a 100644
--- a/container/agent-runner/src/db/connection.ts
+++ b/container/agent-runner/src/db/connection.ts
@@ -27,21 +27,29 @@ const DEFAULT_HEARTBEAT_PATH = '/workspace/.heartbeat';
let _inbound: Database | null = null;
let _outbound: Database | null = null;
let _heartbeatPath: string = DEFAULT_HEARTBEAT_PATH;
+let _testMode = false;
/**
- * Avoid all cached db reads; open inbound.db read-only with mmap and page cache disabled.
- *
+ * Avoid all cached db reads; open inbound.db read-only with mmap and page cache disabled.
+ *
* Use this (not getInboundDb) for readers that need to see host-written rows
* promptly — e.g. messages_in polling. Caller must .close() the returned
* connection (try/finally).
*
* Needed for mounts where host writes don't reliably invalidate
* SQLite's caches: virtiofs (Colima, Lima, Podman Machine, Apple
- * Container), NFS.
- *
+ * Container), NFS.
+ *
* Cost is microseconds per query, so safe for universal use.
*/
export function openInboundDb(): Database {
+ // In test mode return a thin wrapper over the in-memory singleton.
+ // Callers do try/finally { db.close() } — the wrapper no-ops close()
+ // so the singleton survives for the rest of the test.
+ if (_testMode && _inbound) {
+ const db = _inbound;
+ return { prepare: (sql: string) => db.prepare(sql), exec: (sql: string) => db.exec(sql), close: () => {} } as unknown as Database;
+ }
const db = new Database(DEFAULT_INBOUND_PATH, { readonly: true });
db.exec('PRAGMA busy_timeout = 5000');
db.exec('PRAGMA mmap_size = 0');
@@ -170,6 +178,7 @@ export function clearStaleProcessingAcks(): void {
/** For tests — creates in-memory DBs with the session schemas. */
export function initTestSessionDb(): { inbound: Database; outbound: Database } {
+ _testMode = true;
_inbound = new Database(':memory:');
_inbound.exec('PRAGMA foreign_keys = ON');
_inbound.exec(`
@@ -246,6 +255,7 @@ export function initTestSessionDb(): { inbound: Database; outbound: Database } {
export function closeSessionDb(): void {
_inbound?.close();
_inbound = null;
+ _testMode = false;
_outbound?.close();
_outbound = null;
}
diff --git a/migrate-v2.sh b/migrate-v2.sh
index f06a548..2325edd 100644
--- a/migrate-v2.sh
+++ b/migrate-v2.sh
@@ -408,20 +408,12 @@ else
fi
done
- # 2d. WhatsApp LID resolution. After whatsapp is installed (so Baileys
- # is on disk) and auth files have been copied (so we can connect with
- # the migrated identity), boot Baileys briefly to learn LID↔phone
- # mappings during initial sync, then write paired LID-keyed
- # messaging_groups. Best-effort: any failure degrades to runtime
- # approval flow, which the WA adapter's isMention=true on DMs handles.
- for ch in "${SELECTED_CHANNELS[@]}"; do
- if [ "$ch" = "whatsapp" ]; then
- run_step "2d-whatsapp-lids" \
- "Resolve WhatsApp LIDs for migrated DMs" \
- "setup/migrate-v2/whatsapp-resolve-lids.ts"
- break
- fi
- done
+ # 2d. (Removed) WhatsApp LID resolution was previously needed because the
+ # v6 adapter couldn't reliably translate LID→phone JIDs, so the migration
+ # pre-created dual messaging_groups rows. With Baileys v7, the adapter
+ # resolves LIDs via extractAddressingContext + signalRepository.lidMapping
+ # on every inbound message, so dual rows are unnecessary and were causing
+ # split sessions.
fi
echo
diff --git a/nanoclaw.sh b/nanoclaw.sh
index c17966e..bcf4e49 100755
--- a/nanoclaw.sh
+++ b/nanoclaw.sh
@@ -138,16 +138,13 @@ write_header
cat "$PROJECT_ROOT/assets/setup-splash.txt"
# ─── pre-flight: minimum hardware specs ────────────────────────────────
-# NanoClaw runs an agent container per session. Below these thresholds the
-# host + container + agent will struggle (OOM under load, image + session
-# DBs filling the disk). Soft warn — `df` only sees the partition that
-# $PROJECT_ROOT lives on, which can underreport on hosts with separate
-# /home or /var mounts, so the user can override.
+# NanoClaw runs an agent container per session. Below this threshold the
+# host + container + agent will struggle (OOM under load). Soft warn — the
+# user can override.
# RAM floor is set below 4 GB because "4 GB" VMs typically report 3700–3900 MB
# after kernel reserves (e.g. Hetzner CX21 ≈ 3814, AWS t3.medium ≈ 3800).
MIN_MEM_MB=3700
-MIN_DISK_GB=20
detect_mem_mb() {
case "$(uname -s)" in
@@ -162,39 +159,29 @@ detect_mem_mb() {
esac
}
-detect_disk_gb() {
- # -P: POSIX format (no line-wrapping); -k: 1024-byte blocks. Avail is col 4.
- df -Pk "$PROJECT_ROOT" 2>/dev/null \
- | awk 'NR==2 { printf "%d", $4 / 1024 / 1024 }'
-}
-
MEM_MB=$(detect_mem_mb)
-DISK_GB=$(detect_disk_gb)
: "${MEM_MB:=0}"
-: "${DISK_GB:=0}"
-LOW_MEM=false; LOW_DISK=false
-[ "$MEM_MB" -gt 0 ] && [ "$MEM_MB" -lt "$MIN_MEM_MB" ] && LOW_MEM=true
-[ "$DISK_GB" -gt 0 ] && [ "$DISK_GB" -lt "$MIN_DISK_GB" ] && LOW_DISK=true
+LOW_MEM=false
+[ "$MEM_MB" -gt 0 ] && [ "$MEM_MB" -lt "$MIN_MEM_MB" ] && LOW_MEM=true
-if [ "$LOW_MEM" = true ] || [ "$LOW_DISK" = true ]; then
+if [ "$LOW_MEM" = true ]; then
printf ' %s\n' "$(red 'Warning: this machine likely cannot run NanoClaw.')"
- printf ' %s\n' "$(dim 'NanoClaw recommends a 4 GB+ machine with 20 GB+ free disk. Below this,')"
- printf ' %s\n' "$(dim 'the host + agent container will run out of memory or disk under most')"
- printf ' %s\n' "$(dim 'workloads. A stronger machine is strongly recommended.')"
- [ "$LOW_MEM" = true ] && printf ' %s\n' "$(dim " · Detected RAM: ${MEM_MB} MB")"
- [ "$LOW_DISK" = true ] && printf ' %s\n' "$(dim " · Free disk on $PROJECT_ROOT: ${DISK_GB} GB")"
+ printf ' %s\n' "$(dim 'NanoClaw recommends a 4 GB+ RAM machine. Below this, the host + agent')"
+ printf ' %s\n' "$(dim 'container will run out of memory under most workloads. A stronger')"
+ printf ' %s\n' "$(dim 'machine is strongly recommended.')"
+ printf ' %s\n' "$(dim " · Detected RAM: ${MEM_MB} MB")"
printf '\n'
read -r -p " $(bold 'Try anyway?') [y/N] " SPECS_ANS
-
140k tokens, 70% of context window
+