From 4af3c7f672049d6ac7ecc25311e88de7a1bb1a21 Mon Sep 17 00:00:00 2001 From: imcodes-win Date: Mon, 6 Apr 2026 04:19:17 +0800 Subject: [PATCH 01/57] fix(windows): use absolute cmd.exe path in upgrade spawn and startup shortcut MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The daemon runs from a restricted environment (Startup shortcut / schtask) where bare 'cmd.exe' / 'cmd' fails CreateProcess PATH resolution. - command-handler.ts: upgrade batch spawn now uses COMSPEC absolute path - windows-daemon.ts: tryStartStartupShortcut uses COMSPEC absolute path - This was the root cause of empty upgrade logs — the batch never executed Co-Authored-By: Claude Opus 4.6 (1M context) --- src/daemon/command-handler.ts | 4 +++- src/util/windows-daemon.ts | 3 ++- test/util/windows-daemon.test.ts | 10 ++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/daemon/command-handler.ts b/src/daemon/command-handler.ts index 6870c494..cd2c5378 100644 --- a/src/daemon/command-handler.ts +++ b/src/daemon/command-handler.ts @@ -2132,7 +2132,9 @@ launchctl load -w "${plist}"`; writeFileSync(batchPath, batch); - const child = spawn('cmd.exe', ['/c', batchPath], { + // Use absolute path — bare 'cmd.exe' fails in restricted daemon environments + const cmdExe = process.env.COMSPEC || `${process.env.SystemRoot || 'C:\\Windows'}\\system32\\cmd.exe`; + const child = spawn(cmdExe, ['/c', batchPath], { detached: true, stdio: 'ignore', windowsHide: true, diff --git a/src/util/windows-daemon.ts b/src/util/windows-daemon.ts index 257adf9f..7487998c 100644 --- a/src/util/windows-daemon.ts +++ b/src/util/windows-daemon.ts @@ -91,7 +91,8 @@ function tryStartStartupShortcut(): boolean { 'imcodes-daemon.cmd', ); if (!existsSync(startupCmd)) return false; - spawn('cmd', ['/c', startupCmd], { detached: true, stdio: 'ignore', windowsHide: true }).unref(); + const cmdExe = process.env.COMSPEC || `${process.env.SystemRoot || 'C:\\Windows'}\\system32\\cmd.exe`; + spawn(cmdExe, ['/c', startupCmd], { detached: true, stdio: 'ignore', windowsHide: true }).unref(); return true; } diff --git a/test/util/windows-daemon.test.ts b/test/util/windows-daemon.test.ts index 6e5c363a..77d14d13 100644 --- a/test/util/windows-daemon.test.ts +++ b/test/util/windows-daemon.test.ts @@ -126,12 +126,10 @@ describe('restartWindowsDaemon', () => { const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); - expect(state.spawnCalls).toEqual([ - { - cmd: 'cmd', - args: ['/c', 'C:\\Users\\tester\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\imcodes-daemon.cmd'], - }, - ]); + expect(state.spawnCalls).toHaveLength(1); + // cmd resolved via COMSPEC — match any path ending in cmd.exe + expect(state.spawnCalls[0].cmd).toMatch(/cmd(\.exe)?$/i); + expect(state.spawnCalls[0].args).toEqual(['/c', 'C:\\Users\\tester\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\imcodes-daemon.cmd']); }); it('force-kills daemon if tree-kill misses it', async () => { From 2cee873b242587d238bc37335e15c59e0d5865c4 Mon Sep 17 00:00:00 2001 From: imcodes-win Date: Mon, 6 Apr 2026 09:57:24 +0800 Subject: [PATCH 02/57] fix(windows): prevent upgrade race condition and use npm shim in watchdog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: npm install -g deletes old package before writing new one. The watchdog loop tried to restart the daemon during this window, hitting MODULE_NOT_FOUND. After that the watchdog died and never recovered. Fixes: 1. Upgrade batch now kills the entire watchdog tree BEFORE npm install, preventing the race entirely 2. On install failure, abort paths restart the old daemon via VBS so it's never left dead 3. After successful install, starts fresh watchdog via VBS directly instead of calling `imcodes restart` (avoids version-coupling) 4. Watchdog.cmd now uses the npm global shim (`imcodes.cmd`) instead of hard-coded node+script paths — always launches whatever version is currently installed, surviving npm upgrades without repair-watchdog 5. command-handler upgrade spawn uses COMSPEC absolute path Co-Authored-By: Claude Opus 4.6 (1M context) --- src/daemon/command-handler.ts | 5 +-- src/util/windows-launch-artifacts.ts | 15 ++++++- src/util/windows-upgrade-script.ts | 57 +++++++++++++++++++++--- test/util/windows-upgrade-script.test.ts | 54 +++++++++++++++++++--- 4 files changed, 114 insertions(+), 17 deletions(-) diff --git a/src/daemon/command-handler.ts b/src/daemon/command-handler.ts index cd2c5378..4ad3d67c 100644 --- a/src/daemon/command-handler.ts +++ b/src/daemon/command-handler.ts @@ -2118,9 +2118,7 @@ launchctl load -w "${plist}"`; const targetVer = targetVersion ?? 'latest'; const cleanupScript = buildWindowsCleanupScript(scriptDir); writeFileSync(cleanupPath, cleanupScript); - // Windows: install first while the daemon is still running. On success, - // delegate restart to the CLI's shared watchdog logic (`imcodes restart`) - // instead of reimplementing restart behavior in batch. + const vbsLauncherPath = join(homedir(), '.imcodes', 'daemon-launcher.vbs'); const batch = buildWindowsUpgradeBatch({ logFile, scriptDir, @@ -2128,6 +2126,7 @@ launchctl load -w "${plist}"`; npmCmd, pkgSpec, targetVer, + vbsLauncherPath, }); writeFileSync(batchPath, batch); diff --git a/src/util/windows-launch-artifacts.ts b/src/util/windows-launch-artifacts.ts index c037f122..956e2e85 100644 --- a/src/util/windows-launch-artifacts.ts +++ b/src/util/windows-launch-artifacts.ts @@ -1,4 +1,5 @@ import { writeFile, mkdir, stat, truncate } from 'fs/promises'; +import { existsSync } from 'fs'; import { execSync } from 'child_process'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; @@ -29,10 +30,20 @@ export function resolveLaunchPaths(): LaunchPaths { }; } -/** Write the daemon-watchdog.cmd that loops and restarts the daemon. */ +/** Write the daemon-watchdog.cmd that loops and restarts the daemon. + * Uses the npm global shim (`imcodes.cmd`) instead of hard-coding + * node.exe + script paths — this way the watchdog always launches + * whatever version is currently installed, even after npm upgrades. */ export async function writeWatchdogCmd(paths: LaunchPaths): Promise { await mkdir(dirname(paths.watchdogPath), { recursive: true }); - const watchdog = `@echo off\r\nchcp 65001 >nul 2>&1\r\n:loop\r\n"${paths.nodeExe}" "${paths.imcodesScript}" start --foreground >> "${paths.logPath}" 2>&1\r\ntimeout /t 5 /nobreak >nul\r\ngoto loop\r\n`; + // Resolve the npm global shim path (e.g. C:\Users\X\AppData\Roaming\npm\imcodes.cmd) + const npmGlobalBin = dirname(paths.imcodesScript).replace(/[/\\]node_modules[/\\]imcodes[/\\]dist[/\\]src$/i, ''); + const shimPath = join(npmGlobalBin, 'imcodes.cmd'); + // Prefer the shim if it exists; fall back to direct node+script for dev setups + const launchCmd = existsSync(shimPath) + ? `"${shimPath}" start --foreground` + : `"${paths.nodeExe}" "${paths.imcodesScript}" start --foreground`; + const watchdog = `@echo off\r\nchcp 65001 >nul 2>&1\r\n:loop\r\n${launchCmd} >> "${paths.logPath}" 2>&1\r\ntimeout /t 5 /nobreak >nul\r\ngoto loop\r\n`; await writeFile(paths.watchdogPath, watchdog, 'utf8'); } diff --git a/src/util/windows-upgrade-script.ts b/src/util/windows-upgrade-script.ts index d7841912..fc391ca2 100644 --- a/src/util/windows-upgrade-script.ts +++ b/src/util/windows-upgrade-script.ts @@ -5,6 +5,8 @@ export interface WindowsUpgradeScriptInput { npmCmd: string; pkgSpec: string; targetVer: string; + /** Absolute path to daemon-launcher.vbs for hidden restart */ + vbsLauncherPath: string; } export function buildWindowsCleanupScript(scriptDir: string): string { @@ -15,17 +17,48 @@ rmdir /s /q "${scriptDir}"\r } export function buildWindowsUpgradeBatch(input: WindowsUpgradeScriptInput): string { - const { logFile, cleanupPath, npmCmd, pkgSpec, targetVer } = input; + const { logFile, cleanupPath, npmCmd, pkgSpec, targetVer, vbsLauncherPath } = input; return `@echo off\r setlocal EnableDelayedExpansion\r echo === imcodes upgrade started at %date% %time% === >> "${logFile}"\r timeout /t 2 /nobreak > nul\r \r +rem ── Stop watchdog + daemon BEFORE npm install ──────────────────────────\r +rem npm install -g deletes the old package before writing the new one.\r +rem If the watchdog loop restarts the daemon during that window, it hits\r +rem MODULE_NOT_FOUND and dies. Kill the entire watchdog tree first.\r +set "PIDFILE=%USERPROFILE%\\.imcodes\\daemon.pid"\r +if exist "%PIDFILE%" (\r + set /p OLD_PID=<"%PIDFILE%"\r + echo Stopping daemon PID !OLD_PID! and watchdog tree... >> "${logFile}"\r + rem Find watchdog (parent of daemon) via wmic and tree-kill it\r + for /f "tokens=2 delims==" %%a in ('wmic process where "ProcessId=!OLD_PID!" get ParentProcessId /format:list 2^>nul ^| find "="') do (\r + set "WATCHDOG_PID=%%a"\r + )\r + if defined WATCHDOG_PID (\r + rem Strip trailing carriage return from wmic output\r + set "WATCHDOG_PID=!WATCHDOG_PID: =!"\r + for /f "delims=" %%x in ("!WATCHDOG_PID!") do set "WATCHDOG_PID=%%x"\r + taskkill /f /t /pid !WATCHDOG_PID! >nul 2>&1\r + echo Killed watchdog tree PID !WATCHDOG_PID! >> "${logFile}"\r + )\r + rem Belt-and-suspenders: ensure daemon is dead even if tree-kill missed it\r + taskkill /f /pid !OLD_PID! >nul 2>&1\r + rem Also kill any other stale watchdog loops\r + for /f "tokens=2 delims=," %%p in ('wmic process where "CommandLine like '%%daemon-watchdog%%' and Name='cmd.exe'" get ProcessId /format:csv 2^>nul ^| findstr /r "[0-9]"') do (\r + taskkill /f /t /pid %%p >nul 2>&1\r + )\r + del "%PIDFILE%" >nul 2>&1\r + timeout /t 2 /nobreak >nul\r +)\r +\r echo Installing ${pkgSpec}... >> "${logFile}"\r call "${npmCmd}" install -g ${pkgSpec} >> "${logFile}" 2>&1\r if %errorlevel% neq 0 (\r - echo Install FAILED — keeping current daemon running. >> "${logFile}"\r + echo Install FAILED — restarting current daemon. >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + rem Restart the old version so the daemon isn't left dead\r + if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r )\r @@ -35,6 +68,7 @@ for /f "usebackq delims=" %%p in (\`call "${npmCmd}" prefix -g 2^>nul\`) do if n if not defined NPM_PREFIX (\r echo Could not resolve npm global prefix after install. >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r )\r @@ -43,6 +77,7 @@ set "CLI_SHIM=%NPM_PREFIX%\\imcodes.cmd"\r if not exist "%CLI_SHIM%" (\r echo imcodes shim missing after install: %CLI_SHIM% >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r )\r @@ -51,8 +86,9 @@ set "INSTALLED_VER="\r for /f "usebackq delims=" %%v in (\`call "%CLI_SHIM%" --version 2^>nul\`) do if not defined INSTALLED_VER set "INSTALLED_VER=%%v"\r echo Install succeeded. Installed version: %INSTALLED_VER%, target: ${targetVer}, shim: %CLI_SHIM% >> "${logFile}"\r if not "${targetVer}"=="latest" if /I not "%INSTALLED_VER%"=="${targetVer}" (\r - echo Version mismatch after install — keeping current daemon running. >> "${logFile}"\r + echo Version mismatch after install — restarting current version. >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r )\r @@ -66,11 +102,18 @@ call "%CLI_SHIM%" repair-watchdog >> "${logFile}" 2>&1\r if %errorlevel% neq 0 (\r echo WARNING: Launch chain regeneration failed >> "${logFile}"\r )\r -echo Restarting daemon via CLI watchdog path... >> "${logFile}"\r -call "%CLI_SHIM%" restart >> "${logFile}" 2>&1\r -if %errorlevel% neq 0 echo Restart command failed (exit %errorlevel%). >> "${logFile}"\r +rem ── Start fresh hidden watchdog via VBS (not imcodes restart) ──────────\r +rem Using VBS directly avoids depending on the new CLI's restart logic\r +rem which may differ across versions. The watchdog loop inside the CMD\r +rem will start the daemon automatically.\r +echo Starting fresh watchdog via VBS launcher... >> "${logFile}"\r +if exist "${vbsLauncherPath}" (\r + wscript "${vbsLauncherPath}"\r +) else (\r + echo WARNING: VBS launcher not found, falling back to CLI restart >> "${logFile}"\r + call "%CLI_SHIM%" restart >> "${logFile}" 2>&1\r +)\r timeout /t 8 /nobreak >nul\r -set "PIDFILE=%USERPROFILE%\\.imcodes\\daemon.pid"\r if exist "%PIDFILE%" (\r set /p DAEMON_PID=<"%PIDFILE%"\r tasklist /fi "PID eq !DAEMON_PID!" /nh 2^>nul | find "!DAEMON_PID!" >nul\r diff --git a/test/util/windows-upgrade-script.test.ts b/test/util/windows-upgrade-script.test.ts index a1595949..5b8217e5 100644 --- a/test/util/windows-upgrade-script.test.ts +++ b/test/util/windows-upgrade-script.test.ts @@ -18,12 +18,41 @@ describe('buildWindowsUpgradeBatch', () => { npmCmd: 'C:\\Program Files\\nodejs\\npm.cmd', pkgSpec: 'imcodes@1.2.3', targetVer: '1.2.3', + vbsLauncherPath: 'C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs', + }); + + it('kills watchdog tree before npm install to prevent MODULE_NOT_FOUND race', () => { + const installIdx = batch.indexOf('call "C:\\Program Files\\nodejs\\npm.cmd" install'); + const killIdx = batch.indexOf('taskkill /f /t /pid'); + // Kill must come BEFORE the actual install command + expect(killIdx).toBeGreaterThan(-1); + expect(installIdx).toBeGreaterThan(-1); + expect(killIdx).toBeLessThan(installIdx); + // Should also read daemon PID and find parent via wmic + expect(batch).toContain('set /p OLD_PID='); + expect(batch).toContain('wmic process where'); + expect(batch).toContain('ParentProcessId'); + }); + + it('deletes stale PID file after killing watchdog', () => { + expect(batch).toContain('del "%PIDFILE%" >nul 2>&1'); }); it('installs the requested package with a quoted npm path', () => { expect(batch).toContain('call "C:\\Program Files\\nodejs\\npm.cmd" install -g imcodes@1.2.3'); }); + it('restarts old daemon on install failure (does not leave it dead)', () => { + // Every "Install FAILED" / abort path should restart via VBS before aborting + expect(batch).toContain('Install FAILED'); + expect(batch).toContain('restarting current daemon'); + // Count VBS restarts in abort paths (each abort block has wscript call) + const abortBlocks = batch.split('goto :done'); + // At least 4 abort paths (install fail, no prefix, no shim, version mismatch) + const vbsRestarts = abortBlocks.filter(b => b.includes('wscript')); + expect(vbsRestarts.length).toBeGreaterThanOrEqual(4); + }); + it('verifies the installed CLI shim and version before restart', () => { expect(batch).toContain('set "NPM_PREFIX="'); expect(batch).toContain('prefix -g'); @@ -34,14 +63,29 @@ describe('buildWindowsUpgradeBatch', () => { expect(batch).toContain('if /I not "%INSTALLED_VER%"=="1.2.3"'); }); - it('uses the shared CLI restart path through the global shim instead of startup cmd shortcuts', () => { - expect(batch).toContain('call "%CLI_SHIM%" restart'); - expect(batch).not.toContain('imcodes-daemon.cmd'); - expect(batch).not.toContain('taskkill /f /pid'); + it('starts fresh watchdog via VBS launcher instead of imcodes restart', () => { + // After successful install, should use VBS directly (not CLI restart) + expect(batch).toContain('wscript "C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs"'); + // Should NOT depend on `imcodes restart` for the normal path + // (only as fallback if VBS missing) + const afterRepair = batch.split('repair-watchdog')[1] ?? ''; + expect(afterRepair).toContain('Starting fresh watchdog via VBS'); + expect(afterRepair).toContain('wscript'); + }); + + it('runs health check after restart', () => { + expect(batch).toContain('Health check PASSED'); + expect(batch).toContain('Health check FAILED'); + expect(batch).toContain('tasklist /fi "PID eq !DAEMON_PID!"'); }); - it('uses a standalone cleanup script instead of nested inline cleanup quoting', () => { + it('uses minimized cleanup windows', () => { expect(batch).toContain('start "" /min cmd /c "C:\\Temp\\imcodes-upgrade-123\\cleanup.cmd" >nul 2>&1'); expect(batch).not.toContain('rmdir /s /q ""'); }); + + it('kills stale watchdog loops not just the active one', () => { + expect(batch).toContain('daemon-watchdog'); + expect(batch).toContain("Name='cmd.exe'"); + }); }); From 603a2dda71f6ebaa210317fa3d507049004264f9 Mon Sep 17 00:00:00 2001 From: imcodes-win Date: Mon, 6 Apr 2026 10:05:30 +0800 Subject: [PATCH 03/57] fix(windows): upgrade lock file prevents watchdog race during npm install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of relying on killing the watchdog tree (which doesn't work when upgrading from an old version without tree-kill logic), use a simple lock file (~/.imcodes/upgrade.lock): 1. Upgrade batch creates lock file BEFORE npm install 2. Kills old watchdog + daemon (old watchdog doesn't know about lock) 3. npm install runs safely — nothing tries to restart 4. repair-watchdog generates new watchdog.cmd with lock-checking loop 5. Starts new watchdog via VBS — it sees lock, waits 6. Deletes lock file — watchdog immediately starts the new daemon 7. On any abort path: delete lock + restart VBS so daemon is never left dead Also: - watchdog.cmd now uses npm global shim (imcodes.cmd) instead of hard-coded node+script paths — survives npm upgrades without repair-watchdog - restartWindowsDaemon simplified: just kill daemon + launch VBS, let watchdog handle the restart loop Co-Authored-By: Claude Opus 4.6 (1M context) --- src/daemon/command-handler.ts | 2 + src/util/windows-daemon.ts | 47 +++------------- src/util/windows-launch-artifacts.ts | 20 ++++++- src/util/windows-upgrade-script.ts | 65 +++++++++++----------- test/util/windows-daemon.test.ts | 40 ++------------ test/util/windows-upgrade-script.test.ts | 69 +++++++++++------------- 6 files changed, 99 insertions(+), 144 deletions(-) diff --git a/src/daemon/command-handler.ts b/src/daemon/command-handler.ts index 4ad3d67c..164c866f 100644 --- a/src/daemon/command-handler.ts +++ b/src/daemon/command-handler.ts @@ -36,6 +36,7 @@ import { getProvider } from '../agent/provider-registry.js'; import { copyFile } from 'node:fs/promises'; import { ensureImcDir, imcSubDir } from '../util/imc-dir.js'; import { buildWindowsCleanupScript, buildWindowsUpgradeBatch } from '../util/windows-upgrade-script.js'; +import { UPGRADE_LOCK_FILE } from '../util/windows-launch-artifacts.js'; import { registerTempFile, removeTrackedTempFile } from '../store/temp-file-store.js'; import { sanitizeProjectName } from '../../shared/sanitize-project-name.js'; import { P2P_TERMINAL_RUN_STATUSES } from '../../shared/p2p-status.js'; @@ -2127,6 +2128,7 @@ launchctl load -w "${plist}"`; pkgSpec, targetVer, vbsLauncherPath, + upgradeLockFile: UPGRADE_LOCK_FILE, }); writeFileSync(batchPath, batch); diff --git a/src/util/windows-daemon.ts b/src/util/windows-daemon.ts index 7487998c..693824e9 100644 --- a/src/util/windows-daemon.ts +++ b/src/util/windows-daemon.ts @@ -29,37 +29,6 @@ function sleepMs(ms: number): void { Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms); } -// ── Kill the watchdog cmd.exe tree that parents the daemon ────────────────── - -/** Find the parent PID of a process via wmic. Returns null on failure. */ -function getParentPid(pid: number): number | null { - try { - const raw = execSync(`wmic process where "ProcessId=${pid}" get ParentProcessId /format:list`, { - encoding: 'utf8', - stdio: ['pipe', 'pipe', 'ignore'], - }); - const m = raw.match(/ParentProcessId=(\d+)/); - return m ? parseInt(m[1], 10) : null; - } catch { - return null; - } -} - -/** Kill the watchdog process tree that parents the daemon. - * The tree is: wscript → cmd.exe (watchdog loop) → node.exe (daemon). - * We kill the top-level process tree so no stale watchdog keeps respawning. */ -function killWatchdogTree(daemonPid: number): void { - // Walk up to the watchdog (cmd.exe or wscript) - const parentPid = getParentPid(daemonPid); - if (!parentPid) return; - - // The parent of the daemon is the watchdog cmd.exe loop. - // Kill the entire process tree from the watchdog down — this also kills the daemon. - try { - execSync(`taskkill /f /t /pid ${parentPid}`, { stdio: 'ignore' }); - } catch { /* already dead */ } -} - // ── Launcher methods (all hidden — no visible windows) ────────────────────── function tryStartVbsLauncher(): boolean { @@ -111,18 +80,16 @@ function tryStartStartupShortcut(): boolean { export function restartWindowsDaemon(currentPid?: number): boolean { const previousPid = readDaemonPid(currentPid); if (previousPid) { - // Kill the entire watchdog tree, not just the daemon. - // This prevents the old watchdog from racing with the new one. - killWatchdogTree(previousPid); - // Belt-and-suspenders: ensure the daemon itself is dead even if tree-kill missed it - sleepMs(500); - if (isPidAlive(previousPid)) { - try { execSync(`taskkill /f /pid ${previousPid}`, { stdio: 'ignore' }); } catch { /* ignore */ } - } + // Kill the daemon process. The watchdog loop will detect the exit and + // restart it automatically (within ~5 seconds). + try { execSync(`taskkill /f /pid ${previousPid}`, { stdio: 'ignore' }); } catch { /* not running */ } } - // Launch a fresh hidden watchdog. + // If no watchdog is running (e.g. first start after bind), launch one. // Priority: VBS (always hidden) > scheduled task > startup shortcut. + // If a watchdog IS already running, it will restart the daemon on its own — + // but launching a second VBS is harmless (the daemon lock prevents duplicates, + // and the extra watchdog exits when it sees "already running"). let triggered = false; if (tryStartVbsLauncher()) { triggered = true; diff --git a/src/util/windows-launch-artifacts.ts b/src/util/windows-launch-artifacts.ts index 956e2e85..69aa9d9d 100644 --- a/src/util/windows-launch-artifacts.ts +++ b/src/util/windows-launch-artifacts.ts @@ -10,6 +10,10 @@ const __dirname = dirname(__filename); const TASK_NAME = 'imcodes-daemon'; +/** Sentinel file that tells the watchdog loop to pause. + * Created by the upgrade batch before npm install, deleted after restart. */ +export const UPGRADE_LOCK_FILE = join(homedir(), '.imcodes', 'upgrade.lock'); + export interface LaunchPaths { nodeExe: string; imcodesScript: string; @@ -43,7 +47,21 @@ export async function writeWatchdogCmd(paths: LaunchPaths): Promise { const launchCmd = existsSync(shimPath) ? `"${shimPath}" start --foreground` : `"${paths.nodeExe}" "${paths.imcodesScript}" start --foreground`; - const watchdog = `@echo off\r\nchcp 65001 >nul 2>&1\r\n:loop\r\n${launchCmd} >> "${paths.logPath}" 2>&1\r\ntimeout /t 5 /nobreak >nul\r\ngoto loop\r\n`; + const lockFile = UPGRADE_LOCK_FILE.replace(/\//g, '\\'); + const watchdog = [ + '@echo off', + 'chcp 65001 >nul 2>&1', + ':loop', + `if exist "${lockFile}" (`, + ` echo Upgrade in progress, waiting... >> "${paths.logPath}"`, + ' timeout /t 5 /nobreak >nul', + ' goto loop', + ')', + `${launchCmd} >> "${paths.logPath}" 2>&1`, + 'timeout /t 5 /nobreak >nul', + 'goto loop', + '', + ].join('\r\n'); await writeFile(paths.watchdogPath, watchdog, 'utf8'); } diff --git a/src/util/windows-upgrade-script.ts b/src/util/windows-upgrade-script.ts index fc391ca2..6070a6f3 100644 --- a/src/util/windows-upgrade-script.ts +++ b/src/util/windows-upgrade-script.ts @@ -7,6 +7,8 @@ export interface WindowsUpgradeScriptInput { targetVer: string; /** Absolute path to daemon-launcher.vbs for hidden restart */ vbsLauncherPath: string; + /** Sentinel file — while it exists the watchdog loop pauses */ + upgradeLockFile: string; } export function buildWindowsCleanupScript(scriptDir: string): string { @@ -17,47 +19,41 @@ rmdir /s /q "${scriptDir}"\r } export function buildWindowsUpgradeBatch(input: WindowsUpgradeScriptInput): string { - const { logFile, cleanupPath, npmCmd, pkgSpec, targetVer, vbsLauncherPath } = input; + const { logFile, cleanupPath, npmCmd, pkgSpec, targetVer, vbsLauncherPath, upgradeLockFile } = input; return `@echo off\r setlocal EnableDelayedExpansion\r echo === imcodes upgrade started at %date% %time% === >> "${logFile}"\r timeout /t 2 /nobreak > nul\r \r -rem ── Stop watchdog + daemon BEFORE npm install ──────────────────────────\r -rem npm install -g deletes the old package before writing the new one.\r -rem If the watchdog loop restarts the daemon during that window, it hits\r -rem MODULE_NOT_FOUND and dies. Kill the entire watchdog tree first.\r +rem ── Create upgrade lock — watchdog will pause while this file exists ──\r +echo upgrade > "${upgradeLockFile}"\r +echo Upgrade lock created >> "${logFile}"\r +\r +rem ── Kill daemon + old watchdog so npm can overwrite files cleanly ─────\r +rem Old watchdog versions don't know about the lock file, so we must kill\r +rem them. After npm install, repair-watchdog generates a new watchdog\r +rem that respects the lock.\r set "PIDFILE=%USERPROFILE%\\.imcodes\\daemon.pid"\r if exist "%PIDFILE%" (\r set /p OLD_PID=<"%PIDFILE%"\r - echo Stopping daemon PID !OLD_PID! and watchdog tree... >> "${logFile}"\r - rem Find watchdog (parent of daemon) via wmic and tree-kill it\r + echo Stopping daemon PID !OLD_PID! and old watchdog... >> "${logFile}"\r + rem Find watchdog (parent of daemon) and tree-kill it\r for /f "tokens=2 delims==" %%a in ('wmic process where "ProcessId=!OLD_PID!" get ParentProcessId /format:list 2^>nul ^| find "="') do (\r - set "WATCHDOG_PID=%%a"\r + set "WD_PID=%%a"\r )\r - if defined WATCHDOG_PID (\r - rem Strip trailing carriage return from wmic output\r - set "WATCHDOG_PID=!WATCHDOG_PID: =!"\r - for /f "delims=" %%x in ("!WATCHDOG_PID!") do set "WATCHDOG_PID=%%x"\r - taskkill /f /t /pid !WATCHDOG_PID! >nul 2>&1\r - echo Killed watchdog tree PID !WATCHDOG_PID! >> "${logFile}"\r + if defined WD_PID (\r + taskkill /f /t /pid !WD_PID! >nul 2>&1\r )\r - rem Belt-and-suspenders: ensure daemon is dead even if tree-kill missed it\r taskkill /f /pid !OLD_PID! >nul 2>&1\r - rem Also kill any other stale watchdog loops\r - for /f "tokens=2 delims=," %%p in ('wmic process where "CommandLine like '%%daemon-watchdog%%' and Name='cmd.exe'" get ProcessId /format:csv 2^>nul ^| findstr /r "[0-9]"') do (\r - taskkill /f /t /pid %%p >nul 2>&1\r - )\r - del "%PIDFILE%" >nul 2>&1\r timeout /t 2 /nobreak >nul\r )\r \r echo Installing ${pkgSpec}... >> "${logFile}"\r call "${npmCmd}" install -g ${pkgSpec} >> "${logFile}" 2>&1\r if %errorlevel% neq 0 (\r - echo Install FAILED — restarting current daemon. >> "${logFile}"\r + echo Install FAILED — removing lock, watchdog will restart current version. >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r - rem Restart the old version so the daemon isn't left dead\r + del "${upgradeLockFile}" >nul 2>&1\r if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r @@ -68,6 +64,7 @@ for /f "usebackq delims=" %%p in (\`call "${npmCmd}" prefix -g 2^>nul\`) do if n if not defined NPM_PREFIX (\r echo Could not resolve npm global prefix after install. >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + del "${upgradeLockFile}" >nul 2>&1\r if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r @@ -77,6 +74,7 @@ set "CLI_SHIM=%NPM_PREFIX%\\imcodes.cmd"\r if not exist "%CLI_SHIM%" (\r echo imcodes shim missing after install: %CLI_SHIM% >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + del "${upgradeLockFile}" >nul 2>&1\r if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r @@ -86,8 +84,9 @@ set "INSTALLED_VER="\r for /f "usebackq delims=" %%v in (\`call "%CLI_SHIM%" --version 2^>nul\`) do if not defined INSTALLED_VER set "INSTALLED_VER=%%v"\r echo Install succeeded. Installed version: %INSTALLED_VER%, target: ${targetVer}, shim: %CLI_SHIM% >> "${logFile}"\r if not "${targetVer}"=="latest" if /I not "%INSTALLED_VER%"=="${targetVer}" (\r - echo Version mismatch after install — restarting current version. >> "${logFile}"\r + echo Version mismatch after install — removing lock, watchdog will restart. >> "${logFile}"\r echo === upgrade aborted at %date% %time% === >> "${logFile}"\r + del "${upgradeLockFile}" >nul 2>&1\r if exist "${vbsLauncherPath}" wscript "${vbsLauncherPath}"\r start "" /min cmd /c "${cleanupPath}" >nul 2>&1\r goto :done\r @@ -102,18 +101,22 @@ call "%CLI_SHIM%" repair-watchdog >> "${logFile}" 2>&1\r if %errorlevel% neq 0 (\r echo WARNING: Launch chain regeneration failed >> "${logFile}"\r )\r -rem ── Start fresh hidden watchdog via VBS (not imcodes restart) ──────────\r -rem Using VBS directly avoids depending on the new CLI's restart logic\r -rem which may differ across versions. The watchdog loop inside the CMD\r -rem will start the daemon automatically.\r -echo Starting fresh watchdog via VBS launcher... >> "${logFile}"\r +\r +rem ── Start new watchdog (lock-aware), then remove lock ─────────────────\r +rem The new watchdog (generated by repair-watchdog) checks the lock file.\r +rem It will loop/wait while the lock exists, then start the daemon once\r +rem we delete it below.\r +echo Starting new watchdog via VBS... >> "${logFile}"\r if exist "${vbsLauncherPath}" (\r wscript "${vbsLauncherPath}"\r ) else (\r - echo WARNING: VBS launcher not found, falling back to CLI restart >> "${logFile}"\r - call "%CLI_SHIM%" restart >> "${logFile}" 2>&1\r + echo WARNING: VBS launcher not found at ${vbsLauncherPath} >> "${logFile}"\r )\r -timeout /t 8 /nobreak >nul\r +echo Removing upgrade lock... >> "${logFile}"\r +del "${upgradeLockFile}" >nul 2>&1\r +\r +rem Wait for new watchdog to start the daemon, then health-check\r +timeout /t 10 /nobreak >nul\r if exist "%PIDFILE%" (\r set /p DAEMON_PID=<"%PIDFILE%"\r tasklist /fi "PID eq !DAEMON_PID!" /nh 2^>nul | find "!DAEMON_PID!" >nul\r diff --git a/test/util/windows-daemon.test.ts b/test/util/windows-daemon.test.ts index 77d14d13..a149d49c 100644 --- a/test/util/windows-daemon.test.ts +++ b/test/util/windows-daemon.test.ts @@ -9,8 +9,6 @@ const state = vi.hoisted(() => ({ alivePids: new Set(), execCalls: [] as string[], spawnCalls: [] as Array<{ cmd: string; args: string[] }>, - /** Simulated wmic ParentProcessId result for killWatchdogTree */ - wmicParentPid: null as number | null, })); vi.mock('node:os', () => ({ @@ -40,19 +38,8 @@ vi.mock('node:fs', () => ({ })); vi.mock('node:child_process', () => ({ - execSync: vi.fn((cmd: string, opts?: { encoding?: string }) => { + execSync: vi.fn((cmd: string) => { state.execCalls.push(cmd); - // killWatchdogTree: wmic query for parent PID - if (cmd.includes('wmic process where') && cmd.includes('ParentProcessId')) { - if (state.wmicParentPid !== null) { - const result = `\r\nParentProcessId=${state.wmicParentPid}\r\n`; - return opts?.encoding ? result : Buffer.from(result); - } - throw new Error('not found'); - } - // killWatchdogTree: taskkill /f /t (tree kill) - if (cmd.startsWith('taskkill /f /t /pid ')) return ''; - // belt-and-suspenders: taskkill /f /pid (single process) if (cmd.startsWith('taskkill /f /pid ')) return ''; if (cmd.includes('schtasks /Run /TN imcodes-daemon')) { if (!state.scheduledTaskRunOk) throw new Error('run failed'); @@ -77,7 +64,6 @@ describe('restartWindowsDaemon', () => { state.alivePids = new Set(); state.execCalls = []; state.spawnCalls = []; - state.wmicParentPid = null; vi.spyOn(process, 'kill').mockImplementation(((pid: number) => { if (!state.alivePids.has(pid)) throw new Error('not running'); return true; @@ -87,20 +73,18 @@ describe('restartWindowsDaemon', () => { it('returns false when no restart path is available', async () => { const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(false); - // No VBS, no schtask, no startup shortcut — nothing to trigger expect(state.spawnCalls).toHaveLength(0); }); - it('kills watchdog tree and launches VBS when available', async () => { + it('kills daemon and launches VBS when available', async () => { state.pidContents = ['123', '456']; state.alivePids = new Set([456]); state.vbsExists = true; - state.wmicParentPid = 999; // watchdog parent const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); - // Should tree-kill the watchdog parent - expect(state.execCalls).toContain('taskkill /f /t /pid 999'); + // Should kill daemon + expect(state.execCalls).toContain('taskkill /f /pid 123'); // Should launch VBS (preferred over schtask) expect(state.spawnCalls[0]).toEqual( expect.objectContaining({ cmd: 'wscript', args: expect.arrayContaining(['C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs']) }), @@ -111,11 +95,10 @@ describe('restartWindowsDaemon', () => { state.pidContents = ['123', '456']; state.alivePids = new Set([456]); state.scheduledTaskRunOk = true; - state.wmicParentPid = 888; const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); - expect(state.execCalls).toContain('taskkill /f /t /pid 888'); + expect(state.execCalls).toContain('taskkill /f /pid 123'); expect(state.execCalls).toContain('schtasks /Run /TN imcodes-daemon'); }); @@ -127,20 +110,7 @@ describe('restartWindowsDaemon', () => { const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); expect(state.spawnCalls).toHaveLength(1); - // cmd resolved via COMSPEC — match any path ending in cmd.exe expect(state.spawnCalls[0].cmd).toMatch(/cmd(\.exe)?$/i); expect(state.spawnCalls[0].args).toEqual(['/c', 'C:\\Users\\tester\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\imcodes-daemon.cmd']); }); - - it('force-kills daemon if tree-kill misses it', async () => { - state.pidContents = ['123', '456']; - state.alivePids = new Set([123, 456]); // daemon still alive after tree-kill - state.vbsExists = true; - state.wmicParentPid = null; // wmic fails — no parent found - - const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); - expect(restartWindowsDaemon()).toBe(true); - // Should fall back to direct taskkill - expect(state.execCalls).toContain('taskkill /f /pid 123'); - }); }); diff --git a/test/util/windows-upgrade-script.test.ts b/test/util/windows-upgrade-script.test.ts index 5b8217e5..39ae412a 100644 --- a/test/util/windows-upgrade-script.test.ts +++ b/test/util/windows-upgrade-script.test.ts @@ -19,38 +19,41 @@ describe('buildWindowsUpgradeBatch', () => { pkgSpec: 'imcodes@1.2.3', targetVer: '1.2.3', vbsLauncherPath: 'C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs', + upgradeLockFile: 'C:\\Users\\tester\\.imcodes\\upgrade.lock', }); - it('kills watchdog tree before npm install to prevent MODULE_NOT_FOUND race', () => { + it('creates upgrade lock before npm install', () => { + const lockIdx = batch.indexOf('echo upgrade > "C:\\Users\\tester\\.imcodes\\upgrade.lock"'); const installIdx = batch.indexOf('call "C:\\Program Files\\nodejs\\npm.cmd" install'); - const killIdx = batch.indexOf('taskkill /f /t /pid'); - // Kill must come BEFORE the actual install command - expect(killIdx).toBeGreaterThan(-1); + expect(lockIdx).toBeGreaterThan(-1); expect(installIdx).toBeGreaterThan(-1); - expect(killIdx).toBeLessThan(installIdx); - // Should also read daemon PID and find parent via wmic - expect(batch).toContain('set /p OLD_PID='); - expect(batch).toContain('wmic process where'); - expect(batch).toContain('ParentProcessId'); + expect(lockIdx).toBeLessThan(installIdx); }); - it('deletes stale PID file after killing watchdog', () => { - expect(batch).toContain('del "%PIDFILE%" >nul 2>&1'); + it('removes lock on every abort path so watchdog resumes', () => { + const abortBlocks = batch.split('goto :done'); + // At least 4 abort paths (install fail, no prefix, no shim, version mismatch) + const lockDeletes = abortBlocks.filter(b => b.includes('del "C:\\Users\\tester\\.imcodes\\upgrade.lock"')); + expect(lockDeletes.length).toBeGreaterThanOrEqual(4); }); - it('installs the requested package with a quoted npm path', () => { - expect(batch).toContain('call "C:\\Program Files\\nodejs\\npm.cmd" install -g imcodes@1.2.3'); + it('starts new watchdog via VBS then removes lock after successful install', () => { + // After the actual repair-watchdog CLI call, batch should start VBS then remove lock + const repairCallIdx = batch.indexOf('call "%CLI_SHIM%" repair-watchdog'); + const afterRepair = batch.slice(repairCallIdx); + const vbsIdx = afterRepair.indexOf('Starting new watchdog via VBS'); + const delIdx = afterRepair.indexOf('Removing upgrade lock'); + expect(vbsIdx).toBeGreaterThan(-1); + expect(delIdx).toBeGreaterThan(vbsIdx); + expect(afterRepair).toContain('del "C:\\Users\\tester\\.imcodes\\upgrade.lock"'); }); - it('restarts old daemon on install failure (does not leave it dead)', () => { - // Every "Install FAILED" / abort path should restart via VBS before aborting - expect(batch).toContain('Install FAILED'); - expect(batch).toContain('restarting current daemon'); - // Count VBS restarts in abort paths (each abort block has wscript call) - const abortBlocks = batch.split('goto :done'); - // At least 4 abort paths (install fail, no prefix, no shim, version mismatch) - const vbsRestarts = abortBlocks.filter(b => b.includes('wscript')); - expect(vbsRestarts.length).toBeGreaterThanOrEqual(4); + it('kills daemon before npm install', () => { + expect(batch).toContain('taskkill /f /pid !OLD_PID!'); + }); + + it('installs the requested package with a quoted npm path', () => { + expect(batch).toContain('call "C:\\Program Files\\nodejs\\npm.cmd" install -g imcodes@1.2.3'); }); it('verifies the installed CLI shim and version before restart', () => { @@ -63,17 +66,15 @@ describe('buildWindowsUpgradeBatch', () => { expect(batch).toContain('if /I not "%INSTALLED_VER%"=="1.2.3"'); }); - it('starts fresh watchdog via VBS launcher instead of imcodes restart', () => { - // After successful install, should use VBS directly (not CLI restart) - expect(batch).toContain('wscript "C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs"'); - // Should NOT depend on `imcodes restart` for the normal path - // (only as fallback if VBS missing) - const afterRepair = batch.split('repair-watchdog')[1] ?? ''; - expect(afterRepair).toContain('Starting fresh watchdog via VBS'); - expect(afterRepair).toContain('wscript'); + it('lets watchdog restart daemon after lock removal (no manual restart)', () => { + // After successful upgrade, should NOT call `imcodes restart` + // — the watchdog loop will detect lock removal and restart automatically + const afterLockRemoval = batch.split('Removing upgrade lock')[1] ?? ''; + expect(afterLockRemoval).not.toContain('imcodes restart'); + expect(afterLockRemoval).not.toContain('CLI_SHIM%" restart'); }); - it('runs health check after restart', () => { + it('runs health check after watchdog restarts daemon', () => { expect(batch).toContain('Health check PASSED'); expect(batch).toContain('Health check FAILED'); expect(batch).toContain('tasklist /fi "PID eq !DAEMON_PID!"'); @@ -81,11 +82,5 @@ describe('buildWindowsUpgradeBatch', () => { it('uses minimized cleanup windows', () => { expect(batch).toContain('start "" /min cmd /c "C:\\Temp\\imcodes-upgrade-123\\cleanup.cmd" >nul 2>&1'); - expect(batch).not.toContain('rmdir /s /q ""'); - }); - - it('kills stale watchdog loops not just the active one', () => { - expect(batch).toContain('daemon-watchdog'); - expect(batch).toContain("Name='cmd.exe'"); }); }); From 6356c1fa08b308a36bf2f410363a7e0d0b8a3b01 Mon Sep 17 00:00:00 2001 From: imcodes-win Date: Mon, 6 Apr 2026 10:08:35 +0800 Subject: [PATCH 04/57] test(windows): comprehensive daemon recovery tests 32 tests covering every daemon recovery scenario: windows-daemon.test.ts (10 tests): - Launcher priority: VBS > schtask > startup shortcut - Daemon kill: by PID, handles already-dead, skips own PID - PID wait: new PID detection, fresh start without previous PID - windowsHide on all spawn calls windows-upgrade-script.test.ts (16 tests): - Lock file lifecycle: created before install, deleted on every exit path - Every abort path: deletes lock AND restarts VBS (daemon never left dead) - Success path: VBS started before lock removal (watchdog waits on lock) - Old watchdog tree-kill before npm install - Version verification and repair-watchdog ordering - No imcodes restart on success path (watchdog handles it) - Health check after restart - No visible windows (minimized cleanup) - "latest" target skips version comparison windows-launch-artifacts.test.ts (6 tests): - Watchdog.cmd: lock file check before daemon launch - Watchdog.cmd: uses npm global shim, falls back to node+script - Watchdog.cmd: infinite loop with 5s retry - VBS launcher: hidden window (style 0) - UPGRADE_LOCK_FILE path Co-Authored-By: Claude Opus 4.6 (1M context) --- test/util/windows-daemon.test.ts | 158 +++++++++++++++------ test/util/windows-launch-artifacts.test.ts | 149 +++++++++++++++++++ test/util/windows-upgrade-script.test.ts | 155 ++++++++++++++------ 3 files changed, 376 insertions(+), 86 deletions(-) create mode 100644 test/util/windows-launch-artifacts.test.ts diff --git a/test/util/windows-daemon.test.ts b/test/util/windows-daemon.test.ts index a149d49c..bef98882 100644 --- a/test/util/windows-daemon.test.ts +++ b/test/util/windows-daemon.test.ts @@ -1,5 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; +// ── Shared mock state ────────────────────────────────────────────────────────── + const state = vi.hoisted(() => ({ pidContents: [''], pidIndex: 0, @@ -11,37 +13,31 @@ const state = vi.hoisted(() => ({ spawnCalls: [] as Array<{ cmd: string; args: string[] }>, })); -vi.mock('node:os', () => ({ - homedir: () => 'C:\\Users\\tester', -})); +vi.mock('node:os', () => ({ homedir: () => 'C:\\Users\\tester' })); vi.mock('node:path', async () => { const actual = await vi.importActual('node:path'); - return { - ...actual, - resolve: (...parts: string[]) => parts.join('\\'), - }; + return { ...actual, resolve: (...parts: string[]) => parts.join('\\') }; }); vi.mock('node:fs', () => ({ existsSync: vi.fn((path: string) => { if (path.endsWith('daemon-launcher.vbs')) return state.vbsExists; - if (path.endsWith('Start Menu\\Programs\\Startup\\imcodes-daemon.cmd')) return state.startupCmdExists; + if (path.endsWith('imcodes-daemon.cmd')) return state.startupCmdExists; return false; }), readFileSync: vi.fn(() => { const idx = Math.min(state.pidIndex, state.pidContents.length - 1); - const value = state.pidContents[idx] ?? ''; state.pidIndex += 1; - return value; + return state.pidContents[idx] ?? ''; }), })); vi.mock('node:child_process', () => ({ execSync: vi.fn((cmd: string) => { state.execCalls.push(cmd); - if (cmd.startsWith('taskkill /f /pid ')) return ''; - if (cmd.includes('schtasks /Run /TN imcodes-daemon')) { + if (cmd.startsWith('taskkill ')) return ''; + if (cmd.includes('schtasks /Run')) { if (!state.scheduledTaskRunOk) throw new Error('run failed'); return ''; } @@ -53,64 +49,138 @@ vi.mock('node:child_process', () => ({ }), })); +function reset(): void { + vi.resetModules(); + state.pidContents = ['']; + state.pidIndex = 0; + state.scheduledTaskRunOk = false; + state.vbsExists = false; + state.startupCmdExists = false; + state.alivePids = new Set(); + state.execCalls = []; + state.spawnCalls = []; + vi.spyOn(process, 'kill').mockImplementation(((pid: number) => { + if (!state.alivePids.has(pid)) throw new Error('not running'); + return true; + }) as typeof process.kill); +} + +// ── restartWindowsDaemon tests ───────────────────────────────────────────────── + describe('restartWindowsDaemon', () => { - beforeEach(() => { - vi.resetModules(); - state.pidContents = ['']; - state.pidIndex = 0; - state.scheduledTaskRunOk = false; - state.vbsExists = false; - state.startupCmdExists = false; - state.alivePids = new Set(); - state.execCalls = []; - state.spawnCalls = []; - vi.spyOn(process, 'kill').mockImplementation(((pid: number) => { - if (!state.alivePids.has(pid)) throw new Error('not running'); - return true; - }) as typeof process.kill); - }); + beforeEach(reset); + + // ── Launcher priority ── - it('returns false when no restart path is available', async () => { + it('returns false when no launcher path is available', async () => { const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(false); expect(state.spawnCalls).toHaveLength(0); }); - it('kills daemon and launches VBS when available', async () => { - state.pidContents = ['123', '456']; - state.alivePids = new Set([456]); + it('prefers VBS launcher over scheduled task', async () => { + state.pidContents = ['', '100']; + state.alivePids = new Set([100]); state.vbsExists = true; + state.scheduledTaskRunOk = true; const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); - // Should kill daemon - expect(state.execCalls).toContain('taskkill /f /pid 123'); - // Should launch VBS (preferred over schtask) - expect(state.spawnCalls[0]).toEqual( - expect.objectContaining({ cmd: 'wscript', args: expect.arrayContaining(['C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs']) }), - ); + expect(state.spawnCalls[0].cmd).toBe('wscript'); + // Should NOT have called schtasks since VBS succeeded + expect(state.execCalls.some(c => c.includes('schtasks /Run'))).toBe(false); }); - it('falls back to scheduled task when VBS is not available', async () => { - state.pidContents = ['123', '456']; - state.alivePids = new Set([456]); + it('falls back to scheduled task when VBS missing', async () => { + state.pidContents = ['', '200']; + state.alivePids = new Set([200]); state.scheduledTaskRunOk = true; const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); - expect(state.execCalls).toContain('taskkill /f /pid 123'); + expect(state.spawnCalls).toHaveLength(0); expect(state.execCalls).toContain('schtasks /Run /TN imcodes-daemon'); }); it('falls back to startup shortcut as last resort', async () => { - state.pidContents = ['', '901']; - state.alivePids = new Set([901]); + state.pidContents = ['', '300']; + state.alivePids = new Set([300]); state.startupCmdExists = true; const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); expect(restartWindowsDaemon()).toBe(true); expect(state.spawnCalls).toHaveLength(1); expect(state.spawnCalls[0].cmd).toMatch(/cmd(\.exe)?$/i); - expect(state.spawnCalls[0].args).toEqual(['/c', 'C:\\Users\\tester\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\imcodes-daemon.cmd']); + }); + + // ── Daemon kill ── + + it('kills existing daemon by PID before launching', async () => { + state.pidContents = ['555', '666']; + state.alivePids = new Set([666]); + state.vbsExists = true; + + const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); + expect(restartWindowsDaemon()).toBe(true); + expect(state.execCalls).toContain('taskkill /f /pid 555'); + }); + + it('handles daemon already dead gracefully', async () => { + // PID file has a value but process is not running — should not throw + state.pidContents = ['999', '888']; + state.alivePids = new Set([888]); + state.vbsExists = true; + + const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); + expect(restartWindowsDaemon()).toBe(true); + // taskkill was attempted (and silently failed) + expect(state.execCalls).toContain('taskkill /f /pid 999'); + }); + + // ── PID wait logic ── + + it('waits for new PID different from old', async () => { + // First read: old PID 100, second read: new PID 200 + state.pidContents = ['100', '200']; + state.alivePids = new Set([200]); + state.vbsExists = true; + + const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); + expect(restartWindowsDaemon()).toBe(true); + }); + + it('works when no previous PID exists (fresh start)', async () => { + state.pidContents = ['', '500']; + state.alivePids = new Set([500]); + state.vbsExists = true; + + const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); + expect(restartWindowsDaemon()).toBe(true); + }); + + it('skips own PID when passed as currentPid', async () => { + // PID file contains our own PID — should treat as "no previous daemon" + state.pidContents = ['42', '700']; + state.alivePids = new Set([700]); + state.vbsExists = true; + + const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); + // currentPid=42 matches PID file → no taskkill + expect(restartWindowsDaemon(42)).toBe(true); + expect(state.execCalls.some(c => c.includes('taskkill'))).toBe(false); + }); + + // ── windowsHide on all spawn calls ── + + it('passes windowsHide to VBS spawn', async () => { + state.pidContents = ['', '100']; + state.alivePids = new Set([100]); + state.vbsExists = true; + + const { spawn } = await import('node:child_process'); + const { restartWindowsDaemon } = await import('../../src/util/windows-daemon.js'); + restartWindowsDaemon(); + const call = (spawn as ReturnType).mock.calls[0]; + expect(call[2]).toEqual(expect.objectContaining({ windowsHide: true })); }); }); diff --git a/test/util/windows-launch-artifacts.test.ts b/test/util/windows-launch-artifacts.test.ts new file mode 100644 index 00000000..70db7add --- /dev/null +++ b/test/util/windows-launch-artifacts.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, it, vi, beforeEach } from 'vitest'; + +// ── Mock fs so writeWatchdogCmd doesn't touch disk ───────────────────────── + +const written: Record = {}; + +vi.mock('fs/promises', () => ({ + writeFile: vi.fn(async (path: string, content: string) => { written[path] = content; }), + mkdir: vi.fn(async () => undefined), + stat: vi.fn(async () => ({ size: 0 })), + truncate: vi.fn(async () => undefined), +})); + +vi.mock('fs', () => ({ + existsSync: vi.fn((path: string) => { + // Simulate npm global shim exists + if (path.endsWith('imcodes.cmd')) return true; + return false; + }), +})); + +vi.mock('child_process', () => ({ + execSync: vi.fn(() => ''), +})); + +describe('writeWatchdogCmd', () => { + beforeEach(() => { + for (const k of Object.keys(written)) delete written[k]; + }); + + it('generates watchdog with upgrade lock check', async () => { + const { writeWatchdogCmd, UPGRADE_LOCK_FILE } = await import('../../src/util/windows-launch-artifacts.js'); + const paths = { + nodeExe: 'C:\\Program Files\\nodejs\\node.exe', + imcodesScript: 'C:\\Users\\X\\AppData\\Roaming\\npm\\node_modules\\imcodes\\dist\\src\\index.js', + watchdogPath: 'C:\\Users\\X\\.imcodes\\daemon-watchdog.cmd', + vbsPath: 'C:\\Users\\X\\.imcodes\\daemon-launcher.vbs', + logPath: 'C:\\Users\\X\\.imcodes\\watchdog.log', + }; + + await writeWatchdogCmd(paths); + + const cmd = written[paths.watchdogPath]; + expect(cmd).toBeDefined(); + + // Must check lock file BEFORE launching daemon + const lockCheck = cmd.indexOf('if exist'); + const launchCmd = cmd.indexOf('start --foreground'); + expect(lockCheck).toBeGreaterThan(-1); + expect(launchCmd).toBeGreaterThan(lockCheck); + + // Lock file path must be in the check + const lockPath = UPGRADE_LOCK_FILE.replace(/\//g, '\\'); + expect(cmd).toContain(lockPath); + + // When locked, should wait and loop back (not launch daemon) + expect(cmd).toContain('Upgrade in progress, waiting'); + expect(cmd).toContain('goto loop'); + }); + + it('uses npm global shim instead of hard-coded node+script paths', async () => { + const { writeWatchdogCmd } = await import('../../src/util/windows-launch-artifacts.js'); + const paths = { + nodeExe: 'C:\\Program Files\\nodejs\\node.exe', + imcodesScript: 'C:\\Users\\X\\AppData\\Roaming\\npm\\node_modules\\imcodes\\dist\\src\\index.js', + watchdogPath: 'C:\\Users\\X\\.imcodes\\daemon-watchdog.cmd', + vbsPath: 'C:\\Users\\X\\.imcodes\\daemon-launcher.vbs', + logPath: 'C:\\Users\\X\\.imcodes\\watchdog.log', + }; + + await writeWatchdogCmd(paths); + const cmd = written[paths.watchdogPath]; + + // Should use the shim, not the raw node+script + expect(cmd).toContain('imcodes.cmd'); + expect(cmd).not.toContain('node_modules'); + }); + + it('falls back to node+script when shim not found', async () => { + // Override existsSync to return false for shim + const { existsSync } = await import('fs'); + (existsSync as ReturnType).mockReturnValue(false); + + const { writeWatchdogCmd } = await import('../../src/util/windows-launch-artifacts.js'); + const paths = { + nodeExe: 'C:\\Program Files\\nodejs\\node.exe', + imcodesScript: 'C:\\dev\\imcodes\\dist\\src\\index.js', + watchdogPath: 'C:\\Users\\X\\.imcodes\\daemon-watchdog.cmd', + vbsPath: 'C:\\Users\\X\\.imcodes\\daemon-launcher.vbs', + logPath: 'C:\\Users\\X\\.imcodes\\watchdog.log', + }; + + await writeWatchdogCmd(paths); + const cmd = written[paths.watchdogPath]; + + // Should fall back to direct node+script + expect(cmd).toContain('node.exe'); + expect(cmd).toContain('index.js'); + }); + + it('watchdog is an infinite loop with 5s retry', async () => { + const { writeWatchdogCmd } = await import('../../src/util/windows-launch-artifacts.js'); + const paths = { + nodeExe: 'node.exe', + imcodesScript: 'C:\\npm\\node_modules\\imcodes\\dist\\src\\index.js', + watchdogPath: 'out.cmd', + vbsPath: 'out.vbs', + logPath: 'out.log', + }; + + await writeWatchdogCmd(paths); + const cmd = written[paths.watchdogPath]; + + expect(cmd).toContain(':loop'); + expect(cmd).toContain('goto loop'); + expect(cmd).toContain('timeout /t 5'); + }); +}); + +describe('writeVbsLauncher', () => { + beforeEach(() => { + for (const k of Object.keys(written)) delete written[k]; + }); + + it('runs watchdog CMD hidden (window style 0)', async () => { + const { writeVbsLauncher } = await import('../../src/util/windows-launch-artifacts.js'); + const paths = { + nodeExe: '', imcodesScript: '', logPath: '', + watchdogPath: 'C:\\Users\\X\\.imcodes\\daemon-watchdog.cmd', + vbsPath: 'C:\\Users\\X\\.imcodes\\daemon-launcher.vbs', + }; + + await writeVbsLauncher(paths); + const vbs = written[paths.vbsPath]; + + expect(vbs).toContain('WshShell.Run'); + expect(vbs).toContain('daemon-watchdog.cmd'); + // Window style 0 = hidden + expect(vbs).toContain(', 0, False'); + }); +}); + +describe('UPGRADE_LOCK_FILE', () => { + it('is under .imcodes directory', async () => { + const { UPGRADE_LOCK_FILE } = await import('../../src/util/windows-launch-artifacts.js'); + expect(UPGRADE_LOCK_FILE).toContain('.imcodes'); + expect(UPGRADE_LOCK_FILE).toContain('upgrade.lock'); + }); +}); diff --git a/test/util/windows-upgrade-script.test.ts b/test/util/windows-upgrade-script.test.ts index 39ae412a..be6254a7 100644 --- a/test/util/windows-upgrade-script.test.ts +++ b/test/util/windows-upgrade-script.test.ts @@ -1,6 +1,17 @@ import { describe, expect, it } from 'vitest'; import { buildWindowsCleanupScript, buildWindowsUpgradeBatch } from '../../src/util/windows-upgrade-script.js'; +const INPUT = { + logFile: 'C:\\Temp\\upgrade.log', + scriptDir: 'C:\\Temp\\imcodes-upgrade-123', + cleanupPath: 'C:\\Temp\\imcodes-upgrade-123\\cleanup.cmd', + npmCmd: 'C:\\Program Files\\nodejs\\npm.cmd', + pkgSpec: 'imcodes@1.2.3', + targetVer: '1.2.3', + vbsLauncherPath: 'C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs', + upgradeLockFile: 'C:\\Users\\tester\\.imcodes\\upgrade.lock', +} as const; + describe('buildWindowsCleanupScript', () => { it('generates a standalone cleanup cmd script', () => { const script = buildWindowsCleanupScript('C:\\Temp\\imcodes-upgrade-123'); @@ -11,76 +22,136 @@ describe('buildWindowsCleanupScript', () => { }); describe('buildWindowsUpgradeBatch', () => { - const batch = buildWindowsUpgradeBatch({ - logFile: 'C:\\Temp\\upgrade.log', - scriptDir: 'C:\\Temp\\imcodes-upgrade-123', - cleanupPath: 'C:\\Temp\\imcodes-upgrade-123\\cleanup.cmd', - npmCmd: 'C:\\Program Files\\nodejs\\npm.cmd', - pkgSpec: 'imcodes@1.2.3', - targetVer: '1.2.3', - vbsLauncherPath: 'C:\\Users\\tester\\.imcodes\\daemon-launcher.vbs', - upgradeLockFile: 'C:\\Users\\tester\\.imcodes\\upgrade.lock', - }); - - it('creates upgrade lock before npm install', () => { - const lockIdx = batch.indexOf('echo upgrade > "C:\\Users\\tester\\.imcodes\\upgrade.lock"'); - const installIdx = batch.indexOf('call "C:\\Program Files\\nodejs\\npm.cmd" install'); + const batch = buildWindowsUpgradeBatch(INPUT); + + // ── Lock file lifecycle ── + + it('creates upgrade lock BEFORE npm install', () => { + const lockIdx = batch.indexOf(`echo upgrade > "${INPUT.upgradeLockFile}"`); + const installIdx = batch.indexOf(`call "${INPUT.npmCmd}" install`); expect(lockIdx).toBeGreaterThan(-1); expect(installIdx).toBeGreaterThan(-1); expect(lockIdx).toBeLessThan(installIdx); }); - it('removes lock on every abort path so watchdog resumes', () => { - const abortBlocks = batch.split('goto :done'); - // At least 4 abort paths (install fail, no prefix, no shim, version mismatch) - const lockDeletes = abortBlocks.filter(b => b.includes('del "C:\\Users\\tester\\.imcodes\\upgrade.lock"')); - expect(lockDeletes.length).toBeGreaterThanOrEqual(4); + it('every abort path deletes lock AND restarts VBS', () => { + // Split on `goto :done` — each abort block must have both del lock + wscript + const blocks = batch.split('goto :done'); + // Last block is after :done label — skip it + const abortBlocks = blocks.slice(0, -1); + // At least 4 abort paths: install fail, no prefix, no shim, version mismatch + expect(abortBlocks.length).toBeGreaterThanOrEqual(4); + for (const block of abortBlocks) { + expect(block).toContain(`del "${INPUT.upgradeLockFile}"`); + expect(block).toContain('wscript'); + } }); - it('starts new watchdog via VBS then removes lock after successful install', () => { - // After the actual repair-watchdog CLI call, batch should start VBS then remove lock - const repairCallIdx = batch.indexOf('call "%CLI_SHIM%" repair-watchdog'); - const afterRepair = batch.slice(repairCallIdx); + it('success path: starts new watchdog via VBS then removes lock', () => { + const repairIdx = batch.indexOf('call "%CLI_SHIM%" repair-watchdog'); + const afterRepair = batch.slice(repairIdx); const vbsIdx = afterRepair.indexOf('Starting new watchdog via VBS'); const delIdx = afterRepair.indexOf('Removing upgrade lock'); expect(vbsIdx).toBeGreaterThan(-1); - expect(delIdx).toBeGreaterThan(vbsIdx); - expect(afterRepair).toContain('del "C:\\Users\\tester\\.imcodes\\upgrade.lock"'); + expect(delIdx).toBeGreaterThan(-1); + // VBS start must come BEFORE lock removal — watchdog waits on lock + expect(vbsIdx).toBeLessThan(delIdx); }); - it('kills daemon before npm install', () => { + // ── Daemon + old watchdog kill ── + + it('kills old watchdog tree before npm install', () => { + const killTreeIdx = batch.indexOf('taskkill /f /t /pid !WD_PID!'); + const installIdx = batch.indexOf(`call "${INPUT.npmCmd}" install`); + expect(killTreeIdx).toBeGreaterThan(-1); + expect(killTreeIdx).toBeLessThan(installIdx); + }); + + it('kills daemon directly as belt-and-suspenders', () => { expect(batch).toContain('taskkill /f /pid !OLD_PID!'); }); - it('installs the requested package with a quoted npm path', () => { - expect(batch).toContain('call "C:\\Program Files\\nodejs\\npm.cmd" install -g imcodes@1.2.3'); + it('finds watchdog parent via wmic', () => { + expect(batch).toContain('wmic process where'); + expect(batch).toContain('ParentProcessId'); }); - it('verifies the installed CLI shim and version before restart', () => { - expect(batch).toContain('set "NPM_PREFIX="'); - expect(batch).toContain('prefix -g'); + // ── npm install ── + + it('installs with quoted npm path', () => { + expect(batch).toContain(`call "${INPUT.npmCmd}" install -g ${INPUT.pkgSpec}`); + }); + + // ── Version verification ── + + it('verifies installed CLI shim exists', () => { expect(batch).toContain('set "CLI_SHIM=%NPM_PREFIX%\\imcodes.cmd"'); expect(batch).toContain('if not exist "%CLI_SHIM%"'); - expect(batch).toContain('set "INSTALLED_VER="'); + }); + + it('verifies installed version matches target', () => { expect(batch).toContain('call "%CLI_SHIM%" --version'); - expect(batch).toContain('if /I not "%INSTALLED_VER%"=="1.2.3"'); + expect(batch).toContain(`if /I not "%INSTALLED_VER%"=="${INPUT.targetVer}"`); + }); + + // ── repair-watchdog ── + + it('calls repair-watchdog after successful install', () => { + const installOkIdx = batch.indexOf('Install succeeded'); + const repairIdx = batch.indexOf('call "%CLI_SHIM%" repair-watchdog'); + expect(repairIdx).toBeGreaterThan(installOkIdx); }); - it('lets watchdog restart daemon after lock removal (no manual restart)', () => { - // After successful upgrade, should NOT call `imcodes restart` - // — the watchdog loop will detect lock removal and restart automatically - const afterLockRemoval = batch.split('Removing upgrade lock')[1] ?? ''; - expect(afterLockRemoval).not.toContain('imcodes restart'); - expect(afterLockRemoval).not.toContain('CLI_SHIM%" restart'); + // ── Success path does NOT use imcodes restart ── + + it('does not call imcodes restart on success path', () => { + // After repair-watchdog, should use VBS + lock removal, not CLI restart + const afterRepair = batch.slice(batch.indexOf('call "%CLI_SHIM%" repair-watchdog')); + expect(afterRepair).not.toContain('CLI_SHIM%" restart'); }); - it('runs health check after watchdog restarts daemon', () => { + // ── Health check ── + + it('runs health check after daemon restart', () => { expect(batch).toContain('Health check PASSED'); expect(batch).toContain('Health check FAILED'); - expect(batch).toContain('tasklist /fi "PID eq !DAEMON_PID!"'); + expect(batch).toContain('daemon.pid not found'); }); + // ── No visible windows ── + it('uses minimized cleanup windows', () => { - expect(batch).toContain('start "" /min cmd /c "C:\\Temp\\imcodes-upgrade-123\\cleanup.cmd" >nul 2>&1'); + const cleanupCalls = batch.match(/start.*cmd.*cleanup/g) ?? []; + for (const call of cleanupCalls) { + expect(call).toContain('/min'); + } + expect(cleanupCalls.length).toBeGreaterThan(0); + }); + + // ── Recovery guarantee: daemon is never left dead ── + + it('daemon is always restarted — every code path ends with either VBS launch or lock removal', () => { + // Count all paths that could leave the function: + // 1. Each `goto :done` abort block must restart via VBS + // 2. The success path must start VBS + remove lock + // 3. The :done label itself just logs — that's fine since abort blocks already restarted + + const abortBlocks = batch.split('goto :done').slice(0, -1); + for (const block of abortBlocks) { + // Every abort must restart the daemon via VBS + expect(block).toContain(`wscript "${INPUT.vbsLauncherPath}"`); + } + + // Success path must start new watchdog + const successPath = batch.slice(batch.indexOf('Regenerating daemon launch chain')); + expect(successPath).toContain(`wscript "${INPUT.vbsLauncherPath}"`); + }); +}); + +describe('buildWindowsUpgradeBatch with latest target', () => { + it('skips version comparison when target is "latest"', () => { + const batch = buildWindowsUpgradeBatch({ ...INPUT, targetVer: 'latest' }); + expect(batch).toContain('if not "latest"=="latest"'); + // The condition `if not "latest"=="latest"` is always false → skip mismatch abort }); }); From 2290e7c125c5597f28da2e70ac1566626f5f90c6 Mon Sep 17 00:00:00 2001 From: "IM.codes" Date: Mon, 6 Apr 2026 11:02:30 +0800 Subject: [PATCH 05/57] Add SDK transport support for Claude and Codex --- README.md | 16 +- landing/imcodes-watch0.png | Bin 0 -> 34727 bytes landing/imcodes-watch1.png | Bin 0 -> 48093 bytes landing/imcodes-watch2.png | Bin 0 -> 55520 bytes landing/index.html | 37 +- package-lock.json | 1578 ++++++++++++++++- package.json | 4 +- src/agent/detect.ts | 5 +- src/agent/provider-registry.ts | 8 + src/agent/providers/claude-code-sdk.ts | 350 ++++ src/agent/providers/codex-sdk.ts | 310 ++++ src/agent/session-manager.ts | 45 + src/agent/transport-provider.ts | 19 + src/agent/transport-session-runtime.ts | 9 +- src/daemon/lifecycle.ts | 9 +- test/agent/claude-code-sdk-provider.test.ts | 119 ++ test/agent/codex-sdk-provider.test.ts | 100 ++ test/agent/provider-registry.test.ts | 80 +- test/daemon/sdk-transport-restore.test.ts | 186 ++ test/e2e/sdk-transport-flow.test.ts | 222 +++ web/src/components/NewSessionDialog.tsx | 4 +- web/src/i18n/locales/en.json | 4 +- web/src/i18n/locales/es.json | 4 +- web/src/i18n/locales/ja.json | 4 +- web/src/i18n/locales/ko.json | 4 +- web/src/i18n/locales/ru.json | 4 +- web/src/i18n/locales/zh-CN.json | 4 +- web/src/i18n/locales/zh-TW.json | 4 +- web/src/pages/AutoFixControls.tsx | 2 +- web/src/pages/ProjectSettings.tsx | 2 +- web/src/watch-projection.ts | 2 + web/test/components/NewSessionDialog.test.tsx | 4 +- 32 files changed, 3070 insertions(+), 69 deletions(-) create mode 100644 landing/imcodes-watch0.png create mode 100644 landing/imcodes-watch1.png create mode 100644 landing/imcodes-watch2.png create mode 100644 src/agent/providers/claude-code-sdk.ts create mode 100644 src/agent/providers/codex-sdk.ts create mode 100644 test/agent/claude-code-sdk-provider.test.ts create mode 100644 test/agent/codex-sdk-provider.test.ts create mode 100644 test/daemon/sdk-transport-restore.test.ts create mode 100644 test/e2e/sdk-transport-flow.test.ts diff --git a/README.md b/README.md index 5bc929d5..9a86f456 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,21 @@ A specialized instant messenger for AI agents. Keep long-running coding-agent se

+### Apple Watch + +

+ + + +

+ +Watch support covers quick session monitoring, unread counts, push notifications, and quick replies directly from the wrist. + ## Download Download on the App Store -Also available as a [web app](https://app.im.codes) and via `npm install -g imcodes` (daemon CLI). +Supports iPhone, iPad, and Apple Watch. Also available as a [web app](https://app.im.codes) and via `npm install -g imcodes` (daemon CLI). ## Why @@ -68,9 +78,9 @@ Browse project files with a tree view. Upload files, images, and photos from any Preview your local dev server from any device — phone, tablet, or remote browser — without deploying. The daemon proxies `localhost` traffic through a secure WebSocket tunnel to the server. HTML rewriting and a runtime patch handle URL remapping so links, fetch, and WebSocket connections just work. Supports HMR/hot-reload via WebSocket tunneling. No public URLs, no third-party tunnels — traffic stays within your IM.codes server. -### Mobile & Notifications +### Mobile, Watch & Notifications -Full mobile support with biometric auth and push notifications. Shell sessions allow interactive keyboard input on mobile (SSH-like). Sub-session preview cards always show latest messages. Toast notifications navigate directly to the relevant session. +Full mobile support with biometric auth and push notifications. Shell sessions allow interactive keyboard input on mobile (SSH-like). Sub-session preview cards always show latest messages. Toast notifications navigate directly to the relevant session. Apple Watch support adds quick session monitoring, unread counts, and quick replies from the wrist. ### Multi-Agent Discussions & Audit diff --git a/landing/imcodes-watch0.png b/landing/imcodes-watch0.png new file mode 100644 index 0000000000000000000000000000000000000000..c8ae8eb7069e1954766f8b6ab69773a7ce801d71 GIT binary patch literal 34727 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 z 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 literal 0 HcmV?d00001 diff --git a/landing/imcodes-watch1.png b/landing/imcodes-watch1.png new file mode 100644 index 0000000000000000000000000000000000000000..17418906b5a0eff616ea43f955b0b6c9c1b64180 GIT binary patch literal 48093 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 BT>St5 literal 0 HcmV?d00001 diff --git a/landing/imcodes-watch2.png b/landing/imcodes-watch2.png new file mode 100644 index 0000000000000000000000000000000000000000..debefae7d4eaa354049c0d1a43691f32dd7b0fee GIT binary patch literal 55520 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 z zPDz<%;o)XC;!50HvI;U|d1>Y*m)IPEI!Fq!#Hib{M}&ArATWgqaAiW2o;J0cY8s^V zSu*s?3xz8zQHY-}m#&ph9T=O6y!YGt4(GMrWn3gU+;nw!zeZQytL{&2E@guvqu;MN zJwuV~Iv>Z%cdnkJHsi*w7(xTQ?>g56A8(dF-k%5X+=WD#Tzov=>)@(Ox&eqAzyIrK zdV5X+n%oXQfBmMb?A2r0TR)G01H89B#l1<`gbz1$j~$Yt+1Wy!CvgJ&z!|^G_bb2k z9@gm|f=F9n5nPHhEdj_VsheUccgm+A=QoY5TYW(A5Ze$sCJv`T$6XGvs6P?}ZREF* zwS69QvIJy+2ZzBbP`u*m@4M3?@#%T($85L+BEJ&B)#3XuYPzTVZ_ctW{z}EVHP{|~ z5P|eJLPePnn+y;R*a9QerZ@BrVGug5Fxx)q6}pQ0>~32tAqaot4U4)i7M{#gbS9CV z*m~HD08X3op&wq1fAHLN-&rM-mmoNL?<-+PHUX0a{pgbzdEbgpULkz4-fQEAK#X5k zq(hFS)rM6_OR)kP#UNU5zYR15B`ilWxi;;L{H&^w3a6S($l!ODCMR10raT!Krrs}R zjphJQC?+ohV0pfsfbeee=nj9=+?HZ3{4!+Wr9zkQT=ohRdYq+~?dsi_UUyZQ$h$jX zz9mm%ds)gL2K`QBBL99Nf3zQoEb5dITRyjp(|Jo}qqMK$eSA50U0nc$^3cdTirDBG zTIHAmu7(hD^{LCDW7UnfWQ=-@%Kf3op!7?T4|Q}VUFHaI>k`=1rl)dY`Wu;cLBDg4r}{>!P@rF##0Wc_}6 zIihO1pZCm&@*2nVD%e9o8X!n~cAm1lb2Iy~t2+Jt*)Csmp*Dl-ml9gO6#%f@jfwaR z*JQ5{7He~11HXVxj&g{P698!UGUxz-`7VY}#M>k-QV|{U%6vrjyB^(A^za?;j+pBq zjs+IS(z#jeZemg9DN`I8tC_HpTt)C3!o)vuZ~cin2Uk}g{;obbjb+%LXCg|vO*|?x zJ&IGG&NeiM-zmGz`)%%Kk86R!N^6MmG5(1q5te%f$$Z6FCZ=#*+TOYGbXWPD%^#aI z-zEKKlGQ9WqGm=YFcHU*?~yMDma7yMmP;VtmWXwMKcfQ-+Sn(&AYj$ zWZ*(2%`zS6@!Dh!7DiZeMXP8?S2}$EZL>!JxJN6?h5zm36-G6^}$9;^{Q=QDd zoR%e6=Q}xY0u(Z6m+LSL(J{K7@v717_YdWbx1K&$T>b_^Pvucwku=p2xcO4C!nVk1 zl%N~oPlk*iasg}P!sH+sbnLIfQlD_{Qf24^L&x#LgcrW`IR)*=Z?ubQE)J?bSzbao zRAY2z=D69i~o-5&f;pGgQ= z1%EnwyvvuWEJZ_@VSoLk|M9w%Ct&pC&-wO12Ox5r{IE(c_IEW)u>>0J3g-4UEg3Sy z?FD6Mb?or55ISk8qVTu)5Q}^`pwJnF5vlWOk*4pq{s^`I&2hrPOuDH5l!SztkP*a; zz>dI&;Zi8znTIBB81v0fHF05?WpfDQ<@^}thfTYR`A5ei8;++E* z1-S3m&IgZ${@^I0p=~=^fT3HT`qCMqJY#d#Kt;iTrILDl-gG(1eOgDqud> zGmK|4&|jt1s{FM=|NHQ<{P>X8%ZB)H>GY_VMC~zD$0fY^^-bJq82uFiaT8 zA<~X2Z{umisv=i>Z<+_LNC)(rW}wAokk6)Lu#K9F`QZ;m0mM5GPYh#X4o84a>i{PW z2?66iDzb?@fev(y**$A(g|c1*cF&4e?w)*3do6!|y0vJK>=WsRi^IGY6gUQ&{q}R5 z;%>$aR*b!@ujJg+++XuAux{V~#(_E+TX}1`EMPC{ykR}Bn9K1zt_Z}%5;%Rb08VaA z$dP98bHmD&*UkJYiiQz;VpxKIo-Pur1CXj?W)vN0y9LvGun{a?`YG!Z^^%GRRDW@3 zXzZZsQaPtKYheE4-OkaMqX)C^(#ZP1i0^(stkT-U(t61iab~|W4dKBsS6pVO_`2y? z3IL+b^Sf2j0H_;bYAM-6*$0RegR~zyBlvpXG0R+1De@|{3|*E1QztkApt3o~q~QY1 zR)`qSa@9=Cn|mb4zv+!I72G~mDOj)FxgV-gReKrzY()tsl-1Qn>fhG=gA6M3jTImC z5<_Y?{sKi_jpcyoQo?X9A!go)jg&YC;eRft7SJB^^2$4dMMVHMdi3WFxc}}SGl--J z#VJ^PI2AphS^1ZD`E(uh7%+(LqHhw^6LPLWu1Nl^LIw-EUPX-upVa&jk^DWE&-K;x z-ZNT?@2DRUf{u$)?>y^)$+`-!t(LtX@9FNQBZOfgT@DuyMJKt>5J>!j@>*GVP#Uo4 zc^CmtJQ~7y%yis>w>9ha7&sEJxE}(51Ns;ZZ(Sj#@eyopMwZ6fcrr>Fo1w(X>G}*B znErfPe2A5sg(LQng2%@vA8SsHqMJ*p_ChF$a<{InD5|k{nw-Z%r5{S+*B0^uoP)q= zWFc^%peu-LUHbq>NDgLXtkH@DWed7f!k4asOaR%JKv3rTn~l-XKoGvgHk$%rtEa(q zlm1n`zx=#j64>fnhmgoV*L#UK;e6KDH*YXkT=%;P#E*+shY!tqhGY}&uJp26UPP#J;=Q9qO%KC3` zoVsr)`Z`%XhBPyDRD#X-tFMey+^ZP%Xb^`NSVnVBNw&!oP#8bWaA~IzpaY@Qk8gCF zEBkWTk?m2sba;+Jn=hTK610^Cs+o}31!6084ONNFDa zOg-RQldn+XJ)vf$z(^wiZId8UMN$zto4+zN(HY?(-$?-$6Iq`-BgG4Z);gdmXarL&tUz1CjEEdhBVEe^8H=4GO4^Vta8C5}M>^zya)Yw+IOz8;c#~pNsQPRvE z75jmIisEMGoE5I9117l8Tp4w-i531y^sr}QldNcx7Cr!sPKHd>(+4y-q`^{_M_5*~ zym8uW@Pa$c_+Fh(F7lBkj4cbl1**LJvlJK5+isOWhIm@(Xmnt5O5_y^Q_|=1mv??C z1|I$u`7j)OeRVuqDHby z8fVT+@>D_~u?2QLN@Hsp zTqoh#QRPPlw5{fhwjb7*=gDpWK5{sV#FwN50}+Z4meVrw#z<++lQ<ZdV`>?u%>$z;r;KBNLVA z@DVK^Qm+0-Y+{Ti%$Kh68F=7CmCj@HE%rf7Qguo;n6^MA~H>Of`agQ6y-Lu6XmKkqEm2{Vs%0_$ExI@OE=M zK9`ps76JNyM)OgOgis|wpq6tCwmq0Rh&fpy{51!EhKLNS=BRvhDBMyBB2T3iE8WR$ zXSU75znG9{V)8qk5APUzYT=d1Jx%Zc)<+D;-*9;NdSrAWT4+1=rln@#H=58y*#uxP ze*w0ut+wJ>$RzQ5LM?PckKfhR6j2|zrqjI{4NXXz1_#uXO3^D|--0mC2REKIi&#}u zyAo;zkPy3=S@?qUkVy6T7!rv{l~RnEYj`cK8W9=|(TaYT&88b7BD0BI^lnXTr5E22 zZJ;~gHnW$F+>NXtfo>i5^;j^@O@Ztk7V{4&lX5!YXzA2 z!~RwFrE7GA_Zv&*J}I%n&xU-g|9Hof>23-izsO_S{5HrQjY;~3{1TLJcg}0)Ln=(! zL%}lo)qjseYGN#%B8xzo;y?NVk2g5q^?5a0g2ta)8|s)7wOu4Cgbch%#23;tiY=0a zD#(ktG&%i!9e+B?85+{aN)}oVza~+n6!wXBf-73RN|X!JR&@ep`>5PhY}Z6Wm8*Xv zaE%?E`$D)##R>)a;At=A0$&#FQ&M6#tZ57ESrC#77tm#zk~l~;OOyL6v_FL?4nPU` zidbH<5dO2(3e(Qyk3~OiuK1*YG3Gja$~{oPtp1E&o6SEG>MWlxmWB^954R^R>AT#O zt4VS1Ycrx)`szkm^Uk)tcLL+w?*gSUz23w3wSV_1SmXm5c*Q~ihanDDt`-8b6~*1q z0D@c#IrQpGRM~c@;G3Zk7HeRn?TNR1200!glnO*)*^x2vONnM2?+X%!-D?$laov=G zLHHvYpAW9OPs;V-^2_R65n9UTEdh0?BGzOL_ZOys6--f-IsUOhur{xEH+kwYc7hV~ zR%SorHV@*&{D<|_%DpRBF4w;mqSw1^!q=z}atw1weF)OE@08TAP5cywP_K~F$miVo zx3L$q;bp5 z1!+sH6+lb}-bp(&%aUSOfJpaKuW>>t&ESJg$qX4_O6||H-o(AKSrmAYDbtxr%E)Pq z1s4Jim4Pd8x{}*j|5Jnw9<=!)vtQrG?aBKE#H72K4*dOviIMSOPr7CHgo?=W@=(I{ z*N@K!E4SU3>#?YXw%_q$G9lyvYy(h4fkHDj_)^Qx2ms=+Tn21>$`8VDyWVo!4lq!l zu!XkeBi~7~4h(ypTt|`Y{##-t;Wsu$OW#2S<4am(1nZ~+&2&k}n|F_Uq;3s#zb0lV zVl&~01>e!wL4ucXQlvxLK|)HzSW29r4S6k1!mkeS#94sb+L}3-AS#$==ES8fi08X2 z2iLEnK}2pAdW)hzbg6OJt`3T6W%zZC?Ro?pnM&$I@==TFMB;UCyjif%XeV)yf0#Gd z-GEq-vW`k&LJ4>BI8)GS7%y;OQ&^Es7A+RSh!#q8GD)4wI@to%V3&qV=QRT|;VCku z*Z-Wal-9njIY^)pjl#pNItSCpr16FVm*x9b|4@28MHY$v!q<+VV$YawoRQrfiYE|~ zPK3T8B}pxgI72r5iE%%^91!;7@U|K-tUQs%R53^OtA?3)*%*@_RGxtP&&ogSmrG;9 zkqJFBpniaK+DU4Y1Rc`n@pd)gIY@*q@%Jyu1m`Tp^NC#AhO>fzu^*vv&$-*pg)_X;eQ5bc+EUi*so}At?Y*H2sm452q!Vlnx4hFgI%x+=_#J|f~!ot^Rqx} z3W$_F2sDz;A>vW`Y8uB?5`^8HOsVob*WR2hb69P@sN;&glb}!;%QZ}p4^Qq8mEzgJ zI&)sALae$4)^SI}5w0k9uovWtUtijuE(Gac`_c*Y^Jd%Rn^0 zXT5fXfV?RwttlYq5ds(HYNEk`u?{1*!i0G}t_?aA=OP*e#t{>=Xbs?k%=kvkj1+;{ z=`p6;!i|(jAqk8jW-v&i>W^qPMZfwZF3pbMZ8&~&H?pa<|* zu@9URF@cOoHGL->DL$8)5_+JTY6@+mDX0!N{B%tzof~TBHlZrug@T*W-wk1XM;I5A zd@x^}$Ej6P>4O+QfZ)53a7Y{-g0!C#I`k3?7ix&r5C#aW44W9i7~Mjta|MXL3Lzf^ z)12%;y-)zrb3h2uN47?f002M$NklFe8~M&%-xG!r@3ps*ivC zmn%SU^S1B(-tNVIN{|2gB1Qp)_PqSiX1xk9b&5=H6{CfcdABe=aKs>A5|)6);ZCf~ zVc?3O^Y82W0s%*ya4Wg9;Kfolz*`|=5LCocgLw)1nTb>QB`^gGcx(8TbTn#EkT6S} z6gm}yp9m@gFT*u>f#mZFpkPv=*}*>*pOBX>Ow*Hc8~MYXh$y4EQ5$sVM*F~{VBf?w zlJXS&#VP|}fx_HKctQhIxoU0-H%n~_H-ZqPhG-KKxGuDRL5E45anS*U^@#I*oxmsK zSth5kJNA)Kw@YyqM#_2pM^npm*;E6?)(DF8jkL^ESBt^jd)Xb{65O3;A-ThVoolWn;gdT`x;e5Q!6Q`VVSw^ zx>(~R!A{xE^c2*p03P|nEn?>gsDZ>HrAX$KDLC_*19gL1ogZ1&Ru0l%GKYqW6oR2R zdQU!0j&*6Q9*W{=igD0D3>bmRP^}(*LQt0yQMbo*uxbUW0z(5bz*C2Us__baF=-Ne zw6u>ijEly;sCvYCzY$k6S@<{sgth{Ap*Shes6h;fef~TffItmo4e|=z29#!;+^k& z7vNIO2i@r7It?!Lp+Sx`+3nr=*P&40&&wADB@qk|8#iqM9k4PaQQp)rk$N zuHL56tHL#*8A&IKY0=DZI*3C+Du@TXBA`%s(S^X@tVlF_qCR^ZsXIUgM$rcA+;#B>4ZcD@1PQvQmQl1YpNh;E6Lj0@Qp1g3)Yb>jdC=?gtj z7#$9((6%=_cJAUVlP@%XOneF>ieOg>@2Lzo%N0Kmx&#C70v{0rk!;pFaPY{cE!&VE zVL|MP9P?U4j>HUc3Kq*0PC-mBpI-Wam>Sc(5*Vbtml?8uf>tEwZ64pJWqK!6eF3KM>%UOO*FgEIB$Q0C%lroh&&#l*l#+4Cuk2@Ne| z47@V4Q6gr{+J8XPoUI1&SOH>`g;K2V((yKnmp%~yLhVS?vtrPnKWE89pu=dOP=@gq z5jue{V!UnJc8)yyLi6_{Kl-C!L?`h1r3`Bdx(-0Yz|WWn=-VKH5v*W>W)8?>lrUco zLxVWA2~C1QEhF%y_mMtcjP#+BNHHlWP=Me}uOw1*3PplN0~v^SK?m)LCjUxmTUJKK z_iqrnq)Jeg3XxDEaA(N&3B{*#$_P_LMo~S&OvrP(TWHV@D`8ejyJ#Cb(DK>%szSDs zXf`?|M&vq(D$k=zyCZ9wxbcfJQXWG9bJnDTPCQ^wIKxif9V+9C6 zq5ch8BKSKvaut)GF?GBE;;WhF3=N{UO)Hf#w>wgbiGiWPv0R<+uv!o;G>jTq5*RO- z!eE-Sfru}>@5g=&zs3+o^u&Gu7tZig`OKNi%3_R*V<%3r))R)V;##Gvh*mPIq)UOH zDT*~^pR<)dQ#L}IxkXH*PkFE~WX_}v(*Xbk3vCi09u*NrO;BK>S{WTc?AfDvA5K4x+3`m=G14P$ zfEZLCKnwiGYuApj{0}W}8~`HLK^P!pVX%*rDU9$wgq~JWnTp}0`C2>Sfrtar19}<})ou{NzvmBM`QxNqB!7y zxb61S^nDrhn$c`h4)}oxJ?im(C`yr`@kdKl3s(xi@hZRk&=(AvsYHHe>q2nALG%7JK+)3S&dK-jUby2oT|= z3>O3or2q&mgSethVGIL=+7ztCHNqhaDf2_~QS>RyQ8l=)&mfn+jy~uFfR>phPLRZr%3!@&`}%0HW1yq=SU5kw_tn!=cw)u5UwpwpH5>rAfOw z)=wWNOr%s-?9K`fzgP+yPEcdiN=5Zx$teCcbj;BJqJai2IqQW{kRmX`O2nbVM{Hv3 z+qYl7-sxH>RRIDI&yeJI5jm~iMRa#~hFJd&W3wphe4zvRGK=A9jPOw=K%hSW5XD0& z`=Y21>Khsq?*o$p_)dY_st8owLFf>O&`p94tc)m&9jcEL!*66{{crrnZ+xNoV=q0M zGAf90Qy;kGvwGP@Is8wQTm~>W2JRK~^ z>O+#`VLxQsevN<$(a_7YBpU>XIvJ66M_Kw2Ga7(zp;NeH#Uyd9!QxU-C{S*w`jne+ zXSi`{%2tfCN8rPRv)bATNnMYWt|?7DMgp5`6DPr7jCr`LxEa8RLg=JxZMEJniyvWhz<{i?wET<<-xwdCOXdmktzg}7*G4^&>$*6 zXo9mt2krG1Y)_m7Wa2x;{$ZKE1ULlM0AX}6G(dV;OzG8@{RPzi&=%McYba*MwDz=&Qo9_^J*!K^3;BTzQG^f#9WKfSA4p$ zT3O}0xyYgw(Lv!1ssuV!&QzTd42l;p~VrglS(VBy*ndzSj1L~*h!^b+p#;y z8@B^Q%5qG0-TvyYezJjxFTCi*FTrQ21=P-PzV>JWJzAhu)>c&-1QS(>C;+i#+m7QW zP8~UVoZiw}33hYpoDweqD4*f)|@85wabEs#u+280yoXkR4TU zN`$#la6<2}OGP~r`M6cv#_Za;taclWX^2tXbIJxQgNZ{<(mW$TgaJF7CF%~LQ}k4c zPLHsaK`U|UNGwj5iP27TJ~n{Bz5vU-9Eo*I7Xl#4Au%#8(i>ECLOSN!>u?aTglpx> z)l4AwG>8BQ1Q>K+5kJXDfH%c^z*+c3AFzp#nOlrK9(jXSyUz-Y_{1lErDDWOU;45H z8t>Q4SEP&>CZtUiRboJo04%U7Ieq)?XWz$iRJ1b4fCgZKJ`v9oFrTFoifnn@CcT4xD1 zgw`FHJ6#Jgn;O+>>PGFL%mYEByRo*ilm!{hBF?OWQbIW}0l!HbDt?W`>xwUh<}9u> zc-BQvn`ZaVmY4?7;3W>)3d1%gJIg#pV`3ya$jMbg+8sTNz~bE1Pz5CjnzIoas(>40n`Spggk6wkf_en7c6T@vk>n=Q zW)`(ld=FKvq=qWJkjXNolGO#~Q>Id*I3r^j2LrWA#2`SlOZ8ekqF5ZAt>HyeVP!moQ z1my~+ioJvGK)~n3?B>1qJqN5s6UJS%YSrr1Yj8v@0ai2x6J*2sx$d|<`jG)j`neSK z0uAtz7+Q8W+qi95$}gQ~&osQKozC9t4Ga-7aXCUFTp=XT04xY^f%Pd+)oiN_Bg4>eTH?Qf#k~RFmh-S?FSqJo3^uCHJp- z)vGpd*}|@w8c&N+L{|~*<5rQ@Ab2F&ykD~*9SKMhW2s(rf&vG^1vO+O;OZMPbc67O z1T-lUQB{fBBj7b)t^ROlKuErrtwhcVvJg{R2^t8s&66a-lkh@4JN-slgRjxRTIj{X zh*pV^t`v$x3lPG`L0e-~fS~b3m5TG|!bqdPQBh#5NYb;tcEg5Ed-m=}j~EB_VHAMy z6h=BAieu6~p|JWioYFlsJBAPed8<|i+P*aiZ4!<>#a0{&I_Ly+0*V|MAyop@2%Q4F zsKN070ib{}G5{_@mZE(mM&OdbA5jerp@UAQX1&I#+fSc9eGd~E{KV2($2lJBH-J#& z3E47v;^b8ZSQs6ag6Cj7b7ZK&@(VDI5zjtLIv9xsR!Hvv$`Fy_p<&tVh^)u4xA;xs zTnw;@W`PD?kD)0}Qkj#dEy)&(=CTC@owB)f)&}SC=*&9;H>gWwE2$2_LnNStWIS>y zBzxe22dYR9-|&>gG#Xu_z#)`NmcHmkFCI=w%xhlr8otC;AJJ1#1P~ips4{h-`fdlR z24S!S0Z}InECC0*7LW(=dN=4-vcMOT5f43F391FOMRiC_{wPy4JL(4f7Tdj~$H{gG z4+xSE5u{Wp@gi65)hPx3pp!<+R*F(cN|SL_${-1XMUM`ym_-aV)etfdKnyb>Frq3E z!s{V`C>Q}!FO3ifCFL2@)axM3k!NN&q@m~MttTNCZTI79WtywjI7^u@bJ+GA9^0@gQ)@(HgNdP z)~#R!oA=hNS<7|p+I4HztRZKJrFYAyRjh_E88lMybvyPx^G({tOQZxTtaKH~7H)%S zB)2mp8*mAjVI<9g!GZ!~< z>d5=?og1=^Dy)TXT6B2c^B&%|Z95tpXC+}cR5|BE+hpjvljjRw@U`{P*L~d!_wCbZ#Hb$2tBkswR0mw39W%R@egc*BI-^X(n>G}@z4fU{NwYeTp5|6AJjl% zN#=&4npBR2<_(g$HE3JllFR^Q^aQ#<7Dut*uo{pz_>FSm3-VVH+L4LbyN04c85&6K zJZD~T>1yi5BS=z+rsYa03}B>`U{hF}LJGSvM1fX-yf7k_h>-kIm59z65dhI)M7*0A z5fd4sYY=CtLX=?|J)n9hmHd{>FHN@W_rSBSUJL46qjflMM}M8YCwpw&8EPr)oA z5LpfuNYRi$CXNKSEMEyKpth1Dl`bMjJSCYzDYKBKl`5h@4WMF;K@T7`E1_2 z1;-oqw&ZZ#2s1J3M)+G#pg1@lwgV$%#1;pk42RqzJ(p3JWRM5V+~^uNbQ|x|XN)A2 zMM2a>nNx(Mo^P*h5Gt)%OFKX?)G}bwEKss-`wl)TgJJ_Eq=7=dH$^-r^z)Or8c&Q} zXcR$!7}{_X6V6+=@d!AmBK`d5KcAv$G`Jjb1(K@3Km72+&Xy~my{oUh>}4;DVN-`q zfd%Aw&pr3nr`(9DO`FM<9;I~ZOGO|+^1o`efx{yNAV|Eb9SzHk@A*wi+KRfHPsqw; zaV6)3!t9X^v@HcOs-xMV|Ep6X&>bl1$SqJs8$y8EnSYE4n>N#!+{13LpBgICY}~kM z>$dG&=?c?BYMPry;B`=j>VOW)kiMgTSFWNp&`IggiV;=qF|W~0YV?(e z79f1&hn!gm{n_~`r941hoLaDN)v7g5d)m{+9U$bS41l=uDjgxE6%Yc5nChFvM6ss& zVpCuM#8f&AbVn0IjIBh_pu+6%M9?uX5CY7wDG86kUjVU6VDn4p#~zhZriqN*Dk~l zF5#z;i|>4_UL)37H^Q)k%8FWB*^xR1JIb=)DX&-_Kt1XHs@_r)Bc_jvgNbAX$CEOP zSPovS0VH5wu1E;PD7O_Wk!sd5qt^f^niX$L{%^5wJ}e2*?5)?dB? zXrOH=nieA^kO#A$IB~MdGlv(Ecw}Tl3iB=Vq32!>RK4%Md+xc1QdHFHH3ttKs;}T~ zpp}4i8U!pLPe6w$q?*7O#3KlxbP`j0)e8t)H$r~Y$iPPhDGqW){|a~`8rc)$I+sOX zNR{Y>4)6qX|s=;3wrVzdfyp++k?-2c>n%`yeo0ip9B(d+O=ypJVDM-21oFe(FU#}k{HYr z)FPA!^`iao;Rd5p9$Vll$dE9^+AWw0oFW8B$rvUXxxsnJ4ERC*$OA<%c2WA4t=o7V zz9*0XIo!2-Hynw?3Q75rTFA!EUAq|G;dn^mb!q|20vx17u*sI!DG14=Is}^QuDkEH zFu(S-uT@z)1ThlkIO7w7Nl&v2qhriRdh08^2r!X`0C~^}0f@={_jeu*pp94vCI{m( zJxjR|mQ?Y9KZ)2PN}*^*YzmT=7c)?lj&KrB%YXq;Wym%}QWoV>)5u^kEdy}Sj1&Rr zqeQ@I;dJzoyz&rZr;tMeL@)+T2P`>5UZ+X*@s7nyAOmy&0eQ;!a#$k#|!~SXaU-X{9!Et1Xf1c8Uq+%7jpGe4wxAEBJ_K?6u1^h*V7aFhg{HFm!`zzGwvdr81$JnJ)|8?p5Cp7Ut&aj zzBN!jZ3IC>paa~>4T8!jR6^Ppu-)3VSd6mUNduQBM#K&5CHtbN4=p+%-V8`bj-I&x zf#)7NbkrP=&?3FiCf45}fMC!A(O_H#On90Mk!aWvI?)2?OMHzjKwx(O2XHNVDWsae zsi|FbG4Sd`65u0wnz`{IQ9*t}11O2)hcNGfQ^~<%PwfN`yZ1m3btIBDBoc*U$IhKF zI^vAX@H!9i7+J%0SS6L1A|h!*{8)lvdo`ODTq}^y_cnr}3BNW2BDc55hs7uRG z9F;=&5q0R^yLa!tefuehcBY{qlE&eHB4RZ#_ns@hku$?2DM)On~r`p)fIG+Rp$18fvBv!LYP5dLu1B!<<YrM;bwX| zgj|k2#(#wX2zaQVgPcqR`r81(4Nnaaj6V+aH<^*4nTeuZ9MC}Npu^!K$M3uUA+87~ zPYKd{`K(+R#_$a?2|JPxgaI4`;0B2yPz1T9(VK@gPgf;p%p@OZW1!q^hU7tuJ^0{*7G`E8D2sS+JFsjq7JcStWRCve20FEu+ zvzHT`FrD}kFZ7du0Ez(_9NaPt5R}4Ov@L8VcnBOPGt4%w;FOqW{(|&GbQpp6aTq4T z`%us!^o~&hqAsQkfaqgHVnY3I>QodZRB0G{-~NM;Hy*Bsia?j-pBGA{lajfUbU+NK z5A34p03v5G7-<=A=|Thm$$_~gx(oSywmbsBgfT*zXTURJ30Jw>7y#)NcqIWM(7^yf zuhYBAu$UOUMG^EM`ID77iBc*$kTV=|2>3A(b&4 zdd#L^1XXiI0Eobcy*#4tHG*kFp#TD*VQAw%bP$Q60HU}F1rYc?_+<9RO>jPWB9jkR zfOzqXu@@A-Z+|U|u0a?mj_N~R)OTyuAYS#VS3!&bV$tG&E$KD1QV$?7XLj?=B*oJg z5N4_nB!*lFh{ynlk@b{9OVhVxNDI&oWKM^MzOzRF5iLU%1P}DcnzbZ=O$-q96xF8< zfg89B$B+Sno}e!nlW+}?18t&YVYUFBREqwkH4Yv+3{pT6J;ksDiX8wn4)Q(vEfnph zra0P!rhowS5ALC#;z&$}L~;!v({@3Iy*YFETB<-nszf`lQIVp5lOD>jO{$3j{j!zP zfGtWyVuT!)kf#h?ucZN~;Tl~Ty%GOnhot1RNO{ zky99n5vUL0q@-Oe54;%Kvb0b@z4c1sO2@arh6{9uqsKsp<;bc~DNKFt00OQ+lJLRo zXk{m48^(ak31Y|i0!5e@TK+U`nwBO8D5~ZIL4q*|4<_>xT}aWeZS^yBnJ9< zokBHS?A}AyfacIoaomF%WJ?dy0x&8)2=ma-@PK@lp4Vt#qSGb{Mhv2Z7nqfmbp{A8 zm$IP&7HHk47U0&uY4ACf!ta1(L62WH-ssTT7-$dy5SSR3T?Rme1A_UBK!@-?$U|uj zLfc~|$3iK61OXAk=THA3D#!qEj11u8p}A$`hY2T)sHy}TG(4VYv=mIxC2#{Ghq3@` z)*wfwrYcs@Yk~#_A}_C=A2XUdx-#c1be{d5{U=Y|2|AoOc{^FrvW)OB0V2vE#=Ec` z0nX5PwR<=5^g8`*6#y~>5TVc#0~}N*Wdg)aGpQhK4XYu02mmCRm4N_&46<=W5(D3p zj8b4b^h$`q` zwMsY;=E=j)PbUS*AhO1jC)6Ti9aS;?NhGaJ^HO~(%Tu_*(nu50bm$<6A06R(fq)^Q zdw7L6=@Ik=t~3J4lroGy7>t3)0ad~d2pEHE(taA2Vvz{_0;bTOhmRcLN<;BFSy5lU z`O1=WsKQr4yP?Ahh(|U+Bw-{{(gmcahv_{4CE_Eog@3>MO< z5GWAZ&6xmkwRU!+J1A%;tkFRxMgfRA(@9mSJje-l^2t6xpLfNtaFLx&DmfVlU*`=AN}s1$T8}F|LP6*eG&}kfO#wha68XSa;1rN?^5ktWC!L`Fg6<6f z?l$lR0;n3f!HpEhQz%CV0VALn5W&4dYVN5xX>hw!cj#vsRRTIUG!!cQ6q?e`{{iDcH3UlVQMt zLhRro9z_6#qdz>hRA?aQO`EZ(_a8rT`?K$P;P}Z?I3O5F;12>QK!C$wP)15&L1-}y z1u{8z?n1Q46NrJ)m_S0A(lCL>$v7#Kfs{dyc;tad z%La`DzgqR+9OBdMg5LD z?nFW`Z4d(_wzV=y^Qu?B`l07O_oXk*y<2sfgGb0Jqbv9*YUAW_&;(5#o{lkKIYfFv zAy28AP?G5YRbLKEnhSh{W<~|{O&Xti(Hi=!_J&QQr;F7iv3HBw0X;MVpi`Ev*(HQ5 zc_Z9RT8!LK1ZZTc0}=s86eO>slozc5;dO)=NW}qh+ij<4B|Qtj4>I3DwmnMWV+M4H z7tn;20j?3$R@;ScXi4-PeGD&Qk-(4?0kteEwL)RA$g7~CMTamkWGlsdtygy3coWTK z<&>2!jC1S^K+R;u{@oZbCGj;3sz&`!o5gG!}VnoFSZcrBBdxQ!jg7)VIjS0d|oa~lhw&|b$f)}7y*BDBqfe{ACvm_(B zG%xYg%YaMu)g7e@v;g_51t=(1Nsu0}o}rzcO^?J*7S=|}%W$K74dfi-gj#@RM@zLr z$2IUe`3+2g9`XkZR3mTyi)}kJ4%C`vAWSaGW5)q3?r9|y78-%~fO7Z&stnl>4BRui z017CHfRxPD@P$zk_Y`&1hn0%d1Pm!Uakyav9 zzUHjMbF{ZtogMwnJ*`P20ucCJa2zlObI%+$ctI1f40q)!g;fOY$XLgkgLNYtffX%U zQGXpcbOcM{&eM0_i|zne(7q}qj!tkX;?5X<%)W3cz2XG)s7D@A6+5Q+DMv#tmyDAU za&xh_X_cc>bk<0y60zo5oS~iGF34wrbfs7UrbMxVbd%XII>JJLBz}sd;1!d>)!YNR zvfIN%a)U^yM$$qZX}wyqrwWF-3x~mx=xfrh_w9%21s}0Rg2?AQ_~7ea_qr!jkf1-c$7m8F8JY3UJID1+1lf6fbMkoLt$p(}^Vgj$E`=f0p$pe~MZIk|K#H|#Yf z9$-bWMI8VmP)U$s8j47P0^cZi3&d7&;12PYakN#oDx8O766{mrIk9I~zEUmv=6hqY z!4$5aP7ZVgOiNh7$cKAgkbx7;LBm4?JZns;c=Hj8AmD>Sh7$?)-o@$-)ExTe{GRVH zEdP%h(+7yBUUu0tSOp>b!rljYC9k#Okj90NNQhGsuH_IhKDZdi^%x^)ugc}+CS}h* z;RafK*$TXC_=gT6_Dn$R+_e{702FZGe&_DJJlcQY@S(%Uj~ze7u8KSEd^X2Yql17l zFkfaa30DwT*+32HLcmhAGC?ky4mc1f(7_s!v>mG#)a%;ot?k}5pd|%HXs3`XNaiXc zN`YNOOu?Ft5({}5F+zUIaS6O$B&2&+-|Q`+tn%(0rO~hn904ovB`OJAC3|7dUYy== zd}Vj+CVpbjF+joGNorY!XrPg}CR%a0mX-h`FpQJP15~N4f}UurxbHf*h;fzYN-${# z`y$7Q#FS{Rnz@SbyXui%a2nd2gD>4LsncoO0+3C2RC6OC8(+CqGr@5nGTI6_h<<_U zgmVJ*0eyjL5}%MA9>joYz;`y-fj|^1#kf;6$Uu4&JL$bFTM0prS$?N2!N-(4Qpl+Tcg@~(4;tNBJLeWqZMXVMR3lKGcH{j&&vmJ&b1 zxnLv0rzAS(ycY`=bO8Gdf613YgR-jBCYKlHuEmu`FpiXgu~#oKS*cx+SIF@2Sh8}( zlYX*Q&K}HV&0%i9?mz?H76v+gSDQ-)OUk?$+Qs?C9c0=%3j4(LTP$h2A&2fph6|l- zdfi78^-#maH?=N(8tOpFr$%y9@{H08I`q}Lz=*C*P)1N~QiTbPGHl)(XW%-;xd2Qc z|Fn`2q3C^$>L+~!<&-q?T+G*5>Oe^-U#TIgE2#p!SI_|~n_)6SD;Fs*jHwcz_^1K` zg<{U=%NWdh0`vu@4lR9WFRd3KWgj49VgL|!K*+cdKtyd57ix3phSmuwN`R<(xLDBb zh)@OgN5{ud5HX>{OOw~rBK&&21~@G4^|WJ-HofCV$s{14W*e_`rPQ}N3!)O!paU@B zs!2am2#cdoTj(?lwWLN}M7iam46v5ZM1+zaDN0h^4(-)#(#EI?4K~Fn4RbSE+FpoJ zF0CFL2+7T*xUPAVY$H^`sR3d{z-Z)|u=8k|FEuIx}E^DSDnG--LI^z}ft zi3^F{z3zzCR)c4o3opWvS&SE2NrE4qLT;jQtS*HHSCC8SDSad`Mf!!DXuZTLB5D*w zVqA;)LkbE;w9*lHA%K|N0mQ^f2p1y8ilZkpKwLGURUcx)g4z~DFfJrCAVroRbueA! zR_*|za!+L%HE!yP+3Ph;kGJ|9({V;3LXm3oO2eiusLeA=tk4jp*9^Il@HbRBMhQTN z79gS&<=^9YYTe0Fls*U$0hgm*%){xY4WTYt^uX=T2HV6=URDd#@LWtReiHV!jK^a zsc8=0cbY|F1O_|f?v+jry1pOe%ciIEQ6tZx>eqKWuC16d)=iHKVXO`aG80}bX?)WwMcGPVRM|5Jdr})O z=AgA7NYQX!l|$dO*g;I8swJRse71RMb`O#sC)NJd4HTl{p|!h~T66&6vQ&^N+g5Wh zO*B+(pRsNR+Oz%~PCwA#H9Tna4in>Iy!gww&$s6#q zR4C~ZCpWfeHQIduM{!Ts&=5de1whEeK-`|JJ_t^l%O%zFJ9Lf)TA?+_X;wOeMvu`l z2C?w2r%zb3L7FZuLs@8ay-sSlKl@b@()3~`i2iGtqi{y>aebv_=z;sf-;p72wOp0_ zltq`6=ChLCRHc~7)*UNYaX{7gDgax&Rc=FcbNbKGVWf>Cvv(Vp(4K3Dd$x={BnF@IjlhRe2vC4B#(%MEIx^G{p z`EYYK@ik5R;^2MhR@E!rE2>}x+?q+;z+FA2GXK={P2$3bRTjp$DUc!Yk+~6u28ubO z?~~F8!8|8klhhz4T#bD}mH2j>EDPxl*68}k{r|UjA7IuLRo=iC5KvcfMMRPOk|l|W zARt)5y*l%rXR z6l48$tlLc(rb@+#y4UHu-4Chg3MDiYPqFC7#Vu7eD9o90;&^qX%7w>2{DV@Ia31nxQJpE^n=JZihX)nl7;YNewC-l^@z8-pfM*~ZhjxZ4i|I%vc;6kY$G^G4?cK)zs#=iwNjaNrK zYSlZaP5QUgy^c$zpchq)l|Olc9IT&vKVr{4_ugaAy*AloQz%ISV8Vul@Lqtw9o#Hd z;{$tx{|%d+3V>c|o=sC;H`sH}y}WBAAQpKNb)#}r@9+L@)B&Qf zAxeNK5Mmr4##i`Cbm$1Kf(~XD#jg8uSMLU1SoH3ogIEqb{P5j&-@`V3J5|FgZpA2C z4x}Qmd;tLQ#wHKOOeN2wx~|0D`b{t|+#c`IoN%6jSjsUDQ>nv9muq(e`rt zorXZM6v%>B1g>ac_;#v@bxo`#Z06r|)6Kmxx#wPcdr#2|BcQ>yx%Iq<`Vx`vH?v6( zYLr`d18;HL-x#X}!yRI`ddEv+iQ+EpWtgzqN`Tng`&ut~$xA^t)CgV)!Y|YDXCa?b zGGmZ2h9j}qN=s$N44D@QTRei&lqg4w&ZJ{Rp`ie;F(WiFCAxuNoRZ>Qf-K`18WG1Z zB5b%^CU_#4=OsWC=-^WVL_eeXoaDu2fQSGP&tyTAu7`2kp%6_+(8V;hG)IGFtKaCF zHuG(^*~`7&bNJy$ielzXS+B%V34PQKzcS2D5p2gm8q(Aw^xd+Lb`+!R%H#bwT+%7W zdSo$n6;p}Q3ZT7|x#+~>?=N+Nh{o!Y#45ElhAKh{te_%K`2s&qDvaSaT=I?sGhw{s z;+D{s0s)BvAbOpY5#cKV8UTcCeBMkGSpaT&WylMHUJy`7QEUmFW%1s0!KP9QSPc@MEt`)EExe}p@kN1CqOLuEWXL|9fUY5 zE72j?_5mQu0bF;{jf#G`;l}#CGZc8w7!-o{nK5blO>v~VtTR;@U$R-Gr z9_-K+^JGJAP&_@j+~5joiinj|%bWJa3$_9@%yS%GIdDZ&-!NCaj3iPu8>M)m*n4tC z;pK64_S++>QBhv4L-d-RcY*Ckb_?|gHToO$867{~|K&ZA-^*ZLG%j$h(4PVqGy(f+ zq30N5$!mf#<+rKc?LeVGjZ&%H$o1g8Nne*hBqL(O4L1@JQIw}+jy?9!!w&aqs_INe z%sv#a?Ub2QQ`uv!;KXrAM1e0I#qPYpSy&>t)ihV-!HnwMTp&{!7)EStV?h82^NTpSN^FO5^P#hBv9j)`M;aR$ z4yT@W+PUYRcg7iK9&yBx0{Fc2r5iaNPEXan3~R4=#jAGNbvL%R$+@?(w%Ee?F-2IX zVv4>>(YYz9*I${(MGT)Z*b$}Ldh2cV*N)}ic_F9R21_OMT`wtZBleD$y2{tQ_TFb- zQG?v8aOSZK-Cs7Q5GLcMf@+Itay#~ojbtG)N$XV=|!ce`;I zP*JUr4gd1cYVYNWeIl^H9((My@4oxHxS z+r47vop*WN>vn$m%N=zkJdap)#Z}>zw4I+)OO+4Nym#aPA#A(q@*aEcx!->Ks{*F; z6JcHz1)7u~1@ah!E@>T3@Z*W7PK(@2TuclY0kX$2qMQScDl|m=N|&X2ru(&nI;&vS zGRJL}fDxq;!8}g@qN99sGH+;FX*WRF5Xv{%@yb-up?s0CGyg9ve7%r5>9T^0yy;D6 zUwGk#XPLL z%dq<%d(s*DSxlJANwUAt!KiLotKKc!ZAASVyoxUDk45e}gaQ4DhTW!7j?t2_`&>@E&df1_d9v-Tu+Yq4`FpIbe zYltQQUz87P_SuIA_JD&AIYdQA9`*Xe4m(`9H}k2&*HA>k*P6A(5l|gRjCXr6&(_#} z`yCvmOFoxea>;q;oqxJ%}_e?j&LdOizWeQm=K~Ks*t2G6n2AjEM-$(u@qtiope70MSM0s*Y>SDcq9>9qb%OI&jj- zCmYE*(pl{+TV0=aIX2qtLkBga(+$dY;)y5G+gHAFd!150HsUFS2A+1>>1UpKmcA<= zbTIlc_)CvK#~E47lUH5^@VI*5K?j|D$|-7uKE;dTd+kj#&n&{LoqNIwCsKF@h3-zI zePvWtU-a#z8!p`~B^}b;(k0ypNO#wzyQD)(N*d{Ily0TFk?wv+fA9as`}oFqpT%?c z*?a93bIr5n0-NK-Pzi*NO%j`)*cBqf3uRd>wH_S!HM=jK7pt5rq#E;S=#RO7>xO$f zUs9MeG~B%+UQHQgvBs4OW4gQoJiq(Hf#uK9Cw3l_sycJg6c*`7=l_`nkj)e^qa^a> zT1=RTtXJA<3y?JM{Nv;xcv$*1aK*lD!CE3VM z>1GN+y({V@PnOpoUBKV6zql_Jok4IgZ=*liYzF|ZoE`827n0ZUMB#JVQQdpKRV}_A zw`9UHB3}!59{!B=kbSNsQ6=G>*=Uy5yAW*UAliY7n&oXZey5QS`4DvKXPzo;kH(}? zEa@08OKt2>PE%BhO)P1GoGkQRm(Q#X6nKW78_*Ova1_YZALqkxXfvQlW3WI4`Zq_Q zkP~tCc|^RMt1@+Ep)sSV9|%3(Y~Kk9(2Pp5y@@K#WK?ildn84kV>mx0vLK4Z%+*Jr zDKlShxl9Pe_eRvnx+pwnbkc}Q8d+=zK;#5Y?sUJB1P{!@@6&4{vB@H78M>uppz9ku zP^%+t?S7Ff1Hd);|4%qT<@LQQwCwz5&8-oSiw2?l0oHhx@i^1aaSUl8wh}Lrvt8|grasIpQr{@Dt7gZ(C@rfT zw|%s}>p@YPf$urZAL_EB^0VKa_IrKkBGa-;$6^pu^IxJn>1QzHpq_OE5|S#7(ol>X$I~?G-;`q znToSND?luutM4RTw&#F`MX+r?T8Du^T!Sh>-xor@g#RH>!QQ@<06 zB2NM~Lfl}lQjV_$CdR7B#3=n7o=dY<*z%7#M%^(3nSfyW@SsrR32^gsRR4PYY4Q&D z$72r=So*~*USK?L%n@;Br57sEw+{zqScMKGM&o*=LY=}m+es4Jf*aFEz!~<4!UQyG zhXH6BhaJ@4xYYTXLuJdrV}%q(`XZ?5U9N*6&!TOnJ33-R|kRAHzGYqyP!NF(dui}2ul}q(9dG+pK$LGd(P|$v?!=5E#^2+3Gwmu zJuyST5LD!5Sl;dsctiL59h@adHLeBJ6*d`rsDcaXV|PR{^4_Nd$54GqzZ^5Db>IB!tF{rj)%0WCiq@w$rFB5&o zouv)sA)d&PeFc^%w0mrityBzFXjtl`8zN<7H@}r}8N@XIi=jUs4Td4R@;w9{(q@?x z^a;!{Zqjs@j&M@+-ydxSqO)R^uUqm5rqRA}ry+>2u&O=!X%4rWl zL7Pt4rQ_4^H0))>Fi;7G_4((mvCqu#?H zN+T<2$jD{(-41>4juaQw<{zM60S|m)H=sGi$0<$;Afb+ea-i)(f_J+~iPZsDLPwY~ zn%^IQ`qe-MkgzkfQ~MueD!defn(RTjpGV3-5ntRlFpbZ$IywGa`y0^-x1Zl(j~WCE zh;mDMBVwXzT5LJ^ZXxYb_-@6xOS66`ari;@D81rca6h?lhOfy^fO!EZz}fHa6(hlk z+CF_(`KsL<>YXdofl;s;CfAW&Mi5)wanf48=8Km7Hop)Q!C2LPm}yg`iavw25>fPr)-n7zM=k?xqzYX^oH|Q?=LH;lIdzWH=I&M2F zYHHrUv0W}`(z9)8=pp}wa{~v_){=ce7i|u0*>>;M@_)aE>R7{cCkKLs+~A9*M|c_T z>QlTWkQ5XH@3l6yhhheqqE|XFhm=maWZ3(+yn9vkp;YLo+I9#C#N8~waIE?=Z z>U?`b(Jzh?X;C|?CLb>*Arps7%+Wv*Md?@MTz(PO18@ZCKo z;iTvk;;|s{+TxR^IKb-L_|Rr)=Nvj-9&D<8@PFZEDF8aU0ViTS*SvQyazGz)Qf?x7mm$Bt$@u;e^wMMd=q#}RgDwp)lod^y$ z_C_2f{hHUMrrBfrfi2^=G~Gz^_g3$;+3yQh?V-G2vF_M&#d!vrf&13{W&sYih);#M z%D{gBx7kgATTsUX>N(54m9RZCF9l@6C~3LD2Q6v2jkqNv|ALN!Sj-oCwrvmMn>w$(hw)~YJV(|oxy`afJ`ct6 zboclD_?}m#D=A+o2_2CHq;Tz*th}2MUjg*12j#=I{8uHx^N-Y=&l}cKCH~TGzlLLZ zR$Tkg9Jbg$q-E7PoVCXj+-ZVGLfT;WJ28tF?&} zC<1!6%D*m~2@#~4CoxYVPVcmW{ zDbbZLOuk>~Ke4G9c`li=Fq~3LHfg(OzZi0G?iEVS3S}_atMVaelo`b=%B%+p6y+Gn;r<38nLQ zB5l|+MCqERdnQpBbOsob{M1HbF@z=;!ffYZt1$aPOp2NcZH33ZO6#beHK(3Xe7q~Q zy@Q%YP=wyNz38DjD%rT92zV+`A18KxpnOtN|wW_G*kV}!y8 zN`^_%+slw9eMtsm`Iydx6(c0Ap0~eBUl0$-AG>_^q z)=L2z(RGHU4z(Li8j}!_*K28M6%T^+1lcy9e787KQ3v{rs9vY=Q00h-Y>%T+RlS{){8cdng*ro7`Chp?G^rJ8BJKk{e)on9Nza_+&v*1w<n-HmT!$g}Q@?+Wk-o`>1a!YUY1-@8C%r z6bH6>zKqQuyeVoxK3cuTMT_Im#@X6 zc&DzKAT{$5y*poFT-Swaq|}0D_Vco)&cJ*}V>VEw@k_c8Y8{&kzT9DB@SYjlR4v!u zu^JKU4J4!asPxHpzB~-X(9)N6S=ajXa=U<0^O-6DACE8ei!E(qvBoth02(Pve@{o$?`-8;7=2PAyV|f!JJAk8QxV5&DGJD!B&X!AaPXItYU(GCP&RAV|*~{L9R_8Xs*@0>RfW*xm+}ju7nZEAH3t$ z%__Y*{Pb=@!L$XpgRbLlGdc}41)Y>1HXwy>FzR1jJh8N0M?&RFbSNf&@VQIs2XlDZ zSsHZn;WSG7*>gdfr%WGN&bwdqt7WcR+GI-7Hog-c78#x8A*+HF^=hicUM_5f3my3+ zJY_$xvW_Pix=0MnxiL5rRY!Oo2EHwX#s-gHL3s0eIykoY4s)DmgAAMBXp(mIqp40a zi^k0a(|>An3oNLb&cJ^Oa~6$kWeQEFDD6lPU3Z)_y-wu$p&MVBET__}H;sk!N!o%% zU0Zr%RdSr850L_EsmgKT2~|F)w%+N%n>E3x7OHR^KdnEjx+PUP4WUFb>ezkB&x0i< z9?<{8^DtHn&#m=N%l$|+|9Bp|KR2E6Idf3`Y=Jj`#Ob)P*z{f0Z@kaV4R~h72_q2q ztq`kJ4LYXIYU!J zmtBFfocYvuuhL`rd`{q`d5h8Le6QSN)oagZ)g{a0J^xKwTiD28b_(~i;flv;LxR|V zHBL2iVJMz1!T8+%=$)qk_gNgJlnC2YlW4e_=MU>{M-N8Yx9<)5@F^at6yV2P|KQc? z+r8TZu#wF)9m^Fet}v?=U%K2X7WTf5#Z3xa8x*41OPv@Dv^k6Mnt(j93X`vR>$bE+ zJ%lDJA$z@@Dgi~oNv5Ifd-gLYQ)=(WKUQw8Vu{jw&p zmzp`9V-5=P)(mHyEU2f|+;_dWB4KY2IDfpL4(mP3`c-#0RiV@$dkPF+PGz&q6{;Q( zeAxdQaMwqE(t1<{W!;4TBCvLUBCvWs4s}BM!W?`v?_Ftw*`Tb7$4VW0;nDSs@l+D< zKnKh+3&z#zwR^g;5U@B(+&2(!UfjCzw9?+`hxVcQll8Ji{<=SK`7KAcT3n8u+eBbY z9S4{tzozjhBl1wYEvBHOO4nEWgLH3o!tdk~W?5i}nZc(n+5Ybq^GDK`_(s*eS^L)N z78)C5S54r_X+7z#xNw$g4p!P!4tSWk=4rQ6f;Am%+OqNZUTX?j?C^=YoCtV90iLwa zoN~eyl6$TDo2m@W#n1PLc+P?`=MD3C9m#8$BQ57MPi3vFj0LUomA%C&miJng;g>JY z-oH7{%eqxw0j*}|z9oCxH${=RO3gHO7D=x01(^o?fYAaIv0ncQ@@&F#XRhc4$YVDO zcny~d_U#Y;+wmi*g?0A%p)TNi<7gJT&#md`hJU`{y}J?Ymva&f*{3yRG<<)T%HArA zc3xg@;J#w;G30!DusRj2`F%UqVNX%tu}7+R)Dx;!cWbzuUPc9G?L?m55XJ+PCTn+i zfoEk$mW0z}6Nj(V@xs)ayv|5Pd#96?i=cD{XR;e=0nRPvR%UkEGjMn5P2goWT|&~B z`Xcj27?UQZo5gFZ4pH21L#kII!O~+_w5JfidtjIEpimu}^LNKiX4XqoDCW+)H`n<9*fI3k$X=hAvN({8`6Di<%91nej}BQ?<3hO12d^t-7I`Y0 z4c^4#y4**7?^BWI^LVbV&tnsR#o+Dn^ER+^pFZlS?M--eUXq5E+*Sx^C+7bMQ{9ze6#JcNq;h{8sWc0LVsRl>unP!PKAAg#f>9Amk@OywHvI zXmKs{k{f7qFw3-Y2#aU!!o8_~iQID?iWL%`YZcv28FyFZ(b1+Bm#(qz5b!9V_RzNW zOePt4sa8-wBYo0#+Nt7s_qeq7qNyLlMGSFdfJ0;*7rC00h%gN*;@jg8s-@H7Z_NE? zHV9yrGxX{} zC`}dCqp-HmcZfV~U?}rlyRzaVNnJmm29OtVaQ}i1Q9&{MkbDnxXgZ&w7~#^}u77!) zSAEU)ScOYWO1J~WWMB3~UNdxsU+%V6gYk}l494LXSASHC&xRB}_2G9^a)LbrE4Faw zEse!HKw0!dp%>lH>SiQJ#SNiG$(1!JHS5SMU#OQ#g^u%wOor8b-zcfu80NAdCW)NVW7A--~bLfE0x}^|osa<_U>vUtdSi=CaE~ z)5u#|V-?*C#NwldDydnhkFBTv2%buV-B*UXSN+(^h>YM!rVk5%Upu1ekSstCx!b@9 zc%vq6b?f`Mlt?vYu*lPO&CH|w5Vaur?cshR_wJ^j7%Ie8m_4gM!?FWu2l$rE3Ne?E zCF7bxjnc$ydQ|s3t?Ow3l1enlMK~qH6PwZHHX%fhK;|l2I5|z1a|cHnmwW2?X9C8P85a^`v&Cik>NW#Y?7lzdhm z0r_TK?vmdnI}WW2BiB-925+K9A~?*g23?AfPVgKm6cNAEXDNGss20cU=BJT^!M{@L z`$2pW4M?c|)dPzOx3c)9qCz<+UnufYm)p{Dg&DI(R(+EKVS4*P>RZ&8={pZ_hQ$s@ z*l<9vx(n)gCig`_7mh-ji}8Kr^q{qCU>W1p)m~NGG35lS|M^HV{aAU>Ns==hg-SYn z%INr%C@Yj{_S}-a4=YtU^O)@~2z`Lu8qNR1lH0V?tu%MW2hRb(lGsWbzqQ5_D%Xm zq)&44(E04!H?E7+#%R@bL-qV*dcUK#)mZyKiU)yqovq3A&vm)4`W8;9RDLl0O_-kM5No{6n$XeWhF;ZZFj1Ucb0QA=W>3y*>}eJ{9lpY_}&RA=ge|dOg0) zP%NHwXuVHG7J9bYrJ6|VGOfs=P;>H_@>7GbJ&FQ>`?T^S_n2hYwI*J_CuLK|ZASzf z4bAs)a2vTyrp#gv4>S+YM}66JRcEUY7cnmrcw%Bg<-w8K#&<@q55LJ=?tlm$55#K^ zWD`7jGi>itA>nV#dG$umhg$3|9#&Bwn%OybH%e#RvKcXLP?12G+EK3AuyO~cB&Tg0 z`rZpWEE%95qgY)}JFJ){DsstTiu(+rz$gE%jVjGu8XA(cRjI?VDyslxUL}0(S@~>~UW^&X5XbivEq`CtodV<5S}vIz33&jJq?bqM z5-q$3Oj!Tt{uzBy*KNnCge#Zo8*h?)g(J*F?W}cVBsDawM$$UhO(oBu2A(*a+P`@Z zF37#+l>ev$qIdG8Y4xES2E#if=fT1MQ7>FGY+7*SOrP(U-~rMawh{;LnQS-$;YA%= z^z^DuGCbV!hy%WSG|3|Q!5c)EyS0}akNjMxfq`-?5Y;3#yJOHN!I=I8M87ZhnbTq^ zqaZ54&=Fm0=igpwd9JKKp>$pqu|A)8bUk+M>^+m;8Pg~~%wUDR{kXm2%1fbKSS``o z*8!rkaQ{TVxz}|TDvN}K2m6rL`LrYZd(g3s;0gD7y?>w)H%epid@zA6*ZDDA_-X@r zg%f!II>K|v8jfl#J~^RzchP35MP9AdoK{j==8d#w+d2P^zCXhK`tn{~?z6rpeU27W z33KGXBd?e_2&j}hWAjN>SkPXK_rIdXIsZ*vWFl_W4wEwd_Le9@d;J1}6x z4PN50vgcs>Wk+L1q92GcfJ{we-IepghrHTx<{JYj)xQ_bF9UC|{;k{vYz z&&#LV7lsp!IR}FZx_8*+WZBfVfe{w@@i3C&PeaQ7R3-F}R^umJkc3#7RO2tXqGdVP zCq94XzPKba{L2hLy$y+hB14JD2OWlaSG<2aa1C#Dxpr0V$)<~-K$yGXKj?h`|+myaBe zn|L-V#b~y~E_4wP5mPqznjrPQlr;QyqArsTUO<@lrm>6FBwJN+*Y`enx@48SeGe5>8|?i0d|Sd- z#2j6q1+{szgc+SE0u>Pt$U8=8DyS8xBf8?sXC)GVdfz(a&7&T+Xg7W4{6CHvN^+Fp zSXHMm@A&-2qvKI1LbIJZ6kk{54shi=o@t`VuZuQoR7=$H!bEkU)AS0unda`dx)>-6 zt|}|PV_Tiur-CA+k{K$z=;qvq8eH%NSQMU3T}9$l|Od#3FMRG&0>L>&!> z$)Nx`H?zDZRg_zJNKw6`)e=ccaE9rydKsF^*&{d1I`2atI4ZcX3OW)8DjhIej6x8j@ib|)^5@g!)a3c@g2`I>mGxy^?N15w=S;%=W_&ShI;IIDmJZd{$fWsPkd`kb44h|>CHdn@ z^gYz(DCgRh(d)I*JCKtu64*nbh63j#o#VkuM4SFTT*NnGX+W&gzw?>&G^Rm0l^3|3 z08J|ksstEUp>#$aR-guP6i_aUR5m7f1(e0Qk{PRF3%A5S^9 zp;GLY8$D+>2~OJ@(oH?NP9K(KR6LOtbevi3CMy2^TbR!zR{XGymvADm<>;$WJZd8g z7)Y<)*2u)q3K@)lna~b9s@kM?^l2)Ij)@Wnqq`@G4-U;UaumS#O%{ks)U^=LA`_zT|>G(8mP{B>B_N^IMZJpxu27Vf%& z1@bJ+(~=L%ASXnwT4X)n72>VL^UgW5sV?k~Fj=)&7IvLtd;l}(>>zCXGBUh7`^ z6i(vZTytf(Trpn>XA)CvLu>6J31aj_Cc2D#d)s@NHkH);(kfV(55OR{?6BOm*B1=Q z$teAnhsU*7N?$1+M6c{k?8vp}lUvi>1h6CX$4lvZm9Txe`$`VI^|wDc(YX4S1fwo9j!g>2E5(|T>DqI%6Kbyb_jhE z_Koa6>6a0{Pz{YJqpEXMSRvfa{tRXMT}I_E7Nzv7X4SP5gfJg@Mx9lE7li)v+j7Az zF?gJBPf&Grz`IocdS(GTsK2^n`~fE>^uU#&r<$$~u@$Pf9Ur4}h32cHNt9lZLW9CC zN`l=8bJJk3rwa6Tq_TnDY_epc215-2cRNPP=;Fyw3@x}%<@y(#ppf$B<4z*_OooVP zadiGW6+WrV3?|D^vXHHtcpXRuBZ(JF_(`*~k#0MPF*^Rx>D2*!^kuTQn2SU^iHUBe^&Y5f5j7qZ$;la)`e>7w3ir5*}lUQ1STv z2Ocp{y4PSukuB@pE31#~IpF&D0z!1lK5`ZcB#alOD{gM(-fdqd9f2+L>?4=L1MF(3)+a~UM&1v@<>O4NTUVPDu-FA#W`n* zfY1-#0({zu5^Rn;l#4vIQ9SIB_ZRG0+Ir&1;kmdFa4YR6|4}B&_BreF_$Bqf>Y_8{ zly(;cO6}j)380k;_hd(akCOEz~ zF1feZB#3#*n)sm24S=@^)SuuVsuAoxvr^be84lH^uIbZ9{JpI|ut1Xg3P2Watr4Vc z0nJXd7Q&4kuBnvxWhT16w-X5>^bF)gY*G2g;+;Ya zjh`*$)h(LZq8UPK+7Xhzd4tUUHhj!JL)_gkiqT&z{voG_#>WU?N!GU}O{!yM82brv zQQq9914!hcASbaoYT}&oY~iKTvqRbBPl({K1rU2Uxsyh_0jlfYVN@aVN{CC>vh=QK+dlKX?j(FSEAbC1q1nz$ zmNu#3ZlwHM+|E72$Jta0|Mv1?!4<6%SVYve-_1lPXmzN`QOv&#ER^j`EB^{JOV5&vOV zHtrxq^L%E!VQaPIbpKCwAR_wW{u;nSkxg%ilZ!2*Te2Oeycge zxie9t476iNThh`D2tT9J_JM~4QLTiJCp zjbZCqZ}f^b3e<&mqSKtI+$cFVsFx;pHlMhfpYUf9V^#C?sK~SbxxA6M$D+aL!WR%& zswLnt>+N(o4(}u#lS|GuZGXVij{pT1ITxq`y~T(uhMjD9euJkEp+&V-f7_TTc~b7ZKAyf- z*&$wMD+9KGF8DBb_5l(AtE>l-_0;~hh6t?$qObZ0oikL#A6KLyzuw?iI-)(z( zr9eIvg2G$i`!EB~E%N6vhk)pp>*|27-$lX52T9@<=C(Q6`P^b0u1(lWdA)2ZDP!!|BkNT4F z9J=hH8wetv6x$V`kR-(^nJZuhrtoD?k3sd$+XzU|CwWb{0Ue)0ID77^#*8kiGN*PZotdhO$=kWU410w^IJEzZO8>guSI8D zhYf^4K)Ads@}YLswBM$6eP@vT?c>>HVUlv`Yl3-!DV;hI{n{C$DX2r72x+84v|HBsDID#X0&QC0_WV^c~Mq= z&CR#tf%S)>Bu+ivNeJNUMhV~kRm|74qeaBcR>2Y^Sy*OMj{Y! z7)I~=m}uAC;3z(J0$qgQT8aR3^092e$&)Y)QLBHxPBbfPtzgZz&d#aK?wA>h0@^WM zsqT!9*viJiL0n^3-mq2mG+U)xb7UBYXSuf|uWtHszv##yx!l;a0cB#2>e78-xon|wd|(xlt+;lwm}AHJiOX|({u*ptKF@-1Rg&WGLuu1mDZoISZWTn#Z8`me_Ivjl_PN0e`%{+}0oeuEaTfsKD_yf2-T z2rMR7P*k4C4gjMkaA`h@7@q`^{*0jeH>(~u!65U4toxXWxjMk-O5~48&Y_@-j=sRy z{d-w#(khdTb`KKRgJJPLVoT;MzD81`q~qLV0pj(F3sg- zlmkWw`m*-FLT&uV1T7DRkqH-kj&&TB`fGo5)MoXa zRXsO#&JBn8p!79zNi9YHDw;2P z=VL0zgcKICHJrM(jTDC;T$3{U^; zVx(H|w*7KIGyPA4y^nvWRGLg7eBgW9r6)$Uq(!MjuomrLrCfPA9O9qIfCD|R(|P3- z>mX^j34bXTCwaRNZ8Q(7VV6_>rjBuh0{SW>Rz@c4 zn+D(D@|k(t|9od0l`+*mOs}h!Orl+fEq{Bx+sWe^nsfn%TRg(VpU?=Jfep8xtw#mB zpuk->+|H?*?w;kO)WlKNSo66sy&$sBKJWGd>=Y8ykbc|0IC@(OloVHfy3F5R^`0E~ z?YUA2?){O`Yo^7cHyycWcZgmJTi5Z9`W~9ca?Qd!74;UaZq7keHNNJITG&CMFrb#StSg z+lDeK?aYNrrikQk*f|)os1Itk~LloCgs-$tZpS7P4saBIagXNS@j-`$-@ftIm;VfvW1j zPvUYhE0KUrB$(Oxz|8pkcAL$Gc3gfqT(<1{8fh6skq1!dqoNg3K{Um9*(RO>o6mb4ff?p>R=el z0)xbDmAbE1Z#$K{^?H~jWNS~bhpq_~&l~|3K|BhDCfV72^N*{`7}k#RL?xE);eU8@9M>l##TUUy@U~o_$#4$o01|db_ zHEWDnRFH`UWpI(FcAt@PorJf8QMj;foB7Jwkib}AG>#VfPX+mMMIHwqP{fJYyKF-( z9p8-U_k<88b1UP&Te1t9`VEz9#kiRMA5$lN5=K;mE1Ns)GSBsgN<}_|Qe`y|M}`p&;Yu8ot8 zrSY8IELxPjY;0S38_&^J0@_$E1BTl_L$3gg@_s)sZYn%XL}%tC37`VKUN@ca>$&1D zo{5m;2|_%YKey%eXF{${(~6rzecpv3e*#p0=+O0I)F6oCDC&MY{n>x12*@#erg~MJ zA572{yz(sIC@NgTu2pT4tnN2RN>)oer7disdSkrM)Pv-UzSCmW6-9>GdC2qThYN0L z!V!ZjFT%Vu;V8Hl@6376-~Tq1=qU|C6EnL9=>o{*5p}$%Kav|^nYzp zh}pY*(fx^6$9506O9Rpbb*AM~*u= z_Dk*WDPQ?SCFAotJ|}LR04utJ1HUz8d?&bGmsO6Z`VaX=r#%9JO)}KUGcUBq62k2S z&E1@djv33dRy+>Yl1NJzzO*0}4dur-VyOQFNJ{J>zfqF{0f1o~T0h6<;4zvz5F4Dj3sROI`& zX1&`tx*o!I5%H$EA3PA1d-3Idl*S)i;B2#f_+>0vzHK+GC zKW1~^x}_A~jlAsrj?D26arsSz5>ft$&-s2_M*5UH+Tcyh zcdlIA)xQvKgWH4|7gWKIz}7cRXOi9!+2odH3>DGzn3MEY=;?@jDkaHLLF~w$`5Yvr z-QOJlHtd&BIyZFxNAZ^f<>;^QGf6(QBYYB9s~~oX6c&|%e+fP5AFFpF?M)lC^@(Vm zwX1u##US?X`}$Qe;~{m_cgTT5U!8VRv>57s5VnVTOkub0979Z-WHcpuRZbOS$q){$ z6NzRHf{DMR?NzORa#RYbujUyx+sIC~H}RH~Q=nH##`i$#ppKC$)WYgeUM7t>)|PU} z2(i^IL>h~~yr$AW<;*ZUW|sR`h%m+vXdcS%Z`h5~hTq=cPJYo0`DrsacXlA$#RJ`M zyf?!?t3I@QqXcqOTGkc{z#cU8Y_O*!Se>!G@HrKT_2t|NY&}=Vt3M;C5#gYy-H^`e z7c5xJ*Y`ON`5I;rDj8&2hK>wc}J6mMhE!&}w zGlS8NF#vee-tj zlQOAR9uMY@x)mb4BJq^SbH;>r3D+ltwGH4ijXKZaU&#oE0Q>CgGf5xJ%k0s%iPaj{ zv?Q~rHcJY*ygent8D?(;F!#&KdGo~B7F!8B1C|gT^2zz%dS+y1qPTX-{`zw*U9S|V zkEEc2p^c6)sDh3A4k(KKq5l@+L-a{6f+vv_^KV72N@REfPZf~~jvPEBf8LjgNSWdH z&i7fC7(ukD0~V|A;dnf|Zrqyu`ZXH}nQ1nY86goHIm1 zJf8}?WBs>)Yu%K)ga>;7!4L8i-d%{dYLBsnPn1ir3y83)9nQ-ZeV0}+q68sh+cRO| zb({o!iFakkMwQHQ_|+kSYz@+ua{bv@&(^xlO{@?^bg7b%Vmfn1nLOkMfhoG35&;9B zP5Um}Tbd*gSTXJrZG}N7r#kDETa8}ppHCu%?62O>_<1_GKq9E^PA`36L{WW(?LdIc zZ&9CHpZd@HScheUA;P#K$1o`(-9{rt6m!76w--W&bg*#!X&;e(dy}XC8T4N`k*9^C z$RycYI#bvk(&hhtbq__MsqM4_wM|UX^>16Di516zQ&!DzYirurP|c4H0A_=i*Td;h zsDVJZ8}B8>G#+9&Ckp&M{GN{z$qKlG+GQh=+HyWBRX+H?W5$`o7lrko&QRSh`CQ{u zun{=){Cy=&0a}!cZ@g(EV>HDg?nQZcj!G{-XKqJJ+X^J63=dubj2;fmn{n~9iY|)k zEo|okK`eQ6&rP!moq$CUEtHP|wl2ZT2!#1j4@EnLZvLr%<=?xEK~bHF?EKGDKm2tx zEKN^QFo^shNpm|RKH$OdkbTX%MKdeL?Ae?(0UMA>8WfHr#4(g{&nfS+qiBizajss) z!U$x7ALdP3rM^+}XnBe4@o3)0nsJ2!uBBwkTLdm@SmPUdt$(i9JWbCZ z(L_J};CyLjWrv)3@ni@$P9&=RvoJvkrqWZQ5;ITB7fJ|yHnuaxp6?b8y!uC@ni_p( zPQ~0gQ}-oCuk3-}smZAE@$-8L$R~f=xW6PwZ2VgIdoO)Vw`QQW(gD?;CIoxlh|A^}UfbfV|U-5pW!Uo4w|nFt7lLApjT8 zleLb@Hty<^5AeHZPpb>Ci1xAw$EqSeXq^`+0t!4qnK~SQ&`;PF0$U|u5zAxZm1%!C6+WZ-c<;_i~c1&b)i#h0`&?u3Ss>q=*{c%~|^UiB|NezRm1 zf@s44w$ZM&F&1BB=j?xK3k|#LMa8GtD~~<70rad|b~BHF58}p$&}T`hL`y@5j2#MA z2sPkD0PciYBc-OhwQ)6IWx=&8Dzsxz(65T)AJJL6R{d^yYFDCI|GT{pqn0dukP6_3 zMB24*^}W&Ji{`qrveyJaOEWFzbz@C6y&UF94-ef4he|r0qj`9}fBfO7EfOfCGnXA} z0M{MH@xJBoOU{LYg@Ax}8k?FH!@rC9a8<&}4p9IShV>g?`PA+p3aJ0RmjJtI7!>~& zrXM6e(!}%$D^LF)pw}DyzuLRbsHV1U9YQDp6vzP;rGy@&6Uw0nkRm~fpcr}&h!kle z9RvhUP>?Pyh%^O}5{if3q=QO1h=6ctf=ClI3i{UezBk5ucZ~b{-5)pm&mJ>#?>*OA zd#*X>THl;oqBe%7DBO5M4)*Id=P zZz4@g6a_ja)HFRSi1(Y;v7rRGpcIXvJf)N(|5D%&wGT6RO=1rp&P^Kc;3A9*$C%+K z+u3Jrs<{O98h*O==@H-@#5SwuY!(^Z`?`XRwX-vPslwxT5#_^S-l`TmF~!2wo}|6t zjN9kfk)~hnG(~LS#LD|(;^E}Xx2&R=M8aQ|C&`^bRvXoef|0&@MCO4YNcw3~e@by8K%oAWBo&z^N} z9;#?^k{MeSgzce@`p@yNdSKlW4t8yp-g;IaKROx!9hEIDgv%ETZ2w)x;|En+q#3M8 z5#YZG$y9WG33a5dWR0EbLA+Y!Bfz~fVS%L+$4j`;Lg3T>dml19NQsu6E|ZYgX{YSN zcFQylDxfrzLZFjC(H`I>DH8yX`EgBcO&R2?_-7H^a@N$hZ-ey7%J(_q%O(JNgUdpc z)6*4+q{j`Ka&PD)mZN~GrvH&-CcmM`bM|xsnqnLB zp@c|z)m#hF`%vV9^!hJnG|er+lrO5ZiX}pUK{gg?I+>##JunzPXkH*k92wz+ZvR<~ zhDkL?inXx7>#jzj@o0gt%okL)uxeMj$hJ-P_p*HDe$=`-d?Kjtm_6^&jQGr&|G-Qg zLQfZ-e#>oIq2RE-EZNW+3x=2gKgLHfu`YaIGqiC@)%~_6x{wMXjjT}Qeryc;ZJh~s z^|j$knH@Ml=w?U&30;`)A`Bti)KZD)R}WyirK381jMCAhtKwKC=yrDuqf}VA&@C86 z43^pkH4ShD^2*_sm74T7kwouWL@7VbhMG~7jB^e>mO2Hoq^5Pq%(2Z&@--j2#@7PS zQz?J6BR#2~chEyEA?_D+Poy+ zSpE(@R?iHc9^wvLG$=H?;j}6Sjj}1ybfbtS*14Vj|J;Z+;Ygqlqp>(_p4lNUBr`lM z%gv{9!g#L=>H|Sh=*G-l?A?OXZNsJzs!Lu7$V<?>tkT99d1VGL8~L~f0L6akzf9D-lk035f9@sXq*mR3p}~SkR)#04a($Hu1}lp zS8vLsB1qAF0pkkYqHKq3R%s5^4#8xH;A4}?4-t9*&u<$znM8WuH6OaoAQCixyK%52 z=SL2WQ>k#?5Z_H?Jq&H&TQ{P}8q{QwVV;v8ER1TbMINQ1wzhi8#0o%@t=`C)*Jy#1} zJs9H#&)!#NeY^dK)A7_l{`~87hV^wC0aW47qczJtET8t)X7$gQ!IC2^o}7$wXTaU4 z9Vpe>owD&C!MN_nsDF9KkZ&gAGk-pnm$T{74h?$wF5?G;IO#}aNggS!(2}~tF;c2dhSWh zTuIfq!^qacDQ2s3?}(GR

_Dcnia)>7g9VjCNuH zakkghxI47>F>Arl+^vN=>vvi;w`RTWf4+=JpiEhbm*Dpa@rm?G#1Id#CkY@zaK)R% zo+I|>MqvW7q5!Zc8J$X-Kn~7mKcbtnYCJxyKH1&m*uEDhT@)KI$OeP6J$5q)3-0s+ z*{s!x9Ek(4E|Lf=so7+B%-7VTYF}=3AW#4;a;qG?EIDL?pS-Z9UgnY+(Ge?0lo; znNdw3t!T6v10(#zsDXd-#NP?LRUy{7;(m8|-ji!h_~8g_(NY=7cqAY)RxXq__P`Pr zU6YdXX&yP6?{S4w^n>se+aKMECsd^c*MK%?oZLV86qAy7h7MA)C5_F&A8@@0U!9MX z={6Yw%xuf;{YO{dG+Okqquu31%cnsB5b&b0@7KXECkOhpq-Um;RuM3gl~KO_rCHi4 zS0CCXpKG;0tR4N~eFGyJ=BZvgCrmWV?2s@Z)4{Zu9F@DT<-d@5l{{7*?nU%b*kX!^ zCA)c7xQC8kxp(Jzw06ULniJGHJYF1Ch(aqa9IY${MT(zO(lP7&^5My)!p<9s_{RyE z+S(24dwG?4OwLqdX2(YZG7pUX;H3>&;PfZjhpZxx8q5RRqL@^g#Ni0t4F0AwVvkoY z((ArJpM9E*LRS(not9hjn)7FVQ*@W{wYjvW>i7~tZzQg5{O)a51@~1WFXft!JYZ8V zAxTU)qxO;g)e)@cdXX(VTHAKzD8{<@y29sPWberi3&IZr=FZE#J2$WN&aq9kUQWwQ zdqaTNNk>x|(530Nbm-FI1tA@I*%y`|@F>`KL6VvP%9mv?isgq9Ocia!H_Y5+xQ3=% z2?f)%HJGyLZ)?0-py6qfc`ZDwl{EAPT=4{P3LV9!wNP7b%lRhqRHrZOM1zm4aH+k6 z6hGcU9+-frYZ25H{kk}8Cnp1OD`G3BTs$jBSjG|N4vIbiucYvU?%^ z*vMaAiNP-#LOK#Kp{=72UT5uFPHoTqEf%hKE}|P)Z^e24OjDtv0u~6)Jo_C1|%SAI*R-p z3rDCkjRalz1cJY+l#a@`C&gT{U%M2#ioY;$^Xp899pnkO>m)IIJT#a0AzR6)+It@) z;G>*IzdqDWqEml8FKO?TD4c2S-OPTP00oL|S&-A(&GKbjXaD;P#IqK}l5WkB_t&rm zW`A1!OYro28)hA5HD^Pd0l?x+P+XhyhJ$UkSJ79V=|uy+mk}QK|JLD=&AWAlWMw&Y zL`wJ<-gJFXl(tWQza=!L|DVTOAsTk+3)39O+F_sCe|~R2&7$*HW#repk-@9jLNT?z zx`G3Vn{r`@VYa((^mkYa*@8uS3XqFL#9!Ho_q)3FZ8i8q80g_xeiFmsPNKEi-`qc~ ziX^Qb+gfE6hp?3BKUjWKa2SxUJyEohW$y@Skr#r;yE7hdU?iK0i9$ zx-2X`vr{5H7hIgII1~K$B{0p7D9(Le0WMbWkbT=E7@^k5tFzv%2SKwp_LG1Qw*so% zUT?B@Jx`!sH_JLZ`7}uFJwmgo>)grR|1F2{OY4AFz3~E18%`~K-UYEcX^)YlQ{jI0 zAQ#!oTOmg=!&5AuQt}aQ%N&OdK}jKPrwPj!VV3o8fN!)JCmkkxsW`fOa)VvsL{G~{ z*IdtSPz$YOi+<3IBun_&Q>qnr%+Y-YZ=z=yxR%7_H~xJf)}@qxn!0oK)G~m8G=aR` za}oNc(Zs@%OGj1p>biY6I&8_AidpNV>!aFKEG10i<(72}nZL@r)byUR51Lt- zvX8tY+4#=wFylF=0_0(WzgMfO^qGR#JFvQZH;=h_4*QdOP7z#Er!>E7oZA6<5xA1E z=GC+)QZ@eC%)t-TZ5ENeV_5irH~FL6w8R?Ai91@X&AS$oXkI2e`b_`$_)Z*yQHtG= z8V8Awe&69m>UI(e-A(NzeN=WL6gbJSmY$==15bnXU zvfNluHc6s>ybA=?dv3X|e9OL>R!XxsnD@9no~GqHA4jTuOWCfscreenshots Mobile 4 Mobile 5 +

Apple Watch

+
+ Watch session list + Watch quick reply + Watch session details +
+
Watch support covers quick session monitoring, unread counts, OTA update visibility, push notifications, and quick replies from the wrist.
@@ -292,7 +303,7 @@

features

remote terminal
browser & mobile, no SSH/VPN, real-time PTY streaming at 12fps
file browser & git
tree view, upload/download, +/- stats, floating preview
local web preview
preview localhost from any device via secure tunnel, supports HMR
-
mobile & notifications
biometric auth, push notifications, shell keyboard input
+
mobile, watch & notifications
biometric auth, push notifications, shell keyboard input, watch quick replies
multi-agent discussions
discuss, audit, review across providers with ring progress
streaming transport agents
native streaming for OpenClaw & Qwen — real-time delta updates, tool tracking, session restore. Qwen offers a free tier (1,000 req/day) from Alibaba Cloud — subject to change.
terminal + chat
raw CLI or structured view with parsed tool calls
@@ -325,10 +336,14 @@

architecture

download

-
+
Download on the App Store Also available as a web app
+
+ iPhone · iPad · Apple Watch + Watch app includes session list, unread counts, and quick replies. +
@@ -420,14 +435,14 @@

about