diff --git a/.claude/skills/setup/scripts/06-register-channel.sh b/.claude/skills/setup/scripts/06-register-channel.sh index 62da298..3d67266 100755 --- a/.claude/skills/setup/scripts/06-register-channel.sh +++ b/.claude/skills/setup/scripts/06-register-channel.sh @@ -79,6 +79,15 @@ if [ "$ASSISTANT_NAME" != "Andy" ]; then fi done + # Add ASSISTANT_NAME to .env so config.ts picks it up + ENV_FILE="$PROJECT_ROOT/.env" + if [ -f "$ENV_FILE" ] && grep -q '^ASSISTANT_NAME=' "$ENV_FILE"; then + sed "s/^ASSISTANT_NAME=.*/ASSISTANT_NAME=$ASSISTANT_NAME/" "$ENV_FILE" > "$ENV_FILE.tmp" && mv "$ENV_FILE.tmp" "$ENV_FILE" + else + echo "ASSISTANT_NAME=$ASSISTANT_NAME" >> "$ENV_FILE" + fi + log "Set ASSISTANT_NAME=$ASSISTANT_NAME in .env" + NAME_UPDATED="true" fi diff --git a/container/Dockerfile b/container/Dockerfile index d48d8d9..58e1acd 100644 --- a/container/Dockerfile +++ b/container/Dockerfile @@ -56,7 +56,7 @@ RUN mkdir -p /workspace/group /workspace/global /workspace/extra /workspace/ipc/ 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 # Set ownership to node user (non-root) for writable directories -RUN chown -R node:node /workspace +RUN chown -R node:node /workspace && chmod 777 /home/node # Switch to non-root user (required for --dangerously-skip-permissions) USER node diff --git a/src/container-runner.ts b/src/container-runner.ts index 5e20ced..7f4cd5c 100644 --- a/src/container-runner.ts +++ b/src/container-runner.ts @@ -192,6 +192,16 @@ function readSecrets(): Record { function buildContainerArgs(mounts: VolumeMount[], containerName: string): string[] { const args: string[] = ['run', '-i', '--rm', '--name', containerName]; + // Run as host user so bind-mounted files are accessible. + // Skip when running as root (uid 0), as the container's node user (uid 1000), + // or when getuid is unavailable (native Windows without WSL). + const hostUid = process.getuid?.(); + const hostGid = process.getgid?.(); + if (hostUid != null && hostUid !== 0 && hostUid !== 1000) { + args.push('--user', `${hostUid}:${hostGid}`); + args.push('-e', 'HOME=/home/node'); + } + // Apple Container: --mount for readonly, -v for read-write for (const mount of mounts) { if (mount.readonly) { diff --git a/src/whatsapp-auth.ts b/src/whatsapp-auth.ts index fba0899..a969835 100644 --- a/src/whatsapp-auth.ts +++ b/src/whatsapp-auth.ts @@ -41,10 +41,10 @@ function askQuestion(prompt: string): Promise { }); } -async function connectSocket(phoneNumber?: string): Promise { +async function connectSocket(phoneNumber?: string, isReconnect = false): Promise { const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR); - if (state.creds.registered) { + if (state.creds.registered && !isReconnect) { fs.writeFileSync(STATUS_FILE, 'already_authenticated'); console.log('āœ“ Already authenticated with WhatsApp'); console.log( @@ -110,7 +110,7 @@ async function connectSocket(phoneNumber?: string): Promise { // 515 = stream error, often happens after pairing succeeds but before // registration completes. Reconnect to finish the handshake. console.log('\n⟳ Stream error (515) after pairing — reconnecting...'); - connectSocket(phoneNumber); + connectSocket(phoneNumber, true); } else { fs.writeFileSync(STATUS_FILE, `failed:${reason || 'unknown'}`); console.log('\nāœ— Connection failed. Please try again.');