Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ ENV NODE_PATH=/usr/local/lib/node_modules

ENV NODE_ENV=production

# Install wacli (WhatsApp CLI) for the default OpenClaw wacli skill.
ARG WACLI_VERSION="0.15.0"
RUN ARCH=$(dpkg --print-architecture) && \
case "$ARCH" in \
amd64|arm64) WACLI_ARCH="$ARCH" ;; \
*) echo "Unsupported architecture: $ARCH" && exit 1 ;; \
esac && \
TARBALL="wacli_${WACLI_VERSION}_linux_${WACLI_ARCH}.tar.gz" && \
BASE_URL="https://github.com/openclaw/wacli/releases/download/v${WACLI_VERSION}" && \
curl -fsSL "${BASE_URL}/${TARBALL}" -o "/tmp/${TARBALL}" && \
curl -fsSL "${BASE_URL}/checksums.txt" -o /tmp/wacli_checksums.txt && \
grep " ${TARBALL}$" /tmp/wacli_checksums.txt > /tmp/wacli_checksum.txt && \
(cd /tmp && sha256sum -c wacli_checksum.txt) && \
tar -xz -C /usr/local/bin -f "/tmp/${TARBALL}" wacli && \
chmod +x /usr/local/bin/wacli && \
rm "/tmp/${TARBALL}" /tmp/wacli_checksums.txt /tmp/wacli_checksum.txt

# Install ttyd (web terminal) - static binary from GitHub releases
# ttyd is not available in bookworm repos, so we download the pre-built binary
RUN ARCH=$(dpkg --print-architecture) && \
Expand Down
4 changes: 2 additions & 2 deletions dappnode_package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@
"type": "service",
"upstreamArg": "UPSTREAM_VERSION",
"upstreamRepo": "openclaw/openclaw",
"upstreamVersion": "2026.6.11",
"version": "0.1.3",
"upstreamVersion": "2026.7.1",
"version": "0.1.4",
"warnings": {
"onRemove": "Removing this package will delete all your OpenClaw configuration, conversation history, and cached data. Make sure to create a backup first."
}
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ services:
context: .
dockerfile: Dockerfile
args:
UPSTREAM_VERSION: 2026.6.11
UPSTREAM_VERSION: 2026.7.1
image: openclaw.dnp.dappnode.eth:0.1.0
container_name: DAppNodePackage-openclaw.dnp.dappnode.eth
restart: unless-stopped
Expand Down
85 changes: 73 additions & 12 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,74 @@ try {
if (!('dangerouslyDisableDeviceAuth' in cui)) { cui.dangerouslyDisableDeviceAuth = true; changed = true; }
if (auth.token !== envToken) { auth.token = envToken; changed = true; }

function isObject(value) {
return value && typeof value === 'object' && !Array.isArray(value);
}

function migrateTelegramStreaming(entry) {
if (!isObject(entry)) return false;
let entryChanged = false;
const legacyStreaming = entry.streaming;
const streaming = isObject(legacyStreaming) ? legacyStreaming : {};

if ('streaming' in entry && !isObject(legacyStreaming)) {
if (typeof legacyStreaming === 'boolean') {
streaming.mode = legacyStreaming ? 'partial' : 'off';
} else if (legacyStreaming != null) {
streaming.mode = String(legacyStreaming);
}
entry.streaming = streaming;
entryChanged = true;
}
if ('streamMode' in entry) {
if (!streaming.mode) streaming.mode = entry.streamMode;
delete entry.streamMode;
entryChanged = true;
}
if ('chunkMode' in entry) {
if (!('chunkMode' in streaming)) streaming.chunkMode = entry.chunkMode;
delete entry.chunkMode;
entryChanged = true;
}
if ('draftChunk' in entry) {
const preview = isObject(streaming.preview) ? streaming.preview : {};
if (!('chunk' in preview)) preview.chunk = entry.draftChunk;
streaming.preview = preview;
delete entry.draftChunk;
entryChanged = true;
}
if ('blockStreaming' in entry) {
const block = isObject(streaming.block) ? streaming.block : {};
if (!('enabled' in block)) block.enabled = entry.blockStreaming;
streaming.block = block;
delete entry.blockStreaming;
entryChanged = true;
}
if ('blockStreamingCoalesce' in entry) {
const block = isObject(streaming.block) ? streaming.block : {};
if (!('coalesce' in block)) block.coalesce = entry.blockStreamingCoalesce;
streaming.block = block;
delete entry.blockStreamingCoalesce;
entryChanged = true;
}
if (entryChanged) entry.streaming = streaming;
return entryChanged;
}

// Migrate legacy channel keys that openclaw doctor --fix cannot fully resolve in one pass:
// streamMode (string) → streaming (string)
// streaming (boolean) → streaming (string: true→\"partial\", false→\"off\")
// Telegram streamMode / scalar streaming / flat chunk keys → streaming.{mode,chunkMode,preview.chunk,block.*}
// discord.botToken → discord.token (Telegram keeps botToken; Discord uses token)
// discord guild channel: allow (bool) → enabled (bool)
const channels = config.channels || {};
for (const [chName, ch] of Object.entries(channels)) {
if (!ch || typeof ch !== 'object') continue;
// streamMode → streaming string
if ('streamMode' in ch) {
ch.streaming = ch.streamMode;
delete ch.streamMode;
changed = true;
}
// boolean streaming → string
if (typeof ch.streaming === 'boolean') {
ch.streaming = ch.streaming ? 'partial' : 'off';
changed = true;
if (chName === 'telegram') {
if (migrateTelegramStreaming(ch)) changed = true;
if (ch.accounts && typeof ch.accounts === 'object') {
for (const account of Object.values(ch.accounts)) {
if (migrateTelegramStreaming(account)) changed = true;
}
}
}
// Discord: botToken is not valid — migrate to token (plain string)
if (chName === 'discord' && 'botToken' in ch) {
Expand Down Expand Up @@ -104,6 +154,17 @@ fi
# ---------------------------------------------------------------------------
# Run doctor --fix for any remaining migrations not handled above
# ---------------------------------------------------------------------------
echo "Pruning stale OpenClaw session entries..."
MAIN_SESSION_STORE="$OPENCLAW_DIR/agents/main/sessions/sessions.json"
mkdir -p "$(dirname "$MAIN_SESSION_STORE")"
OPENCLAW_STATE_DIR="$OPENCLAW_DIR" openclaw sessions cleanup --store "$MAIN_SESSION_STORE" --enforce --fix-missing || true
if [ -d "$OPENCLAW_DIR/agents" ]; then
find "$OPENCLAW_DIR/agents" -mindepth 3 -maxdepth 3 -path "*/sessions/sessions.json" -print | while IFS= read -r SESSION_STORE; do
[ "$SESSION_STORE" = "$MAIN_SESSION_STORE" ] && continue
OPENCLAW_STATE_DIR="$OPENCLAW_DIR" openclaw sessions cleanup --store "$SESSION_STORE" --enforce --fix-missing || true
done
fi

echo "Running openclaw doctor --fix..."
OPENCLAW_STATE_DIR="$OPENCLAW_DIR" openclaw doctor --fix || true

Expand Down
Loading